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 126.96.36.199.
We were working on a ColdFusion page that accepted a Craft Client value in the URL. The value looks like this:
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
The target page just dumps-out the
<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:
This version contains an encoded forward-slash and an unencoded plus. Something about this combination of characters makes for an unhappy
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
.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:
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
Want to use code from this post? Check out the license.
While not directly related to this, it appears that someone else posted a JIRA ticket about the auto-encoding creating unexpected value: