Cancel Request with browser - java

Assume this scenario: I send a request to my server(apache tomcat) from a browser(firefox). The response come after about 2 minutes from server. How can I cancel this request in a way that my server do not continue for making the response ?
When a user sent a request to the server, it is common to go to another link(or menu or cancel the request) of application and it is so important for developers to cancel such these cases and so reduce the server load.
OK then, I want a technique to detect such incoming requests which are sent to my server and cancel all actions for making the response for client( because the client is not waiting for server response anymore).
I couldn't find useful information in google and stack.
I also set keep-alive-timeout in my server.xml, but nothing happened!
I also read this topic cancle request , but it didn't help me.
So please help me to solve this issue ...

You can cancel the request sending content to its outputstream (and flushing it).
If a user cancels the request, the servlet will loss the connection to the browser and then, sending content to the outputstream will throw a ClientAbortException making the process stop.
Try this:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletOutputStream out = response.getOutputStream();
try {
out.println("<!DOCTYPE html>");
out.println("<html><body>");
out.println("<h1 id=\"count\"></h1>");
for (int i = 0; i < 60; i++) {
Thread.sleep(1000);
out.print("<script>document.getElementById(\"count\").innerHTML=\"" + i + "\";</script>");
out.flush();
System.out.println(i);
}
out.println("</body></html>");
} catch (Exception ex) {
System.out.println("Stoped due to " + ex.toString());
} finally {
out.close();
}
}

Related

How do I print something in Tomcat Servlet, sleep for 3 seconds and then forwarding to another servlet?

This is a project for my study.
I have a JSP with checkboxes which I will store into an Array in the Result.class (Result servlet) after clicking Submit on the JSP page. But before that, I have a PageProcessing (to show some processing text before showing the result of the Array) that will be shown before the Result servlet.
I want to let the PageProcessing servlet show some text and then sleep for 3 seconds before forwarding to the next servlet. The only thing that doesn't work is that it doesn't show the out.println(""); text before sleeping.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
try {
out.println("<h1>Processing..."
+ "<br>"
+ "<h2>Please wait.</h2>");
} finally {
try {
Thread.sleep(3000);
request.getRequestDispatcher("Result").forward(request, response);
out.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Return a complete page to the user and close the connection. This will display a nice status page to the client. Then, let the client re-connect (META REFRESH, jQuery, raw AJAX, timed Javascript window.location='...', etc.) and fetch the follow-up resource.
EDIT 2020-09-08
Examples:
meta refresh
jQuery refresh
javascript (also includes other strategies)

HTTP conversation is not persistent

I need to build a Java server where the client sends an HTTP request, the server sends an HTTP response, the client sends another HTTP request, and the server sends a final response. However, after the server sends the first response to the request, the connection times out. I realized that the client isn't even reading my response until I close the input stream, but this ends the conversation prematurely. Here is the run method for my class ServerThread, which extends Thread.
public void run() {
try {
l.add(index, serv.accept());
new ServerThread(serv, l, index + 1).start();
Socket socket = (Socket)l.get(index);
index++;
while(true) {
while(socket.getInputStream().available() == 0) {}
while(socket.getInputStream().available() > 0)
System.out.print((char)socket.getInputStream().read());
BufferedWriter b = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
b.write("HTTP/1.1 200 OK\n" +
"Connection: keep-alive");
b.flush();
//b.close();
}
} catch (IOException e) {
}
}
Basically, this code accepts a client and blocks until there is information in the input stream. After there is information, it prints out the request and writes a 200 OK response to the client regardless of the request and keep the connection alive. When I comment out the b.close() call, the conversation hangs, but as soon as I stop the server, the client reads the response. How do I get around this?

Java - HttpServlet: When is the response sent to the client?

I was little experimenting with some HttpServlet stuff to understand it better. I wanted to build the scenario that a request is incoming and I need to send the response accordingly and as fast as possible and to do later some more work within the servlet. From my current understanding, the response should only be send to the client when the doGet or doPost method was returned. But from my example, the response is already sent back to the client within the processing of the commands in the servlet. So it is already returned when I was not expecting it to be.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(DisplayHeader.class.getName()).log(Level.SEVERE, null, ex);
}
response.setContentType("text/plain; charset=ISO-8859-1");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
final StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
//TODO most be implemented SynchronizedStatusCodeDimo
out.println("StatusCode=0");
out.println("StatusText=Accepted");
out.println("paymentType=PaymentXY");
out = response.getWriter();
out.print(sw.toString());
out.flush();
out.close();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(DisplayHeader.class.getName()).log(Level.SEVERE, null, ex);
} }
What is happening here, via Firebug I see that I already received the response generated after 510ms. I thought I would need more then 1500ms because of the sleeps. My understanding was based on this post here: Link
The HttpServletResponse will be controlled by your servlet container (Tomcat, Jetty etc.) .
If you write into the response the servlet container automatically flush the response after a defined buffer size (e.g Tomcat after 9000 byte). Usually you can configure it (in Tomcat with the parameter socketBuffer).
This is the way it works, if you do not control it by yourself.
In your case, you control the response by your self and after you call response.flush() the response will be send to the client.
If you had writte more the 9000 Byte (in Tomcat), the response will be send automatically (in the middle of it all).
(excuse my bad english)

