You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2016/03/08 21:04:26 UTC
svn commit: r1734137 [1/2] - in /httpcomponents/httpcore/trunk:
httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/
httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/
httpcore5/src/main/java/org/apache/hc/core5/http/ httpcore5/src/main...
Author: olegk
Date: Tue Mar 8 20:04:26 2016
New Revision: 1734137
URL: http://svn.apache.org/viewvc?rev=1734137&view=rev
Log:
RFC 7541: HPack header coding
Added:
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEntry.java
- copied, changed from r1730834, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackHeader.java
- copied, changed from r1730834, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHeader.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackRepresentation.java
- copied, changed from r1730834, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestHPackCoding.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestInboundDynamicTable.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestOutboundDynamicTable.java (with props)
Removed:
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestHpackCoding.java
Modified:
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHeader.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BufferedHeader.java
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java Tue Mar 8 20:04:26 2016
@@ -0,0 +1,120 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+
+@NotThreadSafe
+final class FifoBuffer {
+
+ private HPackHeader[] array;
+ private int head;
+ private int tail;
+
+ FifoBuffer(final int initialCapacity) {
+ this.array = new HPackHeader[initialCapacity];
+ this.head = 0;
+ this.tail = 0;
+ }
+
+ private void expand() {
+
+ int newcapacity = (array.length + 1) << 1;
+ if (newcapacity < 0) {
+ newcapacity = Integer.MAX_VALUE;
+ }
+ final Header[] oldArray = array;
+ final int len = oldArray.length;
+ final HPackHeader[] newArray = new HPackHeader[newcapacity];
+ System.arraycopy(oldArray, head, newArray, 0, len - head);
+ System.arraycopy(oldArray, 0, newArray, len - head, head);
+ array = newArray;
+ head = len;
+ tail = 0;
+ }
+
+ public void clear() {
+ head = 0;
+ tail = 0;
+ }
+
+ public void addFirst(final HPackHeader header) {
+ array[head++] = header;
+ if (head == array.length) {
+ head = 0;
+ }
+ if (head == tail) {
+ expand();
+ }
+ }
+
+ public HPackHeader get(final int index) {
+ int i = head - index - 1;
+ if (i < 0) {
+ i = array.length + i;
+ }
+ return array[i];
+ }
+
+ public HPackHeader getFirst() {
+ if (head > 0) {
+ return array[head - 1];
+ } else {
+ return array[array.length - 1];
+ }
+ }
+
+ public HPackHeader getLast() {
+ return array[tail];
+ }
+
+ public HPackHeader removeLast() {
+ final HPackHeader header = array[tail];
+ if (header != null) {
+ array[tail++] = null;
+ if (tail == array.length) {
+ tail = 0;
+ }
+ }
+ return header;
+ }
+
+ public int capacity() {
+ return array.length;
+ }
+
+ public int size() {
+ int i = head - tail;
+ if (i < 0) {
+ i = array.length + i;
+ }
+ return i;
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoBuffer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java Tue Mar 8 20:04:26 2016
@@ -0,0 +1,152 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+
+@NotThreadSafe
+final class FifoLinkedList {
+
+ private final InternalNode master;
+ private int length;
+
+ FifoLinkedList() {
+ this.master = new InternalNode(null);
+ this.master.previous = this.master;
+ this.master.next = this.master;
+ }
+
+ public Header get(final int index) {
+ if (index < 0 || index >= length) {
+ throw new IndexOutOfBoundsException();
+ }
+ InternalNode current = master.next;
+ int n = 0;
+ while (current != master) {
+ if (index == n) {
+ return current.header;
+ }
+ current = current.next;
+ n++;
+ }
+ return null;
+ }
+
+ public int getIndex(final InternalNode node) {
+ final int seqNum = node.seqNum;
+ if (seqNum < 1) {
+ return -1;
+ }
+ return length - (seqNum - master.previous.seqNum) - 1;
+ }
+
+ public Header getFirst() {
+ return master.next.header;
+ }
+
+ public Header getLast() {
+ return master.previous.header;
+ }
+
+ public int size() {
+ return length;
+ }
+
+ public InternalNode addFirst(final HPackHeader header) {
+
+ final InternalNode newNode = new InternalNode(header);
+ final InternalNode oldNode = master.next;
+ master.next = newNode;
+ newNode.previous = master;
+ newNode.next = oldNode;
+ oldNode.previous = newNode;
+ newNode.seqNum = oldNode.seqNum + 1;
+ length++;
+ return newNode;
+ }
+
+ public InternalNode removeLast() {
+
+ final InternalNode last = master.previous;
+ if (last.header != null) {
+ final InternalNode lastButOne = last.previous;
+ master.previous = lastButOne;
+ lastButOne.next = master;
+ last.previous = null;
+ last.next = null;
+ last.seqNum = 0;
+ length--;
+ return last;
+ } else {
+ master.seqNum = 0;
+ return null;
+ }
+ }
+
+ public void clear() {
+
+ master.previous = master;
+ master.next = master;
+ master.seqNum = 0;
+ length = 0;
+ }
+
+ class InternalNode implements HPackEntry {
+
+ private final HPackHeader header;
+ private InternalNode previous;
+ private InternalNode next;
+ private int seqNum;
+
+ InternalNode(final HPackHeader header) {
+ this.header = header;
+ }
+
+ public HPackHeader getHeader() {
+ return header;
+ }
+
+ @Override
+ public int getIndex() {
+ return StaticTable.INSTANCE.length() + FifoLinkedList.this.getIndex(this) + 1;
+ }
+
+ @Override
+ public String toString() {
+ return "[" +
+ (header != null ? header.toString() : "master") +
+ "; seqNum=" + seqNum +
+ "; previous=" + (previous != null ? previous.header : null) +
+ "; next=" + (next != null ? next.header : null) +
+ ']';
+ }
+
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/FifoLinkedList.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java?rev=1734137&r1=1734136&r2=1734137&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java Tue Mar 8 20:04:26 2016
@@ -34,31 +34,44 @@ import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.ByteArrayBuffer;
+@NotThreadSafe
public final class HPackDecoder {
private static final String UNEXPECTED_EOS = "Unexpected end of HPACK data";
private static final String MAX_LIMIT_EXCEEDED = "Max integer exceeded";
+ private final InboundDynamicTable dynamicTable;
private final ByteArrayBuffer contentBuf;
private final CharsetDecoder charsetDecoder;
private CharBuffer tmpBuf;
+ private int maxTableSize;
- public HPackDecoder(final Charset charset) {
+ HPackDecoder(final InboundDynamicTable dynamicTable, final Charset charset) {
Args.notNull(charset, "Charset");
+ this.dynamicTable = dynamicTable != null ? dynamicTable : new InboundDynamicTable();
this.contentBuf = new ByteArrayBuffer(256);
this.charsetDecoder = charset.equals(StandardCharsets.US_ASCII) || charset.equals(StandardCharsets.ISO_8859_1) ? null : charset.newDecoder();
}
+ public HPackDecoder(final Charset charset) {
+ this(new InboundDynamicTable(), charset);
+ }
+
static int readByte(final ByteBuffer src) throws HPackException {
if (!src.hasRemaining()) {
throw new HPackException(UNEXPECTED_EOS);
}
- return src.get() & 0xFF;
+ return src.get() & 0xff;
}
static int peekByte(final ByteBuffer src) throws HPackException {
@@ -67,14 +80,14 @@ public final class HPackDecoder {
throw new HPackException(UNEXPECTED_EOS);
}
final int pos = src.position();
- final int b = src.get() & 0xFF;
+ final int b = src.get() & 0xff;
src.position(pos);
return b;
}
static int decodeInt(final ByteBuffer src, final int n) throws HPackException {
- final int nbits = 0xFF >>> (8 - n);
+ final int nbits = 0xff >>> (8 - n);
int value = readByte(src) & nbits;
if (value < nbits) {
return value;
@@ -167,18 +180,18 @@ public final class HPackDecoder {
}
}
- String decodeString(final ByteBuffer src) throws HPackException, CharacterCodingException {
+ int decodeString(final ByteBuffer src, final StringBuilder buf) throws HPackException, CharacterCodingException {
clearState();
decodeString(this.contentBuf, src);
+ final int binaryLen = this.contentBuf.length();
if (this.charsetDecoder == null) {
- final StringBuilder buf = new StringBuilder(this.contentBuf.length());
- for (int i = 0; i < this.contentBuf.length(); i++) {
- buf.append((char) (this.contentBuf.byteAt(i) & 0xFF));
+ buf.ensureCapacity(binaryLen);
+ for (int i = 0; i < binaryLen; i++) {
+ buf.append((char) (this.contentBuf.byteAt(i) & 0xff));
}
- return buf.toString();
} else {
- final ByteBuffer in = ByteBuffer.wrap(this.contentBuf.buffer(), 0, this.contentBuf.length());
+ final ByteBuffer in = ByteBuffer.wrap(this.contentBuf.buffer(), 0, binaryLen);
while (in.hasRemaining()) {
ensureCapacity(in.remaining());
final CoderResult result = this.charsetDecoder.decode(in, this.tmpBuf, true);
@@ -192,8 +205,95 @@ public final class HPackDecoder {
result.throwException();
}
this.tmpBuf.flip();
- return this.tmpBuf.toString();
+ buf.append(this.tmpBuf);
+ }
+ return binaryLen;
+ }
+
+ Header decodeLiteralHeader(
+ final ByteBuffer src,
+ final HPackRepresentation representation) throws HPackException, CharacterCodingException {
+
+ final int n = representation == HPackRepresentation.WITH_INDEXING ? 6 : 4;
+ final int index = decodeInt(src, n);
+ final String name;
+ final int nameLen;
+ if (index == 0) {
+ final StringBuilder buf = new StringBuilder();
+ nameLen = decodeString(src, buf);
+ name = buf.toString();
+ } else {
+ final HPackHeader existing = this.dynamicTable.getHeader(index);
+ if (existing == null) {
+ throw new HPackException("Invalid header index");
+ }
+ name = existing.getName();
+ nameLen = existing.getNameLen();
+ }
+ final StringBuilder buf = new StringBuilder();
+ final int valueLen = decodeString(src, buf);
+ final String value = buf.toString();
+ final HPackHeader header = new HPackHeader(name, nameLen, value, valueLen, representation == HPackRepresentation.NEVER_INDEXED);
+ if (representation == HPackRepresentation.WITH_INDEXING) {
+ this.dynamicTable.add(header);
+ }
+ return new BasicHeader(header.getName(), header.getValue(), header.isSensitive());
+ }
+
+ Header decodeIndexedHeader(final ByteBuffer src) throws HPackException, CharacterCodingException {
+
+ final int index = decodeInt(src, 7);
+ final Header existing = this.dynamicTable.getHeader(index);
+ if (existing == null) {
+ throw new HPackException("Invalid header index");
+ }
+ return existing;
+ }
+
+ public Header decodeHeader(final ByteBuffer src) throws HPackException, CharacterCodingException {
+
+ while (src.hasRemaining()) {
+ final int b = peekByte(src);
+ if ((b & 0x80) == 0x80) {
+ return decodeIndexedHeader(src);
+ } else if ((b & 0xc0) == 0x40) {
+ return decodeLiteralHeader(src, HPackRepresentation.WITH_INDEXING);
+ } else if ((b & 0xf0) == 0x00) {
+ return decodeLiteralHeader(src, HPackRepresentation.WITHOUT_INDEXING);
+ } else if ((b & 0xf0) == 0x10) {
+ return decodeLiteralHeader(src, HPackRepresentation.NEVER_INDEXED);
+ } else if ((b & 0xe0) == 0x20) {
+ final int maxSize = decodeInt(src, 5);
+ this.dynamicTable.setMaxSize(Math.min(this.maxTableSize, maxSize));
+ } else {
+ throw new HPackException("Unexpected header first byte: 0x" + Integer.toHexString(b));
+ }
+ }
+ return null;
+ }
+
+ public List<Header> decodeHeaders(final ByteBuffer src) throws HPackException, CharacterCodingException {
+
+ final List<Header> list = new ArrayList<>();
+ while (src.hasRemaining()) {
+ final Header header = decodeHeader(src);
+ if (header == null) {
+ break;
+ } else {
+ list.add(header);
+ }
}
+ return list;
+ }
+
+ public int getMaxTableSize() {
+ return this.maxTableSize;
+ }
+
+ public void setMaxTableSize(final int maxTableSize) {
+ Args.notNegative(maxTableSize, "Max table size");
+ this.maxTableSize = maxTableSize;
+ this.dynamicTable.setMaxSize(maxTableSize);
}
}
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java?rev=1734137&r1=1734136&r2=1734137&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java Tue Mar 8 20:04:26 2016
@@ -34,66 +34,78 @@ import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;
+import java.util.List;
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.ByteArrayBuffer;
+import org.apache.hc.core5.util.LangUtils;
+@NotThreadSafe
public final class HPackEncoder {
+ private final OutboundDynamicTable dynamicTable;
private final ByteArrayBuffer huffmanBuf;
private final CharsetEncoder charsetEncoder;
private ByteBuffer tmpBuf;
+ private int maxTableSize;
- public HPackEncoder(final Charset charset) {
+ HPackEncoder(final OutboundDynamicTable dynamicTable, final Charset charset) {
Args.notNull(charset, "Charset");
+ this.dynamicTable = dynamicTable != null ? dynamicTable : new OutboundDynamicTable();
this.huffmanBuf = new ByteArrayBuffer(128);
this.charsetEncoder = charset.equals(StandardCharsets.US_ASCII) || charset.equals(StandardCharsets.ISO_8859_1) ? null : charset.newEncoder();
}
- static void encodeInt(final ByteArrayBuffer buffer, final int n, final int i, final int mask) {
+ public HPackEncoder(final Charset charset) {
+ this(new OutboundDynamicTable(), charset);
+ }
+
+ static void encodeInt(final ByteArrayBuffer dst, final int n, final int i, final int mask) {
final int nbits = 0xFF >>> (8 - n);
int value = i;
if (value < nbits) {
- buffer.append(i | mask);
+ dst.append(i | mask);
} else {
- buffer.append(nbits | mask);
+ dst.append(nbits | mask);
value -= nbits;
while (value >= 0x80) {
- buffer.append((value & 0x7F) | 0x80);
+ dst.append((value & 0x7F) | 0x80);
value >>>= 7;
}
- buffer.append(value);
+ dst.append(value);
}
}
- static void encodeHuffman(final ByteArrayBuffer buffer, final ByteBuffer src) throws HPackException {
+ static void encodeHuffman(final ByteArrayBuffer dst, final ByteBuffer src) throws HPackException {
- Huffman.ENCODER.encode(buffer, src);
+ Huffman.ENCODER.encode(dst, src);
}
- void encodeString(final ByteArrayBuffer buffer, final ByteBuffer src, final boolean huffman) throws HPackException {
+ void encodeString(final ByteArrayBuffer dst, final ByteBuffer src, final boolean huffman) throws HPackException {
final int strLen = src.remaining();
if (huffman) {
this.huffmanBuf.clear();
this.huffmanBuf.ensureCapacity(strLen);
Huffman.ENCODER.encode(this.huffmanBuf, src);
- buffer.ensureCapacity(this.huffmanBuf.length() + 8);
- encodeInt(buffer, 7, this.huffmanBuf.length(), 0x80);
- buffer.append(this.huffmanBuf.buffer(), 0, this.huffmanBuf.length());
+ dst.ensureCapacity(this.huffmanBuf.length() + 8);
+ encodeInt(dst, 7, this.huffmanBuf.length(), 0x80);
+ dst.append(this.huffmanBuf.buffer(), 0, this.huffmanBuf.length());
} else {
- buffer.ensureCapacity(strLen + 8);
- encodeInt(buffer, 7, strLen, 0x0);
+ dst.ensureCapacity(strLen + 8);
+ encodeInt(dst, 7, strLen, 0x0);
if (src.hasArray()) {
final byte[] b = src.array();
final int off = src.position();
- buffer.append(b, off, strLen);
+ dst.append(b, off, strLen);
src.position(off + strLen);
} else {
while (src.hasRemaining()) {
- buffer.append(src.get());
+ dst.append(src.get());
}
}
}
@@ -128,8 +140,8 @@ public final class HPackEncoder {
}
}
- void encodeString(
- final ByteArrayBuffer buffer,
+ int encodeString(
+ final ByteArrayBuffer dst,
final CharSequence charSequence, final int off, final int len,
final boolean huffman) throws HPackException, CharacterCodingException {
@@ -139,16 +151,17 @@ public final class HPackEncoder {
this.huffmanBuf.clear();
this.huffmanBuf.ensureCapacity(len);
Huffman.ENCODER.encode(this.huffmanBuf, charSequence, off, len);
- buffer.ensureCapacity(this.huffmanBuf.length() + 8);
- encodeInt(buffer, 7, this.huffmanBuf.length(), 0x80);
- buffer.append(this.huffmanBuf.buffer(), 0, this.huffmanBuf.length());
+ dst.ensureCapacity(this.huffmanBuf.length() + 8);
+ encodeInt(dst, 7, this.huffmanBuf.length(), 0x80);
+ dst.append(this.huffmanBuf.buffer(), 0, this.huffmanBuf.length());
} else {
- buffer.ensureCapacity(len + 8);
- encodeInt(buffer, 7, len, 0x0);
+ dst.ensureCapacity(len + 8);
+ encodeInt(dst, 7, len, 0x0);
for (int i = 0; i < len; i++) {
- buffer.append((int) charSequence.charAt(off + i));
+ dst.append((int) charSequence.charAt(off + i));
}
}
+ return len;
} else {
final CharBuffer in = CharBuffer.wrap(charSequence, off, len);
while (in.hasRemaining()) {
@@ -164,13 +177,142 @@ public final class HPackEncoder {
result.throwException();
}
this.tmpBuf.flip();
- encodeString(buffer, this.tmpBuf, huffman);
+ final int binaryLen = this.tmpBuf.remaining();
+ encodeString(dst, this.tmpBuf, huffman);
+ return binaryLen;
}
}
- void encodeString(final ByteArrayBuffer buffer, final String s, final boolean huffman) throws HPackException, CharacterCodingException {
+ int encodeString(final ByteArrayBuffer dst, final String s, final boolean huffman) throws HPackException, CharacterCodingException {
+
+ return encodeString(dst, s, 0, s.length(), huffman);
+ }
+
+ void encodeLiteralHeader(
+ final ByteArrayBuffer dst, final HPackEntry existing, final Header header,
+ final HPackRepresentation representation, final boolean useHuffman) throws CharacterCodingException, HPackException {
+
+ final int n;
+ final int mask;
+ switch (representation) {
+ case WITH_INDEXING:
+ mask = 0x40;
+ n = 6;
+ break;
+ case WITHOUT_INDEXING:
+ mask = 0x00;
+ n = 4;
+ break;
+ case NEVER_INDEXED:
+ mask = 0x10;
+ n = 4;
+ break;
+ default:
+ throw new IllegalStateException("Unexpected value: " + representation);
+ }
+ final int index = existing != null ? existing.getIndex() : 0;
+ final int nameLen;
+ if (index <= 0) {
+ encodeInt(dst, n, 0, mask);
+ nameLen = encodeString(dst, header.getName(), useHuffman);
+ } else {
+ encodeInt(dst, n, index, mask);
+ nameLen = existing.getHeader().getNameLen();
+ }
+ final int valueLen = encodeString(dst, header.getValue(), useHuffman);
+ if (representation == HPackRepresentation.WITH_INDEXING) {
+ dynamicTable.add(new HPackHeader(header.getName(), nameLen, header.getValue(), valueLen, header.isSensitive()));
+ }
+ }
+
+ void encodeIndex(final ByteArrayBuffer dst, final int index) throws HPackException {
+ encodeInt(dst, 7, index, 0x80);
+ }
+
+ private int findFullMatch(final List<HPackEntry> entries, final String value) {
+ if (entries == null || entries.isEmpty()) {
+ return 0;
+ }
+ for (int i = 0; i < entries.size(); i++) {
+ final HPackEntry entry = entries.get(i);
+ if (LangUtils.equals(value, entry.getHeader().getValue())) {
+ return entry.getIndex();
+ }
+ }
+ return 0;
+ }
+
+ void encodeHeader(
+ final ByteArrayBuffer dst, final Header header,
+ final boolean noIndexing, final boolean useHuffman) throws CharacterCodingException, HPackException {
+
+ final HPackRepresentation representation;
+ if (header.isSensitive()) {
+ representation = HPackRepresentation.NEVER_INDEXED;
+ } else if (noIndexing) {
+ representation = HPackRepresentation.WITHOUT_INDEXING;
+ } else {
+ representation = HPackRepresentation.WITH_INDEXING;
+ }
+
+ final String key = header.getName();
+ final String value = header.getValue();
+
+ final List<HPackEntry> staticEntries = StaticTable.INSTANCE.getByName(key);
+
+ if (representation == HPackRepresentation.WITH_INDEXING) {
+ // Try to find full match and encode as as index
+ final int staticIndex = findFullMatch(staticEntries, value);
+ if (staticIndex > 0) {
+ encodeIndex(dst, staticIndex);
+ return;
+ }
+ final List<HPackEntry> dynamicEntries = dynamicTable.getByName(key);
+ final int dynamicIndex = findFullMatch(dynamicEntries, value);
+ if (dynamicIndex > 0) {
+ encodeIndex(dst, dynamicIndex);
+ return;
+ }
+ }
+ // Encode as literal
+ HPackEntry existing = null;
+ if (staticEntries != null && !staticEntries.isEmpty()) {
+ existing = staticEntries.get(0);
+ } else {
+ final List<HPackEntry> dynamicEntries = dynamicTable.getByName(key);
+ if (dynamicEntries != null && !dynamicEntries.isEmpty()) {
+ existing = dynamicEntries.get(0);
+ }
+ }
+ encodeLiteralHeader(dst, existing, header, representation, useHuffman);
+ }
+
+ void encodeHeaders(
+ final ByteArrayBuffer dst, final List<Header> headers,
+ final boolean noIndexing, final boolean useHuffman) throws CharacterCodingException, HPackException {
+ for (int i = 0; i < headers.size(); i++) {
+ encodeHeader(dst, headers.get(i), noIndexing, useHuffman);
+ }
+ }
+
+ public void encodeHeader(
+ final ByteArrayBuffer dst, final Header header) throws CharacterCodingException, HPackException {
+ encodeHeader(dst, header, false, true);
+ }
+
+ public void encodeHeaders(
+ final ByteArrayBuffer dst, final List<Header> headers) throws CharacterCodingException, HPackException {
+ encodeHeaders(dst, headers, false, true);
+ }
+
+ public int getMaxTableSize() {
+ return this.maxTableSize;
+ }
- encodeString(buffer, s, 0, s.length(), huffman);
+ public void setMaxTableSize(final int maxTableSize) {
+ Args.notNegative(maxTableSize, "Max table size");
+ this.maxTableSize = maxTableSize;
+ this.dynamicTable.setMaxSize(maxTableSize);
}
}
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEntry.java (from r1730834, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEntry.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEntry.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java&r1=1730834&r2=1734137&rev=1734137&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEntry.java Tue Mar 8 20:04:26 2016
@@ -25,27 +25,12 @@
*
*/
-package org.apache.hc.core5.http;
+package org.apache.hc.core5.http2.hpack;
-/**
- * Represents an HTTP header field consisting of a field name and a field value..
- *
- * @since 4.0
- */
-public interface Header {
+interface HPackEntry {
- /**
- * Get the name of the Header.
- *
- * @return the name of the Header, never {@code null}
- */
- String getName();
+ int getIndex();
- /**
- * Get the value of the Header.
- *
- * @return the value of the Header, may be {@code null}
- */
- String getValue();
+ HPackHeader getHeader();
}
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackHeader.java (from r1730834, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHeader.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackHeader.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackHeader.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHeader.java&r1=1730834&r2=1734137&rev=1734137&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHeader.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackHeader.java Tue Mar 8 20:04:26 2016
@@ -25,48 +25,71 @@
*
*/
-package org.apache.hc.core5.http.message;
-
-import java.io.Serializable;
-import java.util.Objects;
+package org.apache.hc.core5.http2.hpack;
import org.apache.hc.core5.annotation.Immutable;
import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.util.Args;
/**
- * Immutable {@link Header}.
- *
- * @since 4.0
+ * Internal HPack header representation that also contains binary length of
+ * header name and header value.
*/
@Immutable
-public class BasicHeader implements Header, Serializable {
+final class HPackHeader implements Header {
- private static final long serialVersionUID = -5427236326487562174L;
+ static private final int ENTRY_SIZE_OVERHEAD = 32;
private final String name;
+ private final int nameLen;
private final String value;
+ private final int valueLen;
+ private final boolean sensitive;
- /**
- * Constructor with name and value
- *
- * @param name the header name
- * @param value the header value, taken as the value's {@link #toString()}.
- */
- public BasicHeader(final String name, final Object value) {
- super();
- this.name = Args.notNull(name, "Name");
- this.value = Objects.toString(value, null);
+ HPackHeader(final String name, final int nameLen, final String value, final int valueLen, final boolean sensitive) {
+ this.name = name;
+ this.nameLen = nameLen;
+ this.value = value;
+ this.valueLen = valueLen;
+ this.sensitive = sensitive;
+ }
+
+ HPackHeader(final String name, final String value, final boolean sensitive) {
+ this(name, name.length(), value, value.length(), sensitive);
+ }
+
+ HPackHeader(final String name, final String value) {
+ this(name, value, false);
+ }
+
+ HPackHeader(final Header header) {
+ this(header.getName(), header.getValue(), header.isSensitive());
}
@Override
public String getName() {
- return this.name;
+ return name;
+ }
+
+ public int getNameLen() {
+ return nameLen;
}
@Override
public String getValue() {
- return this.value;
+ return value;
+ }
+
+ public int getValueLen() {
+ return valueLen;
+ }
+
+ @Override
+ public boolean isSensitive() {
+ return sensitive;
+ }
+
+ public int getTotalSize() {
+ return nameLen + valueLen + ENTRY_SIZE_OVERHEAD;
}
@Override
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackRepresentation.java (from r1730834, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackRepresentation.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackRepresentation.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java&r1=1730834&r2=1734137&rev=1734137&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/Header.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackRepresentation.java Tue Mar 8 20:04:26 2016
@@ -25,27 +25,6 @@
*
*/
-package org.apache.hc.core5.http;
+package org.apache.hc.core5.http2.hpack;
-/**
- * Represents an HTTP header field consisting of a field name and a field value..
- *
- * @since 4.0
- */
-public interface Header {
-
- /**
- * Get the name of the Header.
- *
- * @return the name of the Header, never {@code null}
- */
- String getName();
-
- /**
- * Get the value of the Header.
- *
- * @return the value of the Header, may be {@code null}
- */
- String getValue();
-
-}
+enum HPackRepresentation { WITH_INDEXING, WITHOUT_INDEXING, NEVER_INDEXED }
\ No newline at end of file
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java Tue Mar 8 20:04:26 2016
@@ -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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.util.Asserts;
+
+@NotThreadSafe
+final class InboundDynamicTable {
+
+ private final StaticTable staticTable;
+ private final FifoBuffer headers;
+
+ private int maxSize;
+ private int currentSize;
+
+ InboundDynamicTable(final StaticTable staticTable) {
+ this.staticTable = staticTable;
+ this.headers = new FifoBuffer(256);
+ this.maxSize = Integer.MAX_VALUE;
+ this.currentSize = 0;
+ }
+
+ InboundDynamicTable() {
+ this(StaticTable.INSTANCE);
+ }
+
+ public int getMaxSize() {
+ return maxSize;
+ }
+
+ public void setMaxSize(final int maxSize) {
+ this.maxSize = maxSize;
+ evict();
+ }
+
+ public int getCurrentSize() {
+ return currentSize;
+ }
+
+ int staticLength() {
+ return staticTable.length();
+ }
+
+ int dynamicLength() {
+ return headers.size();
+ }
+
+ Header getDynamicEntry(final int index) {
+ return headers.get(index);
+ }
+
+ public int length() {
+ return staticTable.length() + headers.size();
+ }
+
+ public HPackHeader getHeader(final int index) {
+ if (index < 1 || index > length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (index <= staticTable.length()) {
+ return staticTable.get(index);
+ } else {
+ return headers.get(index - staticTable.length() - 1);
+ }
+ }
+
+ public void add(final HPackHeader header) {
+ final int entrySize = header.getTotalSize();
+ if (entrySize > this.maxSize) {
+ clear();
+ return;
+ }
+ headers.addFirst(header);
+ currentSize += entrySize;
+ evict();
+ }
+
+ private void clear() {
+ currentSize = 0;
+ headers.clear();
+ }
+
+ private void evict() {
+ while (currentSize > maxSize) {
+ final HPackHeader header = headers.removeLast();
+ if (header != null) {
+ currentSize -= header.getTotalSize();
+ } else {
+ Asserts.check(currentSize == 0, "Current table size must be zero");
+ break;
+ }
+ }
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/InboundDynamicTable.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java Tue Mar 8 20:04:26 2016
@@ -0,0 +1,148 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.util.Asserts;
+
+@NotThreadSafe
+final class OutboundDynamicTable {
+
+ private final StaticTable staticTable;
+ private final FifoLinkedList headers;
+ private final Map<String, LinkedList<HPackEntry>> mapByName;
+
+ private int maxSize;
+ private int currentSize;
+
+ OutboundDynamicTable(final StaticTable staticTable) {
+ this.staticTable = staticTable;
+ this.headers = new FifoLinkedList();
+ this.mapByName = new HashMap<>();
+ this.maxSize = Integer.MAX_VALUE;
+ this.currentSize = 0;
+ }
+
+ OutboundDynamicTable() {
+ this(StaticTable.INSTANCE);
+ }
+
+ public int getMaxSize() {
+ return maxSize;
+ }
+
+ public void setMaxSize(final int maxSize) {
+ this.maxSize = maxSize;
+ evict();
+ }
+
+ public int getCurrentSize() {
+ return currentSize;
+ }
+
+ int staticLength() {
+ return staticTable.length();
+ }
+
+ int dynamicLength() {
+ return headers.size();
+ }
+
+ Header getDynamicEntry(final int index) {
+ return headers.get(index);
+ }
+
+ public int length() {
+ return staticTable.length() + headers.size();
+ }
+
+ public Header getHeader(final int index) {
+ if (index < 1 || index > length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (index <= staticTable.length()) {
+ return staticTable.get(index);
+ } else {
+ return headers.get(index - staticTable.length() - 1);
+ }
+ }
+
+ public void add(final HPackHeader header) {
+ final int entrySize = header.getTotalSize();
+ if (entrySize > this.maxSize) {
+ clear();
+ this.mapByName.clear();
+ return;
+ }
+ final String key = header.getName();
+ final FifoLinkedList.InternalNode node = headers.addFirst(header);
+ LinkedList<HPackEntry> nodes = mapByName.get(key);
+ if (nodes == null) {
+ nodes = new LinkedList<>();
+ mapByName.put(key, nodes);
+ }
+ nodes.addFirst(node);
+ currentSize += entrySize;
+ evict();
+ }
+
+ private void clear() {
+ currentSize = 0;
+ headers.clear();
+ }
+
+ public List<HPackEntry> getByName(final String key) {
+ return this.mapByName.get(key);
+ }
+
+ private void evict() {
+ while (currentSize > maxSize) {
+ final FifoLinkedList.InternalNode node = headers.removeLast();
+ if (node != null) {
+ final HPackHeader header = node.getHeader();
+ currentSize -= header.getTotalSize();
+
+ final String key = header.getName();
+ final LinkedList<HPackEntry> nodes = mapByName.get(key);
+ if (nodes != null) {
+ nodes.remove(node);
+ }
+ } else {
+ Asserts.check(currentSize == 0, "Current table size must be zero");
+ break;
+ }
+ }
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/OutboundDynamicTable.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java Tue Mar 8 20:04:26 2016
@@ -0,0 +1,161 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.hc.core5.annotation.Immutable;
+
+@Immutable
+final class StaticTable {
+
+ static final HPackHeader[] STANDARD_HEADERS = {
+ new HPackHeader(":authority", ""),
+ new HPackHeader(":method", "GET"),
+ new HPackHeader(":method", "POST"),
+ new HPackHeader(":path", "/"),
+ new HPackHeader(":path", "/index.html"),
+ new HPackHeader(":scheme", "http"),
+ new HPackHeader(":scheme", "https"),
+ new HPackHeader(":status", "200"),
+ new HPackHeader(":status", "204"),
+ new HPackHeader(":status", "206"),
+ new HPackHeader(":status", "304"),
+ new HPackHeader(":status", "400"),
+ new HPackHeader(":status", "404"),
+ new HPackHeader(":status", "500"),
+ new HPackHeader("accept-charset", ""),
+ new HPackHeader("accept-encoding", "gzip, deflate"),
+ new HPackHeader("accept-language", ""),
+ new HPackHeader("accept-ranges", ""),
+ new HPackHeader("accept", ""),
+ new HPackHeader("access-control-allow-origin", ""),
+ new HPackHeader("age", ""),
+ new HPackHeader("allow", ""),
+ new HPackHeader("authorization", ""),
+ new HPackHeader("cache-control", ""),
+ new HPackHeader("content-disposition", ""),
+ new HPackHeader("content-encoding", ""),
+ new HPackHeader("content-language", ""),
+ new HPackHeader("content-length", ""),
+ new HPackHeader("content-location", ""),
+ new HPackHeader("content-range", ""),
+ new HPackHeader("content-type", ""),
+ new HPackHeader("cookie", ""),
+ new HPackHeader("date", ""),
+ new HPackHeader("etag", ""),
+ new HPackHeader("expect", ""),
+ new HPackHeader("expires", ""),
+ new HPackHeader("from", ""),
+ new HPackHeader("host", ""),
+ new HPackHeader("if-match", ""),
+ new HPackHeader("if-modified-since", ""),
+ new HPackHeader("if-none-match", ""),
+ new HPackHeader("if-range", ""),
+ new HPackHeader("if-unmodified-since", ""),
+ new HPackHeader("last-modified", ""),
+ new HPackHeader("link", ""),
+ new HPackHeader("location", ""),
+ new HPackHeader("max-forwards", ""),
+ new HPackHeader("proxy-authenticate", ""),
+ new HPackHeader("proxy-authorization", ""),
+ new HPackHeader("range", ""),
+ new HPackHeader("referer", ""),
+ new HPackHeader("refresh", ""),
+ new HPackHeader("retry-after", ""),
+ new HPackHeader("server", ""),
+ new HPackHeader("set-cookie", ""),
+ new HPackHeader("strict-transport-security", ""),
+ new HPackHeader("transfer-encoding", ""),
+ new HPackHeader("user-agent", ""),
+ new HPackHeader("vary", ""),
+ new HPackHeader("via", ""),
+ new HPackHeader("www-authenticate", "")
+ };
+
+ final static StaticTable INSTANCE = new StaticTable(STANDARD_HEADERS);
+
+ private final HPackHeader[] headers;
+ private final ConcurrentMap<String, CopyOnWriteArrayList<HPackEntry>> mapByName;
+
+ StaticTable(final HPackHeader... headers) {
+ this.headers = headers;
+ this.mapByName = new ConcurrentHashMap<>();
+
+ for (int i = 0; i < headers.length; i++) {
+ final HPackHeader header = headers[i];
+
+ final String key = header.getName();
+ CopyOnWriteArrayList<HPackEntry> entries = this.mapByName.get(key);
+ if (entries == null) {
+ entries = new CopyOnWriteArrayList<>(new HPackEntry[] { new InternalEntry(header, i) });
+ this.mapByName.put(key, entries);
+ } else {
+ entries.add(new InternalEntry(header, i));
+ }
+ }
+ }
+
+ public int length() {
+ return this.headers.length;
+ }
+
+ public HPackHeader get(final int index) {
+ return this.headers[index - 1];
+ }
+
+ public List<HPackEntry> getByName(final String key) {
+ return this.mapByName.get(key);
+ }
+
+ static class InternalEntry implements HPackEntry {
+
+ private final HPackHeader header;
+ private final int index;
+
+ InternalEntry(final HPackHeader header, final int index) {
+ this.header = header;
+ this.index = index;
+ }
+
+ @Override
+ public int getIndex() {
+ return index + 1;
+ }
+
+ @Override
+ public HPackHeader getHeader() {
+ return header;
+ }
+
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/StaticTable.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java Tue Mar 8 20:04:26 2016
@@ -0,0 +1,136 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestFifoBuffer {
+
+ @Test
+ public void testAddRemoveCycle() throws Exception {
+
+ final FifoBuffer fifoBuffer = new FifoBuffer(5);
+
+ final HPackHeader h1 = new HPackHeader("h", "1");
+ final HPackHeader h2 = new HPackHeader("h", "2");
+ final HPackHeader h3 = new HPackHeader("h", "3");
+ final HPackHeader h4 = new HPackHeader("h", "4");
+
+ for (int i = 0; i < 20; i++) {
+ Assert.assertEquals(0, fifoBuffer.size());
+ Assert.assertSame(null, fifoBuffer.getFirst());
+ Assert.assertSame(null, fifoBuffer.getLast());
+ fifoBuffer.addFirst(h1);
+ Assert.assertSame(h1, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+ Assert.assertEquals(1, fifoBuffer.size());
+ fifoBuffer.addFirst(h2);
+ Assert.assertEquals(2, fifoBuffer.size());
+ Assert.assertSame(h2, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+ fifoBuffer.addFirst(h3);
+ Assert.assertEquals(3, fifoBuffer.size());
+ Assert.assertSame(h3, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+ fifoBuffer.addFirst(h4);
+ Assert.assertEquals(4, fifoBuffer.size());
+ Assert.assertSame(h4, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+
+ Assert.assertSame(h4, fifoBuffer.get(0));
+ Assert.assertSame(h3, fifoBuffer.get(1));
+ Assert.assertSame(h2, fifoBuffer.get(2));
+ Assert.assertSame(h1, fifoBuffer.get(3));
+
+ fifoBuffer.removeLast();
+ Assert.assertEquals(3, fifoBuffer.size());
+ Assert.assertSame(h4, fifoBuffer.getFirst());
+ Assert.assertSame(h2, fifoBuffer.getLast());
+ fifoBuffer.removeLast();
+ Assert.assertEquals(2, fifoBuffer.size());
+ Assert.assertSame(h4, fifoBuffer.getFirst());
+ Assert.assertSame(h3, fifoBuffer.getLast());
+ fifoBuffer.removeLast();
+ Assert.assertEquals(1, fifoBuffer.size());
+ Assert.assertSame(h4, fifoBuffer.getFirst());
+ Assert.assertSame(h4, fifoBuffer.getLast());
+ fifoBuffer.removeLast();
+ Assert.assertEquals(0, fifoBuffer.size());
+ Assert.assertSame(null, fifoBuffer.getFirst());
+ Assert.assertSame(null, fifoBuffer.getLast());
+ }
+ }
+
+ @Test
+ public void testExpand() throws Exception {
+
+ final HPackHeader h1 = new HPackHeader("h", "1");
+ final HPackHeader h2 = new HPackHeader("h", "2");
+ final HPackHeader h3 = new HPackHeader("h", "3");
+ final HPackHeader h4 = new HPackHeader("h", "4");
+
+ for (int i = 0; i < 10; i++) {
+
+ final FifoBuffer fifoBuffer = new FifoBuffer(1);
+
+ for (int n = 0; n < i; n++) {
+
+ fifoBuffer.addFirst(h1);
+ fifoBuffer.removeLast();
+ }
+
+ Assert.assertEquals(0, fifoBuffer.size());
+ Assert.assertSame(null, fifoBuffer.getFirst());
+ Assert.assertSame(null, fifoBuffer.getLast());
+ fifoBuffer.addFirst(h1);
+ Assert.assertSame(h1, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+ Assert.assertEquals(1, fifoBuffer.size());
+ fifoBuffer.addFirst(h2);
+ Assert.assertEquals(2, fifoBuffer.size());
+ Assert.assertSame(h2, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+ fifoBuffer.addFirst(h3);
+ Assert.assertEquals(3, fifoBuffer.size());
+ Assert.assertSame(h3, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+ fifoBuffer.addFirst(h4);
+ Assert.assertEquals(4, fifoBuffer.size());
+ Assert.assertSame(h4, fifoBuffer.getFirst());
+ Assert.assertSame(h1, fifoBuffer.getLast());
+
+ Assert.assertSame(h4, fifoBuffer.get(0));
+ Assert.assertSame(h3, fifoBuffer.get(1));
+ Assert.assertSame(h2, fifoBuffer.get(2));
+ Assert.assertSame(h1, fifoBuffer.get(3));
+ }
+ }
+
+}
+
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoBuffer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java?rev=1734137&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java Tue Mar 8 20:04:26 2016
@@ -0,0 +1,161 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.hpack;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestFifoLinkedList {
+
+ @Test
+ public void testAddRemoveCycle() throws Exception {
+
+ final FifoLinkedList fifoLinkedList = new FifoLinkedList();
+
+ final HPackHeader h1 = new HPackHeader("h", "1");
+ final HPackHeader h2 = new HPackHeader("h", "2");
+ final HPackHeader h3 = new HPackHeader("h", "3");
+ final HPackHeader h4 = new HPackHeader("h", "4");
+
+ for (int i = 0; i < 5; i++) {
+ Assert.assertEquals(0, fifoLinkedList.size());
+ Assert.assertSame(null, fifoLinkedList.getFirst());
+ Assert.assertSame(null, fifoLinkedList.getLast());
+
+ fifoLinkedList.addFirst(h1);
+ Assert.assertEquals(1, fifoLinkedList.size());
+ Assert.assertSame(h1, fifoLinkedList.getFirst());
+ Assert.assertSame(h1, fifoLinkedList.getLast());
+
+ fifoLinkedList.addFirst(h2);
+ Assert.assertEquals(2, fifoLinkedList.size());
+ Assert.assertSame(h2, fifoLinkedList.getFirst());
+ Assert.assertSame(h1, fifoLinkedList.getLast());
+
+ fifoLinkedList.addFirst(h3);
+ Assert.assertEquals(3, fifoLinkedList.size());
+ Assert.assertSame(h3, fifoLinkedList.getFirst());
+ Assert.assertSame(h1, fifoLinkedList.getLast());
+
+ fifoLinkedList.addFirst(h4);
+ Assert.assertEquals(4, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.getFirst());
+ Assert.assertSame(h1, fifoLinkedList.getLast());
+
+ fifoLinkedList.removeLast();
+ Assert.assertEquals(3, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.getFirst());
+ Assert.assertSame(h2, fifoLinkedList.getLast());
+
+ fifoLinkedList.removeLast();
+ Assert.assertEquals(2, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.getFirst());
+ Assert.assertSame(h3, fifoLinkedList.getLast());
+
+ fifoLinkedList.removeLast();
+ Assert.assertEquals(1, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.getFirst());
+ Assert.assertSame(h4, fifoLinkedList.getLast());
+
+ fifoLinkedList.removeLast();
+ Assert.assertEquals(0, fifoLinkedList.size());
+ Assert.assertSame(null, fifoLinkedList.getFirst());
+ Assert.assertSame(null, fifoLinkedList.getLast());
+ }
+ }
+
+ @Test
+ public void testGetIndex() throws Exception {
+
+ final FifoLinkedList fifoLinkedList = new FifoLinkedList();
+
+ final HPackHeader h1 = new HPackHeader("h", "1");
+ final HPackHeader h2 = new HPackHeader("h", "2");
+ final HPackHeader h3 = new HPackHeader("h", "3");
+ final HPackHeader h4 = new HPackHeader("h", "4");
+
+ final FifoLinkedList.InternalNode node1 = fifoLinkedList.addFirst(h1);
+ final FifoLinkedList.InternalNode node2 = fifoLinkedList.addFirst(h2);
+ final FifoLinkedList.InternalNode node3 = fifoLinkedList.addFirst(h3);
+ final FifoLinkedList.InternalNode node4 = fifoLinkedList.addFirst(h4);
+
+ Assert.assertEquals(0, fifoLinkedList.getIndex(node4));
+ Assert.assertEquals(1, fifoLinkedList.getIndex(node3));
+ Assert.assertEquals(2, fifoLinkedList.getIndex(node2));
+ Assert.assertEquals(3, fifoLinkedList.getIndex(node1));
+
+ Assert.assertEquals(4, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.get(0));
+ Assert.assertSame(h3, fifoLinkedList.get(1));
+ Assert.assertSame(h2, fifoLinkedList.get(2));
+ Assert.assertSame(h1, fifoLinkedList.get(3));
+
+ fifoLinkedList.removeLast();
+
+ Assert.assertEquals(0, fifoLinkedList.getIndex(node4));
+ Assert.assertEquals(1, fifoLinkedList.getIndex(node3));
+ Assert.assertEquals(2, fifoLinkedList.getIndex(node2));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node1));
+
+ Assert.assertEquals(3, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.get(0));
+ Assert.assertSame(h3, fifoLinkedList.get(1));
+ Assert.assertSame(h2, fifoLinkedList.get(2));
+
+ fifoLinkedList.removeLast();
+
+ Assert.assertEquals(0, fifoLinkedList.getIndex(node4));
+ Assert.assertEquals(1, fifoLinkedList.getIndex(node3));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node2));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node1));
+
+ Assert.assertEquals(2, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.get(0));
+ Assert.assertSame(h3, fifoLinkedList.get(1));
+
+ fifoLinkedList.removeLast();
+
+ Assert.assertEquals(0, fifoLinkedList.getIndex(node4));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node3));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node2));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node1));
+
+ Assert.assertEquals(1, fifoLinkedList.size());
+ Assert.assertSame(h4, fifoLinkedList.get(0));
+
+ fifoLinkedList.removeLast();
+
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node4));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node3));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node2));
+ Assert.assertEquals(-1, fifoLinkedList.getIndex(node1));
+
+ Assert.assertEquals(0, fifoLinkedList.size());
+ }
+}
+
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestFifoLinkedList.java
------------------------------------------------------------------------------
svn:mime-type = text/plain