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.

Reply via email to