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