Content-Length-Header not set in Jersey Client request - java

I'm using Jersey Client to access a webservice, like this:
response =
r.accept(MediaType.TEXT_PLAIN_TYPE).header("content-length", 0).post(String.class);
where r is a WebResource
However, the Webservice returns 411 - Content-Length is missing.
using tcpdump, i found out that i am able to specify custom headers, i.e. .header("myheader", 0) works fine.
So it seems that jersey is deleting the content-length header for some reasons.
Anyone has any ideas?

I actually had a requirement to use an empty POST request for a Restful webservice.
If you specify an empty string as the second parameter of post method, Jersey will create the Content-Length header with the value of 0.
e.g.
response = r.accept(MediaType.TEXT_PLAIN_TYPE).post(String.class, "");

The content length of a call is computed by Jersey Client, it cannot be set.
Paul Sandoz — a well known commiter on the project — have answered a similar question:
Q: I think that "Content-Length"
header is not being set automatically.
A: The Jersey runtime [...]
determine the length of content.
If you need further informations, please explain what result did you expect from POSTing a String to a Resource with an empty size.

Related

How do I modify the HTTP response code and message in java

My goal is to modify the http response status code and the content that comes with it (not using spring by the way). The current response I'm getting is an HTTP 501 and I would like to modify that response to return an HTTP 200 instead with a custom message.
I've tried using javax.servlet.Filter and found out that that won't work (as far as I know) since I can't modify the response after the filterChain.doFilter() call. I tried redirecting a response using httpResponse.sendError() but didn't work since I'm getting an IllegalStateException telling me about the reponse was already committed or something like that.
I've also tried adding an <error-page>...</error-page> block in my web.xml using a web servlet as the location but apparently that does not work for unsupported methods and invalid headers (tried using a random string as request method; also tried Transfer-Encoding: random as an invalid header); works for invalid uri paths though.
Is there a way to create a general "filter" mechanism where I can modify the response code and message when there's a HTTP error code response?

Jersey 'NoContent' response returns 200 instead of 204

I am using Jersey (1.18) to build a REST API for my WebApplication. In a part of my code I have the following snippet.
return Response.status(Status.NO_CONTENT).entity(err_message).build();
where Status is an instance of com.sun.jersey.api.client.ClientResponse.Status;
According to Jersey Documentation NO_CONTENT should return a 204 code, instead of this, the http response has a header with 200 code.
NO_CONTENT
public static final ClientResponse.Status NO_CONTENT
204 No Content, see HTTP/1.1 documentation.
I tried to change the aforementioned code to
return Response.noContent().entity(err_message).build();
But the issue still exists.
As a side note, using NOT_FOUND instead of NO_CONTENT, return a 404 header as expected.
Any suggestion on 'How can I return 204 code?', is this a bug or I am doing something wrong.
Note: Not a duplicate of Returning 200 response code instead of 204
See this SO answer which says,
...204 means "No Content", meaning that the response contains no
entity, but you put one in it. It's likely that Jersey is switching it
to a 200 for you, which is basically identical to a 204 except that it
contains a response entity.
Finally, you can get 204 responses very simply by a couple of built-in
behaviors: void methods and null return values both map to a 204
response. Otherwise, simply return Response.status(204).build().
In other words, if you want "NO_CONTENT" then don't include content in your response.
After a little more digging I have found the problem. The W3c Documentation gives a hint.
I am quoting
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant.
If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
In my code I have entity(err_message) which causes the problem. By removing it the 204 is returned correctly. I think somehow the Jersey or 'someone' casts the response to 200 since it has content.
Update (02/05/2015)
This blog post link (posted earlier today as an answer and then deleted), gives some additional insights about situation. Based on the content of the blog post, whenever there is any content in the HTTP response the following method is invoked. This method sets the status code back to 200.
private void commitWrite() throws IOException {
if (!isCommitted) {
if (getStatus() == 204)
setStatus(200);
   isCommitted = true;
   o = responseWriter.writeStatusAndHeaders(size, ContainerResponse.this);
}
}
We can say that Jersey detects that since there is some content in the response, the status code was wrongly set to 204 and it changes it to the appropriate 200.

How do I get Rest Assured to return the text (non-encrypted or streamed) value in my REST response?

I recently moved over to Java and am attempting to write some REST tests against the netflix REST service.
I'm having an issue in that my response using rest assured either wants to send a gzip encoded response or "InputStream", neither of which provide the actual XML text in the content of the response. I discovered the "Accept-Encoding" header yet making that blank doesn't seem to be the solution. With .Net I never had to mess with this and I can't seem to find the proper means of returning a human readable response.
My code:
RestAssured.baseURI = "http://api-public.netflix.com";
RestAssured.port = 80;
Response myResponse = given().header("Accept-Encoding", "").given().auth().oauth(consumerKey, consumerSecret, accessToken, secretToken).param("term", "star wars").get("/catalog/titles/autocomplete");
My response object has a "content" value with nothing but references to buffers, wrapped streams etc. Trying to get a ToString() of the response doesn't work. None of the examples I've seen seem to work in my case.
Any suggestions on what I'm doing wrong here?
This has worked for me:
given().config(RestAssured.config().decoderConfig(DecoderConfig.decoderConfig().noContentDecoders())).get(url)
I guess in Java land everything is returned as an input stream. Using a stream reader grabbed me the data I needed.
Until its version 1.9.0, Rest-assured has been providing by default in the requests the header "Accept-Encoding:gzip,deflate" with no way of changing it.
See
https://code.google.com/p/rest-assured/issues/detail?id=154
It works for me:
String responseJson = get("/languages/").asString();

getting Respose Header from webservice in android using Ksoap2

My webservice is in .net and I have successfully get data from Soap Response using KSOAP2 in android. I want to get Response Header and some details from the header , Can any one help how to to get Response header using KSOAP2?
> The HttpTransportSE class exposes the method call that, beyond the
> required SOAP parameters, also accepts a List of HeaderProperty
> instances. It also returns a like List. This provides the ability to
> append additional headers to the request and review the returned
> headers. Since a cookie is just one of those header, one can use this
> facility to send and receive cookies.
The response headers are returned by the "call" method. So you just need to keep track of your JSESSIONID and pass it back again for each call. I overlooked this small detail at first as well. ;)
Keep in mind that the server returns the JSESSIONID with a "set-cookie" header, but it needs to be sent with a "cookie" header.
List respHeaders = android_http.call(SOAP_ACTION, envelope2, reqHeaders);
for(int ix=0; ix<respHeaders.size(); ix++) {
HeaderProperty hp = (HeaderProperty)respHeaders.get(ix);
System.out.println("Header"+ix+"="+hp.getKey()+" / "+hp.getValue());
}

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

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?
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.
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.

Categories