Frith
Frith

Reputation: 21

Jersey ApacheConnector MultiPart file upload - no multipart boundary was found

I hope someone can help,

I've written a client to my spring webmvc app, for the client I am using jersey and the ApacheConnector. I need to keep the jsessionid and can't see how I can do that with jersey's HttpUrlConnector. I should also mention that before I needed to keep track of the session the file upload service worked with jersey's HttpUrlConnector.

I know the spring webmvc file upload service works because my web front end is able to upload a file. Just for completeness it looks like this.

@ResponseBody
private Image onSubmit(@ModelAttribute("uploadedFile") ImageUpload imageUpload) {   
        service.create(imageUpload);
        return new Image();
}

the client init code looks like this:

clientConfig = new ClientConfig();
connector = new ApacheConnector(clientConfig);
clientConfig.connector(connector);
client = ClientBuilder.newBuilder().withConfig(clientConfig)
                .register(MultiPartFeature.class)
                .register(JacksonJsonProvider.class).build();
target = client.target(url);

I've registered the MultiPartFeature and the JacksonJsonProvider as I wanted to use jackson 2.x

the client code to upload a file looks like this:

File file = new File(fileName);
FormDataMultiPart formDataMultiPart = new FormDataMultiPart();
FormDataBodyPart bodyPart = new FormDataBodyPart("file", file,
                MediaType.APPLICATION_OCTET_STREAM_TYPE);
formDataMultiPart.bodyPart(bodyPart);
response = target
                .path(path)
                .request()
                .post(Entity.entity(formDataMultiPart,
                        formDataMultiPart.getMediaType()), Response.class);

I've also tried code that looks like:

final FileDataBodyPart filePart = new FileDataBodyPart("file", new File(fileName));
         final MultiPart multipart = new FormDataMultiPart()
            .field("foo", "bar")
            .bodyPart(filePart);
response = target
                .path(path)
                .request()
                .post(Entity.entity(multipart,
                        multipart.getMediaType()), Response.class);

which closer matches the documentation.

when the file is uploaded the server responds

org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:990)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:334)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:892)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)

which seems like a fairly common problem, I assume this means I don't have a boundary set, So I enabled debugging on the client.

DEBUG: org.apache.http.headers - >> POST /api/content/image/upload HTTP/1.1
DEBUG: org.apache.http.headers - >> Content-Type: multipart/form-data
DEBUG: org.apache.http.headers - >> User-Agent: Jersey/2.3.1 (Apache HttpClient 4.3)
DEBUG: org.apache.http.headers - >> Transfer-Encoding: chunked
DEBUG: org.apache.http.headers - >> Host: localhost:8010
DEBUG: org.apache.http.headers - >> Connection: Keep-Alive
DEBUG: org.apache.http.headers - >> Cookie: JSESSIONID=2xl9hgb4zq031jpbrn07ylp10
DEBUG: org.apache.http.headers - >> Cookie2: $Version=1
DEBUG: org.apache.http.wire -  >> "7d[\r][\n]"
DEBUG: org.apache.http.wire -  >> "--Boundary_1_674530318_1380707961372[\r][\n]"
DEBUG: org.apache.http.wire -  >> "Content-Type: application/octet-stream[\r][\n]"
DEBUG: org.apache.http.wire -  >> "Content-Disposition: form-data; name="file"[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[\r][\n]"
DEBUG: org.apache.http.wire -  >> "1061[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[0x89]PNG[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[0x1a][\n]"
DEBUG: org.apache.http.wire -  >> "[0x0][0x0][0x0][\r]IHDR[0x0]  -!!!! SNIP you don't want to see this !!!!
DEBUG: org.apache.http.wire -  >> "[\r][\n]"
DEBUG: org.apache.http.wire -  >> "2a[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[\r][\n]"
DEBUG: org.apache.http.wire -  >> "--Boundary_1_674530318_1380707961372--[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[\r][\n]"
DEBUG: org.apache.http.wire -  >> "0[\r][\n]"
DEBUG: org.apache.http.wire -  >> "[\r][\n]"
DEBUG: org.apache.http.wire -  << "HTTP/1.1 500 Server Error[\r][\n]"
DEBUG: org.apache.http.wire -  << "Content-Type: text/html; charset=ISO-8859-1[\r][\n]"
DEBUG: org.apache.http.wire -  << "Cache-Control: must-revalidate,no-cache,no-store[\r][\n]"
DEBUG: org.apache.http.wire -  << "Content-Length: 13979[\r][\n]"
DEBUG: org.apache.http.wire -  << "Server: Jetty(9.0.5.v20130815)[\r][\n]"
DEBUG: org.apache.http.wire -  << "[\r][\n]"
DEBUG: org.apache.http.impl.conn.DefaultClientConnection - Receiving response: HTTP/1.1 500 Server Error
DEBUG: org.apache.http.headers - << HTTP/1.1 500 Server Error
DEBUG: org.apache.http.headers - << Content-Type: text/html; charset=ISO-8859-1
DEBUG: org.apache.http.headers - << Cache-Control: must-revalidate,no-cache,no-store
DEBUG: org.apache.http.headers - << Content-Length: 13979
DEBUG: org.apache.http.headers - << Server: Jetty(9.0.5.v20130815)
DEBUG: org.apache.http.impl.client.DefaultHttpClient - Connection can be kept alive indefinitely
DEBUG: ws.webraw.jsonrest.JsonRestClient - reponse code : 500

I was expecting not to see the --Boundary entries. I can only assume something went wrong with the entity encoding when using the ApacheConnector.

Any Help greatly appreciated!

Upvotes: 2

Views: 3923

Answers (2)

lmika
lmika

Reputation: 1755

Try changing the second parameter of post call with a call to MultiPartMediaTypes.createFormData(). This should create a new MediaType instance with a configured boundary, which will be picked up by the MultiPart writer.

target
    .path(path)
    .request()
    .post(Entity.entity(multipart,
                    MultiPartMediaTypes.createFormData()), Response.class);

Upvotes: 7

Uriah Carpenter
Uriah Carpenter

Reputation: 6726

This is a known issue in all of the Jersey connector implementations; the associated bug is JERSEY-2123. A refactoring to fix this issue is being tracked in JERSEY-2341.

The current recommended workaround is to simply use the default implementation of ClientBuilder which uses java.net.HttpUrlConnection and correctly adds the required boundary value to the Content-Type header.

Upvotes: 3

Related Questions