Strange ColdFusion URLDecode() and GetEncoding() Behavior

Posted February 5, 2009 at 9:14 AM by Ben Nadel

Tags: ColdFusion

I ran into a really strange ColdFusion behavior this morning. I don't deal with character encoding very much, so I am not sure if this is a bug or not. It sure feels like a bug to me. Take a look at this example:

  • <!--- Dump out the URL encoding. --->
  • <cffunction name="Test">
  • <cfargument
  • name="URL"
  • type="string"
  • required="false"
  • default=""
  • />
  •  
  • <cfdump var="#UrlDecode( 'http%3A%2F%2Fwww.bennadel.com' )#" />
  • <cfabort />
  • </cffunction>
  •  
  • <!--- Trigger test method. --->
  • <cfset Test() />

This is a really paired down example of the problem code; but, essentially, I needed to URLDecode() a value that was returned from a remote API. However, when we run the above code, we get the following ColdFusion error:

java.lang.String cannot be cast to coldfusion.filter.UrlScope null

As I started to take away parts of the code in an effort to debug, I found that this code also broke:

  • <!--- Dump out the URL encoding. --->
  • <cffunction name="Test">
  • <cfargument
  • name="URL"
  • type="string"
  • required="false"
  • default=""
  • />
  •  
  • <cfdump var="#GetEncoding( 'URL' )#" />
  • <cfabort />
  • </cffunction>
  •  
  • <!--- Trigger test method. --->
  • <cfset Test() />

In fact, this code throws the same error:

java.lang.String cannot be cast to coldfusion.filter.UrlScope null

When I saw that GetEncoding() was throwing the same error as the UrlDecode() method, I started to suspect that there was some sort of name conflict going on, perhaps with the "URL" argument being passed to the UDF method. To test this theory, I renamed the URL argument of the user defined function and ran the code again:

  • <!--- Dump out the URL encoding. --->
  • <cffunction name="Test">
  • <cfargument
  • name="TargetURL"
  • type="string"
  • required="false"
  • default=""
  • />
  •  
  • <cfdump var="#GetEncoding( 'URL' )#" />
  • <cfabort />
  • </cffunction>
  •  
  • <!--- Trigger test method. --->
  • <cfset Test() />

This time, with the TargetURL argument rather than the URL argument, the GetEncoding() method run without error, outputting the value:

UTF-8

Obviously, I am not going to rename my CFArgument value because the name "URL" makes total sense for the given context. So, what can I do about it? I tried to manually set the encoding before calling UrlDecode():

  • <!--- Dump out the URL encoding. --->
  • <cffunction name="Test">
  • <cfargument
  • name="URL"
  • type="string"
  • required="false"
  • default=""
  • />
  •  
  • <!--- Set the URL encoding. --->
  • <cfset SetEncoding( "url", "utf-8" ) />
  •  
  • <cfdump var="#UrlDecode( 'http%3A%2F%2Fwww.bennadel.com' )#" />
  • <cfabort />
  • </cffunction>
  •  
  • <!--- Trigger test method. --->
  • <cfset Test() />

... But this didn't help at all (same error). Finally, after some more playing around for like 10 minutes, I found that adding the CharSet optional argument to the UrlDecode() method did the trick:

  • <!--- Dump out the URL encoding. --->
  • <cffunction name="Test">
  • <cfargument
  • name="URL"
  • type="string"
  • required="false"
  • default=""
  • />
  •  
  • <cfdump var="#UrlDecode( 'http%3A%2F%2Fwww.bennadel.com', 'utf-8' )#" />
  • <cfabort />
  • </cffunction>
  •  
  • <!--- Trigger test method. --->
  • <cfset Test() />

This code runs without error and outputs the value:

http://www.bennadel.com

Again, I don't play around with encodings very much, but this definitely feels like a bug. Anyone have any thoughts or see where I'm missing a big piece of logic?



Reader Comments

Feb 5, 2009 at 9:30 AM // reply »
6 Comments

Ben,

You'll want to use a different variable name, URL is the name of the built in structure for get elements.


Feb 5, 2009 at 9:31 AM // reply »
6 Comments

...; try inURL instead.


Feb 5, 2009 at 9:38 AM // reply »
11,314 Comments

@Jeff,

The name of the CFArgument should never matter as long as your references to the argument are scoped (making sure ColdFusion doesn't have to try to decide before which one you are talking about). When you define arguments this way, they are simply keys in an argument struct and there are no limitations on what values you can use for struct keys (as far as I know).


Feb 5, 2009 at 9:42 AM // reply »
2 Comments

I'm not entirely sure whether to conclude that it's a bug or the nature of it being a naming conflict, or something else.

What I did observe from running a few little tests was that if you remove the cfargument entirely from all of your examples, everything works as expected.

If you keep the cfargument and dump just a simple string like "Hello World" (rather than do anything involving URLs), it seems to work fine too which I found interesting. (I expected it to break, but it didn't.) Not sure what to make of that just yet.

Not sure if this helps or if it muddies it more, but either way thanks for posting this so I'm sure never to name arguments URL.


Feb 5, 2009 at 9:43 AM // reply »
16 Comments

Not sure I would use an argument name of URL either, but did you try explicitly defining the scope?

<cfdump var="#GetEncoding(ARGUMENTS.URL)#" />


Feb 5, 2009 at 9:50 AM // reply »
11,314 Comments

@Steve,

The URL being passed to the method is not a scope. The URL being passed in is a string being used in a remote API request (my example is a paired down version of the code). Also, GetEncoding() takes the name of a scope, not a reference to it (according to documentation - this is the first time I've ever used this method :)).

@Angela,

Please please please don't take away the lesson that you need to restrict your method argument naming. Naming conventions should always be intuitive. If you have to pass in a URL, then name it URL :) That is not the problem here. I have named my arguments after scopes all the time, especially if I'm actually passing in a scope, ex:

MethodCall( URL = Duplicate( URL ) )

Nothing wrong with this. And, as long as you scope your argument references, there is no ambiguity in the execution of said code. If there is a problem, it's in the internal execution of UrlDecode(), not in the argument naming.


Feb 5, 2009 at 9:56 AM // reply »
1 Comments

I have to cast my vote for this not being a bug. It looks like it is simply the result of asking CF to guess whether you mean URL, the built-in scope, or arguments.URL, the local variable. As was suggested, being explicit about which scope to look in is best (arguments.URL) and should work every time.


Feb 5, 2009 at 10:04 AM // reply »
2 Comments

@Ben, well when you put it that way... Maybe I won't take that away after all. Personally I don't have a an issue using names like URLscope or strURL. I find them intuitive enough but I can see your point.

I've named arguments URL in the past, and I'm pretty sure that I even dealt with encoding in the function but I'm not finding any examples to say for sure. (I could be wrong though.) Maybe there's more to this that we're not getting yet.

I'll hold off on deciding which way to go with naming conventions once this plays out some more. After all, there's a workaround which may be sufficient enough to keep the argument named as URL.

Thanks again. :-)


Feb 5, 2009 at 10:06 AM // reply »
11,314 Comments

@Chris,

I don't think there is anything ambiguous about it. When you call GetEncoding(), ColdFusion expects a scope name. When you pass in URL or FORM as a scope reference, ColdFusion complains that it cannot convert it to a simple value (name of scope).

Additionally, ColdFusion does not have to guess at which scopes you are referring to. It keep clear internal track of all the built-in scopes:

<!--- Get all built-in scopes. --->
<cfdump var="#GetPageContext().GetBuiltInScopes()#" />

<!--- Find scope by name. --->
<cfdump var="#GetPageContext().SymTab_findBuiltinScope( 'URL' )#" />

I can't think of any reason, other than a bug, that ColdFusion would have to guess which scope you are referring to. Also, remember that once you are inside the context of a method call (ie GetEncoding()), the internal workings of the function to not have access to the local variables of its calling context.

If anyone comes away from this post thinking they have to be careful about their argument naming (especially when the naming is maximally intuitive), then this post will have done more of a disservice than a service :(


Feb 5, 2009 at 10:14 AM // reply »
29 Comments

This month marks 9 years since I started doing CF development. And I am still more than a little grumpy that you can't use "url" as an identifier. I'm not hating on the Fusion here, I'm just saying...


Feb 5, 2009 at 10:21 AM // reply »
16 Comments

@Ben

Call me Cutter brother. I had to start using the rest of the name in communications because the CF product team kept passing me up on the ACE program because they didn't know who 'Steve Blades' was;)

I understand that you are only passing in a string. ColdFusion doesn't (in the context of that function), because your argument has the same name as a scope. I'm saying, in your function, explicitly tell CF which scope to look at. By explicitly referencing the variable as being a part of the ARGUMENTS scope, it won't get confused and think you are referencing the entire URL scope, but go straight to the ARGUMENTS scope to resolve 'URL'.


Feb 5, 2009 at 10:22 AM // reply »
6 Comments

Ben,

Maybe I am confused as to this code.

Are you attempting to URLDecode the entire URL structure? (ie All passed parameters in the URL (GET) scope?


Feb 5, 2009 at 10:47 AM // reply »
11,314 Comments

@Cutter,

Sorry about that - I know you've brought it up before :) But yes, I I absolutely reference the CFArgument URL via the ARGUMENTS scope when necessary. In general, I try to scope all my variable references for optimal clarity.

@Jeff,

I am not trying to decode the URL scope. I am trying to decode an encoded value passed back from an API. In the demo, I am pasting in a sample URL that was returned:

http%3A%2F%2Fwww.bennadel.com


Feb 5, 2009 at 11:07 AM // reply »
6 Comments

@Ben

I understand your desire for simplified naming, but there are times when the implicit scope precedence does not always work as expected.

In the case of arguments such as this, I have started prefixing the variables with in. So for this, I'd us inURL. What is nice about this methodology is that if I process the URL in someway, I can assign it to a new variable outURL. Especially useful for long, complex code blocks that require referring back to the original argument. This eliminates the need for explicit scope reference. However, I only see this as a potential problem with variables named the same as the global scopes (URL, FORM, CLIENT, etc), basically anything you can do a cfdump on without defining it first.


Feb 6, 2009 at 4:40 PM // reply »
6 Comments

@Ben

I found the reference that wasd in the back of my head.

http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Expressions_2.html#2711961

Third bullet in this case.


Feb 6, 2009 at 4:46 PM // reply »
11,314 Comments

@Jeff,

I can appreciate that you shouldn't use these for variable names. But defining these values with CFArgument tags is what has me on the other side of the fence. Is it a variable? Or is really a struct key in the ARGUMENTS scope? It states nothing about collection keys.

But, the argument here is silly since it clearly breaks unless you specify the character encoding in the UrlDecode() method :)


Feb 6, 2009 at 4:52 PM // reply »
11,314 Comments

@Jeff,

I don't want you to think I'm a total jackass. I would never do things like this:

<cfset URL = { Name = "Value" } />

... cause clearly, there is going to be guessing that ColdFusion is gonna have to do.

However, I still think it would be totally reasonable to do something like:

<cfset REQUEST.URL = { Name = "Value" } />

To me, struct-keys exist in a world of their own.

Now, you could say that unscoped variables are *really* just keys in the implicit context (ie. VARIABLES scope on a page, THIS scope in a CFC); but, something about the unscoped nature of them feels so different.

Arrrrrg! Now I am getting frustrated with myself :)


Feb 6, 2009 at 5:09 PM // reply »
16 Comments

@Ben -

In my day job, there are dozens of variables in our 3k template app that read 'URL' or 'FORM'. They are so numerous, renaming them would be a nightmare. We've been able to avoid the conflicts by, when finding them, putting them in their proper scope:

VARIABLES.url
ARGUMENTS.url
REQUEST.url
FORM.url
VARIABLES.GetSite.url (a query column reference)

It's not the ideal fix, but it does avoid the conflicts.


Feb 6, 2009 at 5:19 PM // reply »
6 Comments

@Ben

I understand completely with what you are saying.

However, in my current situation, I have a deep appreciation of these restrictions. I am coming in on an established application that has had many "generations" of development and many different developers - and therefor styles.

I have come across a few situations where there was implied logic put in place that, once explained (or figured out), is really quite elegant. However, to a fresh set of eyes, it is confusing at times and convoluted and frustrating at others.

Adobe (or Macromedia) choosing to make the system defined scopes be reserved words does actually make sense at this level. It is like any other language with reserved words.

It would be great if the most recent scope took precedence, but there is an issue with the eample you gave.

Let's say you can use a variable named URL. Now, in your procedure, you want to make a comparison with passed parameters in the URL structure? Is it If (URL eq URL.Variable)? I have not tried this, but the only place that could ever possibly be true, if URL as a variable was allowed, would possibly be if there was only one value in the URL structure and it also automatically dereferenced that one value.


Feb 11, 2009 at 8:54 AM // reply »
11,314 Comments

@Jeff,

I guess really what it comes down to is how do we officially define "variable" :) Because, a variable name can't start with a number, but a struct key *can*. So, does that mean that a struct key and a variable are very different things?

Very thin line.


Sep 14, 2009 at 5:12 PM // reply »
1 Comments

I ran into this EXACT issue - fought with it for a good 1/2 hour before turning to google and finding this helpful post.

RSS = Subscribed!!

Thanks for saving me further frustration!

B.


Sep 21, 2009 at 8:26 AM // reply »
11,314 Comments

@Brian,

Glad to help. This is an irritating bug to be sure.


Dec 29, 2009 at 5:55 PM // reply »
5 Comments

Did you try passing in some other scope name like 'form' instead of 'url' to getEncoding?

Definitely a bug; just curious as to it's nature.


Dec 29, 2009 at 6:11 PM // reply »
5 Comments

Strike my last comment. A delete feature would be nice to quell some noise :).

My comment was regarding a red herring of sorts in the post: URL is a reserved word; all scope names in CF are reserved.


Jan 5, 2010 at 8:39 AM // reply »
11,314 Comments

@Danny,

I don't think it has much to do with "reserved" words. I think it must be the way the underlying code searches for the structure that you are looking to encode.


Aug 31, 2010 at 7:05 PM // reply »
10 Comments

Ben, thanks a lot! Had this exact same error, and you just saved me a lot of debugging :-))


Sep 3, 2010 at 10:27 PM // reply »
11,314 Comments

@Paul,

No problem my man. Really strange error, right?!?


Sep 8, 2010 at 4:10 PM // reply »
1 Comments

Yep - too strange since the second arg in urldecode is optional. I did run across the error and googled it and landed safely here. Thanks, Ben!


Feb 1, 2011 at 5:19 PM // reply »
5 Comments

+1 for helping me with the strangest error I have encountered yet.


May 4, 2011 at 9:55 AM // reply »
1 Comments

@Ben,

I absolutely agree with you on all points. This idea that "oh, I better not call my argument this or that because it is a scope", is absolutely rediculous. People that use that ideology don't understand programming and certinaly don't understand the underlying mechanisms. There is nothing wrong at all using scope names as argument names, and yes, you should always refer to your arguments as Arguments.Foo, since that is percisely the reference you are dealing with, any other way does not make sense to me (perhaps because I come from a C++ background).

As for the urlDecode method, yesterday I upgraded one of my installation to ColdFusion 9 (from ver. 8) and all of my urlDecode calls broke with exactly the error referenced here.

Thank you all so much for your efforts and contributions to this thread. I will now be able to easily correct for this, what I consider, very odd behavior. I believe this to be a bug myself. This is NOT expected behavior (ie: bug).


Jan 29, 2013 at 4:36 AM // reply »
1 Comments

???? ????? ????????? ?????? ??????? ????? ? ?????? ?????? ???????. ????????? ?????? ??????, ??? ??? ????? ??????? ?? ????? ?? ???????? ???????.



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 18, 2013 at 9:20 PM
Mapping AngularJS Routes Onto URL Parameters And Client-Side Events
I couldn't find examples of passing multiple arguments using the when() routing statement so figured out through trial and error that you can pass multiple arguments using the following format: .whe ... read »
Jun 18, 2013 at 3:39 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
Hi Ben, THANKS! While not bleeding edge, it is new to me & I like learning new things every day! ... read »
Jun 18, 2013 at 12:30 PM
Disabling Auto-Correct And Auto-Capitalize Features On iPhone Inputs
Also spellcheck="false" should be mentioned as part of html5 specs ... read »
Jun 18, 2013 at 8:40 AM
Using Named Functions Within Self-Executing Function Blocks In Javascript
Hi Ben, you forgot to mention the most important thing for named self-executing functions - they can be referenced by name ONLY inside their execution context (which is parens in this case), it mean ... read »
dee
Jun 18, 2013 at 7:01 AM
My Safari Browser SQLite Database Hello World Example
hai ben, this program is really good i could understand the concept but i dint know how to save it and how to open it as you have done in the video can u give that details pls ... read »
Jun 18, 2013 at 6:04 AM
Clearing Inline CSS Properties With jQuery
Thanks a lot for for post! It helped me a lot... after being stuck since 24 hrs.. found solution from your post. Thanks again! ... read »
Jun 18, 2013 at 2:31 AM
SOTR 2013 - The Best Conference I Never Went To
I keep watching it, should keep me happily distracted until SotR14 ;) ... read »
Jun 17, 2013 at 9:45 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, As I was reading what you wrote, it occurred to me that maybe I do something similar to that in some of my client-side code. In an application I'm working on, there are a bunch of unrelated ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools