How can the servlet determine when an upload has been cancelled? - java

Here is some code on the javascript side for form-based uploads:
iframe.setAttribute('src', 'javascript:false;');
I'm using the code above to cancel an in-progress upload associated with an input element placed in an iframe.
I'm using the code below to cancel an in-progress upload sent via XHR:
myxhr.abort();
In both cases, no more bytes are sent to the servlet. The part I'm struggling with is on the servlet side. Currently, I can't figure out a way for the servlet instance to determine if the user has cancelled the upload. This is critical, otherwise the servlet will go on and process the partially uploaded file as if it is valid.
How can I determine, via the HttpServletRequest, if a user has cancelled the upload?

The POST request with the data contains the Content-Length header which tells you the size of the data that is going to be uploaded.
So when the data stops coming to your server and the size of the data received is less than expected - it would mean that the user (or some network glitch) has canceled the upload.

If the upload has been cancelled the browser will close the connection, resulting in a an IO exception on the servlet side. For example, in Tomcat it will say "Connection reset by peer" and this is a ClientAbortException. Other servers wrap the IOException differently. Point is just catch the IOException and you should be able to handle it as you wish.
Using content-length is not reliable because the HTTP spec does not require content-length headers for POSTs - or for GETs for the matter. Point is, unless you are sure your javascript XHR sets the header explicitly, this method won't work.
Alternatively you could calculate it yourself and set it to be sure, or even better append your own character stream to the end of a the posted data in the XHR, some unique string of characters, e.g. "jh923k49sk$2#%'. In the servlet, snip off the last 14 characters of the inbound message and check it against the string. If it is the same you know they didn't cancel.

I don't see how you can tell, just because a request stream has ended, whether it's done or cancelled. There would have to be a separate HTTP request to indicate cancellation that would have to include some token or ID associated with the upload, since HTTP is stateless and idempotent.

Related

REST API Single Request - Multiple responses

