Add some helpers for handling request bodies
This commit is contained in:
parent
759ff87c0c
commit
e3bc3c12b0
2 changed files with 143 additions and 0 deletions
|
@ -42,6 +42,12 @@
|
||||||
|
|
||||||
make-chunked-output-port/knots
|
make-chunked-output-port/knots
|
||||||
|
|
||||||
|
&request-body-ended-prematurely
|
||||||
|
request-body-ended-prematurely-error?
|
||||||
|
|
||||||
|
request-body-port/knots
|
||||||
|
read-request-body/knots
|
||||||
|
|
||||||
default-exception-handler
|
default-exception-handler
|
||||||
default-write-response-exception-handler
|
default-write-response-exception-handler
|
||||||
|
|
||||||
|
@ -85,6 +91,75 @@ KEEP-ALIVE? is true."
|
||||||
(setvbuf ret 'block buffering)
|
(setvbuf ret 'block buffering)
|
||||||
ret)
|
ret)
|
||||||
|
|
||||||
|
(define* (make-delimited-input-port port len fail
|
||||||
|
#:key (keep-alive? #t))
|
||||||
|
"Return an input port that reads from PORT, and makes sure that
|
||||||
|
exactly LEN bytes are available from PORT. Closing the returned port
|
||||||
|
closes PORT, unless KEEP-ALIVE? is true."
|
||||||
|
(define bytes-read 0)
|
||||||
|
|
||||||
|
(define (read! bv start count)
|
||||||
|
(let ((count (min count (- len bytes-read))))
|
||||||
|
(let loop ((ret (get-bytevector-n! port bv start count)))
|
||||||
|
(cond ((eof-object? ret)
|
||||||
|
(if (= bytes-read len)
|
||||||
|
0 ; EOF
|
||||||
|
(fail bytes-read)))
|
||||||
|
((and (zero? ret) (> count 0))
|
||||||
|
;; Do not return zero since zero means EOF, so try again.
|
||||||
|
(loop (get-bytevector-n! port bv start count)))
|
||||||
|
(else
|
||||||
|
(set! bytes-read (+ bytes-read ret))
|
||||||
|
ret)))))
|
||||||
|
|
||||||
|
(define close
|
||||||
|
(and (not keep-alive?)
|
||||||
|
(lambda ()
|
||||||
|
(close-port port))))
|
||||||
|
|
||||||
|
(make-custom-binary-input-port "delimited input port" read! #f #f close))
|
||||||
|
|
||||||
|
;; Chunked Responses
|
||||||
|
(define &request-body-ended-prematurely
|
||||||
|
(make-exception-type '&request-body-ended-prematurely
|
||||||
|
&external-error
|
||||||
|
'(bytes-read)))
|
||||||
|
|
||||||
|
(define make-request-body-ended-prematurely-error
|
||||||
|
(record-constructor &request-body-ended-prematurely))
|
||||||
|
|
||||||
|
(define request-body-ended-prematurely-error?
|
||||||
|
(record-predicate &request-body-ended-prematurely))
|
||||||
|
|
||||||
|
(define (request-body-port/knots r)
|
||||||
|
(cond
|
||||||
|
((member '(chunked) (request-transfer-encoding r))
|
||||||
|
(make-chunked-input-port (request-port r)
|
||||||
|
#:keep-alive? #t))
|
||||||
|
(else
|
||||||
|
(let ((content-length
|
||||||
|
(request-content-length r)))
|
||||||
|
(make-delimited-input-port
|
||||||
|
(request-port r)
|
||||||
|
content-length
|
||||||
|
(lambda (bytes-read)
|
||||||
|
(raise-exception
|
||||||
|
(make-request-body-ended-prematurely-error bytes-read))))))))
|
||||||
|
|
||||||
|
(define (read-request-body/knots r)
|
||||||
|
(cond
|
||||||
|
((member '(chunked) (request-transfer-encoding r))
|
||||||
|
(get-bytevector-all
|
||||||
|
(request-body-port/knots r)))
|
||||||
|
(else
|
||||||
|
(let ((content-length
|
||||||
|
(request-content-length r)))
|
||||||
|
(if content-length
|
||||||
|
(get-bytevector-n
|
||||||
|
(request-body-port/knots r)
|
||||||
|
content-length)
|
||||||
|
#f)))))
|
||||||
|
|
||||||
(define (extend-response r k v . additional)
|
(define (extend-response r k v . additional)
|
||||||
(define (extend-alist alist k v)
|
(define (extend-alist alist k v)
|
||||||
(let ((pair (assq k alist)))
|
(let ((pair (assq k alist)))
|
||||||
|
|
|
@ -150,6 +150,74 @@
|
||||||
(utf8->string
|
(utf8->string
|
||||||
(get-bytevector-n body 3)))))))
|
(get-bytevector-n body 3)))))))
|
||||||
|
|
||||||
|
(run-fibers-for-tests
|
||||||
|
(lambda ()
|
||||||
|
(let* ((web-server
|
||||||
|
(run-knots-web-server
|
||||||
|
(lambda (request)
|
||||||
|
(if (string=? (utf8->string
|
||||||
|
(read-request-body/knots request))
|
||||||
|
"☺")
|
||||||
|
(values (build-response #:code 200)
|
||||||
|
"")
|
||||||
|
(values (build-response #:code 500)
|
||||||
|
"")))
|
||||||
|
#:port 0)) ;; Bind to any port
|
||||||
|
(port
|
||||||
|
(web-server-port web-server))
|
||||||
|
(uri
|
||||||
|
(build-uri 'http #:host "127.0.0.1" #:port port)))
|
||||||
|
|
||||||
|
(let ((response
|
||||||
|
body
|
||||||
|
(http-post
|
||||||
|
uri
|
||||||
|
#:body "☺"
|
||||||
|
#:port (non-blocking-open-socket-for-uri uri))))
|
||||||
|
(assert-equal
|
||||||
|
200
|
||||||
|
(response-code response))))))
|
||||||
|
|
||||||
|
(run-fibers-for-tests
|
||||||
|
(lambda ()
|
||||||
|
(let* ((channel (make-channel))
|
||||||
|
(web-server
|
||||||
|
(run-knots-web-server
|
||||||
|
(lambda (request)
|
||||||
|
(with-exception-handler
|
||||||
|
(lambda (exn)
|
||||||
|
(put-message channel exn))
|
||||||
|
(lambda ()
|
||||||
|
(read-request-body/knots request))
|
||||||
|
#:unwind? #t))
|
||||||
|
#:port 0)) ;; Bind to any port
|
||||||
|
(port
|
||||||
|
(web-server-port web-server))
|
||||||
|
(uri
|
||||||
|
(build-uri 'http #:host "127.0.0.1" #:port port)))
|
||||||
|
|
||||||
|
(let* ((port (non-blocking-open-socket-for-uri uri))
|
||||||
|
(request
|
||||||
|
(build-request
|
||||||
|
uri
|
||||||
|
#:method 'POST
|
||||||
|
#:version '(1 . 1)
|
||||||
|
#:headers `((connection close)
|
||||||
|
(content-length . 20)
|
||||||
|
(Content-Type . "application/octet-stream"))
|
||||||
|
#:port port)))
|
||||||
|
|
||||||
|
(set-port-encoding! port "ISO-8859-1")
|
||||||
|
(let ((request (write-request request port)))
|
||||||
|
(display "12")
|
||||||
|
(force-output port)
|
||||||
|
|
||||||
|
(close-port port)))
|
||||||
|
|
||||||
|
(assert-true
|
||||||
|
(request-body-ended-prematurely-error?
|
||||||
|
(get-message channel))))))
|
||||||
|
|
||||||
;; Test hanlding of exceptions when writing the response to a client
|
;; Test hanlding of exceptions when writing the response to a client
|
||||||
(run-fibers-for-tests
|
(run-fibers-for-tests
|
||||||
(lambda ()
|
(lambda ()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue