netty5/codec-http/src/main/java/io/netty/handler/codec/http
Ngoc Dao 2b4f667791 Fix DefaultHttpDataFactory cleanup bug
Motivation:

DefaultHttpDataFactory uses HttpRequest as map keys.

Because of the implementation of "hashCode"" and "equals" in DefaultHttpRequest,
if we use normal maps, HttpDatas of different requests may end up in the same map entry,
causing cleanup bug.

Consider this example:
- Suppose that request1 is equal to request2, causing their HttpDatas to be stored in one single map entry.
- request1 is cleaned up first, while request2 is still being decoded.
- Consequently request2's HttpDatas are suddenly gone, causing NPE, or worse loss of data.

This bug can be reproduced by starting the HttpUploadServer example,
then run this command:
ab -T 'application/x-www-form-urlencoded' -n 100 -c 5 -p post.txt http://localhost:8080/form

post.txt file content:
a=1&b=2

There will be errors like this:
java.lang.NullPointerException
        at io.netty.handler.codec.http.multipart.MemoryAttribute.getValue(MemoryAttribute.java:64)
        at io.netty.handler.codec.http.multipart.MixedAttribute.getValue(MixedAttribute.java:243)
        at io.netty.example.http.upload.HttpUploadServerHandler.writeHttpData(HttpUploadServerHandler.java:271)
        at io.netty.example.http.upload.HttpUploadServerHandler.readHttpDataChunkByChunk(HttpUploadServerHandler.java:230)
        at io.netty.example.http.upload.HttpUploadServerHandler.channelRead0(HttpUploadServerHandler.java:193)
        at io.netty.example.http.upload.HttpUploadServerHandler.channelRead0(HttpUploadServerHandler.java:66)
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
        at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1412)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:943)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:141)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)

Modifications:

Keep identity of requests by using IdentityHashMap

Result:

DefaultHttpDataFactory is fixed.

The ConcurrentHashMap is replaced with a synchronized map, but I think the performance won't be affected much in real web apps.
2017-12-28 07:40:17 +01:00
..
cookie Fix ServerCookieEncoder javadoc, close #7115 2017-08-28 20:21:57 +02:00
cors Fixing CorsHandler response Content-Length 2017-10-02 08:20:15 +02:00
multipart Fix DefaultHttpDataFactory cleanup bug 2017-12-28 07:40:17 +01:00
websocketx Correct filling an origin header for WS client 2017-10-23 11:38:34 +02:00
ClientCookieEncoder.java Fix javadoc issues 2017-02-22 07:31:07 +01:00
CombinedHttpHeaders.java HttpHeaders valuesIterator and contains improvements 2017-11-20 08:34:06 -08:00
ComposedLastHttpContent.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
Cookie.java Deprecation cleanup for HTTP headers 2015-09-09 14:30:21 -07:00
CookieDecoder.java Clean up following #6016 2016-11-21 12:35:40 -08:00
CookieUtil.java Validate cookie name and value characters Motivation: 2015-05-07 06:33:36 +02:00
DefaultCookie.java Validate cookie name and value characters Motivation: 2015-05-07 06:33:36 +02:00
DefaultFullHttpRequest.java Only enable validation of headers if original headers were validating as well. 2017-12-21 07:32:29 +01:00
DefaultFullHttpResponse.java Only enable validation of headers if original headers were validating as well. 2017-12-21 07:32:29 +01:00
DefaultHttpContent.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
DefaultHttpHeaders.java Only enable validation of headers if original headers were validating as well. 2017-12-21 07:32:29 +01:00
DefaultHttpMessage.java Add a possibility to create HttpMessage instances with pre-existing Headers 2015-12-31 08:52:30 +01:00
DefaultHttpObject.java Back port HTTP/2 codec from master to 4.1 2015-01-23 11:06:11 -05:00
DefaultHttpRequest.java Add a possibility to create HttpMessage instances with pre-existing Headers 2015-12-31 08:52:30 +01:00
DefaultHttpResponse.java Add a possibility to create HttpMessage instances with pre-existing Headers 2015-12-31 08:52:30 +01:00
DefaultLastHttpContent.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
EmptyHttpHeaders.java Move EmptyHttpHeaders.INSTANCE initialization to inner class. 2017-11-17 16:31:09 +01:00
FullHttpMessage.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
FullHttpRequest.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
FullHttpResponse.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
HttpChunkedInput.java Fix possible NPE in HttpCunkedInput if wrapped ChunkedInput.readChunk(...) return null. 2016-06-17 06:27:04 +02:00
HttpClientCodec.java Correctly handle WebSockets 00 when using HttpClientCodec. 2017-11-03 15:55:22 +01:00
HttpClientUpgradeHandler.java codec-http: HttpClientUpgradeHandler can handle streamed responses 2016-11-01 06:32:41 +01:00
HttpConstants.java [#4010] Correctly handle whitespaces in HttpPostMultipartRequestDecoder 2015-08-14 21:16:42 +02:00
HttpContent.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
HttpContentCompressor.java Netty force encodes already encoded responses 2017-05-27 08:26:14 +02:00
HttpContentDecoder.java Correctly propagate channelInactive even if cleanup throws 2017-11-21 11:55:39 +01:00
HttpContentDecompressor.java Ensure the same ByteBufAllocator is used in the EmbeddedChannel when compress / decompress. Related to [#5294] 2016-05-31 09:08:33 +02:00
HttpContentEncoder.java Correctly propagate channelInactive even if cleanup throws 2017-11-21 11:55:39 +01:00
HttpExpectationFailedEvent.java HttpObjectAggregator doesn't check content-length header 2015-08-17 09:26:50 -07:00
HttpHeaderDateFormat.java Clean up following #6016 2016-11-21 12:35:40 -08:00
HttpHeaderNames.java Immediate caching the strings wrapped to AsciiString 2017-08-15 06:22:14 +02:00
HttpHeaders.java Only enable validation of headers if original headers were validating as well. 2017-12-21 07:32:29 +01:00
HttpHeadersEncoder.java Use ByteBuf#writeShort/writeMedium instead of writeBytes 2017-07-10 14:37:41 +02:00
HttpHeaderValues.java Immediate caching the strings wrapped to AsciiString 2017-08-15 06:22:14 +02:00
HttpMessage.java Remove 'get' prefix from all HTTP/SPDY messages 2014-06-24 18:03:33 +09:00
HttpMessageUtil.java Implement toString() for all HttpMessage implementations 2014-12-31 18:39:00 +09:00
HttpMethod.java HttpMethod#valueOf improvement 2017-11-20 11:07:50 -08:00
HttpObject.java Introduce MessageAggregator and DecoderResultProvider 2014-06-05 16:51:14 +09:00
HttpObjectAggregator.java Only enable validation of headers if original headers were validating as well. 2017-12-21 07:32:29 +01:00
HttpObjectDecoder.java Correctly handle 205 Reset Content response with transfer-encoding 2017-11-14 08:02:09 +01:00
HttpObjectEncoder.java Correctly convert empty HttpContent to ByteBuf 2017-11-08 13:46:32 -08:00
HttpRequest.java Fix errors reported by javadoc 2015-12-27 08:36:45 +01:00
HttpRequestDecoder.java HttpObjectDecoder configurable initial buffer size 2016-02-07 21:23:29 -08:00
HttpRequestEncoder.java Only add / to uri if really needed. 2017-07-18 09:24:19 +02:00
HttpResponse.java Fix errors reported by javadoc 2015-12-27 08:36:45 +01:00
HttpResponseDecoder.java HttpObjectDecoder configurable initial buffer size 2016-02-07 21:23:29 -08:00
HttpResponseEncoder.java Correctly not write any body when 1xx, 204 or 304 is used as response status code. 2017-09-20 07:41:13 -07:00
HttpResponseStatus.java Apply appropriate methods for writing CharSequence into ByteBuf 2017-06-27 07:58:39 +02:00
HttpScheme.java Immediate caching the strings wrapped to AsciiString 2017-08-15 06:22:14 +02:00
HttpServerCodec.java Correctly not write any body when 1xx, 204 or 304 is used as response status code. 2017-09-20 07:41:13 -07:00
HttpServerExpectContinueHandler.java Motivation: 2017-04-27 16:20:29 -07:00
HttpServerKeepAliveHandler.java HttpServerKeepAliveHandler doesn't correctly handle VoidChannelPromise 2017-05-04 14:08:18 -07:00
HttpServerUpgradeHandler.java Do not send Content-Length: 0 on 101 responses. 2017-10-21 14:36:19 +02:00
HttpStatusClass.java Immediate caching the strings wrapped to AsciiString 2017-08-15 06:22:14 +02:00
HttpUtil.java Move EmptyHttpHeaders.INSTANCE initialization to inner class. 2017-11-17 16:31:09 +01:00
HttpVersion.java Apply appropriate methods for writing CharSequence into ByteBuf 2017-06-27 07:58:39 +02:00
LastHttpContent.java Make retained derived buffers recyclable 2016-05-17 11:16:13 +02:00
package-info.java Remove apiviz tags - we are focusing on user guide instead and putting diagrams there 2013-02-14 12:09:16 -08:00
QueryStringDecoder.java Added QueryStringDecoder.rawPath() and rawQuery() 2017-10-24 09:32:06 +02:00
QueryStringEncoder.java Optimizations in QueryStringEncoder 2017-06-23 14:03:32 -07:00
ReadOnlyHttpHeaders.java HttpHeaders valuesIterator and contains improvements 2017-11-20 08:34:06 -08:00
ServerCookieEncoder.java Fix ServerCookieEncoder javadoc, close #7115 2017-08-28 20:21:57 +02:00