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,238 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 »
14 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,238 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,238 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 »
14 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,238 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,238 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,238 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 »
14 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,238 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,238 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,238 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,238 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
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools