Skip to content

Fix Empty Responses when IOExceptions Are Thrown in Toadlets#1120

Draft
Bombe wants to merge 11 commits intohyphanet:nextfrom
Bombe:fix/ioexceptions-in-toadlets
Draft

Fix Empty Responses when IOExceptions Are Thrown in Toadlets#1120
Bombe wants to merge 11 commits intohyphanet:nextfrom
Bombe:fix/ioexceptions-in-toadlets

Conversation

@Bombe
Copy link
Copy Markdown
Contributor

@Bombe Bombe commented Feb 7, 2026

(This PR is built upon PR-1121, because it needs all the test scaffolding from that PR. Merge that one first, this only adds the last commit.)

In ToadletContextImpl.handle(), in the outer-most try-catch block, IOExceptions are completely ignored and do not generate a response; it was probably assumed that IOExceptions will always mean that either the input stream or the output stream of the request itself had some kind of issues, in which case generating a response would be mostly useless; however, Toadlets are also allowed to throw IOExceptions from their handleMethod* methods. These exceptions now generate an HTTP status 500 response and include a stack trace in the response body.

@Bombe Bombe changed the title Fix/ioexceptions in toadlets Fix Empty Responses when IOExceptions Are Thrown in Toadlets Feb 7, 2026
The reason that I/O exceptions were swallowed and caused the node to simply not
send a reply at all is that IOExceptions in the handle() method were ignored.
While the actual reasoning for that is unknown and lost to time, I can imagine
that it was assumed that any IOExceptions that occur would do so either while
parsing the input stream or while writing to the output stream, thus making it
possibly pointless to try and generate a response. This missed the fact that
toadlets are allowed to throw IOExceptions in their handleMethod* methods as
well, and as soon as that happens, the node would simply drop the connection.

Now IOExceptions are handled the same way all (well, most) other exceptions are
handled: by returning an HTTP status code of 500, and a nice, text-only page
that says “Internal error” and prints the stack trace.
@Bombe Bombe force-pushed the fix/ioexceptions-in-toadlets branch from c8adc88 to 6539f48 Compare February 7, 2026 16:33
@bertm
Copy link
Copy Markdown
Contributor

bertm commented Feb 8, 2026

Reviewed 6539f48 in isolation; this looks very much welcome.

@S10wD0wn
Copy link
Copy Markdown

Almost works with IO Exceptions. The error is logged but the error response cannot be sent because the socket is already closed.

If you log the Exception in the Exception handler where the HTTP response should be sent you will get:

(freenet.clients.http.ToadletContextImpl, HTTP socket handler@859137091(3), ERROR): Caught unhandled error in errorhandling: java.net.SocketException: Socket is closed handling socket
java.net.SocketException: Socket is closed
at java.base/java.net.Socket.getOutputStream(Socket.java:1157)
at freenet.clients.http.ToadletContextImpl.handle(ToadletContextImpl.java:733)
at freenet.clients.http.SimpleToadletServer$SocketHandler.run(SimpleToadletServer.java:1075)
at freenet.support.PooledExecutor$MyThread.innerRun(PooledExecutor.java:259)
at freenet.support.PooledExecutor$MyThread.realRun(PooledExecutor.java:197)
at freenet.support.io.NativeThread.run(NativeThread.java:156)

@Bombe
Copy link
Copy Markdown
Contributor Author

Bombe commented Feb 15, 2026

Indeed, we are actually closing the socket (by way of closing the socket’s InputStream by way of the try-with-resources) before we’re actually sending out any error replies. That’s sub-optimal!

@Bombe Bombe marked this pull request as draft February 16, 2026 21:23
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

Successfully merging this pull request may close these issues.

3 participants