diff options
author | Billy Brown <druidofluhn@gmail.com> | 2023-12-21 17:07:00 +0000 |
---|---|---|
committer | Peter Bex <peter@more-magic.net> | 2024-01-11 13:59:39 +0100 |
commit | b9683af2da882d542208a15d67d8040bab8fa5c2 (patch) | |
tree | 947497195eb439a0a22e4839f9adcb952c4b579c /header-parsers.scm | |
parent | b2632661807a99fc7c3e610e8bd1b04c68b869c5 (diff) | |
download | intarweb-2.1.0.tar.gz |
Corrected Range and Content-Range header handling2.1.0
Corrected the handling of the Range request header and the Content-
Range response header. They now have separate parsers, to match the
standard, and the content-range unparser is now correctly named.
The Range header can be in one of three forms:
Range: bytes=<start>-<end>
Range: bytes=<start>-
Range: bytes=-<end>
The Content-Range header can be in one of three forms:
Content-Range: bytes <start>-<end>/<size>
Content-Range: bytes <start>-<end>/*
Content-Range: bytes */<size>
The unit tests were updated to reflect the changes.
Signed-off-by: Peter Bex <peter@more-magic.net>
Diffstat (limited to 'header-parsers.scm')
-rw-r--r-- | header-parsers.scm | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/header-parsers.scm b/header-parsers.scm index 89edeae..ac41a09 100644 --- a/header-parsers.scm +++ b/header-parsers.scm @@ -376,18 +376,42 @@ (cons (substring/shared contents 0 idx) version) (cons contents #f)))) -;; bytes <start>-<end>/<total> +;; Try getting a submatch from an irregex match and parse it, or return #f +(define (try-parse-submatch match group-name parser) + (and-let* ((value (irregex-match-substring match group-name))) + (parser value))) + +;; bytes=<start>-<end> +;; bytes=<start>- +;; bytes=-<end> (define range-subparser (let ((range-regex + (irregex '(seq "bytes=" + (=> start (* digit)) "-" (=> end (* digit)))))) + (lambda (s) + (and-let* ((m (irregex-match range-regex s))) + (let ((start (try-parse-submatch m 'start string->number)) + (end (try-parse-submatch m 'end string->number))) + (if (or start end) + (list start end) + #f)))))) + +;; bytes <start>-<end>/<total> +;; bytes <start>-<end>/* +;; bytes */<total> +(define content-range-subparser + (let ((content-range-regex (irregex '(seq "bytes" (+ space) - (=> start (+ digit)) "-" (=> end (+ digit)) - "/" (=> total (+ digit)))))) + (or (seq "*/" (=> total (+ digit))) + (seq (=> start (+ digit)) "-" (=> end (+ digit)) + "/" (or "*" + (=> total (+ digit))))))))) (lambda (s) - (and-let* ((m (irregex-match range-regex s)) - (start (string->number (irregex-match-substring m 'start))) - (end (string->number (irregex-match-substring m 'end))) - (total (string->number (irregex-match-substring m 'total)))) - (list start end total))))) + (and-let* ((m (irregex-match content-range-regex s))) + (let ((start (try-parse-submatch m 'start string->number)) + (end (try-parse-submatch m 'end string->number)) + (total (try-parse-submatch m 'total string->number))) + (list start end total)))))) ;; Accept *just* a filename, not a full path (simply strips directories) ;; This matches the content-disposition recommendation in RFC2616, 19.5.1: @@ -724,6 +748,23 @@ (if (eq? 'weak (car etag)) "W/" "") (quote-string (cdr etag)))) ;; Etags are _always_ quoted +(define (unparse-content-range content-range) + ; False values are used to represent wildcards "*" + (let ((content-range-value-unparser (lambda (value) + (if value + (number->string value) + "*")))) + (string-append "bytes " + ; If the start and end are wildcards, use only one + (if (not (or (car content-range) (cadr content-range))) + "*" + (string-append + (content-range-value-unparser (car content-range)) + "-" + (content-range-value-unparser (cadr content-range)))) + "/" + (content-range-value-unparser (caddr content-range))))) + ;; There's no need to make a specific header unparser for every header type. ;; Usually, the Scheme value representing a header can unambiguously be ;; unparsed into a header just by checking its type. @@ -772,6 +813,9 @@ (read-date . ,rfc1123-time->string)) value-unparser: unparser))))) +(define (content-range-unparser header-contents) + (list (unparse-content-range (get-value (car header-contents))))) + (define (etag-unparser header-contents) (list (unparse-etag (get-value (car header-contents))))) |