-
Notifications
You must be signed in to change notification settings - Fork 39
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
Parse entire HTTP chunk size #396 #528
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -307,17 +307,20 @@ private[http] trait HttpMessageParser[Output >: MessageOutput <: ParserOutput] { | |
s"HTTP chunk extension length exceeds configured limit of ${settings.maxChunkExtLength} characters") | ||
|
||
@tailrec def parseSize(cursor: Int, size: Long): StateResult = | ||
if (size <= settings.maxChunkSize) { | ||
if (size <= Int.MaxValue) { | ||
byteChar(input, cursor) match { | ||
case c if CharacterClasses.HEXDIG(c) => parseSize(cursor + 1, size * 16 + CharUtils.hexValue(c)) | ||
case ';' if cursor > offset => parseChunkExtensions(size.toInt, cursor + 1)() | ||
case c if size > settings.maxChunkSize => | ||
failEntityStream( | ||
s"HTTP chunk of $size bytes exceeds the configured limit of ${settings.maxChunkSize} bytes") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see now, It was try decoding how big the chunk size is, and it will stop parsing how if the size already exceed MaxValue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about |
||
case ';' if cursor > offset => parseChunkExtensions(size.toInt, cursor + 1)() | ||
case '\r' if cursor > offset && byteChar(input, cursor + 1) == '\n' => | ||
parseChunkBody(size.toInt, "", cursor + 2) | ||
case '\n' if cursor > offset => parseChunkBody(size.toInt, "", cursor + 1) | ||
case c if CharacterClasses.WSP(c) => parseSize(cursor + 1, size) // illegal according to the spec but can happen, see issue #1812 | ||
case c => failEntityStream(s"Illegal character '${escape(c)}' in chunk start") | ||
} | ||
} else failEntityStream(s"HTTP chunk size exceeds the configured limit of ${settings.maxChunkSize} bytes") | ||
} else failEntityStream(s"HTTP chunk size exceeds Integer.MAX_VALUE (${Int.MaxValue}) bytes") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this does not start parsing the actual chunk body. It only reads the size value that's written in the chunk header and bails if that's larger than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did another around of check locally,it's ok. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In netty, when oversize, it invoke a protect method |
||
|
||
try parseSize(offset, 0) | ||
catch { | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -531,13 +531,24 @@ abstract class RequestParserSpec(mode: String, newLine: String) extends AnyFreeS | |||||||
closeAfterResponseCompletion shouldEqual Seq(false) | ||||||||
} | ||||||||
|
||||||||
"too-large chunk size" in new Test { | ||||||||
"too-large chunk size (> Int.MaxValue)" in new Test { | ||||||||
Seq( | ||||||||
start, | ||||||||
"""1a2b3c4d5e | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "1a2b3c4d5e" |
||||||||
|""") should generalMultiParseTo( | ||||||||
Right(baseRequest), | ||||||||
Left(EntityStreamError(ErrorInfo("HTTP chunk size exceeds the configured limit of 1048576 bytes")))) | ||||||||
Left(EntityStreamError(ErrorInfo("HTTP chunk size exceeds Integer.MAX_VALUE (2147483647) bytes")))) | ||||||||
closeAfterResponseCompletion shouldEqual Seq(false) | ||||||||
} | ||||||||
|
||||||||
"too-large chunk size" in new Test { | ||||||||
Seq( | ||||||||
start, | ||||||||
"""400000 | ||||||||
|""") should generalMultiParseTo( | ||||||||
Comment on lines
+547
to
+548
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found that the trailing newline is significant in this and many other tests in the file. |
||||||||
Right(baseRequest), | ||||||||
Left( | ||||||||
EntityStreamError(ErrorInfo("HTTP chunk of 4194304 bytes exceeds the configured limit of 1048576 bytes")))) | ||||||||
closeAfterResponseCompletion shouldEqual Seq(false) | ||||||||
} | ||||||||
|
||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My personal preference (it feels more clear) would be to have:
But I don't feel is binding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
guard clauses. 👍🏻
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to keep the structure consistent with the rest of the file. I also think the above suggestion would be incorrect in the sense that
everything else
would still be executed after callingfailEntityStream
? An else block would still be required.