Wednesday, April 16, 2008

Passing Query Parameters over HTTP

When you start to learn HTML Forms you learn something like:

method - The HTTP method for sending data to the action URL. Default is get.
method="get": This method sends the form contents in the URL: URL?name=value&name=value.

method="post": This method sends the form contents in the body of the request.
(taken from http://www.w3schools.com)


Pretty clear, right?

But what happens when you use POST and add parameters to URL:
form action="URL?name=value&name=value" method="POST"
Will it work?
The answer is yes. It will. Some of the parameters will be passed on URL and some in the body and it will be transparent for the server side.

Is it OK? It looks like bug...
Well, it isn't bug. The HTTP spec (RFC 2616) defines HTTP url as
http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]

for all HTTP verbs. Including POST.
It's HTML spec that defines how the method POST should treat a form data: to put it in the message body and so on; and there is no problem at all to add another query params to the URL.

And what happens if you want to POST a real body? Something that isn't parameters, may be atom message to update Blogger or something?
How would the server know that the body of the message is a body and not a list of parameters?

So here are the rules:
SRV.4.1.1 When Parameters Are Available
The following are the conditions that must be met before post form data will
be populated to the parameter set:
1. The request is an HTTP or HTTPS request.
2. The HTTP method is POST
3. The content type is application/x-www-form-urlencoded
4. The servlet has made an initial call of any of the getParameter family of methods
on the request object.
If the conditions are not met and the post form data is not included in the
parameter set, the post data must still be available to the servlet via the request
object’s input stream. If the conditions are met, post form data will no longer be
available for reading directly from the request object’s input stream.
(From Servlet Specification 2.3)


In addition to these rules, the parameters are not available in case of chunking. I didn’t find this part in spec, but I tested it and it just doesn’t work.

So it as it appears, it's very difficult to get a POSTed body as parameter. You must not use chunking, you must define content type as application/x-www-form-urlencoded and you must to call any of the getParameter family of methods on the request object. Right? It looks very difficult, but it what the most of the people do by default. It was exactly what I did, when I invoked a very simple HTTP call from java application.

So for the clients the best solution, in my opinion, is always ensure that you set proper content type. That's the way you tell the server: the body cotains parameters or the body contains the real body.

For servers the solution is: always call getParameter BEFORE starting reading the body. Checking content type can be also helpful.

No comments: