CFML Request Parameters

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.

10 responses to “CFML Request Parameters”

  1. Rick O

    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.

  2. Peter J. Farrell

    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.

  3. Rick O

    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.

  4. Jason Dean

    @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.

  5. Peter J. Farrell

    @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).

  6. Peter Boughton

    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.

  7. tony petruzzi

    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