In the spring of 2011, we added an event to the WebApplication class called HandleSpecialURL which was intended to give developers a way to create their own API endpoints within a web app, and we mostly succeeded…
Now I really hate changing things which will almost certainly break user code, but every once in a while a fundamental flaw is found, and fixing it means doing just that. Unfortunately this is one of those times.
The Bug
If you’ve done any work with HandleSpecialURL, you probably know that we’ve been trying to make the QueryString and Entity data show up in the right places in the Request object for years. Data was either being omitted, corrupted, replaced or swapped between the properties. While sometimes the answer was to change the MIMEType on the request side, that doesn’t work if you don’t control the request (like a callback from another service).
The Flaw
Until 2014r2, we were routing requests to HandleSpecialURL through a parsing routine which the web framework uses internally for parsing the entity portion of a POST request. The problem was that it was guessing, based on the supplied MimeType, at how it should parse the data, destroying the original data and if it decided that it contained key/value pairs, it would sometimes overwrite some or all of the QueryString properties. If you’ve run into this problem, you know that there’s really no workaround.
The Change
Starting in 2014r2.1, we have disabled the Entity parser for URLs which trigger the HandleSpecialURL event. This means that QueryString data will be accessed through the GetParameter method just like before, but you will need to parse the Entity data yourself. If you were relying on key/value pairs, you can still get them by simply splitting the data on “&”, splitting each pair on “=”, and then calling DecodeURLComponent on each of the values and push each key/value into a dictionary. Keep in mind that it is perfectly legal for an Entity to contain duplicate keys (something that our parser didn’t handle), so you may need to come up with a way to store more than one value per key (a JSONItem would work for this as long as you remember that keys are case-sensitive).
Dim varsTemp() as String = Split(Request.Entity,"&") dim vars as new dictionary For i as Integer = 0 to ubound(varsTemp) dim key as string = nthField(varsTemp(i),"=",1) dim value as string = nthField(varsTemp(i),"=",2) vars.value(key) = value Next i
We believe this change is the best all around solution as it gives you full control over what is done with the data, how conflict resolution is handled as well as creating a consistent experience whenever data is received via the QueryString and Entity portions of an HTTP request. It now works the same on CGI and standalone apps as well.