I have a web service that, when called, may or may not send a body back with the response. For some reason, whenever there is no data the Content-Length header is present, but when I send back a body, a Transfer-Encoding: Chunked header is present instead of the Content-Length header. The request being sent up is, in fact, chunked, but i don't necessarily need the response to be as we want the payload to be a small as possible.
As the following code illustrates, I have tried forcing the content length when data is sent back, but even so, the response still does not have a Content-Length header. I have read that the existence of a Transfer-Encoding: Chunked header will override any COntent-Length header, but I can't figure out how to remove the Transfer-Encoding header, or even why it is there in the first place.
Here is the my callback for a new request:
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setStatus(200);
String mac = req.getHeader("x-kcid");
String cmd = getCache(mac);
if (cmd != null) {
writeToStream(resp, cmd, "text/plain");
clearCache(mac);
}
}
and here is the method that actually writes the response:
private static void writeToStream(HttpServletResponse resp, String msg, String contentType) throws IOException {
resp.setContentType(contentType);
resp.setContentLength(msg.getBytes().length);
resp.getWriter().write(msg);
}
GAE doesn't allow setting the Transfer-Encoding or Content-Length header.
(That headers, and some others are ignored and removed from the response).
Related
When using apache-httpclient-4.x's HttpClient class to process a URL that returns gzip compressed response, there's no "Content-Encoding" header in the response we get. However, if you visit the URL directly in the browser you can get the header.
It seems there's some step that deletes some headers while processing the compression.
https://github.com/apache/httpcomponents-client/blob/73e72f226845c790e4a6e6dccaed50ee32791f45/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java#L124
if (decoderFactory != null) {
response.setEntity(new DecompressingEntity(response.getEntity(), decoderFactory));
response.removeHeaders("Content-Length");
response.removeHeaders("Content-Encoding");
response.removeHeaders("Content-MD5");
}
How can we keep the headers?
I'm making an ajax post request, and i can see the value is being passed in the headers on the client side.
However on the server side the value received is blank? The server seems to be choking on something in the value when it tries to parse it. Because if i use encodeURIComponent it works fine. What is causing this behaviour?
<script>
//var body = getDataFromTheEditor(); //doesn't work
//var body = JSON.stringify(getDataFromTheEditor()); //doesn't work
var body = encodeURIComponent(getDataFromTheEditor()); //works but don't want to do this...
var params = {body: body};
$.post("../../../../CommitEdit", $.param(params));
</script>
Servlet:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String body = request.getParameter("body");
System.out.println(body); //blank if i pass it normally :(
}
I've copied the formdata directly from the header as it is being passed (so there's something in here which the server doesn't like apparently):
pastebin - unparsed formdata
pastebin - parsed formdata
Relevant request headers:
Content-Length: 64488
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Any ideas? Thanks.
It maybe caused because of some security rules in the web server settings.
You can decode your data in Java using this:
String res= java.net.URLDecoder.decode(body, "UTF-8");
The problem was because the string was too long. Apparently the console in Eclipse has a character limit. Which is why i was seeing a blank value. This question here helped solve the issue:
Character limit for System.out.println() in Java
The solution is to:
Go to Window > Preferences > Run/Debug > Console
Uncheck "Limit Console Output" (Alternatively you can increase the Console buffer size.)
I have a Java filter that allows continue or not the request depending of the URL, however I have a problem when the request come from a form.
Let's say I have a HTML form with an action and a submit button, then the filter evaluate the request, if the request is invalid I need to stop the request:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String requestDestination = ((HttpServletRequest) servletRequest).getRequestURI();
if ( requestDestination.contains("/url") ) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
Cookie denied = new Cookie("denied", "url");
httpResponse.addCookie(denied);
return;
}
}
The problem is that despite this action, the browser goes to this URL showing an empty page off course, but what I need is to stop this default behavior, just leaving the user in the same page.
I can't use JavaScript since I don't know exactly who is triggering the request.
You cannot "stop" the request. Once the browser has submitted the form, it will await a response and will render the content of that response body.
Thus if your servlet filter is blocking the request, it is the responsibility of your filter to also return appropriate content to the browser. This is typically some type of error page, the content of which is entirely up to you.
If you want to make the user return back to the previous page, you can try redirecting the user to the url taken from the Referer header:
if ( requestDestination.contains("/url") ) {
String referer = request.getHeader("Referer");
if (referer != null && referer.length() > 0) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(referer));
} else {
// just do nothing and display a blank page if there is no Referer
}
}
But for this to work, you need to be sure that the 'previous page' always accepts such a duplicated request using GET method.
It's not possible to do on server side -- because whatever server response is (and there is always a response, even for stopped requests), your browser will display it. Like empty response in your example.
There only thing you can try to archieve without JavaScript is to show user the same page he comes from:
you can just display the same page he comes from (with form, etc.)
you can redirect user to the same page with httpResponse.sendRedirect(httpRequest.getRequestURI())
Getting some weird behavior here when using the following spring filter.
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("cache-control", "no-store");
response.addHeader("pragma", "no-cache");
filterChain.doFilter(request, response);
}
It is configured in XML as well, and I know it works, because when I send a request, I am always able to see the "pragma" header in there, no matter what happens.
But the interesting thing here, is that when I hit this from curl - I get the following headers back :
Date: Wed, 19 Apr 2017 20:45:48 GMT
Pragma: no-cache
WWW-Authenticate: Basic realm="Spring Security Application"
Content-Type: text/html
Transfer-Encoding: chunked
Server: Jetty(9.2.10.v20150310)
But whenever I make the same request via a rest client (such as postman) I see the following headers : Image posted here because I am not allowed to embed images on stackoverflow just yet.
Any idea why this would happen?
EDIT FOR FURTHER INFORMATION : I also see both headers in the network section of developer tools if I hit this from a browser. No idea why it wont appear in curl.
ALSO, I cannot use an interceptor for this as management have decided they don't like them.
In my code I use some Http Get request to download some files as a stream. I use the following code:
public String getClassName(String url) throws ClientProtocolException, IOException {
HttpResponse response = sendGetRequestJsonText(url);
Header[] all = response.getAllHeaders();
for (Header h : all) {
System.out.println(h.getName() + ": " + h.getValue());
}
Header[] headers = response.getHeaders("Content-Disposition");
InputStreamParser.convertStreamToString(response.getEntity().getContent());
String result = "";
for (Header header : headers) {
result = header.getValue();
}
return result.substring(result.indexOf("''") + "''".length(), result.length()).trim();
}
But this downloads the full content of the response. I want to retrieve only the http headers without the content. A HEAD request seems not to work because then i get the status 501, not implemented. How can I do that?
Instead of making a GET request, you might consider just making a HEAD request:
The HEAD method is identical to GET except that the server MUST NOT
return a message-body in the response. The metainformation contained
in the HTTP headers in response to a HEAD request SHOULD be identical
to the information sent in response to a GET request. This method can
be used for obtaining metainformation about the entity implied by the
request without transferring the entity-body itself. This method is
often used for testing hypertext links for validity, accessibility,
and recent modification.
You might be able to use the Range header in your request to specify a range of bytes to include in the response entity. Possibly something like:
Range: bytes=0-0
If it does work, you should receive back a 206 Partial Content with the bytes specified in your Range header present in the response entity. However, I've not tried this, and it's also not guaranteed to work:
A server MAY ignore the Range header.