apache commons FileUpload - cutting off large files before whole file uploaded - java

Using Tomcat 6, I am using apache commons FileUpload to allow image uploads. I can set the max files using setSizeMax and setFileSizeMax. But it seems that an entire large file is uploaded and then checked too see if it is too big. According to another post, it seems that setSizeMax should cut off the upload, but that is not the behavior I get.
To test this, I set the sizeMax and fieSizeMax very low, and uploaded a rather large file. It took 15 secs uploading the large file, instead of cutting it off almost instantaneously.
Any idea? Here is some code, with a simplified exception clause.
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(30);
upload.setSizeMax(28);
List items = null;
try {
items = upload.parseRequest(request);
} catch (Exception e) {
out.println("exceeded max file size..");
return;
}
MORE INFO: Using tomcat 6. Setting the maxPostSize does not work for content-type: multipart/form-data. Also, checking the request content length again requires the entire file to be uploaded. Finally, using the steaming api of FileUpload also does not seem to work, as it again seems to require the entire file to be uploaded before the stream can be be closed; the upload will continue even if the servlet does not write the bytes to disk. There has to be a way to prevent huge uploads using tomcat 6, as uploading images and such is a very common task for web apps.

The client sends the bits whether you save them on the server or not. There is no way for the server to tell the client to stop sending bits short of forcibly closing the input stream (because of the nature of HTTP: response follows request -- they are not simultaneous). You can try that, but most application servers will drain the input stream from the client when you perform a close() so nothing will change.
If you can control the client and require the use of 100-Continue (via an Expect header), you may be able to snoop the Content-Length of the request and reject it by sending a negative reply instead of 100-Continue.

Tomcat has a maxPostSize attribute for its HTTP Connector. See Tomcat docs
Edit: Too bad that doesn't work for multipart/form-data. Have you considered using a signed Applet or using "Java Web Start" to manage the upload ?

Related

Google Cloud Platform load balancer aborts large file upload requests

When uploading (multipart post) file which is by underlying backend application (tomcat using apache fileupload library) considered as too large and responded with 413 http status, original request is aborted on load balancer with "aborted_request_due_to_backend_early_response" status. This means that user is presented with some built-in system error page instead of application error page.
How should the system be configured to deliver application error response to end user through load-balancer?
Some other details:
when the limit is, for example, 2MB, and the uploaded file is ~5MB, everything works fine, but when the file is >6MB described behaviour occurs (this depends on user's connection quality)
tomcat's / servlet's maxPostSize maxFileSize ... does not make any change
returning 200 instead of 413 does not make any change
I assume, that the response is (for those large ~6MB files) returned back before the file itself has been fully uploaded yet. But that is desired as I don't want to process, say, some gigabyte-large files into filesystem, and return 413 response afterwards - I want to cut them before any processing other than detecting their size.
So how to accomplish this in GCP (load balancer - apache - tomcat) environment?

How to drop HTTP connection if request body is too big?

When I say drop connection I mean actually closing the socket without reading any more bytes. I am trying to prevent a DoS attack where the attacker is trying to make a lot of HTTP requests that upload very very large files. For my purpose, I will consider any client trying to upload file larger than a pre-configured amount as attacker, and I would like to terminate the connection ASAP without reading even single more byte (I would like to send a HTTP 413 back to client if possible, but I don't care if the client receive the response or not, I just don't want any more byte from the client).
I have a app that runs within Jetty and from what I observed even if I throw exception, Jetty itself will still consume all the request body (and drop them) as part of the HTTP request life cycle.
So how do you guy do that? Through Jetty itself or through some kind of reverse proxy?
I know about maxFormContentSize and Apache File Upload, but they don't really do what I am looking for.

REST File uploading - multipart or just sending content on inputstream

I need to write REST resource that should receive a file and save it to the disk.
The files will be sent from jersey client.
For now, I see two options:
1. Using multipart
2. Just reading the inputstream as a string and saving it to a file.
What are the pros of using multipart? is it related to file size? or anything else?
Thanks
If you use Jersey server side, using multipart you gain
disk buffering (surely you don't want to retain huge files in memory)
automatic base64/binary stream conversion
If you choose the String option these benefits are unavailable.
See also my answer to the question JAX-RS Accept Images as input, there is a sample implementation of the multipart option

send to many files from an applet to an servlet

I need to send X number of files to my servlet from an applet, which is the best way to do this?
And I need to send before the files, a java object populated.
I need to do it all in a single connection.
I'll upload my applet 3 ~ 10mb to my servlet.
I currently use FileInput together with the OutputStream and BufferedOutputStream to send a file, causing the buffer size is 8K.
First time I'll try to zip all the files to upload a zip file to the servlet, but I know it's not a good solution.
In the Applet side, send it as a normal multipart/form-data request by either URLConnection or HttpClient. In the Servlet side, use either HttpServletRequest#getParts() or Commons FileUpload to extract the parts from the request. This way the applet and servlet are not tight coupled to each other, but just reuseable on different servers (e.g. PHP) and/or clients (e.g. a simple HTML page).
Whether or not to zip the individual files into a single zip file is a decision you'd need to make yourself based on coding and performance impact.

Java UrlConnection HTTP 1.0

I am trying to download a file from my Java application. But because UrlConnection uses HTTP 1.1 protocol i get a Tranfer Encoding: chunked response in which case i can not find out file size(content-length is not set). From what i could find HTTP version is hard coded in the class and there is no way to change it. Is it somehow possible to change the version back to one or tell the server not to use chunked encoding when sending a file?
Edit: I am not trying to retrive dynamic content my application is a download manager.
files i am downloading are static. Other downloaders i checked wget,igetter,curl use Http 1.0 and they get the size info from most servers. But my application and firefox issuing Http 1.1 always gets chunked encoding. I understand that content-length is not always present but i would like to get it most of time.
The Jakarta Commons HTTP Client contains a "preference architecture" that allows some fine grained control over the particulars of the HTTP connection. See http://hc.apache.org/httpclient-3.x/preference-api.html
It's very likely that the server can't specify a valid content-length, even if you specify HTTP/1.0. When content is dynamically produced, the server has to buffer it all to measure its total length. Not all servers are going to be able to fallback to this less efficient behavior.
If buffering the response is reasonable, why not do it in your client, where you have full control? This is safer than relying on the server.
Read the response without processing, just stuffing the data into a ByteArrayOutputStream. When you are done, measure the length of the resulting byte array. Then create a ByteArrayInputStream with it and process that stream in place of the stream you got from the URLConnection.

Categories