The specification part

We continued the search for the reason of error described in the previous post. After some search in HTTP Specification executed by Prof. Turau: “… Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]…”

For example Accept Header:
Accept = “Accept” “:” #( media-range [ accept-params ] )

But not Content-Type Header:
Content-Type = “Content-Type” “:” media-type

The server-side implementation

Besides Nokia Bug, putting multiple Content-Type headers in one request, there is an additional error server-side. I followed the JBoss call hierarchy which is:

org.jboss.ws.server.StandardEndpointServlet#doPost(HttpServletRequest req, HttpServletResponse res);
org.jboss.ws.server.ServiceEndpointManager#processSOAPRequest();
new org.jboss.ws.server.ServletHeaderSource(HttpServletRequest req, HttpServletResponse res);
org.jboss.ws.server.ServiceEndpoint#handleRequest(HeaderSource headerSource, ServletEndpointContext context, InputStream inputStream);
org.jboss.ws.server.ServletHeaderSource#getMimeHeaders();

During the whole processing, the headers are retrieved from the HttpServletRequest by the ServletHeaderSource which is the only implementation of HeaderSource:

public MimeHeaders getMimeHeaders()
{
    Enumeration e = req.getHeaderNames();
    if(e == null)
        return null;
    MimeHeaders headers = new MimeHeaders();
    String name = null;
    for(; e.hasMoreElements(); headers.addHeader(name, req.getHeader(name)))
        name = (String)e.nextElement();

    return headers;
}

Afterwards, if you call getHeader on the MimeHeaders object the string array is constructed from the existing data and returned:

public String[] getHeader(String name)
{
    ArrayList tmp = new ArrayList();
    for(int n = 0; n < headers.size(); n++)
    {
        MimeHeader mh = (MimeHeader)headers.get(n);
        if(mh.getName().equalsIgnoreCase(name))
            tmp.add(mh.getValue());
    }

    String values[] = null;
    if(tmp.size() > 0)
    {
        values = new String[tmp.size()];
        tmp.toArray(values);
    }
    return values;
}

This means, that the implementation of the HttpServletRequest returns concatinated list of values for the duplicate headers.

Specifications again

Now, I looked in Java Servlet Specifications about the getHeader method:

Servlet 2.1

Returns the value of the requested header. The match between the given name and the request header is case-insensitive. If the header requested does not exist, this method returns null.

Servlet 2.2

The getHeader method allows access to the value of a header given the name of the header. Multiple headers, such as the Cache-Control header, can be present in an HTTP request. If there are multiple headers with the same name in a request, the getHeader method returns the first header contained in the request.

Servlet 2.3 and 2.4

The getHeader method returns a header given the name of the header. There can be multiple headers with the same name, e.g. Cache-Control headers, in an HTTP request. If there are multiple headers with the same name, the getHeader method returns the first head in the request.

Results

So it seems to be a Tomcat Bug, as long as Tomcat provides the implementation for the HttpServletRequest… This bug is integrated in JBoss, because they use Tomcat implementation. Never the less, JBoss use the getHeader method relies on the correct implementation.