If you've worked with ColdFusion (or CFML) for very long, you've probably noticed that CFML's treatment of request parameters is a little unorthodoxed. Specifically, it doesn't differentiate between multiple instance of the same parameter being passed. Consider this url:
page.cfm?a=1&a=2&a=3,4&b=5
As you can see, there are three instances of the 'a' parameter, one of which has a value that contains a comma. In CFML-land, you're going to get a single value:
url.a == "1,2,3,4"
Uh oh.
Fortunately, the Servlet Specification comes to our rescue. You can use getParameterValues on the ServletRequest object to get back an array of values:
getPageContext().getRequest().getParameterValues("a") == ["1", "2", "3,4"]
For a more complete series of examples, check out http://barneyb.com/r/params.cfm. Note that the Servlet spec doesn't differentiate between query string and POST parameters, while CFML does (via the url and form scopes). If you ask me, however, you shouldn't either. They're all just parameters – treat them as such.
Just to be obstinate, you may want to reconsider your point about GET/POST, and "they're all just parameters". It was an okay idea for a while, and it led to much cleaner code, but it also opens the door for XSS/XSRF/etc attacks. More often than not these days, you do want to ensure that you're getting your parameters from the correct source/scope.
Rick,
Can you provide a concrete example of why I'd care? Or more specifically, why I'd ever want to treat them differently? GET is certainly easier to maliciously request than POST, but that's a request method distinction, not a parameter source distinction. I.e. I only allow POST for certain URLs, GET for certain other ones, and both for a third set. But once I'm inside a request, the parameters are just parameters.
For example, within an FB3Lite app where your form actions all start with "do", stick this in the onRequestStart fuseaction:
I think that the CFML engines are just being nice to you and convenience. Remember form and query string data is flat and simple values anyways. Nothing wrong with using variables.a = ListToArray(url.a) if you want an array of parameter items in CFML.
For example in Django, you would get QueryDict object back for all parameters. If 'a' has multiple items in the query string as in your example, calling queryDict.getItem('a') returns only the *last* item (not all items). So you still have to be smart enough to call queryDict.getList('a') to get all the items. (Side step: Lists in Python are like CFML arrays not a string list.) And I wouldn't call getList() all the time to "solve" the issue because that method guarantees a list be returned and I wouldn't want to work with a list for each parameter.
You still have to think that the parameter has multiple values in Django and call the right methods otherwise you just get the last value in the items (which could be disastrous) . The only difference is CFML gives you them all up front instead of having to deduce if you need to call getList() like in Django for all the items. To me, six of one / half dozen of another. Same result because you have to know if you should be expecting multiple items.
While you may be correctly handling GET/POST so that your apps are not vulnerable to cross-site attacks, there will almost certainly be readers of your blog that don't get that (yet). To casually say that they should be treated as equivalent, without adding the appropriate caveat, is then dangerous.
@Rick,
But, for security sake, they should be treated equivalently. Their input should be equally untrusted. I don't see a reason to differentiate for functionality or for security.
Peter,
My point was that with CFML's processing, you can't determine whether the example request had three instance of the 'a' parameter (one of which contains a comma) or four instances of the 'a' parameter, none of which contain commas. Or for that matter, a single instance of 'a' containing three commas. With the request parameter method you CAN make that distinction. ServletRequest's getParameter() and getParameterValues() correspond exactly to QueryDict's getItem() and getList().
The point is that CFML's processing destroys information within the CFML environment. You usually don't care about it, but still destroys info. When it DOES matter you can still get back that information from the underlying Servlet container.
@Barney, I see your point on "damaged" data. There is a flip side in Django. Since you still don't know which parameter names have multiple data calling queryDict.getItem('a') will just return the last value and you'd never know that there was multiple values. So the CFML argument is you don't know if one of the parameters has a comma in it and therefore the "list" is contaminated (or just don't don't use commas as values). In Django, you don't know its a list unless you loop over every parameter using getList('a') and seeing if it is an Python list (akin to CFML array).
Barney, one way around this is Railo's url array notation.
This:
page.cfm?a[]=1&a[]=2&a[]=3,4
Is equivalent to:
a = Array( '1' , '2' , '3,4' )
Works for form variables also.
As well as capturing comma values safely, this can also be used to avoid manually building an array from sequentially named form fields.
Peter,
Nice! That's the same way PHP does it, but I didn't know it worked on Railo as well.
your solution works unless the form is post as multipart. then you don't have access to getParameterValues(). i'm dealing with this problem right now and if anyone has any suggestions, PLEASE post them here or at stackoverflow: http://stackoverflow.com/questions/2194442