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
public abstract class HttpObjectDecoder extends ByteToMessageDecoder
DecodesByteBuf
s intoHttpMessage
s andHttpContent
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, aTooLongFrameException
will be raised.maxHeaderSize
8192 The maximum length of all headers. If the sum of the length of each header exceeds this value, a TooLongFrameException
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 ismaxChunkSize
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 totrue
, 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.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 oneHttpMessage
instance and its followingHttpContent
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]
triggersHttpRequestDecoder
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, insertHttpObjectAggregator
after this decoder in theChannelPipeline
. 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.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static class
HttpObjectDecoder.HeaderParser
private class
HttpObjectDecoder.LineParser
private static class
HttpObjectDecoder.State
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
Fields Modifier and Type Field Description private boolean
allowDuplicateContentLengths
private boolean
chunkedSupported
private long
chunkSize
private static java.util.regex.Pattern
COMMA_PATTERN
private long
contentLength
private HttpObjectDecoder.State
currentState
static boolean
DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS
static boolean
DEFAULT_CHUNKED_SUPPORTED
static int
DEFAULT_INITIAL_BUFFER_SIZE
static int
DEFAULT_MAX_CHUNK_SIZE
static int
DEFAULT_MAX_HEADER_SIZE
static int
DEFAULT_MAX_INITIAL_LINE_LENGTH
static boolean
DEFAULT_VALIDATE_HEADERS
private static java.lang.String
EMPTY_VALUE
private HttpObjectDecoder.HeaderParser
headerParser
private HttpObjectDecoder.LineParser
lineParser
private int
maxChunkSize
private HttpMessage
message
private java.lang.CharSequence
name
private boolean
resetRequested
private LastHttpContent
trailer
protected boolean
validateHeaders
private java.lang.CharSequence
value
-
Fields inherited from class io.netty.handler.codec.ByteToMessageDecoder
COMPOSITE_CUMULATOR, MERGE_CUMULATOR
-
-
Constructor Summary
Constructors Modifier Constructor Description protected
HttpObjectDecoder()
Creates a new instance with the defaultmaxInitialLineLength (4096
},maxHeaderSize (8192)
, andmaxChunkSize (8192)
.protected
HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported)
Creates a new instance with the specified parameters.protected
HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders)
Creates a new instance with the specified parameters.protected
HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize)
Creates a new instance with the specified parameters.protected
HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize, boolean allowDuplicateContentLengths)
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description private long
contentLength()
protected abstract HttpMessage
createInvalidMessage()
protected abstract HttpMessage
createMessage(java.lang.String[] initialLine)
protected void
decode(ChannelHandlerContext ctx, ByteBuf buffer, java.util.List<java.lang.Object> out)
Decode the from oneByteBuf
to an other.protected void
decodeLast(ChannelHandlerContext ctx, ByteBuf in, java.util.List<java.lang.Object> out)
Is called one last time when theChannelHandlerContext
goes in-active.private static int
findEndOfString(AppendableCharSequence sb)
private static int
findNonSPLenient(AppendableCharSequence sb, int offset)
private static int
findNonWhitespace(AppendableCharSequence sb, int offset, boolean validateOWS)
private static int
findSPLenient(AppendableCharSequence sb, int offset)
private static int
getChunkSize(java.lang.String hex)
protected void
handleTransferEncodingChunkedWithContentLength(HttpMessage message)
Invoked when a message with both a "Transfer-Encoding: chunked" and a "Content-Length" header field is detected.private HttpContent
invalidChunk(ByteBuf in, java.lang.Exception cause)
private HttpMessage
invalidMessage(ByteBuf in, java.lang.Exception cause)
protected boolean
isContentAlwaysEmpty(HttpMessage msg)
protected abstract boolean
isDecodingRequest()
private static boolean
isOWS(char ch)
private static boolean
isSPLenient(char c)
protected boolean
isSwitchingToNonHttp1Protocol(HttpResponse msg)
Returns true if the server switched to a different protocol than HTTP/1.0 or HTTP/1.1, e.g.private 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 void
splitHeader(AppendableCharSequence sb)
private static java.lang.String[]
splitInitialLine(AppendableCharSequence sb)
void
userEventTriggered(ChannelHandlerContext ctx, java.lang.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, handlerRemoved0, 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 Detail
-
DEFAULT_MAX_INITIAL_LINE_LENGTH
public static final int DEFAULT_MAX_INITIAL_LINE_LENGTH
- See Also:
- Constant Field Values
-
DEFAULT_MAX_HEADER_SIZE
public static final int DEFAULT_MAX_HEADER_SIZE
- See Also:
- Constant Field Values
-
DEFAULT_CHUNKED_SUPPORTED
public static final boolean DEFAULT_CHUNKED_SUPPORTED
- See Also:
- Constant Field Values
-
DEFAULT_MAX_CHUNK_SIZE
public static final int DEFAULT_MAX_CHUNK_SIZE
- See Also:
- Constant Field Values
-
DEFAULT_VALIDATE_HEADERS
public static final boolean DEFAULT_VALIDATE_HEADERS
- See Also:
- Constant Field Values
-
DEFAULT_INITIAL_BUFFER_SIZE
public static final int DEFAULT_INITIAL_BUFFER_SIZE
- See Also:
- Constant Field Values
-
DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS
public static final boolean DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS
- See Also:
- Constant Field Values
-
EMPTY_VALUE
private static final java.lang.String EMPTY_VALUE
- See Also:
- Constant Field Values
-
COMMA_PATTERN
private static final java.util.regex.Pattern COMMA_PATTERN
-
maxChunkSize
private final int maxChunkSize
-
chunkedSupported
private final boolean chunkedSupported
-
validateHeaders
protected final boolean validateHeaders
-
allowDuplicateContentLengths
private final boolean allowDuplicateContentLengths
-
headerParser
private final HttpObjectDecoder.HeaderParser headerParser
-
lineParser
private final HttpObjectDecoder.LineParser lineParser
-
message
private HttpMessage message
-
chunkSize
private long chunkSize
-
contentLength
private long contentLength
-
resetRequested
private volatile boolean resetRequested
-
name
private java.lang.CharSequence name
-
value
private java.lang.CharSequence value
-
trailer
private LastHttpContent trailer
-
currentState
private HttpObjectDecoder.State currentState
-
-
Constructor Detail
-
HttpObjectDecoder
protected HttpObjectDecoder()
Creates a new instance with the defaultmaxInitialLineLength (4096
},maxHeaderSize (8192)
, andmaxChunkSize (8192)
.
-
HttpObjectDecoder
protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported)
Creates a new instance with the specified parameters.
-
HttpObjectDecoder
protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders)
Creates a new instance with the specified parameters.
-
HttpObjectDecoder
protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize)
Creates a new instance with the specified parameters.
-
HttpObjectDecoder
protected HttpObjectDecoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean chunkedSupported, boolean validateHeaders, int initialBufferSize, boolean allowDuplicateContentLengths)
-
-
Method Detail
-
decode
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, java.util.List<java.lang.Object> out) throws java.lang.Exception
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:
java.lang.Exception
- is thrown if an error occurs
-
decodeLast
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, java.util.List<java.lang.Object> out) throws java.lang.Exception
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:
java.lang.Exception
-
userEventTriggered
public void userEventTriggered(ChannelHandlerContext ctx, java.lang.Object evt) throws java.lang.Exception
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:
java.lang.Exception
-
isContentAlwaysEmpty
protected boolean isContentAlwaysEmpty(HttpMessage msg)
-
isSwitchingToNonHttp1Protocol
protected boolean isSwitchingToNonHttp1Protocol(HttpResponse msg)
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
private HttpMessage invalidMessage(ByteBuf in, java.lang.Exception cause)
-
invalidChunk
private HttpContent invalidChunk(ByteBuf in, java.lang.Exception cause)
-
readHeaders
private HttpObjectDecoder.State readHeaders(ByteBuf buffer)
-
handleTransferEncodingChunkedWithContentLength
protected void handleTransferEncodingChunkedWithContentLength(HttpMessage message)
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
-
contentLength
private long contentLength()
-
readTrailingHeaders
private LastHttpContent readTrailingHeaders(ByteBuf buffer)
-
isDecodingRequest
protected abstract boolean isDecodingRequest()
-
createMessage
protected abstract HttpMessage createMessage(java.lang.String[] initialLine) throws java.lang.Exception
- Throws:
java.lang.Exception
-
createInvalidMessage
protected abstract HttpMessage createInvalidMessage()
-
getChunkSize
private static int getChunkSize(java.lang.String hex)
-
splitInitialLine
private static java.lang.String[] splitInitialLine(AppendableCharSequence sb)
-
splitHeader
private void splitHeader(AppendableCharSequence sb)
-
findNonSPLenient
private static int findNonSPLenient(AppendableCharSequence sb, int offset)
-
findSPLenient
private static int findSPLenient(AppendableCharSequence sb, int offset)
-
isSPLenient
private static boolean isSPLenient(char c)
-
findNonWhitespace
private static int findNonWhitespace(AppendableCharSequence sb, int offset, boolean validateOWS)
-
findEndOfString
private static int findEndOfString(AppendableCharSequence sb)
-
isOWS
private static boolean isOWS(char ch)
-
-