Bill Havanki desu at deszaras.xyz
Sat May 1 03:03:58 BST 2021
- - - - - - - - - - - - - - - - - - -
My thanks to Gary as well. I found that my own Java server implementation had the same problem.
My server gets the socket’s input and output streams in a try-with-resources block, so they are closed when the block exits. Unfortunately, when either of those streams are closed, Java closes the socket as well!
So, I fixed the user_canceled problem by making a thin wrapper object around the socket output stream. When that stream wrapper is closed, it calls shutdownOutput on the socket before closing the original stream (which then closes the socket). Works nicely.
https://github.com/bhavanki/doppio/blob/a4f8802d6e0dbeb066fa71f8c79b66d8616b3cf1/src/main/java/com/havanki/doppio/RequestHandler.java#L555
Bill
On Apr 18, 2021, at 10:41 AM, Alan <gemini at bunburya.eu> wrote:
Hi Gary,
That solved it, thanks! A simple fix but you're right, I couldn't find
anything about it. Good to know there is a solution.
Thanks,
Alan
On 18/04/2021 01:04, Gary Johnson wrote:
Alan<gemini at bunburya.eu> writes:
When using the Amfora browser, I was unable to view "20" responses,
getting instead the following error: "/Issuing creating page: remote
error: tls: user//canceled/". Unusually, every other response is
displayed fine.
Hi Alan,
I'm the author of Space-Age, a Gemini server written in Clojure.
=
https://gitlab.com/lambdatronic/space-age/
The tls_user_canceled issue you are running into is coming from the Java
side. It also mystified me last year when I was writing my server since
I was constantly getting that error in elpher (the Emacs Gemini client)
whenever I tried to browse pages from my capsule.
You have to force your SSLSocket to send the tls_close_notify alert to
the client before closing the socket. This is exceptionally poorly
documented in the JSSE Reference Guide, but I eventually figured out the
solution through trial and error.
All you need to do is to make sure you call socket.shutdownOutput()
immediately before calling socket.close().
Here's my function for writing a Gemini response back to the client for reference:
```
(defn- write-socket! [^SSLSocket socket {:keys [status meta body]}]
(doto (io/writer socket)
(.write (str status " " meta "\r\n"))
(.flush))
(when body
(with-open [in-stream (io/input-stream (if (string? body)
(.getBytes ^String body)
body))]
(let [out-stream (io/output-stream socket)]
(.transferTo in-stream out-stream)
(.flush out-stream))))
(.shutdownOutput socket))
```
This is called from another function that then calls socket.close() to
terminate the connection.
Here is my full Gemini server implementation for further reference:
=
https://gitlab.com/lambdatronic/space-age/-/blob/master/src/space_age/server.clj
Happy hacking!
Gary-------------- next part --------------An HTML attachment was scrubbed...URL: <https://lists.orbitalfox.eu/archives/gemini/attachments/20210501/9bc2a130/attachment-0001.htm>