factor/basis/http/parsers/parsers.factor

180 lines
4.5 KiB
Factor

! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: combinators.short-circuit math math.order math.parser
kernel sequences sequences.deep peg peg.parsers assocs arrays
hashtables strings namespaces make ascii ;
IN: http.parsers
: except ( quot -- parser )
[ not ] compose satisfy ; inline
: except-these ( quots -- parser )
[ 1|| ] curry except ; inline
: tspecial? ( ch -- ? )
"()<>@,;:\\\"/[]?={} \t" member? ;
: token-parser ( -- parser )
{ [ control? ] [ tspecial? ] } except-these repeat1 ;
: case-insensitive ( parser -- parser' )
[ flatten >string >lower ] action ;
: case-sensitive ( parser -- parser' )
[ flatten >string ] action ;
: space-parser ( -- parser )
[ " \t" member? ] satisfy repeat0 hide ;
: one-of ( strings -- parser )
[ token ] map choice ;
: http-method-parser ( -- parser )
{ "OPTIONS" "GET" "HEAD" "POST" "PUT" "DELETE" "TRACE" "CONNECT" } one-of ;
: url-parser ( -- parser )
[ " \t\r\n" member? ] except repeat1 case-sensitive ;
: http-version-parser ( -- parser )
[
"HTTP" token hide ,
space-parser ,
"/" token hide ,
space-parser ,
"1" token ,
"." token ,
{ "0" "1" } one-of ,
] seq* [ "" concat-as ] action ;
: full-request-parser ( -- parser )
[
space-parser ,
http-method-parser ,
space-parser ,
url-parser ,
space-parser ,
http-version-parser ,
space-parser ,
] seq* ;
: simple-request-parser ( -- parser )
[
space-parser ,
"GET" token ,
space-parser ,
url-parser ,
space-parser ,
] seq* [ "1.0" suffix! ] action ;
PEG: parse-request-line ( string -- triple )
#! Triple is { method url version }
full-request-parser simple-request-parser 2array choice ;
: text-parser ( -- parser )
[ control? ] except ;
: response-code-parser ( -- parser )
[ digit? ] satisfy 3 exactly-n [ string>number ] action ;
: response-message-parser ( -- parser )
text-parser repeat0 case-sensitive ;
PEG: parse-response-line ( string -- triple )
#! Triple is { version code message }
[
space-parser ,
http-version-parser ,
space-parser ,
response-code-parser ,
space-parser ,
response-message-parser ,
] seq* just ;
: crlf-parser ( -- parser )
"\r\n" token ;
: lws-parser ( -- parser )
[ " \t" member? ] satisfy repeat1 ;
: qdtext-parser ( -- parser )
{ [ CHAR: " = ] [ control? ] } except-these ;
: quoted-char-parser ( -- parser )
"\\" token hide any-char 2seq ;
: quoted-string-parser ( -- parser )
quoted-char-parser qdtext-parser 2choice repeat0 "\"" "\"" surrounded-by ;
: ctext-parser ( -- parser )
{ [ control? ] [ "()" member? ] } except-these ;
: comment-parser ( -- parser )
ctext-parser comment-parser 2choice repeat0 "(" ")" surrounded-by ;
: field-name-parser ( -- parser )
token-parser case-insensitive ;
: field-content-parser ( -- parser )
quoted-string-parser case-sensitive
text-parser repeat0 case-sensitive
2choice ;
PEG: parse-header-line ( string -- pair )
#! Pair is either { name value } or { f value }. If f, its a
#! continuation of the previous header line.
[
field-name-parser ,
space-parser ,
":" token hide ,
space-parser ,
field-content-parser ,
] seq*
[
lws-parser [ drop f ] action ,
field-content-parser ,
] seq*
2choice ;
: word-parser ( -- parser )
token-parser quoted-string-parser 2choice ;
: value-parser ( -- parser )
quoted-string-parser
[ ";" member? ] except repeat0
2choice case-sensitive ;
: attr-parser ( -- parser )
token-parser case-sensitive ;
: av-pair-parser ( -- parser )
[
space-parser ,
attr-parser ,
space-parser ,
[ "=" token , space-parser , value-parser , ] seq* [ last ] action optional ,
space-parser ,
] seq* ;
: av-pairs-parser ( -- parser )
av-pair-parser ";" token list-of optional ;
PEG: (parse-set-cookie) ( string -- alist )
av-pairs-parser just [ sift ] action ;
: cookie-value-parser ( -- parser )
[
space-parser ,
attr-parser ,
space-parser ,
"=" token hide ,
space-parser ,
value-parser ,
space-parser ,
] seq*
[ ";,=" member? not ] satisfy repeat0 [ drop f ] action
2choice ;
PEG: (parse-cookie) ( string -- alist )
cookie-value-parser [ ";," member? ] satisfy list-of
optional just [ sift ] action ;