Java Servlet 3.0 server push: Sending data multiple times using same AsyncContext

Lead by several examples and questions answered here ( mainly
http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3 ), I want to have server sending the response multiple times to a client without completing the request. When request times out, I create another one and so on.
I want to avoid long polling, since I have to recreate request every time I get the response. (and that quite isn't what async capabilities of servlet 3.0 are aiming at).
I have this on server side:
#WebServlet(urlPatterns = {"/home"}, name = "async", asyncSupported = true)
public class CometServlet extends HttpServlet {
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
AsyncContext ac = request.startAsync(request, response);
HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
store.put(request.getParameter("id"), ac);
}
}
And a thread to write to async context.
class MyThread extends Thread {
String id, message;
public MyThread(String id, String message) {
this.id = id;
this.message = message;
}
public void run() {
HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
AsyncContext ac = store.get(id);
try {
ac.getResponse().getWriter().print(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
But when I make the request, data is sent only if I call ac.complete(). Without it request will always timeout. So basically I want to have data "streamed" before request is completed.
Just to make a note, I have tried this with Jetty 8 Continuation API, I also tried with printing to OutputStream instead of PrintWriter. I also tried flushBuffer() on response. Same thing.
What am I doing wrong?
Client side is done like this:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/home', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 3 || xhr.readyState == 4) {
document.getElementById("dynamicContent").innerHTML = xhr.responseText;
}
}
xhr.send(null);
Can someone at least confirm that server side is okay? :)
Your server-side and client-side code is indeed ok.
The problem is actually with your browser buffering text/plain responses from your web-server.
This is the reason you dont see this issue when you use curl.
I took your client-side code and I was able to see incremental responses, with only just one little change:
response.setContentType("text/html");
The incremental responses showed up immediately regardless of their size.
Without that setting, when my output was a small message, it was considered as text/plain and wasnt showing up at the client immediately. When I kept adding more and more to the client responses, it got accumulated until the buffer size reached about 1024 bytes and then the whole thing showed up on the client side. After that point, however, the small increments showed up immediately (no more accumulation).
I know this is a bit old, but you can just flushBuffer on the response as well.

HttpServletResponse.flushBuffer() on timed out connection does not throw IOException

I am facing quite an unusual situation.
I have two Jboss (7.1) instances which communicate via HTTP.
Instance A opens an HTTP connection to instance B and sends some data to be processed. The connection has timeout set, so after N seconds if no response is read it throws SocketTimeoutEception. Some cleanup is performed and the connection is closed.
Instance B has a servlet, listening for such http requests and when one is received some computation is done. After that the response is populated and returned to the client.
The problem is that if the computation takes too much time, the client (A) will close the connection due to the time out, but server (B) will proceed as normal and will try to send the response after some time. I want to be able to detect that the connection is closed and do some house keeping, however I can't seem to be able to do that.
I have tried calling HttpServletResponse.flushBuffer(), but no exception is thrown. I have also explicitly set in the http request "Connection: close" to avoid persistent connection, but this had no effect. The http servlet resonse is processed as normal and disappears in the void without any exception. I do not know what I am doing wrong, I've read other questions on this site like:
Java's HttpServletResponse doesn't have isClientConnected method
Tomcat - Servlet response blocking - problems with flush
but they do not work in my case.
I think there might be something specific to the jboss servlet container, which causes to ignore or buffer the response, or perhaps the http connection is reused despite my efforts to close it from the client (A). I'd be happy if you could provide some pointers to where to look for the problem. I have spend several days on this and no relevant progress was made, so I need to resolve this urgently.
Here is the relevant code:
Client code (server A):
private static int postContent(URL destination, String fileName, InputStream content)
throws IOException, CRPostException
{
HttpURLConnection connection = null;
//Create the connection object
connection = (HttpURLConnection)destination.openConnection();
// Prepare the HTTP headers
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("content-type", "text/xml; charset=UTF-8");
connection.setRequestProperty("Content-Encoding", "zip");
connection.setRequestProperty("Connection", "close");//Try to make it non-persistent
//Timouts
connection.setConnectTimeout(20000);//20 sec timout
connection.setReadTimeout(20000);//20 sec read timeout
// Connect to the remote system
connection.connect();
try
{
//Write something to the output stream
writeContent(connection, fileName, content);
//Handle response from server
return handleResponse(connection);
}
finally
{
try
{
try
{
connection.getInputStream().close();//Try to explicitly close the connection
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
connection.disconnect();//Close the connection??
}
catch (Exception e)
{
logger.warning("Failed to disconnect the HTTP connection");
}
}
}
private static int handleResponse(HttpURLConnection connection)
throws IOException, CRPostException
{
String responseMessage = connection.getResponseMessage();//Where it blocks until server returns the response
int statusCode = connection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_OK)
{
logger.debug("HTTP status code OK");
InputStream in = connection.getInputStream();
try
{
if (in != null)
{
//Read the result, parse it and return it
....
}
}
catch (JAXBException e)
{
}
}// if
//return error state
return STATE_REJECTED;
}//handleResponse()
Server code (Server B):
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String crXML = null;
MediaType mediaType = null;
Object result;
// Get the media type of the received CR XML
try
{
mediaType = getMediaType(request);
crXML = loadDatatoString(mediaType, request);
result = apply(crXML);
}
catch (Exception e)
{
logger.error("Application of uploaded data has failed");
//Return response that error has occured
....
return;
}
// Finally prepare the OK response
buildStatusResponse(response, result);
// Try to detect that the connection is broken
// and the resonse never got to the client
// and do some housekeeping if so
try
{
response.getOutputStream().flush();
response.flushBuffer();
}
catch (Throwable thr)
{
// Exception is never thrown !!!
// I expect to get an IO exception if the connection has timed out on the client
// but this never happens
thr.printStackTrace();
}
}// doPost(..)
public static void buildStatusResponse(HttpServletResponse responseArg, Object result)
{
responseArg.setHeader("Connection", "close");//Try to set non persistent connection on the response too - no effect
responseArg.setStatus(HttpServletResponse.SC_OK);
// write response object
ByteArrayOutputStream respBinaryOut = null;
try
{
respBinaryOut = new ByteArrayOutputStream();
OutputStreamWriter respWriter = new OutputStreamWriter(respBinaryOut, "UTF-8");
JAXBTools.marshalStatusResponse(result, respWriter);
}
catch (Exception e)
{
logger.error("Failed to write the response object", e);
return;
}
try
{
responseArg.setContentType(ICRConstants.HTTP_CONTENTTYPE_XML_UTF8);
responseArg.getOutputStream().write(respBinaryOut.toByteArray());
}
catch (IOException e)
{
logger.error("Failed to write response object in the HTTP response body!", e);
}
}//buildStatusResponse()
You are running into HTTP connection pooling at the client end. The physical connection isn't really closed, it is returned to a pool for possible later reuse. If it is idle for some timeout it is closed and removed from the pool. So at the moment the server flushBuffer() happened the connection was still alive.
OR
The data being flushed was small enough to fit into the socket send buffer at the sender, so the underlying write returned immediately and successfully, and the disconnect was only discovered later, asynchronously, by TCP.

Categories