users@jersey.java.net

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

From: Michal Gajdos <michal.gajdos_at_oracle.com>
Date: Thu, 04 Oct 2012 13:21:04 +0200

Hi Jeff,

I guess the main reason this check is present in Jersey code is the
following paragraph from RFC1341, section 7.2:

The only header fields that have defined meaning for body parts are
those the names of which begin with "Content-". All other header fields
are generally to be ignored in body parts. Although they should
generally be retained in mail processing, they may be discarded by
gateways if necessary. Such other fields are permitted to appear in body
parts but should not be depended on. "X-" fields may be created for
experimental or private purposes, with the recognition that the
information they contain may be lost at some gateways.

 From my understanding headers other than "Conten-*" should be permitted
as well so the check is unnecessary. I've filed a bug ([1]) targeted for
Jersey 1.15.

[1] http://java.net/jira/browse/JERSEY-1448

thanks,
Michal

On 10/3/12 5:50 AM, Jeff Hagen wrote:
> 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