1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays ascii combinators.short-circuit kernel make
4 math.parser peg peg.parsers sequences sequences.deep strings ;
7 : except ( quot -- parser )
8 [ not ] compose satisfy ; inline
10 : except-these ( quots -- parser )
11 [ 1|| ] curry except ; inline
13 : cookie-key-disallow? ( ch -- ? )
16 : tspecial? ( ch -- ? )
17 "()<>@,;:\\\"/[]?={} \t" member? ;
19 : cookie-key-parser ( -- parser )
20 { [ control? ] [ cookie-key-disallow? ] } except-these repeat1 ;
22 : token-parser ( -- parser )
23 { [ control? ] [ tspecial? ] } except-these repeat1 ;
25 : case-insensitive ( parser -- parser' )
26 [ flatten >string >lower ] action ;
28 : case-sensitive ( parser -- parser' )
29 [ flatten >string ] action ;
31 : space-parser ( -- parser )
32 [ " \t" member? ] satisfy repeat0 hide ;
34 : one-of ( strings -- parser )
35 [ token ] map choice ;
37 : http-method-parser ( -- parser )
38 { "OPTIONS" "GET" "HEAD" "POST" "PUT" "DELETE" "TRACE" "CONNECT" "PATCH" } one-of ;
40 : url-parser ( -- parser )
41 [ " \t\r\n" member? ] except repeat1 case-sensitive ;
43 : http-version-parser ( -- parser )
52 ] seq* [ "" concat-as ] action ;
54 : full-request-parser ( -- parser )
65 : simple-request-parser ( -- parser )
72 ] seq* [ "1.0" suffix! ] action ;
74 PEG: parse-request-line ( string -- triple )
75 ! Triple is { method url version }
76 full-request-parser simple-request-parser 2array choice ;
78 : text-parser ( -- parser )
81 : response-code-parser ( -- parser )
82 [ digit? ] satisfy 3 exactly-n [ string>number ] action ;
84 : response-message-parser ( -- parser )
85 text-parser repeat0 case-sensitive ;
87 PEG: parse-response-line ( string -- triple )
88 ! Triple is { version code message }
93 response-code-parser ,
95 response-message-parser ,
98 : crlf-parser ( -- parser )
101 : lws-parser ( -- parser )
102 [ " \t" member? ] satisfy repeat1 ;
104 : qdtext-parser ( -- parser )
105 { [ CHAR: \" = ] [ control? ] } except-these ;
107 : quoted-char-parser ( -- parser )
108 "\\" token hide any-char 2seq ;
110 : quoted-string-parser ( -- parser )
111 quoted-char-parser qdtext-parser 2choice repeat0 "\"" "\"" surrounded-by ;
113 : ctext-parser ( -- parser )
114 { [ control? ] [ "()" member? ] } except-these ;
116 : comment-parser ( -- parser )
117 ctext-parser comment-parser 2choice repeat0 "(" ")" surrounded-by ;
119 : field-name-parser ( -- parser )
120 token-parser case-insensitive ;
122 : field-content-parser ( -- parser )
123 quoted-string-parser case-sensitive
124 text-parser repeat0 case-sensitive
127 PEG: parse-header-line ( string -- pair )
128 ! Pair is either { name value } or { f value }. If f, its a
129 ! continuation of the previous header line.
135 field-content-parser ,
138 lws-parser [ drop f ] action ,
139 field-content-parser ,
143 : word-parser ( -- parser )
144 token-parser quoted-string-parser 2choice ;
146 : value-parser ( -- parser )
148 [ ";" member? ] except repeat0
149 2choice case-sensitive ;
151 : attr-parser ( -- parser )
152 cookie-key-parser case-sensitive ;
154 : av-pair-parser ( -- parser )
159 [ "=" token , space-parser , value-parser , ] seq* [ last ] action optional ,
163 : av-pairs-parser ( -- parser )
164 av-pair-parser ";" token list-of optional ;
166 PEG: (parse-set-cookie) ( string -- alist )
167 av-pairs-parser just [ sift ] action ;
169 : cookie-value-parser ( -- parser )
179 [ ";,=" member? not ] satisfy repeat0 [ drop f ] action
182 PEG: (parse-cookie) ( string -- alist )
183 cookie-value-parser [ ";," member? ] satisfy list-of
184 optional just [ sift ] action ;