(web http): header names always represented as symbols
authorAndy Wingo <wingo@pobox.com>
Sat, 8 Jan 2011 18:54:07 +0000 (10:54 -0800)
committerAndy Wingo <wingo@pobox.com>
Sat, 8 Jan 2011 18:54:07 +0000 (10:54 -0800)
* module/web/http.scm (declare-header!): No need to specify `sym', as it
  can be derived from `name'. Change to take parser, validator, and
  writer as positional arguments, and multiple? as a keyword.
  (parse-header): Change to take the header as a symbol already, and
  just return the parsed value.  All headers are symbols now, including
  unknown headers.  I feel OK doing this given that the symbol GC works
  now.
  (lookup-header-decl): Only look up headers by symbol.
  (read-header): Adapt to parse-header change.

  (valid-header?, write-header): Adapt to all headers being symbols.
  (split-header-names, list-of-header-names?, write-header-list):
  Represent all header names as symbols.

  (declare-opaque-header!, declare-date-header!)
  (declare-string-list-header!, declare-header-list-header!)
  (declare-integer-header!, declare-uri-header!)
  (declare-quality-list-header!, declare-param-list-header!)
  (declare-key-value-list-header!, declare-entity-tag-list-header!):
  Change to be functions instead of syntax, and no need to specify the
  symbolic name. Update all header declarations accordingly.

* module/web/request.scm (validate-headers):
* module/web/response.scm (validate-headers): Adapt to all headers being
  symbols.

* test-suite/tests/web-http.test (pass-if-parse, pass-if-any-error)
  (pass-if-parse-error): Update for parse-header change.
  ("general headers"): Update header list examples to be all symbols.

module/web/http.scm
module/web/request.scm
module/web/response.scm
test-suite/tests/web-http.test

index 422669a..d4e2b2c 100644 (file)
@@ -1,6 +1,6 @@
 ;;; HTTP messages
 
-;; Copyright (C)  2010 Free Software Foundation, Inc.
+;; Copyright (C)  2010, 2011 Free Software Foundation, Inc.
 
 ;; This library is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU Lesser General Public
 
 ;; sym -> header
 (define *declared-headers* (make-hash-table))
-;; downcased name -> header
-(define *declared-headers-by-name* (make-hash-table))
 
-(define* (declare-header! sym name #:key 
-                          multiple?
+(define* (declare-header! name
                           parser
                           validator
-                          writer)
+                          writer
+                          #:key multiple?)
   "Define a parser, validator, and writer for the HTTP header, @var{name}.
 
 @var{parser} should be a procedure that takes a string and returns a
 Scheme value.  @var{validator} is a predicate for whether the given
 Scheme value is valid for this header.  @var{writer} takes a value and a
 port, and writes the value to the port."
-  (if (and (symbol? sym) (string? name) parser validator writer)
-      (let ((decl (make-header-decl sym name
-                                    multiple? parser validator writer)))
+  (if (and (string? name) parser validator writer)
+      (let* ((sym (string->symbol (string-downcase name)))
+             (decl (make-header-decl sym name
+                                     multiple? parser validator writer)))
         (hashq-set! *declared-headers* sym decl)
-        (hash-set! *declared-headers-by-name* (string-downcase name) decl)
         decl)
-      (error "bad header decl" sym name multiple? parser validator writer)))
+      (error "bad header decl" name multiple? parser validator writer)))
 
 (define (read-line* port)
   (let* ((pair (%read-line port))
@@ -143,63 +141,54 @@ body was reached (i.e., a blank line)."
     (if (or (string-null? line)
             (string=? line "\r"))
         (values *eof* *eof*)
-        (let ((delim (or (string-index line #\:)
-                         (bad-header '%read line))))
-          (parse-header
-           (substring line 0 delim)
-           (read-continuation-line
-            port
-            (string-trim-both line char-whitespace? (1+ delim))))))))
-
-(define (lookup-header-decl name)
-  "Return the @var{header-decl} object registered for the given @var{name}.
-
-@var{name} may be a symbol or a string.  Strings are mapped to headers
-in a case-insensitive fashion."
-  (if (string? name)
-      (hash-ref *declared-headers-by-name* (string-downcase name))
-      (hashq-ref *declared-headers* name)))
-
-(define (parse-header name val)
-  "Parse @var{val}, a string, with the parser for the header named @var{name}.
-
-Returns two values, the header name and parsed value.  If a parser was
-found, the header name will be returned as a symbol.  If a parser was
-not found, both the header name and the value are returned as strings."
-  (let* ((down (string-downcase name))
-         (decl (hash-ref *declared-headers-by-name* down)))
+        (let* ((delim (or (string-index line #\:)
+                          (bad-header '%read line)))
+               (sym (string->symbol
+                     (string-downcase! (substring/copy line 0 delim)))))
+          (values
+           sym
+           (parse-header
+            sym
+            (read-continuation-line
+             port
+             (string-trim-both line char-whitespace? (1+ delim)))))))))
+
+(define (lookup-header-decl sym)
+  "Return the @var{header-decl} object registered for the given
+@var{sym}, which should be a symbol."
+  (hashq-ref *declared-headers* sym))
+
+(define (parse-header sym val)
+  "Parse @var{val}, a string, with the parser registered for the header
+named @var{sym}.
+
+Returns the parsed value.  If a parser was not found, the value is
+returned as a string."
+  (let ((decl (lookup-header-decl sym)))
     (if decl
-        (values (header-decl-sym decl)
-                ((header-decl-parser decl) val))
-        (values down val))))
+        ((header-decl-parser decl) val)
+        val)))
 
 (define (valid-header? sym val)
   "Returns a true value iff @var{val} is a valid Scheme value for the
 header with name @var{sym}."
-  (let ((decl (hashq-ref *declared-headers* sym)))
-    (if (not decl)
-        (error "Unknown header" sym)
-        ((header-decl-validator decl) val))))
-
-(define (write-header name val port)
-  "Writes the given header name and value to @var{port}.  If @var{name}
-is a symbol, looks up a declared header and uses that writer. Otherwise
-the value is written using @var{display}."
-  (if (string? name)
-      ;; assume that it's a header we don't know about...
-      (begin
-        (display name port)
-        (display ": " port)
-        (display val port)
-        (display "\r\n" port))
-      (let ((decl (hashq-ref *declared-headers* name)))
-        (if (not decl)
-            (error "Unknown header" name)
-            (begin
-              (display (header-decl-name decl) port)
-              (display ": " port)
-              ((header-decl-writer decl) val port)
-              (display "\r\n" port))))))
+  (if (symbol? sym)
+      (let ((decl (lookup-header-decl sym)))
+        (or (not decl)
+            ((header-decl-validator decl) val)))
+      (error "header name not a symbol" sym)))
+
+(define (write-header sym val port)
+  "Writes the given header name and value to @var{port}.  If @var{sym}
+is a known header, uses the specific writer registered for that header.
+Otherwise the value is written using @var{display}."
+  (let ((decl (lookup-header-decl sym)))
+    (if decl
+        (display (header-decl-name decl) port)
+        (display (string-titlecase (symbol->string sym)) port))
+    (display ": " port)
+    ((if decl (header-decl-writer decl) display) val port)
+    (display "\r\n" port)))
 
 (define (read-headers port)
   "Read an HTTP message from @var{port}, returning the headers as an
@@ -279,20 +268,18 @@ ordered alist."
 
 (define (split-header-names str)
   (map (lambda (f)
-         (or (and=> (lookup-header-decl f) header-decl-sym)
-             f))
+         (string->symbol (string-downcase f)))
        (split-and-trim str)))
 
 (define (list-of-header-names? val)
-  (list-of? val (lambda (x) (or (string? x) (symbol? x)))))
+  (list-of? val symbol?))
 
 (define (write-header-list val port)
   (write-list val port
               (lambda (x port)
-                (display (or (and (symbol? x)
-                                  (and=> (lookup-header-decl x)
-                                         header-decl-name))
-                             x)
+                (display (or (and=> (lookup-header-decl x)
+                                    header-decl-name)
+                             (string-titlecase (symbol->string x)))
                          port))
               ", "))
 
@@ -834,120 +821,78 @@ phrase\"."
 \f
 
 ;;;
-;;; Syntax for declaring headers
+;;; Helpers for declaring headers
 ;;;
 
-;; emacs: (put 'declare-header 'scheme-indent-function 1)
-(define-syntax declare-header
-  (syntax-rules ()
-    ((_ sym name parser validator writer arg ...)
-     (declare-header!
-      'sym name
-      #:parser parser #:validator validator #:writer writer
-      arg ...))))
-
-;; emacs: (put 'declare-opaque-header 'scheme-indent-function 1)
-(define-syntax declare-opaque-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       parse-opaque-string validate-opaque-string write-opaque-string))))
-
-;; emacs: (put 'declare-date-header 'scheme-indent-function 1)
-(define-syntax declare-date-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       parse-date date? write-date))))
-
-;; emacs: (put 'declare-string-list-header 'scheme-indent-function 1)
-(define-syntax declare-string-list-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       split-and-trim list-of-strings? write-list-of-strings))))
-
-;; emacs: (put 'declare-header-list-header 'scheme-indent-function 1)
-(define-syntax declare-header-list-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       split-header-names list-of-header-names? write-header-list))))
-
-;; emacs: (put 'declare-integer-header 'scheme-indent-function 1)
-(define-syntax declare-integer-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       parse-non-negative-integer non-negative-integer? display))))
-
-;; emacs: (put 'declare-uri-header 'scheme-indent-function 1)
-(define-syntax declare-uri-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       (lambda (str) (or (string->uri str) (bad-header-component 'uri str)))
-       uri?
-       write-uri))))
-
-;; emacs: (put 'declare-quality-list-header 'scheme-indent-function 1)
-(define-syntax declare-quality-list-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       parse-quality-list validate-quality-list write-quality-list))))
-
-;; emacs: (put 'declare-param-list-header 'scheme-indent-function 1)
-(define-syntax declare-param-list-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-param-list-header sym name identity default-kons
-                                default-kv-validator default-val-writer))
-    ((_ sym name kproc)
-     (declare-param-list-header sym name kproc default-kons
-                                default-kv-validator default-val-writer))
-    ((_ sym name kproc kons val-validator val-writer)
-     (declare-header sym
-       name
-       (lambda (str) (parse-param-list str kproc kons))
-       (lambda (val) (validate-param-list val val-validator))
-       (lambda (val port) (write-param-list val port val-writer))))))
-
-;; emacs: (put 'declare-key-value-list-header 'scheme-indent-function 1)
-(define-syntax declare-key-value-list-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-key-value-list-header sym name identity default-kons
-                                    default-kv-validator default-val-writer))
-    ((_ sym name kproc)
-     (declare-key-value-list-header sym name kproc default-kons
-                                    default-kv-validator default-val-writer))
-    ((_ sym name kproc kons val-validator val-writer)
-     (declare-header sym
-       name
-       (lambda (str) (parse-key-value-list str kproc kons))
-       (lambda (val) (key-value-list? val val-validator))
-       (lambda (val port) (write-key-value-list val port val-writer))))))
-
-;; emacs: (put 'declare-entity-tag-list-header 'scheme-indent-function 1)
-(define-syntax declare-entity-tag-list-header
-  (syntax-rules ()
-    ((_ sym name)
-     (declare-header sym
-       name
-       (lambda (str) (if (string=? str "*") '* (parse-entity-tag-list str)))
-       (lambda (val) (or (eq? val '*) (entity-tag-list? val)))
-       (lambda (val port)
-         (if (eq? val '*)
-             (display "*" port)
-             (write-entity-tag-list val port)))))))
+;; emacs: (put 'declare-header! 'scheme-indent-function 1)
+;; emacs: (put 'declare-opaque!-header 'scheme-indent-function 1)
+(define (declare-opaque-header! name)
+  (declare-header! name
+    parse-opaque-string validate-opaque-string write-opaque-string))
+
+;; emacs: (put 'declare-date-header! 'scheme-indent-function 1)
+(define (declare-date-header! name)
+  (declare-header! name
+    parse-date date? write-date))
+
+;; emacs: (put 'declare-string-list-header! 'scheme-indent-function 1)
+(define (declare-string-list-header! name)
+  (declare-header! name
+    split-and-trim list-of-strings? write-list-of-strings))
+
+;; emacs: (put 'declare-header-list-header! 'scheme-indent-function 1)
+(define (declare-header-list-header! name)
+  (declare-header! name
+    split-header-names list-of-header-names? write-header-list))
+
+;; emacs: (put 'declare-integer-header! 'scheme-indent-function 1)
+(define (declare-integer-header! name)
+  (declare-header! name
+    parse-non-negative-integer non-negative-integer? display))
+
+;; emacs: (put 'declare-uri-header! 'scheme-indent-function 1)
+(define (declare-uri-header! name)
+  (declare-header! name
+    (lambda (str) (or (string->uri str) (bad-header-component 'uri str)))
+    uri?
+    write-uri))
+
+;; emacs: (put 'declare-quality-list-header! 'scheme-indent-function 1)
+(define (declare-quality-list-header! name)
+  (declare-header! name
+    parse-quality-list validate-quality-list write-quality-list))
+
+;; emacs: (put 'declare-param-list-header! 'scheme-indent-function 1)
+(define* (declare-param-list-header! name #:optional
+                                     (kproc identity)
+                                     (kons default-kons)
+                                     (val-validator default-kv-validator)
+                                     (val-writer default-val-writer))
+  (declare-header! name
+    (lambda (str) (parse-param-list str kproc kons))
+    (lambda (val) (validate-param-list val val-validator))
+    (lambda (val port) (write-param-list val port val-writer))))
+
+;; emacs: (put 'declare-key-value-list-header! 'scheme-indent-function 1)
+(define* (declare-key-value-list-header! name #:optional
+                                         (kproc identity)
+                                         (kons default-kons)
+                                         (val-validator default-kv-validator)
+                                         (val-writer default-val-writer))
+  (declare-header! name
+    (lambda (str) (parse-key-value-list str kproc kons))
+    (lambda (val) (key-value-list? val val-validator))
+    (lambda (val port) (write-key-value-list val port val-writer))))
+
+;; emacs: (put 'declare-entity-tag-list-header! 'scheme-indent-function 1)
+(define (declare-entity-tag-list-header! name)
+  (declare-header! name
+    (lambda (str) (if (string=? str "*") '* (parse-entity-tag-list str)))
+    (lambda (val) (or (eq? val '*) (entity-tag-list? val)))
+    (lambda (val port)
+      (if (eq? val '*)
+          (display "*" port)
+          (write-entity-tag-list val port)))))
 
 
 \f
@@ -980,8 +925,7 @@ phrase\"."
 ;;      | cache-extension                        ; Section 14.9.6
 ;; cache-extension = token [ "=" ( token | quoted-string ) ]
 ;;
-(declare-key-value-list-header cache-control
-  "Cache-Control"
+(declare-key-value-list-header! "Cache-Control"
   (let ((known-directives (make-hash-table)))
     (for-each (lambda (s) 
                 (hash-set! known-directives s (string->symbol s)))
@@ -1017,40 +961,34 @@ phrase\"."
 ;; e.g.
 ;;     Connection: close, foo-header
 ;; 
-(declare-string-list-header connection
-  "Connection")
+(declare-string-list-header! "Connection")
 
 ;; Date  = "Date" ":" HTTP-date
 ;; e.g.
 ;;     Date: Tue, 15 Nov 1994 08:12:31 GMT
 ;;
-(declare-date-header date
-  "Date")
+(declare-date-header! "Date")
 
 ;; Pragma            = "Pragma" ":" 1#pragma-directive
 ;; pragma-directive  = "no-cache" | extension-pragma
 ;; extension-pragma  = token [ "=" ( token | quoted-string ) ]
 ;;
-(declare-key-value-list-header pragma
-  "Pragma"
+(declare-key-value-list-header! "Pragma"
   (lambda (k) (if (equal? k "no-cache") 'no-cache k)))
 
 ;; Trailer  = "Trailer" ":" 1#field-name
 ;;
-(declare-header-list-header trailer
-  "Trailer")
+(declare-header-list-header! "Trailer")
 
 ;; Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
 ;;
-(declare-param-list-header transfer-encoding
-  "Transfer-Encoding"
+(declare-param-list-header! "Transfer-Encoding"
   (lambda (k)
     (if (equal? k "chunked") 'chunked k)))
 
 ;; Upgrade = "Upgrade" ":" 1#product
 ;;
-(declare-string-list-header upgrade
-  "Upgrade")
+(declare-string-list-header! "Upgrade")
 
 ;; Via =  "Via" ":" 1#( received-protocol received-by [ comment ] )
 ;; received-protocol = [ protocol-name "/" ] protocol-version
@@ -1059,8 +997,7 @@ phrase\"."
 ;; received-by       = ( host [ ":" port ] ) | pseudonym
 ;; pseudonym         = token
 ;;
-(declare-header via
-  "Via"
+(declare-header! "Via"
   split-and-trim
   list-of-strings?
   write-list-of-strings
@@ -1077,8 +1014,7 @@ phrase\"."
 ;;                 ; the Warning header, for use in debugging
 ;; warn-text  = quoted-string
 ;; warn-date  = <"> HTTP-date <">
-(declare-header warning
-  "Warning"
+(declare-header! "Warning"
   (lambda (str)
     (let ((len (string-length str)))
       (let lp ((i (skip-whitespace str 0)))
@@ -1149,33 +1085,27 @@ phrase\"."
 
 ;; Allow = #Method
 ;;
-(declare-string-list-header allow
-  "Allow")
+(declare-string-list-header! "Allow")
 
 ;; Content-Encoding = 1#content-coding
 ;;
-(declare-string-list-header content-encoding
-  "Content-Encoding")
+(declare-string-list-header! "Content-Encoding")
 
 ;; Content-Language = 1#language-tag
 ;;
-(declare-string-list-header content-language
-  "Content-Language")
+(declare-string-list-header! "Content-Language")
 
 ;; Content-Length = 1*DIGIT
 ;;
-(declare-integer-header content-length
-  "Content-Length")
+(declare-integer-header! "Content-Length")
 
 ;; Content-Location = ( absoluteURI | relativeURI )
 ;;
-(declare-uri-header content-location
-  "Content-Location")
+(declare-uri-header! "Content-Location")
 
 ;; Content-MD5 = <base64 of 128 bit MD5 digest as per RFC 1864>
 ;;
-(declare-opaque-header content-md5
-  "Content-MD5")
+(declare-opaque-header! "Content-MD5")
 
 ;; Content-Range = content-range-spec
 ;; content-range-spec      = byte-content-range-spec
@@ -1186,8 +1116,7 @@ phrase\"."
 ;;                                | "*"
 ;; instance-length           = 1*DIGIT
 ;;
-(declare-header content-range
-  "Content-Range"
+(declare-header! "Content-Range"
   (lambda (str)
     (let ((dash (string-index str #\-))
           (slash (string-index str #\/)))
@@ -1232,8 +1161,7 @@ phrase\"."
 
 ;; Content-Type = media-type
 ;;
-(declare-header content-type
-  "Content-Type"
+(declare-header! "Content-Type"
   (lambda (str)
     (let ((parts (string-split str #\;)))
       (cons (parse-media-type (car parts))
@@ -1265,13 +1193,11 @@ phrase\"."
 
 ;; Expires = HTTP-date
 ;;
-(declare-date-header expires
-  "Expires")
+(declare-date-header! "Expires")
 
 ;; Last-Modified = HTTP-date
 ;;
-(declare-date-header last-modified
-  "Last-Modified")
+(declare-date-header! "Last-Modified")
 
 
 \f
@@ -1286,8 +1212,7 @@ phrase\"."
 ;; accept-params = ";" "q" "=" qvalue *( accept-extension )
 ;; accept-extension = ";" token [ "=" ( token | quoted-string ) ]
 ;;
-(declare-param-list-header accept
-  "Accept"
+(declare-param-list-header! "Accept"
   ;; -> ("type/subtype" (str-prop . str-val) ...) ...)
   ;;
   ;; with the exception of prop = "q", in which case the prop will be
@@ -1309,28 +1234,24 @@ phrase\"."
 
 ;; Accept-Charset = 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
 ;;
-(declare-quality-list-header accept-charset
-  "Accept-Charset")
+(declare-quality-list-header! "Accept-Charset")
 
 ;; Accept-Encoding = 1#( codings [ ";" "q" "=" qvalue ] )
 ;; codings = ( content-coding | "*" )
 ;;
-(declare-quality-list-header accept-encoding
-  "Accept-Encoding")
+(declare-quality-list-header! "Accept-Encoding")
 
 ;; Accept-Language = 1#( language-range [ ";" "q" "=" qvalue ] )
 ;; language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
 ;;
-(declare-quality-list-header accept-language
-  "Accept-Language")
+(declare-quality-list-header! "Accept-Language")
 
 ;; Authorization = credentials
 ;;
 ;; Authorization is basically opaque to this HTTP stack, we just pass
 ;; the string value through.
 ;; 
-(declare-opaque-header authorization
-  "Authorization")
+(declare-opaque-header! "Authorization")
 
 ;; Expect = 1#expectation
 ;; expectation = "100-continue" | expectation-extension
@@ -1338,8 +1259,7 @@ phrase\"."
 ;;                         *expect-params ]
 ;; expect-params = ";" token [ "=" ( token | quoted-string ) ]
 ;;
-(declare-param-list-header expect
-  "Expect"
+(declare-param-list-header! "Expect"
   (lambda (k)
     (if (equal? k "100-continue")
         '100-continue
@@ -1349,13 +1269,11 @@ phrase\"."
 ;;
 ;; Should be an email address; we just pass on the string as-is.
 ;;
-(declare-opaque-header from
-  "From")
+(declare-opaque-header! "From")
 
 ;; Host = host [ ":" port ]
 ;; 
-(declare-header host
-  "Host"
+(declare-header! "Host"
   (lambda (str)
     (let ((colon (string-index str #\:)))
       (if colon
@@ -1376,23 +1294,19 @@ phrase\"."
 
 ;; If-Match = ( "*" | 1#entity-tag )
 ;;
-(declare-entity-tag-list-header if-match
-  "If-Match")
+(declare-entity-tag-list-header! "If-Match")
 
 ;; If-Modified-Since = HTTP-date
 ;;
-(declare-date-header if-modified-since
-  "If-Modified-Since")
+(declare-date-header! "If-Modified-Since")
 
 ;; If-None-Match = ( "*" | 1#entity-tag )
 ;;
-(declare-entity-tag-list-header if-none-match
-  "If-None-Match")
+(declare-entity-tag-list-header! "If-None-Match")
 
 ;; If-Range = ( entity-tag | HTTP-date )
 ;;
-(declare-header if-range
-  "If-Range"
+(declare-header! "If-Range"
   (lambda (str)
     (if (or (string-prefix? "\"" str)
             (string-prefix? "W/" str))
@@ -1407,18 +1321,15 @@ phrase\"."
 
 ;; If-Unmodified-Since = HTTP-date
 ;;
-(declare-date-header if-unmodified-since
-  "If-Unmodified-Since")
+(declare-date-header! "If-Unmodified-Since")
 
 ;; Max-Forwards = 1*DIGIT
 ;;
-(declare-integer-header max-forwards
-  "Max-Forwards")
+(declare-integer-header! "Max-Forwards")
 
 ;; Proxy-Authorization = credentials
 ;;
-(declare-opaque-header proxy-authorization
-  "Proxy-Authorization")
+(declare-opaque-header! "Proxy-Authorization")
 
 ;; Range = "Range" ":" ranges-specifier
 ;; ranges-specifier = byte-ranges-specifier
@@ -1430,8 +1341,7 @@ phrase\"."
 ;; suffix-byte-range-spec = "-" suffix-length
 ;; suffix-length = 1*DIGIT
 ;;
-(declare-header range
-  "Range"
+(declare-header! "Range"
   (lambda (str)
     (if (string-prefix? "bytes=" str)
         (cons
@@ -1475,20 +1385,17 @@ phrase\"."
 
 ;; Referer = ( absoluteURI | relativeURI )
 ;;
-(declare-uri-header referer
-  "Referer")
+(declare-uri-header! "Referer")
 
 ;; TE = #( t-codings )
 ;; t-codings = "trailers" | ( transfer-extension [ accept-params ] )
 ;;
-(declare-param-list-header te
-  "TE"
+(declare-param-list-header! "TE"
   (lambda (k) (if (equal? k "trailers") 'trailers k)))
 
 ;; User-Agent = 1*( product | comment )
 ;;
-(declare-opaque-header user-agent
-  "User-Agent")
+(declare-opaque-header! "User-Agent")
 
 
 \f
@@ -1500,38 +1407,32 @@ phrase\"."
 ;; Accept-Ranges = acceptable-ranges
 ;; acceptable-ranges = 1#range-unit | "none"
 ;;
-(declare-string-list-header accept-ranges
-  "Accept-Ranges")
+(declare-string-list-header! "Accept-Ranges")
 
 ;; Age = age-value
 ;; age-value = delta-seconds
 ;;
-(declare-integer-header age
-  "Age")
+(declare-integer-header! "Age")
 
 ;; ETag = entity-tag
 ;;
-(declare-header etag
-  "ETag"
+(declare-header! "ETag"
   parse-entity-tag
   entity-tag?
   write-entity-tag)
 
 ;; Location = absoluteURI
 ;; 
-(declare-uri-header location
-  "Location")
+(declare-uri-header! "Location")
 
 ;; Proxy-Authenticate = 1#challenge
 ;;
 ;; FIXME: split challenges ?
-(declare-opaque-header proxy-authenticate
-  "Proxy-Authenticate")
+(declare-opaque-header! "Proxy-Authenticate")
 
 ;; Retry-After  = ( HTTP-date | delta-seconds )
 ;;
-(declare-header retry-after
-  "Retry-After"
+(declare-header! "Retry-After"
   (lambda (str)
     (if (and (not (string-null? str))
              (char-numeric? (string-ref str 0)))
@@ -1546,13 +1447,11 @@ phrase\"."
 
 ;; Server = 1*( product | comment )
 ;;
-(declare-opaque-header server
-  "Server")
+(declare-opaque-header! "Server")
 
 ;; Vary = ( "*" | 1#field-name )
 ;;
-(declare-header vary
-  "Vary"
+(declare-header! "Vary"
   (lambda (str)
     (if (equal? str "*")
         '*
@@ -1567,5 +1466,4 @@ phrase\"."
 ;; WWW-Authenticate = 1#challenge
 ;;
 ;; Hum.
-(declare-opaque-header www-authenticate
-  "WWW-Authenticate")
+(declare-opaque-header! "WWW-Authenticate")
index adf1dd2..84bc36e 100644 (file)
@@ -1,6 +1,6 @@
 ;;; HTTP request objects
 
-;; Copyright (C)  2010 Free Software Foundation, Inc.
+;; Copyright (C)  2010, 2011 Free Software Foundation, Inc.
 
 ;; This library is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU Lesser General Public
       (let ((h (car headers)))
         (if (pair? h)
             (let ((k (car h)) (v (cdr h)))
-              (if (symbol? k)
-                  (if (not (valid-header? k v))
-                      (bad-request "Bad value for header ~a: ~s" k v))
-                  (if (not (and (string? k) (string? v)))
-                      (bad-request "Unknown header not a pair of strings: ~s"
-                                   h)))
-              (validate-headers (cdr headers)))
+              (if (valid-header? k v)
+                  (validate-headers (cdr headers))
+                  (bad-request "Bad value for header ~a: ~s" k v)))
             (bad-request "Header not a pair: ~a" h)))
       (if (not (null? headers))
           (bad-request "Headers not a list: ~a" headers))))
index 7acde1e..f8a87a2 100644 (file)
@@ -1,6 +1,6 @@
 ;;; HTTP response objects
 
-;; Copyright (C)  2010 Free Software Foundation, Inc.
+;; Copyright (C)  2010, 2011 Free Software Foundation, Inc.
 
 ;; This library is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU Lesser General Public
       (let ((h (car headers)))
         (if (pair? h)
             (let ((k (car h)) (v (cdr h)))
-              (if (symbol? k)
-                  (if (not (valid-header? k v))
-                      (bad-response "Bad value for header ~a: ~s" k v))
-                  (if (not (and (string? k) (string? v)))
-                      (bad-response "Unknown header not a pair of strings: ~s"
-                                    h)))
-              (validate-headers (cdr headers)))
+              (if (valid-header? k v)
+                  (validate-headers (cdr headers))
+                  (bad-response "Bad value for header ~a: ~s" k v)))
             (bad-response "Header not a pair: ~a" h)))
       (if (not (null? headers))
           (bad-response "Headers not a list: ~a" headers))))
index 068523e..bf030a9 100644 (file)
@@ -1,6 +1,6 @@
 ;;;; web-uri.test --- URI library          -*- mode: scheme; coding: utf-8; -*-
 ;;;;
-;;;;   Copyright (C) 2010 Free Software Foundation, Inc.
+;;;;   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -41,9 +41,8 @@
   (syntax-rules ()
     ((_ sym str val)
      (pass-if (format #f "~a: ~s -> ~s" 'sym str val)
-       (call-with-values (lambda () (parse-header (symbol->string 'sym) str))
-         (lambda (k v)
-           (equal? v val)))))))
+       (equal? (parse-header 'sym str)
+               val)))))
 
 (define-syntax pass-if-any-error
   (syntax-rules ()
@@ -51,7 +50,7 @@
      (pass-if (format #f "~a: ~s -> any error" 'sym str)
        (% (catch #t
             (lambda ()
-              (parse-header (symbol->string 'sym) str)
+              (parse-header 'sym str)
               (abort (lambda () (error "expected exception"))))
             (lambda (k . args)
               #t))
@@ -64,7 +63,7 @@
      (pass-if (format #f "~a: ~s -> ~a error" 'sym str 'expected-component)
        (catch 'bad-header
          (lambda ()
-           (parse-header (symbol->string 'sym) str)
+           (parse-header 'sym str)
            (error "expected exception" 'expected-component))
          (lambda (k component arg)
            (if (or (not 'expected-component)
@@ -80,7 +79,7 @@
   (pass-if-parse cache-control "no-cache=\"Authorization, Date\""
                  '((no-cache . (authorization date))))
   (pass-if-parse cache-control "private=\"Foo\""
-                 '((private . ("Foo"))))
+                 '((private . (foo))))
   (pass-if-parse cache-control "no-cache,max-age=10"
                  '(no-cache (max-age . 10)))
 
@@ -96,8 +95,8 @@
   (pass-if-parse pragma "no-cache" '(no-cache))
   (pass-if-parse pragma "no-cache, foo" '(no-cache "foo"))
 
-  (pass-if-parse trailer "foo, bar" '("foo" "bar"))
-  (pass-if-parse trailer "connection, bar" '(connection "bar"))
+  (pass-if-parse trailer "foo, bar" '(foo bar))
+  (pass-if-parse trailer "connection, bar" '(connection bar))
 
   (pass-if-parse transfer-encoding "foo, chunked" '(("foo") (chunked)))
 
   (pass-if-parse retry-after "20" 20)
   (pass-if-parse server "guile!" "guile!")
   (pass-if-parse vary "*" '*)
-  (pass-if-parse vary "foo, bar" '("foo" "bar"))
+  (pass-if-parse vary "foo, bar" '(foo bar))
   (pass-if-parse www-authenticate "secret" "secret"))