Cause of IllegalStateException: Cannot forward after response has been committed [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
java.lang.IllegalStateException: Cannot forward after response has been committed
What is the usual cause of this kind of error:
com.mycompany.myapp.servlet.TxnDetailsServlet doRequest
ERROR: View failed
java.lang.IllegalStateException: Cannot forward after response has been committed
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:312)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at com.mycompany.myapp.servlet.TxnDetailsServlet.doRequest(TxnDetailsServlet.java:82)
at com.mycompany.myapp.servlet.TxnDetailsServlet.doGet(TxnDetailsServlet.java:131)
The servlet process the request (i.e set attributes) then call:
private void doRequest(HttpServletRequest request) throws IOException, ServletException {
// Code omitted
getServletContext().getRequestDispatcher("/Some.jsp").forward(this.request, this.response);
// Code omitted
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.doGet(request, response);
doRequest(request);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.doPost(request, response);
doRequest(request);
}
The servlet does not do anything in reponse.

to add to what others said, response need not be transferred to client(browser) in a single shot. Instead it can be transferred to client in multiple shots as, whenever you call a response.flushBuffer . Once the response starts transferring data to client, you cant do anything that changes response state(setStatus, forward etc)

Don't write to the response output stream if you forward to another servlet/jsp.

Related

How to mock RequestDispatcher so that it goes to the .jsp file?

I am trying to write the JUnit test case for the code:
In SearchController class
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<AlbumSimplified> items = spotifyService.searchAlbum(searchName);
request.setAttribute("items", items);
request.getRequestDispatcher("searchResult.jsp").forward(request, response);
}
as
public void SearchControllerTesting() throws ServletException, IOException {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
//mocked myalbums
when(searchServiceMock.searchAlbum(anyString())).thenReturn(myalbums); when(request.getRequestDispatcher(anyString())).thenReturn(request.getRequestDispatcher("searchResult.jsp"));
searchController.doGet(request, response);
}
The error I am facing is:
java.lang.NullPointerException: Cannot invoke "jakarta.servlet.RequestDispatcher.forward(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse)" because the return value of "jakarta.servlet.http.HttpServletRequest.getRequestDispatcher(String)" is null
I believe that it is due to the fact that the uri is not identified for the request and so, it is not able to find the "searchResult.jsp" located at "/app/src/main/webapp/searchResult.jsp" where app is the root of the project directory.
Hence I tried to set the
when(request.getRequestedURI()).thenReturn("app/search"), which is the URL of the request in the browser for non-testing usage.
However, I am not able to move ahead and solve the issue.
I want the items in the request to go to the searchResult.jsp, and return me a response of type "text/html".
Thanks.

Servlet API - Filter Response Wrapper

I am new to Servlet programming and I have a question about wrapping response. Because I couldnt understand when to use it. For example I have filter and servlet as below.
Filter
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
chain.doFilter(req, resp);
HttpServletResponse httpServletResponse = (HttpServletResponse)resp;
httpServletResponse.getWriter().println("hi from filter");
}
Servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("Hi from servlet");
}
So , What is the difference between them ? I could use both of them to write by using same response object because there are full duplex way (Sincerely, same request and response instances goes to servlet and comes to filter again) between servlet and filter , aren't there ? I am little confused. I appriciate If you could give me a decent sceneraio that could obviously demonstrate the wrapper class's goal.
Thanks & Regards :)

Is it possible to redirect to the same JSP page from a Servlet?

A JSP page named Test.jsp is mapped to the following Servlet.
#WebServlet(name = "TestServlet", urlPatterns = {"/TestServlet"})
public final class TestServlet extends HttpServlet
{
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//request.getRequestDispatcher("/WEB-INF/admin_side/Test.jsp").forward(request, response);
response.sendRedirect("TestServlet");
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
#Override
public String getServletInfo() {
return "Short description";
}
}
This Servlet is mapped to a JSP page Test.jsp. The doGet() method is invoked, when a URL like http://localhost:8080/Assignment/TestServlet is entered in the address bar.
The request can be forwarded to the given URL as commented out. Is it possible to redirect to the same JSP page, Test.jsp?
If an attempt is made to do so, Google Chrome complains,
This webpage has a redirect loop
It can however, redirect to other pages under WEB-INF/admin_side.
The POST-REDIRECT-GET pattern works like so: a client sends a POST request, your server handles it and responds with a redirect, ie. a response with a 302 status code and Location header to the appropriate URI. The client makes a GET request to that URI.
Currently, your server is redirecting on both GET and POSTS requests. What's worse is that your GET is redirecting to the same URI that it is handling, creating the redirect loop you are seeing.
Change your Servlet implementation so that the POST sends a redirect, but the GET actually serves up a normal 200 response with HTML, AJAX, etc.

how to prevent servlet from being invoked directly through browser

I was working on a web project using java servlet and jsp pages. In one of the servlet we have RequestDispatcher method and which is calling another servlet.
#WebServlet("/Demo")
public class DemoServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.sendRedirect("testing"); //calling other servlet
}
}
#WebServlet("/testing")
public class TestingServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("Hello World");
}
}
So, now I wanted to prevent contextRoot/testing from being invoked directly from the browser but instead only let it invoked from the other servlet(Demo)
Please suggest me if there is any way to do that.
Couple of techniques exist:
Look at writing a HTTP Request Filter. You can then inspect the incoming request and the url and reject it if the pattern matches the servlet paths that you do not want to be invoked directly.
Another mechanism is to use the security constraints in your web.xml to allow access to various paths in your application only to authorized users/roles. Look at <security-constraint> tag in web.xml
Answer given by "Romin" is correct. You have to use Filters for this. what you can do is, you can set a new session variable whenever "/Demo" url is accessed and in the filter check for the condition that session exists, if it exists allow the url or else throw error. You could do something similar like this. In "Demo" servlet
#WebServlet("/Demo")
public class DemoServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
HttpSession session = request.getSession() //get new session
res.sendRedirect("testing"); //calling other servlet
}
}
In Filter class add the below code
#WebFilter("/login")
public class MyFilter implements Filter{
public void init(FilterConfig arg0) throws ServletException {}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpRequest request = (HttpRequest) req;
HttpResponse respone = (HttpResponse) res;
HttpSession session = request.getSession(false) //get the existing session object
if(null != session) {
chain.doFilter(req, resp);
} else {
"redirect to some error page or home page"
}
}
public void destroy() {}
}
One approach is to check the caller's ip using ServletRequest.getRemoteAddr() and rejects it if it's not called locally
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
if(!req.getRemoteAddr().equals("127.0.0.1")) { // reject }
}
However this method wouldn't work legitimate caller (eg: proxy) is also using the same ip.

HTTP method GET is not supported by this URL though it executes doGet [duplicate]

This question already has answers here:
HTTP Status 405 - HTTP method is not supported by this URL
(2 answers)
Closed 9 years ago.
public class RoarHistoryUpdate extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException{
super.doGet(request, response);
System.out.println("do Get");
response.setContentType("text/html");
response.getOutputStream().print("Success");
}
}
This is my Servlet. And it is registerd in the web.xml like this:
<servlet>
<display-name>RoarHistoryUpdateServlet</display-name>
<servlet-name>RoarHistoryUpdateServlet</servlet-name>
<servlet-class>de.ulm.uni.vs.avid.roary.servlets.RoarHistoryUpdate</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RoarHistoryUpdateServlet</servlet-name>
<url-pattern>/Roary/UpdateServlet</url-pattern>
</servlet-mapping>
When I go to the URL http://localhost:8080/Roary-JSP/Roary/UpdateServlet It says HTTP Status 405 - HTTP method GET is not supported by this URL
Funny thing is I get the do Get logged to my console. So it actually found the doGet-method.
I am using a GlassFish Server Open Source Edition 3.1.2.2
Because when you do super.doGet(request, response); in your Servlet's doGet() method, you actually call the doget() of the HttpServlet class. The Tomcat 7 implementation of that method is as below (may be a similar implementation exists for Glassfish):
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
My guess is that it's because of invoking super.doGet(). If you check the source code of HttpServlet, you'll see that it sets this status code on the response. So drop the super call. It's not needed.

Categories