Thank you, Brian and Jesse, for your thoughts on this. There may still
be an exception problem here, though.
(and sorry for being sluggish to respond)
On 16 May 2020, at 20:16, Norman Gray wrote:
Now, in tracking this down I can see that I have a wrong design here:
the servlet has started producing output before the exception is
thrown, so it's at this point really too late for me to be throwing
errors and producing custom 5xx error pages.
Brian said:
I think you need to decide when to stream, and when not to stream. In
my
web framework, most requests involve computing the entire response
string
prior to calling (response ...), so if an error is encountered, I can
send
an error response instead of a success response.
and Jesse:
I suggest thinking of a servlet as a response builder, and, if
possible, to
delegate serialization of the response (output-response & friends)
till
after a response? value has been created.
I agree this is the right way of thinking about things here, and it's
reassuring to have that confirmed. Part of what was confusing me was
that it's not particularly clear from the documentation what
serve/servlet's #:servlet-responder is there for. It appears to be just
an odd spelling of 'exception handler', as far as I can tell from the
code.
Indeed it's true that, once the HTTP status code has hit the wire,
there's no provision in the protocol to change one's mind and come up
with a different status (it's possible that forthcoming HTTP/3, with its
concern to multiplex content on the wire, will come up with something
here, but I haven't examined HTTP/3 in detail, and I'd be surprised if
this was one of its concerns).
However, a problem comes when the serialiser _does_ produce a 'real'
exception -- meaning an exception that isn't one that I expected it to
produce. In that case, the response.rkt code just hangs.
Consider:
#lang racket/base
(require web-server/servlet
web-server/servlet-env)
(define (make-response/output writer)
(λ (req)
(response 200 #"OK" (current-seconds) #"text/plain" '()
writer)))
(define my-app/simple
(make-response/output
(λ (op)
(display "hello" op))))
(define my-app/error
(make-response/output
(λ (op)
(error "Oooops")
(display "Hello" op))))
(define my-app/handlers
(make-response/output
(λ (op)
(with-handlers ((exn:fail? (λ (ex) (display "Eeek!" op))))
(error "Oooops")
(display "Hello" op)))))
(serve/servlet my-app/error
#:servlet-regexp #rx""
#:command-line? #t)
If we run this server, and dereference <http://localhost:8000/>, for
example with curl, then the retrieval simply hangs.
It appears that the handler in
web-server-lib/web-server/response.rkt:148 is supposed to handle this
case, but it appears not to. I think it's possible the handler should
be in to-chunker-t instead or as well.
This means that a further possibility is to have an exception handler
within the serialiser, and handle exceptions appropriately there (as in
my-app/handlers above). However all this means that a carefully-written
servlet _must_ have such handlers, if an inadvertent exception in the
serialiser procedure isn't to stall a client.
Best wishes,
Norman
--
Norman Gray : https://nxg.me.uk
SUPA School of Physics and Astronomy, University of Glasgow, UK
--
You received this message because you are subscribed to the Google Groups "Racket
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/racket-users/AB2357DF-5A41-429F-A7BB-7B4321EEDBE3%40glasgow.ac.uk.