Thursday, January 27, 2011

HttpClient 4: Want To Make It 250x Faster?

I just spent a few hours debugging a performance problem with my app. It came down to a default setting inside Apache HttpClient 4.0.3.

Don't get me wrong, HttpClient is an awesome piece of work and a fantastic contribution to the community - I use it in lots of my projects and it's very useful. So my thanks to the HttpClient team for all their hard work.

However, by default HttpClient 4.0.3 adds a...

Expect: 100-continue

...header to every POST request. This appears to interact badly with Tomcat's (and JBoss', and possibly other containers) FormAuthenticator. Specifically somewhere around...

request.getParameter( Constants.FORM_USERNAME )

...FormAuthenticator disappears into a hole (during Request.parseParameters) for some 2 seconds before emerging with the parameters. It appears to be 'lazy loading' the request body during this time? According to the HTTP spec the header "allows a client that is sending a request message with a request body to determine if the origin server is willing to accept the request before the client sends the request body".

If you're using HttpClient to log in to your Java EE server (say, for black box testing) this can be a significant performance hit. Removing the Expect header logs you in in about 8ms, some 250 times faster.

You can remove the Expect header by doing:

client.removeRequestInterceptorByClass( RequestExpectContinue.class );

I've put together a sample WAR to reproduce the problem, along with deployment instructions, under this issue here.

Update: it appears this is actually a bug in Tomcat 6. Now tracking under this issue here.