Issue with Jersey Multipart Libraries: Missing start boundary

Posted by & filed under , .

Teamwork concept. Isolated on white

This one had me pulling my hairs off and going crazy trying to figure it out so I thought it deserves a space on my blog 🙂 While it’s what it looks like a small fix, it turned out to be a b**ch in terms of googling for an answer as whatever combination of search terms I used I got nowhere — or at best got to a question with no answers on Stackoverflow.

Luckily my colleague Patrick Strawderman found the solution and saved us heaps of nerves and time and I’ve gone to the length of summarizing it here for future peeps who encounter the same.

The Problem

TL;DR: “org.jvnet.mimepull.MIMEParsingException: Missing start boundary” in Chrome and Safari but working in Firefox.

During testing my angular.js application which has a Java backend, while implementing a file upload I decided to go for the Angular ng-file-upload directive as it seems pretty easy to implement. It took very little to wire the code and then I ran into this issue where testing this in Firefox worked perfectly fine but switching to Chrome or Safari (both WebKit based!) I got a HTTP 400 (Bad Request) response from my local server and the error being logged server side was "org.jvnet.mimepull.MIMEParsingException: Missing start boundary". The backend is Java based and makes usages of the Jersey libraries.

I’ve checked and the form was set correctly both on client and server side and the Content-Type was correctly set (and expected on the server side) as multipart/form-data. So it was not a question of wrong setup. Even more, setting up a breakpoint in my servlet turns out that the error is thrown on the upper layer, before the request even hits me, somewhere in the Java Jersey libraries.

Explanation

During the investigation (I have employed tcpdump + Wireshark sessions) it turns out that the only difference in between the requests from Firefox and the ones from Chrome and Safari is that Firefox sends the Boundary in the HTTP headers with digits only:
Boundary=------1235545443656
whereas Chrome/Safari use something like
Boundary=------WebKitBoundary1243525
(i.e. both letters and numbers, uppercase and lowercase)

Otherwise all the browsers requests look pretty much the same. Yet the WebKit family fails with the above message.

Patrick tracked down the issue to one of the libraries pulling an older version of Apache CXF — this version idiotically goes through the headers and lowercases them! You can imagine now the rest of what’s happening: by the time the headers reach the libraries which are trying to parse the multipart/form-data request, the Boundary that was declared by the browser in the request is not found in the body of the HTTP POST request and the whole upload fails!

Solution

The solution was as simple as forcing a newer version of the Apache CXF library — in this case, the version being pulled in was one of the old apache-cxf-2.1.*; this has been discontinued by the Apache Software Foundation in version of apache-cxf-3.* (which breaks binary compatibility). So I have forced upgrading this package to the latest supported one 2.7.18. A simple edit of the gradle build file to pin down this particular version and recompile and restart did the trick!

You can see Patrick’s original response (and vote for it!) on Stackoverflow: http://stackoverflow.com/questions/27403904/jersey-multipart-missing-start-boundary/35877972#35877972.