http.scm 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590
  1. ;;; HTTP messages
  2. ;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
  3. ;; This library is free software; you can redistribute it and/or
  4. ;; modify it under the terms of the GNU Lesser General Public
  5. ;; License as published by the Free Software Foundation; either
  6. ;; version 3 of the License, or (at your option) any later version.
  7. ;;
  8. ;; This library is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;; Lesser General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU Lesser General Public
  14. ;; License along with this library; if not, write to the Free Software
  15. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. ;; 02110-1301 USA
  17. ;;; Commentary:
  18. ;;;
  19. ;;; This module has a number of routines to parse textual
  20. ;;; representations of HTTP data into native Scheme data structures.
  21. ;;;
  22. ;;; It tries to follow RFCs fairly strictly---the road to perdition
  23. ;;; being paved with compatibility hacks---though some allowances are
  24. ;;; made for not-too-divergent texts (like a quality of .2 which should
  25. ;;; be 0.2, etc).
  26. ;;;
  27. ;;; Code:
  28. (define-module (web http)
  29. #:use-module ((srfi srfi-1) #:select (append-map! map!))
  30. #:use-module (srfi srfi-9)
  31. #:use-module (srfi srfi-19)
  32. #:use-module (ice-9 regex)
  33. #:use-module (ice-9 rdelim)
  34. #:use-module (web uri)
  35. #:export (string->header
  36. header->string
  37. declare-header!
  38. known-header?
  39. header-parser
  40. header-validator
  41. header-writer
  42. read-header
  43. parse-header
  44. valid-header?
  45. write-header
  46. read-headers
  47. write-headers
  48. parse-http-method
  49. parse-http-version
  50. parse-request-uri
  51. read-request-line
  52. write-request-line
  53. read-response-line
  54. write-response-line))
  55. ;;; TODO
  56. ;;;
  57. ;;; Look at quality lists with more insight.
  58. ;;; Think about `accept' a bit more.
  59. ;;;
  60. (define (string->header name)
  61. "Parse @var{name} to a symbolic header name."
  62. (string->symbol (string-downcase name)))
  63. (define-record-type <header-decl>
  64. (make-header-decl name parser validator writer multiple?)
  65. header-decl?
  66. (name header-decl-name)
  67. (parser header-decl-parser)
  68. (validator header-decl-validator)
  69. (writer header-decl-writer)
  70. (multiple? header-decl-multiple?))
  71. ;; sym -> header
  72. (define *declared-headers* (make-hash-table))
  73. (define (lookup-header-decl sym)
  74. (hashq-ref *declared-headers* sym))
  75. (define* (declare-header! name
  76. parser
  77. validator
  78. writer
  79. #:key multiple?)
  80. "Define a parser, validator, and writer for the HTTP header, @var{name}.
  81. @var{parser} should be a procedure that takes a string and returns a
  82. Scheme value. @var{validator} is a predicate for whether the given
  83. Scheme value is valid for this header. @var{writer} takes a value and a
  84. port, and writes the value to the port."
  85. (if (and (string? name) parser validator writer)
  86. (let ((decl (make-header-decl name parser validator writer multiple?)))
  87. (hashq-set! *declared-headers* (string->header name) decl)
  88. decl)
  89. (error "bad header decl" name parser validator writer multiple?)))
  90. (define (header->string sym)
  91. "Return the string form for the header named @var{sym}."
  92. (let ((decl (lookup-header-decl sym)))
  93. (if decl
  94. (header-decl-name decl)
  95. (string-titlecase (symbol->string sym)))))
  96. (define (known-header? sym)
  97. "Return @code{#t} if there are parsers and writers registered for this
  98. header, otherwise @code{#f}."
  99. (and (lookup-header-decl sym) #t))
  100. (define (header-parser sym)
  101. "Returns a procedure to parse values for the given header."
  102. (let ((decl (lookup-header-decl sym)))
  103. (if decl
  104. (header-decl-parser decl)
  105. (lambda (x) x))))
  106. (define (header-validator sym)
  107. "Returns a procedure to validate values for the given header."
  108. (let ((decl (lookup-header-decl sym)))
  109. (if decl
  110. (header-decl-validator decl)
  111. string?)))
  112. (define (header-writer sym)
  113. "Returns a procedure to write values for the given header to a given
  114. port."
  115. (let ((decl (lookup-header-decl sym)))
  116. (if decl
  117. (header-decl-writer decl)
  118. display)))
  119. (define (read-line* port)
  120. (let* ((pair (%read-line port))
  121. (line (car pair))
  122. (delim (cdr pair)))
  123. (if (and (string? line) (char? delim))
  124. (let ((orig-len (string-length line)))
  125. (let lp ((len orig-len))
  126. (if (and (> len 0)
  127. (char-whitespace? (string-ref line (1- len))))
  128. (lp (1- len))
  129. (if (= len orig-len)
  130. line
  131. (substring line 0 len)))))
  132. (bad-header '%read line))))
  133. (define (read-continuation-line port val)
  134. (if (or (eqv? (peek-char port) #\space)
  135. (eqv? (peek-char port) #\tab))
  136. (read-continuation-line port
  137. (string-append val
  138. (begin
  139. (read-line* port))))
  140. val))
  141. (define *eof* (call-with-input-string "" read))
  142. (define (read-header port)
  143. "Reads one HTTP header from @var{port}. Returns two values: the header
  144. name and the parsed Scheme value. May raise an exception if the header
  145. was known but the value was invalid.
  146. Returns the end-of-file object for both values if the end of the message
  147. body was reached (i.e., a blank line)."
  148. (let ((line (read-line* port)))
  149. (if (or (string-null? line)
  150. (string=? line "\r"))
  151. (values *eof* *eof*)
  152. (let* ((delim (or (string-index line #\:)
  153. (bad-header '%read line)))
  154. (sym (string->header (substring line 0 delim))))
  155. (values
  156. sym
  157. (parse-header
  158. sym
  159. (read-continuation-line
  160. port
  161. (string-trim-both line char-whitespace? (1+ delim)))))))))
  162. (define (parse-header sym val)
  163. "Parse @var{val}, a string, with the parser registered for the header
  164. named @var{sym}.
  165. Returns the parsed value. If a parser was not found, the value is
  166. returned as a string."
  167. ((header-parser sym) val))
  168. (define (valid-header? sym val)
  169. "Returns a true value iff @var{val} is a valid Scheme value for the
  170. header with name @var{sym}."
  171. (if (symbol? sym)
  172. ((header-validator sym) val)
  173. (error "header name not a symbol" sym)))
  174. (define (write-header sym val port)
  175. "Writes the given header name and value to @var{port}. If @var{sym}
  176. is a known header, uses the specific writer registered for that header.
  177. Otherwise the value is written using @var{display}."
  178. (display (header->string sym) port)
  179. (display ": " port)
  180. ((header-writer sym) val port)
  181. (display "\r\n" port))
  182. (define (read-headers port)
  183. "Read an HTTP message from @var{port}, returning the headers as an
  184. ordered alist."
  185. (let lp ((headers '()))
  186. (call-with-values (lambda () (read-header port))
  187. (lambda (k v)
  188. (if (eof-object? k)
  189. (reverse! headers)
  190. (lp (acons k v headers)))))))
  191. (define (write-headers headers port)
  192. "Write the given header alist to @var{port}. Doesn't write the final
  193. \\r\\n, as the user might want to add another header."
  194. (let lp ((headers headers))
  195. (if (pair? headers)
  196. (begin
  197. (write-header (caar headers) (cdar headers) port)
  198. (lp (cdr headers))))))
  199. ;;;
  200. ;;; Utilities
  201. ;;;
  202. (define (bad-header sym val)
  203. (throw 'bad-header sym val))
  204. (define (bad-header-component sym val)
  205. (throw 'bad-header sym val))
  206. (define (parse-opaque-string str)
  207. str)
  208. (define (validate-opaque-string val)
  209. (string? val))
  210. (define (write-opaque-string val port)
  211. (display val port))
  212. (define separators-without-slash
  213. (string->char-set "[^][()<>@,;:\\\"?= \t]"))
  214. (define (validate-media-type str)
  215. (let ((idx (string-index str #\/)))
  216. (and idx (= idx (string-rindex str #\/))
  217. (not (string-index str separators-without-slash)))))
  218. (define (parse-media-type str)
  219. (if (validate-media-type str)
  220. (string->symbol str)
  221. (bad-header-component 'media-type str)))
  222. (define* (skip-whitespace str #:optional (start 0) (end (string-length str)))
  223. (let lp ((i start))
  224. (if (and (< i end) (char-whitespace? (string-ref str i)))
  225. (lp (1+ i))
  226. i)))
  227. (define* (trim-whitespace str #:optional (start 0) (end (string-length str)))
  228. (let lp ((i end))
  229. (if (and (< start i) (char-whitespace? (string-ref str (1- i))))
  230. (lp (1- i))
  231. i)))
  232. (define* (split-and-trim str #:optional (delim #\,)
  233. (start 0) (end (string-length str)))
  234. (let lp ((i start))
  235. (if (< i end)
  236. (let* ((idx (string-index str delim i end))
  237. (tok (string-trim-both str char-whitespace? i (or idx end))))
  238. (cons tok (split-and-trim str delim (if idx (1+ idx) end) end)))
  239. '())))
  240. (define (list-of-strings? val)
  241. (list-of? val string?))
  242. (define (write-list-of-strings val port)
  243. (write-list val port display ", "))
  244. (define (split-header-names str)
  245. (map string->header (split-and-trim str)))
  246. (define (list-of-header-names? val)
  247. (list-of? val symbol?))
  248. (define (write-header-list val port)
  249. (write-list val port
  250. (lambda (x port)
  251. (display (header->string x) port))
  252. ", "))
  253. (define (collect-escaped-string from start len escapes)
  254. (let ((to (make-string len)))
  255. (let lp ((start start) (i 0) (escapes escapes))
  256. (if (null? escapes)
  257. (begin
  258. (substring-move! from start (+ start (- len i)) to i)
  259. to)
  260. (let* ((e (car escapes))
  261. (next-start (+ start (- e i) 2)))
  262. (substring-move! from start (- next-start 2) to i)
  263. (string-set! to e (string-ref from (- next-start 1)))
  264. (lp next-start (1+ e) (cdr escapes)))))))
  265. ;; in incremental mode, returns two values: the string, and the index at
  266. ;; which the string ended
  267. (define* (parse-qstring str #:optional
  268. (start 0) (end (trim-whitespace str start))
  269. #:key incremental?)
  270. (if (and (< start end) (eqv? (string-ref str start) #\"))
  271. (let lp ((i (1+ start)) (qi 0) (escapes '()))
  272. (if (< i end)
  273. (case (string-ref str i)
  274. ((#\\)
  275. (lp (+ i 2) (1+ qi) (cons qi escapes)))
  276. ((#\")
  277. (let ((out (collect-escaped-string str (1+ start) qi escapes)))
  278. (if incremental?
  279. (values out (1+ i))
  280. (if (= (1+ i) end)
  281. out
  282. (bad-header-component 'qstring str)))))
  283. (else
  284. (lp (1+ i) (1+ qi) escapes)))
  285. (bad-header-component 'qstring str)))
  286. (bad-header-component 'qstring str)))
  287. (define (write-list l port write-item delim)
  288. (if (pair? l)
  289. (let lp ((l l))
  290. (write-item (car l) port)
  291. (if (pair? (cdr l))
  292. (begin
  293. (display delim port)
  294. (lp (cdr l)))))))
  295. (define (write-qstring str port)
  296. (display #\" port)
  297. (if (string-index str #\")
  298. ;; optimize me
  299. (write-list (string-split str #\") port display "\\\"")
  300. (display str port))
  301. (display #\" port))
  302. (define* (parse-quality str #:optional (start 0) (end (string-length str)))
  303. (define (char->decimal c)
  304. (let ((i (- (char->integer c) (char->integer #\0))))
  305. (if (and (<= 0 i) (< i 10))
  306. i
  307. (bad-header-component 'quality str))))
  308. (cond
  309. ((not (< start end))
  310. (bad-header-component 'quality str))
  311. ((eqv? (string-ref str start) #\1)
  312. (if (or (string= str "1" start end)
  313. (string= str "1." start end)
  314. (string= str "1.0" start end)
  315. (string= str "1.00" start end)
  316. (string= str "1.000" start end))
  317. 1000
  318. (bad-header-component 'quality str)))
  319. ((eqv? (string-ref str start) #\0)
  320. (if (or (string= str "0" start end)
  321. (string= str "0." start end))
  322. 0
  323. (if (< 2 (- end start) 6)
  324. (let lp ((place 1) (i (+ start 4)) (q 0))
  325. (if (= i (1+ start))
  326. (if (eqv? (string-ref str (1+ start)) #\.)
  327. q
  328. (bad-header-component 'quality str))
  329. (lp (* 10 place) (1- i)
  330. (if (< i end)
  331. (+ q (* place (char->decimal (string-ref str i))))
  332. q))))
  333. (bad-header-component 'quality str))))
  334. ;; Allow the nonstandard .2 instead of 0.2.
  335. ((and (eqv? (string-ref str start) #\.)
  336. (< 1 (- end start) 5))
  337. (let lp ((place 1) (i (+ start 3)) (q 0))
  338. (if (= i start)
  339. q
  340. (lp (* 10 place) (1- i)
  341. (if (< i end)
  342. (+ q (* place (char->decimal (string-ref str i))))
  343. q)))))
  344. (else
  345. (bad-header-component 'quality str))))
  346. (define (valid-quality? q)
  347. (and (non-negative-integer? q) (<= q 1000)))
  348. (define (write-quality q port)
  349. (define (digit->char d)
  350. (integer->char (+ (char->integer #\0) d)))
  351. (display (digit->char (modulo (quotient q 1000) 10)) port)
  352. (display #\. port)
  353. (display (digit->char (modulo (quotient q 100) 10)) port)
  354. (display (digit->char (modulo (quotient q 10) 10)) port)
  355. (display (digit->char (modulo q 10)) port))
  356. (define (list-of? val pred)
  357. (or (null? val)
  358. (and (pair? val)
  359. (pred (car val))
  360. (list-of? (cdr val) pred))))
  361. (define* (parse-quality-list str)
  362. (map (lambda (part)
  363. (cond
  364. ((string-rindex part #\;)
  365. => (lambda (idx)
  366. (let ((qpart (string-trim-both part char-whitespace? (1+ idx))))
  367. (if (string-prefix? "q=" qpart)
  368. (cons (parse-quality qpart 2)
  369. (string-trim-both part char-whitespace? 0 idx))
  370. (bad-header-component 'quality qpart)))))
  371. (else
  372. (cons 1000 (string-trim-both part char-whitespace?)))))
  373. (string-split str #\,)))
  374. (define (validate-quality-list l)
  375. (list-of? l
  376. (lambda (elt)
  377. (and (pair? elt)
  378. (valid-quality? (car elt))
  379. (string? (cdr elt))))))
  380. (define (write-quality-list l port)
  381. (write-list l port
  382. (lambda (x port)
  383. (let ((q (car x))
  384. (str (cdr x)))
  385. (display str port)
  386. (if (< q 1000)
  387. (begin
  388. (display ";q=" port)
  389. (write-quality q port)))))
  390. ","))
  391. (define* (parse-non-negative-integer val #:optional (start 0)
  392. (end (string-length val)))
  393. (define (char->decimal c)
  394. (let ((i (- (char->integer c) (char->integer #\0))))
  395. (if (and (<= 0 i) (< i 10))
  396. i
  397. (bad-header-component 'non-negative-integer val))))
  398. (if (not (< start end))
  399. (bad-header-component 'non-negative-integer val)
  400. (let lp ((i start) (out 0))
  401. (if (< i end)
  402. (lp (1+ i)
  403. (+ (* out 10) (char->decimal (string-ref val i))))
  404. out))))
  405. (define (non-negative-integer? code)
  406. (and (number? code) (>= code 0) (exact? code) (integer? code)))
  407. (define (default-val-parser k val)
  408. val)
  409. (define (default-val-validator k val)
  410. (string? val))
  411. (define (default-val-writer k val port)
  412. (if (or (string-index val #\;)
  413. (string-index val #\,)
  414. (string-index val #\"))
  415. (write-qstring val port)
  416. (display val port)))
  417. (define* (parse-key-value-list str #:optional
  418. (val-parser default-val-parser)
  419. (start 0) (end (string-length str)))
  420. (let lp ((i start) (out '()))
  421. (if (not (< i end))
  422. (reverse! out)
  423. (let* ((i (skip-whitespace str i end))
  424. (eq (string-index str #\= i end))
  425. (comma (string-index str #\, i end))
  426. (delim (min (or eq end) (or comma end)))
  427. (k (string->symbol
  428. (substring str i (trim-whitespace str i delim)))))
  429. (call-with-values
  430. (lambda ()
  431. (if (and eq (or (not comma) (< eq comma)))
  432. (let ((i (skip-whitespace str (1+ eq) end)))
  433. (if (and (< i end) (eqv? (string-ref str i) #\"))
  434. (parse-qstring str i end #:incremental? #t)
  435. (values (substring str i
  436. (trim-whitespace str i
  437. (or comma end)))
  438. (or comma end))))
  439. (values #f delim)))
  440. (lambda (v-str next-i)
  441. (let ((v (val-parser k v-str))
  442. (i (skip-whitespace str next-i end)))
  443. (if (or (= i end) (eqv? (string-ref str i) #\,))
  444. (lp (1+ i) (cons (if v (cons k v) k) out))
  445. (bad-header-component 'key-value-list
  446. (substring str start end))))))))))
  447. (define* (key-value-list? list #:optional
  448. (valid? default-val-validator))
  449. (list-of? list
  450. (lambda (elt)
  451. (cond
  452. ((pair? elt)
  453. (let ((k (car elt))
  454. (v (cdr elt)))
  455. (and (or (string? k) (symbol? k))
  456. (valid? k v))))
  457. ((or (string? elt) (symbol? elt))
  458. (valid? elt #f))
  459. (else #f)))))
  460. (define* (write-key-value-list list port #:optional
  461. (val-writer default-val-writer) (delim ", "))
  462. (write-list
  463. list port
  464. (lambda (x port)
  465. (let ((k (if (pair? x) (car x) x))
  466. (v (if (pair? x) (cdr x) #f)))
  467. (display k port)
  468. (if v
  469. (begin
  470. (display #\= port)
  471. (val-writer k v port)))))
  472. delim))
  473. ;; param-component = token [ "=" (token | quoted-string) ] \
  474. ;; *(";" token [ "=" (token | quoted-string) ])
  475. ;;
  476. (define* (parse-param-component str #:optional
  477. (val-parser default-val-parser)
  478. (start 0) (end (string-length str)))
  479. (let lp ((i start) (out '()))
  480. (if (not (< i end))
  481. (values (reverse! out) end)
  482. (let ((delim (string-index str
  483. (lambda (c) (memq c '(#\, #\; #\=)))
  484. i)))
  485. (let ((k (string->symbol
  486. (substring str i (trim-whitespace str i (or delim end)))))
  487. (delimc (and delim (string-ref str delim))))
  488. (case delimc
  489. ((#\=)
  490. (call-with-values
  491. (lambda ()
  492. (let ((i (skip-whitespace str (1+ delim) end)))
  493. (if (and (< i end) (eqv? (string-ref str i) #\"))
  494. (parse-qstring str i end #:incremental? #t)
  495. (let ((delim
  496. (or (string-index
  497. str
  498. (lambda (c)
  499. (or (eqv? c #\;)
  500. (eqv? c #\,)
  501. (char-whitespace? c)))
  502. i end)
  503. end)))
  504. (values (substring str i delim)
  505. delim)))))
  506. (lambda (v-str next-i)
  507. (let* ((v (val-parser k v-str))
  508. (x (if v (cons k v) k))
  509. (i (skip-whitespace str next-i end)))
  510. (case (and (< i end) (string-ref str i))
  511. ((#f)
  512. (values (reverse! (cons x out)) end))
  513. ((#\;)
  514. (lp (skip-whitespace str (1+ i) end)
  515. (cons x out)))
  516. (else ; including #\,
  517. (values (reverse! (cons x out)) i)))))))
  518. ((#\;)
  519. (let ((v (val-parser k #f)))
  520. (lp (skip-whitespace str (1+ delim) end)
  521. (cons (if v (cons k v) k) out))))
  522. (else ;; either the end of the string or a #\,
  523. (let ((v (val-parser k #f)))
  524. (values (reverse! (cons (if v (cons k v) k) out))
  525. (or delim end))))))))))
  526. (define* (parse-param-list str #:optional
  527. (val-parser default-val-parser)
  528. (start 0) (end (string-length str)))
  529. (let lp ((i start) (out '()))
  530. (call-with-values
  531. (lambda () (parse-param-component str val-parser i end))
  532. (lambda (item i)
  533. (if (< i end)
  534. (if (eqv? (string-ref str i) #\,)
  535. (lp (skip-whitespace str (1+ i) end)
  536. (cons item out))
  537. (bad-header-component 'param-list str))
  538. (reverse! (cons item out)))))))
  539. (define* (validate-param-list list #:optional
  540. (valid? default-val-validator))
  541. (list-of? list
  542. (lambda (elt)
  543. (key-value-list? list valid?))))
  544. (define* (write-param-list list port #:optional
  545. (val-writer default-val-writer))
  546. (write-list
  547. list port
  548. (lambda (item port)
  549. (write-key-value-list item port val-writer ";"))
  550. ","))
  551. (define (parse-date str)
  552. ;; Unfortunately, there is no way to make string->date parse out the
  553. ;; "GMT" bit, so we play string games to append a format it will
  554. ;; understand (the +0000 bit).
  555. (string->date
  556. (if (string-suffix? " GMT" str)
  557. (string-append (substring str 0 (- (string-length str) 4))
  558. " +0000")
  559. (bad-header-component 'date str))
  560. "~a, ~d ~b ~Y ~H:~M:~S ~z"))
  561. (define (write-date date port)
  562. (display (date->string date "~a, ~d ~b ~Y ~H:~M:~S GMT") port))
  563. (define (write-uri uri port)
  564. (display (uri->string uri) port))
  565. (define (parse-entity-tag val)
  566. (if (string-prefix? "W/" val)
  567. (cons (parse-qstring val 2) #f)
  568. (cons (parse-qstring val) #t)))
  569. (define (entity-tag? val)
  570. (and (pair? val)
  571. (string? (car val))))
  572. (define (write-entity-tag val port)
  573. (if (not (cdr val))
  574. (display "W/" port))
  575. (write-qstring (car val) port))
  576. (define* (parse-entity-tag-list val #:optional
  577. (start 0) (end (string-length val)))
  578. (let ((strong? (not (string-prefix? "W/" val 0 2 start end))))
  579. (call-with-values (lambda ()
  580. (parse-qstring val (if strong? start (+ start 2))
  581. end #:incremental? #t))
  582. (lambda (tag next)
  583. (acons tag strong?
  584. (let ((next (skip-whitespace val next end)))
  585. (if (< next end)
  586. (if (eqv? (string-ref val next) #\,)
  587. (parse-entity-tag-list
  588. val
  589. (skip-whitespace val (1+ next) end)
  590. end)
  591. (bad-header-component 'entity-tag-list val))
  592. '())))))))
  593. (define (entity-tag-list? val)
  594. (list-of? val entity-tag?))
  595. (define (write-entity-tag-list val port)
  596. (write-list val port write-entity-tag ", "))
  597. ;; credentials = auth-scheme #auth-param
  598. ;; auth-scheme = token
  599. ;; auth-param = token "=" ( token | quoted-string )
  600. ;;
  601. ;; That's what the spec says. In reality the Basic scheme doesn't have
  602. ;; k-v pairs, just one auth token, so we give that token as a string.
  603. ;;
  604. (define* (parse-credentials str #:optional (val-parser default-val-parser)
  605. (start 0) (end (string-length str)))
  606. (let* ((start (skip-whitespace str start end))
  607. (delim (or (string-index str char-whitespace? start end) end)))
  608. (if (= start end)
  609. (bad-header-component 'authorization str))
  610. (let ((scheme (string->symbol
  611. (string-downcase (substring str start (or delim end))))))
  612. (case scheme
  613. ((basic)
  614. (let* ((start (skip-whitespace str delim end)))
  615. (if (< start end)
  616. (cons scheme (substring str start end))
  617. (bad-header-component 'credentials str))))
  618. (else
  619. (cons scheme (parse-key-value-list str default-val-parser delim end)))))))
  620. (define (validate-credentials val)
  621. (and (pair? val) (symbol? (car val)) (key-value-list? (cdr val))))
  622. (define (write-credentials val port)
  623. (display (car val) port)
  624. (if (pair? (cdr val))
  625. (begin
  626. (display #\space port)
  627. (write-key-value-list (cdr val) port))))
  628. ;; challenges = 1#challenge
  629. ;; challenge = auth-scheme 1*SP 1#auth-param
  630. ;;
  631. ;; A pain to parse, as both challenges and auth params are delimited by
  632. ;; commas, and qstrings can contain anything. We rely on auth params
  633. ;; necessarily having "=" in them.
  634. ;;
  635. (define* (parse-challenge str #:optional
  636. (start 0) (end (string-length str)))
  637. (let* ((start (skip-whitespace str start end))
  638. (sp (string-index str #\space start end))
  639. (scheme (if sp
  640. (string->symbol (string-downcase (substring str start sp)))
  641. (bad-header-component 'challenge str))))
  642. (let lp ((i sp) (out (list scheme)))
  643. (if (not (< i end))
  644. (values (reverse! out) end)
  645. (let* ((i (skip-whitespace str i end))
  646. (eq (string-index str #\= i end))
  647. (comma (string-index str #\, i end))
  648. (delim (min (or eq end) (or comma end)))
  649. (token-end (trim-whitespace str i delim)))
  650. (if (string-index str #\space i token-end)
  651. (values (reverse! out) i)
  652. (let ((k (string->symbol (substring str i token-end))))
  653. (call-with-values
  654. (lambda ()
  655. (if (and eq (or (not comma) (< eq comma)))
  656. (let ((i (skip-whitespace str (1+ eq) end)))
  657. (if (and (< i end) (eqv? (string-ref str i) #\"))
  658. (parse-qstring str i end #:incremental? #t)
  659. (values (substring
  660. str i
  661. (trim-whitespace str i
  662. (or comma end)))
  663. (or comma end))))
  664. (values #f delim)))
  665. (lambda (v next-i)
  666. (let ((i (skip-whitespace str next-i end)))
  667. (if (or (= i end) (eqv? (string-ref str i) #\,))
  668. (lp (1+ i) (cons (if v (cons k v) k) out))
  669. (bad-header-component
  670. 'challenge
  671. (substring str start end)))))))))))))
  672. (define* (parse-challenges str #:optional (val-parser default-val-parser)
  673. (start 0) (end (string-length str)))
  674. (let lp ((i start) (ret '()))
  675. (let ((i (skip-whitespace str i end)))
  676. (if (< i end)
  677. (call-with-values (lambda () (parse-challenge str i end))
  678. (lambda (challenge i)
  679. (lp i (cons challenge ret))))
  680. (reverse ret)))))
  681. (define (validate-challenges val)
  682. (list-of? val (lambda (x)
  683. (and (pair? x) (symbol? (car x))
  684. (key-value-list? (cdr x))))))
  685. (define (write-challenge val port)
  686. (display (car val) port)
  687. (display #\space port)
  688. (write-key-value-list (cdr val) port))
  689. (define (write-challenges val port)
  690. (write-list val port write-challenge ", "))
  691. ;;;
  692. ;;; Request-Line and Response-Line
  693. ;;;
  694. ;; Hmm.
  695. (define (bad-request message . args)
  696. (throw 'bad-request message args))
  697. (define (bad-response message . args)
  698. (throw 'bad-response message args))
  699. (define *known-versions* '())
  700. (define* (parse-http-version str #:optional (start 0) (end (string-length str)))
  701. "Parse an HTTP version from @var{str}, returning it as a major-minor
  702. pair. For example, @code{HTTP/1.1} parses as the pair of integers,
  703. @code{(1 . 1)}."
  704. (or (let lp ((known *known-versions*))
  705. (and (pair? known)
  706. (if (string= str (caar known) start end)
  707. (cdar known)
  708. (lp (cdr known)))))
  709. (let ((dot-idx (string-index str #\. start end)))
  710. (if (and (string-prefix? "HTTP/" str 0 5 start end)
  711. dot-idx
  712. (= dot-idx (string-rindex str #\. start end)))
  713. (cons (parse-non-negative-integer str (+ start 5) dot-idx)
  714. (parse-non-negative-integer str (1+ dot-idx) end))
  715. (bad-header-component 'http-version (substring str start end))))))
  716. (define (write-http-version val port)
  717. "Write the given major-minor version pair to @var{port}."
  718. (display "HTTP/" port)
  719. (display (car val) port)
  720. (display #\. port)
  721. (display (cdr val) port))
  722. (for-each
  723. (lambda (v)
  724. (set! *known-versions*
  725. (acons v (parse-http-version v 0 (string-length v))
  726. *known-versions*)))
  727. '("HTTP/1.0" "HTTP/1.1"))
  728. ;; Request-URI = "*" | absoluteURI | abs_path | authority
  729. ;;
  730. ;; The `authority' form is only permissible for the CONNECT method, so
  731. ;; because we don't expect people to implement CONNECT, we save
  732. ;; ourselves the trouble of that case, and disallow the CONNECT method.
  733. ;;
  734. (define* (parse-http-method str #:optional (start 0) (end (string-length str)))
  735. "Parse an HTTP method from @var{str}. The result is an upper-case
  736. symbol, like @code{GET}."
  737. (cond
  738. ((string= str "GET" start end) 'GET)
  739. ((string= str "HEAD" start end) 'HEAD)
  740. ((string= str "POST" start end) 'POST)
  741. ((string= str "PUT" start end) 'PUT)
  742. ((string= str "DELETE" start end) 'DELETE)
  743. ((string= str "OPTIONS" start end) 'OPTIONS)
  744. ((string= str "TRACE" start end) 'TRACE)
  745. (else (bad-request "Invalid method: ~a" (substring str start end)))))
  746. (define* (parse-request-uri str #:optional (start 0) (end (string-length str)))
  747. "Parse a URI from an HTTP request line. Note that URIs in requests do
  748. not have to have a scheme or host name. The result is a URI object."
  749. (cond
  750. ((= start end)
  751. (bad-request "Missing Request-URI"))
  752. ((string= str "*" start end)
  753. #f)
  754. ((eq? (string-ref str start) #\/)
  755. (let* ((q (string-index str #\? start end))
  756. (f (string-index str #\# start end))
  757. (q (and q (or (not f) (< q f)) q)))
  758. (build-uri 'http
  759. #:path (substring str start (or q f end))
  760. #:query (and q (substring str (1+ q) (or f end)))
  761. #:fragment (and f (substring str (1+ f) end)))))
  762. (else
  763. (or (string->uri (substring str start end))
  764. (bad-request "Invalid URI: ~a" (substring str start end))))))
  765. (define (read-request-line port)
  766. "Read the first line of an HTTP request from @var{port}, returning
  767. three values: the method, the URI, and the version."
  768. (let* ((line (read-line* port))
  769. (d0 (string-index line char-whitespace?)) ; "delimiter zero"
  770. (d1 (string-rindex line char-whitespace?)))
  771. (if (and d0 d1 (< d0 d1))
  772. (values (parse-http-method line 0 d0)
  773. (parse-request-uri line (skip-whitespace line (1+ d0) d1) d1)
  774. (parse-http-version line (1+ d1) (string-length line)))
  775. (bad-request "Bad Request-Line: ~s" line))))
  776. (define (write-uri uri port)
  777. (if (uri-host uri)
  778. (begin
  779. (display (uri-scheme uri) port)
  780. (display "://" port)
  781. (if (uri-userinfo uri)
  782. (begin
  783. (display (uri-userinfo uri) port)
  784. (display #\@ port)))
  785. (display (uri-host uri) port)
  786. (let ((p (uri-port uri)))
  787. (if (and p (not (eqv? p 80)))
  788. (begin
  789. (display #\: port)
  790. (display p port))))))
  791. (let* ((path (uri-path uri))
  792. (len (string-length path)))
  793. (cond
  794. ((and (> len 0) (not (eqv? (string-ref path 0) #\/)))
  795. (bad-request "Non-absolute URI path: ~s" path))
  796. ((and (zero? len) (not (uri-host uri)))
  797. (bad-request "Empty path and no host for URI: ~s" uri))
  798. (else
  799. (display path port))))
  800. (if (uri-query uri)
  801. (begin
  802. (display #\? port)
  803. (display (uri-query uri) port))))
  804. (define (write-request-line method uri version port)
  805. "Write the first line of an HTTP request to @var{port}."
  806. (display method port)
  807. (display #\space port)
  808. (write-uri uri port)
  809. (display #\space port)
  810. (write-http-version version port)
  811. (display "\r\n" port))
  812. (define (read-response-line port)
  813. "Read the first line of an HTTP response from @var{port}, returning
  814. three values: the HTTP version, the response code, and the \"reason
  815. phrase\"."
  816. (let* ((line (read-line* port))
  817. (d0 (string-index line char-whitespace?)) ; "delimiter zero"
  818. (d1 (and d0 (string-index line char-whitespace?
  819. (skip-whitespace line d0)))))
  820. (if (and d0 d1)
  821. (values (parse-http-version line 0 d0)
  822. (parse-non-negative-integer line (skip-whitespace line d0 d1)
  823. d1)
  824. (string-trim-both line char-whitespace? d1))
  825. (bad-response "Bad Response-Line: ~s" line))))
  826. (define (write-response-line version code reason-phrase port)
  827. "Write the first line of an HTTP response to @var{port}."
  828. (write-http-version version port)
  829. (display #\space port)
  830. (display code port)
  831. (display #\space port)
  832. (display reason-phrase port)
  833. (display "\r\n" port))
  834. ;;;
  835. ;;; Helpers for declaring headers
  836. ;;;
  837. ;; emacs: (put 'declare-header! 'scheme-indent-function 1)
  838. ;; emacs: (put 'declare-opaque!-header 'scheme-indent-function 1)
  839. (define (declare-opaque-header! name)
  840. (declare-header! name
  841. parse-opaque-string validate-opaque-string write-opaque-string))
  842. ;; emacs: (put 'declare-date-header! 'scheme-indent-function 1)
  843. (define (declare-date-header! name)
  844. (declare-header! name
  845. parse-date date? write-date))
  846. ;; emacs: (put 'declare-string-list-header! 'scheme-indent-function 1)
  847. (define (declare-string-list-header! name)
  848. (declare-header! name
  849. split-and-trim list-of-strings? write-list-of-strings))
  850. ;; emacs: (put 'declare-symbol-list-header! 'scheme-indent-function 1)
  851. (define (declare-symbol-list-header! name)
  852. (declare-header! name
  853. (lambda (str)
  854. (map string->symbol (split-and-trim str)))
  855. (lambda (v)
  856. (list-of? symbol? v))
  857. (lambda (v port)
  858. (write-list v port display ", "))))
  859. ;; emacs: (put 'declare-header-list-header! 'scheme-indent-function 1)
  860. (define (declare-header-list-header! name)
  861. (declare-header! name
  862. split-header-names list-of-header-names? write-header-list))
  863. ;; emacs: (put 'declare-integer-header! 'scheme-indent-function 1)
  864. (define (declare-integer-header! name)
  865. (declare-header! name
  866. parse-non-negative-integer non-negative-integer? display))
  867. ;; emacs: (put 'declare-uri-header! 'scheme-indent-function 1)
  868. (define (declare-uri-header! name)
  869. (declare-header! name
  870. (lambda (str) (or (string->uri str) (bad-header-component 'uri str)))
  871. uri?
  872. write-uri))
  873. ;; emacs: (put 'declare-quality-list-header! 'scheme-indent-function 1)
  874. (define (declare-quality-list-header! name)
  875. (declare-header! name
  876. parse-quality-list validate-quality-list write-quality-list))
  877. ;; emacs: (put 'declare-param-list-header! 'scheme-indent-function 1)
  878. (define* (declare-param-list-header! name #:optional
  879. (val-parser default-val-parser)
  880. (val-validator default-val-validator)
  881. (val-writer default-val-writer))
  882. (declare-header! name
  883. (lambda (str) (parse-param-list str val-parser))
  884. (lambda (val) (validate-param-list val val-validator))
  885. (lambda (val port) (write-param-list val port val-writer))))
  886. ;; emacs: (put 'declare-key-value-list-header! 'scheme-indent-function 1)
  887. (define* (declare-key-value-list-header! name #:optional
  888. (val-parser default-val-parser)
  889. (val-validator default-val-validator)
  890. (val-writer default-val-writer))
  891. (declare-header! name
  892. (lambda (str) (parse-key-value-list str val-parser))
  893. (lambda (val) (key-value-list? val val-validator))
  894. (lambda (val port) (write-key-value-list val port val-writer))))
  895. ;; emacs: (put 'declare-entity-tag-list-header! 'scheme-indent-function 1)
  896. (define (declare-entity-tag-list-header! name)
  897. (declare-header! name
  898. (lambda (str) (if (string=? str "*") '* (parse-entity-tag-list str)))
  899. (lambda (val) (or (eq? val '*) (entity-tag-list? val)))
  900. (lambda (val port)
  901. (if (eq? val '*)
  902. (display "*" port)
  903. (write-entity-tag-list val port)))))
  904. ;; emacs: (put 'declare-credentials-header! 'scheme-indent-function 1)
  905. (define (declare-credentials-header! name)
  906. (declare-header! name
  907. parse-credentials validate-credentials write-credentials))
  908. ;; emacs: (put 'declare-challenge-list-header! 'scheme-indent-function 1)
  909. (define (declare-challenge-list-header! name)
  910. (declare-header! name
  911. parse-challenges validate-challenges write-challenges))
  912. ;;;
  913. ;;; General headers
  914. ;;;
  915. ;; Cache-Control = 1#(cache-directive)
  916. ;; cache-directive = cache-request-directive | cache-response-directive
  917. ;; cache-request-directive =
  918. ;; "no-cache" ; Section 14.9.1
  919. ;; | "no-store" ; Section 14.9.2
  920. ;; | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
  921. ;; | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
  922. ;; | "min-fresh" "=" delta-seconds ; Section 14.9.3
  923. ;; | "no-transform" ; Section 14.9.5
  924. ;; | "only-if-cached" ; Section 14.9.4
  925. ;; | cache-extension ; Section 14.9.6
  926. ;; cache-response-directive =
  927. ;; "public" ; Section 14.9.1
  928. ;; | "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
  929. ;; | "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
  930. ;; | "no-store" ; Section 14.9.2
  931. ;; | "no-transform" ; Section 14.9.5
  932. ;; | "must-revalidate" ; Section 14.9.4
  933. ;; | "proxy-revalidate" ; Section 14.9.4
  934. ;; | "max-age" "=" delta-seconds ; Section 14.9.3
  935. ;; | "s-maxage" "=" delta-seconds ; Section 14.9.3
  936. ;; | cache-extension ; Section 14.9.6
  937. ;; cache-extension = token [ "=" ( token | quoted-string ) ]
  938. ;;
  939. (declare-key-value-list-header! "Cache-Control"
  940. (lambda (k v-str)
  941. (case k
  942. ((max-age max-stale min-fresh s-maxage)
  943. (parse-non-negative-integer v-str))
  944. ((private no-cache)
  945. (and v-str (split-header-names v-str)))
  946. (else v-str)))
  947. default-val-validator
  948. (lambda (k v port)
  949. (cond
  950. ((string? v) (display v port))
  951. ((pair? v)
  952. (display #\" port)
  953. (write-header-list v port)
  954. (display #\" port))
  955. ((integer? v)
  956. (display v port))
  957. (else
  958. (bad-header-component 'cache-control v)))))
  959. ;; Connection = "Connection" ":" 1#(connection-token)
  960. ;; connection-token = token
  961. ;; e.g.
  962. ;; Connection: close, foo-header
  963. ;;
  964. (declare-header-list-header! "Connection")
  965. ;; Date = "Date" ":" HTTP-date
  966. ;; e.g.
  967. ;; Date: Tue, 15 Nov 1994 08:12:31 GMT
  968. ;;
  969. (declare-date-header! "Date")
  970. ;; Pragma = "Pragma" ":" 1#pragma-directive
  971. ;; pragma-directive = "no-cache" | extension-pragma
  972. ;; extension-pragma = token [ "=" ( token | quoted-string ) ]
  973. ;;
  974. (declare-key-value-list-header! "Pragma")
  975. ;; Trailer = "Trailer" ":" 1#field-name
  976. ;;
  977. (declare-header-list-header! "Trailer")
  978. ;; Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
  979. ;;
  980. (declare-param-list-header! "Transfer-Encoding")
  981. ;; Upgrade = "Upgrade" ":" 1#product
  982. ;;
  983. (declare-string-list-header! "Upgrade")
  984. ;; Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
  985. ;; received-protocol = [ protocol-name "/" ] protocol-version
  986. ;; protocol-name = token
  987. ;; protocol-version = token
  988. ;; received-by = ( host [ ":" port ] ) | pseudonym
  989. ;; pseudonym = token
  990. ;;
  991. (declare-header! "Via"
  992. split-and-trim
  993. list-of-strings?
  994. write-list-of-strings
  995. #:multiple? #t)
  996. ;; Warning = "Warning" ":" 1#warning-value
  997. ;;
  998. ;; warning-value = warn-code SP warn-agent SP warn-text
  999. ;; [SP warn-date]
  1000. ;;
  1001. ;; warn-code = 3DIGIT
  1002. ;; warn-agent = ( host [ ":" port ] ) | pseudonym
  1003. ;; ; the name or pseudonym of the server adding
  1004. ;; ; the Warning header, for use in debugging
  1005. ;; warn-text = quoted-string
  1006. ;; warn-date = <"> HTTP-date <">
  1007. (declare-header! "Warning"
  1008. (lambda (str)
  1009. (let ((len (string-length str)))
  1010. (let lp ((i (skip-whitespace str 0)))
  1011. (let* ((idx1 (string-index str #\space i))
  1012. (idx2 (string-index str #\space (1+ idx1))))
  1013. (if (and idx1 idx2)
  1014. (let ((code (parse-non-negative-integer str i idx1))
  1015. (agent (substring str (1+ idx1) idx2)))
  1016. (call-with-values
  1017. (lambda () (parse-qstring str (1+ idx2) #:incremental? #t))
  1018. (lambda (text i)
  1019. (call-with-values
  1020. (lambda ()
  1021. (let ((c (and (< i len) (string-ref str i))))
  1022. (case c
  1023. ((#\space)
  1024. ;; we have a date.
  1025. (call-with-values
  1026. (lambda () (parse-qstring str (1+ i)
  1027. #:incremental? #t))
  1028. (lambda (date i)
  1029. (values text (parse-date date) i))))
  1030. (else
  1031. (values text #f i)))))
  1032. (lambda (text date i)
  1033. (let ((w (list code agent text date))
  1034. (c (and (< i len) (string-ref str i))))
  1035. (case c
  1036. ((#f) (list w))
  1037. ((#\,) (cons w (lp (skip-whitespace str (1+ i)))))
  1038. (else (bad-header 'warning str))))))))))))))
  1039. (lambda (val)
  1040. (list-of? val
  1041. (lambda (elt)
  1042. (and (list? elt)
  1043. (= (length elt) 4)
  1044. (apply (lambda (code host text date)
  1045. (and (non-negative-integer? code) (< code 1000)
  1046. (string? host)
  1047. (string? text)
  1048. (or (not date) (date? date))))
  1049. elt)))))
  1050. (lambda (val port)
  1051. (write-list
  1052. val port
  1053. (lambda (w port)
  1054. (apply
  1055. (lambda (code host text date)
  1056. (display code port)
  1057. (display #\space port)
  1058. (display host port)
  1059. (display #\space port)
  1060. (write-qstring text port)
  1061. (if date
  1062. (begin
  1063. (display #\space port)
  1064. (write-date date port))))
  1065. w))
  1066. ", "))
  1067. #:multiple? #t)
  1068. ;;;
  1069. ;;; Entity headers
  1070. ;;;
  1071. ;; Allow = #Method
  1072. ;;
  1073. (declare-symbol-list-header! "Allow")
  1074. ;; Content-Encoding = 1#content-coding
  1075. ;;
  1076. (declare-symbol-list-header! "Content-Encoding")
  1077. ;; Content-Language = 1#language-tag
  1078. ;;
  1079. (declare-string-list-header! "Content-Language")
  1080. ;; Content-Length = 1*DIGIT
  1081. ;;
  1082. (declare-integer-header! "Content-Length")
  1083. ;; Content-Location = ( absoluteURI | relativeURI )
  1084. ;;
  1085. (declare-uri-header! "Content-Location")
  1086. ;; Content-MD5 = <base64 of 128 bit MD5 digest as per RFC 1864>
  1087. ;;
  1088. (declare-opaque-header! "Content-MD5")
  1089. ;; Content-Range = content-range-spec
  1090. ;; content-range-spec = byte-content-range-spec
  1091. ;; byte-content-range-spec = bytes-unit SP
  1092. ;; byte-range-resp-spec "/"
  1093. ;; ( instance-length | "*" )
  1094. ;; byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
  1095. ;; | "*"
  1096. ;; instance-length = 1*DIGIT
  1097. ;;
  1098. (declare-header! "Content-Range"
  1099. (lambda (str)
  1100. (let ((dash (string-index str #\-))
  1101. (slash (string-index str #\/)))
  1102. (if (and (string-prefix? "bytes " str) slash)
  1103. (list 'bytes
  1104. (cond
  1105. (dash
  1106. (cons
  1107. (parse-non-negative-integer str 6 dash)
  1108. (parse-non-negative-integer str (1+ dash) slash)))
  1109. ((string= str "*" 6 slash)
  1110. '*)
  1111. (else
  1112. (bad-header 'content-range str)))
  1113. (if (string= str "*" (1+ slash))
  1114. '*
  1115. (parse-non-negative-integer str (1+ slash))))
  1116. (bad-header 'content-range str))))
  1117. (lambda (val)
  1118. (and (list? val) (= (length val) 3)
  1119. (symbol? (car val))
  1120. (let ((x (cadr val)))
  1121. (or (eq? x '*)
  1122. (and (pair? x)
  1123. (non-negative-integer? (car x))
  1124. (non-negative-integer? (cdr x)))))
  1125. (let ((x (caddr val)))
  1126. (or (eq? x '*)
  1127. (non-negative-integer? x)))))
  1128. (lambda (val port)
  1129. (display (car val) port)
  1130. (display #\space port)
  1131. (if (eq? (cadr val) '*)
  1132. (display #\* port)
  1133. (begin
  1134. (display (caadr val) port)
  1135. (display #\- port)
  1136. (display (caadr val) port)))
  1137. (if (eq? (caddr val) '*)
  1138. (display #\* port)
  1139. (display (caddr val) port))))
  1140. ;; Content-Type = media-type
  1141. ;;
  1142. (declare-header! "Content-Type"
  1143. (lambda (str)
  1144. (let ((parts (string-split str #\;)))
  1145. (cons (parse-media-type (car parts))
  1146. (map (lambda (x)
  1147. (let ((eq (string-index x #\=)))
  1148. (if (and eq (= eq (string-rindex x #\=)))
  1149. (cons (string->symbol
  1150. (string-trim x char-whitespace? 0 eq))
  1151. (string-trim-right x char-whitespace? (1+ eq)))
  1152. (bad-header 'content-type str))))
  1153. (cdr parts)))))
  1154. (lambda (val)
  1155. (and (pair? val)
  1156. (symbol? (car val))
  1157. (list-of? (cdr val)
  1158. (lambda (x)
  1159. (and (pair? x) (symbol? (car x)) (string? (cdr x)))))))
  1160. (lambda (val port)
  1161. (display (car val) port)
  1162. (if (pair? (cdr val))
  1163. (begin
  1164. (display ";" port)
  1165. (write-list
  1166. (cdr val) port
  1167. (lambda (pair port)
  1168. (display (car pair) port)
  1169. (display #\= port)
  1170. (display (cdr pair) port))
  1171. ";")))))
  1172. ;; Expires = HTTP-date
  1173. ;;
  1174. (declare-date-header! "Expires")
  1175. ;; Last-Modified = HTTP-date
  1176. ;;
  1177. (declare-date-header! "Last-Modified")
  1178. ;;;
  1179. ;;; Request headers
  1180. ;;;
  1181. ;; Accept = #( media-range [ accept-params ] )
  1182. ;; media-range = ( "*/*" | ( type "/" "*" ) | ( type "/" subtype ) )
  1183. ;; *( ";" parameter )
  1184. ;; accept-params = ";" "q" "=" qvalue *( accept-extension )
  1185. ;; accept-extension = ";" token [ "=" ( token | quoted-string ) ]
  1186. ;;
  1187. (declare-param-list-header! "Accept"
  1188. ;; -> (type/subtype (sym-prop . str-val) ...) ...)
  1189. ;;
  1190. ;; with the exception of prop `q', in which case the val will be a
  1191. ;; valid quality value
  1192. ;;
  1193. (lambda (k v)
  1194. (if (eq? k 'q)
  1195. (parse-quality v)
  1196. v))
  1197. (lambda (k v)
  1198. (if (eq? k 'q)
  1199. (valid-quality? v)
  1200. (string? v)))
  1201. (lambda (k v port)
  1202. (if (eq? k 'q)
  1203. (write-quality v port)
  1204. (default-val-writer k v port))))
  1205. ;; Accept-Charset = 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
  1206. ;;
  1207. (declare-quality-list-header! "Accept-Charset")
  1208. ;; Accept-Encoding = 1#( codings [ ";" "q" "=" qvalue ] )
  1209. ;; codings = ( content-coding | "*" )
  1210. ;;
  1211. (declare-quality-list-header! "Accept-Encoding")
  1212. ;; Accept-Language = 1#( language-range [ ";" "q" "=" qvalue ] )
  1213. ;; language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
  1214. ;;
  1215. (declare-quality-list-header! "Accept-Language")
  1216. ;; Authorization = credentials
  1217. ;; credentials = auth-scheme #auth-param
  1218. ;; auth-scheme = token
  1219. ;; auth-param = token "=" ( token | quoted-string )
  1220. ;;
  1221. (declare-credentials-header! "Authorization")
  1222. ;; Expect = 1#expectation
  1223. ;; expectation = "100-continue" | expectation-extension
  1224. ;; expectation-extension = token [ "=" ( token | quoted-string )
  1225. ;; *expect-params ]
  1226. ;; expect-params = ";" token [ "=" ( token | quoted-string ) ]
  1227. ;;
  1228. (declare-param-list-header! "Expect")
  1229. ;; From = mailbox
  1230. ;;
  1231. ;; Should be an email address; we just pass on the string as-is.
  1232. ;;
  1233. (declare-opaque-header! "From")
  1234. ;; Host = host [ ":" port ]
  1235. ;;
  1236. (declare-header! "Host"
  1237. (lambda (str)
  1238. (let ((colon (string-index str #\:)))
  1239. (if colon
  1240. (cons (substring str 0 colon)
  1241. (parse-non-negative-integer str (1+ colon)))
  1242. (cons str #f))))
  1243. (lambda (val)
  1244. (and (pair? val)
  1245. (string? (car val))
  1246. (or (not (cdr val))
  1247. (non-negative-integer? (cdr val)))))
  1248. (lambda (val port)
  1249. (display (car val) port)
  1250. (if (cdr val)
  1251. (begin
  1252. (display #\: port)
  1253. (display (cdr val) port)))))
  1254. ;; If-Match = ( "*" | 1#entity-tag )
  1255. ;;
  1256. (declare-entity-tag-list-header! "If-Match")
  1257. ;; If-Modified-Since = HTTP-date
  1258. ;;
  1259. (declare-date-header! "If-Modified-Since")
  1260. ;; If-None-Match = ( "*" | 1#entity-tag )
  1261. ;;
  1262. (declare-entity-tag-list-header! "If-None-Match")
  1263. ;; If-Range = ( entity-tag | HTTP-date )
  1264. ;;
  1265. (declare-header! "If-Range"
  1266. (lambda (str)
  1267. (if (or (string-prefix? "\"" str)
  1268. (string-prefix? "W/" str))
  1269. (parse-entity-tag str)
  1270. (parse-date str)))
  1271. (lambda (val)
  1272. (or (date? val) (entity-tag? val)))
  1273. (lambda (val port)
  1274. (if (date? val)
  1275. (write-date val port)
  1276. (write-entity-tag val port))))
  1277. ;; If-Unmodified-Since = HTTP-date
  1278. ;;
  1279. (declare-date-header! "If-Unmodified-Since")
  1280. ;; Max-Forwards = 1*DIGIT
  1281. ;;
  1282. (declare-integer-header! "Max-Forwards")
  1283. ;; Proxy-Authorization = credentials
  1284. ;;
  1285. (declare-credentials-header! "Proxy-Authorization")
  1286. ;; Range = "Range" ":" ranges-specifier
  1287. ;; ranges-specifier = byte-ranges-specifier
  1288. ;; byte-ranges-specifier = bytes-unit "=" byte-range-set
  1289. ;; byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
  1290. ;; byte-range-spec = first-byte-pos "-" [last-byte-pos]
  1291. ;; first-byte-pos = 1*DIGIT
  1292. ;; last-byte-pos = 1*DIGIT
  1293. ;; suffix-byte-range-spec = "-" suffix-length
  1294. ;; suffix-length = 1*DIGIT
  1295. ;;
  1296. (declare-header! "Range"
  1297. (lambda (str)
  1298. (if (string-prefix? "bytes=" str)
  1299. (cons
  1300. 'bytes
  1301. (map (lambda (x)
  1302. (let ((dash (string-index x #\-)))
  1303. (cond
  1304. ((not dash)
  1305. (bad-header 'range str))
  1306. ((zero? dash)
  1307. (cons #f (parse-non-negative-integer x 1)))
  1308. ((= dash (1- (string-length x)))
  1309. (cons (parse-non-negative-integer x 0 dash) #f))
  1310. (else
  1311. (cons (parse-non-negative-integer x 0 dash)
  1312. (parse-non-negative-integer x (1+ dash)))))))
  1313. (string-split (substring str 6) #\,)))
  1314. (bad-header 'range str)))
  1315. (lambda (val)
  1316. (and (pair? val)
  1317. (symbol? (car val))
  1318. (list-of? (cdr val)
  1319. (lambda (elt)
  1320. (and (pair? elt)
  1321. (let ((x (car elt)) (y (cdr elt)))
  1322. (and (or x y)
  1323. (or (not x) (non-negative-integer? x))
  1324. (or (not y) (non-negative-integer? y)))))))))
  1325. (lambda (val port)
  1326. (display (car val) port)
  1327. (display #\= port)
  1328. (write-list
  1329. (cdr val) port
  1330. (lambda (pair port)
  1331. (if (car pair)
  1332. (display (car pair) port))
  1333. (display #\- port)
  1334. (if (cdr pair)
  1335. (display (cdr pair) port)))
  1336. ",")))
  1337. ;; Referer = ( absoluteURI | relativeURI )
  1338. ;;
  1339. (declare-uri-header! "Referer")
  1340. ;; TE = #( t-codings )
  1341. ;; t-codings = "trailers" | ( transfer-extension [ accept-params ] )
  1342. ;;
  1343. (declare-param-list-header! "TE")
  1344. ;; User-Agent = 1*( product | comment )
  1345. ;;
  1346. (declare-opaque-header! "User-Agent")
  1347. ;;;
  1348. ;;; Reponse headers
  1349. ;;;
  1350. ;; Accept-Ranges = acceptable-ranges
  1351. ;; acceptable-ranges = 1#range-unit | "none"
  1352. ;;
  1353. (declare-symbol-list-header! "Accept-Ranges")
  1354. ;; Age = age-value
  1355. ;; age-value = delta-seconds
  1356. ;;
  1357. (declare-integer-header! "Age")
  1358. ;; ETag = entity-tag
  1359. ;;
  1360. (declare-header! "ETag"
  1361. parse-entity-tag
  1362. entity-tag?
  1363. write-entity-tag)
  1364. ;; Location = absoluteURI
  1365. ;;
  1366. (declare-uri-header! "Location")
  1367. ;; Proxy-Authenticate = 1#challenge
  1368. ;;
  1369. (declare-challenge-list-header! "Proxy-Authenticate")
  1370. ;; Retry-After = ( HTTP-date | delta-seconds )
  1371. ;;
  1372. (declare-header! "Retry-After"
  1373. (lambda (str)
  1374. (if (and (not (string-null? str))
  1375. (char-numeric? (string-ref str 0)))
  1376. (parse-non-negative-integer str)
  1377. (parse-date str)))
  1378. (lambda (val)
  1379. (or (date? val) (non-negative-integer? val)))
  1380. (lambda (val port)
  1381. (if (date? val)
  1382. (write-date val port)
  1383. (display val port))))
  1384. ;; Server = 1*( product | comment )
  1385. ;;
  1386. (declare-opaque-header! "Server")
  1387. ;; Vary = ( "*" | 1#field-name )
  1388. ;;
  1389. (declare-header! "Vary"
  1390. (lambda (str)
  1391. (if (equal? str "*")
  1392. '*
  1393. (split-header-names str)))
  1394. (lambda (val)
  1395. (or (eq? val '*) (list-of-header-names? val)))
  1396. (lambda (val port)
  1397. (if (eq? val '*)
  1398. (display "*" port)
  1399. (write-header-list val port))))
  1400. ;; WWW-Authenticate = 1#challenge
  1401. ;;
  1402. (declare-challenge-list-header! "WWW-Authenticate")