Many improvements to drivers/http.rkt

This commit is contained in:
Tony Garnock-Jones 2024-04-10 15:42:22 +02:00
parent bd973f069a
commit c538c577c3
1 changed files with 66 additions and 53 deletions

View File

@ -110,18 +110,26 @@
(turn! facet
(lambda ()
(react
(local-connection-protocol ds connection-name conn routes req)
(local-connection-protocol ds connection-name conn port routes req)
(on-stop (async-channel-put continue-ch 'dummy)))))
(async-channel-get continue-ch)
(unless close? (process-requests)))))))
(define next-request-id (inexact->exact (floor (current-inexact-milliseconds))))
(define (local-connection-protocol ds connection-name conn routes req)
(define (local-connection-protocol ds connection-name conn port routes req)
(let/ec return
(define reply-sent? #f)
(define (unless-reply-sent thunk)
(unless reply-sent?
(set! reply-sent? #t)
(thunk)))
(define (respond! resp)
(output-response/method conn resp (request-method req))
(unless-reply-sent
(lambda ()
(output-response/method conn resp (request-method req))))
(stop-current-facet))
(define (decode-bytes bs)
@ -148,10 +156,11 @@
(define headers (headers-map (request-headers/raw req)))
(define host-and-port (cond [(assq 'host (request-headers req)) => cdr] [else #f]))
(define-values (host port)
(define host
(match host-and-port
[(regexp #px"(.*):(\\d+)" (list _ host port)) (values host (string->number port))]
[host (values host 80)]))
[#f (RequestHost-absent)]
[(regexp #px"(.*):\\d+" (list _ host)) (RequestHost-present host)]
[host (RequestHost-present host)]))
(define method (lowercase-symbol! (decode-bytes (request-method req))))
@ -198,76 +207,74 @@
(list)))
(return (void)))))
(match-define (active-handler handler handler-terminated?) (set-first handler-set))
(define processing #f)
(define pending-code 500)
(define pending-message "Internal Server Error")
(define pending-code 200)
(define pending-message "OK")
(define pending-headers-rev '())
(define chunk-ch #f)
(define (check-processing!)
(unless processing
(error 'HttpResponse "Attempt to reply before <processing> has been asserted")))
(define (send-headers!)
(define (start-chunked-response!)
(unless chunk-ch
(set! chunk-ch (make-async-channel))
(thread
(lambda ()
(output-response/method conn
(response pending-code
(string->bytes/utf-8 pending-message)
(current-seconds)
#f
(build-headers (reverse pending-headers-rev))
(lambda (output-port)
(let loop ()
(match (async-channel-get chunk-ch)
[#f (void)]
[bs
(write-bytes bs output-port)
(flush-output output-port)
(loop)]))))
(request-method req))))))
(unless-reply-sent
(lambda ()
(output-response/method conn
(response pending-code
(string->bytes/utf-8 pending-message)
(current-seconds)
#f
(build-headers (reverse pending-headers-rev))
(lambda (output-port)
(let loop ()
(match (async-channel-get chunk-ch)
[#f (void)]
[bs
(write-bytes bs output-port)
(flush-output output-port)
(loop)]))))
(request-method req))))))))
(define (finish-request!)
(send-headers!)
(async-channel-put chunk-ch #f)
(stop-current-facet))
(define (send-final-chunk! chunk)
(define bs (chunk->bytes chunk))
(if chunk-ch
(begin (async-channel-put chunk-ch bs)
(async-channel-put chunk-ch #f)
(stop-current-facet))
(respond! (response/full pending-code
(string->bytes/utf-8 pending-message)
(current-seconds)
#f
(build-headers (reverse pending-headers-rev))
(list bs)))))
(begin/dataflow
(when (handler-terminated?)
(finish-request!)))
(set! pending-code 500)
(set! pending-message "Internal Server Error")
(set! pending-headers-rev '())
(send-final-chunk! *empty-chunk*)))
(define res (object #:name connection-name
[#:asserted (HttpResponse-processing)
(log-syndicate/drivers/http-debug "~v: +processing" connection-name)
(set! processing #t)
(set! pending-code 200)
(set! pending-message "OK")
#:retracted
(log-syndicate/drivers/http-debug "~v: -processing" connection-name)
(finish-request!)]
[#:message (HttpResponse-status code message)
(log-syndicate/drivers/http-debug "~v: status ~v ~v" connection-name
code message)
(check-processing!)
(set! pending-code code)
(set! pending-message message)]
[#:message (HttpResponse-header name value)
(log-syndicate/drivers/http-debug "~v: header ~v ~v" connection-name
name value)
(check-processing!)
(set! pending-headers-rev (cons (cons name value) pending-headers-rev))]
[#:message (HttpResponse-body chunk)
(log-syndicate/drivers/http-debug "~v: chunk ~v" connection-name
chunk)
(check-processing!)
(send-headers!)
(async-channel-put chunk-ch (chunk->bytes chunk))]))
[#:message (HttpResponse-chunk chunk)
(start-chunked-response!)
(async-channel-put chunk-ch (chunk->bytes chunk))]
[#:message (HttpResponse-done chunk)
(send-final-chunk! chunk)]))
(at handler (assert (HttpContext decoded-req res)))
(return (void)))))
(begin (try-hostname host)
(begin (when (RequestHost-present? host)
(try-hostname (RequestHost-present-value host)))
(try-hostname #f)
(respond! (response/full 404
#"Not Found"
@ -285,6 +292,8 @@
[[(cons expected pat) (cons actual p)] #:when (equal? expected actual) (loop pat p)]
[[_ _] #f])))
(define *empty-chunk* (Chunk-bytes #""))
(define (chunk->bytes c)
(match c
[(Chunk-string s) (string->bytes/utf-8 s)]
@ -313,7 +322,6 @@
(lambda () method)
(lambda () (quote-path-pattern () (path-pattern-element ...)))
(lambda (req res)
(at res (assert (HttpResponse-processing)))
(match (HttpRequest-path req)
[#,(match-quote-path-pattern #'(path-pattern-element ...))
(async (match (let () body ...)
@ -381,6 +389,7 @@
(define (send-http-response! res code message
#:headers [headers '()]
#:mime-type [mime-type #f]
#:done? [done? #t]
. chunks)
(send! res (HttpResponse-status code message))
(when mime-type
@ -390,7 +399,11 @@
(for [(header headers)]
(match-define (cons name value) header)
(send! res (HttpResponse-header name value)))
(for [(chunk chunks)] (send! res (HttpResponse-body chunk))))
(let loop ((chunks chunks))
(match chunks
['() (when done? (send! res (HttpResponse-done *empty-chunk*)))]
[(list ch) (send! res ((if done? HttpResponse-done HttpResponse-chunk) ch))]
[(cons ch more) (send! res (HttpResponse-chunk ch)) (loop more)])))
;;---------------------------------------------------------------------------