1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: combinators.short-circuit math math.order math.parser
4 kernel sequences sequences.deep peg peg.parsers assocs arrays
5 hashtables strings namespaces make ascii ;
8 : except ( quot -- parser )
9 [ not ] compose satisfy ; inline
11 : except-these ( quots -- parser )
12 [ 1|| ] curry except ; inline
14 : cookie-key-disallow? ( ch -- ? )
17 : tspecial? ( ch -- ? )
18 "()<>@,;:\\\"/[]?={} \t" member? ;
20 : cookie-key-parser ( -- parser )
21 { [ control? ] [ cookie-key-disallow? ] } except-these repeat1 ;
23 : token-parser ( -- parser )
24 { [ control? ] [ tspecial? ] } except-these repeat1 ;
26 : case-insensitive ( parser -- parser' )
27 [ flatten >string >lower ] action ;
29 : case-sensitive ( parser -- parser' )
30 [ flatten >string ] action ;
32 : space-parser ( -- parser )
33 [ " \t" member? ] satisfy repeat0 hide ;
35 : one-of ( strings -- parser )
36 [ token ] map choice ;
38 : http-method-parser ( -- parser )
39 { "OPTIONS" "GET" "HEAD" "POST" "PUT" "DELETE" "TRACE" "CONNECT" "PATCH" } one-of ;
41 : url-parser ( -- parser )
42 [ " \t\r\n" member? ] except repeat1 case-sensitive ;
44 : http-version-parser ( -- parser )
53 ] seq* [ "" concat-as ] action ;
55 : full-request-parser ( -- parser )
66 : simple-request-parser ( -- parser )
73 ] seq* [ "1.0" suffix! ] action ;
75 PEG: parse-request-line ( string -- triple )
76 ! Triple is { method url version }
77 full-request-parser simple-request-parser 2array choice ;
79 : text-parser ( -- parser )
82 : response-code-parser ( -- parser )
83 [ digit? ] satisfy 3 exactly-n [ string>number ] action ;
85 : response-message-parser ( -- parser )
86 text-parser repeat0 case-sensitive ;
88 PEG: parse-response-line ( string -- triple )
89 ! Triple is { version code message }
94 response-code-parser ,
96 response-message-parser ,
99 : crlf-parser ( -- parser )
102 : lws-parser ( -- parser )
103 [ " \t" member? ] satisfy repeat1 ;
105 : qdtext-parser ( -- parser )
106 { [ CHAR: \" = ] [ control? ] } except-these ;
108 : quoted-char-parser ( -- parser )
109 "\\" token hide any-char 2seq ;
111 : quoted-string-parser ( -- parser )
112 quoted-char-parser qdtext-parser 2choice repeat0 "\"" "\"" surrounded-by ;
114 : ctext-parser ( -- parser )
115 { [ control? ] [ "()" member? ] } except-these ;
117 : comment-parser ( -- parser )
118 ctext-parser comment-parser 2choice repeat0 "(" ")" surrounded-by ;
120 : field-name-parser ( -- parser )
121 token-parser case-insensitive ;
123 : field-content-parser ( -- parser )
124 quoted-string-parser case-sensitive
125 text-parser repeat0 case-sensitive
128 PEG: parse-header-line ( string -- pair )
129 ! Pair is either { name value } or { f value }. If f, its a
130 ! continuation of the previous header line.
136 field-content-parser ,
139 lws-parser [ drop f ] action ,
140 field-content-parser ,
144 : word-parser ( -- parser )
145 token-parser quoted-string-parser 2choice ;
147 : value-parser ( -- parser )
149 [ ";" member? ] except repeat0
150 2choice case-sensitive ;
152 : attr-parser ( -- parser )
153 cookie-key-parser case-sensitive ;
155 : av-pair-parser ( -- parser )
160 [ "=" token , space-parser , value-parser , ] seq* [ last ] action optional ,
164 : av-pairs-parser ( -- parser )
165 av-pair-parser ";" token list-of optional ;
167 PEG: (parse-set-cookie) ( string -- alist )
168 av-pairs-parser just [ sift ] action ;
170 : cookie-value-parser ( -- parser )
180 [ ";,=" member? not ] satisfy repeat0 [ drop f ] action
183 PEG: (parse-cookie) ( string -- alist )
184 cookie-value-parser [ ";," member? ] satisfy list-of
185 optional just [ sift ] action ;