Skip to main content
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Simon Free
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Simon Free

Strange Double-Encoding Character Behavior With CFLocation Tag In Lucee CFML 5.3.6.61

By
Published in Comments (1)

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:

CFDump of the URL scope reveals double-encoding of some fowrard-slash values in Lucee CFML.

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:

HTTP Headers show discrepancy between pre and post CFLocation manipulation in Lucee CFML.

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:

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

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel