Skip to content

Commit

Permalink
Adding examples for HTTP/2 framing.
Browse files Browse the repository at this point in the history
Motivation:

Provide some example code to show how to bootstrap client and server for
use with HTTP/2 framing.

Modifications:

- Fixed Http2ConnectionHandler to allow headers after stream creation.
Needed for response headers.

- Added toString() to all frame classes to help with debugging/logging

- Added example classes for HTTP/2

Result:

HTTP/2 connections now properly support response headers. Examples for
HTTP/2 provided with the distribution of examples module.

After your change, what will change.
  • Loading branch information
nmittler authored and Norman Maurer committed Apr 8, 2014
1 parent 25e0d9d commit 6982663
Show file tree
Hide file tree
Showing 20 changed files with 654 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,16 @@ private void handleInboundHeaders(ChannelHandlerContext ctx, Http2HeadersFrame f
connection.remote().createStream(frame.getStreamId(), frame.getPriority(),
frame.isEndOfStream());
} else {
// If the stream already exists, it must be a reserved push stream. If so, open
// it for push to the local endpoint.
stream.verifyState(PROTOCOL_ERROR, RESERVED_REMOTE);
stream.openForPush();
if (stream.getState() == RESERVED_REMOTE) {
// Received headers for a reserved push stream ... open it for push to the
// local endpoint.
stream.verifyState(PROTOCOL_ERROR, RESERVED_REMOTE);
stream.openForPush();
} else {
// Receiving headers on an existing stream. Make sure the stream is in an allowed
// state.
stream.verifyState(PROTOCOL_ERROR, OPEN, HALF_CLOSED_LOCAL);
}

// If the headers completes this stream, close it.
if (frame.isEndOfStream()) {
Expand Down Expand Up @@ -450,17 +456,20 @@ private void handleOutboundHeaders(ChannelHandlerContext ctx, Http2HeadersFrame
stream = connection.local().createStream(frame.getStreamId(), frame.getPriority(),
frame.isEndOfStream());
} else {
// If the stream already exists, it must be a reserved push stream. If so, open
// it for push to the remote endpoint.
stream.verifyState(PROTOCOL_ERROR, RESERVED_LOCAL);
stream.openForPush();
if (stream.getState() == RESERVED_LOCAL) {
// Sending headers on a reserved push stream ... open it for push to the remote
// endpoint.
stream.openForPush();
} else {
// The stream already exists, make sure it's in an allowed state.
stream.verifyState(PROTOCOL_ERROR, OPEN, HALF_CLOSED_REMOTE);
}

// If the headers are the end of the stream, close it now.
if (frame.isEndOfStream()) {
stream.closeLocalSide(ctx, promise);
}
}

// Flush to send all of the frames.
ctx.writeAndFlush(frame, promise);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import static io.netty.handler.codec.http2.draft10.frame.Http2FrameCodecUtil.MAX_FRAME_PAYLOAD_LENGTH;
import static io.netty.handler.codec.http2.draft10.frame.Http2FrameCodecUtil.MAX_UNSIGNED_SHORT;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.DefaultByteBufHolder;
import io.netty.buffer.Unpooled;
Expand Down Expand Up @@ -121,6 +120,17 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("streamId=").append(streamId);
builder.append(", endOfStream=").append(endOfStream);
builder.append(", paddingLength=").append(paddingLength);
builder.append(", contentLength=").append(content().readableBytes());
builder.append("]");
return builder.toString();
}

private Builder copyBuilder() {
return new Builder().setStreamId(streamId).setPaddingLength(paddingLength)
.setEndOfStream(endOfStream);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import static io.netty.handler.codec.http2.draft10.frame.Http2FrameCodecUtil.MAX_FRAME_PAYLOAD_LENGTH;
import static io.netty.handler.codec.http2.draft10.frame.Http2FrameCodecUtil.MAX_UNSIGNED_INT;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.DefaultByteBufHolder;
import io.netty.buffer.Unpooled;
Expand Down Expand Up @@ -110,6 +109,15 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("lastStreamId=").append(lastStreamId);
builder.append(", errorCode=").append(errorCode);
builder.append("]");
return builder.toString();
}

private Builder copyBuilder() {
return new Builder().setErrorCode(errorCode).setLastStreamId(lastStreamId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,13 @@ public boolean equals(Object obj) {

@Override
public String toString() {
return "DefaultHttp2HeadersFrame [streamId=" + streamId + ", priority=" + priority
+ ", endOfStream=" + endOfStream + ", headers=" + headers + ']';
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("streamId=").append(streamId);
builder.append(", priority=").append(priority);
builder.append(", endOfStream=").append(endOfStream);
builder.append(", headers=").append(headers);
builder.append("]");
return builder.toString();
}

public static class Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package io.netty.handler.codec.http2.draft10.frame;

import static io.netty.handler.codec.http2.draft10.frame.Http2FrameCodecUtil.PING_FRAME_PAYLOAD_LENGTH;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.DefaultByteBufHolder;

Expand Down Expand Up @@ -100,6 +99,14 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("ack=").append(ack);
builder.append("]");
return builder.toString();
}

/**
* Builds instances of {@link DefaultHttp2PingFrame}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("streamId=").append(streamId);
builder.append(", priority=").append(priority);
builder.append("]");
return builder.toString();
}
/**
* Builds instances of {@link DefaultHttp2PriorityFrame}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,12 @@ public boolean equals(Object obj) {

@Override
public String toString() {
return "DefaultHttp2PushPromiseFrame [streamId=" + streamId + ", promisedStreamId="
+ promisedStreamId + ", headers=" + headers + ']';
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("streamId=").append(streamId);
builder.append(", promisedStreamId=").append(promisedStreamId);
builder.append(", headers=").append(headers);
builder.append("]");
return builder.toString();
}

public static class Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("streamId=").append(streamId);
builder.append(", errorCode=").append(errorCode);
builder.append("]");
return builder.toString();
}

/**
* Builds instances of {@link DefaultHttp2RstStreamFrame}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,26 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("ack=").append(ack);
if (headerTableSize != null) {
builder.append(", headerTableSize=").append(headerTableSize);
}
if (pushEnabled != null) {
builder.append(", pushEnabled=").append(pushEnabled);
}
if (maxConcurrentStreams != null) {
builder.append(", maxConcurrentStreams=").append(maxConcurrentStreams);
}
if (initialWindowSize != null) {
builder.append(", initialWindowSize=").append(initialWindowSize);
}
builder.append("]");
return builder.toString();
}

/**
* Builds instances of {@link DefaultHttp2SettingsFrame}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append("[");
builder.append("streamId=").append(streamId);
builder.append(", windowSizeIncrement=").append(windowSizeIncrement);
builder.append("]");
return builder.toString();
}

/**
* Builds instances of {@link DefaultHttp2WindowUpdateFrame}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,35 @@ public boolean equals(Object obj) {
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("value = ").append(value).append(" (");
if (isAck()) {
builder.append("ACK,");
}
if (isEndOfHeaders()) {
builder.append("END_OF_HEADERS,");
}
if (isEndOfStream()) {
builder.append("END_OF_STREAM,");
}
if (isPriorityPresent()) {
builder.append("PRIORITY_PRESENT,");
}
if (isEndOfSegment()) {
builder.append("END_OF_SEGMENT,");
}
if (isPadHighPresent()) {
builder.append("PAD_HIGH,");
}
if (isPadLowPresent()) {
builder.append("PAD_LOW,");
}
builder.append(")");
return builder.toString();
}

private boolean isSet(short mask) {
return (value & mask) != 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package io.netty.handler.codec.http2.draft10.connection;

import static io.netty.handler.codec.http2.draft10.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.draft10.connection.Http2Stream.State.RESERVED_LOCAL;
import static io.netty.handler.codec.http2.draft10.connection.Http2Stream.State.RESERVED_REMOTE;
import static io.netty.handler.codec.http2.draft10.frame.Http2FrameCodecUtil.PING_FRAME_PAYLOAD_LENGTH;
import static io.netty.util.CharsetUtil.UTF_8;
import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -227,7 +229,8 @@ public void inboundHeadersWithEndOfStreamShouldCreateHalfClosedStream() throws E
}

@Test
public void inboundHeadersWithForPromisedStreamShouldHalfOpenStream() throws Exception {
public void inboundHeadersForPromisedStreamShouldHalfOpenStream() throws Exception {
when(stream.getState()).thenReturn(RESERVED_REMOTE);
Http2Frame frame =
new DefaultHttp2HeadersFrame.Builder().setStreamId(STREAM_ID).setPriority(1)
.setHeaders(Http2Headers.EMPTY_HEADERS).build();
Expand All @@ -237,7 +240,8 @@ public void inboundHeadersWithForPromisedStreamShouldHalfOpenStream() throws Exc
}

@Test
public void inboundHeadersWithForPromisedStreamShouldCloseStream() throws Exception {
public void inboundHeadersForPromisedStreamShouldCloseStream() throws Exception {
when(stream.getState()).thenReturn(RESERVED_REMOTE);
Http2Frame frame =
new DefaultHttp2HeadersFrame.Builder().setStreamId(STREAM_ID).setPriority(1)
.setEndOfStream(true).setHeaders(Http2Headers.EMPTY_HEADERS)
Expand Down Expand Up @@ -479,6 +483,7 @@ public void outboundHeadersShouldCreateHalfClosedStream() throws Exception {

@Test
public void outboundHeadersShouldOpenStreamForPush() throws Exception {
when(stream.getState()).thenReturn(RESERVED_LOCAL);
Http2Frame frame =
new DefaultHttp2HeadersFrame.Builder().setStreamId(STREAM_ID).setPriority(1)
.setHeaders(Http2Headers.EMPTY_HEADERS).build();
Expand All @@ -491,6 +496,7 @@ public void outboundHeadersShouldOpenStreamForPush() throws Exception {

@Test
public void outboundHeadersShouldClosePushStream() throws Exception {
when(stream.getState()).thenReturn(RESERVED_LOCAL);
Http2Frame frame =
new DefaultHttp2HeadersFrame.Builder().setStreamId(STREAM_ID).setPriority(1)
.setEndOfStream(true).setHeaders(Http2Headers.EMPTY_HEADERS)
Expand Down
5 changes: 5 additions & 0 deletions example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<artifactId>netty-codec-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-codec-http2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-codec-socks</artifactId>
Expand Down
Loading

0 comments on commit 6982663

Please sign in to comment.