Skip to content

improve: table size update must come first in header block #140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions hpack/shared/src/main/scala/org/http4s/hpack/Decoder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@
*/
package org.http4s.hpack;

import java.io.IOException;
import java.io.InputStream;

import org.http4s.hpack.HpackUtil.IndexType;
import org.http4s.hpack.HeaderField.HEADER_ENTRY_OVERHEAD
import org.http4s.hpack.HpackUtil.IndexType

import org.http4s.hpack.HeaderField.HEADER_ENTRY_OVERHEAD;
import java.io.IOException
import java.io.InputStream;

private[http4s] final class Decoder(dynamicTable: DynamicTable) {

Expand All @@ -48,6 +47,11 @@ private[http4s] final class Decoder(dynamicTable: DynamicTable) {
new IOException("invalid max dynamic table size");
private[this] val MAX_DYNAMIC_TABLE_SIZE_CHANGE_REQUIRED =
new IOException("max dynamic table size change required");
private[this] val UNEXPECTED_DYNAMIC_TABLE_SIZE_UPDATE =
new IOException(
"Dynamic table size update must happen "
+ "at the beginning of the header block"
)

private[this] val EMPTY = Array.emptyByteArray;

Expand Down Expand Up @@ -103,6 +107,8 @@ private[http4s] final class Decoder(dynamicTable: DynamicTable) {
*/
@throws[IOException]
def decode(in: InputStream, headerListener: HeaderListener): Unit = {
var seenOnlyDynamicTableSizeUpdate = true

while (in.available() > 0) {
var b: Byte = 0
import State._
Expand All @@ -115,6 +121,7 @@ private[http4s] final class Decoder(dynamicTable: DynamicTable) {
}
if (b < 0) {
// Indexed Header Field
seenOnlyDynamicTableSizeUpdate = false
index = b & 0x7f;
if (index == 0) {
throw ILLEGAL_INDEX_VALUE;
Expand All @@ -125,6 +132,7 @@ private[http4s] final class Decoder(dynamicTable: DynamicTable) {
}
} else if ((b & 0x40) == 0x40) {
// Literal Header Field with Incremental Indexing
seenOnlyDynamicTableSizeUpdate = false
indexType = IndexType.INCREMENTAL;
index = b & 0x3f;
if (index == 0) {
Expand All @@ -138,15 +146,20 @@ private[http4s] final class Decoder(dynamicTable: DynamicTable) {
}
} else if ((b & 0x20) == 0x20) {
// Dynamic Table Size Update
index = b & 0x1f;
if (index == 0x1f) {
state = State.READ_MAX_DYNAMIC_TABLE_SIZE;
if (seenOnlyDynamicTableSizeUpdate) {
index = b & 0x1f;
if (index == 0x1f) {
state = State.READ_MAX_DYNAMIC_TABLE_SIZE;
} else {
setDynamicTableSize(index);
state = State.READ_HEADER_REPRESENTATION;
}
} else {
setDynamicTableSize(index);
state = State.READ_HEADER_REPRESENTATION;
throw UNEXPECTED_DYNAMIC_TABLE_SIZE_UPDATE
}
} else {
// Literal Header Field without Indexing / never Indexed
seenOnlyDynamicTableSizeUpdate = false
indexType = if ((b & 0x10) == 0x10) IndexType.NEVER else IndexType.NONE;
index = b & 0x0f;
if (index == 0) {
Expand Down
20 changes: 15 additions & 5 deletions hpack/shared/src/test/scala/org/http4s/hpack/DecoderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ package org.http4s.hpack

import cats.kernel.Eq
import cats.syntax.all._

import java.io.ByteArrayInputStream
import java.io.IOException
import org.junit.Before
import org.junit.Test
import org.http4s.hpack.HpackUtil.ISO_8859_1
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test

import java.io.ByteArrayInputStream
import java.io.IOException

object DecoderTest {
private val MAX_HEADER_SIZE = 8192
Expand Down Expand Up @@ -142,6 +142,16 @@ class DecoderTest {
decode("2081")
}

@Test(expected = classOf[IOException])
@throws[IOException]
def testDynamicTableSizeUpdateAfterTheBeginningOfTheBlock(): Unit =
decode("8120")

@Test(expected = classOf[IOException])
@throws[Exception]
def testDynamicTableSizeUpdateAfterTheBeginningOfTheBlockLong(): Unit =
decode("813FE11F")

@Test(expected = classOf[IOException])
@throws[Exception]
def testTooLargeDynamicTableSizeUpdate(): Unit = {
Expand Down
Loading