I am writing a REST API in JAX-RS 2.0, JDK 8 for the below requirement
POST API /server/fileUpload/ (Multipart Form data) where I need to send a Big .AI (Adobe Illustrator) File in this.
The Server, takes the file and return Status 202 (Accepted), Acknowledging that file transfer happened Successfully. (From endpoint to Server)
Now at the Server, I am using Java + Imagemagik to convert .AI File (20-25 MB File) to small JPG Thumbnail, place on a Apache HTTP Server and share the location (like http://happyplace/thumbnail0987.jpg)
Now the Second Response should come from Server with Status 200 OK and Thumbnail URL
is it feasible with one REST API? (Async/similar)
or should I split it to 2 API calls, Please suggest
No. In http, one request gets one response. The client must send a second request to get a second response.
You can use WebSockets for that.
If you are calling from script the call will be async you can handle the Thumbnail URL when you get a response. When you are calling from java program i suggest to run it on a different thread, If the execution is not sequential i.e ( Remaining lines can be executed without getting URL). If url is needed for the remaining section of code you can make one call and wait for the response then execute remaining code.
You need to make different APIs for both scenarios. One for showing file upload status and another for all file conversion and manipulation.
On the client side second request must be callback of first request.
The best way to handle these kind of scenario is to use Java Reactive (Project Reactor, WebFlux).
You can return two response using custom middlewares in asp.net (however not recommended).
Return response from one middleware and subsequently you can invoke next middleware and return second response from second middleware

Redirect webpage after having sent some content

I am working with a web framework (uPortal) that is handling errors by just throwing an exception and then hanging. The framework works by rendering XML into HTML. When there is an exception, the browser recieves rendered content up to the XML template element that is failing, and then the browser just sits and waits for a timeout. Our team's theory is that the content is sent before the error occurs, which surprised me. Other frameworks I've worked with seem to finish rendering before sending content.
My question is, is there a way to redirect the browser after content has already been sent? In this case, we are in the middle of rendering the content of a <script> tag, but the error could occur potentially anywhere in the html.
My only current thought is to inject some javascript at the top of the page, and to try to change the framework's behavior to fail quickly and close the connection and add </body> and </html> tags when an error occurs. Then the above mentioned javascript would run on pageload and detect if the entire page's content was there and do a client-side redirect if not. Maybe it could look for a special hidden div at the bottom of the page.
Are there any examples of frameworks solving this problem differently or of people using similar framework working around this issue?
You must either capture the error, or capture the output in a buffer. If you can handle the exception, you can probably print a simple script tag like
<script> window.location.href = 'some_new_url';</script>
If the browser understands the doctype to be something related to HTML, it will execute that tag.
If you can capture the output in a buffer, when you handle the error you can decide to send an HTTP redirect to the browser and destroy the output buffer up to that point.
As for other frameowrks, in PHP, you can simply enable output buffering with ob_start(), which won't start sending content until the request is fully completed.
I don't know that framework, but
In http, every response has a response-code associated with it. Since the page is already half-way transferred / rendered that status code (usually "200") was sent (and received) already.
There's no way for the browser to accept another response code (like "301" for redirect) for the same response! Also the server is not able to send another response code, because the original response code was already commited and sent to the client.
Your description of the error and knowledge of the http-protocol implies that there is probably some implementation error in the framework / server components used, OR it was done deliberatly, risking the situation that you are in now...
to redirect a page , you need to set redirect information in header. but you can write header once you start writing content ( may be header is already received by client by the time you compete writing whole document )
But, you can do it in different way as below
1.let document loading complete and record if you need to redirect the page while rendering
2. add a unique request-id identifier for each page load
3. invoke ajax call with request-id ( may be rest call) to server asking if page needs to be redirected.
4. if page needs to be redirected , do so, via javascript in browser at client end.
A HTTP response consists of headers and an optional response content.
Once you have started to write the response to the socket connection you can't revert it. In your example: If you run into an error in the middle of content generation you can't add a redirect header - the header section has already be written.
The statement above is not entirely true: in HTTP chunked transfer encoding the response is sent in separate chunks. The last chunk can have an optional trailer containing entity-header fields and theoretically a redirect header. But if you can use these mechanism is a different question. For instance a servlet container may use chunked transfer encoding but does not give you an API to set the trailer.
But writing must not start immediately: For instance HttpServletResponse maintains a buffer for the response content. If you set headers and start writing the content only the buffer is filled and you still can reset the response and start all over. But once the buffer overflows the response is written to the connection and the HttpServletResponse is now committed.
Such a mechanism gives you way to deal with errors during content generation which happen when the response is not yet committed: Just reset the response and send an error message instead. You could examine your framework if it supports such an mechanism. But obviously this is not a solution for larger responses.
A second way to avoid errors during content generation is simply to make sure that they can't happen. First gather all your data needed for the response (e.g. making unsafe database calls), then in a second step generate the response - the second now step should not fail (except if you have bugs in your code).
You already mentioned a third way to handle an error, by having the client sanitize the response and take some action it errors are detected (e.g. by including a script in the generated HTML response).
The only reliable way to do this is to create a proxy HttpServletResponse object that caches the response. You'd need to give the uPortal this proxy instead of the actual HttpServletResponse, and only send the output using the real response once the processing completes / send redirect if the processing fails.
It is HTTP protocol design limitation that you cannot send HTTP redirect once output was started.
Other possible ways rely on HTML or Javascript redirects, but since you write that the error may happen at any moment, it would be difficult to print it out in a way that the browsers would reliably interpret it as redirect.

Java servlet, respond after recieving each request before queuing

I am using Java servlets using Apache tomcat.
I've configured a threadpool and am dealing with each request.
My page is taking in many GET requests at the same time, I'm wondering if I can respond to the server after each get request before any of the logic happens?
So server gives me a request -> I respond with either 'good send another' or 'bad send another' before I start my queueing.
Any help would be much appreciated!
EDIT
Sorry that was terribly written :(
What I'm asking for is a way to send a Header to the client (in this case it's a server which sends me lots of requests). The response would just be 200 or error based on the information I get sent.
What my program is doing:
My servlet gets sent lots of GET requests from one client. (over 100,000) Which I am using tomcat to queue and put into a threadpool. It is then assigned to a worker thread which processes it and puts it into a database.
I've been told to do is send a request back to that server saying 'ok received it'. I think I can use a header response but I don't have the URL of that client (and the client can change for different campaigns). So was wondering what the best way would be to send that response.
After doing some more research I think what I'm looking for is ServletOutputStream.
response.setContentType("text/html");
ServletOutputStream output = response.getOutputStream();
output.flush();
output.close();
Using servlet output stream where do I set the <head><body> tag? and insert the header response afterwards.
The simple answer is "sure".
If these are get requests from a web page for a web page, include a refresh timer and send back some token that can be used to identify the difference between a first-time-request and an I-requested-earlier-are-you-done request. In this case the refresh timer can be set via a meta refresh tag.
If the get requests are part of a REST API then you can define "got it and I'm working" into the protocol. For instance, return a 202 to indicate "got it but not done" and return 200 to indicate "done". As with the html page, consider sending some token back with the 202 that identifies the pending request.

How to get the status of a request by another request?

Let me explain what I am doing first:
I have a servlet that handles some GET, POST and PUT requests.
Now on my PUT request I am saving a file from the request.inputStream. Now I want to do some things like I issue another GET request that can give me the status of reading the input stream of that previous request. I can issue an PUT request that can put some binary data with range for that file I am saving previously. Or I can send a DELETE request that will cancel the upload.
How can I do that? How can I access one request from another?
You could use the HttpSession object on the request and save the bytes read on the InputStream.
The session attribute will be accessible on the following request.

HttpURLConnection: set Byte-range request after connected

So I used the setRequestProperty to send a Byte-Range request to a URL. But the problem is I want to get the size first using getContentLength. However, the compiler complains that I was already connected to that URl after asking for the length, I can no longer set the byte-range. Is there anyway to do this in this particular order w/o it throwing an error? I tried to go:
getContentLength() -> connection.disconnect() -> setRequestProperty() ->connection.connect(). But that didn't work either. After I disconnected it and connect again, it didn't receive any data at all.
An HttpURLConnection is used to make a single request to the server and can not be reused for a subsequent request. And since getContentLength() returns the length of the response, by the time it returns the request has already been sent, which is why you can no longer add headers to the request afterwards.
You can use two HttpURLConnections -- the first one to request the length of the document, and the second one (in which you set the Range header based on the length you got from the first request) to get the actual document range you're interested in.

Categories

Resources