GetRequestDispatcher.forward is sending me through doGet again - java

I have a servlet with doGet overridden. The relevant pieces would be:
// called from doGet(req,res)
private void serviceInternal(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.info("servicing a request");
// magically compute jsp path from request params (includes the
// logging of the app/mod/act as mentioned below
log.info(jspPath);
request.getRequestDispatcher(jspPath).forward(request, response);
}
Now I'm logging the urls that come into the service method and if the url is server:8080/context/app/mod/act?param=1 the log message would say app='app' mod='mod' act='act' and I've verified that this is working well.
When I try to hit something that should be routing me to a jsp, for some silly reason it sends me back into my doGet method! My log looks like this:
INFO 2015-04-12 21:35:07,511 servicing a request
INFO 2015-04-12 21:35:07,519 app='' mod='' act='' uid='null'
INFO 2015-04-12 21:35:07,571 /WEB-INF/index.jsp
INFO 2015-04-12 21:35:07,571 servicing a request
INFO 2015-04-12 21:35:07,571 app='WEB-INF' mod='index.jsp' act='' uid='null'
But I don't want to send my jsp through my doGet - I want to send it to the JSP! Why would it be doing this?
My servlet is catching "/*", if that helps at all. But I wouldn't have expected it to catch jsps.
What am I doing wrong here?

My servlet is catching "/*", if that helps at all. But I wouldn't have
expected it to catch jsps.
You just found the problem yourself. That is the reason.

Related

Sending response before processing in Java servlet

I have a Java Servlet application running on JBoss 4 and this application receives POST request from another service. I want to acknowledge back to this service before processing. Is it fine to do the following?
protected void doPost(HttpServletRequest req, HttpServletResponse res) {
readReceivedPOSTData();
//send response
PrintWriter out = res.getWriter();
out.print("ack");
out.close();
//Process
processData(); //takes long time
}
I appreciate your help. Thank you.
The basis is ok.
Just some tips:
Use an identifier in the request so you can check in the future the status of that request.
Start another thread to process the data or use a jms queue
remember that you can't write additional data to the response in the processData() method

Servlet: Cannot forward after response has been committed

I'm working on servlet page that renders content based on geo-location, and I want to use both sendRedirect and forward together; e.g; you browse example.com/aPage.jsp from France; first I want the servlet to redirect you to example.com/fr/aPage.jsp and then forward you to the resources page.
This is what I have in my servlet:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
....
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
// after redirect forward the resources page
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
...
}
But I get:
java.lang.IllegalStateException: Cannot forward after response has been committed
I know the error appears because I can't use both sendRedirect and forward one after another, but I don't know how to achieve what I want (as described above) without this.
any help?
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
// after redirect forward the resources page
After that line , Your response start writing to clinet.
And you are trying to add additional data to it.
The server has already finished writing the response header and is writing the body of the content, and which point you are trying to write more to the header - of course it cant rewind.
So,Thumb rule while dealing with servlet is
Finish your logic before redirect or forward add return statement.So execution ends there .
When you call
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
you are sending your client a 302 HTTP status code with the location to redirect to. Your client then needs to make a new HTTP request to that location. Whichever Servlet is supposed to handle the path REDIRECT_URL_BASED_ON_GEO should then use the RequestDispatcher to forward to the resource described by RESOURCES_PAGE.
To better explain your exception
java.lang.IllegalStateException: Cannot forward after response has been committed
a committed response is a response where HTTP headers are already sent. If we look at your code
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
After this line, you've already sent the response along with the headers (302).
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
After these lines, you're asking the resource RESOURCES_PAGE to finish processing the request. That includes writing HTTP headers and body. But the request has already been processed and a response has already been sent, so it will fail, throwing the exception.
You have to be aware that a redirect is a complete response to the browser and the browser will in turn issue a new request to the url you redirected to. Even though you can't really sse it when dealing with the browser you always have to be aware that this is what happens.
Now, if you use the same controller for the second request you have to check wether a redirect is necessary or you can now do the forward instead.
if (!path.startsWith(locationPrefix)) {
response.sendRedirect(locationPrefix + path);
return;
} else {
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
return;
}
Of course it would be nicer to have a distinct controller per request, but depending of url structure and framework this is not always possible.
Once you redirect, the servlet you're working on is no longer in control. You need to get the servlet that is the target of the redirect to recognize the correct condition to forward and then call forward there, with similar code:
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
Even if it's the same servlet, it's a new invocation of the servlet's doGet( or other similar method.

AsyncContext in Servlet 3.0 infinite browser loading

I'm going to make streaming. I have .jsp file and at the end of .jsp file I include my Async Servlet using following code:
<jsp:include page = '/simple' flush = 'true' />
So I want when whole page is loaded to open an infinite Async request, which will handle Async response.
Here is my Servlet code:
public class SimpleAsyncServlet extends HttpServlet {
public static AsyncContext ctx;
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
ctx = req.startAsync();
ctx.setTimeout(0);
}
}
From other java classes I'm using the static SimpleAsyncServlet.ctx.getResponse.getWriter() to println some javascript code to current page. It is working without any problem, but browser keep showing that it's loading. According to Async idea page should be loaded and this Async Request should stay alive in background and..that's it, but no....browser keeps loading the page till forever (timeout is 0, cos I want to have infinite open reqeust)
Where am I wrong and how can I make this permanent request without this browser loading ?
P.S. I have tried to access my servlet direct from url (localhost.../simple) and then I see nothing printed on page. It keep loading till forever.
You are trying to achieve the impossible.
The browser will showing that the page is loading until it knows it has received the full request by one of the following methods:
it has received the number bytes stated in a Content-Length header
the connection is closed
it received an end chunk when using chunked encoding
Since you want an 'infinite' response, none of the three options above is ever going to happen.

Can we somehow change the url in addressbar after dispatching request from servlet to jsp

I am having a weird problem here, and I am really stuck, need to get this work badly.
so i have a page say index.jsp with a link say "a href=servlet?id=10". when I click on this link it will go to doGet() on my servlet and here is the code in my servlet.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("id");
// search database and create an arraylist
if(//user logged in)
address = "s/results.jsp";
else
address = "results.jsp";
// set arraylist in session object
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request,response);
}
So the above code works fine but after request forwarding, my browser shows the url as
http://localhost/project/servlet?id=10.
I don't want the above url as i am forwarding to two different jsp's based on the user login status one is in 's' folder and other is outside of that.
if user is logged in then i forward to 's/results.jsp' and if user is not logged in i am forwarding to 'results.jsp'.
in case of s/results.jsp i am accessing resources like images and scripts from outside of 's' folder by using ../ in the results.jsp.
as url is not changing to s/results.jsp , i am unable to access the resources with '../'
and as i am using jsp pagination , when i click next the url is changing to s/results.jsp
and in that case i am able to access resources using ../
one solution in my mind is to copy all resources in s folder , but that would increase
redundancy.
one other solution in my mind is to create two different servlets for two jsp's
but i don't know where to put the servlet so that it can access resources outside of s folder with ../
is their any other good way i can do the task..
I have tried to find information about this but haven't been able to figure it out.
Any help will be very much appreciated.
You have basically instructed your webbrowser to send a request to exactly that URL. The forward does not change the URL. It is entirely server side. Apart from using response.sendRedirect() instead -which would trash the current request, including all of its attributes, and create a brand new request on the given URL-, you could also just change your link to <a href="results?id=10">, or when the user is logged in, to <a href="s/results?id=10">.
<a href="${user.loggedin ? 's/' : ''}results?id=10">
Finally alter the servlet mapping accordingly so that it get invoked on those URLs.
<url-pattern>/results</url-pattern>
<url-pattern>/s/results</url-pattern>
You'll only miss the JSP extension. But JSPs which are to be used by a dispatcher belong in /WEB-INF folder anyway so that they cannot be viewed by the enduser directly without invoking the servlet first. You also end up with nicer URLs.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("id");
// search database and create an arraylist
if(//user logged in)
address = "s/results.jsp";
else
address = "results.jsp";
// set arraylist in session object
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request,response);
}
in the above code instead of using request dispatcher,
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request,response);
we can try with
response.sendRedirect(request.getContextPath()+"/address");

How to drop body of a request after checking headers in Servlet

I want to check the header of the request whether it contains a certain header or not before continuing with the body. For example, I want to check whether a multipart/form-data contains "Authorization" in the header or not. If it is not then there is no need to continue with uploading the multipart body which are generally quite large for file uploading.
Does servlet allow you to do this? I have tried to search on google randomly but there is no luck. Here is the code i try in my servlet but it still continues with recieving the body before this doPost method is called. It seems that the stream is fully received before the servlet is invoked.
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/plain");
if (request.getHeader("Authorization") == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
out.println("Status: " + HttpServletResponse.SC_UNAUTHORIZED + " - UNAUTHORIZED");
return;
}
// ... the rests
}
That's the limitation of HTTP. You can't send a response when the request hasn't been read fully to end.
RFC 2616 says:
An HTTP/1.1 (or later) client sending a message-body SHOULD monitor the network connection for an error status while it is transmitting the request. If the client sees an error status, it SHOULD immediately cease transmitting the body.
So I disagree, this is not a HTTP limitation but a servlet one.

Categories

Resources