users@jersey.java.net

[Jersey] multipart.BodyPart only allowing headers that start with Content-*

From: Jeff Hagen <jeff.hagen_at_oracle.com>
Date: Tue, 2 Oct 2012 20:50:26 -0700

Hi,

I'm working on a servlet in Jersey (1.14) which returns Multipart/Mixed content to the client. One of the things I would like to do is stamp bodies within each multipart message with an Etag.

The issue I am running into it that it seems that the multipart.BodyPart component seems to be written to only allow custom headers that start with "Content-", despite me not being able to find that requirement in the RFC.

I do not see anywhere in the RFC where it says that headers in a body part must start with "Content-". Am I missing the portion of the RFC somewhere, or have I discovered a bug?

Details follow:

I would like to do something like this (this has been marked up by hand so it might be inconsistent):

$ curl -v http://localhost:9090/Server/data
* About to connect() to localhost port 9090 (#0)
* Trying ::1...
* connected
* Connected to localhost (::1) port 9090 (#0)
> GET /Server/data HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:9090
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< MIME-Version: 1.0
< Content-Type: multipart/mixed; boundary=Boundary_3_292152454_1349234105097
< Transfer-Encoding: chunked
< Date: Wed, 03 Oct 2012 03:15:05 GMT
<
--Boundary_3_292152454_1349234105097
Etag: item1
Content-Encoding: utf-8
Content-Type: text/plain

this is item 1
--Boundary_3_292152454_1349234105097
Etag: item2
Content-Encoding: utf-8
Content-Type: text/plain

this is item 2
--Boundary_3_292152454_1349234105097
Etag: item3
Content-Encoding: utf-8
Content-Type: text/plain

this is item 3
--Boundary_3_292152454_1349234105097--
* Connection #0 to host localhost left intact
* Closing connection #0


Here is the core dump I get when I try to do this in Jersey:
javax.ws.rs.WebApplicationException: java.lang.IllegalArgumentException: Invalid body part header 'Etag', only Content-* allowed
        at com.sun.jersey.multipart.impl.MultiPartWriter.writeTo(MultiPartWriter.java:174)
        at com.sun.jersey.multipart.impl.MultiPartWriter.writeTo(MultiPartWriter.java:71)
        at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306)
        at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1448)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1350)
        at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


The code at that line in MultiPartWriter.java says:
 //Only headers that match "Content-*" are allowed on body parts
 if (!entry.getKey().toLowerCase().startsWith("content-")) {
   throw new WebApplicationException(new IllegalArgumentException("Invalid body part header '" + entry.getKey() + "', only Content-* allowed"));


RFC 2046 says the syntax for a body-part is:
     body-part := <"message" as defined in RFC 822, with all
                   header fields optional, not starting with the
                   specified dash-boundary, and with the
                   delimiter not occurring anywhere in the
                   body part. Note that the semantics of a
                   part differ from the semantics of a message,
                   as described in the text.>

This was taken from the BNF grammar for a multipart message. It simply says that I can not use a custom header that starts with the same dash boundary used in the multipart MIME format. If I were able to specify my own dash boundary I could make sure that it does not match, however I do not see a way of doing this.

Even if I were able to specify my own boundary it seems though that the writer is put together in a way that will still prevent me from using any header that does not start with "Content-". Even disallowing any header that starts with "Boundary" would be much improved over only allowing starting with "Content-".

Any assistance would be appreciated.

I am not subscribed to the mailing list so please CC me directly in any response.

Thanks!
-Jeff Hagen
jeff.hagen_at_oracle.com