package test.codec.http2.decode; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import org.junit.Assert; import org.junit.Test; import com.firefly.codec.http2.encode.Generator; import com.firefly.codec.http2.encode.HeadersGenerator; import com.firefly.codec.http2.encode.SettingsGenerator; import com.firefly.codec.http2.frame.DataFrame; import com.firefly.codec.http2.frame.FrameType; import com.firefly.codec.http2.frame.GoAwayFrame; import com.firefly.codec.http2.frame.HeadersFrame; import com.firefly.codec.http2.frame.PingFrame; import com.firefly.codec.http2.frame.PrefaceFrame; import com.firefly.codec.http2.frame.PushPromiseFrame; import com.firefly.codec.http2.frame.ResetFrame; import com.firefly.codec.http2.frame.SettingsFrame; import com.firefly.codec.http2.model.HostPortHttpField; import com.firefly.codec.http2.model.HttpFields; import com.firefly.codec.http2.model.HttpHeader; import com.firefly.codec.http2.model.HttpScheme; import com.firefly.codec.http2.model.HttpVersion; import com.firefly.codec.http2.model.MetaData; import com.firefly.codec.http2.stream.HTTP2Configuration; import com.firefly.codec.http2.stream.Session; import com.firefly.codec.http2.stream.Stream; import com.firefly.codec.http2.stream.Stream.Listener; import com.firefly.server.http2.HTTP2ServerDecoder; import com.firefly.server.http2.HTTP2ServerConnection; import com.firefly.server.http2.ServerSessionListener; import com.firefly.utils.concurrent.Callback; public class HTTP2DecoderTest { @Test public void testData() throws Throwable { final byte[] smallContent = new byte[22]; final byte[] bigContent = new byte[50]; Random random = new Random(); random.nextBytes(smallContent); random.nextBytes(bigContent); final HTTP2ServerDecoder decoder = new HTTP2ServerDecoder(); final HTTP2MockSession session = new HTTP2MockSession(); final HTTP2Configuration http2Configuration = new HTTP2Configuration(); http2Configuration.setFlowControlStrategy("simple"); final Map<Integer, Integer> settings = new HashMap<>(); settings.put(SettingsFrame.HEADER_TABLE_SIZE, http2Configuration.getMaxDynamicTableSize()); settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, http2Configuration.getInitialStreamSendWindow()); final HTTP2ServerConnection http2ServerConnection = new HTTP2ServerConnection(http2Configuration, session, null, new ServerSessionListener(){ @Override public Map<Integer, Integer> onPreface(Session session) { System.out.println("on preface: " + session.isClosed()); Assert.assertThat(session.isClosed(), is(false)); return settings; } @Override public Listener onNewStream(Stream stream, HeadersFrame frame) { System.out.println("on new stream: " + stream.getId()); System.out.println("on new stread headers: " + frame.getMetaData().toString()); Assert.assertThat(stream.getId(), is(5)); Assert.assertThat(frame.getMetaData().getHttpVersion(), is(HttpVersion.HTTP_2)); Assert.assertThat(frame.getMetaData().getFields().get("User-Agent"), is("Firefly Client 1.0")); Assert.assertThat(frame.getMetaData().getFields().get(HttpHeader.CONTENT_LENGTH), is("72")); MetaData.Request request = (MetaData.Request) frame.getMetaData(); Assert.assertThat(request.getMethod(), is("POST")); Assert.assertThat(request.getURI().getPath(), is("/data")); Assert.assertThat(request.getURI().getPort(), is(8080)); Assert.assertThat(request.getURI().getHost(), is("localhost")); return new Listener(){ @Override public void onHeaders(Stream stream, HeadersFrame frame) { System.out.println("on headers: " + frame.getMetaData()); } @Override public Listener onPush(Stream stream, PushPromiseFrame frame) { return null; } @Override public void onData(Stream stream, DataFrame frame, Callback callback) { Assert.assertThat(stream.getId(), is(5)); if(frame.isEndStream()) { Assert.assertThat(frame.remaining(), is(50)); Assert.assertThat(frame.getData().array(), is(bigContent)); } else { Assert.assertThat(frame.remaining(), is(22)); Assert.assertThat(frame.getData().array(), is(smallContent)); } System.out.println("data size:" + frame.remaining()); callback.succeeded(); } @Override public void onReset(Stream stream, ResetFrame frame) { } @Override public boolean onIdleTimeout(Stream stream, Throwable x) { return true; }}; } @Override public void onSettings(Session session, SettingsFrame frame) { System.out.println("on settings: " + frame.toString()); Assert.assertThat(frame.getSettings().get(SettingsFrame.INITIAL_WINDOW_SIZE), is(http2Configuration.getInitialStreamSendWindow())); } @Override public void onPing(Session session, PingFrame frame) { } @Override public void onReset(Session session, ResetFrame frame) { } @Override public void onClose(Session session, GoAwayFrame frame) { } @Override public void onFailure(Session session, Throwable failure) { } @Override public void onAccept(Session session) { } @Override public boolean onIdleTimeout(Session session) { // TODO Auto-generated method stub return false; }}); session.attachObject(http2ServerConnection); int streamId = 5; HttpFields fields = new HttpFields(); fields.put(HttpHeader.ACCEPT, "text/html"); fields.put(HttpHeader.USER_AGENT, "Firefly Client 1.0"); fields.put(HttpHeader.CONTENT_LENGTH, "72"); MetaData.Request metaData = new MetaData.Request("POST", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/data", HttpVersion.HTTP_2, fields); DataFrame smallDataFrame = new DataFrame(streamId, ByteBuffer.wrap(smallContent), false); DataFrame bigDateFrame = new DataFrame(streamId, ByteBuffer.wrap(bigContent), true); Generator generator = new Generator(http2Configuration.getMaxDynamicTableSize(), http2Configuration.getMaxHeaderBlockFragment()); HeadersGenerator headersGenerator = generator.getControlGenerator(FrameType.HEADERS); SettingsGenerator settingsGenerator = generator.getControlGenerator(FrameType.SETTINGS); List<ByteBuffer> list = new LinkedList<>(); list.add(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES)); list.add(settingsGenerator.generateSettings(settings, false)); list.addAll(headersGenerator.generateHeaders(streamId, metaData, null, false)); list.addAll(generator.data(smallDataFrame, smallContent.length).second); list.addAll(generator.data(bigDateFrame, bigContent.length).second); for(ByteBuffer buffer : list) { decoder.decode(buffer, session); } System.out.println("out data: " + session.outboundData.size()); Assert.assertThat(session.outboundData.size(), greaterThan(1)); http2ServerConnection.close(); } @Test public void testHeaders() throws Throwable { final HTTP2ServerDecoder decoder = new HTTP2ServerDecoder(); final HTTP2MockSession session = new HTTP2MockSession(); final HTTP2Configuration http2Configuration = new HTTP2Configuration(); final HTTP2ServerConnection http2ServerConnection = new HTTP2ServerConnection(http2Configuration, session, null, new ServerSessionListener(){ @Override public Map<Integer, Integer> onPreface(Session session) { System.out.println("on preface: " + session.isClosed()); Assert.assertThat(session.isClosed(), is(false)); return null; } @Override public Listener onNewStream(Stream stream, HeadersFrame frame) { System.out.println("on new stream: " + stream.getId()); System.out.println("on new stread headers: " + frame.getMetaData().toString()); Assert.assertThat(stream.getId(), is(5)); Assert.assertThat(frame.getMetaData().getHttpVersion(), is(HttpVersion.HTTP_2)); Assert.assertThat(frame.getMetaData().getFields().get("User-Agent"), is("Firefly Client 1.0")); MetaData.Request request = (MetaData.Request) frame.getMetaData(); Assert.assertThat(request.getMethod(), is("GET")); Assert.assertThat(request.getURI().getPath(), is("/index")); Assert.assertThat(request.getURI().getPort(), is(8080)); Assert.assertThat(request.getURI().getHost(), is("localhost")); return new Listener(){ @Override public void onHeaders(Stream stream, HeadersFrame frame) { System.out.println("on headers: " + frame.getMetaData()); } @Override public Listener onPush(Stream stream, PushPromiseFrame frame) { return null; } @Override public void onData(Stream stream, DataFrame frame, Callback callback) { } @Override public void onReset(Stream stream, ResetFrame frame) { } @Override public boolean onIdleTimeout(Stream stream, Throwable x) { return true; }}; } @Override public void onSettings(Session session, SettingsFrame frame) { System.out.println("on settings: " + frame.toString()); Assert.assertThat(frame.getSettings().get(SettingsFrame.INITIAL_WINDOW_SIZE), is(http2Configuration.getInitialStreamSendWindow())); } @Override public void onPing(Session session, PingFrame frame) { } @Override public void onReset(Session session, ResetFrame frame) { } @Override public void onClose(Session session, GoAwayFrame frame) { } @Override public void onFailure(Session session, Throwable failure) { } @Override public void onAccept(Session session) { } @Override public boolean onIdleTimeout(Session session) { // TODO Auto-generated method stub return false; }}); session.attachObject(http2ServerConnection); int streamId = 5; HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Firefly Client 1.0"); MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/index", HttpVersion.HTTP_2, fields); Map<Integer, Integer> settings = new HashMap<>(); settings.put(SettingsFrame.HEADER_TABLE_SIZE, http2Configuration.getMaxDynamicTableSize()); settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, http2Configuration.getInitialStreamSendWindow()); Generator generator = new Generator(http2Configuration.getMaxDynamicTableSize(), http2Configuration.getMaxHeaderBlockFragment()); HeadersGenerator headersGenerator = generator.getControlGenerator(FrameType.HEADERS); SettingsGenerator settingsGenerator = generator.getControlGenerator(FrameType.SETTINGS); List<ByteBuffer> list = new LinkedList<>(); list.add(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES)); list.add(settingsGenerator.generateSettings(settings, false)); list.addAll(headersGenerator.generateHeaders(streamId, metaData, null, true)); for(ByteBuffer buffer : list) { decoder.decode(buffer, session); } Assert.assertThat(session.outboundData.size(), greaterThan(0)); System.out.println("out data: " + session.outboundData.size()); Assert.assertThat(session.outboundData.size(), greaterThan(1)); http2ServerConnection.close(); } }