Avoiding IllegalStateException in Java/Servlet web stack - java

I don't know, but I feel that IllegalStateException is causing undo headache. If I have a request say a JSP or some other servlet and need to associate a filter with that request. I can't do any other modifications to the output to the client if the response has already been committed?
For example, I see in JSP code that sets the mimetype to response.setContent("html") and then I have a filter associated with the JSP that needs to set the mimetype to something
else. setContent("image") or "xhtml". But I get an IllegalStateException?
Is there a way to clear the previous response that has been committed or is there something to avoid this issue.
This is on websphere.

I think you need to rethink how you're preparing and returning your responses. You can't write to the response (which may write to the client) and then change your mind.
Leaving aside the question of why your solution has to change the return type, I would write to some dummy container object with the return date + type, and make this mutable. Only once your servlet has completed all its work would you then write this object (type+content) to the outputstream.
(to clarify, I don't think servlet filters are the right approach for this. They will intercept the request, and the response, but the response population is the responsibility of the servlet)

I agree with the other posters that this is ugly but you can create an HttpServletResponseWrapper in your filter that would hijack the output and pass that wrapper to the chain instead of the original response object.

Your premise to execute a jsp outputting HTML and then have a filter changing the content type to something else like image all in the same response makes no sense. A response can only return a single artefact be it a HTML file or image. There is no way to return both within the same response- any attempt to do so is nonsense . It makes no sense to send some HTML with image binary tacked on the end. The content type is for the entire response. You cannot package multiple thingos in the one response.
Sometimes you can resetBuffer() if the output as not exceeded the buffersize. The best approach is to avoid this facility and deyermi e what to do before you start outputting a response..

Related

Accessing InputStream of x-www-form-urlencoded ServletRequest [duplicate]

This question already has answers here:
How to read request.getInputStream() multiple times
(6 answers)
Closed 5 years ago.
When you try to access the raw InputStream of a x-www-form-urlencoded servlet request, the stream could have already been indirectly consumed by a prior access to the parameters (e.g., via ServletRequest#getParameterMap()) of the request. This feature (bug?) has already been documented in the section SRV.3.1.1 of the Servlet spec and there are other people who have been bitten by this as well.
This indirect stream consumption makes it, to the best of my knowledge, impossible to mirror the InputStream, which is exactly what we are trying to achieve in HRRS. Hence, I try to re-construct the InputStream from request parameters. This, as you can imagine, a really nasty hack which I am not fond of either. Further, to make the things worse, when servlet pushes the form parameters into request parameter map, it merges them with query parameters too. Now you need to manually parse both request and query parameters to figure out the initial form parameters. A total shipwreck.
Any ideas on how to replace this hack with a proper solution?
Edit: Dear SO Java-badge owners, this is not a duplicate question. Please see the Tomcat bug report before marking the post as duplicate.
Even if HRRS is the first filter in the list, it is not consuming InputStream, it is just wrapping the InputStream and passing along the wrapped request along the chain. Problem is, getParameter() calls in Tomcat is using an internal reference to the InputStream (that is, o.a.c.connector.Request#getStream()) and not calling javax.servlet.ServletRequest#getInputStream(). Hence, InputStream gets indirectly consumed without the wrapped one getting used at all. (See o.a.c.connector.Request#readPostBody() source code for details.)
I don't think it is possible to completely recreate the original request in all cases. The order of request parameters will be lost for example.
For a tool like this I think it is perfectly acceptable to expect to be the outermost filter. That way you shouldn't have the problem in the first place. But maybe I'm missing something?

Setting Request Header in java

Is there any way to modify or set-header of request inside action class? I want to modify it or you can say i want to put flag inside request Header just like we put values in 'attribute' and parameters.
You can do this using HttpServletRequestWrapper. But it's quite dirty solution. Are there really no other ways to solve your problem?
You cannot. Request parameters returned from the servlet are unmodifiable Map. You cannot add/delete content returned from request (via servlet).
In order to set a flag, my suggestion is to store it in a session, and on another action, retrieve the flag & delete it from session.
I think you'd need to wrap the original request into a request class containing the change you wish to have.
It might be better design to have the request parameters parsed earlier in processing to such objects that make more sense to your application logic, and then set the state of those objects in the place where you now would like to modify the original header.
The answer to this depends on what problem you're trying to solve.
One of your comments suggests you're trying to test; if this is the case you have two basic options:
Use a mock request (unit-style testing).
Change the header from the client (integration-style testing).
For testing from real clients, set headers on the client side.
For mocking client interactions, you should be using some form of mock. StrutsTestCase, for example, provides MockStrutsTestCase (outside container) and CactusStrutsTestCase (inside container) classes allowing easy manipulation of request properties and characteristics.
If you are trying to open a URL connection using Java,
you can something like this What is the proper way of setting headers in a URLConnection?
If you can make requests with a browser,
You can use this Firefox plugin to add/modify any number of request headers.
https://addons.mozilla.org/en-US/firefox/addon/modify-headers/
Good Luck
You need to give more details. It sounds like you want to manipulate the request header once the server has received the request. I'm not sure I understand why you would want to do that. Modifying the response headers make sense. But not the request.
I think they only clean way you can do this is via an HttpServletRequestWrapper
Just override getHeader, getHeaders, getHeaderNames and you are good to go.

Passing a HttpServletRequest Object as a Parameter

In general, I need to upload a large file via an html form calling a servlet, and then manipulate that file with a heavy algorithm and return a xml document as a response.
This whole process takes a lot of time, so in order to avoid the browser timeout connection, I have decided to create an object (extending Thread) that will perform the time consuming process (uploading the file and manipulate it) in a different thread and that will be able to indicate the progress of the process. To do that, I need to pass the HttpServletRequest request as an argument to the object.
When I tried to parse the request parameter (I am using apache commons FileUpload), I got the following exception:
"the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is null" .
Is it possible to pass a HttpServletRequest object to an object extending Thread? if so, what is the correct practice of safely doing it?
You shouldn't. When the request object is used in the thread, the request may no longer be valid, and Tomcat might have cleaned it (hence your exception) (of course, assuming your form is indeed a enctype="multipart/form-data")
So in order to handle this properly, extract the data from the request and pass it to the new thread. Thus you won't depend on the request object - only on its contents.
Note that Servlet 3.0 adds an option for asynchronous server-side processing which seems to be a good option for you - check it out.
The error that you are getting indicates that the form on the client side may not be set up properly. Make sure that your form is defines like this:
<FORM action="YOUR_SERVLET"
enctype="multipart/form-data"
method="post">

HttpServletRequest getParameter AND getReader

I am developing a HttpServlet that handles a POST request from an application that includes parameters on the query string, and a JSON object in the body. It is not a form post, the entire body is the JSON object. I understand that I need to use HttpServletRequest.getReader() to read the body. But I also need to use HttpServletRequest.getParameter() to get the query parameters. And I understand that both can not be used.
I think the intended solution is to create a HttpServletRequestWrapper and override getReader() in such a way as to allow it to be called more than once. But I can't figure out how to do that. Or maybe this is not the intended approach. All the examples of HttpServletRequestWrapper that I can find seem to be related to creating filters and modifying the contents of the request.
Any help is greatly appreciated.
BTW, this is hosted on Google App Engine, but I don't think that will affect the solution.
I think you can implement multiple-callable getReader() in your HttpServletRequestWrapper :
save the HTTP-request body into a temporary file.
when HttpServletRequestWrapper.getReader() is called, open the temporary file.
delete the temporary file at the end of request processing.
to implement (1) and (3), ServletFilter may be useful.
I would suggest reading the query string parameters directly by parsing the query string. This way you won't touch the message body and you can use HttpServletRequest.getReader().
Parsing the query string is tricky but there it can be done safely using URLEncodedUtils from Apache Http Client package as discussed here:
Parsing query strings in Java

Need to Set HTTP Headers Conditionally on Servlet Response

I want to set HTTP headers depending on the type of response. My problem is that some reponses commit their headers before I can set mine. Any suggestions about how to handle this?
One idea is to set the response header in the response object in a filter before the servlet is called.
Another one is to provide the servlet with a response wrapper that prevents the real response from actually being committed. This might entail buffering the response body in memory.
But I think that the best approach is to modify the servlets so that they set the required headers.
Do I HAVE to buffer the entire response by providing my own outputstream to the wrapper ? Can I overwrite flush() or something like that ?
It is up to you how you implement it. The constraint is that response wrapper object must somehow arrange that the special header gets added before the writing of the response body starts. The conceptually simple way is to buffer the response body, but you could also get the response wrapper to provide an output stream / writer that adds the header before the first flush to the real response output stream / writer.
I am worried about buffering causing performance issues
Yes, well it could do, though you would need to look at the entire webapp to determine if this is significant.
From a performance perspective, the best solution is to get the servlet to set the header itself.

Categories