netty5/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2FrameCodecTest.java

835 lines
35 KiB
Java
Raw Normal View History

/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeEvent;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http2.Http2Exception.StreamException;
import io.netty.handler.codec.http2.Http2Stream.State;
import io.netty.handler.logging.LogLevel;
import io.netty.util.AbstractReferenceCounted;
import io.netty.util.AsciiString;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ReferenceCounted;
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.ReflectionUtil;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
import static io.netty.handler.codec.http2.Http2CodecUtil.isStreamIdValid;
import static io.netty.handler.codec.http2.Http2TestUtil.anyChannelPromise;
import static io.netty.handler.codec.http2.Http2TestUtil.anyHttp2Settings;
import static io.netty.handler.codec.http2.Http2TestUtil.assertEqualsAndRelease;
import static io.netty.handler.codec.http2.Http2TestUtil.bb;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyShort;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Unit tests for {@link Http2FrameCodec}.
*/
public class Http2FrameCodecTest {
// For verifying outbound frames
private Http2FrameWriter frameWriter;
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
private Http2FrameCodec frameCodec;
private EmbeddedChannel channel;
// For injecting inbound frames
private Http2FrameInboundWriter frameInboundWriter;
private LastInboundHandler inboundHandler;
private final Http2Headers request = new DefaultHttp2Headers()
.method(HttpMethod.GET.asciiName()).scheme(HttpScheme.HTTPS.name())
.authority(new AsciiString("example.org")).path(new AsciiString("/foo"));
private final Http2Headers response = new DefaultHttp2Headers()
.status(HttpResponseStatus.OK.codeAsText());
@Before
public void setUp() throws Exception {
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
setUp(Http2FrameCodecBuilder.forServer(), new Http2Settings());
}
@After
public void tearDown() throws Exception {
if (inboundHandler != null) {
inboundHandler.finishAndReleaseAll();
inboundHandler = null;
}
if (channel != null) {
channel.finishAndReleaseAll();
channel.close();
channel = null;
}
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
}
private void setUp(Http2FrameCodecBuilder frameCodecBuilder, Http2Settings initialRemoteSettings) throws Exception {
/**
* Some tests call this method twice. Once with JUnit's @Before and once directly to pass special settings.
* This call ensures that in case of two consecutive calls to setUp(), the previous channel is shutdown and
* ByteBufs are released correctly.
*/
tearDown();
frameWriter = Http2TestUtil.mockedFrameWriter();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
frameCodec = frameCodecBuilder.frameWriter(frameWriter).frameLogger(new Http2FrameLogger(LogLevel.TRACE))
.initialSettings(initialRemoteSettings).build();
inboundHandler = new LastInboundHandler();
channel = new EmbeddedChannel();
frameInboundWriter = new Http2FrameInboundWriter(channel);
channel.connect(new InetSocketAddress(0));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
channel.pipeline().addLast(frameCodec);
channel.pipeline().addLast(inboundHandler);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
channel.pipeline().fireChannelActive();
// Handshake
verify(frameWriter).writeSettings(eqFrameCodecCtx(), anyHttp2Settings(), anyChannelPromise());
verifyNoMoreInteractions(frameWriter);
channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf());
frameInboundWriter.writeInboundSettings(initialRemoteSettings);
verify(frameWriter).writeSettingsAck(eqFrameCodecCtx(), anyChannelPromise());
frameInboundWriter.writeInboundSettingsAck();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2SettingsFrame settingsFrame = inboundHandler.readInbound();
assertNotNull(settingsFrame);
Http2SettingsAckFrame settingsAckFrame = inboundHandler.readInbound();
assertNotNull(settingsAckFrame);
}
@Test
public void stateChanges() throws Exception {
frameInboundWriter.writeInboundHeaders(1, request, 31, true);
Http2Stream stream = frameCodec.connection().stream(1);
assertNotNull(stream);
assertEquals(State.HALF_CLOSED_REMOTE, stream.state());
Http2FrameStreamEvent event = inboundHandler.readInboundMessageOrUserEvent();
assertEquals(State.HALF_CLOSED_REMOTE, event.stream().state());
Http2StreamFrame inboundFrame = inboundHandler.readInbound();
Http2FrameStream stream2 = inboundFrame.stream();
assertNotNull(stream2);
assertEquals(1, stream2.id());
assertEquals(inboundFrame, new DefaultHttp2HeadersFrame(request, true, 31).stream(stream2));
assertNull(inboundHandler.readInbound());
channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2));
verify(frameWriter).writeHeaders(
eqFrameCodecCtx(), eq(1), eq(response), anyInt(), anyShort(), anyBoolean(),
eq(27), eq(true), anyChannelPromise());
verify(frameWriter, never()).writeRstStream(
eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise());
assertEquals(State.CLOSED, stream.state());
event = inboundHandler.readInboundMessageOrUserEvent();
assertEquals(State.CLOSED, event.stream().state());
assertTrue(channel.isActive());
}
@Test
public void headerRequestHeaderResponse() throws Exception {
frameInboundWriter.writeInboundHeaders(1, request, 31, true);
Http2Stream stream = frameCodec.connection().stream(1);
assertNotNull(stream);
assertEquals(State.HALF_CLOSED_REMOTE, stream.state());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2StreamFrame inboundFrame = inboundHandler.readInbound();
Http2FrameStream stream2 = inboundFrame.stream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNotNull(stream2);
assertEquals(1, stream2.id());
assertEquals(inboundFrame, new DefaultHttp2HeadersFrame(request, true, 31).stream(stream2));
assertNull(inboundHandler.readInbound());
channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2));
verify(frameWriter).writeHeaders(
eqFrameCodecCtx(), eq(1), eq(response), anyInt(), anyShort(), anyBoolean(),
eq(27), eq(true), anyChannelPromise());
verify(frameWriter, never()).writeRstStream(
eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise());
assertEquals(State.CLOSED, stream.state());
assertTrue(channel.isActive());
}
@Test
public void flowControlShouldBeResilientToMissingStreams() throws Http2Exception {
Http2Connection conn = new DefaultHttp2Connection(true);
Http2ConnectionEncoder enc = new DefaultHttp2ConnectionEncoder(conn, new DefaultHttp2FrameWriter());
Http2ConnectionDecoder dec = new DefaultHttp2ConnectionDecoder(conn, enc, new DefaultHttp2FrameReader());
Http2FrameCodec codec = new Http2FrameCodec(enc, dec, new Http2Settings());
EmbeddedChannel em = new EmbeddedChannel(codec);
// We call #consumeBytes on a stream id which has not been seen yet to emulate the case
// where a stream is deregistered which in reality can happen in response to a RST.
assertFalse(codec.consumeBytes(1, 1));
assertTrue(em.finishAndReleaseAll());
}
@Test
public void entityRequestEntityResponse() throws Exception {
frameInboundWriter.writeInboundHeaders(1, request, 0, false);
Http2Stream stream = frameCodec.connection().stream(1);
assertNotNull(stream);
assertEquals(State.OPEN, stream.state());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame inboundHeaders = inboundHandler.readInbound();
Http2FrameStream stream2 = inboundHeaders.stream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNotNull(stream2);
assertEquals(1, stream2.id());
assertEquals(new DefaultHttp2HeadersFrame(request, false).stream(stream2), inboundHeaders);
assertNull(inboundHandler.readInbound());
ByteBuf hello = bb("hello");
frameInboundWriter.writeInboundData(1, hello, 31, true);
Http2DataFrame inboundData = inboundHandler.readInbound();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2DataFrame expected = new DefaultHttp2DataFrame(bb("hello"), true, 31).stream(stream2);
assertEqualsAndRelease(expected, inboundData);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNull(inboundHandler.readInbound());
channel.writeOutbound(new DefaultHttp2HeadersFrame(response, false).stream(stream2));
verify(frameWriter).writeHeaders(eqFrameCodecCtx(), eq(1), eq(response), anyInt(),
anyShort(), anyBoolean(), eq(0), eq(false), anyChannelPromise());
channel.writeOutbound(new DefaultHttp2DataFrame(bb("world"), true, 27).stream(stream2));
ArgumentCaptor<ByteBuf> outboundData = ArgumentCaptor.forClass(ByteBuf.class);
verify(frameWriter).writeData(eqFrameCodecCtx(), eq(1), outboundData.capture(), eq(27),
eq(true), anyChannelPromise());
ByteBuf bb = bb("world");
assertEquals(bb, outboundData.getValue());
assertEquals(1, outboundData.getValue().refCnt());
bb.release();
outboundData.getValue().release();
verify(frameWriter, never()).writeRstStream(eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise());
assertTrue(channel.isActive());
}
@Test
public void sendRstStream() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, true);
Http2Stream stream = frameCodec.connection().stream(3);
assertNotNull(stream);
assertEquals(State.HALF_CLOSED_REMOTE, stream.state());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame inboundHeaders = inboundHandler.readInbound();
assertNotNull(inboundHeaders);
assertTrue(inboundHeaders.isEndStream());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2FrameStream stream2 = inboundHeaders.stream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNotNull(stream2);
assertEquals(3, stream2.id());
channel.writeOutbound(new DefaultHttp2ResetFrame(314 /* non-standard error */).stream(stream2));
verify(frameWriter).writeRstStream(eqFrameCodecCtx(), eq(3), eq(314L), anyChannelPromise());
assertEquals(State.CLOSED, stream.state());
assertTrue(channel.isActive());
}
@Test
public void receiveRstStream() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
Http2Stream stream = frameCodec.connection().stream(3);
assertNotNull(stream);
assertEquals(State.OPEN, stream.state());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame expectedHeaders = new DefaultHttp2HeadersFrame(request, false, 31);
Http2HeadersFrame actualHeaders = inboundHandler.readInbound();
assertEquals(expectedHeaders.stream(actualHeaders.stream()), actualHeaders);
frameInboundWriter.writeInboundRstStream(3, Http2Error.NO_ERROR.code());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2ResetFrame expectedRst = new DefaultHttp2ResetFrame(Http2Error.NO_ERROR).stream(actualHeaders.stream());
Http2ResetFrame actualRst = inboundHandler.readInbound();
assertEquals(expectedRst, actualRst);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNull(inboundHandler.readInbound());
}
@Test
public void sendGoAway() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
Http2Stream stream = frameCodec.connection().stream(3);
assertNotNull(stream);
assertEquals(State.OPEN, stream.state());
ByteBuf debugData = bb("debug");
ByteBuf expected = debugData.copy();
Http2GoAwayFrame goAwayFrame = new DefaultHttp2GoAwayFrame(Http2Error.NO_ERROR.code(), debugData);
goAwayFrame.setExtraStreamIds(2);
channel.writeOutbound(goAwayFrame);
verify(frameWriter).writeGoAway(eqFrameCodecCtx(), eq(7),
eq(Http2Error.NO_ERROR.code()), eq(expected), anyChannelPromise());
assertEquals(1, debugData.refCnt());
assertEquals(State.OPEN, stream.state());
assertTrue(channel.isActive());
expected.release();
debugData.release();
}
@Test
public void receiveGoaway() throws Exception {
ByteBuf debugData = bb("foo");
frameInboundWriter.writeInboundGoAway(2, Http2Error.NO_ERROR.code(), debugData);
Http2GoAwayFrame expectedFrame = new DefaultHttp2GoAwayFrame(2, Http2Error.NO_ERROR.code(), bb("foo"));
Http2GoAwayFrame actualFrame = inboundHandler.readInbound();
assertEqualsAndRelease(expectedFrame, actualFrame);
assertNull(inboundHandler.readInbound());
}
@Test
public void unknownFrameTypeShouldThrowAndBeReleased() throws Exception {
class UnknownHttp2Frame extends AbstractReferenceCounted implements Http2Frame {
@Override
public String name() {
return "UNKNOWN";
}
@Override
protected void deallocate() {
}
@Override
public ReferenceCounted touch(Object hint) {
return this;
}
}
UnknownHttp2Frame frame = new UnknownHttp2Frame();
assertEquals(1, frame.refCnt());
ChannelFuture f = channel.write(frame);
f.await();
assertTrue(f.isDone());
assertFalse(f.isSuccess());
assertThat(f.cause(), instanceOf(UnsupportedMessageTypeException.class));
assertEquals(0, frame.refCnt());
}
@Test
public void goAwayLastStreamIdOverflowed() throws Exception {
frameInboundWriter.writeInboundHeaders(5, request, 31, false);
Http2Stream stream = frameCodec.connection().stream(5);
assertNotNull(stream);
assertEquals(State.OPEN, stream.state());
ByteBuf debugData = bb("debug");
Http2GoAwayFrame goAwayFrame = new DefaultHttp2GoAwayFrame(Http2Error.NO_ERROR.code(), debugData.slice());
goAwayFrame.setExtraStreamIds(Integer.MAX_VALUE);
channel.writeOutbound(goAwayFrame);
// When the last stream id computation overflows, the last stream id should just be set to 2^31 - 1.
verify(frameWriter).writeGoAway(eqFrameCodecCtx(), eq(Integer.MAX_VALUE),
eq(Http2Error.NO_ERROR.code()), eq(debugData), anyChannelPromise());
assertEquals(1, debugData.refCnt());
assertEquals(State.OPEN, stream.state());
assertTrue(channel.isActive());
}
@Test
public void streamErrorShouldFireExceptionForInbound() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
Http2Stream stream = frameCodec.connection().stream(3);
assertNotNull(stream);
StreamException streamEx = new StreamException(3, Http2Error.INTERNAL_ERROR, "foo");
channel.pipeline().fireExceptionCaught(streamEx);
Http2FrameStreamEvent event = inboundHandler.readInboundMessageOrUserEvent();
assertEquals(Http2FrameStreamEvent.Type.State, event.type());
assertEquals(State.OPEN, event.stream().state());
Http2HeadersFrame headersFrame = inboundHandler.readInboundMessageOrUserEvent();
assertNotNull(headersFrame);
try {
inboundHandler.checkException();
fail("stream exception expected");
} catch (Http2FrameStreamException e) {
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertEquals(streamEx, e.getCause());
}
assertNull(inboundHandler.readInboundMessageOrUserEvent());
}
@Test
public void streamErrorShouldNotFireExceptionForOutbound() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
Http2Stream stream = frameCodec.connection().stream(3);
assertNotNull(stream);
StreamException streamEx = new StreamException(3, Http2Error.INTERNAL_ERROR, "foo");
frameCodec.onError(frameCodec.ctx, true, streamEx);
Http2FrameStreamEvent event = inboundHandler.readInboundMessageOrUserEvent();
assertEquals(Http2FrameStreamEvent.Type.State, event.type());
assertEquals(State.OPEN, event.stream().state());
Http2HeadersFrame headersFrame = inboundHandler.readInboundMessageOrUserEvent();
assertNotNull(headersFrame);
// No exception expected
inboundHandler.checkException();
assertNull(inboundHandler.readInboundMessageOrUserEvent());
}
@Test
public void windowUpdateFrameDecrementsConsumedBytes() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
Http2Connection connection = frameCodec.connection();
Http2Stream stream = connection.stream(3);
assertNotNull(stream);
ByteBuf data = Unpooled.buffer(100).writeZero(100);
frameInboundWriter.writeInboundData(3, data, 0, false);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame inboundHeaders = inboundHandler.readInbound();
assertNotNull(inboundHeaders);
assertNotNull(inboundHeaders.stream());
Http2FrameStream stream2 = inboundHeaders.stream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
int before = connection.local().flowController().unconsumedBytes(stream);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
ChannelFuture f = channel.write(new DefaultHttp2WindowUpdateFrame(100).stream(stream2));
int after = connection.local().flowController().unconsumedBytes(stream);
assertEquals(100, before - after);
assertTrue(f.isSuccess());
}
@Test
public void windowUpdateMayFail() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
Http2Connection connection = frameCodec.connection();
Http2Stream stream = connection.stream(3);
assertNotNull(stream);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame inboundHeaders = inboundHandler.readInbound();
assertNotNull(inboundHeaders);
Http2FrameStream stream2 = inboundHeaders.stream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
// Fails, cause trying to return too many bytes to the flow controller
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
ChannelFuture f = channel.write(new DefaultHttp2WindowUpdateFrame(100).stream(stream2));
assertTrue(f.isDone());
assertFalse(f.isSuccess());
assertThat(f.cause(), instanceOf(Http2Exception.class));
}
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
@Test
public void inboundWindowUpdateShouldBeForwarded() throws Exception {
frameInboundWriter.writeInboundHeaders(3, request, 31, false);
frameInboundWriter.writeInboundWindowUpdate(3, 100);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
// Connection-level window update
frameInboundWriter.writeInboundWindowUpdate(0, 100);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame headersFrame = inboundHandler.readInbound();
assertNotNull(headersFrame);
Http2WindowUpdateFrame windowUpdateFrame = inboundHandler.readInbound();
assertNotNull(windowUpdateFrame);
assertEquals(3, windowUpdateFrame.stream().id());
assertEquals(100, windowUpdateFrame.windowSizeIncrement());
// Window update for the connection should not be forwarded.
assertNull(inboundHandler.readInbound());
}
@Test
public void streamZeroWindowUpdateIncrementsConnectionWindow() throws Http2Exception {
Http2Connection connection = frameCodec.connection();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2LocalFlowController localFlow = connection.local().flowController();
int initialWindowSizeBefore = localFlow.initialWindowSize();
Http2Stream connectionStream = connection.connectionStream();
int connectionWindowSizeBefore = localFlow.windowSize(connectionStream);
// We only replenish the flow control window after the amount consumed drops below the following threshold.
// We make the threshold very "high" so that window updates will be sent when the delta is relatively small.
((DefaultHttp2LocalFlowController) localFlow).windowUpdateRatio(connectionStream, .999f);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
int windowUpdate = 1024;
channel.write(new DefaultHttp2WindowUpdateFrame(windowUpdate));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
// The initial window size is only changed by Http2Settings, so it shouldn't change.
assertEquals(initialWindowSizeBefore, localFlow.initialWindowSize());
// The connection window should be increased by the delta amount.
assertEquals(connectionWindowSizeBefore + windowUpdate, localFlow.windowSize(connectionStream));
}
@Test
public void windowUpdateDoesNotOverflowConnectionWindow() {
Http2Connection connection = frameCodec.connection();
Http2LocalFlowController localFlow = connection.local().flowController();
int initialWindowSizeBefore = localFlow.initialWindowSize();
channel.write(new DefaultHttp2WindowUpdateFrame(Integer.MAX_VALUE));
// The initial window size is only changed by Http2Settings, so it shouldn't change.
assertEquals(initialWindowSizeBefore, localFlow.initialWindowSize());
// The connection window should be increased by the delta amount.
assertEquals(Integer.MAX_VALUE, localFlow.windowSize(connection.connectionStream()));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
}
@Test
public void writeUnknownFrame() {
final Http2FrameStream stream = frameCodec.newStream();
ByteBuf buffer = Unpooled.buffer().writeByte(1);
DefaultHttp2UnknownFrame unknownFrame = new DefaultHttp2UnknownFrame(
(byte) 20, new Http2Flags().ack(true), buffer);
unknownFrame.stream(stream);
channel.write(unknownFrame);
verify(frameWriter).writeFrame(eqFrameCodecCtx(), eq(unknownFrame.frameType()),
eq(unknownFrame.stream().id()), eq(unknownFrame.flags()), eq(buffer), any(ChannelPromise.class));
}
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
@Test
public void sendSettingsFrame() {
Http2Settings settings = new Http2Settings();
channel.write(new DefaultHttp2SettingsFrame(settings));
verify(frameWriter).writeSettings(eqFrameCodecCtx(), same(settings), any(ChannelPromise.class));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
}
@Test(timeout = 5000)
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
public void newOutboundStream() {
final Http2FrameStream stream = frameCodec.newStream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNotNull(stream);
assertFalse(isStreamIdValid(stream.id()));
final Promise<Void> listenerExecuted = new DefaultPromise<Void>(GlobalEventExecutor.INSTANCE);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers(), false).stream(stream))
.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
assertTrue(future.isSuccess());
assertTrue(isStreamIdValid(stream.id()));
listenerExecuted.setSuccess(null);
}
}
);
ByteBuf data = Unpooled.buffer().writeZero(100);
ChannelFuture f = channel.writeAndFlush(new DefaultHttp2DataFrame(data).stream(stream));
assertTrue(f.isSuccess());
listenerExecuted.syncUninterruptibly();
assertTrue(listenerExecuted.isSuccess());
}
@Test
public void newOutboundStreamsShouldBeBuffered() throws Exception {
setUp(Http2FrameCodecBuilder.forServer().encoderEnforceMaxConcurrentStreams(true),
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
new Http2Settings().maxConcurrentStreams(1));
Http2FrameStream stream1 = frameCodec.newStream();
Http2FrameStream stream2 = frameCodec.newStream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
ChannelPromise promise1 = channel.newPromise();
ChannelPromise promise2 = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream1), promise1);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2), promise2);
assertTrue(isStreamIdValid(stream1.id()));
channel.runPendingTasks();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertTrue(isStreamIdValid(stream2.id()));
assertTrue(promise1.syncUninterruptibly().isSuccess());
assertFalse(promise2.isDone());
// Increase concurrent streams limit to 2
frameInboundWriter.writeInboundSettings(new Http2Settings().maxConcurrentStreams(2));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
channel.flush();
assertTrue(promise2.syncUninterruptibly().isSuccess());
}
@Test
public void multipleNewOutboundStreamsShouldBeBuffered() throws Exception {
// We use a limit of 1 and then increase it step by step.
setUp(Http2FrameCodecBuilder.forServer().encoderEnforceMaxConcurrentStreams(true),
new Http2Settings().maxConcurrentStreams(1));
Http2FrameStream stream1 = frameCodec.newStream();
Http2FrameStream stream2 = frameCodec.newStream();
Http2FrameStream stream3 = frameCodec.newStream();
ChannelPromise promise1 = channel.newPromise();
ChannelPromise promise2 = channel.newPromise();
ChannelPromise promise3 = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream1), promise1);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2), promise2);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream3), promise3);
assertTrue(isStreamIdValid(stream1.id()));
channel.runPendingTasks();
assertTrue(isStreamIdValid(stream2.id()));
assertTrue(promise1.syncUninterruptibly().isSuccess());
assertFalse(promise2.isDone());
assertFalse(promise3.isDone());
// Increase concurrent streams limit to 2
frameInboundWriter.writeInboundSettings(new Http2Settings().maxConcurrentStreams(2));
channel.flush();
// As we increased the limit to 2 we should have also succeed the second frame.
assertTrue(promise2.syncUninterruptibly().isSuccess());
assertFalse(promise3.isDone());
frameInboundWriter.writeInboundSettings(new Http2Settings().maxConcurrentStreams(3));
channel.flush();
// With the max streams of 3 all streams should be succeed now.
assertTrue(promise3.syncUninterruptibly().isSuccess());
assertFalse(channel.finishAndReleaseAll());
}
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
@Test
public void streamIdentifiersExhausted() throws Http2Exception {
int maxServerStreamId = Integer.MAX_VALUE - 1;
assertNotNull(frameCodec.connection().local().createStream(maxServerStreamId, false));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2FrameStream stream = frameCodec.newStream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertNotNull(stream);
ChannelPromise writePromise = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream), writePromise);
assertThat(writePromise.cause(), instanceOf(Http2NoMoreStreamIdsException.class));
}
@Test
public void receivePing() throws Http2Exception {
frameInboundWriter.writeInboundPing(false, 12345L);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2PingFrame pingFrame = inboundHandler.readInbound();
assertNotNull(pingFrame);
assertEquals(12345, pingFrame.content());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
assertFalse(pingFrame.ack());
}
@Test
public void sendPing() {
channel.writeAndFlush(new DefaultHttp2PingFrame(12345));
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
verify(frameWriter).writePing(eqFrameCodecCtx(), eq(false), eq(12345L), anyChannelPromise());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
}
@Test
public void receiveSettings() throws Http2Exception {
Http2Settings settings = new Http2Settings().maxConcurrentStreams(1);
frameInboundWriter.writeInboundSettings(settings);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2SettingsFrame settingsFrame = inboundHandler.readInbound();
assertNotNull(settingsFrame);
assertEquals(settings, settingsFrame.settings());
}
@Test
public void sendSettings() {
Http2Settings settings = new Http2Settings().maxConcurrentStreams(1);
channel.writeAndFlush(new DefaultHttp2SettingsFrame(settings));
verify(frameWriter).writeSettings(eqFrameCodecCtx(), eq(settings), anyChannelPromise());
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
}
@Test
public void iterateActiveStreams() throws Exception {
setUp(Http2FrameCodecBuilder.forServer().encoderEnforceMaxConcurrentStreams(true),
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
new Http2Settings().maxConcurrentStreams(1));
frameInboundWriter.writeInboundHeaders(3, request, 0, false);
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2HeadersFrame headersFrame = inboundHandler.readInbound();
assertNotNull(headersFrame);
Http2FrameStream activeInbond = headersFrame.stream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
Http2FrameStream activeOutbound = frameCodec.newStream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(activeOutbound));
Http2FrameStream bufferedOutbound = frameCodec.newStream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(bufferedOutbound));
@SuppressWarnings("unused")
Http2FrameStream idleStream = frameCodec.newStream();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
final Set<Http2FrameStream> activeStreams = new HashSet<Http2FrameStream>();
frameCodec.forEachActiveStream(new Http2FrameStreamVisitor() {
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
@Override
public boolean visit(Http2FrameStream stream) {
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
activeStreams.add(stream);
return true;
}
});
assertEquals(2, activeStreams.size());
Set<Http2FrameStream> expectedStreams = new HashSet<Http2FrameStream>();
HTTP/2 Child Channel and FrameCodec Feature Parity. Motivation: This PR (unfortunately) does 4 things: 1) Add outbound flow control to the Http2MultiplexCodec: The HTTP/2 child channel API should interact with HTTP/2 outbound/remote flow control. That is, if a H2 stream used up all its flow control window, the corresponding child channel should be marked unwritable and a writability-changed event should be fired. Similarly, a unwritable child channel should be marked writable and a writability-event should be fired, once a WINDOW_UPDATE frame has been received. The changes are (mostly) contained in ChannelOutboundBuffer, AbstractHttp2StreamChannel and Http2MultiplexCodec. 2) Introduce a Http2Stream2 object, that is used instead of stream identifiers on stream frames. A Http2Stream2 object allows an application to attach state to it, and so a application handler no longer needs to maintain stream state (i.e. in a map(id -> state)) himself. 3) Remove stream state events, which are no longer necessary due to the introduction of Http2Stream2. Also those stream state events have been found hard and complex to work with, when porting gRPC to the Http2FrameCodec. 4) Add support for HTTP/2 frames that have not yet been implemented, like PING and SETTINGS. Also add a Http2FrameCodecBuilder that exposes options from the Http2ConnectionHandler API that couldn't else be used with the frame codec, like buffering outbound streams, window update ratio, frame logger, etc. Modifications: 1) A child channel's writability and a H2 stream's outbound flow control window interact, as described in the motivation. A channel handler is free to ignore the channel's writability, in which case the parent channel is reponsible for buffering writes until a WINDOW_UPDATE is received. The connection-level flow control window is ignored for now. That is, a child channel's writability is only affected by the stream-level flow control window. So a child channel could be marked writable, even though the connection-level flow control window is zero. 2) Modify Http2StreamFrame and the Http2FrameCodec to take a Http2Stream2 object intstead of a primitive integer. Introduce a special Http2ChannelDuplexHandler that has newStream() and forEachActiveStream() methods. It's recommended for a user to extend from this handler, to use those advanced features. 3) As explained in the documentation, a new inbound stream active can be detected by checking if the Http2Stream2.managedState() of a Http2HeadersFrame is null. An outbound stream active can be detected by adding a listener to the ChannelPromise of the write of the first Http2HeadersFrame. A stream closed event can be listened to by adding a listener to the Http2Stream2.closeFuture(). 4) Add a simple Http2FrameCodecBuilder and implement the missing frame types. Result: 1) The Http2MultiplexCodec supports outbound flow control. 2) The Http2FrameCodec API makes it easy for a user to manage custom stream specific state and to create new outbound streams. 3) The Http2FrameCodec API is much cleaner and easier to work with. Hacks like the ChannelCarryingHeadersFrame are no longer necessary. 4) The Http2FrameCodec now also supports PING and SETTINGS frames. The Http2FrameCodecBuilder allows the Http2FrameCodec to use some of the rich features of the Http2ConnectionHandler API.
2016-08-23 13:03:39 +02:00
expectedStreams.add(activeInbond);
expectedStreams.add(activeOutbound);
assertEquals(expectedStreams, activeStreams);
}
@Test
public void streamShouldBeOpenInListener() {
final Http2FrameStream stream2 = frameCodec.newStream();
assertEquals(State.IDLE, stream2.state());
final AtomicBoolean listenerExecuted = new AtomicBoolean();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2))
.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
assertTrue(future.isSuccess());
assertEquals(State.OPEN, stream2.state());
listenerExecuted.set(true);
}
});
assertTrue(listenerExecuted.get());
}
@Test
public void upgradeEventNoRefCntError() throws Exception {
frameInboundWriter.writeInboundHeaders(Http2CodecUtil.HTTP_UPGRADE_STREAM_ID, request, 31, false);
// Using reflect as the constructor is package-private and the class is final.
Constructor<UpgradeEvent> constructor =
UpgradeEvent.class.getDeclaredConstructor(CharSequence.class, FullHttpRequest.class);
// Check if we could make it accessible which may fail on java9.
Assume.assumeTrue(ReflectionUtil.trySetAccessible(constructor, true) == null);
HttpServerUpgradeHandler.UpgradeEvent upgradeEvent = constructor.newInstance(
"HTTP/2", new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"));
channel.pipeline().fireUserEventTriggered(upgradeEvent);
assertEquals(1, upgradeEvent.refCnt());
}
@Test
public void upgradeWithoutFlowControlling() throws Exception {
channel.pipeline().addAfter(frameCodec.ctx.name(), null, new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Http2DataFrame) {
// Simulate consuming the frame and update the flow-controller.
Http2DataFrame data = (Http2DataFrame) msg;
ctx.writeAndFlush(new DefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes())
.stream(data.stream())).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
ctx.fireExceptionCaught(cause);
}
}
});
}
ReferenceCountUtil.release(msg);
}
});
frameInboundWriter.writeInboundHeaders(Http2CodecUtil.HTTP_UPGRADE_STREAM_ID, request, 31, false);
// Using reflect as the constructor is package-private and the class is final.
Constructor<UpgradeEvent> constructor =
UpgradeEvent.class.getDeclaredConstructor(CharSequence.class, FullHttpRequest.class);
// Check if we could make it accessible which may fail on java9.
Assume.assumeTrue(ReflectionUtil.trySetAccessible(constructor, true) == null);
String longString = new String(new char[70000]).replace("\0", "*");
DefaultFullHttpRequest request =
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/", bb(longString));
HttpServerUpgradeHandler.UpgradeEvent upgradeEvent = constructor.newInstance(
"HTTP/2", request);
channel.pipeline().fireUserEventTriggered(upgradeEvent);
}
private ChannelHandlerContext eqFrameCodecCtx() {
return eq(frameCodec.ctx);
}
}