-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Errors deleting multipart tmp files java.lang.NullPointerException under heavy load #4383
Comments
what is the jetty version you are using? |
It's mentioned in the bug report.
…On Sun, 1 Dec. 2019, 6:10 pm Olivier Lamy, ***@***.***> wrote:
what is the jetty version you are using?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#4383>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAEQE3QLQ3HW7A3IFV3BRLQWNPQBANCNFSM4JTKHAUA>
.
|
Seems to be an issue with async servlets. This servlet won't cause that error: @WebServlet(name = "SyncUploadServlet", urlPatterns = "/sync/upload")
@MultipartConfig
public class SyncUploadServlet extends AbstractUploadServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
try {
doPostImpl(request, response);
} catch (Exception e) {
doQuietly(() -> {
response.setStatus(SC_INTERNAL_SERVER_ERROR);
response.getWriter().println("Failure");
response.getWriter().flush();
response.getWriter().close();
});
return;
}
doQuietly(() -> {
response.setStatus(SC_OK);
response.getWriter().println("Success");
response.getWriter().flush();
response.getWriter().close();
});
}
private void doPostImpl(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (!isContentTypeValid(request)) {
sendCustomError(request, response, SC_BAD_REQUEST, "Request is not multipart/form-data.");
return;
}
if (!isDocumentPartValid(request)) {
sendCustomError(request, response, SC_BAD_REQUEST, "Document part is not valid.");
return;
}
final var documentMetadata = getDocumentMetadata(request);
if (!isDocumentMetadataValid(documentMetadata)) {
sendCustomError(request, response, SC_BAD_REQUEST, "Document metadata is not valid.");
return;
}
final var part = request.getPart(DOCUMENT_PART_NAME);
try {
saveDocument(documentMetadata, part);
} catch (IOException | SQLException e) {
e.printStackTrace();
sendCustomError(request, response, SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
}
private void saveDocument(final Map<String, String[]> metadata, final Part document) throws IOException, SQLException {
final var fileName = UUID.randomUUID().toString();
document.write(fileName);
}
} but this one does: @WebServlet(name = "AsyncUploadServlet", urlPatterns = "/async/upload", asyncSupported = true)
@MultipartConfig
public class AsyncUploadServlet extends AbstractUploadServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
final var asyncContext = request.startAsync();
asyncContext.setTimeout(60_000 * 30);
asyncContext.start(() -> {
try {
if (!isContentTypeValid(request)) {
sendCustomError(request, response, SC_BAD_REQUEST, "Request is not multipart/form-data.");
return;
}
if (!isDocumentPartValid(request)) {
sendCustomError(request, response, SC_BAD_REQUEST, "Document part is not valid.");
return;
}
final var documentMetadata = getDocumentMetadata(request);
if (!isDocumentMetadataValid(documentMetadata)) {
sendCustomError(request, response, SC_BAD_REQUEST, "Document metadata is not valid.");
return;
}
final var part = request.getPart(DOCUMENT_PART_NAME);
try {
saveDocument(documentMetadata, part);
} catch (IOException | SQLException e) {
e.printStackTrace();
sendCustomError(request, response, SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
response.setStatus(SC_OK);
response.getWriter().println("Success");
response.getWriter().flush();
response.getWriter().close();
} catch (IOException | ServletException e) {
e.printStackTrace();
} finally {
asyncContext.complete();
}
});
}
private void saveDocument(final Map<String, String[]> metadata, final Part document) throws IOException, SQLException {
final var fileName = UUID.randomUUID().toString();
document.write(fileName);
}
} Again, the full source code is available here: https://github.com/turingg/file-server/tree/jetty-npe. |
@lachlan-roberts it could be that the changes you did in jetty-10 for #4368 would mean this doesn't happen in jetty-10 - can you confirm that? |
@behrangsa as a work around, try calling request.getParameter(String) or request.getParameterMap() BEFORE starting async - this will ensure that your multipart content is already parsed and not in some race condition with the request timing out. |
Always assign _parts when constructed so it is never null. Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Hi Jan,
I will try that tomorrow but would this race condition get fixed in an
upcoming 9.x release by any chance?
Best regards,
{
"blog" : "https://blog.behrang.org",
"twitter" : "https://twitter.com/behrangsa",
"github" : "https://github.com/behrangsa/",
"stackoverflow" : "https://stackoverflow.com/users/309683?tab=profile"}
…On Tue, Dec 3, 2019 at 1:39 PM Jan Bartel ***@***.***> wrote:
@behrangsa <https://github.com/behrangsa> as a work around, try calling
request.getParameter(String) or request.getParameterMap() BEFORE starting
async - this will ensure that your multipart content is already parsed and
not in some race condition with the request timing out.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4383>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAEQE3HWFTDDMWIP44U24DQWXBGTANCNFSM4JTKHAUA>
.
|
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This will stop two threads from parsing at the same time. Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
- Removed synchronization for parsing by two threads. - Introduced an atomic state to decide when it is safe to remove the parts. The call to deleteParts will now cancel the parsing and only delete the parts when the parser exits. Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
Issue #4383 - Minimal NPE prevention on MultiPart
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Issue #4383 - synchronize multiparts for cleanup from different thread
Jetty version
9.4.24.v20191120
Java version
AdoptOpenJDK 11.0.5 HotSpot
OS type/version
Linux, Ubuntu 19.04
Description
Under mostly file-upload heavy load, Jetty sometimes throws an NPE:
** How to reproduce **
You can run the Gatling load tests in this project: https://github.com/turingg/file-server/tree/jetty-npe (the jetty-npe tag).
The text was updated successfully, but these errors were encountered: