Tomcat 7 running behind Apache 2 SSL proxy and client certificate authentication
This is not really a ZK bug, it is more of a browser/apache issue. The problem occurs only when uploading files with ZK Fileupload through an SSL/TLS connection with client certificate authentication.
When the file is larger than 128 KB, the server (Apache 2, which is a proxy to the Tomcat that hosts the application) returns 413 Request Entity Too Large, regardless of request size limit settings. After doing a little research, I found out that at the moment I upload a file, the server requires SSL renegotiation. Since the SSL buffer is 128 KB (default) and the POST request I'm sending when uploading the file is larger than 128 KB, this causes an SSL Buffer Overflow error and Apache returns 413. The request does not even get to the ZK Fileupload AU extension, but the upload component starts to send progress check requests. The data stuctures required for the progress check are not initialized because the first, multipart, request, which did not get to tomcat, initialises them. NPEs start flying.
The most obvious, yet naive approach would be to increase the SSL Buffer size. However, this is prone to DoS attacks with large request bodies.
A little more hacky, but currently working solution, is to send a GET request to the server right before uploading the file. This is due to the fact, that the GET request triggers the SSL renegotiation and then the POST multipart request with the (possibly) large request body uses the same connection, since the default Keep-Alive time is 5 seconds.
My current workaround is to start a ZK timer ticking once every few seconds, to keep the connection alive, wherever I have file upload functionality.
My suggestions are:
- Introduce a setting which makes the fileupload component send an AJAX GET request before POSTing the multipart form, in order to avoid SSL Buffer Overflow
- When sending the periodic AJAX requests that get the progress of the file being uploaded, check whether the Maps, conataining the progress data are initialised. If they aren't, signal an error.