http.scm 71 KB

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