-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix out-of-order write in HttpStreamsHandler (#9416)
HttpStreamsHandler delays writing the first HttpContent to when the request has been fully written. The second HttpContent was not delayed however, so when writing the request took time (apparently with TLS?), the second HttpContent was written before the first. This patch delays all further writes (normal, complete and error) until the first content has been written. Should fix micronaut-projects/micronaut-tracing#316
- Loading branch information
Showing
2 changed files
with
96 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
...-netty/src/test/groovy/io/micronaut/http/netty/stream/HttpStreamsClientHandlerSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package io.micronaut.http.netty.stream | ||
|
||
import io.netty.buffer.ByteBuf | ||
import io.netty.buffer.Unpooled | ||
import io.netty.channel.ChannelHandlerContext | ||
import io.netty.channel.ChannelOutboundHandlerAdapter | ||
import io.netty.channel.ChannelPromise | ||
import io.netty.channel.embedded.EmbeddedChannel | ||
import io.netty.handler.codec.http.DefaultHttpContent | ||
import io.netty.handler.codec.http.DefaultHttpRequest | ||
import io.netty.handler.codec.http.HttpContent | ||
import io.netty.handler.codec.http.HttpMethod | ||
import io.netty.handler.codec.http.HttpRequest | ||
import io.netty.handler.codec.http.HttpVersion | ||
import io.netty.handler.codec.http.LastHttpContent | ||
import reactor.core.publisher.Flux | ||
import spock.lang.Issue | ||
import spock.lang.Specification | ||
|
||
import java.nio.charset.StandardCharsets | ||
|
||
class HttpStreamsClientHandlerSpec extends Specification { | ||
@Issue('https://github.com/micronaut-projects/micronaut-tracing/issues/316') | ||
def 'out of order write'() { | ||
given: | ||
ChannelPromise firstWritePromise = null | ||
def channel = new EmbeddedChannel( | ||
new ChannelOutboundHandlerAdapter() { | ||
@Override | ||
void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { | ||
// delay the completion of the write of the HttpRequest | ||
if (firstWritePromise == null) { | ||
firstWritePromise = promise | ||
ctx.write(msg, ctx.voidPromise()) | ||
return | ||
} | ||
super.write(ctx, msg, promise) | ||
} | ||
}, | ||
new HttpStreamsClientHandler() | ||
) | ||
def msg = new DelegateStreamedHttpRequest( | ||
new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/"), | ||
JsonSubscriber.lift(Flux.just(new DefaultHttpContent(Unpooled.wrappedBuffer("\"foo\"".getBytes(StandardCharsets.UTF_8))))) | ||
) | ||
|
||
when: | ||
channel.writeOutbound(msg) | ||
firstWritePromise.trySuccess() | ||
channel.flushOutbound() | ||
then: | ||
channel.readOutbound() instanceof HttpRequest | ||
when: | ||
ByteBuf combined = Unpooled.buffer() | ||
while (true) { | ||
HttpContent h = channel.readOutbound() | ||
combined.writeBytes(h.content()) | ||
if (h instanceof LastHttpContent) { | ||
break | ||
} | ||
} | ||
then: | ||
combined.toString(StandardCharsets.UTF_8) == "[\"foo\"]" | ||
!channel.finish() | ||
} | ||
} |