Servlet Response Wrapper ignored for static content - java

I've created server filter, that counts response size. It does that by creating response wrapper, which wraps ServletOutputStream with Apache Commons CountingOutputStream. Also, wrapper creates PrintWriter with wrapped stream. So in theory, whatever method would be used to create actual output, it should go through CountingOutputStream.
The problem is that, while whole thing works for typical servlet requests, it fails for static content. To be precise, the request is being picked up by filter, response wrapper is created and chain.doFilter() called. However when it returns, the wrapped stream claims no data was sent, while in reality data was sent. After further debugging it appears that during serving static content neither getOutputStream() nor getWriter() are called on the response wrapper.
The filter and app are running on Jetty 8.1.x. I've skimmed through Jetty's default servlet and it appears static content is being served in the usual way (that is by obtaining output stream and writting to it).
So the question is: Why the wrapper methods are being ignored?

Are you sure you disabled all cache mechanisms?

The problem turned out to be me expecting something not really possible. I was making a request to non-existent static resource. I still expected some data to go through filter, because http client was getting bunch of headers and my filter was reporting 0 bytes which simply felt wrong. However, it turned out that filters only do see raw data produced by servlet (or in case of static content and jetty - handler). They can't see headers as they are added later by the server, when all of the app code was already executed. While I'd like to have total response size (headers and content) it appears I have to settle down with only content beng measured.

Related

JSP error page appended to previous output

I have a Spring MVC project where I am using controller advice to handle errors thrown in controllers. However, I also want to display a nice error page if an error occurs within JSP files (even though this really shouldn't happen!). Therefore I have added the following to my project's web.xml file:
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/views/application/error/view-error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/views/application/error/view-error.jsp</location>
</error-page>
If I trigger an error in JSTL on purpose, the contents of view-error.jsp is rendered fine. However, the content is appended to the output of the JSP file in which the error occurred. For instance, if an error occurs within display-users.jsp at line 50, the result is that the output that was generated before the error occurred (line 1-50) is prepended the contents in view-error.jsp.
This is very undesirable as it generates a funky looking error page. And since I cannot tell where an exception will be thrown (if I could, I would fix the error), then what the user sees is very likely to look bad.
I guess it's because the output is already in the buffer, and may already have been sent to the client? Is there any way I can fix this, or perhaps an alternative approach? Thanks!
This is a problem with large JSP generating big HTML, with scriptlet java code intermixed everywhere. As soon as enough data have been writen, the server commits the headers (sends them to client) and send the beginning of the page. At that moment, you can no longer rollback anything to get back the data that has already been received (and possibly displayed) by the browser.
That's one of the reasons why scriplet are not recommended, and if you really need to put some intelligence it the JSP, it should be at the beginning of the page before anything is actually sent to browser. But ideally, everything should have been computed in advance in a servlet and prepared data put in request attributes. That way the JSP should only contain simple conditionnal or loop tags in addition to HTML output and request attributes rendition. All that with little risk to generate an exception.
Looks like the OutputStream of the HttpServletResponse is being written to before the enitre JSP finishes rendering.
This ideally should be controllable by "autoflush" property. https://tomcat.apache.org/tomcat-5.5-doc/jspapi/javax/servlet/jsp/JspWriter.html
But just in case it isn't solvable by that:
You could intercept anything that written to HttpServletResponse by using the HttpServletResponseWrapper approach.
The general idea there is that you create a Filter and that Filter will pass a "Response Wrapper" to the layers below. This Response Wrapper holds a reference to real Response instance. Anything that gets written to the Response, can be then manipulated by the Response Wrapper and then sent to the real Response instance.
So, for your case, you could append all the data in a StringBuilder, and when then controls returns back to the Filter, the Filter can print the entire StringBuilder to the real Response's OutputStream.
Here is an example that intercepts anything the Servlets, etc. write and then sends the GZipped version of that to the Browser:
http://tutorials.jenkov.com/java-servlets/gzip-servlet-filter.html
Been there, done that. Here's a quick and dirty workaround until you can redesign.
1) Place the all the JSTL code that generates output in a new JSP -- let's call it display-users-view.jsp (call it whatever you want).
2) Import display-users-view.jsp from your display-users.jsp page via a <c:import>, but make sure you dump the contents to a var(!). e.g.:
<c:import url="display-users-view.jsp" var="output"/>
3) As a final step in display-users.jsp, dump the output to the screen with a simple:
${output}
Now, if the error is thrown before the ${output} .. no harm, no foul because you haven't output anything to the browser yet. If there is no error, the ${output} will dump the HTML that was generated in the display-users-view.jsp.
Note, by using c:import you don't have to pass any querystring or form params that were submitted to display-users.jsp because you will still have them available in your display-users-view.jsp.

RequestDispatcher.include() from custom tags and IllegalStateExceptions

In a custom tag, I want to include other things through the RequestDispatcher:
RequestDispatcher rd = request.getRequestDispatcher(url);
rd.include(request, response);
but I can not know the state of the response's output stream. I am currently working around this by wrapping the response and the JspWriter available to the tag in another object that implements HttpServletRequest. when there is a call to getWriter() inside, this works fine. But if code handling the request actually wants to get the raw OutputStream (which i cannot safely get within the tag, either), I get an IllegalStateException (because getOutputStream() has already been called).
Now I could ALSO create a new OutputStream and wrap it up in my request wrapper, buffer it until the include() returns, and then get the bytes written into it and write them to the JspWriter.
My question, however, is this: should I try to maintain character encodings? as in: should I "mock" even more of the response object so I can at least try to do a conversion from the character encoding set in the request wrapper I pass into the include and the underlying outputstream? Would this be "clean enough"? Are there any utility classes I should look into?
You cannot use both getServletOutputStream() and getWriter() in same response.
I think somewhere in your code you are using getServletOutputStream() and including JSP's uses getWriter(). This is causing you the exception.
Please see the duplicate question.
java.lang.IllegalStateException: Already using output stream

How to configure HTTPServer to use content length and not transfer encoding: chunked?

I'm using java's HTTP Server object with web service implemeted by WebServiceProvider.
I see that no matter of the client request, the answer is chunked and i need it to be with content length.
so i'm assuming the problem is in the server and not the web server provider, right?
and how can i configure the http header to use content length and not chunked?
HttpServer m_server = HttpServer.create();
Endpoint ep= Endpoint.create(new ep());
HttpContext epContext = m_server.createContext("/DownloadFile");
ep.publish(downloadFileContext);
I assume you're talking about the com.sun.net.httpserver HTTPServer. I further assume that you're connecting the server to the service with a call to Endpoint.publish, using some service provider which supports HTTPServer.
The key is in the HttpExchange.sendResponseHeaders method:
If the response length parameter is greater than zero, this specifies an exact number of bytes to send and the application must send that exact amount of data. If the response length parameter is zero, then chunked transfer encoding is used and an arbitrary amount of data may be sent. The application terminates the response body by closing the OutputStream.
So, as long as the handler is passing a positive value for responseLength, Content-Length is used. Of course, to do that, it will have to know how much data it is going to send ahead of time, which it might well not. Whether it does or not depends entirely on the implementation of the binding, i'm afraid. I don't believe this is standardised - indeed, i don't believe that the WebServiceProvider/HTTPServer is standardised at all.
However, even if your provider is uncooperative, you have a recourse: write a Filter which adds buffering, and add it to the HttpContext which you are using to publish the service. I think that to do this, you would have to write an implementation of HttpExchange which buffers the data written to it, pass that down the filter chain for the handler to write its response to, then when it comes back, write the buffered content, setting the responseLength when it does so.

Servlet 3.0 include html page

I'm trying to achieve the following behavior using the Servlet 3.0 API:
send an inital html page
send subsequent responses that update the page
This all works except the only way I could send the initial page without getting the response committed is by manually writing using the HttpResponse Writer...
I was wondering if there is a way of using something similar to RequestDispatcher#include with an html page without running into problems with the AsyncContext. Some things I tried until now and didn't work:
use AsyncContext#dispatch: as much as I read on the Internet, it is destined for sending the final response to the container in order to render it
use RequestDispatcher#forward: getting IllegalStateException due to trying to write more content in the OutputStream
use RequestDispatcher#include: if I initialize the AsyncContext before calling this method, request.isAsyncSupported returns true, after calling the method, it returns false. I read that it calls flushBuffer() and sets the commit flag to true on the response
Also, in the Servlet 3.0 spec there are some lines mentioning that dispatching from async servlet to normal servlet is possible but will commit the answer. I believe a static html page belongs to this category...
If you have any ideas of how an elegant include can be done without affecting the ability to still send streamed responses back to the client, please let me know.
Thanks
One solution (not the only one): if it's just a html page, then write the html page itself in html and do ajax calls to the serrvlet that needs to provide the updates.
use static elements on the page that store data and use requestdispatcher.
Or you could also just simply refresh the entire page with such an arrangement using response.setHeader("refresh", "5; URL=officer.html").
I really don't understand your need to send multiple requests without the response being committed to a servlet. are you trying to interact with a serving thread multiple times ?

AS2: Does xml.sendAndLoad use POST or GET?

All,
I'm trying to find out, unambiguously, what method (GET or POST) Flash/AS2 uses with XML.sendAndLoad.
Here's what the help/docs (http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002340.html) say about the function
Encodes the specified XML object into
an XML document, sends it to the
specified URL using the POST method,
downloads the server's response, and
loads it into the resultXMLobject
specified in the parameters.
However, I'm using this method to send XML data to a Java Servlet developed and maintained by another team of developers. And they're seeing log entries that look like this:
GET /portal/delegate/[someService]?svc=setPayCheckInfo&XMLStr=[an encoded version of the XML I send]
After a Google search to figure out why the POST shows up as a GET in their log, I found this Adobe technote (http://kb2.adobe.com/cps/159/tn_15908.html). Here's what it says:
When loadVariables or getURL actions are
used to send data to Java servlets it
can appear that the data is being sent
using a GET request, when the POST
method was specified in the Flash
movie.
This happens because Flash sends the
data in a GET/POST hybrid format. If
the data were being sent using a GET
request, the variables would appear in
a query string appended to the end of
the URL. Flash uses a GET server
request, but the Name/Value pairs
containing the variables are sent in a
second transmission using POST.
Although this causes the servlet to
trigger the doGet() method, the
variables are still available in the
server request.
I don't really understand that. What is a "GET/POST hybrid format"?
Why does the method Flash uses (POST or GET) depend on whether the data is sent to a Java servlet or elsewhere (e.g., a PHP page?)
Can anyone make sense of this? Many thanks in advance!
Cheers,
Matt
Have you try doing something like that :
var sendVar=new LoadVars();
var xml=new XML("<r>test</r>");
sendVar.xml=xml;
sendVar.svc="setPayCheckInfo";
var receiveXML=new XML();
function onLoad(success) {
if (success) {
trace("receive:"+receiveXML);
} else {
trace('error');
}
}
receiveXML.onLoad=onLoad;
sendVar.sendAndLoad("http://mywebserver", receiveXML, "POST");
The hybrid format is just a term Macromedia invented to paint over its misuse of HTTP.
HTTP is very vague on what you can do with GET and POST. But the convention is that no message body is used in GET. Adobe violates this convention by sending parameters in the message body.
Flash sends the same request regardless of the server. You have problem in Servlet because most implementation (like Tomcat) ignores message body for GET. PHP doesn't care the verb and it processes the message body for GET too.

Categories