jax-ws change Content-type to Content-Type because server is hyper sensitive

18,268

Solution 1

I have to connect to a poorly implemented server that only understands Content-Type(capital-T) and not Content-type. How can I ask my jax-ws client to send Content-Type?

I've dug this question a bit more and, sadly, I'm afraid the answer is: you can't. Let me share my findings.

First, the code that you'll find in https://jax-ws.dev.java.net/guide/HTTP_headers.html does not give you access to the HTTP headers of the future HTTP request (that hasn't been created at this point), it allows you to set additional HTTP headers for making a request (that will be added to the HTTP request later).

So, don't expect the following code to not return null if you don't put anything before (and actually, you'll only get what you put in there):

((BindingProvider)port).getRequestContext().get(MessageContext.HTTP_REQUEST_HEADERS);

Then, I did a little test based on the code provided in the same link:

AddNumbersImplService service = new AddNumbersImplService();
AddNumbersImpl port = service.getAddNumbersImplPort();

((BindingProvider)port).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,
    Collections.singletonMap("X-Client-Version",Collections.singletonList("1.0-RC")));

port.addNumbers(3, 5);

And this is what I see in the HTTP request when running the client code:

POST /q2372336/addnumbers HTTP/1.1
Content-type: text/xml;charset="utf-8"
X-client-version: 1.0-RC
Soapaction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: JAX-WS RI 2.1.6 in JDK 6
Host: localhost:8080
Connection: keep-alive
Content-Length: 249

Do you notice the difference: only the first char of the X-Client-Version header is kept upper cased, the rest is lowered!

And indeed, if you check the class c.s.x.w.t.Headers that is used to represent HTTP request (and response) headers, you'll see that it "normalizes" keys when they are added (in normalize(String)):

/* Normalize the key by converting to following form.
 * First char upper case, rest lower case.
 * key is presumed to be ASCII 
 */
 private String normalize (String key) {
     ...
 }

So, while the c.s.x.w.t.h.c.HttpTransportPipe class (my understanding is that this is where the HTTP request is created, this is also where previously added headers will be added to the HTTP request headers) actually adds "Content-Type" as key in a c.s.x.w.t.Headers instance, the key will be modified because of the previously mentioned implementation detail.

I may be wrong but I don't see how this could be changed without patching the code. And the odd part is that I don't think that this "normalizing" stuff is really RFCs compliant (didn't check what RFCs say about headers case though). I'm surprised. Actually, you should raise an issue.

So I see three options here (since waiting for a fix might not be an option):

  • Patch the code yourself and rebuild JAX-WS RI (with all the drawbacks of this approach).
  • Try another JAX-WS implementation like CFX for your client.
  • Let the request go through some kind of custom proxy to modify the header on the fly.

Solution 2

You can modify the HTTP headers from the RequestContext. If you have access to the port object you can cast it to a javax.xml.ws.BindingProvider, which will give you access to the RequestContext.

You might also want to remove the unaccepted "Content-type" header.

This page shows how to do it in a bit more detail: https://jax-ws.dev.java.net/guide/HTTP_headers.html

Let me know if you need more code samples, or if you paste some of your code I can show you how to modify it.

Share:
18,268
Esben Skov Pedersen
Author by

Esben Skov Pedersen

.NET developer in the Copenhagen area.

Updated on June 05, 2022

Comments

  • Esben Skov Pedersen
    Esben Skov Pedersen about 2 years

    I have to connect to a poorly implemented server that only understands Content-Type (capital-T) and not Content-type. How can I ask my JAX-WS client to send Content-Type?

    I've tried:

    Map<String, List<String>> headers = (Map<String, List<String>>)
    ((BindingProvider)port).getRequestContext().get(MessageContext.HTTP_REQUEST_HEADERS);
    

    But headers is null. What am I doing wrong?

  • Esben Skov Pedersen
    Esben Skov Pedersen over 14 years
    I've used the custom proxy for now... Ugly as hell and would like to remove this ugly mofo from my code. Oh well. C'est la via
  • Devanshu Mevada
    Devanshu Mevada over 14 years
    @EsbenP If you raise an issue for this, please update the question with the link. I'd really like to get some feedback from JAX-WS RI developers on this.
  • Junchen Liu
    Junchen Liu about 7 years
    the link is broken, also I tried msg.getMimeHeaders() then removeHeader or addHeader even removeAllHeaders nothing works, the vector backs the headers seems immutable