Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@ public static String decode(String item, short decFrom) throws PageException {

}

private static String decodeURL(String input) throws PageException {
return org.lucee.extension.guard.util.Canonicalize.decode(input);
/**
* URL (form) decoding: "+" becomes a space, valid %XX escapes are decoded and a "%" that does not start a
* valid escape is kept as is instead of throwing (LDEV-6699). "+" is replaced first, so an encoded plus
* (%2B) still decodes to "+".
*/
private static String decodeURL(String input) {
return org.lucee.extension.guard.util.Canonicalize.decodePercent(input.replace('+', ' '));
}

/**
Expand Down
21 changes: 0 additions & 21 deletions source/java/src/org/lucee/extension/guard/util/Canonicalize.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;

import lucee.loader.engine.CFMLEngine;
import lucee.loader.engine.CFMLEngineFactory;
import lucee.runtime.exp.PageException;
import lucee.runtime.util.Strings;
Expand Down Expand Up @@ -203,25 +201,6 @@ private static int hex(char c) {
return -1;
}

public static String decode(String str) throws PageException {
CFMLEngine eng = CFMLEngineFactory.getInstance();
try {
Class<?> clazz = eng.getClassUtil().loadClass("lucee.commons.net.URLDecoder");

// decode(String str, boolean force)
return eng.getCastUtil().toString(eng.getClassUtil().callMethod(clazz, eng.getCreationUtil().createKey("decode"), new Object[] { str, false }));
}
catch (Exception e) {
try {
return URLDecoder.decode(str, "UTF-8");
}
catch (UnsupportedEncodingException e1) {
throw eng.getCastUtil().toPageException(e);
}
}

}

/**
* Example usage
*
Expand Down
35 changes: 35 additions & 0 deletions tests/LDEV6699.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
component extends="org.lucee.cfml.test.LuceeTestCase" labels="guard" {
function run( testResults , testBox ) {
describe( title='Testcase for LDEV-6699: decodeFromURL() with a % that is not a valid escape' , body=function() {

it( title='a trailing % is kept as is', body=function() {
expect( decodeFromURL( "100%" ) ).toBe( "100%" );
expect( guardDecode( "url", "100%" ) ).toBe( "100%" );
});

it( title='a % followed by non hex characters is kept as is', body=function() {
expect( decodeFromURL( "50% off" ) ).toBe( "50% off" );
expect( decodeFromURL( "(80 - 100%).pdf" ) ).toBe( "(80 - 100%).pdf" );
expect( decodeFromURL( "a%zzb" ) ).toBe( "a%zzb" );
expect( decodeFromURL( "a%4" ) ).toBe( "a%4" );
});

it( title='valid escapes next to a bare % are still decoded', body=function() {
expect( decodeFromURL( "%3Cb%3E 100%" ) ).toBe( "<b> 100%" );
expect( decodeFromURL( "%E2%82%AC 5%" ) ).toBe( "#chr( 8364 )# 5%" );
expect( decodeFromURL( "100%25" ) ).toBe( "100%" );
});

it( title='+ is decoded to a space, an encoded + stays a +', body=function() {
expect( decodeFromURL( "a+b" ) ).toBe( "a b" );
expect( decodeFromURL( "1%2B1" ) ).toBe( "1+1" );
expect( decodeFromURL( "50%+off" ) ).toBe( "50% off" );
});

it( title='decodeFromURL() is the inverse of encodeForURL()', body=function() {
var str = "a b+c&d=e/100%";
expect( decodeFromURL( encodeForURL( str ) ) ).toBe( str );
});
});
}
}
Loading