nla / outbackcdx

Web archive index server based on RocksDB

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Possible infinite loop upon malformed requests

anjackson opened this issue · comments

This may be an old problem, as this is an error we're seeing in our old version, but we seem to have hit a condition where tinycdxserver gets caught in an infinite error loop and spools out huge amounts of error logging. The errors look like this:

java.lang.IllegalArgumentException: URLDecoder: Incomplete trailing escape (%) pattern
        at java.net.URLDecoder.decode(URLDecoder.java:187)
        at tinycdxserver.XmlQuery.decodeQueryString(XmlQuery.java:49)
        at tinycdxserver.XmlQuery.<init>(XmlQuery.java:32)
        at tinycdxserver.XmlQuery.query(XmlQuery.java:192)
        at tinycdxserver.Server.query(Server.java:182)
        at tinycdxserver.Server.serve(Server.java:126)
        at tinycdxserver.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:831)
        at tinycdxserver.NanoHTTPD$1$1.run(NanoHTTPD.java:205)
        at java.lang.Thread.run(Thread.java:745)
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:141)
        at tinycdxserver.NanoHTTPD$Response.send(NanoHTTPD.java:535)
        at tinycdxserver.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:840)
        at tinycdxserver.NanoHTTPD$1$1.run(NanoHTTPD.java:205)
        at java.lang.Thread.run(Thread.java:745)

As I said, this is the old version so may no longer be relevant, but is there any way this error could lead to an infinite loop? I notice there's a while (!myServerSocket.isClosed()) so perhaps some edge case is stopping the socket getting closed? Or possibly at while (!finalAccept.isClosed()).

Perhaps safeClose(Socket) needs tweaking to cope with java.net.SocketException: Broken pipe ? Hmm, guess not as SocketException is a subclass of IOException.

There's a lot of this too:

java.net.SocketException: Socket closed
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:116)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:141)
        at tinycdxserver.NanoHTTPD$Response.send(NanoHTTPD.java:535)
        at tinycdxserver.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:840)
        at tinycdxserver.NanoHTTPD$1$1.run(NanoHTTPD.java:205)
        at java.lang.Thread.run(Thread.java:745)

When it's looping is it repeating those same two exceptions over and over?

I can reproduce the IllegalArgumentException like this against the latest version but it doesn't loop:

$ curl 'http://localhost:8080/myindex?q=%'
curl: (52) Empty reply from server

It's hard to tell, and we've deleted the log file now, and it's not erroring at the moment. Here's the largest chunk of errors I could find in my console history:

java.lang.IllegalArgumentException: URLDecoder: Incomplete trailing escape (%) p                                  attern
        at java.net.URLDecoder.decode(URLDecoder.java:187)
        at tinycdxserver.XmlQuery.decodeQueryString(XmlQuery.java:49)
        at tinycdxserver.XmlQuery.<init>(XmlQuery.java:32)
        at tinycdxserver.XmlQuery.query(XmlQuery.java:192)
        at tinycdxserver.Server.query(Server.java:182)
        at tinycdxserver.Server.serve(Server.java:126)
        at tinycdxserver.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:831)
        at tinycdxserver.NanoHTTPD$1$1.run(NanoHTTPD.java:205)
        at java.lang.Thread.run(Thread.java:745)
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        at tinycdxserver.NanoHTTPD$Response.sendAsFixedLength(NanoHTTPD.java:598                                  )
        at tinycdxserver.NanoHTTPD$Response.send(NanoHTTPD.java:546)
        at tinycdxserver.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:840)
        at tinycdxserver.NanoHTTPD$1$1.run(NanoHTTPD.java:205)
        at java.lang.Thread.run(Thread.java:745)
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        at tinycdxserver.NanoHTTPD$Response.sendAsFixedLength(NanoHTTPD.java:598                                  )
        at tinycdxserver.NanoHTTPD$Response.send(NanoHTTPD.java:546)
        at tinycdxserver.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:840)
        at tinycdxserver.NanoHTTPD$1$1.run(NanoHTTPD.java:205)
        at java.lang.Thread.run(Thread.java:745)
[snip]

(Edit by @ato: I moved the rest here for my issue reading sanity: https://gist.github.com/ato/d1b57f7401603fce736a153539770be1 )
(Edit by @anjackson: Ah good idea should have thought of that....)

I think the looping is caused by a request larger than the httpd request buffer: NanoHttpd/nanohttpd#362
I've put in a workaround to reject too large requests. If you actually need to query for URLs large than 8000 characters we might need a different solution though.

No, URLs over 8000 chars can be ignored. Maybe our systems are mis-handling some discovered data: URIs.