Multiple HTTP2 PDUs
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 index ba8a8fe..3bf58f6 100644 --- a/http2/src/main/java/org/apache/mina/http2/api/Http2Constants.java +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2Constants.java
@@ -190,4 +190,6 @@ 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..0138d17 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2ContinuationFrame.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.api; + +/** + * An SPY data 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; + } + + protected <T extends AbstractHttp2ContinuationFrameBuilder<T,V>, V extends Http2ContinuationFrame> Http2ContinuationFrame(AbstractHttp2ContinuationFrameBuilder<T, V> builder) { + super(builder); + this.headerBlockFragment = builder.getHeaderBlockFragment(); + } + + + public static abstract class AbstractHttp2ContinuationFrameBuilder<T extends AbstractHttp2ContinuationFrameBuilder<T,V>, V extends Http2ContinuationFrame> extends AbstractHttp2FrameBuilder<T,V> { + private byte[] headerBlockFragment = new byte[0]; + + @SuppressWarnings("unchecked") + public T headerBlockFragment(byte[] headerBlockFragment) { + this.headerBlockFragment = headerBlockFragment; + return (T) this; + } + + public byte[] getHeaderBlockFragment() { + return headerBlockFragment; + } + } + + public static class Builder extends AbstractHttp2ContinuationFrameBuilder<Builder, Http2ContinuationFrame> { + + @Override + public Http2ContinuationFrame build() { + return new Http2ContinuationFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..2a4802d --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2DataFrame.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.api; + +import static org.apache.mina.http2.api.Http2Constants.EMPTY_BYTE_ARRAY; + +/** + * An SPY 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; + } + + protected <T extends AbstractHttp2DataFrameBuilder<T,V>, V extends Http2Frame> Http2DataFrame(AbstractHttp2DataFrameBuilder<T, V> builder) { + super(builder); + this.data = builder.getData(); + this.padding = builder.getPadding(); + } + + + public static abstract class AbstractHttp2DataFrameBuilder<T extends AbstractHttp2DataFrameBuilder<T,V>, V extends Http2Frame> extends AbstractHttp2FrameBuilder<T,V> { + private byte[] data = EMPTY_BYTE_ARRAY; + + private byte[] padding = EMPTY_BYTE_ARRAY; + + @SuppressWarnings("unchecked") + public T data(byte[] data) { + this.data = data; + return (T) this; + } + + public byte[] getData() { + return data; + } + + @SuppressWarnings("unchecked") + public T padding(byte[] padding) { + this.padding = padding; + return (T) this; + } + + public byte[] getPadding() { + return padding; + } +} + + public static class Builder extends AbstractHttp2DataFrameBuilder<Builder, Http2Frame> { + + @Override + public Http2Frame build() { + return new Http2DataFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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 index b6a3ed2..356c2b8 100644 --- a/http2/src/main/java/org/apache/mina/http2/api/Http2Frame.java +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2Frame.java
@@ -20,89 +20,93 @@ package org.apache.mina.http2.api; /** - * An SPY frame + * An SPY data frame * * @author <a href="http://mina.apache.org">Apache MINA Project</a> * */ -public class Http2Frame { - private int length; - - private short type; - - private short flags; - - private int streamID; - - public byte[] payload; +public abstract class Http2Frame { - /** - * @return the length - */ + private final int length; + + private final short type; + + private final short flags; + + private final int streamID; + public int getLength() { return length; } - /** - * @param length the length to set - */ - public void setLength(int length) { - this.length = length; - } - - /** - * @return the type - */ public short getType() { return type; } - - /** - * @param type the type to set - */ - public void setType(short type) { - this.type = type; - } - - /** - * @return the flags - */ + public short getFlags() { return flags; } - /** - * @param flags the flags to set - */ - public void setFlags(short flags) { - this.flags = flags; - } - - /** - * @return the streamID - */ public int getStreamID() { return streamID; } - /** - * @param streamID the streamID to set - */ - public void setStreamID(int streamID) { - this.streamID = streamID; + 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(); } - /** - * @return the payload - */ - public byte[] getPayload() { - return payload; - } + public static abstract class AbstractHttp2FrameBuilder<T extends AbstractHttp2FrameBuilder<T,V>, V extends Http2Frame> { + private int length; + + private short type; + + private short flags; + + private int streamID; + + @SuppressWarnings("unchecked") + public T length(int length) { + this.length = length; + return (T) this; + } + + public int getLength() { + return length; + } - /** - * @param payload the payload to set - */ - public void setPayload(byte[] payload) { - this.payload = payload; + @SuppressWarnings("unchecked") + public T type(short type) { + this.type = type; + return (T) this; + } + + public short getType() { + return type; + } + + @SuppressWarnings("unchecked") + public T flags(short flags) { + this.flags = flags; + return (T) this; + } + + public short getFlags() { + return flags; + } + + @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/Http2FrameHeadePartialDecoder.java b/http2/src/main/java/org/apache/mina/http2/api/Http2FrameHeadePartialDecoder.java new file mode 100644 index 0000000..059f193 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2FrameHeadePartialDecoder.java
@@ -0,0 +1,106 @@ +/** + * + */ +package org.apache.mina.http2.api; + +import java.nio.ByteBuffer; + +import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK; +/** + * @author jeffmaury + * + */ +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/api/Http2GoAwayFrame.java b/http2/src/main/java/org/apache/mina/http2/api/Http2GoAwayFrame.java new file mode 100644 index 0000000..fbc5ea1 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2GoAwayFrame.java
@@ -0,0 +1,104 @@ +/* + * 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; + +/** + * 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 int errorCode; + + private byte[] data; + + public int getLastStreamID() { + return lastStreamID; + } + + public int getErrorCode() { + return errorCode; + } + + public byte[] getData() { + return data; + } + + protected <T extends AbstractHttp2GoAwayFrameBuilder<T,V>, V extends Http2GoAwayFrame> Http2GoAwayFrame(AbstractHttp2GoAwayFrameBuilder<T, V> builder) { + super(builder); + this.lastStreamID = builder.getLastStreamID(); + this.errorCode = builder.getErrorCode(); + this.data = builder.getData(); + } + + + public static abstract class AbstractHttp2GoAwayFrameBuilder<T extends AbstractHttp2GoAwayFrameBuilder<T,V>, V extends Http2GoAwayFrame> extends AbstractHttp2FrameBuilder<T,V> { + private int lastStreamID; + + private int errorCode; + + private byte[] data; + + @SuppressWarnings("unchecked") + public T lastStreamID(int lastStreamID) { + this.lastStreamID = lastStreamID; + return (T) this; + } + + public int getLastStreamID() { + return lastStreamID; + } + + @SuppressWarnings("unchecked") + public T errorCode(int errorCode) { + this.errorCode = errorCode; + return (T) this; + } + + public int getErrorCode() { + return errorCode; + } + + @SuppressWarnings("unchecked") + public T data(byte[] data) { + this.data = data; + return (T) this; + } + + public byte[] getData() { + return data; + } + } + + public static class Builder extends AbstractHttp2GoAwayFrameBuilder<Builder, Http2GoAwayFrame> { + + @Override + public Http2GoAwayFrame build() { + return new Http2GoAwayFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..aadb1bc --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2HeadersFrame.java
@@ -0,0 +1,145 @@ +/* + * 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; + +/** + * An SPY data 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 byte weight; + + private final byte[] headerBlockFragment; + + + public byte[] getPadding() { + return padding; + } + + public int getStreamDependencyID() { + return streamDependencyID; + } + + public boolean getExclusiveMode() { + return exclusiveMode; + } + + public byte getWeight() { + return weight; + } + + public byte[] getHeaderBlockFragment() { + return headerBlockFragment; + } + + protected <T extends AbstractHttp2HeadersFrameBuilder<T,V>, V extends Http2HeadersFrame> Http2HeadersFrame(AbstractHttp2HeadersFrameBuilder<T, V> 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 abstract class AbstractHttp2HeadersFrameBuilder<T extends AbstractHttp2HeadersFrameBuilder<T,V>, V extends Http2HeadersFrame> extends AbstractHttp2FrameBuilder<T,V> { + private byte[] padding; + + private int streamDependencyID; + + private byte weight; + + private byte[] headerBlockFragment; + + private boolean exclusiveMode; + + @SuppressWarnings("unchecked") + public T padding(byte[] padding) { + this.padding = padding; + return (T) this; + } + + public byte[] getPadding() { + return padding; + } + + @SuppressWarnings("unchecked") + public T streamDependencyID(int streamDependencyID) { + this.streamDependencyID = streamDependencyID; + return (T) this; + } + + public int getStreamDependencyID() { + return streamDependencyID; + } + + @SuppressWarnings("unchecked") + public T exclusiveMode(boolean exclusiveMode) { + this.exclusiveMode = exclusiveMode; + return (T) this; + } + + public boolean getExclusiveMode() { + return exclusiveMode; + } + + @SuppressWarnings("unchecked") + public T weight(byte weight) { + this.weight = weight; + return (T) this; + } + + public byte getWeight() { + return weight; + } + + @SuppressWarnings("unchecked") + public T headerBlockFragment(byte[] headerBlockFragment) { + this.headerBlockFragment = headerBlockFragment; + return (T) this; + } + + public byte[] getHeaderBlockFragment() { + return headerBlockFragment; + } + } + + public static class Builder extends AbstractHttp2HeadersFrameBuilder<Builder, Http2HeadersFrame> { + + @Override + public Http2HeadersFrame build() { + return new Http2HeadersFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + + } +}
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..c1df709 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2PingFrame.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.api; + +/** + * 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; + } + + protected <T extends AbstractHttp2PingFrameBuilder<T,V>, V extends Http2PingFrame> Http2PingFrame(AbstractHttp2PingFrameBuilder<T, V> builder) { + super(builder); + this.data = builder.getData(); + } + + + public static abstract class AbstractHttp2PingFrameBuilder<T extends AbstractHttp2PingFrameBuilder<T,V>, V extends Http2PingFrame> extends AbstractHttp2FrameBuilder<T,V> { + private byte[] data; + + @SuppressWarnings("unchecked") + public T data(byte[] data) { + this.data = data; + return (T) this; + } + + public byte[] getData() { + return data; + } + } + + public static class Builder extends AbstractHttp2PingFrameBuilder<Builder, Http2PingFrame> { + + @Override + public Http2PingFrame build() { + return new Http2PingFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..5478c69 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2PriorityFrame.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; + +/** + * An SPY data 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; + } + + protected <T extends AbstractHttp2PriorityFrameBuilder<T,V>, V extends Http2PriorityFrame> Http2PriorityFrame(AbstractHttp2PriorityFrameBuilder<T, V> builder) { + super(builder); + this.streamDependencyID = builder.getStreamDependencyID(); + this.exclusiveMode = builder.exclusiveMode; + this.weight = builder.getWeight(); + } + + + public static abstract class AbstractHttp2PriorityFrameBuilder<T extends AbstractHttp2PriorityFrameBuilder<T,V>, V extends Http2PriorityFrame> extends AbstractHttp2FrameBuilder<T,V> { + private int streamDependencyID; + + private boolean exclusiveMode; + + private short weight; + + @SuppressWarnings("unchecked") + public T streamDependencyID(int streamDependencyID) { + this.streamDependencyID = streamDependencyID; + return (T) this; + } + + public int getStreamDependencyID() { + return streamDependencyID; + } + + @SuppressWarnings("unchecked") + public T exclusiveMode(boolean exclusiveMode) { + this.exclusiveMode = exclusiveMode; + return (T) this; + } + + public boolean getExclusiveMode() { + return exclusiveMode; + } + + + @SuppressWarnings("unchecked") + public T weight(short weight) { + this.weight = weight; + return (T) this; + } + + public short getWeight() { + return weight; + } + } + + public static class Builder extends AbstractHttp2PriorityFrameBuilder<Builder, Http2PriorityFrame> { + + @Override + public Http2PriorityFrame build() { + return new Http2PriorityFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..a2ab2c7 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2PushPromiseFrame.java
@@ -0,0 +1,107 @@ +/* + * 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; + +/** + * 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; + } + + protected <T extends AbstractHttp2PushPromiseFrameBuilder<T,V>, V extends Http2PushPromiseFrame> Http2PushPromiseFrame(AbstractHttp2PushPromiseFrameBuilder<T, V> builder) { + super(builder); + this.padding = builder.getPadding(); + this.promisedStreamID = builder.getPromisedStreamID(); + this.headerBlockFragment = builder.getHeaderBlockFragment(); + } + + public static abstract class AbstractHttp2PushPromiseFrameBuilder<T extends AbstractHttp2PushPromiseFrameBuilder<T,V>, V extends Http2PushPromiseFrame> extends AbstractHttp2FrameBuilder<T,V> { + private byte[] padding = EMPTY_BYTE_ARRAY; + + private int promisedStreamID; + + private byte[] headerBlockFragment = EMPTY_BYTE_ARRAY; + + @SuppressWarnings("unchecked") + public T padding(byte[] padding) { + this.padding = padding; + return (T) this; + } + + public byte[] getPadding() { + return padding; + } + + @SuppressWarnings("unchecked") + public T promisedStreamID(int promisedStreamID) { + this.promisedStreamID = promisedStreamID; + return (T) this; + } + + public int getPromisedStreamID() { + return promisedStreamID; + } + + @SuppressWarnings("unchecked") + public T headerBlockFragment(byte[] headerBlockFragment) { + this.headerBlockFragment = headerBlockFragment; + return (T) this; + } + + public byte[] getHeaderBlockFragment() { + return headerBlockFragment; + } + } + + public static class Builder extends AbstractHttp2PushPromiseFrameBuilder<Builder, Http2PushPromiseFrame> { + + @Override + public Http2PushPromiseFrame build() { + return new Http2PushPromiseFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..1536594 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2RstStreamFrame.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.api; + +/** + * An SPY data 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; + } + + protected <T extends AbstractHttp2RstStreamFrameBuilder<T,V>, V extends Http2RstStreamFrame> Http2RstStreamFrame(AbstractHttp2RstStreamFrameBuilder<T, V> builder) { + super(builder); + this.errorCode = builder.getErrorCode(); + } + + + public static abstract class AbstractHttp2RstStreamFrameBuilder<T extends AbstractHttp2RstStreamFrameBuilder<T,V>, V extends Http2RstStreamFrame> extends AbstractHttp2FrameBuilder<T,V> { + private long errorCode; + + @SuppressWarnings("unchecked") + public T errorCode(long errorCode) { + this.errorCode = errorCode; + return (T) this; + } + + public long getErrorCode() { + return errorCode; + } + } + + public static class Builder extends AbstractHttp2RstStreamFrameBuilder<Builder, Http2RstStreamFrame> { + + @Override + public Http2RstStreamFrame build() { + return new Http2RstStreamFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..66c44ba --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2SettingsFrame.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.api; + +import java.util.Collection; + +/** + * An SPY data 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; + } + + protected <T extends AbstractHttp2SettingsFrameBuilder<T,V>, V extends Http2SettingsFrame> Http2SettingsFrame(AbstractHttp2SettingsFrameBuilder<T, V> builder) { + super(builder); + this.settings = builder.getSettings(); + } + + + public static abstract class AbstractHttp2SettingsFrameBuilder<T extends AbstractHttp2SettingsFrameBuilder<T,V>, V extends Http2SettingsFrame> extends AbstractHttp2FrameBuilder<T,V> { + private Collection<Http2Setting> settings; + + @SuppressWarnings("unchecked") + public T settings(Collection<Http2Setting> settings) { + this.settings = settings; + return (T) this; + } + + public Collection<Http2Setting> getSettings() { + return settings; + } + } + + public static class Builder extends AbstractHttp2SettingsFrameBuilder<Builder, Http2SettingsFrame> { + + @Override + public Http2SettingsFrame build() { + return new Http2SettingsFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..1cdcaef --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2UnknownFrame.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.api; + +/** + * An SPY data 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; + } + + protected <T extends AbstractHttp2UnknownFrameBuilder<T,V>, V extends Http2UnknownFrame> Http2UnknownFrame(AbstractHttp2UnknownFrameBuilder<T, V> builder) { + super(builder); + this.payload = builder.getPayload(); + } + + + public static abstract class AbstractHttp2UnknownFrameBuilder<T extends AbstractHttp2UnknownFrameBuilder<T,V>, V extends Http2UnknownFrame> extends AbstractHttp2FrameBuilder<T,V> { + private byte[] payload = new byte[0]; + + @SuppressWarnings("unchecked") + public T payload(byte[] payload) { + this.payload = payload; + return (T) this; + } + + public byte[] getPayload() { + return payload; + } + } + + public static class Builder extends AbstractHttp2UnknownFrameBuilder<Builder, Http2UnknownFrame> { + + @Override + public Http2UnknownFrame build() { + return new Http2UnknownFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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..f552aaf --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/api/Http2WindowUpdateFrame.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.api; + +/** + * 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; + } + + protected <T extends AbstractHttp2WindowUpdateFrameBuilder<T,V>, V extends Http2WindowUpdateFrame> Http2WindowUpdateFrame(AbstractHttp2WindowUpdateFrameBuilder<T, V> builder) { + super(builder); + this.windowUpdateIncrement = builder.getWindowUpdateIncrement(); + } + + + public static abstract class AbstractHttp2WindowUpdateFrameBuilder<T extends AbstractHttp2WindowUpdateFrameBuilder<T,V>, V extends Http2WindowUpdateFrame> extends AbstractHttp2FrameBuilder<T,V> { + private int windowUpdateIncrement; + + @SuppressWarnings("unchecked") + public T windowUpdateIncrement(int windowUpdateIncrement) { + this.windowUpdateIncrement = windowUpdateIncrement; + return (T) this; + } + + public int getWindowUpdateIncrement() { + return windowUpdateIncrement; + } + } + + public static class Builder extends AbstractHttp2WindowUpdateFrameBuilder<Builder, Http2WindowUpdateFrame> { + + @Override + public Http2WindowUpdateFrame build() { + return new Http2WindowUpdateFrame(this); + } + + public static Builder builder() { + return new Builder(); + } + } +}
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 index 3019b20..9ec5b4f 100644 --- a/http2/src/main/java/org/apache/mina/http2/impl/Http2Connection.java +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2Connection.java
@@ -3,10 +3,29 @@ import java.nio.ByteBuffer; import org.apache.mina.http2.api.Http2Frame; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder; +import org.apache.mina.http2.api.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; public class Http2Connection { - private final Http2FrameDecoder decoder = new Http2FrameDecoder(); + 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, @@ -17,9 +36,59 @@ */ public Http2Frame decode(ByteBuffer input) { Http2Frame frame = null; - if (decoder.consume(input)) { - frame = decoder.getValue(); - decoder.reset(); + 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..39f6706 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2ContinuationFrameDecoder.java
@@ -0,0 +1,51 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2ContinuationFrame.Builder; + +/** + * @author jeffmaury + * + */ +public class Http2ContinuationFrameDecoder extends Http2FrameDecoder { + + private BytePartialDecoder decoder; + + private Builder builder = new Builder(); + + 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..7a07812 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2DataFrameDecoder.java
@@ -0,0 +1,96 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2DataFrame.Builder; +import org.apache.mina.http2.api.PartialDecoder; + +import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING; + +/** + * @author jeffmaury + * + */ +public class Http2DataFrameDecoder extends Http2FrameDecoder { + + private enum State { + PAD_LENGTH, + DATA, + PADDING + } + + private State state; + + private PartialDecoder<?> decoder; + + private int padLength; + + private Builder builder = new Builder(); + + 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 index ba32afc..e59c41e 100644 --- a/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameDecoder.java +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2FrameDecoder.java
@@ -3,86 +3,50 @@ */ package org.apache.mina.http2.impl; -import java.nio.ByteBuffer; - -import org.apache.mina.http2.api.BytePartialDecoder; import org.apache.mina.http2.api.Http2Frame; -import org.apache.mina.http2.api.LongPartialDecoder; +import org.apache.mina.http2.api.Http2Frame.AbstractHttp2FrameBuilder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; import org.apache.mina.http2.api.PartialDecoder; -import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK; - /** * @author jeffmaury * */ -public class Http2FrameDecoder implements PartialDecoder<Http2Frame> { - - private static enum State { - LENGTH_TYPE_FLAGS, - STREAMID, - PAYLOAD - } - - private State state; - - private PartialDecoder<?> decoder; +public abstract class Http2FrameDecoder implements PartialDecoder<Http2Frame> { + private Http2FrameHeader header; private Http2Frame frame; - - private boolean frameComplete; - public Http2FrameDecoder() { - reset(); + public Http2FrameDecoder(Http2FrameHeader header) { + this.header = header; } - @Override - public boolean consume(ByteBuffer buffer) { - while (!frameComplete && buffer.remaining() > 0) { - switch (state) { - case LENGTH_TYPE_FLAGS: - if (decoder.consume(buffer)) { - long val = ((LongPartialDecoder)decoder).getValue(); - frame.setLength((int) ((val >> 16) & 0xFFFFFFL)); - frame.setType((short) ((val >> 8) & 0xFF)); - frame.setFlags((short) (val & 0xFF)); - state = State.STREAMID; - decoder = new LongPartialDecoder(4); - } - break; - case STREAMID: - if (decoder.consume(buffer)) { - frame.setStreamID((int) (((LongPartialDecoder)decoder).getValue() & HTTP2_31BITS_MASK)); - if (frame.getLength() > 0) { - decoder = new BytePartialDecoder(frame.getLength()); - state = State.PAYLOAD; - } else { - frameComplete = true; - } - } - break; - case PAYLOAD: - if (decoder.consume(buffer)) { - frame.setPayload(((BytePartialDecoder)decoder).getValue()); - frameComplete = true; - } - break; - } - } - return frameComplete; + 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() { - state = State.LENGTH_TYPE_FLAGS; - decoder = new LongPartialDecoder(5); - frame = new Http2Frame(); - frameComplete = false; } }
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..86187b2 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2GoAwayFrameDecoder.java
@@ -0,0 +1,82 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2GoAwayFrame.Builder; +import org.apache.mina.http2.api.IntPartialDecoder; +import org.apache.mina.http2.api.PartialDecoder; + +import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK; +/** + * @author jeffmaury + * + */ +public class Http2GoAwayFrameDecoder extends Http2FrameDecoder { + + private enum State { + LAST_STREAM_ID, + CODE, + EXTRA + } + + private State state; + + private PartialDecoder<?> decoder; + + private Builder builder = new Builder(); + + 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.reset(); + } + case CODE: + if (decoder.consume(buffer)) { + builder.errorCode(((IntPartialDecoder)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..72a89c3 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2HeadersFrameDecoder.java
@@ -0,0 +1,117 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2HeadersFrame.Builder; +import org.apache.mina.http2.api.IntPartialDecoder; +import org.apache.mina.http2.api.PartialDecoder; + +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 jeffmaury + * + */ +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 Builder builder = new Builder(); + + 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..4098d49 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2PingFrameDecoder.java
@@ -0,0 +1,70 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2PingFrame.Builder; + +/** + * @author jeffmaury + * + */ +public class Http2PingFrameDecoder extends Http2FrameDecoder { + + private static enum State { + DATA, + EXTRA + } + + private State state; + + private BytePartialDecoder decoder; + + private Builder builder = new Builder(); + + public Http2PingFrameDecoder(Http2FrameHeader header) { + super(header); + decoder = new BytePartialDecoder(8); + state = State.DATA; + 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 DATA: + if (decoder.consume(buffer)) { + builder.data(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)) { + 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/Http2PriorityFrameDecoder.java b/http2/src/main/java/org/apache/mina/http2/impl/Http2PriorityFrameDecoder.java new file mode 100644 index 0000000..8fd1036 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2PriorityFrameDecoder.java
@@ -0,0 +1,83 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2PriorityFrame.Builder; +import org.apache.mina.http2.api.IntPartialDecoder; +import org.apache.mina.http2.api.PartialDecoder; + +import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK; +import static org.apache.mina.http2.api.Http2Constants.HTTP2_EXCLUSIVE_MASK; + +/** + * @author jeffmaury + * + */ +public class Http2PriorityFrameDecoder extends Http2FrameDecoder { + + private enum State { + STREAM_DEPENDENCY, + WEIGHT, + EXTRA + } + + private State state; + + private PartialDecoder<?> decoder; + + private Builder builder = new Builder(); + + 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..34863ce --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2PushPromiseFrameDecoder.java
@@ -0,0 +1,101 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2PushPromiseFrame.Builder; +import org.apache.mina.http2.api.IntPartialDecoder; +import org.apache.mina.http2.api.PartialDecoder; + +import static org.apache.mina.http2.api.Http2Constants.FLAGS_PADDING; +import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK; + +/** + * @author jeffmaury + * + */ +public class Http2PushPromiseFrameDecoder extends Http2FrameDecoder { + + private enum State { + PAD_LENGTH, + PROMISED_STREAM, + HEADER, + PADDING + } + + private State state; + + private PartialDecoder<?> decoder; + + private int padLength; + + private Builder builder = new Builder(); + + 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..e16b0bc --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2RstStreamFrameDecoder.java
@@ -0,0 +1,75 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2RstStreamFrame.Builder; +import org.apache.mina.http2.api.IntPartialDecoder; +import org.apache.mina.http2.api.LongPartialDecoder; +import org.apache.mina.http2.api.PartialDecoder; + +import static org.apache.mina.http2.api.Http2Constants.HTTP2_31BITS_MASK; + +/** + * @author jeffmaury + * + */ +public class Http2RstStreamFrameDecoder extends Http2FrameDecoder { + + private enum State { + ERROR_CODE, + EXTRA + } + + private State state; + + private PartialDecoder<?> decoder; + + private Builder builder = new Builder(); + + 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..6213c66 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2SettingsFrameDecoder.java
@@ -0,0 +1,64 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2SettingsFrame.Builder; +import org.apache.mina.http2.api.Http2Setting; +import org.apache.mina.http2.api.LongPartialDecoder; + +/** + * @author jeffmaury + * + */ +public class Http2SettingsFrameDecoder extends Http2FrameDecoder { + + private int remaining; + + private LongPartialDecoder decoder = new LongPartialDecoder(6); + + private Builder builder = new Builder(); + + 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..f19e55f --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2UnknownFrameDecoder.java
@@ -0,0 +1,52 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2UnknownFrame.Builder; + +/** + * @author jeffmaury + * + */ +public class Http2UnknownFrameDecoder extends Http2FrameDecoder { + + private BytePartialDecoder decoder; + + private Builder builder = new Builder(); + + 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..6d96327 --- /dev/null +++ b/http2/src/main/java/org/apache/mina/http2/impl/Http2WindowUpdateFrameDecoder.java
@@ -0,0 +1,73 @@ +/** + * + */ +package org.apache.mina.http2.impl; + +import java.nio.ByteBuffer; + +import org.apache.mina.http2.api.BytePartialDecoder; +import org.apache.mina.http2.api.Http2FrameHeadePartialDecoder.Http2FrameHeader; +import org.apache.mina.http2.api.Http2WindowUpdateFrame.Builder; +import org.apache.mina.http2.api.IntPartialDecoder; +import org.apache.mina.http2.api.PartialDecoder; + +/** + * @author jeffmaury + * + */ +public class Http2WindowUpdateFrameDecoder extends Http2FrameDecoder { + + private enum State { + INCREMENT, + EXTRA + } + + private State state; + + private PartialDecoder<?> decoder; + + private Builder builder = new Builder(); + + 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/test/java/org/apache/mina/http2/api/Htp2PushPromiseFrameDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/api/Htp2PushPromiseFrameDecoderTest.java index 30b7299..02f7198 100644 --- a/http2/src/test/java/org/apache/mina/http2/api/Htp2PushPromiseFrameDecoderTest.java +++ b/http2/src/test/java/org/apache/mina/http2/api/Htp2PushPromiseFrameDecoderTest.java
@@ -11,10 +11,10 @@ public class Htp2PushPromiseFrameDecoderTest { @Test - public void checkHeadersFrameWithNotPadding() { + public void checkWithNoPadding() { Http2Connection connection = new Http2Connection(); ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x05, /*length*/ - 0x01, /*type*/ + 0x05, /*type*/ 0x00, /*flags*/ 0x00, 0x00, 0x00, 0x01, /*streamID*/ 0x00, 0x00, 0x01, 0x00, /*promisedStreamID*/ @@ -32,49 +32,26 @@ @Test - public void checkHeadersFramePaddingPriority() { + public void checkWithPadding() { Http2Connection connection = new Http2Connection(); - ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x17, /*length*/ - 0x01, /*type*/ - 0x28, /*flags*/ + ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x16, /*length*/ + 0x05, /*type*/ + 0x08, /*flags*/ 0x00, 0x00, 0x00, 0x03, /*streamID*/ 0x10, /*padding length*/ - (byte)0x0080, 0x00, 0x00, 0x14, /*stream dependency*/ - 0x09, /*weight*/ + 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*/}); - Http2HeadersFrame frame = (Http2HeadersFrame) connection.decode(buffer); - assertNotNull(frame); - assertEquals(23, frame.getLength()); - assertEquals(1, frame.getType()); - assertEquals(0x28, frame.getFlags()); + Http2PushPromiseFrame frame = (Http2PushPromiseFrame) connection.decode(buffer); + assertEquals(22, frame.getLength()); + assertEquals(5, frame.getType()); + assertEquals(0x08, frame.getFlags()); assertEquals(3, frame.getStreamID()); - assertEquals(10, frame.getWeight()); + 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 checkHeadersFramePaddingNoPriority() { - Http2Connection connection = new Http2Connection(); - ByteBuffer buffer = ByteBuffer.wrap(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*/}); - 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()); - } }
diff --git a/http2/src/test/java/org/apache/mina/http2/api/Http2FrameHeaderPartialDecoderTest.java b/http2/src/test/java/org/apache/mina/http2/api/Http2FrameHeaderPartialDecoderTest.java index bda0c77..af684b4 100644 --- a/http2/src/test/java/org/apache/mina/http2/api/Http2FrameHeaderPartialDecoderTest.java +++ b/http2/src/test/java/org/apache/mina/http2/api/Http2FrameHeaderPartialDecoderTest.java
@@ -58,8 +58,6 @@ assertEquals(0, header.getType()); assertEquals(0, header.getFlags()); assertEquals(1, header.getStreamID()); - assertEquals(1, header.getPayload().length); - assertEquals(0x40, header.getPayload()[0] ); } }