Cannot call sendRedirect() after downloading PDF - servlets

I saw many questions like the one I am asking, but they are not exactly about what I am looking for.
I am using Command pattern, and want to create PDF-file and download it. Creating is perfect, but when I want to download it, it's starts downloading and throws an exception.
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response
java.lang.IllegalStateException: getOutputStream() has already been called for this response
Here is my code from Command Pattern
#Override
public String execute(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException, AppException {
String fontPath = request.getServletContext().getRealPath(AppConstants.FONT_PATH);
DBManager db = DBManager.getInstance();
String ticketCode = request.getParameter("ticketCode");
String place = request.getParameter("place");
int amountTickets = Integer.valueOf(place);
String flightName = Encoding.encoding(request.getParameter("flightName"));
User user = (User) request.getSession().getAttribute("client");
String locale = (String) request.getServletContext().getAttribute("currentLocale");
db.updateFlightTickets(flightName, --amountTickets);
///////create pdf document and represent it to the byte array
ByteArrayOutputStream baos =ReportCreator.createReport(locale, fontPath, ticketCode, place, user,
db.getFlightByName(flightName));
response.setContentType("application/pdf");
response.setContentLength(baos.size());
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"Ticket\"");
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
return Path.SUCCESS;
}
Here is my "success page", sorry but can not add more, not enough reputation
<fmt:message key="success_jsp.label.success" />
And here is my servlet code
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
private void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String commandName = request.getParameter("command");
Command command = CommandContainer.get(commandName);
String forward = "";
try {
forward = command.execute(request, response);
} catch (AppException ex) {
request.setAttribute("errorMessage", ex.getMessage());
}
if (forward.equals(Path.SUCCESS)) {
response.sendRedirect(forward);
} else {
request.getRequestDispatcher(forward).forward(request, response);
}
}
Part of code in JSP, where click is calling the servlet
<td><button><fmt:message key="welcome_jsp.submit.buy_ticket" /></button></td>
How can i avoid it?

The exception says you are trying to working with the request/response once you redirect it or viceversa, and it's not valid.
Once you redirect a request, you cannot do anything else with the request/response, so getting the output stream and writing something to it is completely insane.
It's true about vice-versa situation, writing something and then redirect it will cause the browser will ignore the response data, or exception on server as I'm guessing you got.(but it depends on container)
So you either do not redirect the browser, or provide the pdf file with the target servlet/cgi where you are trying to redirect.
=================
And your current situation/problem:
Server sets the content-length, content-type,... and starts to write down some stream to the browser, since you haven't set any status, container will set default 200 OK which indicates there is some right response for the request.
Then browser will get some data(the pdf file) as 200 OK data(and consider it done), now how would you redirect the user once the response is almost done?!!?!!?!
I still do not understand why do you like to redirect a request when it's almost closed? you like to redirect the user after download complete? you cannot.

Related

Get beautified URL from HttpServletRequest

I am using the org.omnifaces.filter.HttpFilter to redirect visitors on login page when nobody is logged in.
#Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, HttpSession session, FilterChain chain) throws ServletException, IOException {
String loginUrl = "/myapp/login?redirect_url=" + req.getRequestURL();
boolean loggedIn = (req.getRemoteUser() != null);
if (loggedIn) {
chain.doFilter(req, res); // So, just continue request.
} else {
Servlets.facesRedirect(req, res, loginUrl);
}
}
I want to redirect not logged in users to /login?redirect_url=previous_page_url
The problem is that all my URLs are beautified by pretty-faces and when I try to get the previous URL with HttpServletRequest.getRequestURI(), it gives me the ugly URL.
For example, I configured an url /myapp/my-page-3 which displays /views/module1/page3.xhtml.
But HttpServletRequest.getRequestURI() is giving me /views/module1/page3.xhtml and not /myapp/my-page-3.
Any ideas ?
When the servlet based URL rewrite engine uses under the covers RequestDispatcher#forward() to forward an incoming friendly-URL request to the desired resource, then you can use request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) to find out the original request URI.
String originalRequestURI = request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
As you're already using OmniFaces, you can use Servlets#getRequestURI() to automatically detect it and return it when present, else fall back to the default HttpServletRequest#getRequestURI().
String requestURI = Servlets.getRequestURI(request);

how to get filter httpservletresponse outputstream error message in filter

I am using spring 4 and filters I got some error response in servletResponse. It contains outputstream with an error message.
How can I get this error message in Outputstream and audit to my app?
try{
filterChain.doFilter(wrappedRequest, servletResponse);
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
LOGGER.info("Basic Authenticate HttpServletResponse code {}"+httpServletResponse.getStatus());
httpServletResponse.getOutputStream();
// I need to read this outputstream, its contains error message.?
}catch(Exception e){
LOGGER.error("Error Basic Authenticate Error :{}", e);
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
AtomicInteger statusCode = new AtomicInteger(httpServletResponse.getStatus());
Response response = ResponseUtil.populateResponse(statusCode, e.getMessage().toString(), 0);
httpServletResponse.sendError(httpServletResponse.getStatus(), e.getMessage());
auditService.updateRestAuditRecord(auditId,StringUtils.EMPTY, response);
}
The key is the HttpServletResponseWrapper decorator class. Adapt these steps to your specific needs:
Fully read the stream you want to audit to something like a byte buffer.
Do your auditing task.
Extend HttpServletResponseWrapper, override getOutputStream() and return an extension of ServletOutputStream that streams your byte buffer.
Pass the HttpServletResponseWrapper to the next downstream filter in the chain.

Is it necessary for doGet() or doPost() to execute completely in order to send a response or is a response sent immediately on writer.print()?

I have written a callback for a web service I am using. That service sends my web app a request and requires me to send a response within 3 seconds.
I call two methods from inside my doPost() method.
What I want to do is to return the response after one of those methods has executed and then execute the second method.
Here is a sample of what I am trying to do -
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter writer = response.getWriter();
try {
this.doSomething();
writer.print("200 - OK");
writer.flush();
writer.close();
} catch (Exception e) {
writer.print("400 - Bad Request");
writer.flush();
writer.close();
}
this.doSomeThingElse();
}
Is this allowed? Or is the response sent after the doPost() method executes completely?
Also, under what condition does the thread that the servlet spawns to process the request get blocked? (i.e. it is not returned to the thread-pool)
It's allowed to invoke doSomethingElse(). But you can't send some data in this method (or later) to the client, since you called writer.close().

use of getsession() in http sessions

How come the following code snippet always enters the else block?
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out=response.getWriter();
request.getRequestDispatcher("link.html").include(request, response);
HttpSession session=request.getSession();
if(session!=null){
String name=(String)session.getAttribute("name");
out.print("Hello, "+name+" Welcome to Profile");
}
else{
out.print("Please login first");
request.getRequestDispatcher("login.html").include(request, response);
}
out.close();
}
from java doc getSession() Returns the current session associated with this request,
or if the request does not have a session, creates one.
In your code
HttpSession session=request.getSession();
It will check for current session associated with request and if there is not any,then it is going to create one.
So the check if(session!=null){ will always be true.
If you want to check that if session is present then only return HttpSession object else return null,then you can use one overloaded version of this method
HttpSession session=request.getSession(false);
See Also
JavaDoc getSession()
JavaDoc getSession(boolean)

How to send data via HTTP get in Java?

So, I am going to connect to a servlet via an iphone and use HTTP. I am actually developing a multiplayer game and would like to know how I can send specific data to the iphone via HTTP get in java (doGet). I am using libcurl on the iphone (cocos2d-x).
Here is how my code is set up:
size_t write_data(void* buffer, size_t size, size_t nmemb, void *data)
{
//do stuff with data
}
//main or some init method
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl)
{
char *data = "hi imma get=yeah";
curl_easy_setopt(curl, CURLOPT_URL, "http://whatever.com");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
{
CCLOG("WELP BETTER DO SOMETHING ERROR");
}
curl_easy_cleanup(curl);
}
So, what I would like to know is how I can use the response in the doGet method in java to send a string to that write_function defined above? As in, what do I do with response parameter in the doGet method?
For reference here is the doGet method:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
System.out.println("GET METHOD CALLED");
}
So, now what do I do with that response to pass some data to the write_function?
Thanks, for any and all input!!
By using response's Writer, as shown below.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// tell response what format your output is in, we select plain text here
response.setContentType("text/plain;charset=UTF-8");
// ask the response object for a Writer object
PrintWriter out = response.getWriter();
try {
// and use it like you would use System.out. Only, this stuff gets sent
//to the client
out.println("GET METHOD CALLED");
} finally {
// housekeeping: ensure that the Writer is closed when you're ready.
out.close();
}
}
In some cases it's easier to use a Stream. That's also possible but you can never have both the Writer and the OutputStream open simultaneously.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/plain;charset=UTF-8");
// ask the response object for an OutputStream object
OutputStream os = response.getOutputStream();
try {
// output some stuff, here just the characters ABC
os.write(new byte[]{65,66,67});
} finally {
os.close();
}
}
If you want to know more, there are loads of tutorials about servlets available on the web, including the Servlet chapter of the official Java EE tutorial on oracle.com

Resources