Strange Double-Encoding Character Behavior With CFLocation Tag In Lucee CFML 5.3.6.61
Yesterday, I was working with the Craft team at InVision to try and debug a rather odd URL-encoding problem. It seems that the CFLocation
tag double-encodes the forward-slash (/
); but, only when certain combinations of characters are present in the query-string parameter. I've been able to create an isolated example of this in Lucee CFML 5.3.6.61.
We were working on a ColdFusion page that accepted a Craft Client value in the URL. The value looks like this:
CraftManager/1.0.97+196
In the context of a URL's query-string, this value contains two "special" characters: the forward-slash (/
) and the plus (+
). So, when passing this value through to another page, via CFLocation
, I was sure to use the encodeForUrl()
security function. However, the incoming value seemed to have a somewhat incomplete encoding of its own, which I think is - at least in part - what was causing the issue. That said, here's my reproduction in Lucee CFML:
<cfscript>
// The value we are passing-through the URL has two "special" characters in it: the
// forward-slash ("/") and the plus ("+"). Let's see what happens when we pass-
// through different combinations of encodings on these two characters.
// --
// NOTE: In URL parlance, the "+" typically represents a Space character.
targetUrl = (
"./test.cfm" &
"?value[]=CraftManager/1.0.97+196" &
"&value[]=CraftManager%2F1.0.97+196" &
"&value[]=CraftManager%2F1.0.97%2B196" &
"&value[]=#encodeForUrl( 'CraftManager/1.0.97+196' )#" &
"&value[]=#urlEncodedFormat( 'CraftManager/1.0.97+196' )#"
);
// Let's included the generated URL as an HTTP Header as well, so we can see how the
// value differs from the value in the "Location" header.
header
name = "X-Target-Url"
value = targetUrl
;
location
url = targetUrl
addToken = false
;
</cfscript>
As you can see, we're passing a number of value
parameters through to the next page using Lucee's URL-Array notation. Each value uses a different combination of encoded and unencoded values. In addition to the Location
header that ColdFusion is automatically including, I'm also explicitly adding an X-Target-Url
HTTP header so we can spot any discrepancies.
NOTE: This issue happens with or without the special Array-notation. I'm just using it in this case because it makes the subsequent
CFDump
easier.
The target page just dumps-out the URL
scope:
<cfdump
label="Url Scope (Lucee CFML #server.lucee.version#)"
var="#url#"
/>
<p>
<a href="./">Try again</a>
</p>
So now, if we run the index-page and get redirect, we get the following browser output:
As you can see, the second instance of our value[]
query-string parameter contains an encoded forward-slash. Which means, it was sent through to the target page as a double-encoded slash. Specifically, it was this version:
value[]=CraftManager%2F1.0.97+196
This version contains an encoded forward-slash and an unencoded plus. Something about this combination of characters makes for an unhappy CFLocation
tag.
If we look at the HTTP headers during the relocation, we can spot the discrepancy:
As you can see, when the CFLocation
tag goes to encode the plus, it appears to double-encode the already-encoded forward-slash.
To work around this, I just replaced all instances of the encoded slash in the URL prior to calling the CFLocation
tag:
.replaceNoCase( "%2F", "/", "all" )
This fixes the issue in this use-case, at least temporarily.
I tried digging around in the Lucee CFML source-code to figure out what was going on; but, I couldn't pin-point the issue:
CFLocation
tag callingHTTPUtil.encode(url)
HTTPUtil
callingescapeQSValue()
HTTPUtil
callingURLEncoder
URLEncoder
calling Java
So, ultimately, my problem is likely that the original value, CraftManager/1.0.97+196
, was not encoded correctly in the call to the Lucee CFML server - I think the +
wasn't being encoded. That said, something is clearly fishy in the CFLocation
tag.
Want to use code from this post? Check out the license.
Reader Comments
While not directly related to this, it appears that someone else posted a JIRA ticket about the auto-encoding creating unexpected value:
https://luceeserver.atlassian.net/browse/LDEV-2164