http.scm 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057
  1. ;;; HTTP messages
  2. ;; Copyright (C) 2010-2017, 2023 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-9)
  30. #:use-module (srfi srfi-19)
  31. #:use-module (ice-9 rdelim)
  32. #:use-module (ice-9 match)
  33. #:use-module (ice-9 binary-ports)
  34. #:use-module (ice-9 textual-ports)
  35. #:use-module (ice-9 exceptions)
  36. #:use-module (web uri)
  37. #:export (string->header
  38. header->string
  39. declare-header!
  40. declare-opaque-header!
  41. known-header?
  42. header-parser
  43. header-validator
  44. header-writer
  45. read-header
  46. parse-header
  47. valid-header?
  48. write-header
  49. read-headers
  50. write-headers
  51. parse-http-method
  52. parse-http-version
  53. parse-request-uri
  54. read-request-line
  55. write-request-line
  56. read-response-line
  57. write-response-line
  58. &chunked-input-error-prematurely
  59. chunked-input-ended-prematurely-error?
  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. ;; While according to RFC 7617 Schemes are case-insensitive:
  871. ;;
  872. ;; 'Note that both scheme and parameter names are matched
  873. ;; case-insensitive'
  874. ;;
  875. ;; some software (*) incorrectly assumes title case for scheme
  876. ;; names, so use the more titlecase.
  877. ;;
  878. ;; (*): See, e.g.,
  879. ;; https://community.spotify.com/t5/Spotify-for-Developers/API-Authorization-header-doesn-t-follow-HTTP-spec/m-p/5397381#M4917
  880. (define (write-credentials val port)
  881. (match val
  882. (('basic . cred)
  883. (put-string port "Basic ")
  884. (put-string port cred))
  885. ((scheme . params)
  886. (put-string port (string-titlecase (symbol->string scheme)))
  887. (put-char port #\space)
  888. (write-key-value-list params port))))
  889. ;; challenges = 1#challenge
  890. ;; challenge = auth-scheme 1*SP 1#auth-param
  891. ;;
  892. ;; A pain to parse, as both challenges and auth params are delimited by
  893. ;; commas, and qstrings can contain anything. We rely on auth params
  894. ;; necessarily having "=" in them.
  895. ;;
  896. (define* (parse-challenge str #:optional
  897. (start 0) (end (string-length str)))
  898. (let* ((start (skip-whitespace str start end))
  899. (sp (string-index str #\space start end))
  900. (scheme (if sp
  901. (string->symbol (string-downcase (substring str start sp)))
  902. (bad-header-component 'challenge str))))
  903. (let lp ((i sp) (out (list scheme)))
  904. (if (not (< i end))
  905. (values (reverse! out) end)
  906. (let* ((i (skip-whitespace str i end))
  907. (eq (string-index str #\= i end))
  908. (comma (string-index str #\, i end))
  909. (delim (min (or eq end) (or comma end)))
  910. (token-end (trim-whitespace str i delim)))
  911. (if (string-index str #\space i token-end)
  912. (values (reverse! out) i)
  913. (let ((k (string->symbol (substring str i token-end))))
  914. (call-with-values
  915. (lambda ()
  916. (if (and eq (or (not comma) (< eq comma)))
  917. (let ((i (skip-whitespace str (1+ eq) end)))
  918. (if (and (< i end) (eqv? (string-ref str i) #\"))
  919. (parse-qstring str i end #:incremental? #t)
  920. (values (substring
  921. str i
  922. (trim-whitespace str i
  923. (or comma end)))
  924. (or comma end))))
  925. (values #f delim)))
  926. (lambda (v next-i)
  927. (let ((i (skip-whitespace str next-i end)))
  928. (unless (or (= i end) (eqv? (string-ref str i) #\,))
  929. (bad-header-component 'challenge
  930. (substring str start end)))
  931. (lp (1+ i) (cons (if v (cons k v) k) out))))))))))))
  932. (define* (parse-challenges str #:optional (val-parser default-val-parser)
  933. (start 0) (end (string-length str)))
  934. (let lp ((i start))
  935. (let ((i (skip-whitespace str i end)))
  936. (if (< i end)
  937. (call-with-values (lambda () (parse-challenge str i end))
  938. (lambda (challenge i)
  939. (cons challenge (lp i))))
  940. '()))))
  941. (define (validate-challenges val)
  942. (match val
  943. ((((? symbol?) . (? key-value-list?)) ...) #t)
  944. (_ #f)))
  945. (define (put-challenge port val)
  946. (match val
  947. ((scheme . params)
  948. (put-symbol port scheme)
  949. (put-char port #\space)
  950. (write-key-value-list params port))))
  951. (define (write-challenges val port)
  952. (put-list port val put-challenge ", "))
  953. ;;;
  954. ;;; Request-Line and Response-Line
  955. ;;;
  956. ;; Hmm.
  957. (define (bad-request message . args)
  958. (throw 'bad-request message args))
  959. (define (bad-response message . args)
  960. (throw 'bad-response message args))
  961. (define *known-versions* '())
  962. (define* (parse-http-version str #:optional (start 0) (end (string-length str)))
  963. "Parse an HTTP version from STR, returning it as a major–minor
  964. pair. For example, ‘HTTP/1.1’ parses as the pair of integers,
  965. ‘(1 . 1)’."
  966. (let lp ((known *known-versions*))
  967. (match known
  968. (((version-str . version-val) . known)
  969. (if (string= str version-str start end)
  970. version-val
  971. (lp known)))
  972. (()
  973. (let ((dot-idx (string-index str #\. start end)))
  974. (unless (and (string-prefix? "HTTP/" str 0 5 start end)
  975. dot-idx
  976. (= dot-idx (string-rindex str #\. start end)))
  977. (bad-header-component 'http-version (substring str start end)))
  978. (cons (parse-non-negative-integer str (+ start 5) dot-idx)
  979. (parse-non-negative-integer str (1+ dot-idx) end)))))))
  980. (define (write-http-version val port)
  981. "Write the given major-minor version pair to PORT."
  982. (put-string port "HTTP/")
  983. (put-non-negative-integer port (car val))
  984. (put-char port #\.)
  985. (put-non-negative-integer port (cdr val)))
  986. (for-each
  987. (lambda (v)
  988. (set! *known-versions*
  989. (acons v (parse-http-version v 0 (string-length v))
  990. *known-versions*)))
  991. '("HTTP/1.0" "HTTP/1.1"))
  992. ;; Request-URI = "*" | absoluteURI | abs_path | authority
  993. ;;
  994. ;; The `authority' form is only permissible for the CONNECT method, so
  995. ;; because we don't expect people to implement CONNECT, we save
  996. ;; ourselves the trouble of that case, and disallow the CONNECT method.
  997. ;;
  998. (define* (parse-http-method str #:optional (start 0) (end (string-length str)))
  999. "Parse an HTTP method from STR. The result is an upper-case
  1000. symbol, like ‘GET’."
  1001. (cond
  1002. ((string= str "GET" start end) 'GET)
  1003. ((string= str "HEAD" start end) 'HEAD)
  1004. ((string= str "POST" start end) 'POST)
  1005. ((string= str "PUT" start end) 'PUT)
  1006. ((string= str "DELETE" start end) 'DELETE)
  1007. ((string= str "OPTIONS" start end) 'OPTIONS)
  1008. ((string= str "TRACE" start end) 'TRACE)
  1009. ((string= str "CONNECT" start end) 'CONNECT)
  1010. ((string= str "PATCH" start end) 'PATCH)
  1011. (else (bad-request "Invalid method: ~a" (substring str start end)))))
  1012. (define* (parse-request-uri str #:optional (start 0) (end (string-length str)))
  1013. "Parse a URI from an HTTP request line. Note that URIs in requests do
  1014. not have to have a scheme or host name. The result is a URI-reference
  1015. object."
  1016. (cond
  1017. ((= start end)
  1018. (bad-request "Missing Request-URI"))
  1019. ((string= str "*" start end)
  1020. #f)
  1021. ((eqv? (string-ref str start) #\/)
  1022. (let* ((q (string-index str #\? start end))
  1023. (f (string-index str #\# start end))
  1024. (q (and q (or (not f) (< q f)) q)))
  1025. (build-uri-reference
  1026. #:path (substring str start (or q f end))
  1027. #:query (and q (substring str (1+ q) (or f end)))
  1028. #:fragment (and f (substring str (1+ f) end)))))
  1029. (else
  1030. (or (string->uri (substring str start end))
  1031. (bad-request "Invalid URI: ~a" (substring str start end))))))
  1032. (define (read-request-line port)
  1033. "Read the first line of an HTTP request from PORT, returning
  1034. three values: the method, the URI, and the version."
  1035. (let* ((line (read-header-line port))
  1036. (d0 (string-index line char-set:whitespace)) ; "delimiter zero"
  1037. (d1 (string-rindex line char-set:whitespace)))
  1038. (unless (and d0 d1 (< d0 d1))
  1039. (bad-request "Bad Request-Line: ~s" line))
  1040. (values (parse-http-method line 0 d0)
  1041. (parse-request-uri line (skip-whitespace line (1+ d0) d1) d1)
  1042. (parse-http-version line (1+ d1) (string-length line)))))
  1043. (define (write-uri uri port)
  1044. (put-string port (uri->string uri #:include-fragment? #f)))
  1045. (define (write-request-line method uri version port)
  1046. "Write the first line of an HTTP request to PORT."
  1047. (put-symbol port method)
  1048. (put-char port #\space)
  1049. (when (http-proxy-port? port)
  1050. (let ((scheme (uri-scheme uri))
  1051. (host (uri-host uri))
  1052. (host-port (uri-port uri)))
  1053. (when (and scheme host)
  1054. (put-symbol port scheme)
  1055. (put-string port "://")
  1056. (cond
  1057. ((string-index host #\:)
  1058. (put-char port #\[)
  1059. (put-string port host)
  1060. (put-char port #\]))
  1061. (else
  1062. (put-string port host)))
  1063. (unless ((@@ (web uri) default-port?) scheme host-port)
  1064. (put-char port #\:)
  1065. (put-non-negative-integer port host-port)))))
  1066. (let ((path (uri-path uri))
  1067. (query (uri-query uri)))
  1068. (if (string-null? path)
  1069. (put-string port "/")
  1070. (put-string port path))
  1071. (when query
  1072. (put-string port "?")
  1073. (put-string port query)))
  1074. (put-char port #\space)
  1075. (write-http-version version port)
  1076. (put-string port "\r\n"))
  1077. (define (read-response-line port)
  1078. "Read the first line of an HTTP response from PORT, returning three
  1079. values: the HTTP version, the response code, and the (possibly empty)
  1080. \"reason phrase\"."
  1081. (let* ((line (read-header-line port))
  1082. (d0 (string-index line char-set:whitespace)) ; "delimiter zero"
  1083. (d1 (and d0 (string-index line char-set:whitespace
  1084. (skip-whitespace line d0)))))
  1085. (unless (and d0 d1)
  1086. (bad-response "Bad Response-Line: ~s" line))
  1087. (values (parse-http-version line 0 d0)
  1088. (parse-non-negative-integer line (skip-whitespace line d0 d1)
  1089. d1)
  1090. (string-trim-both line char-set:whitespace d1))))
  1091. (define (write-response-line version code reason-phrase port)
  1092. "Write the first line of an HTTP response to PORT."
  1093. (write-http-version version port)
  1094. (put-char port #\space)
  1095. (put-non-negative-integer port code)
  1096. (put-char port #\space)
  1097. (put-string port reason-phrase)
  1098. (put-string port "\r\n"))
  1099. ;;;
  1100. ;;; Helpers for declaring headers
  1101. ;;;
  1102. ;; emacs: (put 'declare-header! 'scheme-indent-function 1)
  1103. ;; emacs: (put 'declare-opaque!-header 'scheme-indent-function 1)
  1104. (define (declare-opaque-header! name)
  1105. "Declares a given header as \"opaque\", meaning that its value is not
  1106. treated specially, and is just returned as a plain string."
  1107. (declare-header! name
  1108. parse-opaque-string validate-opaque-string write-opaque-string))
  1109. ;; emacs: (put 'declare-date-header! 'scheme-indent-function 1)
  1110. (define (declare-date-header! name)
  1111. (declare-header! name
  1112. parse-date date? write-date))
  1113. ;; emacs: (put 'declare-string-list-header! 'scheme-indent-function 1)
  1114. (define (declare-string-list-header! name)
  1115. (declare-header! name
  1116. split-and-trim list-of-strings? write-list-of-strings))
  1117. ;; emacs: (put 'declare-symbol-list-header! 'scheme-indent-function 1)
  1118. (define (declare-symbol-list-header! name)
  1119. (declare-header! name
  1120. (lambda (str)
  1121. (map string->symbol (split-and-trim str)))
  1122. (lambda (v)
  1123. (list-of? v symbol?))
  1124. (lambda (v port)
  1125. (put-list port v put-symbol ", "))))
  1126. ;; emacs: (put 'declare-header-list-header! 'scheme-indent-function 1)
  1127. (define (declare-header-list-header! name)
  1128. (declare-header! name
  1129. split-header-names list-of-header-names? write-header-list))
  1130. ;; emacs: (put 'declare-integer-header! 'scheme-indent-function 1)
  1131. (define (declare-integer-header! name)
  1132. (declare-header! name
  1133. parse-non-negative-integer non-negative-integer?
  1134. (lambda (val port) (put-non-negative-integer port val))))
  1135. ;; emacs: (put 'declare-uri-reference-header! 'scheme-indent-function 1)
  1136. (define (declare-uri-reference-header! name)
  1137. (declare-header! name
  1138. (lambda (str)
  1139. (or (string->uri-reference str)
  1140. (bad-header-component 'uri-reference str)))
  1141. uri-reference?
  1142. write-uri))
  1143. ;; emacs: (put 'declare-quality-list-header! 'scheme-indent-function 1)
  1144. (define (declare-quality-list-header! name)
  1145. (declare-header! name
  1146. parse-quality-list validate-quality-list write-quality-list))
  1147. ;; emacs: (put 'declare-param-list-header! 'scheme-indent-function 1)
  1148. (define* (declare-param-list-header! name #:optional
  1149. (val-parser default-val-parser)
  1150. (val-validator default-val-validator)
  1151. (val-writer default-val-writer))
  1152. (declare-header! name
  1153. (lambda (str) (parse-param-list str val-parser))
  1154. (lambda (val) (validate-param-list val val-validator))
  1155. (lambda (val port) (write-param-list val port val-writer))))
  1156. ;; emacs: (put 'declare-key-value-list-header! 'scheme-indent-function 1)
  1157. (define* (declare-key-value-list-header! name #:optional
  1158. (val-parser default-val-parser)
  1159. (val-validator default-val-validator)
  1160. (val-writer default-val-writer))
  1161. (declare-header! name
  1162. (lambda (str) (parse-key-value-list str val-parser))
  1163. (lambda (val) (key-value-list? val val-validator))
  1164. (lambda (val port) (write-key-value-list val port val-writer))))
  1165. ;; emacs: (put 'declare-entity-tag-list-header! 'scheme-indent-function 1)
  1166. (define (declare-entity-tag-list-header! name)
  1167. (declare-header! name
  1168. (lambda (str) (if (string=? str "*") '* (parse-entity-tag-list str)))
  1169. (lambda (val) (or (eq? val '*) (entity-tag-list? val)))
  1170. (lambda (val port)
  1171. (if (eq? val '*)
  1172. (put-string port "*")
  1173. (put-entity-tag-list port val)))))
  1174. ;; emacs: (put 'declare-credentials-header! 'scheme-indent-function 1)
  1175. (define (declare-credentials-header! name)
  1176. (declare-header! name
  1177. parse-credentials validate-credentials write-credentials))
  1178. ;; emacs: (put 'declare-challenge-list-header! 'scheme-indent-function 1)
  1179. (define (declare-challenge-list-header! name)
  1180. (declare-header! name
  1181. parse-challenges validate-challenges write-challenges))
  1182. ;;;
  1183. ;;; General headers
  1184. ;;;
  1185. ;; Cache-Control = 1#(cache-directive)
  1186. ;; cache-directive = cache-request-directive | cache-response-directive
  1187. ;; cache-request-directive =
  1188. ;; "no-cache" ; Section 14.9.1
  1189. ;; | "no-store" ; Section 14.9.2
  1190. ;; | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
  1191. ;; | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
  1192. ;; | "min-fresh" "=" delta-seconds ; Section 14.9.3
  1193. ;; | "no-transform" ; Section 14.9.5
  1194. ;; | "only-if-cached" ; Section 14.9.4
  1195. ;; | cache-extension ; Section 14.9.6
  1196. ;; cache-response-directive =
  1197. ;; "public" ; Section 14.9.1
  1198. ;; | "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
  1199. ;; | "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
  1200. ;; | "no-store" ; Section 14.9.2
  1201. ;; | "no-transform" ; Section 14.9.5
  1202. ;; | "must-revalidate" ; Section 14.9.4
  1203. ;; | "proxy-revalidate" ; Section 14.9.4
  1204. ;; | "max-age" "=" delta-seconds ; Section 14.9.3
  1205. ;; | "s-maxage" "=" delta-seconds ; Section 14.9.3
  1206. ;; | cache-extension ; Section 14.9.6
  1207. ;; cache-extension = token [ "=" ( token | quoted-string ) ]
  1208. ;;
  1209. (declare-key-value-list-header! "Cache-Control"
  1210. (lambda (k v-str)
  1211. (case k
  1212. ((max-age min-fresh s-maxage)
  1213. (parse-non-negative-integer v-str))
  1214. ((max-stale)
  1215. (and v-str (parse-non-negative-integer v-str)))
  1216. ((private no-cache)
  1217. (and v-str (split-header-names v-str)))
  1218. (else v-str)))
  1219. (lambda (k v)
  1220. (case k
  1221. ((max-age min-fresh s-maxage)
  1222. (non-negative-integer? v))
  1223. ((max-stale)
  1224. (or (not v) (non-negative-integer? v)))
  1225. ((private no-cache)
  1226. (or (not v) (list-of-header-names? v)))
  1227. ((no-store no-transform only-if-cache must-revalidate proxy-revalidate)
  1228. (not v))
  1229. (else
  1230. (or (not v) (string? v)))))
  1231. (lambda (k v port)
  1232. (cond
  1233. ((string? v) (default-val-writer k v port))
  1234. ((pair? v)
  1235. (put-char port #\")
  1236. (write-header-list v port)
  1237. (put-char port #\"))
  1238. ((integer? v)
  1239. (put-non-negative-integer port v))
  1240. (else
  1241. (bad-header-component 'cache-control v)))))
  1242. ;; Connection = "Connection" ":" 1#(connection-token)
  1243. ;; connection-token = token
  1244. ;; e.g.
  1245. ;; Connection: close, Foo-Header
  1246. ;;
  1247. (declare-header! "Connection"
  1248. split-header-names
  1249. list-of-header-names?
  1250. (lambda (val port)
  1251. (put-list port val
  1252. (lambda (port x)
  1253. (put-string port
  1254. (if (eq? x 'close)
  1255. "close"
  1256. (header->string x))))
  1257. ", ")))
  1258. ;; Date = "Date" ":" HTTP-date
  1259. ;; e.g.
  1260. ;; Date: Tue, 15 Nov 1994 08:12:31 GMT
  1261. ;;
  1262. (declare-date-header! "Date")
  1263. ;; Pragma = "Pragma" ":" 1#pragma-directive
  1264. ;; pragma-directive = "no-cache" | extension-pragma
  1265. ;; extension-pragma = token [ "=" ( token | quoted-string ) ]
  1266. ;;
  1267. (declare-key-value-list-header! "Pragma")
  1268. ;; Trailer = "Trailer" ":" 1#field-name
  1269. ;;
  1270. (declare-header-list-header! "Trailer")
  1271. ;; Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
  1272. ;;
  1273. (declare-param-list-header! "Transfer-Encoding")
  1274. ;; Upgrade = "Upgrade" ":" 1#product
  1275. ;;
  1276. (declare-string-list-header! "Upgrade")
  1277. ;; Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
  1278. ;; received-protocol = [ protocol-name "/" ] protocol-version
  1279. ;; protocol-name = token
  1280. ;; protocol-version = token
  1281. ;; received-by = ( host [ ":" port ] ) | pseudonym
  1282. ;; pseudonym = token
  1283. ;;
  1284. (declare-header! "Via"
  1285. split-and-trim
  1286. list-of-strings?
  1287. write-list-of-strings
  1288. #:multiple? #t)
  1289. ;; Warning = "Warning" ":" 1#warning-value
  1290. ;;
  1291. ;; warning-value = warn-code SP warn-agent SP warn-text
  1292. ;; [SP warn-date]
  1293. ;;
  1294. ;; warn-code = 3DIGIT
  1295. ;; warn-agent = ( host [ ":" port ] ) | pseudonym
  1296. ;; ; the name or pseudonym of the server adding
  1297. ;; ; the Warning header, for use in debugging
  1298. ;; warn-text = quoted-string
  1299. ;; warn-date = <"> HTTP-date <">
  1300. (declare-header! "Warning"
  1301. (lambda (str)
  1302. (let ((len (string-length str)))
  1303. (let lp ((i (skip-whitespace str 0)))
  1304. (let* ((idx1 (string-index str #\space i))
  1305. (idx2 (string-index str #\space (1+ idx1))))
  1306. (when (and idx1 idx2)
  1307. (let ((code (parse-non-negative-integer str i idx1))
  1308. (agent (substring str (1+ idx1) idx2)))
  1309. (call-with-values
  1310. (lambda () (parse-qstring str (1+ idx2) #:incremental? #t))
  1311. (lambda (text i)
  1312. (call-with-values
  1313. (lambda ()
  1314. (let ((c (and (< i len) (string-ref str i))))
  1315. (case c
  1316. ((#\space)
  1317. ;; we have a date.
  1318. (call-with-values
  1319. (lambda () (parse-qstring str (1+ i)
  1320. #:incremental? #t))
  1321. (lambda (date i)
  1322. (values text (parse-date date) i))))
  1323. (else
  1324. (values text #f i)))))
  1325. (lambda (text date i)
  1326. (let ((w (list code agent text date))
  1327. (c (and (< i len) (string-ref str i))))
  1328. (case c
  1329. ((#f) (list w))
  1330. ((#\,) (cons w (lp (skip-whitespace str (1+ i)))))
  1331. (else (bad-header 'warning str))))))))))))))
  1332. (lambda (val)
  1333. (list-of? val
  1334. (lambda (elt)
  1335. (match elt
  1336. ((code host text date)
  1337. (and (non-negative-integer? code) (< code 1000)
  1338. (string? host)
  1339. (string? text)
  1340. (or (not date) (date? date))))
  1341. (_ #f)))))
  1342. (lambda (val port)
  1343. (put-list
  1344. port val
  1345. (lambda (port w)
  1346. (match w
  1347. ((code host text date)
  1348. (put-non-negative-integer port code)
  1349. (put-char port #\space)
  1350. (put-string port host)
  1351. (put-char port #\space)
  1352. (write-qstring text port)
  1353. (when date
  1354. (put-char port #\space)
  1355. (put-char port #\")
  1356. (write-date date port)
  1357. (put-char port #\")))))
  1358. ", "))
  1359. #:multiple? #t)
  1360. ;;;
  1361. ;;; Entity headers
  1362. ;;;
  1363. ;; Allow = #Method
  1364. ;;
  1365. (declare-symbol-list-header! "Allow")
  1366. ;; Content-Disposition = disposition-type *( ";" disposition-parm )
  1367. ;; disposition-type = "attachment" | disp-extension-token
  1368. ;; disposition-parm = filename-parm | disp-extension-parm
  1369. ;; filename-parm = "filename" "=" quoted-string
  1370. ;; disp-extension-token = token
  1371. ;; disp-extension-parm = token "=" ( token | quoted-string )
  1372. ;;
  1373. (declare-header! "Content-Disposition"
  1374. (lambda (str)
  1375. ;; Lazily reuse the param list parser.
  1376. (match (parse-param-list str default-val-parser)
  1377. ((disposition) disposition)
  1378. (_ (bad-header-component 'content-disposition str))))
  1379. (lambda (val)
  1380. (match val
  1381. (((? symbol?) ((? symbol?) . (? string?)) ...) #t)
  1382. (_ #f)))
  1383. (lambda (val port)
  1384. (write-param-list (list val) port)))
  1385. ;; Content-Encoding = 1#content-coding
  1386. ;;
  1387. (declare-symbol-list-header! "Content-Encoding")
  1388. ;; Content-Language = 1#language-tag
  1389. ;;
  1390. (declare-string-list-header! "Content-Language")
  1391. ;; Content-Length = 1*DIGIT
  1392. ;;
  1393. (declare-integer-header! "Content-Length")
  1394. ;; Content-Location = URI-reference
  1395. ;;
  1396. (declare-uri-reference-header! "Content-Location")
  1397. ;; Content-MD5 = <base64 of 128 bit MD5 digest as per RFC 1864>
  1398. ;;
  1399. (declare-opaque-header! "Content-MD5")
  1400. ;; Content-Range = content-range-spec
  1401. ;; content-range-spec = byte-content-range-spec
  1402. ;; byte-content-range-spec = bytes-unit SP
  1403. ;; byte-range-resp-spec "/"
  1404. ;; ( instance-length | "*" )
  1405. ;; byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
  1406. ;; | "*"
  1407. ;; instance-length = 1*DIGIT
  1408. ;;
  1409. (declare-header! "Content-Range"
  1410. (lambda (str)
  1411. (let ((dash (string-index str #\-))
  1412. (slash (string-index str #\/)))
  1413. (unless (and (string-prefix? "bytes " str) slash)
  1414. (bad-header 'content-range str))
  1415. (list 'bytes
  1416. (cond
  1417. (dash
  1418. (cons
  1419. (parse-non-negative-integer str 6 dash)
  1420. (parse-non-negative-integer str (1+ dash) slash)))
  1421. ((string= str "*" 6 slash)
  1422. '*)
  1423. (else
  1424. (bad-header 'content-range str)))
  1425. (if (string= str "*" (1+ slash))
  1426. '*
  1427. (parse-non-negative-integer str (1+ slash))))))
  1428. (lambda (val)
  1429. (match val
  1430. (((? symbol?)
  1431. (or '* ((? non-negative-integer?) . (? non-negative-integer?)))
  1432. (or '* (? non-negative-integer?)))
  1433. #t)
  1434. (_ #f)))
  1435. (lambda (val port)
  1436. (match val
  1437. ((unit range instance-length)
  1438. (put-symbol port unit)
  1439. (put-char port #\space)
  1440. (match range
  1441. ('*
  1442. (put-char port #\*))
  1443. ((start . end)
  1444. (put-non-negative-integer port start)
  1445. (put-char port #\-)
  1446. (put-non-negative-integer port end)))
  1447. (put-char port #\/)
  1448. (match instance-length
  1449. ('* (put-char port #\*))
  1450. (len (put-non-negative-integer port len)))))))
  1451. ;; Content-Type = media-type
  1452. ;;
  1453. (declare-header! "Content-Type"
  1454. (lambda (str)
  1455. (let ((parts (string-split str #\;)))
  1456. (cons (parse-media-type (car parts))
  1457. (map (lambda (x)
  1458. (let ((eq (string-index x #\=)))
  1459. (unless (and eq (= eq (string-rindex x #\=)))
  1460. (bad-header 'content-type str))
  1461. (cons
  1462. (string->symbol
  1463. (string-trim x char-set:whitespace 0 eq))
  1464. (string-trim-right x char-set:whitespace (1+ eq)))))
  1465. (cdr parts)))))
  1466. (lambda (val)
  1467. (match val
  1468. (((? symbol?) ((? symbol?) . (? string?)) ...) #t)
  1469. (_ #f)))
  1470. (lambda (val port)
  1471. (match val
  1472. ((type . args)
  1473. (put-symbol port type)
  1474. (match args
  1475. (() (values))
  1476. (args
  1477. (put-string port ";")
  1478. (put-list
  1479. port args
  1480. (lambda (port pair)
  1481. (match pair
  1482. ((k . v)
  1483. (put-symbol port k)
  1484. (put-char port #\=)
  1485. (put-string port v))))
  1486. ";")))))))
  1487. ;; Expires = HTTP-date
  1488. ;;
  1489. (define *date-in-the-past* (parse-date "Thu, 01 Jan 1970 00:00:00 GMT"))
  1490. (declare-header! "Expires"
  1491. (lambda (str)
  1492. (if (member str '("0" "-1"))
  1493. *date-in-the-past*
  1494. (parse-date str)))
  1495. date?
  1496. write-date)
  1497. ;; Last-Modified = HTTP-date
  1498. ;;
  1499. (declare-date-header! "Last-Modified")
  1500. ;;;
  1501. ;;; Request headers
  1502. ;;;
  1503. ;; Accept = #( media-range [ accept-params ] )
  1504. ;; media-range = ( "*/*" | ( type "/" "*" ) | ( type "/" subtype ) )
  1505. ;; *( ";" parameter )
  1506. ;; accept-params = ";" "q" "=" qvalue *( accept-extension )
  1507. ;; accept-extension = ";" token [ "=" ( token | quoted-string ) ]
  1508. ;;
  1509. (declare-param-list-header! "Accept"
  1510. ;; -> (type/subtype (sym-prop . str-val) ...) ...)
  1511. ;;
  1512. ;; with the exception of prop `q', in which case the val will be a
  1513. ;; valid quality value
  1514. ;;
  1515. (lambda (k v)
  1516. (if (eq? k 'q)
  1517. (parse-quality v)
  1518. v))
  1519. (lambda (k v)
  1520. (if (eq? k 'q)
  1521. (valid-quality? v)
  1522. (or (not v) (string? v))))
  1523. (lambda (k v port)
  1524. (if (eq? k 'q)
  1525. (write-quality v port)
  1526. (default-val-writer k v port))))
  1527. ;; Accept-Charset = 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
  1528. ;;
  1529. (declare-quality-list-header! "Accept-Charset")
  1530. ;; Accept-Encoding = 1#( codings [ ";" "q" "=" qvalue ] )
  1531. ;; codings = ( content-coding | "*" )
  1532. ;;
  1533. (declare-quality-list-header! "Accept-Encoding")
  1534. ;; Accept-Language = 1#( language-range [ ";" "q" "=" qvalue ] )
  1535. ;; language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
  1536. ;;
  1537. (declare-quality-list-header! "Accept-Language")
  1538. ;; Authorization = credentials
  1539. ;; credentials = auth-scheme #auth-param
  1540. ;; auth-scheme = token
  1541. ;; auth-param = token "=" ( token | quoted-string )
  1542. ;;
  1543. (declare-credentials-header! "Authorization")
  1544. ;; Expect = 1#expectation
  1545. ;; expectation = "100-continue" | expectation-extension
  1546. ;; expectation-extension = token [ "=" ( token | quoted-string )
  1547. ;; *expect-params ]
  1548. ;; expect-params = ";" token [ "=" ( token | quoted-string ) ]
  1549. ;;
  1550. (declare-param-list-header! "Expect")
  1551. ;; From = mailbox
  1552. ;;
  1553. ;; Should be an email address; we just pass on the string as-is.
  1554. ;;
  1555. (declare-opaque-header! "From")
  1556. ;; Host = host [ ":" port ]
  1557. ;;
  1558. (declare-header! "Host"
  1559. (lambda (str)
  1560. (let* ((rbracket (string-index str #\]))
  1561. (colon (string-index str #\: (or rbracket 0)))
  1562. (host (cond
  1563. (rbracket
  1564. (unless (eqv? (string-ref str 0) #\[)
  1565. (bad-header 'host str))
  1566. (substring str 1 rbracket))
  1567. (colon
  1568. (substring str 0 colon))
  1569. (else
  1570. str)))
  1571. (port (and colon
  1572. (parse-non-negative-integer str (1+ colon)))))
  1573. (cons host port)))
  1574. (lambda (val)
  1575. (match val
  1576. (((? string?) . (or #f (? non-negative-integer?))) #t)
  1577. (_ #f)))
  1578. (lambda (val port)
  1579. (match val
  1580. ((host-name . host-port)
  1581. (cond
  1582. ((string-index host-name #\:)
  1583. (put-char port #\[)
  1584. (put-string port host-name)
  1585. (put-char port #\]))
  1586. (else
  1587. (put-string port host-name)))
  1588. (when host-port
  1589. (put-char port #\:)
  1590. (put-non-negative-integer port host-port))))))
  1591. ;; If-Match = ( "*" | 1#entity-tag )
  1592. ;;
  1593. (declare-entity-tag-list-header! "If-Match")
  1594. ;; If-Modified-Since = HTTP-date
  1595. ;;
  1596. (declare-date-header! "If-Modified-Since")
  1597. ;; If-None-Match = ( "*" | 1#entity-tag )
  1598. ;;
  1599. (declare-entity-tag-list-header! "If-None-Match")
  1600. ;; If-Range = ( entity-tag | HTTP-date )
  1601. ;;
  1602. (declare-header! "If-Range"
  1603. (lambda (str)
  1604. (if (or (string-prefix? "\"" str)
  1605. (string-prefix? "W/" str))
  1606. (parse-entity-tag str)
  1607. (parse-date str)))
  1608. (lambda (val)
  1609. (or (date? val) (entity-tag? val)))
  1610. (lambda (val port)
  1611. (if (date? val)
  1612. (write-date val port)
  1613. (put-entity-tag port val))))
  1614. ;; If-Unmodified-Since = HTTP-date
  1615. ;;
  1616. (declare-date-header! "If-Unmodified-Since")
  1617. ;; Max-Forwards = 1*DIGIT
  1618. ;;
  1619. (declare-integer-header! "Max-Forwards")
  1620. ;; Proxy-Authorization = credentials
  1621. ;;
  1622. (declare-credentials-header! "Proxy-Authorization")
  1623. ;; Range = "Range" ":" ranges-specifier
  1624. ;; ranges-specifier = byte-ranges-specifier
  1625. ;; byte-ranges-specifier = bytes-unit "=" byte-range-set
  1626. ;; byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
  1627. ;; byte-range-spec = first-byte-pos "-" [last-byte-pos]
  1628. ;; first-byte-pos = 1*DIGIT
  1629. ;; last-byte-pos = 1*DIGIT
  1630. ;; suffix-byte-range-spec = "-" suffix-length
  1631. ;; suffix-length = 1*DIGIT
  1632. ;;
  1633. (declare-header! "Range"
  1634. (lambda (str)
  1635. (unless (string-prefix? "bytes=" str)
  1636. (bad-header 'range str))
  1637. (cons
  1638. 'bytes
  1639. (map (lambda (x)
  1640. (let ((dash (string-index x #\-)))
  1641. (cond
  1642. ((not dash)
  1643. (bad-header 'range str))
  1644. ((zero? dash)
  1645. (cons #f (parse-non-negative-integer x 1)))
  1646. ((= dash (1- (string-length x)))
  1647. (cons (parse-non-negative-integer x 0 dash) #f))
  1648. (else
  1649. (cons (parse-non-negative-integer x 0 dash)
  1650. (parse-non-negative-integer x (1+ dash)))))))
  1651. (string-split (substring str 6) #\,))))
  1652. (lambda (val)
  1653. (match val
  1654. (((? symbol?)
  1655. (or (#f . (? non-negative-integer?))
  1656. ((? non-negative-integer?) . (? non-negative-integer?))
  1657. ((? non-negative-integer?) . #f))
  1658. ...) #t)
  1659. (_ #f)))
  1660. (lambda (val port)
  1661. (match val
  1662. ((unit . ranges)
  1663. (put-symbol port unit)
  1664. (put-char port #\=)
  1665. (put-list
  1666. port ranges
  1667. (lambda (port range)
  1668. (match range
  1669. ((start . end)
  1670. (when start (put-non-negative-integer port start))
  1671. (put-char port #\-)
  1672. (when end (put-non-negative-integer port end)))))
  1673. ",")))))
  1674. ;; Referer = URI-reference
  1675. ;;
  1676. (declare-uri-reference-header! "Referer")
  1677. ;; TE = #( t-codings )
  1678. ;; t-codings = "trailers" | ( transfer-extension [ accept-params ] )
  1679. ;;
  1680. (declare-param-list-header! "TE")
  1681. ;; User-Agent = 1*( product | comment )
  1682. ;;
  1683. (declare-opaque-header! "User-Agent")
  1684. ;;;
  1685. ;;; Reponse headers
  1686. ;;;
  1687. ;; Accept-Ranges = acceptable-ranges
  1688. ;; acceptable-ranges = 1#range-unit | "none"
  1689. ;;
  1690. (declare-symbol-list-header! "Accept-Ranges")
  1691. ;; Age = age-value
  1692. ;; age-value = delta-seconds
  1693. ;;
  1694. (declare-integer-header! "Age")
  1695. ;; ETag = entity-tag
  1696. ;;
  1697. (declare-header! "ETag"
  1698. parse-entity-tag
  1699. entity-tag?
  1700. (lambda (val port)
  1701. (put-entity-tag port val)))
  1702. ;; Location = URI-reference
  1703. ;;
  1704. ;; In RFC 2616, Location was specified as being an absolute URI. This
  1705. ;; was changed in RFC 7231 to permit URI references generally, which
  1706. ;; matches web reality.
  1707. ;;
  1708. (declare-uri-reference-header! "Location")
  1709. ;; Proxy-Authenticate = 1#challenge
  1710. ;;
  1711. (declare-challenge-list-header! "Proxy-Authenticate")
  1712. ;; Retry-After = ( HTTP-date | delta-seconds )
  1713. ;;
  1714. (declare-header! "Retry-After"
  1715. (lambda (str)
  1716. (if (and (not (string-null? str))
  1717. (char-numeric? (string-ref str 0)))
  1718. (parse-non-negative-integer str)
  1719. (parse-date str)))
  1720. (lambda (val)
  1721. (or (date? val) (non-negative-integer? val)))
  1722. (lambda (val port)
  1723. (if (date? val)
  1724. (write-date val port)
  1725. (put-non-negative-integer port val))))
  1726. ;; Server = 1*( product | comment )
  1727. ;;
  1728. (declare-opaque-header! "Server")
  1729. ;; Vary = ( "*" | 1#field-name )
  1730. ;;
  1731. (declare-header! "Vary"
  1732. (lambda (str)
  1733. (if (equal? str "*")
  1734. '*
  1735. (split-header-names str)))
  1736. (lambda (val)
  1737. (or (eq? val '*) (list-of-header-names? val)))
  1738. (lambda (val port)
  1739. (if (eq? val '*)
  1740. (put-string port "*")
  1741. (write-header-list val port))))
  1742. ;; WWW-Authenticate = 1#challenge
  1743. ;;
  1744. (declare-challenge-list-header! "WWW-Authenticate")
  1745. ;; Chunked Responses
  1746. (define &chunked-input-ended-prematurely
  1747. (make-exception-type '&chunked-input-error-prematurely
  1748. &external-error
  1749. '()))
  1750. (define make-chunked-input-ended-prematurely-error
  1751. (record-constructor &chunked-input-ended-prematurely))
  1752. (define chunked-input-ended-prematurely-error?
  1753. (record-predicate &chunked-input-ended-prematurely))
  1754. (define (read-chunk-header port)
  1755. "Read a chunk header from PORT and return the size in bytes of the
  1756. upcoming chunk."
  1757. (match (read-line port)
  1758. ((? eof-object?)
  1759. ;; Connection closed prematurely: there's nothing left to read.
  1760. 0)
  1761. (str
  1762. (let ((extension-start (string-index str
  1763. (lambda (c)
  1764. (or (char=? c #\;)
  1765. (char=? c #\return))))))
  1766. (string->number (if extension-start ; unnecessary?
  1767. (substring str 0 extension-start)
  1768. str)
  1769. 16)))))
  1770. (define* (make-chunked-input-port port #:key (keep-alive? #f))
  1771. "Returns a new port which translates HTTP chunked transfer encoded
  1772. data from PORT into a non-encoded format. Returns eof when it has
  1773. read the final chunk from PORT. This does not necessarily mean
  1774. that there is no more data on PORT. When the returned port is
  1775. closed it will also close PORT, unless the KEEP-ALIVE? is true."
  1776. (define (close)
  1777. (unless keep-alive?
  1778. (close-port port)))
  1779. (define chunk-size 0) ;size of the current chunk
  1780. (define remaining 0) ;number of bytes left from the current chunk
  1781. (define finished? #f) ;did we get all the chunks?
  1782. (define (read! bv idx to-read)
  1783. (define (loop to-read num-read)
  1784. (cond ((or finished? (zero? to-read))
  1785. num-read)
  1786. ((zero? remaining) ;get a new chunk
  1787. (let ((size (read-chunk-header port)))
  1788. (set! chunk-size size)
  1789. (set! remaining size)
  1790. (cond
  1791. ((zero? size)
  1792. (set! finished? #t)
  1793. (get-bytevector-n port 2) ; \r\n follows the last chunk
  1794. num-read)
  1795. (else
  1796. (loop to-read num-read)))))
  1797. (else ;read from the current chunk
  1798. (let* ((ask-for (min to-read remaining))
  1799. (read (get-bytevector-n! port bv (+ idx num-read)
  1800. ask-for)))
  1801. (cond
  1802. ((eof-object? read) ;premature termination
  1803. (raise-exception
  1804. (make-chunked-input-ended-prematurely-error)))
  1805. (else
  1806. (let ((left (- remaining read)))
  1807. (set! remaining left)
  1808. (when (zero? left)
  1809. ;; We're done with this chunk; read CR and LF.
  1810. (get-u8 port) (get-u8 port))
  1811. (loop (- to-read read)
  1812. (+ num-read read)))))))))
  1813. (loop to-read 0))
  1814. (make-custom-binary-input-port "chunked input port" read! #f #f close))
  1815. (define* (make-chunked-output-port port #:key (keep-alive? #f)
  1816. (buffering 1200))
  1817. "Returns a new port which translates non-encoded data into a HTTP
  1818. chunked transfer encoded data and writes this to PORT. Data written to
  1819. this port is buffered until the port is flushed, at which point it is
  1820. all sent as one chunk. The port will otherwise be flushed every
  1821. BUFFERING bytes, which defaults to 1200. Take care to close the port
  1822. when done, as it will output the remaining data, and encode the final
  1823. zero chunk. When the port is closed it will also close PORT, unless
  1824. KEEP-ALIVE? is true."
  1825. (define (write! bv start count)
  1826. (put-string port (number->string count 16))
  1827. (put-string port "\r\n")
  1828. (put-bytevector port bv start count)
  1829. (put-string port "\r\n")
  1830. (force-output port)
  1831. count)
  1832. (define (close)
  1833. (put-string port "0\r\n\r\n")
  1834. (force-output port)
  1835. (unless keep-alive?
  1836. (close-port port)))
  1837. (define ret
  1838. (make-custom-binary-output-port "chunked http" write! #f #f close))
  1839. (set-port-encoding! port "UTF-8")
  1840. (setvbuf ret 'block buffering)
  1841. ret)
  1842. (define %http-proxy-port? (make-object-property))
  1843. (define (http-proxy-port? port) (%http-proxy-port? port))
  1844. (define (set-http-proxy-port?! port flag)
  1845. (set! (%http-proxy-port? port) flag))