(define-module(www server-utils parse-request)#:export(request? request-method request-upath request-protocol-version request-headers request-body receive-request hqf<-upath alist<-query)#:use-module((www crlf)#:select(read-three-part-line read-headers/get-body))#:use-module((www url-coding)#:select(url-coding:decode))#:use-module((srfi srfi-2)#:select(and-let*))#:use-module((srfi srfi-9)#:select(define-record-type))#:use-module((srfi srfi-11)#:select(let-values))#:use-module((srfi srfi-13)#:select(substring/shared string-titlecase string-index string-tokenize))#:use-module((srfi srfi-14)#:select(char-set char-set-complement))#:use-module((ice-9 regex)#:select(match:substring))#:use-module(ice-9 optargs))
(define(read-request port s2s)(let-values(((method upath pvers)(read-three-part-line port)))(let-values(((headers get-body)(read-headers/get-body port s2s)))(values method upath pvers headers get-body))))
(define-record-type request(make-request method upath protocol-version headers body)request?(method request-method)(upath request-upath)(protocol-version request-protocol-version)(headers request-headers)(body request-body))
(define PV-RX(make-regexp "HTTP/([0-9]+)[.]([0-9]+)"))
(define*(receive-request port #:key(s2s string-titlecase)(style #f))(let((rd-req(or(and style(vector-ref style 0))read-request)))(let-values(((method upath pvers headers get-body)(rd-req port s2s)))(make-request(string->symbol method)upath(cond((regexp-exec PV-RX pvers)=>(lambda(m)(define(num n)(string->number(match:substring m n)))(cons(num 1)(num 2))))(else  '(1 . 0)))headers get-body))))
(define-macro (false-if-eof . body) `(catch  'unexpected-eof(lambda() ,@body)(lambda ignored #f)))
(define hqf<-upath(let((question-mark/number-sign(char-set #\? #\#)))(define (bit . x)(apply substring/shared upath x))(lambda(upath)(or(and-let*((one(string-index upath question-mark/number-sign))(h(bit 0 one))(more(#{1+}# one)))(and(string-null? h)(set! h #f))(cond((char=? #\#(string-ref upath one))(values h #f(bit more)))((string-index upath #\# more)=>(lambda(two)(values h(bit more two)(bit(#{1+}# two)))))(else(values h(bit more)#f))))(values upath #f #f)))))
(define amp-split(let((not-amp-cs(char-set-complement(char-set #\&))))(lambda(s)(string-tokenize s not-amp-cs))))
(define*(alist<-query query-string #:optional(u8 #f))(map(lambda(pair)(define (decode . args)(url-coding:decode(apply substring/shared pair args)u8))(let((mid(string-index pair #\=)))(cons(if mid(decode 0 mid)(decode 0))(and mid(decode(#{1+}# mid))))))(amp-split query-string)))
