]> gitweb.factorcode.org Git - factor.git/blob - basis/http/parsers/parsers.factor
Fix comments to be ! not #!.
[factor.git] / basis / http / parsers / parsers.factor
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 ;
6 IN: http.parsers
7
8 : except ( quot -- parser )
9     [ not ] compose satisfy ; inline
10
11 : except-these ( quots -- parser )
12     [ 1|| ] curry except ; inline
13
14 : tspecial? ( ch -- ? )
15     "()<>@,;:\\\"/[]?={} \t" member? ;
16
17 : token-parser ( -- parser )
18     { [ control? ] [ tspecial? ] } except-these repeat1 ;
19
20 : case-insensitive ( parser -- parser' )
21     [ flatten >string >lower ] action ;
22
23 : case-sensitive ( parser -- parser' )
24     [ flatten >string ] action ;
25
26 : space-parser ( -- parser )
27     [ " \t" member? ] satisfy repeat0 hide ;
28
29 : one-of ( strings -- parser )
30     [ token ] map choice ;
31
32 : http-method-parser ( -- parser )
33     { "OPTIONS" "GET" "HEAD" "POST" "PUT" "DELETE" "TRACE" "CONNECT" } one-of ;
34
35 : url-parser ( -- parser )
36     [ " \t\r\n" member? ] except repeat1 case-sensitive ;
37
38 : http-version-parser ( -- parser )
39     [
40         "HTTP" token hide ,
41         space-parser ,
42         "/" token hide ,
43         space-parser ,
44         "1" token ,
45         "." token ,
46         { "0" "1" } one-of ,
47     ] seq* [ "" concat-as ] action ;
48
49 : full-request-parser ( -- parser )
50     [
51         space-parser ,
52         http-method-parser ,
53         space-parser ,
54         url-parser ,
55         space-parser ,
56         http-version-parser ,
57         space-parser ,
58     ] seq* ;
59
60 : simple-request-parser ( -- parser )
61     [
62         space-parser ,
63         "GET" token ,
64         space-parser ,
65         url-parser ,
66         space-parser ,
67     ] seq* [ "1.0" suffix! ] action ;
68
69 PEG: parse-request-line ( string -- triple )
70     ! Triple is { method url version }
71     full-request-parser simple-request-parser 2array choice ;
72
73 : text-parser ( -- parser )
74     [ control? ] except ;
75
76 : response-code-parser ( -- parser )
77     [ digit? ] satisfy 3 exactly-n [ string>number ] action ;
78
79 : response-message-parser ( -- parser )
80     text-parser repeat0 case-sensitive ;
81
82 PEG: parse-response-line ( string -- triple )
83     ! Triple is { version code message }
84     [
85         space-parser ,
86         http-version-parser ,
87         space-parser ,
88         response-code-parser ,
89         space-parser ,
90         response-message-parser ,
91     ] seq* just ;
92
93 : crlf-parser ( -- parser )
94     "\r\n" token ;
95
96 : lws-parser ( -- parser )
97     [ " \t" member? ] satisfy repeat1 ;
98
99 : qdtext-parser ( -- parser )
100     { [ CHAR: " = ] [ control? ] } except-these ;
101
102 : quoted-char-parser ( -- parser )
103     "\\" token hide any-char 2seq ;
104
105 : quoted-string-parser ( -- parser )
106     quoted-char-parser qdtext-parser 2choice repeat0 "\"" "\"" surrounded-by ;
107
108 : ctext-parser ( -- parser )
109     { [ control? ] [ "()" member? ] } except-these ;
110
111 : comment-parser ( -- parser )
112     ctext-parser comment-parser 2choice repeat0 "(" ")" surrounded-by ;
113
114 : field-name-parser ( -- parser )
115     token-parser case-insensitive ;
116
117 : field-content-parser ( -- parser )
118     quoted-string-parser case-sensitive
119     text-parser repeat0 case-sensitive
120     2choice ;
121
122 PEG: parse-header-line ( string -- pair )
123     ! Pair is either { name value } or { f value }. If f, its a
124     ! continuation of the previous header line.
125     [
126         field-name-parser ,
127         space-parser ,
128         ":" token hide ,
129         space-parser ,
130         field-content-parser ,
131     ] seq*
132     [
133         lws-parser [ drop f ] action ,
134         field-content-parser ,
135     ] seq*
136     2choice ;
137
138 : word-parser ( -- parser )
139     token-parser quoted-string-parser 2choice ;
140
141 : value-parser ( -- parser )
142     quoted-string-parser
143     [ ";" member? ] except repeat0
144     2choice case-sensitive ;
145
146 : attr-parser ( -- parser )
147     token-parser case-sensitive ;
148
149 : av-pair-parser ( -- parser )
150     [
151         space-parser ,
152         attr-parser ,
153         space-parser ,
154         [ "=" token , space-parser , value-parser , ] seq* [ last ] action optional ,
155         space-parser ,
156     ] seq* ;
157
158 : av-pairs-parser ( -- parser )
159     av-pair-parser ";" token list-of optional ;
160
161 PEG: (parse-set-cookie) ( string -- alist )
162     av-pairs-parser just [ sift ] action ;
163
164 : cookie-value-parser ( -- parser )
165     [
166         space-parser ,
167         attr-parser ,
168         space-parser ,
169         "=" token hide ,
170         space-parser ,
171         value-parser ,
172         space-parser ,
173     ] seq*
174     [ ";,=" member? not ] satisfy repeat0 [ drop f ] action
175     2choice ;
176
177 PEG: (parse-cookie) ( string -- alist )
178     cookie-value-parser [ ";," member? ] satisfy list-of
179     optional just [ sift ] action ;