Package io.netty.handler.codec.http
Class HttpObjectDecoder
java.lang.Object
io.netty.channel.ChannelHandlerAdapter
io.netty.channel.ChannelInboundHandlerAdapter
io.netty.handler.codec.ByteToMessageDecoder
io.netty.handler.codec.http.HttpObjectDecoder
- All Implemented Interfaces:
ChannelHandler
,ChannelInboundHandler
- Direct Known Subclasses:
HttpRequestDecoder
,HttpResponseDecoder
,RtspDecoder
,RtspObjectDecoder
Decodes
ByteBuf
s into HttpMessage
s and
HttpContent
s.
Parameters that prevents excessive memory consumption
Name | Default value | Meaning |
---|---|---|
maxInitialLineLength |
4096 | The maximum length of the initial line
(e.g. "GET / HTTP/1.0" or "HTTP/1.0 200 OK" )
If the length of the initial line exceeds this value, a
TooLongHttpLineException will be raised. |
maxHeaderSize |
8192 | The maximum length of all headers. If the sum of the length of each
header exceeds this value, a TooLongHttpHeaderException will be raised. |
maxChunkSize |
8192 | The maximum length of the content or each chunk. If the content length
(or the length of each chunk) exceeds this value, the content or chunk
will be split into multiple HttpContent s whose length is
maxChunkSize at maximum. |
Parameters that control parsing behavior
Name | Default value | Meaning |
---|---|---|
allowDuplicateContentLengths |
false | When set to false , will reject any messages that contain multiple Content-Length header fields.
When set to true , will allow multiple Content-Length headers only if they are all the same decimal value.
The duplicated field-values will be replaced with a single valid Content-Length field.
See RFC 7230, Section 3.3.2. |
allowPartialChunks |
true | If the length of a chunk exceeds the ByteBuf s readable bytes and allowPartialChunks
is set to true , the chunk will be split into multiple HttpContent s.
Otherwise, if the chunk size does not exceed maxChunkSize and allowPartialChunks
is set to false , the ByteBuf is not decoded into an HttpContent until
the readable bytes are greater or equal to the chunk size. |
Chunked Content
If the content of an HTTP message is greater thanmaxChunkSize
or
the transfer encoding of the HTTP message is 'chunked', this decoder
generates one HttpMessage
instance and its following
HttpContent
s per single HTTP message to avoid excessive memory
consumption. For example, the following HTTP message:
GET / HTTP/1.1 Transfer-Encoding: chunked 1a abcdefghijklmnopqrstuvwxyz 10 1234567890abcdef 0 Content-MD5: ... [blank line]triggers
HttpRequestDecoder
to generate 3 objects:
- An
HttpRequest
, - The first
HttpContent
whose content is'abcdefghijklmnopqrstuvwxyz'
, - The second
LastHttpContent
whose content is'1234567890abcdef'
, which marks the end of the content.
HttpContent
s by yourself for your
convenience, insert HttpObjectAggregator
after this decoder in the
ChannelPipeline
. However, please note that your server might not
be as memory efficient as without the aggregator.
Extensibility
Please note that this decoder is designed to be extended to implement a protocol derived from HTTP, such as RTSP and ICAP. To implement the decoder of such a derived protocol, extend this class and implement all abstract methods properly.Header Validation
It is recommended to always enable header validation.Without header validation, your system can become vulnerable to CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting') .
This recommendation stands even when both peers in the HTTP exchange are trusted, as it helps with defence-in-depth.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static class
private final class
private static enum
The internal state ofHttpObjectDecoder
.Nested classes/interfaces inherited from class io.netty.handler.codec.ByteToMessageDecoder
ByteToMessageDecoder.Cumulator
Nested classes/interfaces inherited from interface io.netty.channel.ChannelHandler
ChannelHandler.Sharable
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final boolean
private final boolean
private boolean
private final boolean
private long
private long
private HttpObjectDecoder.State
static final boolean
static final boolean
static final boolean
static final int
static final int
static final int
static final int
static final boolean
private final HttpObjectDecoder.HeaderParser
protected final HttpHeadersFactory
private static final boolean[]
private boolean
private static final boolean[]
private final HttpObjectDecoder.LineParser
private final int
private HttpMessage
private AsciiString
private final ByteBuf
private final AtomicBoolean
private static final ByteProcessor
private static final boolean[]
private LastHttpContent
protected final HttpHeadersFactory
protected final boolean
Deprecated.private String
Fields inherited from class io.netty.handler.codec.ByteToMessageDecoder
COMPOSITE_CUMULATOR, MERGE_CUMULATOR
-
Constructor Summary
ConstructorsModifierConstructorDescriptionprotected
Creates a new instance with the defaultmaxInitialLineLength (4096)
,maxHeaderSize (8192)
, andmaxChunkSize (8192)
.protected
HttpObjectDecoder
(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported) Deprecated.protected
HttpObjectDecoder
(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.protected
HttpObjectDecoder
(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.protected
HttpObjectDecoder
(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize, boolean allowDuplicateContentLengths) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.protected
HttpObjectDecoder
(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize, boolean allowDuplicateContentLengths, boolean allowPartialChunks) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.protected
HttpObjectDecoder
(HttpDecoderConfig config) Creates a new instance with the specified configuration. -
Method Summary
Modifier and TypeMethodDescriptionprivate void
addCurrentMessage
(List<Object> out) protected abstract HttpMessage
protected abstract HttpMessage
createMessage
(String[] initialLine) protected void
decode
(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) Decode the from oneByteBuf
to an other.protected void
decodeLast
(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) Is called one last time when theChannelHandlerContext
goes in-active.private static int
findEndOfString
(byte[] sb, int start, int end) private static int
findNonSPLenient
(byte[] sb, int offset, int end) private static int
findNonWhitespace
(byte[] sb, int offset, int end) private static int
findSPLenient
(byte[] sb, int offset, int end) private static int
getChunkSize
(byte[] hex, int start, int length) protected void
Gets called after theByteToMessageDecoder
was removed from the actual context and it doesn't handle events anymore.protected void
Invoked when a message with both a "Transfer-Encoding: chunked" and a "Content-Length" header field is detected.private HttpContent
invalidChunk
(ByteBuf in, Exception cause) private HttpMessage
invalidMessage
(HttpMessage current, ByteBuf in, Exception cause) protected boolean
private static boolean
isControlOrWhitespaceAsciiChar
(byte b) protected abstract boolean
private static boolean
isOWS
(byte ch) private static boolean
isSPLenient
(byte c) protected boolean
Returns true if the server switched to a different protocol than HTTP/1.0 or HTTP/1.1, e.g.protected boolean
isValidating
(HttpHeadersFactory headersFactory) private static boolean
isWhitespace
(byte b) private static String
langAsciiString
(byte[] asciiContent, int start, int length) This method shouldn't exist: look at https://bugs.openjdk.org/browse/JDK-8295496 for more contextprivate HttpObjectDecoder.State
readHeaders
(ByteBuf buffer) private LastHttpContent
readTrailingHeaders
(ByteBuf buffer) void
reset()
Resets the state of the decoder so that it is ready to decode a new message.private void
resetNow()
private static int
skipWhiteSpaces
(byte[] hex, int start, int length) It skips any whitespace char and return the number of skipped bytes.protected String
splitFirstWordInitialLine
(byte[] asciiContent, int start, int length) private void
splitHeader
(byte[] line, int start, int length) protected AsciiString
splitHeaderName
(byte[] sb, int start, int length) private String[]
splitInitialLine
(ByteBuf asciiBuffer) protected String
splitSecondWordInitialLine
(byte[] asciiContent, int start, int length) protected String
splitThirdWordInitialLine
(byte[] asciiContent, int start, int length) void
userEventTriggered
(ChannelHandlerContext ctx, Object evt) CallsChannelHandlerContext.fireUserEventTriggered(Object)
to forward to the nextChannelInboundHandler
in theChannelPipeline
.Methods inherited from class io.netty.handler.codec.ByteToMessageDecoder
actualReadableBytes, callDecode, channelInactive, channelRead, channelReadComplete, discardSomeReadBytes, handlerRemoved, internalBuffer, isSingleDecode, setCumulator, setDiscardAfterReads, setSingleDecode
Methods inherited from class io.netty.channel.ChannelInboundHandlerAdapter
channelActive, channelRegistered, channelUnregistered, channelWritabilityChanged, exceptionCaught
Methods inherited from class io.netty.channel.ChannelHandlerAdapter
ensureNotSharable, handlerAdded, isSharable
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Methods inherited from interface io.netty.channel.ChannelHandler
handlerAdded
-
Field Details
-
DEFAULT_MAX_INITIAL_LINE_LENGTH
public static final int DEFAULT_MAX_INITIAL_LINE_LENGTH- See Also:
-
DEFAULT_MAX_HEADER_SIZE
public static final int DEFAULT_MAX_HEADER_SIZE- See Also:
-
DEFAULT_CHUNKED_SUPPORTED
public static final boolean DEFAULT_CHUNKED_SUPPORTED- See Also:
-
DEFAULT_ALLOW_PARTIAL_CHUNKS
public static final boolean DEFAULT_ALLOW_PARTIAL_CHUNKS- See Also:
-
DEFAULT_MAX_CHUNK_SIZE
public static final int DEFAULT_MAX_CHUNK_SIZE- See Also:
-
DEFAULT_VALIDATE_HEADERS
public static final boolean DEFAULT_VALIDATE_HEADERS- See Also:
-
DEFAULT_INITIAL_BUFFER_SIZE
public static final int DEFAULT_INITIAL_BUFFER_SIZE- See Also:
-
DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS
public static final boolean DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS- See Also:
-
maxChunkSize
private final int maxChunkSize -
chunkedSupported
private final boolean chunkedSupported -
allowPartialChunks
private final boolean allowPartialChunks -
validateHeaders
Deprecated.This field is no longer used. It is only kept around for backwards compatibility purpose. -
headersFactory
-
trailersFactory
-
allowDuplicateContentLengths
private final boolean allowDuplicateContentLengths -
parserScratchBuffer
-
headerParser
-
lineParser
-
message
-
chunkSize
private long chunkSize -
contentLength
private long contentLength -
chunked
private boolean chunked -
isSwitchingToNonHttp1Protocol
private boolean isSwitchingToNonHttp1Protocol -
resetRequested
-
name
-
value
-
trailer
-
currentState
-
SP_LENIENT_BYTES
private static final boolean[] SP_LENIENT_BYTES -
LATIN_WHITESPACE
private static final boolean[] LATIN_WHITESPACE -
ISO_CONTROL_OR_WHITESPACE
private static final boolean[] ISO_CONTROL_OR_WHITESPACE -
SKIP_CONTROL_CHARS_BYTES
-
-
Constructor Details
-
HttpObjectDecoder
protected HttpObjectDecoder()Creates a new instance with the defaultmaxInitialLineLength (4096)
,maxHeaderSize (8192)
, andmaxChunkSize (8192)
. -
HttpObjectDecoder
@Deprecated protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.Creates a new instance with the specified parameters. -
HttpObjectDecoder
@Deprecated protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.Creates a new instance with the specified parameters. -
HttpObjectDecoder
@Deprecated protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.Creates a new instance with the specified parameters. -
HttpObjectDecoder
@Deprecated protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize, boolean allowDuplicateContentLengths) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.Creates a new instance with the specified parameters. -
HttpObjectDecoder
@Deprecated protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize, boolean allowDuplicateContentLengths, boolean allowPartialChunks) Deprecated.UseHttpObjectDecoder(HttpDecoderConfig)
instead.Creates a new instance with the specified parameters. -
HttpObjectDecoder
Creates a new instance with the specified configuration.
-
-
Method Details
-
handlerRemoved0
Description copied from class:ByteToMessageDecoder
Gets called after theByteToMessageDecoder
was removed from the actual context and it doesn't handle events anymore.- Overrides:
handlerRemoved0
in classByteToMessageDecoder
- Throws:
Exception
-
isValidating
-
decode
Description copied from class:ByteToMessageDecoder
Decode the from oneByteBuf
to an other. This method will be called till either the inputByteBuf
has nothing to read when return from this method or till nothing was read from the inputByteBuf
.- Specified by:
decode
in classByteToMessageDecoder
- Parameters:
ctx
- theChannelHandlerContext
which thisByteToMessageDecoder
belongs tobuffer
- theByteBuf
from which to read dataout
- theList
to which decoded messages should be added- Throws:
Exception
- is thrown if an error occurs
-
decodeLast
Description copied from class:ByteToMessageDecoder
Is called one last time when theChannelHandlerContext
goes in-active. Which means theByteToMessageDecoder.channelInactive(ChannelHandlerContext)
was triggered. By default, this will just callByteToMessageDecoder.decode(ChannelHandlerContext, ByteBuf, List)
but sub-classes may override this for some special cleanup operation.- Overrides:
decodeLast
in classByteToMessageDecoder
- Throws:
Exception
-
userEventTriggered
Description copied from class:ChannelInboundHandlerAdapter
CallsChannelHandlerContext.fireUserEventTriggered(Object)
to forward to the nextChannelInboundHandler
in theChannelPipeline
. Sub-classes may override this method to change behavior.- Specified by:
userEventTriggered
in interfaceChannelInboundHandler
- Overrides:
userEventTriggered
in classByteToMessageDecoder
- Throws:
Exception
-
addCurrentMessage
-
isContentAlwaysEmpty
-
isSwitchingToNonHttp1Protocol
Returns true if the server switched to a different protocol than HTTP/1.0 or HTTP/1.1, e.g. HTTP/2 or Websocket. Returns false if the upgrade happened in a different layer, e.g. upgrade from HTTP/1.1 to HTTP/1.1 over TLS. -
reset
public void reset()Resets the state of the decoder so that it is ready to decode a new message. This method is useful for handling a rejected request withExpect: 100-continue
header. -
resetNow
private void resetNow() -
invalidMessage
-
invalidChunk
-
readHeaders
-
handleTransferEncodingChunkedWithContentLength
Invoked when a message with both a "Transfer-Encoding: chunked" and a "Content-Length" header field is detected. The default behavior is to remove the Content-Length field, but this method could be overridden to change the behavior (to, e.g., throw an exception and produce an invalid message).See: https://tools.ietf.org/html/rfc7230#section-3.3.3
If a message is received with both a Transfer-Encoding and a Content-Length header field, the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt to perform request smuggling (Section 9.5) or response splitting (Section 9.4) and ought to be handled as an error. A sender MUST remove the received Content-Length field prior to forwarding such a message downstream.
Also see: https://github.com/apache/tomcat/blob/b693d7c1981fa7f51e58bc8c8e72e3fe80b7b773/ java/org/apache/coyote/http11/Http11Processor.java#L747-L755 https://github.com/nginx/nginx/blob/0ad4393e30c119d250415cb769e3d8bc8dce5186/ src/http/ngx_http_request.c#L1946-L1953 -
readTrailingHeaders
-
isDecodingRequest
protected abstract boolean isDecodingRequest() -
createMessage
- Throws:
Exception
-
createInvalidMessage
-
skipWhiteSpaces
private static int skipWhiteSpaces(byte[] hex, int start, int length) It skips any whitespace char and return the number of skipped bytes. -
getChunkSize
private static int getChunkSize(byte[] hex, int start, int length) -
splitInitialLine
-
splitFirstWordInitialLine
-
splitSecondWordInitialLine
-
splitThirdWordInitialLine
-
langAsciiString
This method shouldn't exist: look at https://bugs.openjdk.org/browse/JDK-8295496 for more context -
splitHeader
private void splitHeader(byte[] line, int start, int length) -
splitHeaderName
-
findNonSPLenient
private static int findNonSPLenient(byte[] sb, int offset, int end) -
findSPLenient
private static int findSPLenient(byte[] sb, int offset, int end) -
isSPLenient
private static boolean isSPLenient(byte c) -
isWhitespace
private static boolean isWhitespace(byte b) -
findNonWhitespace
private static int findNonWhitespace(byte[] sb, int offset, int end) -
findEndOfString
private static int findEndOfString(byte[] sb, int start, int end) -
isOWS
private static boolean isOWS(byte ch) -
isControlOrWhitespaceAsciiChar
private static boolean isControlOrWhitespaceAsciiChar(byte b)
-
HttpObjectDecoder(HttpDecoderConfig)
instead.