-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Workaround for netty chunked upload issue #1563
Workaround for netty chunked upload issue #1563
Conversation
String className = element.getClassName(); | ||
String methodName = element.getMethodName(); | ||
if (className.contains("ChunkedWriteHandler") && (methodName.equals("flush") || methodName.equals("write"))) | ||
System.exit(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
o_0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol... sorry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anyway build will fail due to some issues:
Dynamic Oracle JDK installations are currently unavailable due to a problem with our upstream provider. In the meantime, container-based builds come with JDKs preinstalled.
c3e81d0
to
3cf0473
Compare
not my day :D |
@beargummy Any reason why you closed this PR? Is it broken? |
I found one more case which also affected by this issue (BodyChunkedInput) |
if (className.contains("ChunkedWriteHandler") && (methodName.equals("flush") || methodName.equals("write"))) | ||
return true; | ||
} | ||
} catch (Throwable ignore) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this try/catch for? Are you sure you want to catch Throwable???
.addListener(new WriteProgressListener(future, false, getContentLength()) { | ||
@Override | ||
public void operationComplete(ChannelProgressiveFuture cf) { | ||
closeSilently(body); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need that? I would expect Netty to close the ChunkedInput.
@@ -56,6 +59,14 @@ public void write(final Channel channel, NettyResponseFuture<?> future) { | |||
if (body instanceof RandomAccessBody && !ChannelManager.isSslHandlerConfigured(channel.pipeline()) && !config.isDisableZeroCopy()) { | |||
msg = new BodyFileRegion((RandomAccessBody) body); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason you only fixed for ChunkedInput and not for FileRegion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen it failing, but I'll add workaround for this case too.
} | ||
} | ||
|
||
return t.getCause() != null && recoverOnChunkedUploadFailed(t.getCause()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you check which Exception you actually get? Do you really need to recurse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, there is no need for recursive call.
// FIXME dirty hack until netty issue is not resolved, see https://github.com/netty/netty/issues/6706 | ||
if (cause instanceof IOException && StackTraceInspector.recoverOnChunkedUploadFailed(cause)) | ||
return false; | ||
return super.abortOnThrowable(channel, cause); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge into one single boolean op
// FIXME dirty hack until netty issue is not resolved, see https://github.com/netty/netty/issues/6706 | ||
if (cause instanceof IOException && StackTraceInspector.recoverOnChunkedUploadFailed(cause)) | ||
return false; | ||
return super.abortOnThrowable(channel, cause); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge into one single boolean op
Motivation: Netty doesn't provide any ability to handle early server response when uploading chunked file and instead, `IOException: Pipe closed` is thrown (see netty/netty#6706 for details). Changes: NettyInputStreamBody and BodyChunkedInput swallow ChannelOutputShutdownException in case it is thrown from netty's ChunkedWriteHandler. Result: Multipart early response is available to be handled properly.
df27f2d
to
cc71b72
Compare
@slandelle do you have any objections? |
@Override | ||
protected boolean abortOnThrowable(Channel channel, Throwable cause) { | ||
// FIXME dirty hack until netty issue is not resolved, see https://github.com/netty/netty/issues/6706 | ||
return StackTraceInspector.recoverOnChunkedUploadFailed(cause) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, do we really need stacktrace inspection?
We already know that we're uploading a body. Is there really a way to get a ChannelOutputShutdownException
whose stacktrace wouldn't pass though ChunkedWriteHandler#flush
(note that there's still some work to do with FileRegion)?
Then, my concern is that I'm not sure wether a ChannelOutputShutdownException
always means that we'll still be able to read nor if there's anything to read at all. I'm afraid if we don't have a response to read, we'll hang in half closed state forever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right, there is no need to check stack trace in this case.
Regarding FileRegion - it is not affected by this issue, since ChunkedWriteHandler handles it in totally different manner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure there's the same issue with FileRegion, but that it can't be fixed the same way :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I wasn't able to reproduce the issue for FileRegion so far. But maybe you're right.
@@ -69,6 +69,13 @@ public void handle(String pathInContext, Request request, HttpServletRequest htt | |||
httpResponse.sendRedirect(httpRequest.getHeader("X-redirect")); | |||
return; | |||
} | |||
if (headerName.startsWith("X-fail")) { | |||
httpResponse.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); | |||
httpResponse.getOutputStream().write("custom error message".getBytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This response is invalid: as you set a body (and we want one as we want to test this use case), you need to set the Content-Length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String#getBytes
is something horrible that should be dropped from Java. Please pass the Charset, eg getBytes(StandardCharsets.US_ASCII/UTF_8)
@@ -69,6 +69,13 @@ public void handle(String pathInContext, Request request, HttpServletRequest htt | |||
httpResponse.sendRedirect(httpRequest.getHeader("X-redirect")); | |||
return; | |||
} | |||
if (headerName.startsWith("X-fail")) { | |||
httpResponse.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); | |||
httpResponse.getOutputStream().write("custom error message".getBytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String#getBytes
is something horrible that should be dropped from Java. Please pass the Charset, eg getBytes(StandardCharsets.US_ASCII/UTF_8)
Motivation:
Netty doesn't provide any ability to handle early server response when uploading chunked file and instead,
IOException: Pipe closed
is thrown (see netty/netty#6706 for details).Changes:
NettyInputStreamBody swallows ChannelOutputShutdownException in case it is thrown from netty's ChunkedWriteHandler.
Result:
Multipart early response is available to be handled properly.