use of io.netty.handler.codec.http.FullHttpMessage in project netty by netty.
the class InboundHttp2ToHttpAdapterTest method serverResponseHeaderInformational.
@Test
public void serverResponseHeaderInformational() throws Exception {
boostrapEnv(1, 2, 1, 2, 1);
final FullHttpMessage request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.PUT, "/info/test", true);
HttpHeaders httpHeaders = request.headers();
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
httpHeaders.set(HttpHeaderNames.EXPECT, HttpHeaderValues.CONTINUE);
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("PUT")).path(new AsciiString("/info/test")).set(new AsciiString(HttpHeaderNames.EXPECT.toString()), new AsciiString(HttpHeaderValues.CONTINUE.toString()));
final FullHttpMessage response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
final String text = "a big payload";
final ByteBuf payload = Unpooled.copiedBuffer(text.getBytes());
final FullHttpMessage request2 = request.replace(payload);
final FullHttpMessage response2 = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
try {
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
clientChannel.flush();
}
});
awaitRequests();
httpHeaders = response.headers();
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
final Http2Headers http2HeadersResponse = new DefaultHttp2Headers().status(new AsciiString("100"));
runInChannel(serverConnectedChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2HeadersResponse, 0, false, newPromiseServer());
serverConnectedChannel.flush();
}
});
awaitResponses();
httpHeaders = request2.headers();
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length());
httpHeaders.remove(HttpHeaderNames.EXPECT);
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() {
clientHandler.encoder().writeData(ctxClient(), 3, payload.retainedDuplicate(), 0, true, newPromiseClient());
clientChannel.flush();
}
});
awaitRequests2();
httpHeaders = response2.headers();
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
final Http2Headers http2HeadersResponse2 = new DefaultHttp2Headers().status(new AsciiString("200"));
runInChannel(serverConnectedChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2HeadersResponse2, 0, true, newPromiseServer());
serverConnectedChannel.flush();
}
});
awaitResponses2();
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
verify(serverListener, times(2)).messageReceived(requestCaptor.capture());
capturedRequests = requestCaptor.getAllValues();
assertEquals(2, capturedRequests.size());
assertEquals(request, capturedRequests.get(0));
assertEquals(request2, capturedRequests.get(1));
ArgumentCaptor<FullHttpMessage> responseCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
verify(clientListener, times(2)).messageReceived(responseCaptor.capture());
capturedResponses = responseCaptor.getAllValues();
assertEquals(2, capturedResponses.size());
assertEquals(response, capturedResponses.get(0));
assertEquals(response2, capturedResponses.get(1));
} finally {
request.release();
request2.release();
response.release();
response2.release();
}
}
use of io.netty.handler.codec.http.FullHttpMessage in project netty by netty.
the class HttpToHttp2ConnectionHandler method write.
/**
* Handles conversion of {@link HttpMessage} and {@link HttpContent} to HTTP/2 frames.
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
if (!(msg instanceof HttpMessage || msg instanceof HttpContent)) {
ctx.write(msg, promise);
return;
}
boolean release = true;
SimpleChannelPromiseAggregator promiseAggregator = new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
try {
Http2ConnectionEncoder encoder = encoder();
boolean endStream = false;
if (msg instanceof HttpMessage) {
final HttpMessage httpMsg = (HttpMessage) msg;
// Provide the user the opportunity to specify the streamId
currentStreamId = getStreamId(httpMsg.headers());
// Convert and write the headers.
Http2Headers http2Headers = HttpConversionUtil.toHttp2Headers(httpMsg, validateHeaders);
endStream = msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable();
writeHeaders(ctx, encoder, currentStreamId, httpMsg.headers(), http2Headers, endStream, promiseAggregator);
}
if (!endStream && msg instanceof HttpContent) {
boolean isLastContent = false;
HttpHeaders trailers = EmptyHttpHeaders.INSTANCE;
Http2Headers http2Trailers = EmptyHttp2Headers.INSTANCE;
if (msg instanceof LastHttpContent) {
isLastContent = true;
// Convert any trailing headers.
final LastHttpContent lastContent = (LastHttpContent) msg;
trailers = lastContent.trailingHeaders();
http2Trailers = HttpConversionUtil.toHttp2Headers(trailers, validateHeaders);
}
// Write the data
final ByteBuf content = ((HttpContent) msg).content();
endStream = isLastContent && trailers.isEmpty();
release = false;
encoder.writeData(ctx, currentStreamId, content, 0, endStream, promiseAggregator.newPromise());
if (!trailers.isEmpty()) {
// Write trailing headers.
writeHeaders(ctx, encoder, currentStreamId, trailers, http2Trailers, true, promiseAggregator);
}
}
} catch (Throwable t) {
onError(ctx, t);
promiseAggregator.setFailure(t);
} finally {
if (release) {
ReferenceCountUtil.release(msg);
}
promiseAggregator.doneAllocatingPromises();
}
}
use of io.netty.handler.codec.http.FullHttpMessage in project netty by netty.
the class InboundHttp2ToHttpAdapter method onHeadersRead.
@Override
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency, short weight, boolean exclusive, int padding, boolean endOfStream) throws Http2Exception {
Http2Stream stream = connection.stream(streamId);
FullHttpMessage msg = processHeadersBegin(ctx, stream, headers, endOfStream, true, true);
if (msg != null) {
// See https://github.com/netty/netty/issues/5866
if (streamDependency != Http2CodecUtil.CONNECTION_STREAM_ID) {
msg.headers().setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_DEPENDENCY_ID.text(), streamDependency);
}
msg.headers().setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), weight);
processHeadersEnd(ctx, stream, msg, endOfStream);
}
}
use of io.netty.handler.codec.http.FullHttpMessage in project netty by netty.
the class InboundHttp2ToHttpAdapter method processHeadersBegin.
/**
* Provides translation between HTTP/2 and HTTP header objects while ensuring the stream
* is in a valid state for additional headers.
*
* @param ctx The context for which this message has been received.
* Used to send informational header if detected.
* @param stream The stream the {@code headers} apply to
* @param headers The headers to process
* @param endOfStream {@code true} if the {@code stream} has received the end of stream flag
* @param allowAppend
* <ul>
* <li>{@code true} if headers will be appended if the stream already exists.</li>
* <li>if {@code false} and the stream already exists this method returns {@code null}.</li>
* </ul>
* @param appendToTrailer
* <ul>
* <li>{@code true} if a message {@code stream} already exists then the headers
* should be added to the trailing headers.</li>
* <li>{@code false} then appends will be done to the initial headers.</li>
* </ul>
* @return The object used to track the stream corresponding to {@code stream}. {@code null} if
* {@code allowAppend} is {@code false} and the stream already exists.
* @throws Http2Exception If the stream id is not in the correct state to process the headers request
*/
protected FullHttpMessage processHeadersBegin(ChannelHandlerContext ctx, Http2Stream stream, Http2Headers headers, boolean endOfStream, boolean allowAppend, boolean appendToTrailer) throws Http2Exception {
FullHttpMessage msg = getMessage(stream);
boolean release = true;
if (msg == null) {
msg = newMessage(stream, headers, validateHttpHeaders, ctx.alloc());
} else if (allowAppend) {
release = false;
HttpConversionUtil.addHttp2ToHttpHeaders(stream.id(), headers, msg, appendToTrailer);
} else {
release = false;
msg = null;
}
if (sendDetector.mustSendImmediately(msg)) {
// Copy the message (if necessary) before sending. The content is not expected to be copied (or used) in
// this operation but just in case it is used do the copy before sending and the resource may be released
final FullHttpMessage copy = endOfStream ? null : sendDetector.copyIfNeeded(msg);
fireChannelRead(ctx, msg, release, stream);
return copy;
}
return msg;
}
use of io.netty.handler.codec.http.FullHttpMessage in project netty by netty.
the class InboundHttp2ToHttpAdapter method onRstStreamRead.
@Override
public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
Http2Stream stream = connection.stream(streamId);
FullHttpMessage msg = getMessage(stream);
if (msg != null) {
onRstStreamRead(stream, msg);
}
ctx.fireExceptionCaught(Http2Exception.streamError(streamId, Http2Error.valueOf(errorCode), "HTTP/2 to HTTP layer caught stream reset"));
}
Aggregations