Repository: netty/netty
Issue: double counting header name length in http/2

### Expected behavior

A header with a name of length X and a value of length Y gets considered as being length X + Y in total.

### Actual behavior

A header with a name of length X and a value of length Y gets considered as being length 2X + Y in total.  I think this is where the bug is:

https://github.com/netty/netty/blob/4.1/codec-http2/src/main/java/io/netty/handler/codec/http2/HpackDecoder.java#L262

### Steps to reproduce

Use hpack decoder to decode a header.

### Netty version

4.1.16.Final

### JVM version (e.g. `java -version`)

jdk8

Issue comments:
@mosesn can you open a PR with a unit test ?
@normanmaurer yeah, I'll take a look.
@mosesn thanks buddy
I still haven't been able to make a unit test, but I have a better idea of what's happening.

After we have already added the name length and value length  of the header with the long name length to the headersLength, we can go into "Literal Header Field with Incremental Indexing" mode, and then we go to READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX , and if index is not 127 or 0, we go into into the same area as before, because `nameLength` hasn't changed yet.

Pull request review comments:
this comment is a bit confusing... when we "get an exception" shouldn't we need to catch it ?
oh, I just copy/pasted this from the previous test.  I'll just delete it.
updated, PTAL

Patch that resolved the issue:
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/HpackDecoder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/HpackDecoder.java
index ce81f7c4984..07b1e30b535 100644
--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/HpackDecoder.java
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/HpackDecoder.java
@@ -162,6 +162,7 @@ public void decode(int streamId, ByteBuf in, Http2Headers headers) throws Http2E
                             default:
                                 // Index was stored as the prefix
                                 name = readName(index);
+                                nameLength = name.length();
                                 state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                         }
                     } else if ((b & 0x20) == 0x20) {
@@ -187,6 +188,7 @@ public void decode(int streamId, ByteBuf in, Http2Headers headers) throws Http2E
                             default:
                             // Index was stored as the prefix
                             name = readName(index);
+                            nameLength = name.length();
                             state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                         }
                     }
@@ -205,6 +207,7 @@ public void decode(int streamId, ByteBuf in, Http2Headers headers) throws Http2E
                 case READ_INDEXED_HEADER_NAME:
                     // Header Name matches an entry in the Header Table
                     name = readName(decodeULE128(in, index));
+                    nameLength = name.length();
                     state = READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                     break;
 


Test patch:
diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/HpackDecoderTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/HpackDecoderTest.java
index 8dd885400ce..04552b9263e 100644
--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/HpackDecoderTest.java
+++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/HpackDecoderTest.java
@@ -455,4 +455,26 @@ public void testDecodeLargerThanMaxHeaderListSizeButSmallerThanMaxHeaderListSize
             in.release();
         }
     }
+
+    @Test
+    public void testDecodeCountsNamesOnlyOnce() throws Http2Exception {
+        ByteBuf in = Unpooled.buffer(200);
+        try {
+            hpackDecoder.setMaxHeaderListSize(3500, 4000);
+            HpackEncoder hpackEncoder = new HpackEncoder(true);
+
+            // encode headers that are slightly larger than maxHeaderListSize
+            // but smaller than maxHeaderListSizeGoAway
+            Http2Headers toEncode = new DefaultHttp2Headers();
+            toEncode.add(String.format("%03000d", 0).replace('0', 'f'), "value");
+            toEncode.add("accept", "value");
+            hpackEncoder.encodeHeaders(1, in, toEncode, NEVER_SENSITIVE);
+
+            Http2Headers decoded = new DefaultHttp2Headers();
+            hpackDecoder.decode(1, in, decoded);
+            assertEquals(2, decoded.size());
+        } finally {
+            in.release();
+        }
+    }
 }