diff --git a/rmq/private/util.rkt b/rmq/private/util.rkt index d42cf63..4f8d425 100644 --- a/rmq/private/util.rkt +++ b/rmq/private/util.rkt @@ -4,9 +4,12 @@ random-hex-string extend-url-string-query web-respond/status! - web-request!) + web-request! + parse-link-headers) (require racket/dict) +(require racket/match) +(require racket/string) (require (only-in file/sha1 bytes->hex-string)) (require (only-in racket/random crypto-random-bytes)) (require net/url) @@ -28,6 +31,20 @@ (define u (string->url urlstr)) (url->string (struct-copy url u [query (append (url-query u) extension)]))) +(module+ test + (check-equal? (extend-url-string-query "http://localhost/" '((a . "hi"))) + "http://localhost/?a=hi") + (check-equal? (extend-url-string-query "http://localhost/" '()) + "http://localhost/") + (check-equal? (extend-url-string-query "http://localhost?foo=bar" '()) + "http://localhost?foo=bar") + (check-equal? (extend-url-string-query "http://localhost/?foo=bar" '()) + "http://localhost/?foo=bar") + (check-equal? (extend-url-string-query "http://localhost?foo=bar" '((a . "hi"))) + "http://localhost?foo=bar&a=hi") + (check-equal? (extend-url-string-query "http://localhost/?foo=bar" '((a . "hi"))) + "http://localhost/?foo=bar&a=hi")) + (define (web-respond/status! id code message [body #""]) (web-respond/bytes! id #:header (web-response-header @@ -64,16 +81,38 @@ #:redirect-budget (- redirect-budget 1)) (values resp response-body))) +(define (parse-link-headers headers) + (define rel-dict-reverse-order + (for/fold [(seed (hasheq))] [(header headers)] + (if (eq? (car header) 'link) + (parse-link-header-value (cdr header) seed) + seed))) + (for/hasheq [((rel urls-rev) (in-hash rel-dict-reverse-order))] + (values rel (reverse urls-rev)))) + +(define (parse-link-header-value link-header seed) + ;; This is not adequate with respect to the RFC 5988 grammar, which + ;; includes a wide variety of link-params other than "rel". + (define pieces + (append (regexp-match* #rx"(<([^>]+)>; +rel=([^\"][^,]*))" link-header #:match-select values) + (regexp-match* #rx"(<([^>]+)>; +rel=\"([^\"]+)\")" link-header #:match-select values))) + (for/fold [(rel-dict seed)] [(piece pieces)] + (match-define (list _ _ url rels-str) piece) + (for/fold [(rel-dict rel-dict)] [(rel-str (string-split rels-str))] + (define rel (string->symbol rel-str)) + (hash-set rel-dict rel (cons url (hash-ref rel-dict rel '())))))) + (module+ test - (check-equal? (extend-url-string-query "http://localhost/" '((a . "hi"))) - "http://localhost/?a=hi") - (check-equal? (extend-url-string-query "http://localhost/" '()) - "http://localhost/") - (check-equal? (extend-url-string-query "http://localhost?foo=bar" '()) - "http://localhost?foo=bar") - (check-equal? (extend-url-string-query "http://localhost/?foo=bar" '()) - "http://localhost/?foo=bar") - (check-equal? (extend-url-string-query "http://localhost?foo=bar" '((a . "hi"))) - "http://localhost?foo=bar&a=hi") - (check-equal? (extend-url-string-query "http://localhost/?foo=bar" '((a . "hi"))) - "http://localhost/?foo=bar&a=hi")) + (define combined "; rel=\"hub\", ; rel=\"self\"") + (define separate "; rel=hub") + (check-equal? (parse-link-header-value combined (hasheq)) + (hasheq 'hub (list "http://phubb.cweiske.de/hub.php") + 'self (list "http://push-tester.cweiske.de/feed.php"))) + (check-equal? (parse-link-header-value separate (hasheq)) + (hasheq 'hub (list "http://localhost:7827/hub"))) + (check-equal? (parse-link-headers (list (cons 'link combined) + (cons 'content-type "text/plain") + (cons 'link separate))) + (hasheq 'hub (list "http://phubb.cweiske.de/hub.php" + "http://localhost:7827/hub") + 'self (list "http://push-tester.cweiske.de/feed.php"))))