Skip to content
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

NullPointerException in ProxyUtils.isHead #303

Closed
caseyoneill opened this issue Jun 14, 2016 · 7 comments
Closed

NullPointerException in ProxyUtils.isHead #303

caseyoneill opened this issue Jun 14, 2016 · 7 comments

Comments

@caseyoneill
Copy link

caseyoneill commented Jun 14, 2016

I don't have many details on how to reproduce this as it occurs very rarely but I do see this show up in the server logs every few days. What I can share is that I am configuring LittleProxy with HttpFiltersSourceAdapter, ActivityTracker, and MitmManager.

java.lang.NullPointerException: null
    at org.littleshoot.proxy.impl.ProxyUtils.isHead(ProxyUtils.java:396)
    at org.littleshoot.proxy.impl.ClientToProxyConnection.respond(ClientToProxyConnection.java:430)
    at org.littleshoot.proxy.impl.ProxyToServerConnection.respondWith(ProxyToServerConnection.java:534)
    at org.littleshoot.proxy.impl.ProxyToServerConnection.readHTTPInitial(ProxyToServerConnection.java:227)
    at org.littleshoot.proxy.impl.ProxyToServerConnection.readHTTPInitial(ProxyToServerConnection.java:73)
    at org.littleshoot.proxy.impl.ProxyConnection.readHTTP(ProxyConnection.java:135)
    at org.littleshoot.proxy.impl.ProxyConnection.read(ProxyConnection.java:120)
    at org.littleshoot.proxy.impl.ProxyToServerConnection.read(ProxyToServerConnection.java:216)
    at org.littleshoot.proxy.impl.ProxyConnection.channelRead0(ProxyConnection.java:587)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    at org.littleshoot.proxy.impl.ProxyConnection$ResponseReadMonitor.channelRead(ProxyConnection.java:738)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:277)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:264)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    at org.littleshoot.proxy.impl.ProxyConnection$BytesReadMonitor.channelRead(ProxyConnection.java:692)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:962)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
    at java.lang.Thread.run(Thread.java:745)
@jekh
Copy link
Collaborator

jekh commented Jun 18, 2016

This is very strange, indeed. Which version of LP are you using? In the current version, the only thing that could cause an NPE at ProxyUtils.java:396 is if the currentHttpRequest from the ProxyToServerConnection were null. That should not happen, but the code seems to anticipate such an unusual scenario in identifyCurrentRequest(). Have you seen a message like the one below earlier in the logs? It would be at the WARN level.

Got null HTTP request object.

@MediumOne
Copy link
Contributor

This has been reported before as well. There is a discussion on this here -
#255

On Sun, Jun 19, 2016 at 3:45 AM, Jason Hoetger notifications@github.com
wrote:

This is very strange, indeed. Which version of LP are you using? In the
current version, the only thing that could cause an NPE at
ProxyUtils.java:396 is if the currentHttpRequest from the
ProxyToServerConnection were null. That should not happen, but the code
seems to anticipate such an unusual scenario in identifyCurrentRequest().
Have you seen a message like the one below earlier in the logs? It would be
at the WARN level.

Got null HTTP request object.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#303 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AMCoPF2LoatDPrnv85sAN1yjILHjXM0tks5qNG4SgaJpZM4I1u-d
.

@zboralski
Copy link

zboralski commented Dec 8, 2016

If netty fails to parse the httpObject correctly... it will catch the exception and add it to decodeResult as a failure...

It won't show in LittleProxy's log unless you have its level set to debug :

  • DEBUG [LittleProxy-0-ProxyToServerWorker-0] impl.ProxyToServerConnection (ProxyToServerConnection.java:224).readHTTPInitial() - (AWAITING_INITIAL) [id: 0xba9629ee, L:/127.0.0.1:59374 - R:/127.0.0.1:8000]: Received raw response: DefaultFullHttpResponse(decodeResult: failure(java.lang.IllegalArgumentException: Header name cannot contain non-ASCII
  • DEBUG [LittleProxy-0-ProxyToServerWorker-0] impl.ProxyToServerConnection (ProxyToServerConnection.java:224).readHTTPInitial() - (AWAITING_INITIAL) [id: 0xba9629ee, L:/127.0.0.1:59374 - R:/127.0.0.1:8000]: Received raw response: DefaultFullHttpResponse(decodeResult: failure(java.lang.NumberFormatException: For input string: "81774918712"), version: HTTP/1.0, content: EmptyByteBufBE)

The currentHttpRequest will be null and cause a NPE.

@jekh
Copy link
Collaborator

jekh commented Dec 10, 2016

@zboralski - is there a URL you know of that consistently reproduces this issue? This is very helpful information indeed.

@zboralski
Copy link

zboralski commented Dec 15, 2016

@jekh if you want to reproduce the issue:

LittleProxy is running on port 8080

cat <<EOF | nc -l 8000
HTTP/1.1231231231231231 200 OK
Date: Wed, 07 Dec 2016 01:24:03 GMT
Connection: close
Transfer-Encoding: chunked
qwerqewrqewr qwerq
 wr
qwe
rqwe
r
EOF

In another terminal

export http_proxy=http://localhost:8080
curl http://localhost:8000

@jekh
Copy link
Collaborator

jekh commented Dec 18, 2016

Thank you, @zboralski, that was extremely helpful. I'm able to repro the issue consistently, and I see what's happening. It looks like there are two separate issues that need to be resolved:

  1. The currentHttpRequest in ProxyToServerConnection is null, which is the immediate cause of the NPE. The reason it's null is because it's generally not set until after netty successfully decodes the response from the server. This is done in HeadAwareHttpResponseDecoder#isContentAlwaysEmpty(), seemingly because it's convenient, not because there's any inherent reason that checking to see if the response content is always empty should trigger "remembering" of the current request. Because of the decoding error in the response, that method is never called.
  2. In ProxyToServerConnection#readHTTPInitial(HttpResponse), we do not currently detect if the response from the server failed to decode, which results in sending an invalid HttpResponse to the client (netty marshalls the response as a 999 Unknown status code). This should be pretty simple to fix.

I'm going to work on a fix for this and see if I can get it out for review soon enough to make the next release. Thanks again, @zboralski, this issue has been around for a long time and it's great to finally understand why.

@jekh
Copy link
Collaborator

jekh commented Dec 27, 2016

This should be fixed now in 1.1.1. I've been testing with it extensively and have not run into this issue. Feel free to reopen if you see it again.

HUGE thanks to @zboralski for the steps to repro this!

@jekh jekh closed this as completed Dec 27, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants