http.scm 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044
  1. ;;; HTTP messages
  2. ;; Copyright (C) 2010-2017 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 rdelim)
  33. #:use-module (ice-9 match)
  34. #:use-module (ice-9 q)
  35. #:use-module (ice-9 binary-ports)
  36. #:use-module (ice-9 textual-ports)
  37. #:use-module (rnrs bytevectors)
  38. #:use-module (web uri)
  39. #:export (string->header
  40. header->string
  41. declare-header!
  42. declare-opaque-header!
  43. known-header?
  44. header-parser
  45. header-validator
  46. header-writer
  47. read-header
  48. parse-header
  49. valid-header?
  50. write-header
  51. read-headers
  52. write-headers
  53. parse-http-method
  54. parse-http-version
  55. parse-request-uri
  56. read-request-line
  57. write-request-line
  58. read-response-line
  59. write-response-line
  60. make-chunked-input-port
  61. make-chunked-output-port
  62. http-proxy-port?
  63. set-http-proxy-port?!))
  64. (define (put-symbol port sym)
  65. (put-string port (symbol->string sym)))
  66. (define (put-non-negative-integer port i)
  67. (put-string port (number->string i)))
  68. (define (string->header name)
  69. "Parse NAME to a symbolic header name."
  70. (string->symbol (string-downcase name)))
  71. (define-record-type <header-decl>
  72. (make-header-decl name parser validator writer multiple?)
  73. header-decl?
  74. (name header-decl-name)
  75. (parser header-decl-parser)
  76. (validator header-decl-validator)
  77. (writer header-decl-writer)
  78. (multiple? header-decl-multiple?))
  79. ;; sym -> header
  80. (define *declared-headers* (make-hash-table))
  81. (define (lookup-header-decl sym)
  82. (hashq-ref *declared-headers* sym))
  83. (define* (declare-header! name
  84. parser
  85. validator
  86. writer
  87. #:key multiple?)
  88. "Declare a parser, validator, and writer for a given header."
  89. (unless (and (string? name) parser validator writer)
  90. (error "bad header decl" name parser validator writer multiple?))
  91. (let ((decl (make-header-decl name parser validator writer multiple?)))
  92. (hashq-set! *declared-headers* (string->header name) decl)
  93. decl))
  94. (define (header->string sym)
  95. "Return the string form for the header named SYM."
  96. (let ((decl (lookup-header-decl sym)))
  97. (if decl
  98. (header-decl-name decl)
  99. (string-titlecase (symbol->string sym)))))
  100. (define (known-header? sym)
  101. "Return ‘#t’ iff SYM is a known header, with associated
  102. parsers and serialization procedures."
  103. (and (lookup-header-decl sym) #t))
  104. (define (header-parser sym)
  105. "Return the value parser for headers named SYM. The result is a
  106. procedure that takes one argument, a string, and returns the parsed
  107. value. If the header isn't known to Guile, a default parser is returned
  108. that passes through the string unchanged."
  109. (let ((decl (lookup-header-decl sym)))
  110. (if decl
  111. (header-decl-parser decl)
  112. (lambda (x) x))))
  113. (define (header-validator sym)
  114. "Return a predicate which returns ‘#t’ if the given value is valid
  115. for headers named SYM. The default validator for unknown headers
  116. is ‘string?’."
  117. (let ((decl (lookup-header-decl sym)))
  118. (if decl
  119. (header-decl-validator decl)
  120. string?)))
  121. (define (header-writer sym)
  122. "Return a procedure that writes values for headers named SYM to a
  123. port. The resulting procedure takes two arguments: a value and a port.
  124. The default writer will call ‘put-string’."
  125. (let ((decl (lookup-header-decl sym)))
  126. (if decl
  127. (header-decl-writer decl)
  128. (lambda (val port)
  129. (put-string port val)))))
  130. (define (read-header-line port)
  131. "Read an HTTP header line and return it without its final CRLF or LF.
  132. Raise a 'bad-header' exception if the line does not end in CRLF or LF,
  133. or if EOF is reached."
  134. (match (%read-line port)
  135. (((? string? line) . #\newline)
  136. ;; '%read-line' does not consider #\return a delimiter; so if it's
  137. ;; there, remove it. We are more tolerant than the RFC in that we
  138. ;; tolerate LF-only endings.
  139. (if (string-suffix? "\r" line)
  140. (string-drop-right line 1)
  141. line))
  142. ((line . _) ;EOF or missing delimiter
  143. (bad-header 'read-header-line line))))
  144. (define (read-continuation-line port val)
  145. (match (peek-char port)
  146. ((or #\space #\tab)
  147. (read-continuation-line port
  148. (string-append val (read-header-line port))))
  149. (_ val)))
  150. (define *eof* (call-with-input-string "" read))
  151. (define (read-header port)
  152. "Read one HTTP header from PORT. Return two values: the header
  153. name and the parsed Scheme value. May raise an exception if the header
  154. was known but the value was invalid.
  155. Returns the end-of-file object for both values if the end of the message
  156. body was reached (i.e., a blank line)."
  157. (let ((line (read-header-line port)))
  158. (if (or (string-null? line)
  159. (string=? line "\r"))
  160. (values *eof* *eof*)
  161. (let* ((delim (or (string-index line #\:)
  162. (bad-header '%read line)))
  163. (sym (string->header (substring line 0 delim))))
  164. (values
  165. sym
  166. (parse-header
  167. sym
  168. (read-continuation-line
  169. port
  170. (string-trim-both line char-set:whitespace (1+ delim)))))))))
  171. (define (parse-header sym val)
  172. "Parse VAL, a string, with the parser registered for the header
  173. named SYM. Returns the parsed value."
  174. ((header-parser sym) val))
  175. (define (valid-header? sym val)
  176. "Returns a true value iff VAL is a valid Scheme value for the
  177. header with name SYM."
  178. (unless (symbol? sym)
  179. (error "header name not a symbol" sym))
  180. ((header-validator sym) val))
  181. (define (write-header sym val port)
  182. "Write the given header name and value to PORT, using the writer
  183. from ‘header-writer’."
  184. (put-string port (header->string sym))
  185. (put-string port ": ")
  186. ((header-writer sym) val port)
  187. (put-string port "\r\n"))
  188. (define (read-headers port)
  189. "Read the headers of an HTTP message from PORT, returning them
  190. as an ordered alist."
  191. (let lp ((headers '()))
  192. (call-with-values (lambda () (read-header port))
  193. (lambda (k v)
  194. (if (eof-object? k)
  195. (reverse! headers)
  196. (lp (acons k v headers)))))))
  197. (define (write-headers headers port)
  198. "Write the given header alist to PORT. Doesn't write the final
  199. ‘\\r\\n’, as the user might want to add another header."
  200. (let lp ((headers headers))
  201. (match headers
  202. (((k . v) . headers)
  203. (write-header k v port)
  204. (lp headers))
  205. (()
  206. (values)))))
  207. ;;;
  208. ;;; Utilities
  209. ;;;
  210. (define (bad-header sym val)
  211. (throw 'bad-header sym val))
  212. (define (bad-header-component sym val)
  213. (throw 'bad-header-component sym val))
  214. (define (bad-header-printer port key args default-printer)
  215. (apply (case-lambda
  216. ((sym val)
  217. (format port "Bad ~a header: ~a\n" (header->string sym) val))
  218. (_ (default-printer)))
  219. args))
  220. (define (bad-header-component-printer port key args default-printer)
  221. (apply (case-lambda
  222. ((sym val)
  223. (format port "Bad ~a header component: ~a\n" sym val))
  224. (_ (default-printer)))
  225. args))
  226. (set-exception-printer! 'bad-header bad-header-printer)
  227. (set-exception-printer! 'bad-header-component bad-header-component-printer)
  228. (define (parse-opaque-string str)
  229. str)
  230. (define (validate-opaque-string val)
  231. (string? val))
  232. (define (write-opaque-string val port)
  233. (put-string port val))
  234. (define separators-without-slash
  235. (string->char-set "[^][()<>@,;:\\\"?= \t]"))
  236. (define (validate-media-type str)
  237. (let ((idx (string-index str #\/)))
  238. (and idx (= idx (string-rindex str #\/))
  239. (not (string-index str separators-without-slash)))))
  240. (define (parse-media-type str)
  241. (unless (validate-media-type str)
  242. (bad-header-component 'media-type str))
  243. (string->symbol str))
  244. (define* (skip-whitespace str #:optional (start 0) (end (string-length str)))
  245. (let lp ((i start))
  246. (if (and (< i end) (char-whitespace? (string-ref str i)))
  247. (lp (1+ i))
  248. i)))
  249. (define* (trim-whitespace str #:optional (start 0) (end (string-length str)))
  250. (let lp ((i end))
  251. (if (and (< start i) (char-whitespace? (string-ref str (1- i))))
  252. (lp (1- i))
  253. i)))
  254. (define* (split-and-trim str #:optional (delim #\,)
  255. (start 0) (end (string-length str)))
  256. (let lp ((i start))
  257. (if (< i end)
  258. (let* ((idx (string-index str delim i end))
  259. (tok (string-trim-both str char-set:whitespace i (or idx end))))
  260. (cons tok (split-and-trim str delim (if idx (1+ idx) end) end)))
  261. '())))
  262. (define (list-of-strings? val)
  263. (list-of? val string?))
  264. (define (write-list-of-strings val port)
  265. (put-list port val put-string ", "))
  266. (define (split-header-names str)
  267. (map string->header (split-and-trim str)))
  268. (define (list-of-header-names? val)
  269. (list-of? val symbol?))
  270. (define (write-header-list val port)
  271. (put-list port val
  272. (lambda (port x)
  273. (put-string port (header->string x)))
  274. ", "))
  275. (define (collect-escaped-string from start len escapes)
  276. (let ((to (make-string len)))
  277. (let lp ((start start) (i 0) (escapes escapes))
  278. (match escapes
  279. (()
  280. (substring-move! from start (+ start (- len i)) to i)
  281. to)
  282. ((e . escapes)
  283. (let ((next-start (+ start (- e i) 2)))
  284. (substring-move! from start (- next-start 2) to i)
  285. (string-set! to e (string-ref from (- next-start 1)))
  286. (lp next-start (1+ e) escapes)))))))
  287. ;; in incremental mode, returns two values: the string, and the index at
  288. ;; which the string ended
  289. (define* (parse-qstring str #:optional
  290. (start 0) (end (trim-whitespace str start))
  291. #:key incremental?)
  292. (unless (and (< start end) (eqv? (string-ref str start) #\"))
  293. (bad-header-component 'qstring str))
  294. (let lp ((i (1+ start)) (qi 0) (escapes '()))
  295. (if (< i end)
  296. (case (string-ref str i)
  297. ((#\\)
  298. (lp (+ i 2) (1+ qi) (cons qi escapes)))
  299. ((#\")
  300. (let ((out (collect-escaped-string str (1+ start) qi escapes)))
  301. (cond
  302. (incremental? (values out (1+ i)))
  303. ((= (1+ i) end) out)
  304. (else (bad-header-component 'qstring str)))))
  305. (else
  306. (lp (1+ i) (1+ qi) escapes)))
  307. (bad-header-component 'qstring str))))
  308. (define (put-list port items put-item delim)
  309. (match items
  310. (() (values))
  311. ((item . items)
  312. (put-item port item)
  313. (let lp ((items items))
  314. (match items
  315. (() (values))
  316. ((item . items)
  317. (put-string port delim)
  318. (put-item port item)
  319. (lp items)))))))
  320. (define (write-qstring str port)
  321. (put-char port #\")
  322. (if (string-index str #\")
  323. ;; optimize me
  324. (put-list port (string-split str #\") put-string "\\\"")
  325. (put-string port str))
  326. (put-char port #\"))
  327. (define* (parse-quality str #:optional (start 0) (end (string-length str)))
  328. (define (char->decimal c)
  329. (let ((i (- (char->integer c) (char->integer #\0))))
  330. (unless (and (<= 0 i) (< i 10))
  331. (bad-header-component 'quality str))
  332. i))
  333. (cond
  334. ((not (< start end))
  335. (bad-header-component 'quality str))
  336. ((eqv? (string-ref str start) #\1)
  337. (unless (or (string= str "1" start end)
  338. (string= str "1." start end)
  339. (string= str "1.0" start end)
  340. (string= str "1.00" start end)
  341. (string= str "1.000" start end))
  342. (bad-header-component 'quality str))
  343. 1000)
  344. ((eqv? (string-ref str start) #\0)
  345. (if (or (string= str "0" start end)
  346. (string= str "0." start end))
  347. 0
  348. (if (< 2 (- end start) 6)
  349. (let lp ((place 1) (i (+ start 4)) (q 0))
  350. (if (= i (1+ start))
  351. (if (eqv? (string-ref str (1+ start)) #\.)
  352. q
  353. (bad-header-component 'quality str))
  354. (lp (* 10 place) (1- i)
  355. (if (< i end)
  356. (+ q (* place (char->decimal (string-ref str i))))
  357. q))))
  358. (bad-header-component 'quality str))))
  359. ;; Allow the nonstandard .2 instead of 0.2.
  360. ((and (eqv? (string-ref str start) #\.)
  361. (< 1 (- end start) 5))
  362. (let lp ((place 1) (i (+ start 3)) (q 0))
  363. (if (= i start)
  364. q
  365. (lp (* 10 place) (1- i)
  366. (if (< i end)
  367. (+ q (* place (char->decimal (string-ref str i))))
  368. q)))))
  369. (else
  370. (bad-header-component 'quality str))))
  371. (define (valid-quality? q)
  372. (and (non-negative-integer? q) (<= q 1000)))
  373. (define (write-quality q port)
  374. (define (digit->char d)
  375. (integer->char (+ (char->integer #\0) d)))
  376. (put-char port (digit->char (modulo (quotient q 1000) 10)))
  377. (put-char port #\.)
  378. (put-char port (digit->char (modulo (quotient q 100) 10)))
  379. (put-char port (digit->char (modulo (quotient q 10) 10)))
  380. (put-char port (digit->char (modulo q 10))))
  381. (define (list-of? val pred)
  382. (match val
  383. (((? pred) ...) #t)
  384. (_ #f)))
  385. (define* (parse-quality-list str)
  386. (map (lambda (part)
  387. (cond
  388. ((string-rindex part #\;)
  389. => (lambda (idx)
  390. (let ((qpart (string-trim-both part char-set:whitespace (1+ idx))))
  391. (unless (string-prefix? "q=" qpart)
  392. (bad-header-component 'quality qpart))
  393. (cons (parse-quality qpart 2)
  394. (string-trim-both part char-set:whitespace 0 idx)))))
  395. (else
  396. (cons 1000 (string-trim-both part char-set:whitespace)))))
  397. (string-split str #\,)))
  398. (define (validate-quality-list l)
  399. (match l
  400. ((((? valid-quality?) . (? string?)) ...) #t)
  401. (_ #f)))
  402. (define (write-quality-list l port)
  403. (put-list port l
  404. (lambda (port x)
  405. (let ((q (car x))
  406. (str (cdr x)))
  407. (put-string port str)
  408. (when (< q 1000)
  409. (put-string port ";q=")
  410. (write-quality q port))))
  411. ","))
  412. (define* (parse-non-negative-integer val #:optional (start 0)
  413. (end (string-length val)))
  414. (define (char->decimal c)
  415. (let ((i (- (char->integer c) (char->integer #\0))))
  416. (unless (and (<= 0 i) (< i 10))
  417. (bad-header-component 'non-negative-integer val))
  418. i))
  419. (unless (< start end)
  420. (bad-header-component 'non-negative-integer val))
  421. (let lp ((i start) (out 0))
  422. (if (< i end)
  423. (lp (1+ i)
  424. (+ (* out 10) (char->decimal (string-ref val i))))
  425. out)))
  426. (define (non-negative-integer? code)
  427. (and (number? code) (>= code 0) (exact? code) (integer? code)))
  428. (define (default-val-parser k val)
  429. val)
  430. (define (default-val-validator k val)
  431. (or (not val) (string? val)))
  432. (define (default-val-writer k val port)
  433. (if (or (string-index val #\;)
  434. (string-index val #\,)
  435. (string-index val #\"))
  436. (write-qstring val port)
  437. (put-string port val)))
  438. (define* (parse-key-value-list str #:optional
  439. (val-parser default-val-parser)
  440. (start 0) (end (string-length str)))
  441. (let lp ((i start))
  442. (if (not (< i end))
  443. '()
  444. (let* ((i (skip-whitespace str i end))
  445. (eq (string-index str #\= i end))
  446. (comma (string-index str #\, i end))
  447. (delim (min (or eq end) (or comma end)))
  448. (k (string->symbol
  449. (substring str i (trim-whitespace str i delim)))))
  450. (call-with-values
  451. (lambda ()
  452. (if (and eq (or (not comma) (< eq comma)))
  453. (let ((i (skip-whitespace str (1+ eq) end)))
  454. (if (and (< i end) (eqv? (string-ref str i) #\"))
  455. (parse-qstring str i end #:incremental? #t)
  456. (values (substring str i
  457. (trim-whitespace str i
  458. (or comma end)))
  459. (or comma end))))
  460. (values #f delim)))
  461. (lambda (v-str next-i)
  462. (let ((v (val-parser k v-str))
  463. (i (skip-whitespace str next-i end)))
  464. (unless (or (= i end) (eqv? (string-ref str i) #\,))
  465. (bad-header-component 'key-value-list
  466. (substring str start end)))
  467. (cons (if v (cons k v) k)
  468. (lp (1+ i))))))))))
  469. (define* (key-value-list? list #:optional
  470. (valid? default-val-validator))
  471. (list-of? list
  472. (lambda (elt)
  473. (match elt
  474. (((? symbol? k) . v) (valid? k v))
  475. ((? symbol? k) (valid? k #f))
  476. (_ #f)))))
  477. (define* (write-key-value-list list port #:optional
  478. (val-writer default-val-writer) (delim ", "))
  479. (put-list
  480. port list
  481. (lambda (port x)
  482. (match x
  483. ((k . #f)
  484. (put-symbol port k))
  485. ((k . v)
  486. (put-symbol port k)
  487. (put-char port #\=)
  488. (val-writer k v port))
  489. (k
  490. (put-symbol port k))))
  491. delim))
  492. ;; param-component = token [ "=" (token | quoted-string) ] \
  493. ;; *(";" token [ "=" (token | quoted-string) ])
  494. ;;
  495. (define param-delimiters (char-set #\, #\; #\=))
  496. (define param-value-delimiters (char-set-adjoin char-set:whitespace #\, #\;))
  497. (define* (parse-param-component str #:optional
  498. (val-parser default-val-parser)
  499. (start 0) (end (string-length str)))
  500. (let lp ((i start) (out '()))
  501. (if (not (< i end))
  502. (values (reverse! out) end)
  503. (let ((delim (string-index str param-delimiters i)))
  504. (let ((k (string->symbol
  505. (substring str i (trim-whitespace str i (or delim end)))))
  506. (delimc (and delim (string-ref str delim))))
  507. (case delimc
  508. ((#\=)
  509. (call-with-values
  510. (lambda ()
  511. (let ((i (skip-whitespace str (1+ delim) end)))
  512. (if (and (< i end) (eqv? (string-ref str i) #\"))
  513. (parse-qstring str i end #:incremental? #t)
  514. (let ((delim
  515. (or (string-index str param-value-delimiters
  516. i end)
  517. end)))
  518. (values (substring str i delim)
  519. delim)))))
  520. (lambda (v-str next-i)
  521. (let* ((v (val-parser k v-str))
  522. (x (if v (cons k v) k))
  523. (i (skip-whitespace str next-i end)))
  524. (case (and (< i end) (string-ref str i))
  525. ((#f)
  526. (values (reverse! (cons x out)) end))
  527. ((#\;)
  528. (lp (skip-whitespace str (1+ i) end)
  529. (cons x out)))
  530. (else ; including #\,
  531. (values (reverse! (cons x out)) i)))))))
  532. ((#\;)
  533. (let ((v (val-parser k #f)))
  534. (lp (skip-whitespace str (1+ delim) end)
  535. (cons (if v (cons k v) k) out))))
  536. (else ;; either the end of the string or a #\,
  537. (let ((v (val-parser k #f)))
  538. (values (reverse! (cons (if v (cons k v) k) out))
  539. (or delim end))))))))))
  540. (define* (parse-param-list str #:optional
  541. (val-parser default-val-parser)
  542. (start 0) (end (string-length str)))
  543. (let lp ((i start) (out '()))
  544. (call-with-values
  545. (lambda () (parse-param-component str val-parser i end))
  546. (lambda (item i)
  547. (if (< i end)
  548. (if (eqv? (string-ref str i) #\,)
  549. (lp (skip-whitespace str (1+ i) end)
  550. (cons item out))
  551. (bad-header-component 'param-list str))
  552. (reverse! (cons item out)))))))
  553. (define* (validate-param-list list #:optional
  554. (valid? default-val-validator))
  555. (list-of? list
  556. (lambda (elt)
  557. (key-value-list? elt valid?))))
  558. (define* (write-param-list list port #:optional
  559. (val-writer default-val-writer))
  560. (put-list
  561. port list
  562. (lambda (port item)
  563. (write-key-value-list item port val-writer ";"))
  564. ","))
  565. (define-syntax string-match?
  566. (lambda (x)
  567. (syntax-case x ()
  568. ((_ str pat) (string? (syntax->datum #'pat))
  569. (let ((p (syntax->datum #'pat)))
  570. #`(let ((s str))
  571. (and
  572. (= (string-length s) #,(string-length p))
  573. #,@(let lp ((i 0) (tests '()))
  574. (if (< i (string-length p))
  575. (let ((c (string-ref p i)))
  576. (lp (1+ i)
  577. (case c
  578. ((#\.) ; Whatever.
  579. tests)
  580. ((#\d) ; Digit.
  581. (cons #`(char-numeric? (string-ref s #,i))
  582. tests))
  583. ((#\a) ; Alphabetic.
  584. (cons #`(char-alphabetic? (string-ref s #,i))
  585. tests))
  586. (else ; Literal.
  587. (cons #`(eqv? (string-ref s #,i) #,c)
  588. tests)))))
  589. tests)))))))))
  590. ;; "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun"
  591. ;; "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"
  592. (define (parse-month str start end)
  593. (define (bad)
  594. (bad-header-component 'month (substring str start end)))
  595. (if (not (= (- end start) 3))
  596. (bad)
  597. (let ((a (string-ref str (+ start 0)))
  598. (b (string-ref str (+ start 1)))
  599. (c (string-ref str (+ start 2))))
  600. (case a
  601. ((#\J)
  602. (case b
  603. ((#\a) (case c ((#\n) 1) (else (bad))))
  604. ((#\u) (case c ((#\n) 6) ((#\l) 7) (else (bad))))
  605. (else (bad))))
  606. ((#\F)
  607. (case b
  608. ((#\e) (case c ((#\b) 2) (else (bad))))
  609. (else (bad))))
  610. ((#\M)
  611. (case b
  612. ((#\a) (case c ((#\r) 3) ((#\y) 5) (else (bad))))
  613. (else (bad))))
  614. ((#\A)
  615. (case b
  616. ((#\p) (case c ((#\r) 4) (else (bad))))
  617. ((#\u) (case c ((#\g) 8) (else (bad))))
  618. (else (bad))))
  619. ((#\S)
  620. (case b
  621. ((#\e) (case c ((#\p) 9) (else (bad))))
  622. (else (bad))))
  623. ((#\O)
  624. (case b
  625. ((#\c) (case c ((#\t) 10) (else (bad))))
  626. (else (bad))))
  627. ((#\N)
  628. (case b
  629. ((#\o) (case c ((#\v) 11) (else (bad))))
  630. (else (bad))))
  631. ((#\D)
  632. (case b
  633. ((#\e) (case c ((#\c) 12) (else (bad))))
  634. (else (bad))))
  635. (else (bad))))))
  636. ;; "GMT" | "+" 4DIGIT | "-" 4DIGIT
  637. ;;
  638. ;; RFC 2616 requires date values to use "GMT", but recommends accepting
  639. ;; the others as they are commonly generated by e.g. RFC 822 sources.
  640. (define (parse-zone-offset str start)
  641. (let ((s (substring str start)))
  642. (define (bad)
  643. (bad-header-component 'zone-offset s))
  644. (cond
  645. ((string=? s "GMT")
  646. 0)
  647. ((string=? s "UTC")
  648. 0)
  649. ((string-match? s ".dddd")
  650. (let ((sign (case (string-ref s 0)
  651. ((#\+) +1)
  652. ((#\-) -1)
  653. (else (bad))))
  654. (hours (parse-non-negative-integer s 1 3))
  655. (minutes (parse-non-negative-integer s 3 5)))
  656. (* sign 60 (+ (* 60 hours) minutes)))) ; seconds east of Greenwich
  657. (else (bad)))))
  658. ;; RFC 822, updated by RFC 1123
  659. ;;
  660. ;; Sun, 06 Nov 1994 08:49:37 GMT
  661. ;; 01234567890123456789012345678
  662. ;; 0 1 2
  663. (define (parse-rfc-822-date str space zone-offset)
  664. ;; We could verify the day of the week but we don't.
  665. (cond ((string-match? (substring str 0 space) "aaa, dd aaa dddd dd:dd:dd")
  666. (let ((date (parse-non-negative-integer str 5 7))
  667. (month (parse-month str 8 11))
  668. (year (parse-non-negative-integer str 12 16))
  669. (hour (parse-non-negative-integer str 17 19))
  670. (minute (parse-non-negative-integer str 20 22))
  671. (second (parse-non-negative-integer str 23 25)))
  672. (make-date 0 second minute hour date month year zone-offset)))
  673. ((string-match? (substring str 0 space) "aaa, d aaa dddd dd:dd:dd")
  674. (let ((date (parse-non-negative-integer str 5 6))
  675. (month (parse-month str 7 10))
  676. (year (parse-non-negative-integer str 11 15))
  677. (hour (parse-non-negative-integer str 16 18))
  678. (minute (parse-non-negative-integer str 19 21))
  679. (second (parse-non-negative-integer str 22 24)))
  680. (make-date 0 second minute hour date month year zone-offset)))
  681. ;; The next two clauses match dates that have a space instead of
  682. ;; a leading zero for hours, like " 8:49:37".
  683. ((string-match? (substring str 0 space) "aaa, dd aaa dddd d:dd:dd")
  684. (let ((date (parse-non-negative-integer str 5 7))
  685. (month (parse-month str 8 11))
  686. (year (parse-non-negative-integer str 12 16))
  687. (hour (parse-non-negative-integer str 18 19))
  688. (minute (parse-non-negative-integer str 20 22))
  689. (second (parse-non-negative-integer str 23 25)))
  690. (make-date 0 second minute hour date month year zone-offset)))
  691. ((string-match? (substring str 0 space) "aaa, d aaa dddd d:dd:dd")
  692. (let ((date (parse-non-negative-integer str 5 6))
  693. (month (parse-month str 7 10))
  694. (year (parse-non-negative-integer str 11 15))
  695. (hour (parse-non-negative-integer str 17 18))
  696. (minute (parse-non-negative-integer str 19 21))
  697. (second (parse-non-negative-integer str 22 24)))
  698. (make-date 0 second minute hour date month year zone-offset)))
  699. (else
  700. (bad-header 'date str) ; prevent tail call
  701. #f)))
  702. ;; RFC 850, updated by RFC 1036
  703. ;; Sunday, 06-Nov-94 08:49:37 GMT
  704. ;; 0123456789012345678901
  705. ;; 0 1 2
  706. (define (parse-rfc-850-date str comma space zone-offset)
  707. ;; We could verify the day of the week but we don't.
  708. (let ((tail (substring str (1+ comma) space)))
  709. (unless (string-match? tail " dd-aaa-dd dd:dd:dd")
  710. (bad-header 'date str))
  711. (let ((date (parse-non-negative-integer tail 1 3))
  712. (month (parse-month tail 4 7))
  713. (year (parse-non-negative-integer tail 8 10))
  714. (hour (parse-non-negative-integer tail 11 13))
  715. (minute (parse-non-negative-integer tail 14 16))
  716. (second (parse-non-negative-integer tail 17 19)))
  717. (make-date 0 second minute hour date month
  718. (let* ((now (date-year (current-date)))
  719. (then (+ now year (- (modulo now 100)))))
  720. (cond ((< (+ then 50) now) (+ then 100))
  721. ((< (+ now 50) then) (- then 100))
  722. (else then)))
  723. zone-offset))))
  724. ;; ANSI C's asctime() format
  725. ;; Sun Nov 6 08:49:37 1994
  726. ;; 012345678901234567890123
  727. ;; 0 1 2
  728. (define (parse-asctime-date str)
  729. (unless (string-match? str "aaa aaa .d dd:dd:dd dddd")
  730. (bad-header 'date str))
  731. (let ((date (parse-non-negative-integer
  732. str
  733. (if (eqv? (string-ref str 8) #\space) 9 8)
  734. 10))
  735. (month (parse-month str 4 7))
  736. (year (parse-non-negative-integer str 20 24))
  737. (hour (parse-non-negative-integer str 11 13))
  738. (minute (parse-non-negative-integer str 14 16))
  739. (second (parse-non-negative-integer str 17 19)))
  740. (make-date 0 second minute hour date month year 0)))
  741. ;; Convert all date values to GMT time zone, as per RFC 2616 appendix C.
  742. (define (normalize-date date)
  743. (if (zero? (date-zone-offset date))
  744. date
  745. (time-utc->date (date->time-utc date) 0)))
  746. (define (parse-date str)
  747. (let* ((space (string-rindex str #\space))
  748. (zone-offset (and space (false-if-exception
  749. (parse-zone-offset str (1+ space))))))
  750. (normalize-date
  751. (if zone-offset
  752. (let ((comma (string-index str #\,)))
  753. (cond ((not comma) (bad-header 'date str))
  754. ((= comma 3) (parse-rfc-822-date str space zone-offset))
  755. (else (parse-rfc-850-date str comma space zone-offset))))
  756. (parse-asctime-date str)))))
  757. (define (write-date date port)
  758. (define (put-digits port n digits)
  759. (define zero (char->integer #\0))
  760. (let lp ((tens (expt 10 (1- digits))))
  761. (when (> tens 0)
  762. (put-char port
  763. (integer->char (+ zero (modulo (truncate/ n tens) 10))))
  764. (lp (floor/ tens 10)))))
  765. (let ((date (if (zero? (date-zone-offset date))
  766. date
  767. (time-tai->date (date->time-tai date) 0))))
  768. (put-string port
  769. (case (date-week-day date)
  770. ((0) "Sun, ") ((1) "Mon, ") ((2) "Tue, ")
  771. ((3) "Wed, ") ((4) "Thu, ") ((5) "Fri, ")
  772. ((6) "Sat, ") (else (error "bad date" date))))
  773. (put-digits port (date-day date) 2)
  774. (put-string port
  775. (case (date-month date)
  776. ((1) " Jan ") ((2) " Feb ") ((3) " Mar ")
  777. ((4) " Apr ") ((5) " May ") ((6) " Jun ")
  778. ((7) " Jul ") ((8) " Aug ") ((9) " Sep ")
  779. ((10) " Oct ") ((11) " Nov ") ((12) " Dec ")
  780. (else (error "bad date" date))))
  781. (put-digits port (date-year date) 4)
  782. (put-char port #\space)
  783. (put-digits port (date-hour date) 2)
  784. (put-char port #\:)
  785. (put-digits port (date-minute date) 2)
  786. (put-char port #\:)
  787. (put-digits port (date-second date) 2)
  788. (put-string port " GMT")))
  789. ;; Following https://tools.ietf.org/html/rfc7232#section-2.3, an entity
  790. ;; tag should really be a qstring. However there are a number of
  791. ;; servers that emit etags as unquoted strings. Assume that if the
  792. ;; value doesn't start with a quote, it's an unquoted strong etag.
  793. (define* (parse-entity-tag val #:optional (start 0) (end (string-length val))
  794. #:key sloppy-delimiters)
  795. (define (parse-proper-etag-at start strong?)
  796. (cond
  797. (sloppy-delimiters
  798. (call-with-values (lambda ()
  799. (parse-qstring val start end #:incremental? #t))
  800. (lambda (tag next)
  801. (values (cons tag strong?) next))))
  802. (else
  803. (values (cons (parse-qstring val start end) strong?) end))))
  804. (cond
  805. ((string-prefix? "W/" val 0 2 start end)
  806. (parse-proper-etag-at (+ start 2) #f))
  807. ((string-prefix? "\"" val 0 1 start end)
  808. (parse-proper-etag-at start #t))
  809. (else
  810. (let ((delim (or (and sloppy-delimiters
  811. (string-index val sloppy-delimiters start end))
  812. end)))
  813. (values (cons (substring val start delim) #t) delim)))))
  814. (define (entity-tag? val)
  815. (match val
  816. (((? string?) . _) #t)
  817. (_ #f)))
  818. (define (put-entity-tag port val)
  819. (match val
  820. ((tag . strong?)
  821. (unless strong? (put-string port "W/"))
  822. (write-qstring tag port))))
  823. (define* (parse-entity-tag-list val #:optional
  824. (start 0) (end (string-length val)))
  825. (call-with-values (lambda ()
  826. (parse-entity-tag val start end #:sloppy-delimiters #\,))
  827. (lambda (etag next)
  828. (cons etag
  829. (let ((next (skip-whitespace val next end)))
  830. (if (< next end)
  831. (if (eqv? (string-ref val next) #\,)
  832. (parse-entity-tag-list
  833. val
  834. (skip-whitespace val (1+ next) end)
  835. end)
  836. (bad-header-component 'entity-tag-list val))
  837. '()))))))
  838. (define (entity-tag-list? val)
  839. (list-of? val entity-tag?))
  840. (define (put-entity-tag-list port val)
  841. (put-list port val put-entity-tag ", "))
  842. ;; credentials = auth-scheme #auth-param
  843. ;; auth-scheme = token
  844. ;; auth-param = token "=" ( token | quoted-string )
  845. ;;
  846. ;; That's what the spec says. In reality the Basic scheme doesn't have
  847. ;; k-v pairs, just one auth token, so we give that token as a string.
  848. ;;
  849. (define* (parse-credentials str #:optional (val-parser default-val-parser)
  850. (start 0) (end (string-length str)))
  851. (let* ((start (skip-whitespace str start end))
  852. (delim (or (string-index str char-set:whitespace start end) end)))
  853. (when (= start end)
  854. (bad-header-component 'authorization str))
  855. (let ((scheme (string->symbol
  856. (string-downcase (substring str start (or delim end))))))
  857. (case scheme
  858. ((basic)
  859. (let* ((start (skip-whitespace str delim end)))
  860. (unless (< start end)
  861. (bad-header-component 'credentials str))
  862. (cons scheme (substring str start end))))
  863. (else
  864. (cons scheme (parse-key-value-list str default-val-parser delim end)))))))
  865. (define (validate-credentials val)
  866. (match val
  867. (('basic . (? string?)) #t)
  868. (((? symbol?) . (? key-value-list?)) #t)
  869. (_ #f)))
  870. (define (write-credentials val port)
  871. (match val
  872. (('basic . cred)
  873. (put-string port "basic ")
  874. (put-string port cred))
  875. ((scheme . params)
  876. (put-symbol port scheme)
  877. (put-char port #\space)
  878. (write-key-value-list params port))))
  879. ;; challenges = 1#challenge
  880. ;; challenge = auth-scheme 1*SP 1#auth-param
  881. ;;
  882. ;; A pain to parse, as both challenges and auth params are delimited by
  883. ;; commas, and qstrings can contain anything. We rely on auth params
  884. ;; necessarily having "=" in them.
  885. ;;
  886. (define* (parse-challenge str #:optional
  887. (start 0) (end (string-length str)))
  888. (let* ((start (skip-whitespace str start end))
  889. (sp (string-index str #\space start end))
  890. (scheme (if sp
  891. (string->symbol (string-downcase (substring str start sp)))
  892. (bad-header-component 'challenge str))))
  893. (let lp ((i sp) (out (list scheme)))
  894. (if (not (< i end))
  895. (values (reverse! out) end)
  896. (let* ((i (skip-whitespace str i end))
  897. (eq (string-index str #\= i end))
  898. (comma (string-index str #\, i end))
  899. (delim (min (or eq end) (or comma end)))
  900. (token-end (trim-whitespace str i delim)))
  901. (if (string-index str #\space i token-end)
  902. (values (reverse! out) i)
  903. (let ((k (string->symbol (substring str i token-end))))
  904. (call-with-values
  905. (lambda ()
  906. (if (and eq (or (not comma) (< eq comma)))
  907. (let ((i (skip-whitespace str (1+ eq) end)))
  908. (if (and (< i end) (eqv? (string-ref str i) #\"))
  909. (parse-qstring str i end #:incremental? #t)
  910. (values (substring
  911. str i
  912. (trim-whitespace str i
  913. (or comma end)))
  914. (or comma end))))
  915. (values #f delim)))
  916. (lambda (v next-i)
  917. (let ((i (skip-whitespace str next-i end)))
  918. (unless (or (= i end) (eqv? (string-ref str i) #\,))
  919. (bad-header-component 'challenge
  920. (substring str start end)))
  921. (lp (1+ i) (cons (if v (cons k v) k) out))))))))))))
  922. (define* (parse-challenges str #:optional (val-parser default-val-parser)
  923. (start 0) (end (string-length str)))
  924. (let lp ((i start))
  925. (let ((i (skip-whitespace str i end)))
  926. (if (< i end)
  927. (call-with-values (lambda () (parse-challenge str i end))
  928. (lambda (challenge i)
  929. (cons challenge (lp i))))
  930. '()))))
  931. (define (validate-challenges val)
  932. (match val
  933. ((((? symbol?) . (? key-value-list?)) ...) #t)
  934. (_ #f)))
  935. (define (put-challenge port val)
  936. (match val
  937. ((scheme . params)
  938. (put-symbol port scheme)
  939. (put-char port #\space)
  940. (write-key-value-list params port))))
  941. (define (write-challenges val port)
  942. (put-list port val put-challenge ", "))
  943. ;;;
  944. ;;; Request-Line and Response-Line
  945. ;;;
  946. ;; Hmm.
  947. (define (bad-request message . args)
  948. (throw 'bad-request message args))
  949. (define (bad-response message . args)
  950. (throw 'bad-response message args))
  951. (define *known-versions* '())
  952. (define* (parse-http-version str #:optional (start 0) (end (string-length str)))
  953. "Parse an HTTP version from STR, returning it as a major–minor
  954. pair. For example, ‘HTTP/1.1’ parses as the pair of integers,
  955. ‘(1 . 1)’."
  956. (let lp ((known *known-versions*))
  957. (match known
  958. (((version-str . version-val) . known)
  959. (if (string= str version-str start end)
  960. version-val
  961. (lp known)))
  962. (()
  963. (let ((dot-idx (string-index str #\. start end)))
  964. (unless (and (string-prefix? "HTTP/" str 0 5 start end)
  965. dot-idx
  966. (= dot-idx (string-rindex str #\. start end)))
  967. (bad-header-component 'http-version (substring str start end)))
  968. (cons (parse-non-negative-integer str (+ start 5) dot-idx)
  969. (parse-non-negative-integer str (1+ dot-idx) end)))))))
  970. (define (write-http-version val port)
  971. "Write the given major-minor version pair to PORT."
  972. (put-string port "HTTP/")
  973. (put-non-negative-integer port (car val))
  974. (put-char port #\.)
  975. (put-non-negative-integer port (cdr val)))
  976. (for-each
  977. (lambda (v)
  978. (set! *known-versions*
  979. (acons v (parse-http-version v 0 (string-length v))
  980. *known-versions*)))
  981. '("HTTP/1.0" "HTTP/1.1"))
  982. ;; Request-URI = "*" | absoluteURI | abs_path | authority
  983. ;;
  984. ;; The `authority' form is only permissible for the CONNECT method, so
  985. ;; because we don't expect people to implement CONNECT, we save
  986. ;; ourselves the trouble of that case, and disallow the CONNECT method.
  987. ;;
  988. (define* (parse-http-method str #:optional (start 0) (end (string-length str)))
  989. "Parse an HTTP method from STR. The result is an upper-case
  990. symbol, like ‘GET’."
  991. (cond
  992. ((string= str "GET" start end) 'GET)
  993. ((string= str "HEAD" start end) 'HEAD)
  994. ((string= str "POST" start end) 'POST)
  995. ((string= str "PUT" start end) 'PUT)
  996. ((string= str "DELETE" start end) 'DELETE)
  997. ((string= str "OPTIONS" start end) 'OPTIONS)
  998. ((string= str "TRACE" start end) 'TRACE)
  999. (else (bad-request "Invalid method: ~a" (substring str start end)))))
  1000. (define* (parse-request-uri str #:optional (start 0) (end (string-length str)))
  1001. "Parse a URI from an HTTP request line. Note that URIs in requests do
  1002. not have to have a scheme or host name. The result is a URI-reference
  1003. object."
  1004. (cond
  1005. ((= start end)
  1006. (bad-request "Missing Request-URI"))
  1007. ((string= str "*" start end)
  1008. #f)
  1009. ((eqv? (string-ref str start) #\/)
  1010. (let* ((q (string-index str #\? start end))
  1011. (f (string-index str #\# start end))
  1012. (q (and q (or (not f) (< q f)) q)))
  1013. (build-uri-reference
  1014. #:path (substring str start (or q f end))
  1015. #:query (and q (substring str (1+ q) (or f end)))
  1016. #:fragment (and f (substring str (1+ f) end)))))
  1017. (else
  1018. (or (string->uri (substring str start end))
  1019. (bad-request "Invalid URI: ~a" (substring str start end))))))
  1020. (define (read-request-line port)
  1021. "Read the first line of an HTTP request from PORT, returning
  1022. three values: the method, the URI, and the version."
  1023. (let* ((line (read-header-line port))
  1024. (d0 (string-index line char-set:whitespace)) ; "delimiter zero"
  1025. (d1 (string-rindex line char-set:whitespace)))
  1026. (unless (and d0 d1 (< d0 d1))
  1027. (bad-request "Bad Request-Line: ~s" line))
  1028. (values (parse-http-method line 0 d0)
  1029. (parse-request-uri line (skip-whitespace line (1+ d0) d1) d1)
  1030. (parse-http-version line (1+ d1) (string-length line)))))
  1031. (define (write-uri uri port)
  1032. (put-string port (uri->string uri #:include-fragment? #f)))
  1033. (define (write-request-line method uri version port)
  1034. "Write the first line of an HTTP request to PORT."
  1035. (put-symbol port method)
  1036. (put-char port #\space)
  1037. (when (http-proxy-port? port)
  1038. (let ((scheme (uri-scheme uri))
  1039. (host (uri-host uri))
  1040. (host-port (uri-port uri)))
  1041. (when (and scheme host)
  1042. (put-symbol port scheme)
  1043. (put-string port "://")
  1044. (cond
  1045. ((string-index host #\:)
  1046. (put-char port #\[)
  1047. (put-string port host)
  1048. (put-char port #\]))
  1049. (else
  1050. (put-string port host)))
  1051. (unless ((@@ (web uri) default-port?) scheme host-port)
  1052. (put-char port #\:)
  1053. (put-non-negative-integer port host-port)))))
  1054. (let ((path (uri-path uri))
  1055. (query (uri-query uri)))
  1056. (if (string-null? path)
  1057. (put-string port "/")
  1058. (put-string port path))
  1059. (when query
  1060. (put-string port "?")
  1061. (put-string port query)))
  1062. (put-char port #\space)
  1063. (write-http-version version port)
  1064. (put-string port "\r\n"))
  1065. (define (read-response-line port)
  1066. "Read the first line of an HTTP response from PORT, returning three
  1067. values: the HTTP version, the response code, and the (possibly empty)
  1068. \"reason phrase\"."
  1069. (let* ((line (read-header-line port))
  1070. (d0 (string-index line char-set:whitespace)) ; "delimiter zero"
  1071. (d1 (and d0 (string-index line char-set:whitespace
  1072. (skip-whitespace line d0)))))
  1073. (unless (and d0 d1)
  1074. (bad-response "Bad Response-Line: ~s" line))
  1075. (values (parse-http-version line 0 d0)
  1076. (parse-non-negative-integer line (skip-whitespace line d0 d1)
  1077. d1)
  1078. (string-trim-both line char-set:whitespace d1))))
  1079. (define (write-response-line version code reason-phrase port)
  1080. "Write the first line of an HTTP response to PORT."
  1081. (write-http-version version port)
  1082. (put-char port #\space)
  1083. (put-non-negative-integer port code)
  1084. (put-char port #\space)
  1085. (put-string port reason-phrase)
  1086. (put-string port "\r\n"))
  1087. ;;;
  1088. ;;; Helpers for declaring headers
  1089. ;;;
  1090. ;; emacs: (put 'declare-header! 'scheme-indent-function 1)
  1091. ;; emacs: (put 'declare-opaque!-header 'scheme-indent-function 1)
  1092. (define (declare-opaque-header! name)
  1093. "Declares a given header as \"opaque\", meaning that its value is not
  1094. treated specially, and is just returned as a plain string."
  1095. (declare-header! name
  1096. parse-opaque-string validate-opaque-string write-opaque-string))
  1097. ;; emacs: (put 'declare-date-header! 'scheme-indent-function 1)
  1098. (define (declare-date-header! name)
  1099. (declare-header! name
  1100. parse-date date? write-date))
  1101. ;; emacs: (put 'declare-string-list-header! 'scheme-indent-function 1)
  1102. (define (declare-string-list-header! name)
  1103. (declare-header! name
  1104. split-and-trim list-of-strings? write-list-of-strings))
  1105. ;; emacs: (put 'declare-symbol-list-header! 'scheme-indent-function 1)
  1106. (define (declare-symbol-list-header! name)
  1107. (declare-header! name
  1108. (lambda (str)
  1109. (map string->symbol (split-and-trim str)))
  1110. (lambda (v)
  1111. (list-of? v symbol?))
  1112. (lambda (v port)
  1113. (put-list port v put-symbol ", "))))
  1114. ;; emacs: (put 'declare-header-list-header! 'scheme-indent-function 1)
  1115. (define (declare-header-list-header! name)
  1116. (declare-header! name
  1117. split-header-names list-of-header-names? write-header-list))
  1118. ;; emacs: (put 'declare-integer-header! 'scheme-indent-function 1)
  1119. (define (declare-integer-header! name)
  1120. (declare-header! name
  1121. parse-non-negative-integer non-negative-integer?
  1122. (lambda (val port) (put-non-negative-integer port val))))
  1123. ;; emacs: (put 'declare-uri-reference-header! 'scheme-indent-function 1)
  1124. (define (declare-uri-reference-header! name)
  1125. (declare-header! name
  1126. (lambda (str)
  1127. (or (string->uri-reference str)
  1128. (bad-header-component 'uri-reference str)))
  1129. uri-reference?
  1130. write-uri))
  1131. ;; emacs: (put 'declare-quality-list-header! 'scheme-indent-function 1)
  1132. (define (declare-quality-list-header! name)
  1133. (declare-header! name
  1134. parse-quality-list validate-quality-list write-quality-list))
  1135. ;; emacs: (put 'declare-param-list-header! 'scheme-indent-function 1)
  1136. (define* (declare-param-list-header! name #:optional
  1137. (val-parser default-val-parser)
  1138. (val-validator default-val-validator)
  1139. (val-writer default-val-writer))
  1140. (declare-header! name
  1141. (lambda (str) (parse-param-list str val-parser))
  1142. (lambda (val) (validate-param-list val val-validator))
  1143. (lambda (val port) (write-param-list val port val-writer))))
  1144. ;; emacs: (put 'declare-key-value-list-header! 'scheme-indent-function 1)
  1145. (define* (declare-key-value-list-header! name #:optional
  1146. (val-parser default-val-parser)
  1147. (val-validator default-val-validator)
  1148. (val-writer default-val-writer))
  1149. (declare-header! name
  1150. (lambda (str) (parse-key-value-list str val-parser))
  1151. (lambda (val) (key-value-list? val val-validator))
  1152. (lambda (val port) (write-key-value-list val port val-writer))))
  1153. ;; emacs: (put 'declare-entity-tag-list-header! 'scheme-indent-function 1)
  1154. (define (declare-entity-tag-list-header! name)
  1155. (declare-header! name
  1156. (lambda (str) (if (string=? str "*") '* (parse-entity-tag-list str)))
  1157. (lambda (val) (or (eq? val '*) (entity-tag-list? val)))
  1158. (lambda (val port)
  1159. (if (eq? val '*)
  1160. (put-string port "*")
  1161. (put-entity-tag-list port val)))))
  1162. ;; emacs: (put 'declare-credentials-header! 'scheme-indent-function 1)
  1163. (define (declare-credentials-header! name)
  1164. (declare-header! name
  1165. parse-credentials validate-credentials write-credentials))
  1166. ;; emacs: (put 'declare-challenge-list-header! 'scheme-indent-function 1)
  1167. (define (declare-challenge-list-header! name)
  1168. (declare-header! name
  1169. parse-challenges validate-challenges write-challenges))
  1170. ;;;
  1171. ;;; General headers
  1172. ;;;
  1173. ;; Cache-Control = 1#(cache-directive)
  1174. ;; cache-directive = cache-request-directive | cache-response-directive
  1175. ;; cache-request-directive =
  1176. ;; "no-cache" ; Section 14.9.1
  1177. ;; | "no-store" ; Section 14.9.2
  1178. ;; | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
  1179. ;; | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
  1180. ;; | "min-fresh" "=" delta-seconds ; Section 14.9.3
  1181. ;; | "no-transform" ; Section 14.9.5
  1182. ;; | "only-if-cached" ; Section 14.9.4
  1183. ;; | cache-extension ; Section 14.9.6
  1184. ;; cache-response-directive =
  1185. ;; "public" ; Section 14.9.1
  1186. ;; | "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
  1187. ;; | "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
  1188. ;; | "no-store" ; Section 14.9.2
  1189. ;; | "no-transform" ; Section 14.9.5
  1190. ;; | "must-revalidate" ; Section 14.9.4
  1191. ;; | "proxy-revalidate" ; Section 14.9.4
  1192. ;; | "max-age" "=" delta-seconds ; Section 14.9.3
  1193. ;; | "s-maxage" "=" delta-seconds ; Section 14.9.3
  1194. ;; | cache-extension ; Section 14.9.6
  1195. ;; cache-extension = token [ "=" ( token | quoted-string ) ]
  1196. ;;
  1197. (declare-key-value-list-header! "Cache-Control"
  1198. (lambda (k v-str)
  1199. (case k
  1200. ((max-age min-fresh s-maxage)
  1201. (parse-non-negative-integer v-str))
  1202. ((max-stale)
  1203. (and v-str (parse-non-negative-integer v-str)))
  1204. ((private no-cache)
  1205. (and v-str (split-header-names v-str)))
  1206. (else v-str)))
  1207. (lambda (k v)
  1208. (case k
  1209. ((max-age min-fresh s-maxage)
  1210. (non-negative-integer? v))
  1211. ((max-stale)
  1212. (or (not v) (non-negative-integer? v)))
  1213. ((private no-cache)
  1214. (or (not v) (list-of-header-names? v)))
  1215. ((no-store no-transform only-if-cache must-revalidate proxy-revalidate)
  1216. (not v))
  1217. (else
  1218. (or (not v) (string? v)))))
  1219. (lambda (k v port)
  1220. (cond
  1221. ((string? v) (default-val-writer k v port))
  1222. ((pair? v)
  1223. (put-char port #\")
  1224. (write-header-list v port)
  1225. (put-char port #\"))
  1226. ((integer? v)
  1227. (put-non-negative-integer port v))
  1228. (else
  1229. (bad-header-component 'cache-control v)))))
  1230. ;; Connection = "Connection" ":" 1#(connection-token)
  1231. ;; connection-token = token
  1232. ;; e.g.
  1233. ;; Connection: close, Foo-Header
  1234. ;;
  1235. (declare-header! "Connection"
  1236. split-header-names
  1237. list-of-header-names?
  1238. (lambda (val port)
  1239. (put-list port val
  1240. (lambda (port x)
  1241. (put-string port
  1242. (if (eq? x 'close)
  1243. "close"
  1244. (header->string x))))
  1245. ", ")))
  1246. ;; Date = "Date" ":" HTTP-date
  1247. ;; e.g.
  1248. ;; Date: Tue, 15 Nov 1994 08:12:31 GMT
  1249. ;;
  1250. (declare-date-header! "Date")
  1251. ;; Pragma = "Pragma" ":" 1#pragma-directive
  1252. ;; pragma-directive = "no-cache" | extension-pragma
  1253. ;; extension-pragma = token [ "=" ( token | quoted-string ) ]
  1254. ;;
  1255. (declare-key-value-list-header! "Pragma")
  1256. ;; Trailer = "Trailer" ":" 1#field-name
  1257. ;;
  1258. (declare-header-list-header! "Trailer")
  1259. ;; Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
  1260. ;;
  1261. (declare-param-list-header! "Transfer-Encoding")
  1262. ;; Upgrade = "Upgrade" ":" 1#product
  1263. ;;
  1264. (declare-string-list-header! "Upgrade")
  1265. ;; Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
  1266. ;; received-protocol = [ protocol-name "/" ] protocol-version
  1267. ;; protocol-name = token
  1268. ;; protocol-version = token
  1269. ;; received-by = ( host [ ":" port ] ) | pseudonym
  1270. ;; pseudonym = token
  1271. ;;
  1272. (declare-header! "Via"
  1273. split-and-trim
  1274. list-of-strings?
  1275. write-list-of-strings
  1276. #:multiple? #t)
  1277. ;; Warning = "Warning" ":" 1#warning-value
  1278. ;;
  1279. ;; warning-value = warn-code SP warn-agent SP warn-text
  1280. ;; [SP warn-date]
  1281. ;;
  1282. ;; warn-code = 3DIGIT
  1283. ;; warn-agent = ( host [ ":" port ] ) | pseudonym
  1284. ;; ; the name or pseudonym of the server adding
  1285. ;; ; the Warning header, for use in debugging
  1286. ;; warn-text = quoted-string
  1287. ;; warn-date = <"> HTTP-date <">
  1288. (declare-header! "Warning"
  1289. (lambda (str)
  1290. (let ((len (string-length str)))
  1291. (let lp ((i (skip-whitespace str 0)))
  1292. (let* ((idx1 (string-index str #\space i))
  1293. (idx2 (string-index str #\space (1+ idx1))))
  1294. (when (and idx1 idx2)
  1295. (let ((code (parse-non-negative-integer str i idx1))
  1296. (agent (substring str (1+ idx1) idx2)))
  1297. (call-with-values
  1298. (lambda () (parse-qstring str (1+ idx2) #:incremental? #t))
  1299. (lambda (text i)
  1300. (call-with-values
  1301. (lambda ()
  1302. (let ((c (and (< i len) (string-ref str i))))
  1303. (case c
  1304. ((#\space)
  1305. ;; we have a date.
  1306. (call-with-values
  1307. (lambda () (parse-qstring str (1+ i)
  1308. #:incremental? #t))
  1309. (lambda (date i)
  1310. (values text (parse-date date) i))))
  1311. (else
  1312. (values text #f i)))))
  1313. (lambda (text date i)
  1314. (let ((w (list code agent text date))
  1315. (c (and (< i len) (string-ref str i))))
  1316. (case c
  1317. ((#f) (list w))
  1318. ((#\,) (cons w (lp (skip-whitespace str (1+ i)))))
  1319. (else (bad-header 'warning str))))))))))))))
  1320. (lambda (val)
  1321. (list-of? val
  1322. (lambda (elt)
  1323. (match elt
  1324. ((code host text date)
  1325. (and (non-negative-integer? code) (< code 1000)
  1326. (string? host)
  1327. (string? text)
  1328. (or (not date) (date? date))))
  1329. (_ #f)))))
  1330. (lambda (val port)
  1331. (put-list
  1332. port val
  1333. (lambda (port w)
  1334. (match w
  1335. ((code host text date)
  1336. (put-non-negative-integer port code)
  1337. (put-char port #\space)
  1338. (put-string port host)
  1339. (put-char port #\space)
  1340. (write-qstring text port)
  1341. (when date
  1342. (put-char port #\space)
  1343. (put-char port #\")
  1344. (write-date date port)
  1345. (put-char port #\")))))
  1346. ", "))
  1347. #:multiple? #t)
  1348. ;;;
  1349. ;;; Entity headers
  1350. ;;;
  1351. ;; Allow = #Method
  1352. ;;
  1353. (declare-symbol-list-header! "Allow")
  1354. ;; Content-Disposition = disposition-type *( ";" disposition-parm )
  1355. ;; disposition-type = "attachment" | disp-extension-token
  1356. ;; disposition-parm = filename-parm | disp-extension-parm
  1357. ;; filename-parm = "filename" "=" quoted-string
  1358. ;; disp-extension-token = token
  1359. ;; disp-extension-parm = token "=" ( token | quoted-string )
  1360. ;;
  1361. (declare-header! "Content-Disposition"
  1362. (lambda (str)
  1363. ;; Lazily reuse the param list parser.
  1364. (match (parse-param-list str default-val-parser)
  1365. ((disposition) disposition)
  1366. (_ (bad-header-component 'content-disposition str))))
  1367. (lambda (val)
  1368. (match val
  1369. (((? symbol?) ((? symbol?) . (? string?)) ...) #t)
  1370. (_ #f)))
  1371. (lambda (val port)
  1372. (write-param-list (list val) port)))
  1373. ;; Content-Encoding = 1#content-coding
  1374. ;;
  1375. (declare-symbol-list-header! "Content-Encoding")
  1376. ;; Content-Language = 1#language-tag
  1377. ;;
  1378. (declare-string-list-header! "Content-Language")
  1379. ;; Content-Length = 1*DIGIT
  1380. ;;
  1381. (declare-integer-header! "Content-Length")
  1382. ;; Content-Location = URI-reference
  1383. ;;
  1384. (declare-uri-reference-header! "Content-Location")
  1385. ;; Content-MD5 = <base64 of 128 bit MD5 digest as per RFC 1864>
  1386. ;;
  1387. (declare-opaque-header! "Content-MD5")
  1388. ;; Content-Range = content-range-spec
  1389. ;; content-range-spec = byte-content-range-spec
  1390. ;; byte-content-range-spec = bytes-unit SP
  1391. ;; byte-range-resp-spec "/"
  1392. ;; ( instance-length | "*" )
  1393. ;; byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
  1394. ;; | "*"
  1395. ;; instance-length = 1*DIGIT
  1396. ;;
  1397. (declare-header! "Content-Range"
  1398. (lambda (str)
  1399. (let ((dash (string-index str #\-))
  1400. (slash (string-index str #\/)))
  1401. (unless (and (string-prefix? "bytes " str) slash)
  1402. (bad-header 'content-range str))
  1403. (list 'bytes
  1404. (cond
  1405. (dash
  1406. (cons
  1407. (parse-non-negative-integer str 6 dash)
  1408. (parse-non-negative-integer str (1+ dash) slash)))
  1409. ((string= str "*" 6 slash)
  1410. '*)
  1411. (else
  1412. (bad-header 'content-range str)))
  1413. (if (string= str "*" (1+ slash))
  1414. '*
  1415. (parse-non-negative-integer str (1+ slash))))))
  1416. (lambda (val)
  1417. (match val
  1418. (((? symbol?)
  1419. (or '* ((? non-negative-integer?) . (? non-negative-integer?)))
  1420. (or '* (? non-negative-integer?)))
  1421. #t)
  1422. (_ #f)))
  1423. (lambda (val port)
  1424. (match val
  1425. ((unit range instance-length)
  1426. (put-symbol port unit)
  1427. (put-char port #\space)
  1428. (match range
  1429. ('*
  1430. (put-char port #\*))
  1431. ((start . end)
  1432. (put-non-negative-integer port start)
  1433. (put-char port #\-)
  1434. (put-non-negative-integer port end)))
  1435. (put-char port #\/)
  1436. (match instance-length
  1437. ('* (put-char port #\*))
  1438. (len (put-non-negative-integer port len)))))))
  1439. ;; Content-Type = media-type
  1440. ;;
  1441. (declare-header! "Content-Type"
  1442. (lambda (str)
  1443. (let ((parts (string-split str #\;)))
  1444. (cons (parse-media-type (car parts))
  1445. (map (lambda (x)
  1446. (let ((eq (string-index x #\=)))
  1447. (unless (and eq (= eq (string-rindex x #\=)))
  1448. (bad-header 'content-type str))
  1449. (cons
  1450. (string->symbol
  1451. (string-trim x char-set:whitespace 0 eq))
  1452. (string-trim-right x char-set:whitespace (1+ eq)))))
  1453. (cdr parts)))))
  1454. (lambda (val)
  1455. (match val
  1456. (((? symbol?) ((? symbol?) . (? string?)) ...) #t)
  1457. (_ #f)))
  1458. (lambda (val port)
  1459. (match val
  1460. ((type . args)
  1461. (put-symbol port type)
  1462. (match args
  1463. (() (values))
  1464. (args
  1465. (put-string port ";")
  1466. (put-list
  1467. port args
  1468. (lambda (port pair)
  1469. (match pair
  1470. ((k . v)
  1471. (put-symbol port k)
  1472. (put-char port #\=)
  1473. (put-string port v))))
  1474. ";")))))))
  1475. ;; Expires = HTTP-date
  1476. ;;
  1477. (define *date-in-the-past* (parse-date "Thu, 01 Jan 1970 00:00:00 GMT"))
  1478. (declare-header! "Expires"
  1479. (lambda (str)
  1480. (if (member str '("0" "-1"))
  1481. *date-in-the-past*
  1482. (parse-date str)))
  1483. date?
  1484. write-date)
  1485. ;; Last-Modified = HTTP-date
  1486. ;;
  1487. (declare-date-header! "Last-Modified")
  1488. ;;;
  1489. ;;; Request headers
  1490. ;;;
  1491. ;; Accept = #( media-range [ accept-params ] )
  1492. ;; media-range = ( "*/*" | ( type "/" "*" ) | ( type "/" subtype ) )
  1493. ;; *( ";" parameter )
  1494. ;; accept-params = ";" "q" "=" qvalue *( accept-extension )
  1495. ;; accept-extension = ";" token [ "=" ( token | quoted-string ) ]
  1496. ;;
  1497. (declare-param-list-header! "Accept"
  1498. ;; -> (type/subtype (sym-prop . str-val) ...) ...)
  1499. ;;
  1500. ;; with the exception of prop `q', in which case the val will be a
  1501. ;; valid quality value
  1502. ;;
  1503. (lambda (k v)
  1504. (if (eq? k 'q)
  1505. (parse-quality v)
  1506. v))
  1507. (lambda (k v)
  1508. (if (eq? k 'q)
  1509. (valid-quality? v)
  1510. (or (not v) (string? v))))
  1511. (lambda (k v port)
  1512. (if (eq? k 'q)
  1513. (write-quality v port)
  1514. (default-val-writer k v port))))
  1515. ;; Accept-Charset = 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
  1516. ;;
  1517. (declare-quality-list-header! "Accept-Charset")
  1518. ;; Accept-Encoding = 1#( codings [ ";" "q" "=" qvalue ] )
  1519. ;; codings = ( content-coding | "*" )
  1520. ;;
  1521. (declare-quality-list-header! "Accept-Encoding")
  1522. ;; Accept-Language = 1#( language-range [ ";" "q" "=" qvalue ] )
  1523. ;; language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
  1524. ;;
  1525. (declare-quality-list-header! "Accept-Language")
  1526. ;; Authorization = credentials
  1527. ;; credentials = auth-scheme #auth-param
  1528. ;; auth-scheme = token
  1529. ;; auth-param = token "=" ( token | quoted-string )
  1530. ;;
  1531. (declare-credentials-header! "Authorization")
  1532. ;; Expect = 1#expectation
  1533. ;; expectation = "100-continue" | expectation-extension
  1534. ;; expectation-extension = token [ "=" ( token | quoted-string )
  1535. ;; *expect-params ]
  1536. ;; expect-params = ";" token [ "=" ( token | quoted-string ) ]
  1537. ;;
  1538. (declare-param-list-header! "Expect")
  1539. ;; From = mailbox
  1540. ;;
  1541. ;; Should be an email address; we just pass on the string as-is.
  1542. ;;
  1543. (declare-opaque-header! "From")
  1544. ;; Host = host [ ":" port ]
  1545. ;;
  1546. (declare-header! "Host"
  1547. (lambda (str)
  1548. (let* ((rbracket (string-index str #\]))
  1549. (colon (string-index str #\: (or rbracket 0)))
  1550. (host (cond
  1551. (rbracket
  1552. (unless (eqv? (string-ref str 0) #\[)
  1553. (bad-header 'host str))
  1554. (substring str 1 rbracket))
  1555. (colon
  1556. (substring str 0 colon))
  1557. (else
  1558. str)))
  1559. (port (and colon
  1560. (parse-non-negative-integer str (1+ colon)))))
  1561. (cons host port)))
  1562. (lambda (val)
  1563. (match val
  1564. (((? string?) . (or #f (? non-negative-integer?))) #t)
  1565. (_ #f)))
  1566. (lambda (val port)
  1567. (match val
  1568. ((host-name . host-port)
  1569. (cond
  1570. ((string-index host-name #\:)
  1571. (put-char port #\[)
  1572. (put-string port host-name)
  1573. (put-char port #\]))
  1574. (else
  1575. (put-string port host-name)))
  1576. (when host-port
  1577. (put-char port #\:)
  1578. (put-non-negative-integer port host-port))))))
  1579. ;; If-Match = ( "*" | 1#entity-tag )
  1580. ;;
  1581. (declare-entity-tag-list-header! "If-Match")
  1582. ;; If-Modified-Since = HTTP-date
  1583. ;;
  1584. (declare-date-header! "If-Modified-Since")
  1585. ;; If-None-Match = ( "*" | 1#entity-tag )
  1586. ;;
  1587. (declare-entity-tag-list-header! "If-None-Match")
  1588. ;; If-Range = ( entity-tag | HTTP-date )
  1589. ;;
  1590. (declare-header! "If-Range"
  1591. (lambda (str)
  1592. (if (or (string-prefix? "\"" str)
  1593. (string-prefix? "W/" str))
  1594. (parse-entity-tag str)
  1595. (parse-date str)))
  1596. (lambda (val)
  1597. (or (date? val) (entity-tag? val)))
  1598. (lambda (val port)
  1599. (if (date? val)
  1600. (write-date val port)
  1601. (put-entity-tag port val))))
  1602. ;; If-Unmodified-Since = HTTP-date
  1603. ;;
  1604. (declare-date-header! "If-Unmodified-Since")
  1605. ;; Max-Forwards = 1*DIGIT
  1606. ;;
  1607. (declare-integer-header! "Max-Forwards")
  1608. ;; Proxy-Authorization = credentials
  1609. ;;
  1610. (declare-credentials-header! "Proxy-Authorization")
  1611. ;; Range = "Range" ":" ranges-specifier
  1612. ;; ranges-specifier = byte-ranges-specifier
  1613. ;; byte-ranges-specifier = bytes-unit "=" byte-range-set
  1614. ;; byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
  1615. ;; byte-range-spec = first-byte-pos "-" [last-byte-pos]
  1616. ;; first-byte-pos = 1*DIGIT
  1617. ;; last-byte-pos = 1*DIGIT
  1618. ;; suffix-byte-range-spec = "-" suffix-length
  1619. ;; suffix-length = 1*DIGIT
  1620. ;;
  1621. (declare-header! "Range"
  1622. (lambda (str)
  1623. (unless (string-prefix? "bytes=" str)
  1624. (bad-header 'range str))
  1625. (cons
  1626. 'bytes
  1627. (map (lambda (x)
  1628. (let ((dash (string-index x #\-)))
  1629. (cond
  1630. ((not dash)
  1631. (bad-header 'range str))
  1632. ((zero? dash)
  1633. (cons #f (parse-non-negative-integer x 1)))
  1634. ((= dash (1- (string-length x)))
  1635. (cons (parse-non-negative-integer x 0 dash) #f))
  1636. (else
  1637. (cons (parse-non-negative-integer x 0 dash)
  1638. (parse-non-negative-integer x (1+ dash)))))))
  1639. (string-split (substring str 6) #\,))))
  1640. (lambda (val)
  1641. (match val
  1642. (((? symbol?)
  1643. (or (#f . (? non-negative-integer?))
  1644. ((? non-negative-integer?) . (? non-negative-integer?))
  1645. ((? non-negative-integer?) . #f))
  1646. ...) #t)
  1647. (_ #f)))
  1648. (lambda (val port)
  1649. (match val
  1650. ((unit . ranges)
  1651. (put-symbol port unit)
  1652. (put-char port #\=)
  1653. (put-list
  1654. port ranges
  1655. (lambda (port range)
  1656. (match range
  1657. ((start . end)
  1658. (when start (put-non-negative-integer port start))
  1659. (put-char port #\-)
  1660. (when end (put-non-negative-integer port end)))))
  1661. ",")))))
  1662. ;; Referer = URI-reference
  1663. ;;
  1664. (declare-uri-reference-header! "Referer")
  1665. ;; TE = #( t-codings )
  1666. ;; t-codings = "trailers" | ( transfer-extension [ accept-params ] )
  1667. ;;
  1668. (declare-param-list-header! "TE")
  1669. ;; User-Agent = 1*( product | comment )
  1670. ;;
  1671. (declare-opaque-header! "User-Agent")
  1672. ;;;
  1673. ;;; Reponse headers
  1674. ;;;
  1675. ;; Accept-Ranges = acceptable-ranges
  1676. ;; acceptable-ranges = 1#range-unit | "none"
  1677. ;;
  1678. (declare-symbol-list-header! "Accept-Ranges")
  1679. ;; Age = age-value
  1680. ;; age-value = delta-seconds
  1681. ;;
  1682. (declare-integer-header! "Age")
  1683. ;; ETag = entity-tag
  1684. ;;
  1685. (declare-header! "ETag"
  1686. parse-entity-tag
  1687. entity-tag?
  1688. (lambda (val port)
  1689. (put-entity-tag port val)))
  1690. ;; Location = URI-reference
  1691. ;;
  1692. ;; In RFC 2616, Location was specified as being an absolute URI. This
  1693. ;; was changed in RFC 7231 to permit URI references generally, which
  1694. ;; matches web reality.
  1695. ;;
  1696. (declare-uri-reference-header! "Location")
  1697. ;; Proxy-Authenticate = 1#challenge
  1698. ;;
  1699. (declare-challenge-list-header! "Proxy-Authenticate")
  1700. ;; Retry-After = ( HTTP-date | delta-seconds )
  1701. ;;
  1702. (declare-header! "Retry-After"
  1703. (lambda (str)
  1704. (if (and (not (string-null? str))
  1705. (char-numeric? (string-ref str 0)))
  1706. (parse-non-negative-integer str)
  1707. (parse-date str)))
  1708. (lambda (val)
  1709. (or (date? val) (non-negative-integer? val)))
  1710. (lambda (val port)
  1711. (if (date? val)
  1712. (write-date val port)
  1713. (put-non-negative-integer port val))))
  1714. ;; Server = 1*( product | comment )
  1715. ;;
  1716. (declare-opaque-header! "Server")
  1717. ;; Vary = ( "*" | 1#field-name )
  1718. ;;
  1719. (declare-header! "Vary"
  1720. (lambda (str)
  1721. (if (equal? str "*")
  1722. '*
  1723. (split-header-names str)))
  1724. (lambda (val)
  1725. (or (eq? val '*) (list-of-header-names? val)))
  1726. (lambda (val port)
  1727. (if (eq? val '*)
  1728. (put-string port "*")
  1729. (write-header-list val port))))
  1730. ;; WWW-Authenticate = 1#challenge
  1731. ;;
  1732. (declare-challenge-list-header! "WWW-Authenticate")
  1733. ;; Chunked Responses
  1734. (define (read-chunk-header port)
  1735. "Read a chunk header from PORT and return the size in bytes of the
  1736. upcoming chunk."
  1737. (match (read-line port)
  1738. ((? eof-object?)
  1739. ;; Connection closed prematurely: there's nothing left to read.
  1740. 0)
  1741. (str
  1742. (let ((extension-start (string-index str
  1743. (lambda (c)
  1744. (or (char=? c #\;)
  1745. (char=? c #\return))))))
  1746. (string->number (if extension-start ; unnecessary?
  1747. (substring str 0 extension-start)
  1748. str)
  1749. 16)))))
  1750. (define* (make-chunked-input-port port #:key (keep-alive? #f))
  1751. "Returns a new port which translates HTTP chunked transfer encoded
  1752. data from PORT into a non-encoded format. Returns eof when it has
  1753. read the final chunk from PORT. This does not necessarily mean
  1754. that there is no more data on PORT. When the returned port is
  1755. closed it will also close PORT, unless the KEEP-ALIVE? is true."
  1756. (define (close)
  1757. (unless keep-alive?
  1758. (close-port port)))
  1759. (define chunk-size 0) ;size of the current chunk
  1760. (define remaining 0) ;number of bytes left from the current chunk
  1761. (define finished? #f) ;did we get all the chunks?
  1762. (define (read! bv idx to-read)
  1763. (define (loop to-read num-read)
  1764. (cond ((or finished? (zero? to-read))
  1765. num-read)
  1766. ((zero? remaining) ;get a new chunk
  1767. (let ((size (read-chunk-header port)))
  1768. (set! chunk-size size)
  1769. (set! remaining size)
  1770. (cond
  1771. ((zero? size)
  1772. (set! finished? #t)
  1773. num-read)
  1774. (else
  1775. (loop to-read num-read)))))
  1776. (else ;read from the current chunk
  1777. (let* ((ask-for (min to-read remaining))
  1778. (read (get-bytevector-n! port bv (+ idx num-read)
  1779. ask-for)))
  1780. (cond
  1781. ((eof-object? read) ;premature termination
  1782. (set! finished? #t)
  1783. num-read)
  1784. (else
  1785. (let ((left (- remaining read)))
  1786. (set! remaining left)
  1787. (when (zero? left)
  1788. ;; We're done with this chunk; read CR and LF.
  1789. (get-u8 port) (get-u8 port))
  1790. (loop (- to-read read)
  1791. (+ num-read read)))))))))
  1792. (loop to-read 0))
  1793. (make-custom-binary-input-port "chunked input port" read! #f #f close))
  1794. (define* (make-chunked-output-port port #:key (keep-alive? #f)
  1795. (buffering 1200))
  1796. "Returns a new port which translates non-encoded data into a HTTP
  1797. chunked transfer encoded data and writes this to PORT. Data written to
  1798. this port is buffered until the port is flushed, at which point it is
  1799. all sent as one chunk. The port will otherwise be flushed every
  1800. BUFFERING bytes, which defaults to 1200. Take care to close the port
  1801. when done, as it will output the remaining data, and encode the final
  1802. zero chunk. When the port is closed it will also close PORT, unless
  1803. KEEP-ALIVE? is true."
  1804. (define (q-for-each f q)
  1805. (while (not (q-empty? q))
  1806. (f (deq! q))))
  1807. (define queue (make-q))
  1808. (define (%put-char c)
  1809. (enq! queue c))
  1810. (define (%put-string s)
  1811. (string-for-each (lambda (c) (enq! queue c))
  1812. s))
  1813. (define (flush)
  1814. ;; It is important that we do _not_ write a chunk if the queue is
  1815. ;; empty, since it will be treated as the final chunk.
  1816. (unless (q-empty? queue)
  1817. (let ((len (q-length queue)))
  1818. (put-string port (number->string len 16))
  1819. (put-string port "\r\n")
  1820. (q-for-each (lambda (elem) (put-char port elem))
  1821. queue)
  1822. (put-string port "\r\n"))))
  1823. (define (close)
  1824. (flush)
  1825. (put-string port "0\r\n")
  1826. (force-output port)
  1827. (unless keep-alive?
  1828. (close-port port)))
  1829. (let ((ret (make-soft-port (vector %put-char %put-string flush #f close) "w")))
  1830. (setvbuf ret 'block buffering)
  1831. ret))
  1832. (define %http-proxy-port? (make-object-property))
  1833. (define (http-proxy-port? port) (%http-proxy-port? port))
  1834. (define (set-http-proxy-port?! port flag)
  1835. (set! (%http-proxy-port? port) flag))