New HTTP2 module (low level)
diff --git a/core/pom.xml b/core/pom.xml
index d5c7435..3bb9647 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -56,6 +56,18 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-slf4j-impl</artifactId>
+ <version>2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>2.1</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java b/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
index 04228e1..b145d9c 100644
--- a/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
+++ b/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
@@ -149,12 +149,12 @@
// ----------- Helper methods ---------------------------------------------
@SuppressWarnings("unchecked")
- private DECODING_STATE getDecodingState(IoSession session) {
+ protected DECODING_STATE getDecodingState(IoSession session) {
return (DECODING_STATE) session.getAttribute(DECODER);
}
@SuppressWarnings("unchecked")
- private ENCODING_STATE getEncodingState(IoSession session) {
+ protected ENCODING_STATE getEncodingState(IoSession session) {
return (ENCODING_STATE) session.getAttribute(ENCODER);
}
diff --git a/http/src/main/java/org/apache/mina/http/HttpRequestImpl.java b/http/src/main/java/org/apache/mina/http/HttpRequestImpl.java
index 0c78497..91639f4 100644
--- a/http/src/main/java/org/apache/mina/http/HttpRequestImpl.java
+++ b/http/src/main/java/org/apache/mina/http/HttpRequestImpl.java
@@ -39,14 +39,14 @@
private final HttpMethod method;
- private final String requestedPath;
+ private final String targetURI;
private final Map<String, String> headers;
- public HttpRequestImpl(HttpVersion version, HttpMethod method, String requestedPath, Map<String, String> headers) {
+ public HttpRequestImpl(HttpVersion version, HttpMethod method, String targetURI, Map<String, String> headers) {
this.version = version;
this.method = method;
- this.requestedPath = requestedPath;
+ this.targetURI = targetURI;
this.headers = Collections.unmodifiableMap(headers);
}
@@ -62,6 +62,14 @@
* {@inheritDoc}
*/
@Override
+ public String getTargetURI() {
+ return targetURI;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public String getContentType() {
return headers.get("content-type");
}
@@ -148,7 +156,7 @@
sb.append("HTTP REQUEST METHOD: ").append(method).append('\n');
sb.append("VERSION: ").append(version).append('\n');
- sb.append("PATH: ").append(requestedPath).append('\n');
+ sb.append("PATH: ").append(targetURI).append('\n');
sb.append("--- HEADER --- \n");
diff --git a/http/src/main/java/org/apache/mina/http/api/HttpRequest.java b/http/src/main/java/org/apache/mina/http/api/HttpRequest.java
index 9e51d72..d248770 100644
--- a/http/src/main/java/org/apache/mina/http/api/HttpRequest.java
+++ b/http/src/main/java/org/apache/mina/http/api/HttpRequest.java
@@ -62,4 +62,18 @@
* @return the method
*/
HttpMethod getMethod();
+
+ /**
+ * Return the HTTP protocol version of the request {@link HttpVersion}.
+ *
+ * @return the HTTP version
+ */
+ HttpVersion getProtocolVersion();
+
+ /**
+ * Return the target URI of the request.
+ *
+ * @return the target URI
+ */
+ String getTargetURI();
}
diff --git a/http2/pom.xml b/http2/pom.xml
new file mode 100644
index 0000000..ecce674
--- /dev/null
+++ b/http2/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.mina</groupId>
+ <artifactId>mina-parent</artifactId>
+ <version>3.0.0-M3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>mina-http2</artifactId>
+ <name>Apache MINA HTTP2 ${project.version}</name>
+ <packaging>jar</packaging>
+ <description>Low level HTTP2 codec for building simple & fast HTTP2 server and clients</description>
+
+ <properties>
+ <symbolicName>${project.groupId}.http2</symbolicName>
+ <exportedPackage>${project.groupId}.http2.api</exportedPackage>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mina-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mina-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.twitter</groupId>
+ <artifactId>hpack</artifactId>
+ <version>0.10.0</version>
+ </dependency>
+ </dependencies>
+</project>
+
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2Constants.java b/http2/src/main/java/org/apache/mina/http2/api/Http2Constants.java
new file mode 100644
index 0000000..4b7f04c
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2Constants.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import java.nio.charset.Charset;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public final class Http2Constants {
+ /**
+ * Mask used when decoding on a 4 byte boundary, masking the reserved
+ * bit
+ */
+ public static final int HTTP2_31BITS_MASK = 0x7FFFFFFF;
+
+ /**
+ * Mask used when decoding on a 4 byte boundary, retrieving
+ * the exclusive bit
+ */
+ public static final int HTTP2_EXCLUSIVE_MASK = 0x80000000;
+
+ /**
+ * Length of the HTTP2 header (length, type, flags, streamID)
+ */
+ public static final int HTTP2_HEADER_LENGTH = 9;
+
+ /*
+ * Frame types
+ */
+ /**
+ * DATA frame
+ */
+ public static final short FRAME_TYPE_DATA = 0x00;
+
+ /**
+ * HEADERS frame
+ */
+ public static final short FRAME_TYPE_HEADERS = 0x01;
+
+ /**
+ * PRIORITY frame
+ */
+ public static final short FRAME_TYPE_PRIORITY = 0x02;
+
+ /**
+ * RST_STREAM frame
+ */
+ public static final short FRAME_TYPE_RST_STREAM = 0x03;
+
+ /**
+ * SETTINGS stream
+ */
+ public static final short FRAME_TYPE_SETTINGS = 0x04;
+
+ /**
+ * PUSH_PROMISE frame
+ */
+ public static final short FRAME_TYPE_PUSH_PROMISE = 0x05;
+
+ /**
+ * PING frame
+ */
+ public static final short FRAME_TYPE_PING = 0x06;
+
+ /**
+ * GOAWAY frame
+ */
+ public static final short FRAME_TYPE_GOAWAY = 0x07;
+
+ /**
+ * WINDOW_UPDATE frame
+ */
+ public static final short FRAME_TYPE_WINDOW_UPDATE = 0x08;
+
+ /**
+ * CONTINUATION frame
+ */
+ public static final short FRAME_TYPE_CONTINUATION = 0x09;
+
+ /*
+ * Flags
+ */
+ public static final byte FLAGS_END_STREAM = 0x01;
+
+ public static final byte FLAGS_ACK = 0x01;
+
+ public static final byte FLAGS_END_HEADERS = 0x04;
+
+ public static final byte FLAGS_PADDING = 0x08;
+
+ public static final byte FLAGS_PRIORITY = 0x20;
+
+ /*
+ * Error codes
+ */
+ /**
+ * The associated condition is not as a result of an error. For example, a GOAWAY might include this code to indicate graceful shutdown of a connection.
+ */
+ public static final int NO_ERROR = 0x0;
+
+ /**
+ * The endpoint detected an unspecific protocol error. This error is for use when a more specific error code is not available.
+ */
+ public static final int PROTOCOL_ERROR = 0x1;
+
+ /**
+ * The endpoint encountered an unexpected internal error.
+ */
+ public static final int INTERNAL_ERROR = 0x2;
+
+ /**
+ * The endpoint detected that its peer violated the flow control protocol.
+ */
+ public static final int FLOW_CONTROL_ERROR = 0x3;
+
+ /**
+ * The endpoint sent a SETTINGS frame, but did not receive a response in a timely manner. See Settings Synchronization (Section 6.5.3).
+ */
+ public static final int SETTINGS_TIMEOUT = 0x4;
+
+ /**
+ * The endpoint received a frame after a stream was half closed.
+ */
+ public static final int STREAM_CLOSED = 0x5;
+
+ /**
+ * The endpoint received a frame with an invalid size.
+ */
+ public static final int FRAME_SIZE_ERROR = 0x6;
+
+ /**
+ * The endpoint refuses the stream prior to performing any application processing, see Section 8.1.4 for details.
+ */
+ public static final int REFUSED_STREAM = 0x7;
+
+ /**
+ * Used by the endpoint to indicate that the stream is no longer needed.
+ */
+ public static final int CANCEL = 0x8;
+
+ /**
+ * The endpoint is unable to maintain the header compression context for the connection.
+ */
+ public static final int COMPRESSION_ERROR = 0x9;
+
+ /**
+ * The connection established in response to a CONNECT request (Section 8.3) was reset or abnormally closed.
+ */
+ public static final int CONNECT_ERROR = 0xa;
+
+ /**
+ * The endpoint detected that its peer is exhibiting a behavior that might be generating excessive load.
+ */
+ public static final int ENHANCE_YOUR_CALM = 0xb;
+
+ /**
+ * The underlying transport has properties that do not meet minimum security requirements (see Section 9.2).
+ */
+ public static final int INADEQUATE_SECURITY = 0xc;
+
+ /**
+ * The endpoint requires that HTTP/1.1 be used instead of HTTP/2.
+ */
+ public static final int HTTP_1_1_REQUIRED = 0xd;
+
+ /*
+ * Settings related stuff
+ */
+ public static final int SETTINGS_HEADER_TABLE_SIZE = 0x01;
+
+ public static final int SETTINGS_HEADER_TABLE_SIZE_DEFAULT = 4096;
+
+ public static final int SETTINGS_ENABLE_PUSH = 0x02;
+
+ public static final int SETTINGS_ENABLE_PUSH_DEFAULT = 1;
+
+ public static final int SETTINGS_MAX_CONCURRENT_STREAMS = 0x03;
+
+ public static final int SETTINGS_MAX_CONCURRENT_STREAMS_DEFAULT = Integer.MAX_VALUE;
+
+ public static final int SETTINGS_INITIAL_WINDOW_SIZE = 0x04;
+
+ public static final int SETTINGS_INITIAL_WINDOW_SIZE_DEFAULT = 65535;
+
+ public static final int SETTINGS_MAX_FRAME_SIZE = 0x05;
+
+ public static final int SETTINGS_MAX_FRAME_SIZE_DEFAULT = 16384;
+
+ public static final int SETTINGS_MAX_HEADER_LIST_SIZE = 0x06;
+
+ public static final int SETTINGS_MAX_HEADER_LIST_SIZE_DEFAULT = Integer.MAX_VALUE;
+
+ public static final Charset US_ASCII_CHARSET = Charset.forName("US-ASCII");
+
+ public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2ContinuationFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2ContinuationFrame.java
new file mode 100644
index 0000000..ce0a6ef
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2ContinuationFrame.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_CONTINUATION;
+import static org.apache.mina.http2.api.Http2Constants.EMPTY_BYTE_ARRAY;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An HTTP2 continuation frame.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2ContinuationFrame extends Http2Frame {
+
+ private final byte[] headerBlockFragment;
+
+
+ public byte[] getHeaderBlockFragment() {
+ return headerBlockFragment;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.put(getHeaderBlockFragment());
+ }
+
+ protected Http2ContinuationFrame(Http2ContinuationFrameBuilder builder) {
+ super(builder);
+ this.headerBlockFragment = builder.getHeaderBlockFragment();
+ }
+
+
+ public static class Http2ContinuationFrameBuilder extends AbstractHttp2FrameBuilder<Http2ContinuationFrameBuilder,Http2ContinuationFrame> {
+ private byte[] headerBlockFragment = EMPTY_BYTE_ARRAY;
+
+ public Http2ContinuationFrameBuilder headerBlockFragment(byte[] headerBlockFragment) {
+ this.headerBlockFragment = headerBlockFragment;
+ return this;
+ }
+
+ public byte[] getHeaderBlockFragment() {
+ return headerBlockFragment;
+ }
+
+ @Override
+ public Http2ContinuationFrame build() {
+ if (getLength() == (-1)) {
+ setLength(getHeaderBlockFragment().length);
+ }
+ return new Http2ContinuationFrame(type(FRAME_TYPE_CONTINUATION));
+ }
+
+ public static Http2ContinuationFrameBuilder builder() {
+ return new Http2ContinuationFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2DataFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2DataFrame.java
new file mode 100644
index 0000000..e8de92e
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2DataFrame.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.EMPTY_BYTE_ARRAY;
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_DATA;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_HEADER_LENGTH;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An HTTP2 data frame
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2DataFrame extends Http2Frame {
+ private final byte[] data;
+
+ private final byte[] padding;
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public byte[] getPadding() {
+ return padding;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ if (isFlagSet(FLAGS_PADDING)) {
+ buffer.put((byte) getPadding().length);
+ }
+ buffer.put(getData());
+ if (isFlagSet(FLAGS_PADDING)) {
+ buffer.put(getPadding());
+ }
+ }
+
+ protected Http2DataFrame(Http2DataFrameBuilder builder) {
+ super(builder);
+ data = builder.getData();
+ padding = builder.getPadding();
+ }
+
+ public static class Http2DataFrameBuilder extends AbstractHttp2FrameBuilder<Http2DataFrameBuilder,Http2DataFrame> {
+ private byte[] data = EMPTY_BYTE_ARRAY;
+
+ private byte[] padding = EMPTY_BYTE_ARRAY;
+
+ public Http2DataFrameBuilder data(byte[] data) {
+ this.data = data;
+ return this;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public Http2DataFrameBuilder padding(byte[] padding) {
+ this.padding = padding;
+ addFlag(FLAGS_PADDING);
+ return this;
+ }
+
+ public byte[] getPadding() {
+ return padding;
+ }
+
+ @Override
+ public Http2DataFrame build() {
+ if (getLength() == (-1)) {
+ int length = getData().length;
+ if (isFlagSet(FLAGS_PADDING)) {
+ length += getPadding().length + 1;
+ }
+ length(length);
+ }
+ return new Http2DataFrame(type(FRAME_TYPE_DATA));
+ }
+
+ public static Http2DataFrameBuilder builder() {
+ return new Http2DataFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2Frame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2Frame.java
new file mode 100644
index 0000000..82da9f7
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2Frame.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import java.nio.ByteBuffer;
+
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_HEADER_LENGTH;
+
+/**
+ * An HTTP2 frame.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public abstract class Http2Frame {
+
+ private final int length;
+
+ private final short type;
+
+ private final byte flags;
+
+ private final int streamID;
+
+ public int getLength() {
+ return length;
+ }
+
+ public short getType() {
+ return type;
+ }
+
+ public byte getFlags() {
+ return flags;
+ }
+
+ /**
+ * Utility method to test if a specific bit is set in the flags.
+ *
+ * @param flag the bit to test
+ * @return
+ */
+ protected boolean isFlagSet(byte flag) {
+ return (getFlags() & flag) == flag;
+ }
+
+ public int getStreamID() {
+ return streamID;
+ }
+
+ /**
+ * Serialize the frame to a buffer.
+ *
+ * @return the allocated buffer
+ */
+ public ByteBuffer toBuffer() {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(HTTP2_HEADER_LENGTH + getLength());
+ buffer.put((byte) (getLength() >> 16));
+ buffer.put((byte) (getLength() >> 8));
+ buffer.put((byte) (getLength() ));
+ buffer.put((byte) getType());
+ buffer.put(getFlags());
+ buffer.putInt(getStreamID());
+ writePayload(buffer);
+ buffer.flip();
+ return buffer;
+ }
+
+ /**
+ * Writes the frame specific payload to the allocated buffer.
+ * Must be implemented by frames implementation.
+ *
+ * @param buffer the buffer to write to
+ */
+ public abstract void writePayload(ByteBuffer buffer);
+
+ protected <T extends AbstractHttp2FrameBuilder<T,V>, V extends Http2Frame> Http2Frame(AbstractHttp2FrameBuilder<T, V> builder) {
+ this.length = builder.getLength();
+ this.type = builder.getType();
+ this.flags = builder.getFlags();
+ this.streamID = builder.getStreamID();
+ }
+
+ public static abstract class AbstractHttp2FrameBuilder<T extends AbstractHttp2FrameBuilder<T,V>, V extends Http2Frame> {
+ private int length = (-1);
+
+ private short type;
+
+ private byte flags;
+
+ private int streamID;
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T length(int length) {
+ setLength(length);
+ return (T) this;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T type(short type) {
+ this.type = type;
+ return (T) this;
+ }
+
+ public short getType() {
+ return type;
+ }
+
+ public void setFlags(byte flags) {
+ this.flags = flags;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T flags(byte flags) {
+ setFlags(flags);
+ return (T) this;
+ }
+
+ public byte getFlags() {
+ return flags;
+ }
+
+ /**
+ * Utility method for setting a specific bit in the flags.
+ *
+ * @param flag the bit to set
+ */
+ protected void addFlag(byte flag) {
+ setFlags((byte) (getFlags() | flag));
+ }
+
+ /**
+ * Utility method to test if a specific bit is set in the flags.
+ *
+ * @param flag the bit to test
+ * @return
+ */
+ protected boolean isFlagSet(byte flag) {
+ return (getFlags() & flag) == flag;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T streamID(int streamID) {
+ this.streamID = streamID;
+ return (T) this;
+ }
+
+ public int getStreamID() {
+ return streamID;
+ }
+
+ public abstract V build();
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2GoAwayFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2GoAwayFrame.java
new file mode 100644
index 0000000..8dcb487
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2GoAwayFrame.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_GOAWAY;
+import static org.apache.mina.http2.api.Http2Constants.EMPTY_BYTE_ARRAY;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An SPY data frame
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2GoAwayFrame extends Http2Frame {
+ private final int lastStreamID;
+
+ private final long errorCode;
+
+ private byte[] data;
+
+ public int getLastStreamID() {
+ return lastStreamID;
+ }
+
+ public long getErrorCode() {
+ return errorCode;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.putInt(getLastStreamID());
+ buffer.putInt((int) getErrorCode());
+ buffer.put(getData());
+ }
+
+ protected Http2GoAwayFrame(Http2GoAwayFrameBuilder builder) {
+ super(builder);
+ this.lastStreamID = builder.getLastStreamID();
+ this.errorCode = builder.getErrorCode();
+ this.data = builder.getData();
+ }
+
+
+ public static class Http2GoAwayFrameBuilder extends AbstractHttp2FrameBuilder<Http2GoAwayFrameBuilder,Http2GoAwayFrame> {
+ private int lastStreamID;
+
+ private long errorCode;
+
+ private byte[] data = EMPTY_BYTE_ARRAY;
+
+ public Http2GoAwayFrameBuilder lastStreamID(int lastStreamID) {
+ this.lastStreamID = lastStreamID;
+ return this;
+ }
+
+ public int getLastStreamID() {
+ return lastStreamID;
+ }
+
+ public Http2GoAwayFrameBuilder errorCode(long errorCode) {
+ this.errorCode = errorCode;
+ return this;
+ }
+
+ public long getErrorCode() {
+ return errorCode;
+ }
+
+ public Http2GoAwayFrameBuilder data(byte[] data) {
+ this.data = data;
+ return this;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ @Override
+ public Http2GoAwayFrame build() {
+ if (getLength() == (-1)) {
+ setLength(getData().length + 8);
+ }
+ return new Http2GoAwayFrame(type(FRAME_TYPE_GOAWAY));
+ }
+
+ public static Http2GoAwayFrameBuilder builder() {
+ return new Http2GoAwayFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2Header.java b/http2/src/main/java/org/apache/mina/http2/api/Http2Header.java
new file mode 100644
index 0000000..3ee02ca
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2Header.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public enum Http2Header {
+
+ METHOD(":method"),
+
+ PATH(":path"),
+
+ STATUS(":status"),
+
+ AUTHORITY(":authority"),
+
+ SCHEME(":scheme");
+
+ private final String name;
+
+ private Http2Header(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Check whether a header is an HTTP2 reserved one.
+ *
+ * @param name the name of the HTTP header
+ * @return true is this is a reserved HTTP2 header, false otherwise
+ */
+ public static boolean isHTTP2ReservedHeader(String name) {
+ for(Http2Header header : Http2Header.values()) {
+ if (header.getName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2HeadersFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2HeadersFrame.java
new file mode 100644
index 0000000..1dd2bcc
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2HeadersFrame.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING;
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PRIORITY;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_HEADERS;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_HEADER_LENGTH;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_EXCLUSIVE_MASK;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An HTTP2 HEADERS frame
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2HeadersFrame extends Http2Frame {
+
+ private final byte[] padding;
+
+ private final int streamDependencyID;
+
+ private final boolean exclusiveMode;
+
+ private final short weight;
+
+ private final byte[] headerBlockFragment;
+
+
+ public byte[] getPadding() {
+ return padding;
+ }
+
+ public int getStreamDependencyID() {
+ return streamDependencyID;
+ }
+
+ public boolean getExclusiveMode() {
+ return exclusiveMode;
+ }
+
+ public short getWeight() {
+ return weight;
+ }
+
+ public byte[] getHeaderBlockFragment() {
+ return headerBlockFragment;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ if (isFlagSet(FLAGS_PADDING)) {
+ buffer.put((byte) getPadding().length);
+ }
+ if (isFlagSet(FLAGS_PRIORITY)) {
+ buffer.putInt(getExclusiveMode()?HTTP2_EXCLUSIVE_MASK | getStreamDependencyID():getStreamDependencyID());
+ buffer.put((byte) (getWeight() - 1));
+ }
+ buffer.put(getHeaderBlockFragment());
+ if (isFlagSet(FLAGS_PADDING)) {
+ buffer.put(getPadding());
+ }
+ }
+
+ protected Http2HeadersFrame(Http2HeadersFrameBuilder builder) {
+ super(builder);
+ this.padding = builder.getPadding();
+ this.streamDependencyID = builder.getStreamDependencyID();
+ this.exclusiveMode = builder.getExclusiveMode();
+ this.weight = builder.getWeight();
+ this.headerBlockFragment = builder.getHeaderBlockFragment();
+ }
+
+
+ public static class Http2HeadersFrameBuilder extends AbstractHttp2FrameBuilder<Http2HeadersFrameBuilder,Http2HeadersFrame> {
+ private byte[] padding;
+
+ private int streamDependencyID;
+
+ private short weight;
+
+ private byte[] headerBlockFragment;
+
+ private boolean exclusiveMode;
+
+ public Http2HeadersFrameBuilder padding(byte[] padding) {
+ this.padding = padding;
+ addFlag(FLAGS_PADDING);
+ return this;
+ }
+
+ public byte[] getPadding() {
+ return padding;
+ }
+
+ public Http2HeadersFrameBuilder streamDependencyID(int streamDependencyID) {
+ this.streamDependencyID = streamDependencyID;
+ addFlag(FLAGS_PRIORITY);
+ return this;
+ }
+
+ public int getStreamDependencyID() {
+ return streamDependencyID;
+ }
+
+ public Http2HeadersFrameBuilder exclusiveMode(boolean exclusiveMode) {
+ this.exclusiveMode = exclusiveMode;
+ addFlag(FLAGS_PRIORITY);
+ return this;
+ }
+
+ public boolean getExclusiveMode() {
+ return exclusiveMode;
+ }
+
+ public Http2HeadersFrameBuilder weight(short weight) {
+ this.weight = weight;
+ addFlag(FLAGS_PRIORITY);
+ return this;
+ }
+
+ public short getWeight() {
+ return weight;
+ }
+
+ public Http2HeadersFrameBuilder headerBlockFragment(byte[] headerBlockFragment) {
+ this.headerBlockFragment = headerBlockFragment;
+ return this;
+ }
+
+ public byte[] getHeaderBlockFragment() {
+ return headerBlockFragment;
+ }
+
+ @Override
+ public Http2HeadersFrame build() {
+ if (getLength() == (-1)) {
+ int length = getHeaderBlockFragment().length;
+ if (isFlagSet(FLAGS_PADDING)) {
+ length += getPadding().length + 1;
+ }
+ if (isFlagSet(FLAGS_PRIORITY)) {
+ length += 5;
+ }
+ length(length);
+ }
+ return new Http2HeadersFrame(type(FRAME_TYPE_HEADERS));
+ }
+
+ public static Http2HeadersFrameBuilder builder() {
+ return new Http2HeadersFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2NameValuePair.java b/http2/src/main/java/org/apache/mina/http2/api/Http2NameValuePair.java
new file mode 100644
index 0000000..994ccca
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2NameValuePair.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2NameValuePair {
+ private String name;
+ private String value;
+
+ /**
+ * Build a name/value pair given the name and value.
+ *
+ * @param name the name of the pair
+ * @param value the value of the pair
+ */
+ public Http2NameValuePair(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getValue() {
+ return value;
+ }
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2PingFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2PingFrame.java
new file mode 100644
index 0000000..1bd87e5
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2PingFrame.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_PING;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An SPY data frame
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2PingFrame extends Http2Frame {
+ private final byte[] data;
+
+ public byte[] getData() {
+ return data;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.put(getData());
+ }
+
+ protected Http2PingFrame(Http2PingFrameBuilder builder) {
+ super(builder);
+ this.data = builder.getData();
+ }
+
+
+ public static class Http2PingFrameBuilder extends AbstractHttp2FrameBuilder<Http2PingFrameBuilder,Http2PingFrame> {
+ private byte[] data;
+
+ public Http2PingFrameBuilder data(byte[] data) {
+ this.data = data;
+ return this;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ @Override
+ public Http2PingFrame build() {
+ if (getLength() == (-1)) {
+ setLength(getData().length);
+ }
+ return new Http2PingFrame(type(FRAME_TYPE_PING));
+ }
+
+ public static Http2PingFrameBuilder builder() {
+ return new Http2PingFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2PriorityFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2PriorityFrame.java
new file mode 100644
index 0000000..1f766d3
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2PriorityFrame.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_PRIORITY;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_EXCLUSIVE_MASK;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An HTTP2 PRIORITY frame.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2PriorityFrame extends Http2Frame {
+ private final int streamDependencyID;
+
+ private boolean exclusiveMode;
+
+ private final short weight;
+
+ public int getStreamDependencyID() {
+ return streamDependencyID;
+ }
+
+ public boolean getExclusiveMode() {
+ return exclusiveMode;
+ }
+
+ public short getWeight() {
+ return weight;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.putInt(getExclusiveMode()?HTTP2_EXCLUSIVE_MASK | getStreamDependencyID():getStreamDependencyID());
+ buffer.put((byte) (getWeight() - 1));
+ }
+
+ protected Http2PriorityFrame(Http2PriorityFrameBuilder builder) {
+ super(builder);
+ this.streamDependencyID = builder.getStreamDependencyID();
+ this.exclusiveMode = builder.exclusiveMode;
+ this.weight = builder.getWeight();
+ }
+
+
+ public static class Http2PriorityFrameBuilder extends AbstractHttp2FrameBuilder<Http2PriorityFrameBuilder,Http2PriorityFrame> {
+ private int streamDependencyID;
+
+ private boolean exclusiveMode;
+
+ private short weight;
+
+ public Http2PriorityFrameBuilder streamDependencyID(int streamDependencyID) {
+ this.streamDependencyID = streamDependencyID;
+ return this;
+ }
+
+ public int getStreamDependencyID() {
+ return streamDependencyID;
+ }
+
+ public Http2PriorityFrameBuilder exclusiveMode(boolean exclusiveMode) {
+ this.exclusiveMode = exclusiveMode;
+ return this;
+ }
+
+ public boolean getExclusiveMode() {
+ return exclusiveMode;
+ }
+
+ public Http2PriorityFrameBuilder weight(short weight) {
+ this.weight = weight;
+ return this;
+ }
+
+ public short getWeight() {
+ return weight;
+ }
+
+ @Override
+ public Http2PriorityFrame build() {
+ if (getLength() == (-1)) {
+ setLength(5);
+ }
+ return new Http2PriorityFrame(type(FRAME_TYPE_PRIORITY));
+ }
+
+ public static Http2PriorityFrameBuilder builder() {
+ return new Http2PriorityFrameBuilder();
+ }
+ }
+ }
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2PushPromiseFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2PushPromiseFrame.java
new file mode 100644
index 0000000..c28b4f6
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2PushPromiseFrame.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.EMPTY_BYTE_ARRAY;
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_PUSH_PROMISE;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An SPY data frame
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2PushPromiseFrame extends Http2Frame {
+
+ private final byte[] padding;
+
+ private final int promisedStreamID;
+
+ private final byte[] headerBlockFragment;
+
+
+ public byte[] getPadding() {
+ return padding;
+ }
+
+ public int getPromisedStreamID() {
+ return promisedStreamID;
+ }
+
+ public byte[] getHeaderBlockFragment() {
+ return headerBlockFragment;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ if (isFlagSet(FLAGS_PADDING)) {
+ buffer.put((byte) getPadding().length);
+ }
+ buffer.putInt(getPromisedStreamID());
+ buffer.put(getHeaderBlockFragment());
+ if (isFlagSet(FLAGS_PADDING)) {
+ buffer.put(getPadding());
+ }
+ }
+
+ protected Http2PushPromiseFrame(Http2PushPromiseFrameBuilder builder) {
+ super(builder);
+ this.padding = builder.getPadding();
+ this.promisedStreamID = builder.getPromisedStreamID();
+ this.headerBlockFragment = builder.getHeaderBlockFragment();
+ }
+
+ public static class Http2PushPromiseFrameBuilder extends AbstractHttp2FrameBuilder<Http2PushPromiseFrameBuilder,Http2PushPromiseFrame> {
+ private byte[] padding = EMPTY_BYTE_ARRAY;
+
+ private int promisedStreamID;
+
+ private byte[] headerBlockFragment = EMPTY_BYTE_ARRAY;
+
+ public Http2PushPromiseFrameBuilder padding(byte[] padding) {
+ this.padding = padding;
+ addFlag(FLAGS_PADDING);
+ return this;
+ }
+
+ public byte[] getPadding() {
+ return padding;
+ }
+
+ public Http2PushPromiseFrameBuilder promisedStreamID(int promisedStreamID) {
+ this.promisedStreamID = promisedStreamID;
+ return this;
+ }
+
+ public int getPromisedStreamID() {
+ return promisedStreamID;
+ }
+
+ public Http2PushPromiseFrameBuilder headerBlockFragment(byte[] headerBlockFragment) {
+ this.headerBlockFragment = headerBlockFragment;
+ return this;
+ }
+
+ public byte[] getHeaderBlockFragment() {
+ return headerBlockFragment;
+ }
+
+ @Override
+ public Http2PushPromiseFrame build() {
+ if (getLength() == (-1)) {
+ int length = getHeaderBlockFragment().length + 4;
+ if (isFlagSet(FLAGS_PADDING)) {
+ length += getPadding().length + 1;
+ }
+ setLength(length);
+ }
+ return new Http2PushPromiseFrame(type(FRAME_TYPE_PUSH_PROMISE));
+ }
+
+ public static Http2PushPromiseFrameBuilder builder() {
+ return new Http2PushPromiseFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2RstStreamFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2RstStreamFrame.java
new file mode 100644
index 0000000..b6bcb23
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2RstStreamFrame.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_RST_STREAM;
+
+import java.nio.ByteBuffer;
+/**
+ * An HTTP2 RST_STREAM frame.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2RstStreamFrame extends Http2Frame {
+ private final long errorCode;
+
+ public long getErrorCode() {
+ return errorCode;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.putInt((int) getErrorCode());
+ }
+
+ protected Http2RstStreamFrame(Http2RstStreamFrameBuilder builder) {
+ super(builder);
+ this.errorCode = builder.getErrorCode();
+ }
+
+
+ public static class Http2RstStreamFrameBuilder extends AbstractHttp2FrameBuilder<Http2RstStreamFrameBuilder,Http2RstStreamFrame> {
+ private long errorCode;
+
+ public Http2RstStreamFrameBuilder errorCode(long errorCode) {
+ this.errorCode = errorCode;
+ return this;
+ }
+
+ public long getErrorCode() {
+ return errorCode;
+ }
+
+ @Override
+ public Http2RstStreamFrame build() {
+ if (getLength() == (-1)) {
+ setLength(4);
+ }
+ return new Http2RstStreamFrame(type(FRAME_TYPE_RST_STREAM));
+ }
+
+ public static Http2RstStreamFrameBuilder builder() {
+ return new Http2RstStreamFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2Setting.java b/http2/src/main/java/org/apache/mina/http2/api/Http2Setting.java
new file mode 100644
index 0000000..f78e9aa
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2Setting.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2Setting {
+ private int ID;
+
+ private long value;
+
+ public Http2Setting(int ID, long value) {
+ this.ID = ID;
+ this.value = value;
+ }
+
+ /**
+ * Default empty constructor
+ */
+ public Http2Setting() {
+ }
+
+ public int getID() {
+ return ID;
+ }
+
+ public void setID(int iD) {
+ ID = iD;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
+ public void setValue(long value) {
+ this.value = value;
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2SettingsFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2SettingsFrame.java
new file mode 100644
index 0000000..d72d5ee
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2SettingsFrame.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_SETTINGS;
+/**
+ * An HTTP2 SETTINGS frame.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2SettingsFrame extends Http2Frame {
+ private final Collection<Http2Setting> settings;
+
+ public Collection<Http2Setting> getSettings() {
+ return settings;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ for(Http2Setting setting : getSettings()) {
+ buffer.putShort((short) setting.getID());
+ buffer.putInt((int) setting.getValue());
+ }
+ }
+
+ protected Http2SettingsFrame(Http2SettingsFrameBuilder builder) {
+ super(builder);
+ this.settings = builder.getSettings();
+ }
+
+ public static class Http2SettingsFrameBuilder extends AbstractHttp2FrameBuilder<Http2SettingsFrameBuilder,Http2SettingsFrame> {
+ private Collection<Http2Setting> settings = Collections.emptyList();
+
+ public Http2SettingsFrameBuilder settings(Collection<Http2Setting> settings) {
+ this.settings = settings;
+ return this;
+ }
+
+ public Collection<Http2Setting> getSettings() {
+ return settings;
+ }
+
+ @Override
+ public Http2SettingsFrame build() {
+ if (getLength() == (-1)) {
+ setLength(getSettings().size() * 6);
+ }
+ return new Http2SettingsFrame(type(FRAME_TYPE_SETTINGS));
+ }
+
+ public static Http2SettingsFrameBuilder builder() {
+ return new Http2SettingsFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2UnknownFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2UnknownFrame.java
new file mode 100644
index 0000000..8714100
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2UnknownFrame.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An HTTP2 unknown frame.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2UnknownFrame extends Http2Frame {
+ private final byte[] payload;
+
+ public byte[] getPayload() {
+ return payload;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.put(getPayload());
+ }
+
+ protected Http2UnknownFrame(Http2UnknownFrameBuilder builder) {
+ super(builder);
+ this.payload = builder.getPayload();
+ }
+
+
+ public static class Http2UnknownFrameBuilder extends AbstractHttp2FrameBuilder<Http2UnknownFrameBuilder,Http2UnknownFrame> {
+ private byte[] payload = new byte[0];
+
+ public Http2UnknownFrameBuilder payload(byte[] payload) {
+ this.payload = payload;
+ return this;
+ }
+
+ public byte[] getPayload() {
+ return payload;
+ }
+
+ @Override
+ public Http2UnknownFrame build() {
+ if (getLength() == (-1)) {
+ setLength(getPayload().length);
+ }
+ return new Http2UnknownFrame(this);
+ }
+
+ public static Http2UnknownFrameBuilder builder() {
+ return new Http2UnknownFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/api/Http2WindowUpdateFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2WindowUpdateFrame.java
new file mode 100644
index 0000000..c468d81
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/api/Http2WindowUpdateFrame.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_WINDOW_UPDATE;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An SPY data frame
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public class Http2WindowUpdateFrame extends Http2Frame {
+ private final int windowUpdateIncrement;
+
+ public int getWindowUpdateIncrement() {
+ return windowUpdateIncrement;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.Http2Frame#writePayload(java.nio.ByteBuffer)
+ */
+ @Override
+ public void writePayload(ByteBuffer buffer) {
+ buffer.putInt(getWindowUpdateIncrement());
+ }
+
+ protected Http2WindowUpdateFrame(Http2WindowUpdateFrameBuilder builder) {
+ super(builder);
+ this.windowUpdateIncrement = builder.getWindowUpdateIncrement();
+ }
+
+
+ public static class Http2WindowUpdateFrameBuilder extends AbstractHttp2FrameBuilder<Http2WindowUpdateFrameBuilder,Http2WindowUpdateFrame> {
+ private int windowUpdateIncrement;
+
+ public Http2WindowUpdateFrameBuilder windowUpdateIncrement(int windowUpdateIncrement) {
+ this.windowUpdateIncrement = windowUpdateIncrement;
+ return this;
+ }
+
+ public int getWindowUpdateIncrement() {
+ return windowUpdateIncrement;
+ }
+
+ @Override
+ public Http2WindowUpdateFrame build() {
+ if (getLength() == (-1)) {
+ setLength(4);
+ }
+ return new Http2WindowUpdateFrame(type(FRAME_TYPE_WINDOW_UPDATE));
+ }
+
+ public static Http2WindowUpdateFrameBuilder builder() {
+ return new Http2WindowUpdateFrameBuilder();
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/codec/Http2ProtocolDecoder.java b/http2/src/main/java/org/apache/mina/http2/codec/Http2ProtocolDecoder.java
new file mode 100644
index 0000000..d87060e
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/codec/Http2ProtocolDecoder.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.codec;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.codec.ProtocolDecoder;
+import org.apache.mina.http2.api.Http2Frame;
+import org.apache.mina.http2.impl.Http2Connection;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2ProtocolDecoder implements ProtocolDecoder<ByteBuffer, Http2Frame, Http2Connection> {
+
+ @Override
+ public Http2Connection createDecoderState() {
+ return new Http2Connection();
+ }
+
+ @Override
+ public Http2Frame decode(ByteBuffer input, Http2Connection context) {
+ return context.decode(input);
+ }
+
+ @Override
+ public void finishDecode(Http2Connection context) {
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/codec/Http2ProtocolEncoder.java b/http2/src/main/java/org/apache/mina/http2/codec/Http2ProtocolEncoder.java
new file mode 100644
index 0000000..bd1655c
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/codec/Http2ProtocolEncoder.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.codec;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.codec.StatelessProtocolEncoder;
+import org.apache.mina.http2.api.Http2Frame;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2ProtocolEncoder implements StatelessProtocolEncoder<Http2Frame, ByteBuffer> {
+
+ @Override
+ public Void createEncoderState() {
+ return null;
+ }
+
+ @Override
+ public ByteBuffer encode(Http2Frame message, Void context) {
+ return message.toBuffer();
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/BytePartialDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/BytePartialDecoder.java
new file mode 100644
index 0000000..9153b97
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/BytePartialDecoder.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class BytePartialDecoder implements PartialDecoder<byte[]> {
+ private int offset;
+ private byte[] value;
+
+ /**
+ * Decode an byte array.
+ *
+ * @param size the size of the byte array to decode
+ */
+ public BytePartialDecoder(int size) {
+ this.offset = 0;
+ this.value = new byte[size];
+ }
+
+ public boolean consume(ByteBuffer buffer) {
+ if (value.length - offset == 0) {
+ throw new IllegalStateException();
+ }
+ int length = Math.min(buffer.remaining(), value.length - offset);
+ buffer.get(value, offset, length);
+ offset += length;
+ return value.length - offset == 0;
+ }
+
+ public byte[] getValue() {
+ if (value.length - offset > 0) {
+ throw new IllegalStateException();
+ }
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void reset() {
+ offset = 0;
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/HeadersEncoder.java b/http2/src/main/java/org/apache/mina/http2/impl/HeadersEncoder.java
new file mode 100644
index 0000000..6c51612
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/HeadersEncoder.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import org.apache.mina.http.api.HttpMessage;
+import org.apache.mina.http.api.HttpRequest;
+import org.apache.mina.http.api.HttpResponse;
+import org.apache.mina.http2.api.Http2Header;
+
+import com.twitter.hpack.Encoder;
+
+import static org.apache.mina.http2.api.Http2Constants.US_ASCII_CHARSET;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class HeadersEncoder {
+
+ private final Encoder encoder;
+
+ public HeadersEncoder(int maxHeaderTableSize) {
+ encoder = new Encoder(maxHeaderTableSize);
+ }
+
+ private static String getMethod(HttpMessage message) {
+ String method = null;
+ if (message instanceof HttpRequest) {
+ ((HttpRequest)message).getMethod().name();
+ }
+ return method;
+ }
+
+ private static String getPath(HttpMessage message) {
+ String path = null;
+ if (message instanceof HttpRequest) {
+ path = ((HttpRequest)message).getTargetURI();
+ }
+ return path;
+ }
+
+ public void encode(HttpMessage message, OutputStream out) throws IOException {
+ String value = getMethod(message);
+ if (value != null) {
+ encoder.encodeHeader(out,
+ Http2Header.METHOD.getName().getBytes(US_ASCII_CHARSET),
+ value.getBytes(US_ASCII_CHARSET),
+ false);
+ }
+ value = getPath(message);
+ if (value != null) {
+ encoder.encodeHeader(out,
+ Http2Header.PATH.getName().getBytes(US_ASCII_CHARSET),
+ value.getBytes(US_ASCII_CHARSET),
+ false);
+ }
+ if (message instanceof HttpResponse) {
+ encoder.encodeHeader(out,
+ Http2Header.STATUS.getName().getBytes(US_ASCII_CHARSET),
+ Integer.toString(((HttpResponse)message).getStatus().code()).getBytes(US_ASCII_CHARSET),
+ false);
+ }
+ for(String name : message.getHeaders().keySet()) {
+ if (!Http2Header.isHTTP2ReservedHeader(name)) {
+ encoder.encodeHeader(out,
+ name.getBytes(US_ASCII_CHARSET),
+ message.getHeaders().get(name).getBytes(US_ASCII_CHARSET),
+ false);
+ }
+ }
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2Connection.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2Connection.java
new file mode 100644
index 0000000..584e6f2
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2Connection.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2Frame;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_DATA;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_HEADERS;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_PRIORITY;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_RST_STREAM;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_SETTINGS;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_PUSH_PROMISE;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_PING;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_GOAWAY;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_WINDOW_UPDATE;
+import static org.apache.mina.http2.api.Http2Constants.FRAME_TYPE_CONTINUATION;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2Connection {
+
+ private static enum DecoderState {
+ HEADER,
+ FRAME
+ }
+
+ private final Http2FrameHeadePartialDecoder headerDecoder = new Http2FrameHeadePartialDecoder();
+ private Http2FrameDecoder frameDecoder;
+ private DecoderState decoderState = DecoderState.HEADER;
+
+ /**
+ * Decode the incoming message and if all frame data has been received,
+ * then the decoded frame will be returned. Otherwise, null is returned.
+ *
+ * @param input the input buffer to decode
+ * @return the decoder HTTP2 frame or null if more data are required
+ */
+ public Http2Frame decode(ByteBuffer input) {
+ Http2Frame frame = null;
+ switch (decoderState) {
+ case HEADER:
+ if (headerDecoder.consume(input)) {
+ Http2FrameHeader header = headerDecoder.getValue();
+ headerDecoder.reset();
+ decoderState = DecoderState.FRAME;
+ switch (header.getType()) {
+ case FRAME_TYPE_DATA:
+ frameDecoder = new Http2DataFrameDecoder(header);
+ break;
+ case FRAME_TYPE_HEADERS:
+ frameDecoder = new Http2HeadersFrameDecoder(header);
+ break;
+ case FRAME_TYPE_PRIORITY:
+ frameDecoder = new Http2PriorityFrameDecoder(header);
+ break;
+ case FRAME_TYPE_RST_STREAM:
+ frameDecoder = new Http2RstStreamFrameDecoder(header);
+ break;
+ case FRAME_TYPE_SETTINGS:
+ frameDecoder =new Http2SettingsFrameDecoder(header);
+ break;
+ case FRAME_TYPE_PUSH_PROMISE:
+ frameDecoder = new Http2PushPromiseFrameDecoder(header);
+ break;
+ case FRAME_TYPE_PING:
+ frameDecoder = new Http2PingFrameDecoder(header);
+ break;
+ case FRAME_TYPE_GOAWAY:
+ frameDecoder = new Http2GoAwayFrameDecoder(header);
+ break;
+ case FRAME_TYPE_WINDOW_UPDATE:
+ frameDecoder = new Http2WindowUpdateFrameDecoder(header);
+ break;
+ case FRAME_TYPE_CONTINUATION:
+ frameDecoder = new Http2ContinuationFrameDecoder(header);
+ break;
+ default:
+ frameDecoder = new Http2UnknownFrameDecoder(header);
+ break;
+ }
+ if (frameDecoder.consume(input)) {
+ frame = frameDecoder.getValue();
+ decoderState = DecoderState.HEADER;
+ }
+ }
+ break;
+ case FRAME:
+ if (frameDecoder.consume(input)) {
+ frame = frameDecoder.getValue();
+ decoderState = DecoderState.HEADER;
+ }
+ break;
+ }
+ return frame;
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2ContinuationFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2ContinuationFrameDecoder.java
new file mode 100644
index 0000000..d9ca244
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2ContinuationFrameDecoder.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2ContinuationFrame.Http2ContinuationFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2ContinuationFrameDecoder extends Http2FrameDecoder {
+
+ private BytePartialDecoder decoder;
+
+ private Http2ContinuationFrameBuilder builder = new Http2ContinuationFrameBuilder();
+
+ public Http2ContinuationFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ initBuilder(builder);
+ if (header.getLength() > 0) {
+ decoder = new BytePartialDecoder(header.getLength());
+ } else {
+ setValue(builder.build());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ if ((decoder != null) && decoder.consume(buffer)) {
+ builder.headerBlockFragment(decoder.getValue());
+ setValue(builder.build());
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2DataFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2DataFrameDecoder.java
new file mode 100644
index 0000000..6763e55
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2DataFrameDecoder.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2DataFrame.Http2DataFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2DataFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ PAD_LENGTH,
+ DATA,
+ PADDING
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private int padLength;
+
+ private Http2DataFrameBuilder builder = new Http2DataFrameBuilder();
+
+ public Http2DataFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ initBuilder(builder);
+ if (isFlagSet(FLAGS_PADDING)) {
+ state = State.PAD_LENGTH;
+ } else if (header.getLength() > 0) {
+ state = State.DATA;
+ decoder = new BytePartialDecoder(header.getLength());
+ } else {
+ setValue(builder.build());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case PAD_LENGTH:
+ padLength = buffer.get();
+ if ((getHeader().getLength() - 1 - padLength) > 0) {
+ state = State.DATA;
+ decoder = new BytePartialDecoder(getHeader().getLength() - 1 - padLength);
+ } else if (padLength > 0) {
+ state = State.PADDING;
+ decoder = new BytePartialDecoder(padLength);
+ } else {
+ setValue(builder.build());
+ }
+ break;
+ case DATA:
+ if (decoder.consume(buffer)) {
+ builder.data(((BytePartialDecoder)decoder).getValue());
+ if (isFlagSet(FLAGS_PADDING) && (padLength > 0)) {
+ state = State.PADDING;
+ decoder = new BytePartialDecoder(padLength);
+ } else {
+ setValue(builder.build());
+ }
+ }
+ break;
+ case PADDING:
+ if (decoder.consume(buffer)) {
+ builder.padding(((BytePartialDecoder)decoder).getValue());
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameDecoder.java
new file mode 100644
index 0000000..003bd53
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameDecoder.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import org.apache.mina.http2.api.Http2Frame;
+import org.apache.mina.http2.api.Http2Frame.AbstractHttp2FrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public abstract class Http2FrameDecoder implements PartialDecoder<Http2Frame> {
+ private Http2FrameHeader header;
+
+ private Http2Frame frame;
+
+ public Http2FrameDecoder(Http2FrameHeader header) {
+ this.header = header;
+ }
+
+ protected boolean isFlagSet(short mask) {
+ return (header.getFlags() & mask) == mask;
+ }
+
+ protected void initBuilder(AbstractHttp2FrameBuilder builder) {
+ builder.length(header.getLength());
+ builder.type(header.getType());
+ builder.flags(header.getFlags());
+ builder.streamID(header.getStreamID());
+ }
+
+ protected Http2FrameHeader getHeader() {
+ return header;
+ }
+
+ @Override
+ public Http2Frame getValue() {
+ return frame;
+ }
+
+ protected void setValue(Http2Frame frame) {
+ this.frame = frame;
+ }
+
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameHeadePartialDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameHeadePartialDecoder.java
new file mode 100644
index 0000000..41e8817
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameHeadePartialDecoder.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2FrameHeadePartialDecoder implements PartialDecoder<Http2FrameHeadePartialDecoder.Http2FrameHeader> {
+ public static class Http2FrameHeader {
+ private int length;
+ private short type;
+ private byte flags;
+ private int streamID;
+
+ public int getLength() {
+ return length;
+ }
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ public short getType() {
+ return type;
+ }
+
+ public void setType(short type) {
+ this.type = type;
+ }
+
+ public byte getFlags() {
+ return flags;
+ }
+
+ public void setFlags(byte flags) {
+ this.flags = flags;
+ }
+
+ public int getStreamID() {
+ return streamID;
+ }
+
+ public void setStreamID(int streamID) {
+ this.streamID = streamID;
+ }
+ }
+
+ private static enum State {
+ LENGTH,
+ TYPE_FLAGS,
+ STREAMID,
+ END
+ }
+
+ private State state;
+ private PartialDecoder<?> decoder;
+ private Http2FrameHeader value;
+
+ public Http2FrameHeadePartialDecoder() {
+ reset();
+ }
+
+ public boolean consume(ByteBuffer buffer) {
+ while (buffer.hasRemaining() && state != State.END) {
+ if (decoder.consume(buffer)) {
+ switch (state) {
+ case LENGTH:
+ value.setLength(((IntPartialDecoder)decoder).getValue().intValue());
+ decoder = new BytePartialDecoder(2);
+ state = State.TYPE_FLAGS;
+ break;
+ case TYPE_FLAGS:
+ value.setType(((BytePartialDecoder)decoder).getValue()[0]);
+ value.setFlags(((BytePartialDecoder)decoder).getValue()[1]);
+ decoder = new IntPartialDecoder(4);
+ state = State.STREAMID;
+ break;
+ case STREAMID:
+ value.setStreamID(((IntPartialDecoder)decoder).getValue() & HTTP2_31BITS_MASK);
+ state = State.END;
+ break;
+ }
+ }
+ }
+ return state == State.END;
+ }
+
+ public Http2FrameHeader getValue() {
+ return value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ state = State.LENGTH;
+ decoder = new IntPartialDecoder(3);
+ value = new Http2FrameHeader();
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2GoAwayFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2GoAwayFrameDecoder.java
new file mode 100644
index 0000000..e00007f
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2GoAwayFrameDecoder.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2GoAwayFrame.Http2GoAwayFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2GoAwayFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ LAST_STREAM_ID,
+ CODE,
+ EXTRA
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private Http2GoAwayFrameBuilder builder = new Http2GoAwayFrameBuilder();
+
+ public Http2GoAwayFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ state = State.LAST_STREAM_ID;
+ decoder = new IntPartialDecoder(4);
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case LAST_STREAM_ID:
+ if (decoder.consume(buffer)) {
+ builder.lastStreamID(((IntPartialDecoder)decoder).getValue() & HTTP2_31BITS_MASK);
+ state = State.CODE;
+ decoder = new LongPartialDecoder(4);
+ }
+ case CODE:
+ if (decoder.consume(buffer)) {
+ builder.errorCode(((LongPartialDecoder)decoder).getValue());
+ if (getHeader().getLength() > 8) {
+ state = State.EXTRA;
+ decoder = new BytePartialDecoder(getHeader().getLength() - 8);
+ } else {
+ setValue(builder.build());
+ }
+ }
+ break;
+ case EXTRA:
+ if (decoder.consume(buffer)) {
+ builder.data(((BytePartialDecoder)decoder).getValue());
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2HeadersFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2HeadersFrameDecoder.java
new file mode 100644
index 0000000..d1deb9d
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2HeadersFrameDecoder.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2HeadersFrame.Http2HeadersFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING;
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PRIORITY;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_EXCLUSIVE_MASK;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2HeadersFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ PAD_LENGTH,
+ STREAM_DEPENDENCY,
+ WEIGHT,
+ HEADER,
+ PADDING
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private int padLength;
+
+ private Http2HeadersFrameBuilder builder = new Http2HeadersFrameBuilder();
+
+ public Http2HeadersFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ if (isFlagSet(FLAGS_PADDING)) {
+ state = State.PAD_LENGTH;
+ } else if (isFlagSet(FLAGS_PRIORITY)) {
+ state = State.STREAM_DEPENDENCY;
+ decoder = new IntPartialDecoder(4);
+ } else {
+ state = State.HEADER;
+ decoder = new BytePartialDecoder(header.getLength());
+ }
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case PAD_LENGTH:
+ padLength = buffer.get();
+ if (isFlagSet(FLAGS_PRIORITY)) {
+ decoder = new IntPartialDecoder(4);
+ state = State.STREAM_DEPENDENCY;
+ } else {
+ state = State.HEADER;
+ decoder = new BytePartialDecoder(getHeader().getLength() - 1 - padLength);
+ }
+ break;
+ case STREAM_DEPENDENCY:
+ if (decoder.consume(buffer)) {
+ builder.streamDependencyID(((IntPartialDecoder)decoder).getValue() & HTTP2_31BITS_MASK);
+ builder.exclusiveMode((((IntPartialDecoder)decoder).getValue() & HTTP2_EXCLUSIVE_MASK) == HTTP2_EXCLUSIVE_MASK);
+ state = State.WEIGHT;
+ }
+ break;
+ case WEIGHT:
+ builder.weight((byte) (buffer.get()+1));
+ state = State.HEADER;
+ int headerLength = getHeader().getLength() - 5;
+ if (isFlagSet(FLAGS_PADDING)) {
+ headerLength -= (padLength + 1);
+ }
+ decoder = new BytePartialDecoder(headerLength);
+ break;
+ case HEADER:
+ if (decoder.consume(buffer)) {
+ builder.headerBlockFragment(((BytePartialDecoder)decoder).getValue());
+ if (isFlagSet(FLAGS_PADDING)) {
+ state = State.PADDING;
+ decoder = new BytePartialDecoder(padLength);
+ } else {
+ setValue(builder.build());
+ }
+ }
+ break;
+ case PADDING:
+ if (decoder.consume(buffer)) {
+ builder.padding(((BytePartialDecoder)decoder).getValue());
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2PingFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2PingFrameDecoder.java
new file mode 100644
index 0000000..c894c98
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2PingFrameDecoder.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2PingFrame.Http2PingFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2PingFrameDecoder extends Http2FrameDecoder {
+ private BytePartialDecoder decoder;
+
+ private Http2PingFrameBuilder builder = new Http2PingFrameBuilder();
+
+ public Http2PingFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ decoder = new BytePartialDecoder(header.getLength());
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ if (decoder.consume(buffer)) {
+ builder.data(decoder.getValue());
+ setValue(builder.build());
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2PriorityFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2PriorityFrameDecoder.java
new file mode 100644
index 0000000..3dbdfd2
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2PriorityFrameDecoder.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2PriorityFrame.Http2PriorityFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_EXCLUSIVE_MASK;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2PriorityFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ STREAM_DEPENDENCY,
+ WEIGHT,
+ EXTRA
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private Http2PriorityFrameBuilder builder = new Http2PriorityFrameBuilder();
+
+ public Http2PriorityFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ state = State.STREAM_DEPENDENCY;
+ decoder = new IntPartialDecoder(4);
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case STREAM_DEPENDENCY:
+ if (decoder.consume(buffer)) {
+ builder.streamDependencyID(((IntPartialDecoder)decoder).getValue() & HTTP2_31BITS_MASK);
+ builder.exclusiveMode((((IntPartialDecoder)decoder).getValue() & HTTP2_EXCLUSIVE_MASK) == HTTP2_EXCLUSIVE_MASK);
+ state = State.WEIGHT;
+ }
+ break;
+ case WEIGHT:
+ builder.weight((short) ((buffer.get() & 0x00FF) + 1));
+ int extraLength = getHeader().getLength() - 5;
+ if (extraLength > 0) {
+ decoder = new BytePartialDecoder(extraLength);
+ state = State.EXTRA;
+ } else {
+ setValue(builder.build());
+ }
+ break;
+ case EXTRA:
+ if (decoder.consume(buffer)) {
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2PushPromiseFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2PushPromiseFrameDecoder.java
new file mode 100644
index 0000000..077e7da
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2PushPromiseFrameDecoder.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2PushPromiseFrame.Http2PushPromiseFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING;
+import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2PushPromiseFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ PAD_LENGTH,
+ PROMISED_STREAM,
+ HEADER,
+ PADDING
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private int padLength;
+
+ private Http2PushPromiseFrameBuilder builder = new Http2PushPromiseFrameBuilder();
+
+ public Http2PushPromiseFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ if (isFlagSet(FLAGS_PADDING)) {
+ state = State.PAD_LENGTH;
+ } else {
+ state = State.PROMISED_STREAM;
+ decoder = new IntPartialDecoder(4);
+ }
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case PAD_LENGTH:
+ padLength = buffer.get();
+ state = State.PROMISED_STREAM;
+ decoder = new IntPartialDecoder(4);
+ break;
+ case PROMISED_STREAM:
+ if (decoder.consume(buffer)) {
+ builder.promisedStreamID(((IntPartialDecoder)decoder).getValue() & HTTP2_31BITS_MASK);
+ state = State.HEADER;
+ int headerLength = getHeader().getLength() - 4;
+ if (isFlagSet(FLAGS_PADDING)) {
+ headerLength -= (padLength + 1);
+ }
+ decoder = new BytePartialDecoder(headerLength);
+ }
+ break;
+ case HEADER:
+ if (decoder.consume(buffer)) {
+ builder.headerBlockFragment(((BytePartialDecoder)decoder).getValue());
+ if (isFlagSet(FLAGS_PADDING)) {
+ state = State.PADDING;
+ decoder = new BytePartialDecoder(padLength);
+ } else {
+ setValue(builder.build());
+ }
+ }
+ break;
+ case PADDING:
+ if (decoder.consume(buffer)) {
+ builder.padding(((BytePartialDecoder)decoder).getValue());
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2RstStreamFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2RstStreamFrameDecoder.java
new file mode 100644
index 0000000..f64175c
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2RstStreamFrameDecoder.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2RstStreamFrame.Http2RstStreamFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2RstStreamFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ ERROR_CODE,
+ EXTRA
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private Http2RstStreamFrameBuilder builder = new Http2RstStreamFrameBuilder();
+
+ public Http2RstStreamFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ state = State.ERROR_CODE;
+ decoder = new LongPartialDecoder(4);
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case ERROR_CODE:
+ if (decoder.consume(buffer)) {
+ builder.errorCode(((LongPartialDecoder)decoder).getValue());
+ if (getHeader().getLength() > 4) {
+ state = State.EXTRA;
+ decoder = new BytePartialDecoder(getHeader().getLength() - 4);
+ } else {
+ setValue(builder.build());
+ }
+ }
+ break;
+ case EXTRA:
+ if (decoder.consume(buffer)) {
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2SettingsFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2SettingsFrameDecoder.java
new file mode 100644
index 0000000..ab3166b
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2SettingsFrameDecoder.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.mina.http2.api.Http2Setting;
+import org.apache.mina.http2.api.Http2SettingsFrame.Http2SettingsFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2SettingsFrameDecoder extends Http2FrameDecoder {
+
+ private int remaining;
+
+ private LongPartialDecoder decoder = new LongPartialDecoder(6);
+
+ private Http2SettingsFrameBuilder builder = new Http2SettingsFrameBuilder();
+
+ private Collection<Http2Setting> settings = new ArrayList<Http2Setting>();
+
+ public Http2SettingsFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ remaining = header.getLength() / 6;
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ if (decoder.consume(buffer)) {
+ remaining--;
+ Http2Setting setting = new Http2Setting();
+ setting.setID((int) ((decoder.getValue() & 0x00FFFF00000000L) >> 32));
+ setting.setValue((decoder.getValue() & 0x00FFFFFFFFL));
+ settings.add(setting);
+ decoder.reset();
+ if (remaining == 0) {
+ builder.settings(settings);
+ setValue(builder.build());
+ }
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2UnknownFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2UnknownFrameDecoder.java
new file mode 100644
index 0000000..df64cfc
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2UnknownFrameDecoder.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2UnknownFrame.Http2UnknownFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2UnknownFrameDecoder extends Http2FrameDecoder {
+
+ private BytePartialDecoder decoder;
+
+ private Http2UnknownFrameBuilder builder = new Http2UnknownFrameBuilder();
+
+ public Http2UnknownFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ initBuilder(builder);
+ if (header.getLength() > 0) {
+ decoder = new BytePartialDecoder(header.getLength());
+ } else {
+ setValue(builder.build());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ if (decoder.consume(buffer)) {
+ builder.payload(decoder.getValue());
+ setValue(builder.build());
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/Http2WindowUpdateFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2WindowUpdateFrameDecoder.java
new file mode 100644
index 0000000..234db5c
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2WindowUpdateFrameDecoder.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.api.Http2WindowUpdateFrame.Http2WindowUpdateFrameBuilder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2WindowUpdateFrameDecoder extends Http2FrameDecoder {
+
+ private enum State {
+ INCREMENT,
+ EXTRA
+ }
+
+ private State state;
+
+ private PartialDecoder<?> decoder;
+
+ private Http2WindowUpdateFrameBuilder builder = new Http2WindowUpdateFrameBuilder();
+
+ public Http2WindowUpdateFrameDecoder(Http2FrameHeader header) {
+ super(header);
+ state = State.INCREMENT;
+ decoder = new IntPartialDecoder(4);
+ initBuilder(builder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#consume(java.nio.ByteBuffer)
+ */
+ @Override
+ public boolean consume(ByteBuffer buffer) {
+ while ((getValue() == null) && buffer.remaining() > 0) {
+ switch (state) {
+ case INCREMENT:
+ if (decoder.consume(buffer)) {
+ builder.windowUpdateIncrement(((IntPartialDecoder)decoder).getValue());
+ if (getHeader().getLength() > 4) {
+ state = State.EXTRA;
+ decoder = new BytePartialDecoder(getHeader().getLength() - 4);
+ } else {
+ setValue(builder.build());
+ }
+ }
+ break;
+ case EXTRA:
+ if (decoder.consume(buffer)) {
+ setValue(builder.build());
+ }
+ break;
+ }
+ }
+ return getValue() != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ }
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/IntPartialDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/IntPartialDecoder.java
new file mode 100644
index 0000000..152d840
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/IntPartialDecoder.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class IntPartialDecoder implements PartialDecoder<Integer> {
+ private int size;
+ private int remaining;
+ private int value;
+
+ /**
+ * Decode an integer whose size is different from the standard 4.
+ *
+ * @param size the size (1,2,3,4) to decode
+ */
+ public IntPartialDecoder(int size) {
+ this.remaining = size;
+ this.size = size;
+ }
+
+ /**
+ * Decode a 4 bytes integer
+ */
+ public IntPartialDecoder() {
+ this(4);
+ }
+
+ public boolean consume(ByteBuffer buffer) {
+ if (remaining == 0) {
+ throw new IllegalStateException();
+ }
+ while (remaining > 0 && buffer.hasRemaining()) {
+ value = (value << 8) + (buffer.get() & 0x00FF);
+ --remaining;
+ }
+ return remaining == 0;
+ }
+
+ public Integer getValue() {
+ if (remaining > 0) {
+ throw new IllegalStateException();
+ }
+ return value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ remaining = size;
+ value = 0;
+ }
+
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/LongPartialDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/LongPartialDecoder.java
new file mode 100644
index 0000000..e6ac6eb
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/LongPartialDecoder.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class LongPartialDecoder implements PartialDecoder<Long> {
+ private int size;
+ private int remaining;
+ private long value;
+
+ /**
+ * Decode a long integer whose size is different from the standard 8.
+ *
+ * @param size the size (1 to 8) to decode
+ */
+ public LongPartialDecoder(int size) {
+ this.remaining = size;
+ this.size = size;
+ }
+
+ /**
+ * Decode a 8 bytes long integer
+ */
+ public LongPartialDecoder() {
+ this(8);
+ }
+
+ public boolean consume(ByteBuffer buffer) {
+ if (remaining == 0) {
+ throw new IllegalStateException();
+ }
+ while (remaining > 0 && buffer.hasRemaining()) {
+ value = (value << 8) + (buffer.get() & 0x00FF);
+ --remaining;
+ }
+ return remaining == 0;
+ }
+
+ public Long getValue() {
+ if (remaining > 0) {
+ throw new IllegalStateException();
+ }
+ return value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.mina.http2.api.PartialDecoder#reset()
+ */
+ @Override
+ public void reset() {
+ remaining = size;
+ value = 0;
+ }
+
+
+}
diff --git a/http2/src/main/java/org/apache/mina/http2/impl/PartialDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/PartialDecoder.java
new file mode 100644
index 0000000..0139382
--- /dev/null
+++ b/http2/src/main/java/org/apache/mina/http2/impl/PartialDecoder.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public interface PartialDecoder<T> {
+ /**
+ * Consume the buffer so as to decode a value. Not all the input buffer
+ * may be consumed.
+ *
+ * @param buffer the input buffer to decode
+ * @return true if a value is available false if more data is requested
+ */
+ public boolean consume(ByteBuffer buffer);
+
+ /**
+ * Return the decoded value.
+ *
+ * @return the decoded value
+ */
+ public T getValue();
+
+ /**
+ * Reset the internal state of the decoder to that new decoding can take place.
+ */
+ public void reset();
+
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/Http2Test.java b/http2/src/test/java/org/apache/mina/http2/Http2Test.java
new file mode 100644
index 0000000..44ee14b
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/Http2Test.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+
+public abstract class Http2Test {
+ protected byte[] toByteArray(ByteBuffer buffer) {
+ byte[] result = new byte[buffer.remaining()];
+ buffer.get(result);
+ return result;
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/TestMessages.java b/http2/src/test/java/org/apache/mina/http2/TestMessages.java
new file mode 100644
index 0000000..c931603
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/TestMessages.java
@@ -0,0 +1,465 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2;
+
+import java.util.Collections;
+
+import org.apache.mina.http2.api.Http2ContinuationFrame;
+import org.apache.mina.http2.api.Http2ContinuationFrame.Http2ContinuationFrameBuilder;
+import org.apache.mina.http2.api.Http2DataFrame;
+import org.apache.mina.http2.api.Http2DataFrame.Http2DataFrameBuilder;
+import org.apache.mina.http2.api.Http2GoAwayFrame;
+import org.apache.mina.http2.api.Http2GoAwayFrame.Http2GoAwayFrameBuilder;
+import org.apache.mina.http2.api.Http2HeadersFrame;
+import org.apache.mina.http2.api.Http2HeadersFrame.Http2HeadersFrameBuilder;
+import org.apache.mina.http2.api.Http2PingFrame;
+import org.apache.mina.http2.api.Http2PingFrame.Http2PingFrameBuilder;
+import org.apache.mina.http2.api.Http2PriorityFrame;
+import org.apache.mina.http2.api.Http2PriorityFrame.Http2PriorityFrameBuilder;
+import org.apache.mina.http2.api.Http2PushPromiseFrame;
+import org.apache.mina.http2.api.Http2PushPromiseFrame.Http2PushPromiseFrameBuilder;
+import org.apache.mina.http2.api.Http2RstStreamFrame;
+import org.apache.mina.http2.api.Http2RstStreamFrame.Http2RstStreamFrameBuilder;
+import org.apache.mina.http2.api.Http2Setting;
+import org.apache.mina.http2.api.Http2SettingsFrame;
+import org.apache.mina.http2.api.Http2SettingsFrame.Http2SettingsFrameBuilder;
+import org.apache.mina.http2.api.Http2UnknownFrame;
+import org.apache.mina.http2.api.Http2UnknownFrame.Http2UnknownFrameBuilder;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+
+public final class TestMessages {
+
+ public static final byte[] CONTINUATION_NO_HEADER_FRAGMENT_BUFFER = new byte[] {
+ 0x00, 0x00, 0x00, /*length*/
+ 0x09, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x32 /*streamID*/
+ };
+
+ public static final Http2ContinuationFrame CONTINUATION_NO_HEADER_FRAGMENT_FRAME = Http2ContinuationFrameBuilder.builder().
+ streamID(50).
+ build();
+
+ public static final byte[] CONTINUATION_HEADER_FRAGMENT_BUFFER = new byte[] {
+ 0x00, 0x00, 0x0A, /*length*/
+ 0x09, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x32, /*streamID*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A /*headerFragment*/
+ };
+
+ public static final Http2ContinuationFrame CONTINUATION_HEADER_FRAGMENT_FRAME = Http2ContinuationFrameBuilder.builder().
+ streamID(50).
+ headerBlockFragment(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}).
+ build();
+
+ public static final byte[] DATA_NO_PAYLOAD_NO_PADDING_BUFFER = new byte[] {
+ 0x00, 0x00, 0x00, /*length*/
+ 0x00, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x32 /*streamID*/
+ };
+
+ public static final Http2DataFrame DATA_NO_PAYLOAD_NO_PADDING_FRAME = Http2DataFrameBuilder.builder().
+ streamID(50).
+ build();
+
+ public static final byte[] DATA_PAYLOAD_NO_PADDING_BUFFER = new byte[] {
+ 0x00, 0x00, 0x0A, /*length*/
+ 0x00, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x32, /*streamID*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A /*headerFragment*/
+ };
+
+ public static final Http2DataFrame DATA_PAYLOAD_NO_PADDING_FRAME = Http2DataFrameBuilder.builder().
+ streamID(50).
+ data(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}).
+ build();
+
+ public static final byte[] DATA_NO_PAYLOAD_PADDING_BUFFER = new byte[] {
+ 0x00, 0x00, 0x03, /*length*/
+ 0x00, /*type*/
+ 0x08, /*flags*/
+ 0x00, 0x00, 0x00, 0x32, /*streamID*/
+ 0x02, /*padLength*/
+ 0x0E, 0x28 /*padding*/
+ };
+
+ public static final Http2DataFrame DATA_NO_PAYLOAD_PADDING_FRAME = Http2DataFrameBuilder.builder().
+ streamID(50).
+ padding(new byte[] {0x0E, 0x28}).
+ build();
+
+ public static final byte[] DATA_PAYLOAD_PADDING_BUFFER = new byte[] {
+ 0x00, 0x00, 0x0D, /*length*/
+ 0x00, /*type*/
+ 0x08, /*flags*/
+ 0x00, 0x00, 0x00, 0x32, /*streamID*/
+ 0x02, /*padLength*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, /*data*/
+ 0x0E, 0x28 /*padding*/
+ };
+
+ public static final Http2DataFrame DATA_PAYLOAD_PADDING_FRAME = Http2DataFrameBuilder.builder().
+ streamID(50).
+ data(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}).
+ padding(new byte[] {0x0E, 0x28}).
+ build();
+
+ public static final byte[] GOAWAY_NO_DATA_BUFFER = new byte[] {
+ 0x00, 0x00, 0x08, /*length*/
+ 0x07, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ 0x00, 0x00, 0x01, 0x00, /*lastStreamID*/
+ 0x00, 0x01, 0x02, 0x03 /*errorCode*/
+ };
+
+ public static final Http2GoAwayFrame GOAWAY_NO_DATA_FRAME = Http2GoAwayFrameBuilder.builder().
+ streamID(1).
+ lastStreamID(256).
+ errorCode(0x010203).
+ build();
+
+ public static final byte[] GOAWAY_NO_DATA_HIGHEST_STREAMID_BUFFER = new byte[] {
+ 0x00, 0x00, 0x08, /*length*/
+ 0x07, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, /*lastStreamID*/
+ 0x00, 0x01, 0x02, 0x03 /*errorCode*/
+ };
+
+ public static final Http2GoAwayFrame GOAWAY_NO_DATA_HIGHEST_STREAMID_FRAME = Http2GoAwayFrameBuilder.builder().
+ streamID(1).
+ lastStreamID(0x7FFFFFFF).
+ errorCode(0x010203).
+ build();
+
+ public static final byte[] GOAWAY_NO_DATA_HIGHEST_STREAMID_RESERVED_BIT_BUFFER = new byte[] {
+ 0x00, 0x00, 0x08, /*length*/
+ 0x07, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, /*lastStreamID*/
+ 0x00, 0x01, 0x02, 0x03 /*errorCode*/
+ };
+
+ public static final byte[] GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_BUFFER = new byte[] {
+ 0x00, 0x00, 0x08, /*length*/
+ 0x07, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, /*lastStreamID*/
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF /*errorCode*/
+ };
+
+ public static final Http2GoAwayFrame GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_FRAME = Http2GoAwayFrameBuilder.builder().
+ streamID(1).
+ lastStreamID(0x7FFFFFFF).
+ errorCode(0x00FFFFFFFFL).
+ build();
+
+ public static final byte[] GOAWAY_DATA_BUFFER = new byte[] {
+ 0x00, 0x00, 0x09, /*length*/
+ 0x07, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ 0x00, 0x00, 0x01, 0x00, /*lastStreamID*/
+ 0x00, 0x01, 0x02, 0x03, /*errorCode*/
+ 0x01 /*additionData*/
+ };
+
+ public static final Http2GoAwayFrame GOAWAY_DATA_FRAME = Http2GoAwayFrameBuilder.builder().
+ streamID(1).
+ lastStreamID(256).
+ errorCode(0x010203).
+ data(new byte[] { 0x01}).
+ build();
+
+ public static final byte[] HEADERS_NO_PADDING_NO_PRIORITY_BUFFER = new byte[] {
+ 0x00, 0x00, 0x01, /*length*/
+ 0x01, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ (byte) 0x82 /*headerFragment*/
+ };
+
+ public static final Http2HeadersFrame HEADERS_NO_PADDING_NO_PRIORITY_FRAME = Http2HeadersFrameBuilder.builder().
+ streamID(1).
+ headerBlockFragment(new byte[] {(byte) 0x82}).
+ build();
+
+ public static final byte[] HEADERS_PADDING_PRIORITY_BUFFER = new byte[] {
+ 0x00, 0x00, 0x17, /*length*/
+ 0x01, /*type*/
+ 0x28, /*flags*/
+ 0x00, 0x00, 0x00, 0x03, /*streamID*/
+ 0x10, /*padding length*/
+ (byte)0x0080, 0x00, 0x00, 0x14, /*stream dependency*/
+ 0x09, /*weight*/
+ (byte) 0x82, /*headerFragment*/
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E /*padding*/
+ };
+
+ public static final Http2HeadersFrame HEADERS_PADDING_PRIORITY_FRAME = Http2HeadersFrameBuilder.builder().
+ streamID(3).
+ exclusiveMode(true).
+ streamDependencyID(20).
+ weight((short) 10).
+ headerBlockFragment(new byte[] { (byte) 0x82}).
+ padding(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}).
+ build();
+
+ public static final byte[] HEADERS_PADDING_NO_PRIORITY_BUFFER = new byte[] {
+ 0x00, 0x00, 0x12, /*length*/
+ 0x01, /*type*/
+ 0x08, /*flags*/
+ 0x00, 0x00, 0x00, 0x03, /*streamID*/
+ 0x10, /*padding length*/
+ (byte) 0x0082, /*headerFragment*/
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E /*padding*/
+ };
+
+ public static final Http2HeadersFrame HEADERS_PADDING_NO_PRIORITY_FRAME = Http2HeadersFrameBuilder.builder().
+ streamID(3).
+ headerBlockFragment(new byte[] { (byte) 0x82}).
+ padding(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}).
+ build();
+
+ public static final byte[] PING_STANDARD_BUFFER = new byte[] {
+ 0x00, 0x00, 0x08, /*length*/
+ 0x06, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07/*opaqueData*/
+ };
+
+ public static final Http2PingFrame PING_STANDARD_FRAME = Http2PingFrameBuilder.builder().
+ streamID(32).
+ data(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}).
+ build();
+
+ public static final byte[] PING_EXTRA_DATA_BUFFER = new byte[] {
+ 0x00, 0x00, 0x09, /*length*/
+ 0x06, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08/*opaqueData*/
+ };
+
+ public static final Http2PingFrame PING_EXTRA_DATA_FRAME = Http2PingFrameBuilder.builder().
+ streamID(32).
+ data(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}).
+ build();
+
+ public static final byte[] PING_NO_ENOUGH_DATA_BUFFER = new byte[] {
+ 0x00, 0x00, 0x01, /*length*/
+ 0x06, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00/*opaqueData*/
+ };
+
+ public static final Http2PingFrame PING_NO_ENOUGH_DATA_FRAME = Http2PingFrameBuilder.builder().
+ streamID(32).
+ data(new byte[] {0x00}).
+ build();
+
+ public static final byte[] PRIORITY_NO_EXCLUSIVE_MODE_BUFFER = new byte[] {
+ 0x00, 0x00, 0x05, /*length*/
+ 0x02, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x00, 0x01, 0x00, /*streamDependency*/
+ 0x01 /*weight*/
+ };
+
+ public static final Http2PriorityFrame PRIORITY_NO_EXCLUSIVE_MODE_FRAME = Http2PriorityFrameBuilder.builder().
+ streamID(32).
+ weight((short) 2).
+ streamDependencyID(256).
+ build();
+
+ public static final byte[] PRIORITY_EXCLUSIVE_MODE_BUFFER = new byte[] {
+ 0x00, 0x00, 0x05, /*length*/
+ 0x02, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ (byte) 0x80, 0x00, 0x01, 0x00, /*streamDependency*/
+ 0x01 /*weight*/
+ };
+
+ public static final Http2PriorityFrame PRIORITY_EXCLUSIVE_MODE_FRAME = Http2PriorityFrameBuilder.builder().
+ streamID(32).
+ weight((short) 2).
+ streamDependencyID(256).
+ exclusiveMode(true).
+ build();
+
+ public static final byte[] PUSH_PROMISE_NO_PADDING_BUFFER = new byte[] {
+ 0x00, 0x00, 0x05, /*length*/
+ 0x05, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01, /*streamID*/
+ 0x00, 0x00, 0x01, 0x00, /*promisedStreamID*/
+ (byte) 0x82 /*headerFragment*/
+ };
+
+ public static final Http2PushPromiseFrame PUSH_PROMISE_NO_PADDING_FRAME = Http2PushPromiseFrameBuilder.builder().
+ streamID(1).
+ promisedStreamID(256).
+ headerBlockFragment(new byte[] {(byte) 0x82}).
+ build();
+
+ public static final byte[] PUSH_PROMISE_PADDING_BUFFER = new byte[] {
+ 0x00, 0x00, 0x16, /*length*/
+ 0x05, /*type*/
+ 0x08, /*flags*/
+ 0x00, 0x00, 0x00, 0x03, /*streamID*/
+ 0x10, /*padding length*/
+ 0x00, 0x00, 0x00, 0x14, /*promisedStreamID*/
+ (byte) 0x0082, /*headerFragment*/
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E /*padding*/
+ };
+
+ public static final Http2PushPromiseFrame PUSH_PROMISE_PADDING_FRAME = Http2PushPromiseFrameBuilder.builder().
+ streamID(3).
+ promisedStreamID(20).
+ headerBlockFragment(new byte[] {(byte) 0x82}).
+ padding(new byte[] { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}).
+ build();
+
+ public static final byte[] RST_STREAM_NO_EXTRA_PAYLOAD_BUFFER = new byte[] {
+ 0x00, 0x00, 0x04, /*length*/
+ 0x03, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x00, 0x01, 0x00, /*errorCode*/
+ };
+
+ public static final Http2RstStreamFrame RST_STREAM_NO_EXTRA_PAYLOAD_FRAME = Http2RstStreamFrameBuilder.builder().
+ streamID(32).
+ errorCode(256).
+ build();
+
+ public static final byte[] RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_BUFFER = new byte[] {0x00, 0x00, 0x04, /*length*/
+ 0x03, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, /*errorCode*/
+ };
+
+ public static final Http2RstStreamFrame RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_FRAME = Http2RstStreamFrameBuilder.builder().
+ streamID(32).
+ errorCode(0x00FFFFFFFFL).
+ build();
+
+ public static final byte[] RST_STREAM_EXTRA_PAYLOAD_BUFFER = new byte[] {
+ 0x00, 0x00, 0x06, /*length*/
+ 0x03, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x00, 0x01, 0x00, /*errorCode*/
+ 0x0E, 0x28
+ };
+
+ public static final byte[] RST_STREAM_EXTRA_PAYLOAD_HIGHEST_BUFFER = new byte[] {
+ 0x00, 0x00, 0x06, /*length*/
+ 0x03, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, /*errorCode*/
+ 0x0E, 0x28
+ };
+
+ public static final byte[] SETTINGS_DEFAULT_BUFFER = new byte[] {
+ 0x00, 0x00, 0x06, /*length*/
+ 0x04, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x01, /*ID*/
+ 0x01, 0x02, 0x03, 0x04, /*value*/
+ };
+
+ public static final Http2SettingsFrame SETTINGS_DEFAULT_FRAME = Http2SettingsFrameBuilder.builder().
+ streamID(32).
+ settings(Collections.singletonList(new Http2Setting(1, 0x01020304))).
+ build();
+
+ public static final byte[] SETTINGS_HIGHEST_ID_BUFFER = new byte[] {
+ 0x00, 0x00, 0x06, /*length*/
+ 0x04, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ (byte) 0xFF, (byte) 0xFF, /*ID*/
+ 0x01, 0x02, 0x03, 0x04, /*value*/
+ };
+
+ public static final Http2SettingsFrame SETTINGS_HIGHEST_ID_FRAME = Http2SettingsFrameBuilder.builder().
+ streamID(32).
+ settings(Collections.singletonList(new Http2Setting(0x00FFFF, 0x01020304))).
+ build();
+
+ public static final byte[] SETTINGS_HIGHEST_VALUE_BUFFER = new byte[] {
+ 0x00, 0x00, 0x06, /*length*/
+ 0x04, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x00, 0x01, /*ID*/
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, /*value*/
+ };
+
+ public static final Http2SettingsFrame SETTINGS_HIGHEST_VALUE_FRAME = Http2SettingsFrameBuilder.builder().
+ streamID(32).
+ settings(Collections.singletonList(new Http2Setting(1, 0xFFFFFFFFL))).
+ build();
+
+ public static final byte[] UNKNOWN_PAYLOAD_BUFFER = new byte[] {
+ 0x00, 0x00, 0x02, /*length*/
+ (byte) 0x00FF, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20, /*streamID*/
+ 0x0E, 0x18
+ };
+
+ public static final Http2UnknownFrame UNKNOWN_PAYLOAD_FRAME = Http2UnknownFrameBuilder.builder().
+ type((short) 255).
+ streamID(32).
+ payload(new byte[] { 0x0E, 0x18}).
+ build();
+
+ public static final byte[] UNKNOWN_NO_PAYLOAD_BUFFER = new byte[] {
+ 0x00, 0x00, 0x00, /*length*/
+ (byte) 0x00FF, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x20 /*streamID*/
+ };
+
+ public static final Http2UnknownFrame UNKNOWN_NO_PAYLOAD_FRAME = Http2UnknownFrameBuilder.builder().
+ type((short) 255).
+ streamID(32).
+ build();
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2ContinuationFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2ContinuationFrameTest.java
new file mode 100644
index 0000000..0c0329f
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2ContinuationFrameTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2ContinuationFrameTest extends Http2Test {
+
+ @Test
+ public void decodeNoHeaderFragment() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.CONTINUATION_NO_HEADER_FRAGMENT_BUFFER);
+ Http2ContinuationFrame frame = (Http2ContinuationFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(0, frame.getLength());
+ assertEquals(9, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(0, frame.getHeaderBlockFragment().length);
+ }
+
+ @Test
+ public void encodeNoHeaderFragment() {
+ Http2ContinuationFrame frame = TestMessages.CONTINUATION_NO_HEADER_FRAGMENT_FRAME;
+ assertArrayEquals(TestMessages.CONTINUATION_NO_HEADER_FRAGMENT_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeHeaderFragment() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.CONTINUATION_HEADER_FRAGMENT_BUFFER);
+ Http2ContinuationFrame frame = (Http2ContinuationFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(10, frame.getLength());
+ assertEquals(9, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(10, frame.getHeaderBlockFragment().length);
+ assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, frame.getHeaderBlockFragment());
+ }
+
+ @Test
+ public void encodeHeaderFragment() {
+ Http2ContinuationFrame frame = TestMessages.CONTINUATION_HEADER_FRAGMENT_FRAME;
+ assertArrayEquals(TestMessages.CONTINUATION_HEADER_FRAGMENT_BUFFER, toByteArray(frame.toBuffer()));
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2DataFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2DataFrameTest.java
new file mode 100644
index 0000000..5c7ff95
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2DataFrameTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2DataFrameTest extends Http2Test {
+
+ @Test
+ public void decodeNoPayloadNoPadding() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_NO_PAYLOAD_NO_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(0, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(0, frame.getData().length);
+ assertEquals(0, frame.getPadding().length);
+ }
+
+ @Test
+ public void encodeNoPayloadNoPadding() {
+ Http2DataFrame frame = TestMessages.DATA_NO_PAYLOAD_NO_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_NO_PAYLOAD_NO_PADDING_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodePayloadNoPadding() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_PAYLOAD_NO_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(10, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(10, frame.getData().length);
+ assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, frame.getData());
+ assertEquals(0, frame.getPadding().length);
+ }
+
+ @Test
+ public void encodePayloadNoPadding() {
+ Http2DataFrame frame = TestMessages.DATA_PAYLOAD_NO_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_PAYLOAD_NO_PADDING_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeNoPayloadPadding() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_NO_PAYLOAD_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(3, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(0,frame.getData().length);
+ assertEquals(2, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x0E, 0x28}, frame.getPadding());
+ }
+
+ @Test
+ public void encodeNoPayloadPadding() {
+ Http2DataFrame frame = TestMessages.DATA_NO_PAYLOAD_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_NO_PAYLOAD_PADDING_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodePayloadPadding() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_PAYLOAD_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(13, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(10, frame.getData().length);
+ assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, frame.getData());
+ assertEquals(2, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x0E, 0x28}, frame.getPadding());
+ }
+
+ @Test
+ public void encodePayloadPadding() {
+ Http2DataFrame frame = TestMessages.DATA_PAYLOAD_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_PAYLOAD_PADDING_BUFFER, toByteArray(frame.toBuffer()));
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2GoAwayFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2GoAwayFrameTest.java
new file mode 100644
index 0000000..1921423
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2GoAwayFrameTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2GoAwayFrameTest extends Http2Test {
+
+
+ @Test
+ public void decodeNoAdditionalData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(256, frame.getLastStreamID());
+ assertEquals(0x010203, frame.getErrorCode());
+ }
+
+ @Test
+ public void encodeWNoAdditionalData() {
+ Http2GoAwayFrame frame = TestMessages.GOAWAY_NO_DATA_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_NO_DATA_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeHighestLastStreamIDNoAdditionalData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(0x7FFFFFFF, frame.getLastStreamID());
+ assertEquals(0x010203, frame.getErrorCode());
+ }
+
+ @Test
+ public void encodeHighestLastStreamIDWNoAdditionalData() {
+ Http2GoAwayFrame frame = TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeHighestLastStreamIDReservedBitSetNoAdditionalData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_RESERVED_BIT_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(0x7FFFFFFF, frame.getLastStreamID());
+ assertEquals(0x010203, frame.getErrorCode());
+ }
+
+ @Test
+ public void decodeHighestErrorCodeNoAdditionalData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(0x7FFFFFFF, frame.getLastStreamID());
+ assertEquals(0x00FFFFFFFFL, frame.getErrorCode());
+ }
+
+ @Test
+ public void encodeHighestErrorCodeNoAdditionalData() {
+ Http2GoAwayFrame frame = TestMessages.GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeAdditionalData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_DATA_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(9, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(256, frame.getLastStreamID());
+ assertEquals(0x00010203, frame.getErrorCode());
+ assertArrayEquals(new byte[] {0x01}, frame.getData());
+ }
+
+ @Test
+ public void encodeAdditionalData() {
+ Http2GoAwayFrame frame = TestMessages.GOAWAY_DATA_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_DATA_BUFFER, toByteArray(frame.toBuffer()));
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2HeadersFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2HeadersFrameTest.java
new file mode 100644
index 0000000..a108474
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2HeadersFrameTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2HeadersFrameTest extends Http2Test {
+
+ @Test
+ public void decodeNoPaddingNoPriority() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.HEADERS_NO_PADDING_NO_PRIORITY_BUFFER);
+ Http2HeadersFrame frame = (Http2HeadersFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(1, frame.getLength());
+ assertEquals(1, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ }
+
+ @Test
+ public void encodeNoPaddingNoPriority() {
+ Http2HeadersFrame frame = TestMessages.HEADERS_NO_PADDING_NO_PRIORITY_FRAME;
+ assertArrayEquals(TestMessages.HEADERS_NO_PADDING_NO_PRIORITY_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+
+ @Test
+ public void decodePaddingPriority() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.HEADERS_PADDING_PRIORITY_BUFFER);
+ Http2HeadersFrame frame = (Http2HeadersFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(23, frame.getLength());
+ assertEquals(1, frame.getType());
+ assertEquals(0x28, frame.getFlags());
+ assertEquals(3, frame.getStreamID());
+ assertEquals(10, frame.getWeight());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ assertEquals(16, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}, frame.getPadding());
+ }
+
+ @Test
+ public void encodePaddingPriority() {
+ Http2HeadersFrame frame = TestMessages.HEADERS_PADDING_PRIORITY_FRAME;
+ assertArrayEquals(TestMessages.HEADERS_PADDING_PRIORITY_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodePaddingNoPriority() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.HEADERS_PADDING_NO_PRIORITY_BUFFER);
+ Http2HeadersFrame frame = (Http2HeadersFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(18, frame.getLength());
+ assertEquals(1, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(3, frame.getStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ assertEquals(16, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}, frame.getPadding());
+ }
+
+ @Test
+ public void encodePaddingNoPriority() {
+ Http2HeadersFrame frame = TestMessages.HEADERS_PADDING_NO_PRIORITY_FRAME;
+ assertArrayEquals(TestMessages.HEADERS_PADDING_NO_PRIORITY_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2PingFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2PingFrameTest.java
new file mode 100644
index 0000000..12d3283
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2PingFrameTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2PingFrameTest extends Http2Test {
+
+ @Test
+ public void decode() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PING_STANDARD_BUFFER);
+ Http2PingFrame frame = (Http2PingFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(6, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertArrayEquals(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, frame.getData());
+ }
+
+ @Test
+ public void encode() {
+ Http2PingFrame frame = TestMessages.PING_STANDARD_FRAME;
+ assertArrayEquals(TestMessages.PING_STANDARD_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeExtraData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PING_EXTRA_DATA_BUFFER);
+ Http2PingFrame frame = (Http2PingFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(9, frame.getLength());
+ assertEquals(6, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertArrayEquals(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, frame.getData());
+ }
+
+ @Test
+ public void encodeExtraData() {
+ Http2PingFrame frame = TestMessages.PING_EXTRA_DATA_FRAME;
+ assertArrayEquals(TestMessages.PING_EXTRA_DATA_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeNotEnoughData() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PING_NO_ENOUGH_DATA_BUFFER);
+ Http2PingFrame frame = (Http2PingFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(1, frame.getLength());
+ assertEquals(6, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertArrayEquals(new byte[] {0x00}, frame.getData());
+ }
+
+ @Test
+ public void encodeNotEnoughData() {
+ Http2PingFrame frame = TestMessages.PING_NO_ENOUGH_DATA_FRAME;
+ assertArrayEquals(TestMessages.PING_NO_ENOUGH_DATA_BUFFER, toByteArray(frame.toBuffer()));
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2PriorityFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2PriorityFrameTest.java
new file mode 100644
index 0000000..397ba36
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2PriorityFrameTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2PriorityFrameTest extends Http2Test {
+
+ @Test
+ public void decodeNoExclusive() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PRIORITY_NO_EXCLUSIVE_MODE_BUFFER);
+ Http2PriorityFrame frame = (Http2PriorityFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(5, frame.getLength());
+ assertEquals(2, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getStreamDependencyID());
+ assertFalse(frame.getExclusiveMode());
+ assertEquals(2, frame.getWeight());
+ }
+
+ @Test
+ public void encodeNoExclusive() {
+ Http2PriorityFrame frame = TestMessages.PRIORITY_NO_EXCLUSIVE_MODE_FRAME;
+ assertArrayEquals(TestMessages.PRIORITY_NO_EXCLUSIVE_MODE_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeExclusive() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PRIORITY_EXCLUSIVE_MODE_BUFFER);
+ Http2PriorityFrame frame = (Http2PriorityFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(5, frame.getLength());
+ assertEquals(2, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getStreamDependencyID());
+ assertTrue(frame.getExclusiveMode());
+ assertEquals(2, frame.getWeight());
+ }
+
+ @Test
+ public void encodeExclusive() {
+ Http2PriorityFrame frame = TestMessages.PRIORITY_EXCLUSIVE_MODE_FRAME;
+ assertArrayEquals(TestMessages.PRIORITY_EXCLUSIVE_MODE_BUFFER, toByteArray(frame.toBuffer()));
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2PushPromiseFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2PushPromiseFrameTest.java
new file mode 100644
index 0000000..612c788
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2PushPromiseFrameTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2PushPromiseFrameTest extends Http2Test {
+
+ @Test
+ public void decodeNoPadding() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PUSH_PROMISE_NO_PADDING_BUFFER);
+ Http2PushPromiseFrame frame = (Http2PushPromiseFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(5, frame.getLength());
+ assertEquals(5, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(256, frame.getPromisedStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ }
+
+ @Test
+ public void encodeNoPadding() {
+ Http2PushPromiseFrame frame = TestMessages.PUSH_PROMISE_NO_PADDING_FRAME;
+ assertArrayEquals(TestMessages.PUSH_PROMISE_NO_PADDING_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+
+ @Test
+ public void decodePadding() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PUSH_PROMISE_PADDING_BUFFER);
+ Http2PushPromiseFrame frame = (Http2PushPromiseFrame) connection.decode(buffer);
+ assertEquals(22, frame.getLength());
+ assertEquals(5, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(3, frame.getStreamID());
+ assertEquals(20, frame.getPromisedStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ assertEquals(16, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}, frame.getPadding());
+ }
+
+ @Test
+ public void encodePadding() {
+ Http2PushPromiseFrame frame = TestMessages.PUSH_PROMISE_PADDING_FRAME;
+ assertArrayEquals(TestMessages.PUSH_PROMISE_PADDING_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2RstStreamFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2RstStreamFrameTest.java
new file mode 100644
index 0000000..c8b42d5
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2RstStreamFrameTest.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.api.Http2RstStreamFrame.Http2RstStreamFrameBuilder;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2RstStreamFrameTest extends Http2Test {
+
+ @Test
+ public void decodeNoExtraPayload() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_NO_EXTRA_PAYLOAD_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(4, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getErrorCode());
+ }
+
+ @Test
+ public void encodeNoExtraPayload() {
+ Http2RstStreamFrame frame = TestMessages.RST_STREAM_NO_EXTRA_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.RST_STREAM_NO_EXTRA_PAYLOAD_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeHighestValueNoExtraPayload() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(4, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(0x00FFFFFFFFL, frame.getErrorCode());
+ }
+
+ @Test
+ public void encodeHighestValueNoExtraPayload() {
+ Http2RstStreamFrame frame = TestMessages.RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeExtraPayload() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_EXTRA_PAYLOAD_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getErrorCode());
+ }
+
+ @Test
+ public void decodeHighestValueExtraPayload() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_EXTRA_PAYLOAD_HIGHEST_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(0x00FFFFFFFFL, frame.getErrorCode());
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2SettingsFrameDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2SettingsFrameDecoderTest.java
new file mode 100644
index 0000000..3681978
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2SettingsFrameDecoderTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2SettingsFrameDecoderTest extends Http2Test {
+
+ @Test
+ public void decode() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.SETTINGS_DEFAULT_BUFFER);
+ Http2SettingsFrame frame = (Http2SettingsFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(4, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(1, frame.getSettings().size());
+ Http2Setting setting = frame.getSettings().iterator().next();
+ assertEquals(1, setting.getID());
+ assertEquals(0x01020304L, setting.getValue());
+ }
+
+ @Test
+ public void encode() {
+ Http2SettingsFrame frame = TestMessages.SETTINGS_DEFAULT_FRAME;
+ assertArrayEquals(TestMessages.SETTINGS_DEFAULT_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeHighestID() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.SETTINGS_HIGHEST_ID_BUFFER);
+ Http2SettingsFrame frame = (Http2SettingsFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(4, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(1, frame.getSettings().size());
+ Http2Setting setting = frame.getSettings().iterator().next();
+ assertEquals(0x00FFFF, setting.getID());
+ assertEquals(0x01020304L, setting.getValue());
+ }
+
+ @Test
+ public void encodeHighestID() {
+ Http2SettingsFrame frame = TestMessages.SETTINGS_HIGHEST_ID_FRAME;
+ assertArrayEquals(TestMessages.SETTINGS_HIGHEST_ID_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeHighestValue() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.SETTINGS_HIGHEST_VALUE_BUFFER);
+ Http2SettingsFrame frame = (Http2SettingsFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(4, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(1, frame.getSettings().size());
+ Http2Setting setting = frame.getSettings().iterator().next();
+ assertEquals(1, setting.getID());
+ assertEquals(0xFFFFFFFFL, setting.getValue());
+ }
+
+ @Test
+ public void encodeHighestValue() {
+ Http2SettingsFrame frame = TestMessages.SETTINGS_HIGHEST_VALUE_FRAME;
+ assertArrayEquals(TestMessages.SETTINGS_HIGHEST_VALUE_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2UnknownFrameTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2UnknownFrameTest.java
new file mode 100644
index 0000000..764e924
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/api/Http2UnknownFrameTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2UnknownFrameTest extends Http2Test {
+
+ @Test
+ public void decode() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.UNKNOWN_PAYLOAD_BUFFER);
+ Http2UnknownFrame frame = (Http2UnknownFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(2, frame.getLength());
+ assertEquals(255, frame.getType() & 0x00FF);
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(2, frame.getPayload().length);
+ assertArrayEquals(new byte[] {0x0E, 0x18}, frame.getPayload());
+ }
+
+ @Test
+ public void encode() {
+ Http2UnknownFrame frame = TestMessages.UNKNOWN_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.UNKNOWN_PAYLOAD_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+ @Test
+ public void decodeWithoutPayload() {
+ Http2Connection connection = new Http2Connection();
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.UNKNOWN_NO_PAYLOAD_BUFFER);
+ Http2UnknownFrame frame = (Http2UnknownFrame) connection.decode(buffer);
+ assertNotNull(frame);
+ assertEquals(0, frame.getLength());
+ assertEquals(255, frame.getType() & 0x00FF);
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(0, frame.getPayload().length);
+ }
+
+ @Test
+ public void encodeWithoutPayload() {
+ Http2UnknownFrame frame = TestMessages.UNKNOWN_NO_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.UNKNOWN_NO_PAYLOAD_BUFFER, toByteArray(frame.toBuffer()));
+ }
+
+
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/codec/Http2ProtocolDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/codec/Http2ProtocolDecoderTest.java
new file mode 100644
index 0000000..6a478dd
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/codec/Http2ProtocolDecoderTest.java
@@ -0,0 +1,458 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.codec;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.api.Http2ContinuationFrame;
+import org.apache.mina.http2.api.Http2DataFrame;
+import org.apache.mina.http2.api.Http2Frame;
+import org.apache.mina.http2.api.Http2GoAwayFrame;
+import org.apache.mina.http2.api.Http2HeadersFrame;
+import org.apache.mina.http2.api.Http2PingFrame;
+import org.apache.mina.http2.api.Http2PriorityFrame;
+import org.apache.mina.http2.api.Http2PushPromiseFrame;
+import org.apache.mina.http2.api.Http2RstStreamFrame;
+import org.apache.mina.http2.api.Http2Setting;
+import org.apache.mina.http2.api.Http2SettingsFrame;
+import org.apache.mina.http2.api.Http2UnknownFrame;
+import org.apache.mina.http2.impl.Http2Connection;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+
+public class Http2ProtocolDecoderTest extends Http2Test {
+
+ private Http2ProtocolDecoder decoder = new Http2ProtocolDecoder();
+ private Http2Connection context = new Http2Connection();
+
+ @Test
+ public void continuationNoHeaderBlock() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.CONTINUATION_NO_HEADER_FRAGMENT_BUFFER);
+ Http2ContinuationFrame frame = (Http2ContinuationFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(0, frame.getLength());
+ assertEquals(9, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(0, frame.getHeaderBlockFragment().length);
+ }
+
+ @Test
+ public void continuationHeaderBlock() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.CONTINUATION_HEADER_FRAGMENT_BUFFER);
+ Http2ContinuationFrame frame = (Http2ContinuationFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(10, frame.getLength());
+ assertEquals(9, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(10, frame.getHeaderBlockFragment().length);
+ assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, frame.getHeaderBlockFragment());
+ }
+
+ @Test
+ public void dataNoPayloadNoPadding() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_NO_PAYLOAD_NO_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(0, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(0, frame.getData().length);
+ assertEquals(0, frame.getPadding().length);
+ }
+
+ @Test
+ public void dataPayloadNoPadding() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_PAYLOAD_NO_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(10, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(10, frame.getData().length);
+ assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, frame.getData());
+ assertEquals(0, frame.getPadding().length);
+ }
+
+ @Test
+ public void dataNoPayloadPadding() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_NO_PAYLOAD_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(3, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(0,frame.getData().length);
+ assertEquals(2, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x0E, 0x28}, frame.getPadding());
+ }
+
+ @Test
+ public void dataPayloadPadding() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.DATA_PAYLOAD_PADDING_BUFFER);
+ Http2DataFrame frame = (Http2DataFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(13, frame.getLength());
+ assertEquals(0, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(50, frame.getStreamID());
+ assertEquals(10, frame.getData().length);
+ assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, frame.getData());
+ assertEquals(2, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x0E, 0x28}, frame.getPadding());
+ }
+
+ @Test
+ public void goAwayNoAdditionalData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(256, frame.getLastStreamID());
+ assertEquals(0x010203, frame.getErrorCode());
+ }
+
+ @Test
+ public void goAwayHighestLastStreamIDNoAdditionalData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(0x7FFFFFFF, frame.getLastStreamID());
+ assertEquals(0x010203, frame.getErrorCode());
+ }
+
+ @Test
+ public void goAwayHighestLastStreamIDReservedBitSetNoAdditionalData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_RESERVED_BIT_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(0x7FFFFFFF, frame.getLastStreamID());
+ assertEquals(0x010203, frame.getErrorCode());
+ }
+
+ @Test
+ public void goAwayHighestErrorCodeNoAdditionalData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(0x7FFFFFFF, frame.getLastStreamID());
+ assertEquals(0x00FFFFFFFFL, frame.getErrorCode());
+ }
+
+ @Test
+ public void goAwayAdditionalData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.GOAWAY_DATA_BUFFER);
+ Http2GoAwayFrame frame = (Http2GoAwayFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(9, frame.getLength());
+ assertEquals(7, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(256, frame.getLastStreamID());
+ assertEquals(0x00010203, frame.getErrorCode());
+ assertArrayEquals(new byte[] {0x01}, frame.getData());
+ }
+
+ @Test
+ public void headersNoPaddingNoPriority() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.HEADERS_NO_PADDING_NO_PRIORITY_BUFFER);
+ Http2HeadersFrame frame = (Http2HeadersFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(1, frame.getLength());
+ assertEquals(1, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ }
+
+ @Test
+ public void headersPaddingPriority() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.HEADERS_PADDING_PRIORITY_BUFFER);
+ Http2HeadersFrame frame = (Http2HeadersFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(23, frame.getLength());
+ assertEquals(1, frame.getType());
+ assertEquals(0x28, frame.getFlags());
+ assertEquals(3, frame.getStreamID());
+ assertEquals(10, frame.getWeight());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ assertEquals(16, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}, frame.getPadding());
+ }
+
+ @Test
+ public void headersPaddingNoPriority() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.HEADERS_PADDING_NO_PRIORITY_BUFFER);
+ Http2HeadersFrame frame = (Http2HeadersFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(18, frame.getLength());
+ assertEquals(1, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(3, frame.getStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ assertEquals(16, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}, frame.getPadding());
+ }
+
+ @Test
+ public void ping() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PING_STANDARD_BUFFER);
+ Http2PingFrame frame = (Http2PingFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(8, frame.getLength());
+ assertEquals(6, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertArrayEquals(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, frame.getData());
+ }
+
+ @Test
+ public void pingExtraData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PING_EXTRA_DATA_BUFFER);
+ Http2PingFrame frame = (Http2PingFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(9, frame.getLength());
+ assertEquals(6, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertArrayEquals(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, frame.getData());
+ }
+
+ @Test
+ public void pingNotEnoughData() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PING_NO_ENOUGH_DATA_BUFFER);
+ Http2PingFrame frame = (Http2PingFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(1, frame.getLength());
+ assertEquals(6, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertArrayEquals(new byte[] {0x00}, frame.getData());
+ }
+
+ @Test
+ public void priorityNoExclusive() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PRIORITY_NO_EXCLUSIVE_MODE_BUFFER);
+ Http2PriorityFrame frame = (Http2PriorityFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(5, frame.getLength());
+ assertEquals(2, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getStreamDependencyID());
+ assertFalse(frame.getExclusiveMode());
+ assertEquals(2, frame.getWeight());
+ }
+
+ @Test
+ public void priorityExclusive() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PRIORITY_EXCLUSIVE_MODE_BUFFER);
+ Http2PriorityFrame frame = (Http2PriorityFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(5, frame.getLength());
+ assertEquals(2, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getStreamDependencyID());
+ assertTrue(frame.getExclusiveMode());
+ assertEquals(2, frame.getWeight());
+ }
+
+ @Test
+ public void pushPromiseNoPadding() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PUSH_PROMISE_NO_PADDING_BUFFER);
+ Http2PushPromiseFrame frame = (Http2PushPromiseFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(5, frame.getLength());
+ assertEquals(5, frame.getType());
+ assertEquals(0, frame.getFlags());
+ assertEquals(1, frame.getStreamID());
+ assertEquals(256, frame.getPromisedStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ }
+
+ @Test
+ public void pushPromisePadding() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.PUSH_PROMISE_PADDING_BUFFER);
+ Http2PushPromiseFrame frame = (Http2PushPromiseFrame) decoder.decode(buffer, context);
+ assertEquals(22, frame.getLength());
+ assertEquals(5, frame.getType());
+ assertEquals(0x08, frame.getFlags());
+ assertEquals(3, frame.getStreamID());
+ assertEquals(20, frame.getPromisedStreamID());
+ assertEquals(1, frame.getHeaderBlockFragment().length);
+ assertEquals(0x0082, frame.getHeaderBlockFragment()[0] & 0x00FF);
+ assertEquals(16, frame.getPadding().length);
+ assertArrayEquals(new byte[] {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x2E}, frame.getPadding());
+ }
+
+ @Test
+ public void rstStreamNoExtraPayload() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_NO_EXTRA_PAYLOAD_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(4, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getErrorCode());
+ }
+
+ @Test
+ public void rstStreamHighestValueNoExtraPayload() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(4, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(0x00FFFFFFFFL, frame.getErrorCode());
+ }
+
+ @Test
+ public void rstStreamExtraPayload() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_EXTRA_PAYLOAD_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(256, frame.getErrorCode());
+ }
+
+ @Test
+ public void rstStreamHighestValueExtraPayload() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.RST_STREAM_EXTRA_PAYLOAD_HIGHEST_BUFFER);
+ Http2RstStreamFrame frame = (Http2RstStreamFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(3, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(0x00FFFFFFFFL, frame.getErrorCode());
+ }
+
+ @Test
+ public void settings() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.SETTINGS_DEFAULT_BUFFER);
+ Http2SettingsFrame frame = (Http2SettingsFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(4, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(1, frame.getSettings().size());
+ Http2Setting setting = frame.getSettings().iterator().next();
+ assertEquals(1, setting.getID());
+ assertEquals(0x01020304L, setting.getValue());
+ }
+
+ @Test
+ public void settingsHighestID() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.SETTINGS_HIGHEST_ID_BUFFER);
+ Http2SettingsFrame frame = (Http2SettingsFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(4, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(1, frame.getSettings().size());
+ Http2Setting setting = frame.getSettings().iterator().next();
+ assertEquals(0x00FFFF, setting.getID());
+ assertEquals(0x01020304L, setting.getValue());
+ }
+
+ @Test
+ public void settingsHighestValue() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.SETTINGS_HIGHEST_VALUE_BUFFER);
+ Http2SettingsFrame frame = (Http2SettingsFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(6, frame.getLength());
+ assertEquals(4, frame.getType());
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(1, frame.getSettings().size());
+ Http2Setting setting = frame.getSettings().iterator().next();
+ assertEquals(1, setting.getID());
+ assertEquals(0xFFFFFFFFL, setting.getValue());
+ }
+
+ @Test
+ public void unknownFrame() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.UNKNOWN_PAYLOAD_BUFFER);
+ Http2UnknownFrame frame = (Http2UnknownFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(2, frame.getLength());
+ assertEquals(255, frame.getType() & 0x00FF);
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(2, frame.getPayload().length);
+ assertArrayEquals(new byte[] {0x0E, 0x18}, frame.getPayload());
+ }
+
+ @Test
+ public void unknownFrameNoPayload() {
+ ByteBuffer buffer = ByteBuffer.wrap(TestMessages.UNKNOWN_NO_PAYLOAD_BUFFER);
+ Http2UnknownFrame frame = (Http2UnknownFrame) decoder.decode(buffer, context);
+ assertNotNull(frame);
+ assertEquals(0, frame.getLength());
+ assertEquals(255, frame.getType() & 0x00FF);
+ assertEquals(0x00, frame.getFlags());
+ assertEquals(32, frame.getStreamID());
+ assertEquals(0, frame.getPayload().length);
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/codec/Http2ProtocolEncoderTest.java b/http2/src/test/java/org/apache/mina/http2/codec/Http2ProtocolEncoderTest.java
new file mode 100644
index 0000000..ecea462
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/codec/Http2ProtocolEncoderTest.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.codec;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import org.apache.mina.http2.Http2Test;
+import org.apache.mina.http2.TestMessages;
+import org.apache.mina.http2.api.Http2Frame;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+
+public class Http2ProtocolEncoderTest extends Http2Test {
+
+ private Http2ProtocolEncoder encoder = new Http2ProtocolEncoder();
+
+ @Test
+ public void continuationNoHeaderBlock() {
+ Http2Frame frame = TestMessages.CONTINUATION_NO_HEADER_FRAGMENT_FRAME;
+ assertArrayEquals(TestMessages.CONTINUATION_NO_HEADER_FRAGMENT_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void continuationHeaderBlock() {
+ Http2Frame frame = TestMessages.CONTINUATION_HEADER_FRAGMENT_FRAME;
+ assertArrayEquals(TestMessages.CONTINUATION_HEADER_FRAGMENT_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+
+ @Test
+ public void dataNoPayloadNoPadding() {
+ Http2Frame frame = TestMessages.DATA_NO_PAYLOAD_NO_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_NO_PAYLOAD_NO_PADDING_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void dataPayloadNoPadding() {
+ Http2Frame frame = TestMessages.DATA_PAYLOAD_NO_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_PAYLOAD_NO_PADDING_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void dataNoPayloadPadding() {
+ Http2Frame frame = TestMessages.DATA_NO_PAYLOAD_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_NO_PAYLOAD_PADDING_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void dataPayloadPadding() {
+ Http2Frame frame = TestMessages.DATA_PAYLOAD_PADDING_FRAME;
+ assertArrayEquals(TestMessages.DATA_PAYLOAD_PADDING_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void goAwayNoAdditionalData() {
+ Http2Frame frame = TestMessages.GOAWAY_NO_DATA_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_NO_DATA_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void goAwayHighestLastStreamIDNoAdditionalData() {
+ Http2Frame frame = TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_NO_DATA_HIGHEST_STREAMID_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void goAwayHighestErrorCodeNoAdditionalData() {
+ Http2Frame frame = TestMessages.GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_NO_DATA_HIGHEST_ERROR_CODE_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void goAwayAdditionalData() {
+ Http2Frame frame = TestMessages.GOAWAY_DATA_FRAME;
+ assertArrayEquals(TestMessages.GOAWAY_DATA_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void headersNoPaddingNoPriority() {
+ Http2Frame frame = TestMessages.HEADERS_NO_PADDING_NO_PRIORITY_FRAME;
+ assertArrayEquals(TestMessages.HEADERS_NO_PADDING_NO_PRIORITY_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void headersPaddingPriority() {
+ Http2Frame frame = TestMessages.HEADERS_PADDING_PRIORITY_FRAME;
+ assertArrayEquals(TestMessages.HEADERS_PADDING_PRIORITY_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void headersPaddingNoPriority() {
+ Http2Frame frame = TestMessages.HEADERS_PADDING_NO_PRIORITY_FRAME;
+ assertArrayEquals(TestMessages.HEADERS_PADDING_NO_PRIORITY_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void ping() {
+ Http2Frame frame = TestMessages.PING_STANDARD_FRAME;
+ assertArrayEquals(TestMessages.PING_STANDARD_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void pingExtraData() {
+ Http2Frame frame = TestMessages.PING_EXTRA_DATA_FRAME;
+ assertArrayEquals(TestMessages.PING_EXTRA_DATA_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void pingNotEnoughData() {
+ Http2Frame frame = TestMessages.PING_NO_ENOUGH_DATA_FRAME;
+ assertArrayEquals(TestMessages.PING_NO_ENOUGH_DATA_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void priorityNoExclusive() {
+ Http2Frame frame = TestMessages.PRIORITY_NO_EXCLUSIVE_MODE_FRAME;
+ assertArrayEquals(TestMessages.PRIORITY_NO_EXCLUSIVE_MODE_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void priorityExclusive() {
+ Http2Frame frame = TestMessages.PRIORITY_EXCLUSIVE_MODE_FRAME;
+ assertArrayEquals(TestMessages.PRIORITY_EXCLUSIVE_MODE_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void pushPromiseNoPadding() {
+ Http2Frame frame = TestMessages.PUSH_PROMISE_NO_PADDING_FRAME;
+ assertArrayEquals(TestMessages.PUSH_PROMISE_NO_PADDING_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void pushPromisePadding() {
+ Http2Frame frame = TestMessages.PUSH_PROMISE_PADDING_FRAME;
+ assertArrayEquals(TestMessages.PUSH_PROMISE_PADDING_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void rstStreamNoExtraPayload() {
+ Http2Frame frame = TestMessages.RST_STREAM_NO_EXTRA_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.RST_STREAM_NO_EXTRA_PAYLOAD_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void rstStreamHighestValueNoExtraPayload() {
+ Http2Frame frame = TestMessages.RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.RST_STREAM_HIGHEST_VALUE_NO_EXTRA_PAYLOAD_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void settings() {
+ Http2Frame frame = TestMessages.SETTINGS_DEFAULT_FRAME;
+ assertArrayEquals(TestMessages.SETTINGS_DEFAULT_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void settingsHighestID() {
+ Http2Frame frame = TestMessages.SETTINGS_HIGHEST_ID_FRAME;
+ assertArrayEquals(TestMessages.SETTINGS_HIGHEST_ID_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void settingsHighestValue() {
+ Http2Frame frame = TestMessages.SETTINGS_HIGHEST_VALUE_FRAME;
+ assertArrayEquals(TestMessages.SETTINGS_HIGHEST_VALUE_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void unknownFrame() {
+ Http2Frame frame = TestMessages.UNKNOWN_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.UNKNOWN_PAYLOAD_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+
+ @Test
+ public void unknownFrameNoPayload() {
+ Http2Frame frame = TestMessages.UNKNOWN_NO_PAYLOAD_FRAME;
+ assertArrayEquals(TestMessages.UNKNOWN_NO_PAYLOAD_BUFFER, toByteArray(encoder.encode(frame, null)));
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/impl/BytePartialDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/impl/BytePartialDecoderTest.java
new file mode 100644
index 0000000..6a30567
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/impl/BytePartialDecoderTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.impl.BytePartialDecoder;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class BytePartialDecoderTest {
+
+ private static final byte[] SAMPLE_VALUE_1 = new byte[] {0x74, 0x18, 0x4F, 0x68};
+ private static final byte[] SAMPLE_VALUE_2 = new byte[] {0x74, 0x18, 0x4F, 0x68, 0x0F};
+
+ @Test
+ public void checkSimpleValue() {
+ BytePartialDecoder decoder = new BytePartialDecoder(4);
+ ByteBuffer buffer = ByteBuffer.wrap(SAMPLE_VALUE_1);
+ assertTrue(decoder.consume(buffer));
+ assertArrayEquals(SAMPLE_VALUE_1, decoder.getValue());
+ }
+
+ @Test
+ public void checkNotenoughData() {
+ BytePartialDecoder decoder = new BytePartialDecoder(4);
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00});
+ assertFalse(decoder.consume(buffer));
+ }
+
+ @Test
+ public void checkTooMuchData() {
+ BytePartialDecoder decoder = new BytePartialDecoder(4);
+ ByteBuffer buffer = ByteBuffer.wrap(SAMPLE_VALUE_2);
+ assertTrue(decoder.consume(buffer));
+ assertArrayEquals(SAMPLE_VALUE_1, decoder.getValue());
+ assertEquals(1, buffer.remaining());
+ }
+
+ @Test
+ public void checkDecodingIn2Steps() {
+ BytePartialDecoder decoder = new BytePartialDecoder(4);
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {SAMPLE_VALUE_2[0], SAMPLE_VALUE_2[1]});
+ assertFalse(decoder.consume(buffer));
+ buffer = ByteBuffer.wrap(new byte[] {SAMPLE_VALUE_2[2], SAMPLE_VALUE_2[3], SAMPLE_VALUE_2[4]});
+ assertTrue(decoder.consume(buffer));
+ assertArrayEquals(SAMPLE_VALUE_1, decoder.getValue());
+ assertEquals(1, buffer.remaining());
+ }
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/impl/Http2FrameHeaderPartialDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/impl/Http2FrameHeaderPartialDecoderTest.java
new file mode 100644
index 0000000..dc12569
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/impl/Http2FrameHeaderPartialDecoderTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder;
+import org.apache.mina.http2.impl.Http2FrameHeadePartialDecoder.Http2FrameHeader;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class Http2FrameHeaderPartialDecoderTest {
+
+ @Test
+ public void checkStandardValue() {
+ Http2FrameHeadePartialDecoder decoder = new Http2FrameHeadePartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x00, /*length*/
+ 0x00, /*type*/
+ 0x00, /*flags*/
+ 0x00, 0x00, 0x00, 0x01 /*streamID*/});
+ assertTrue(decoder.consume(buffer));
+ Http2FrameHeader header = decoder.getValue();
+ assertNotNull(header);
+ assertEquals(0, header.getLength());
+ assertEquals(0, header.getType());
+ assertEquals(0, header.getFlags());
+ assertEquals(1, header.getStreamID());
+ }
+
+ @Test
+ public void checkReservedBitIsNotTransmitted() {
+ Http2FrameHeadePartialDecoder decoder = new Http2FrameHeadePartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x00, /*length*/
+ 0x00, /*type*/
+ 0x00, /*flags*/
+ (byte)0x80, 0x00, 0x00, 0x01 /*streamID*/});
+ assertTrue(decoder.consume(buffer));
+ Http2FrameHeader header = decoder.getValue();
+ assertNotNull(header);
+ assertEquals(0, header.getLength());
+ assertEquals(0, header.getType());
+ assertEquals(0, header.getFlags());
+ assertEquals(1, header.getStreamID());
+ }
+
+ @Test
+ public void checkPayLoadIsTransmitted() {
+ Http2FrameHeadePartialDecoder decoder = new Http2FrameHeadePartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x01, /*length*/
+ 0x00, /*type*/
+ 0x00, /*flags*/
+ (byte)0x80, 0x00, 0x00, 0x01, /*streamID*/
+ 0x40});
+ assertTrue(decoder.consume(buffer));
+ Http2FrameHeader header = decoder.getValue();
+ assertNotNull(header);
+ assertEquals(1, header.getLength());
+ assertEquals(0, header.getType());
+ assertEquals(0, header.getFlags());
+ assertEquals(1, header.getStreamID());
+ }
+
+}
diff --git a/http2/src/test/java/org/apache/mina/http2/impl/IntPartialDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/impl/IntPartialDecoderTest.java
new file mode 100644
index 0000000..674a76e
--- /dev/null
+++ b/http2/src/test/java/org/apache/mina/http2/impl/IntPartialDecoderTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.http2.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.http2.impl.IntPartialDecoder;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class IntPartialDecoderTest {
+
+ @Test
+ public void checkSimpleValue() {
+ IntPartialDecoder decoder = new IntPartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x00, 0x00});
+ assertTrue(decoder.consume(buffer));
+ assertEquals(0, decoder.getValue().intValue());
+ }
+
+ @Test
+ public void checkNotenoughData() {
+ IntPartialDecoder decoder = new IntPartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00});
+ assertFalse(decoder.consume(buffer));
+ }
+
+ @Test
+ public void checkTooMuchData() {
+ IntPartialDecoder decoder = new IntPartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00});
+ assertTrue(decoder.consume(buffer));
+ assertEquals(0, decoder.getValue().intValue());
+ assertEquals(1, buffer.remaining());
+ }
+
+ @Test
+ public void checkDecodingIn2Steps() {
+ IntPartialDecoder decoder = new IntPartialDecoder();
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00});
+ assertFalse(decoder.consume(buffer));
+ buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x00});
+ assertTrue(decoder.consume(buffer));
+ assertEquals(0, decoder.getValue().intValue());
+ assertEquals(1, buffer.remaining());
+ }
+}
diff --git a/pom.xml b/pom.xml
index 97a960e..cc851e7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -111,6 +111,7 @@
<module>core</module>
<module>codec</module>
<module>http</module>
+ <module>http2</module>
<module>examples</module>
<module>coap</module>
<module>thrift</module>