src/​examples/​cpp03/​http/​server/​request_parser.​cppsrc/​examples/​cpp11/​http/​server/​request_parser.​cpp
1 /​/​1 /​/​
2 /​/​·​request_parser.​cpp2 /​/​·​request_parser.​cpp
3 /​/​·​~~~~~~~~~~~~~~~~~~3 /​/​·​~~~~~~~~~~~~~~~~~~
4 /​/​4 /​/​
5 /​/​·​Copyright·​(c)​·​2003-​2023·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2023·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​
6 /​/​6 /​/​
7 /​/​·​Distributed·​under·​the·​Boost·​Software·​License,​·​Version·​1.​0.​·​(See·​accompanying7 /​/​·​Distributed·​under·​the·​Boost·​Software·​License,​·​Version·​1.​0.​·​(See·​accompanying
8 /​/​·​file·​LICENSE_1_0.​txt·​or·​copy·​at·​http:​/​/​www.​boost.​org/​LICENSE_1_0.​txt)​8 /​/​·​file·​LICENSE_1_0.​txt·​or·​copy·​at·​http:​/​/​www.​boost.​org/​LICENSE_1_0.​txt)​
9 /​/​9 /​/​
10 10
11 #include·​"request_parser.​hpp"11 #include·​"request_parser.​hpp"
12 #include·​"request.​hpp"12 #include·​"request.​hpp"
13 13
14 namespace·​http·​{14 namespace·​http·​{
15 namespace·​server·​{15 namespace·​server·​{
16 16
17 request_parser:​:​request_parser()​17 request_parser:​:​request_parser()​
18 ··​:​·​state_(method_start)​18 ··​:​·​state_(method_start)​
19 {19 {
20 }20 }
21 21
22 void·​request_parser:​:​reset()​22 void·​request_parser:​:​reset()​
23 {23 {
24 ··​state_·​=·​method_start;​24 ··​state_·​=·​method_start;​
25 }25 }
26 26
27 boost:​:​tribool·​request_parser:​:​consume(request&·​req,​·​char·​input)​27 request_parser:​:​result_type·​request_parser:​:​consume(request&·​req,​·​char·​input)​
28 {28 {
29 ··​switch·​(state_)​29 ··​switch·​(state_)​
30 ··​{30 ··​{
31 ··​case·​method_start:​31 ··​case·​method_start:​
32 ····​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​32 ····​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​
33 ····​{33 ····​{
34 ······​return·false;​34 ······​return·bad;​
35 ····​}35 ····​}
36 ····​else36 ····​else
37 ····​{37 ····​{
38 ······​state_·​=·​method;​38 ······​state_·​=·​method;​
39 ······​req.​method.​push_back(input)​;​39 ······​req.​method.​push_back(input)​;​
40 ······​return·boost:​:​indeterminate;​40 ······​return·​indeterminate;​
41 ····​}41 ····​}
42 ··​case·​method:​42 ··​case·​method:​
43 ····​if·​(input·​==·​'·​')​43 ····​if·​(input·​==·​'·​')​
44 ····​{44 ····​{
45 ······​state_·​=·​uri;​45 ······​state_·​=·​uri;​
46 ······​return·boost:​:​indeterminate;​46 ······​return·​indeterminate;​
47 ····​}47 ····​}
48 ····​else·​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​48 ····​else·​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​
49 ····​{49 ····​{
50 ······​return·false;​50 ······​return·bad;​
51 ····​}51 ····​}
52 ····​else52 ····​else
53 ····​{53 ····​{
54 ······​req.​method.​push_back(input)​;​54 ······​req.​method.​push_back(input)​;​
55 ······​return·boost:​:​indeterminate;​55 ······​return·​indeterminate;​
56 ····​}56 ····​}
57 ··​case·​uri:​57 ··​case·​uri:​
58 ····​if·​(input·​==·​'·​')​58 ····​if·​(input·​==·​'·​')​
59 ····​{59 ····​{
60 ······​state_·​=·​http_version_h;​60 ······​state_·​=·​http_version_h;​
61 ······​return·boost:​:​indeterminate;​61 ······​return·​indeterminate;​
62 ····​}62 ····​}
63 ····​else·​if·​(is_ctl(input)​)​63 ····​else·​if·​(is_ctl(input)​)​
64 ····​{64 ····​{
65 ······​return·false;​65 ······​return·bad;​
66 ····​}66 ····​}
67 ····​else67 ····​else
68 ····​{68 ····​{
69 ······​req.​uri.​push_back(input)​;​69 ······​req.​uri.​push_back(input)​;​
70 ······​return·boost:​:​indeterminate;​70 ······​return·​indeterminate;​
71 ····​}71 ····​}
72 ··​case·​http_version_h:​72 ··​case·​http_version_h:​
73 ····​if·​(input·​==·​'H')​73 ····​if·​(input·​==·​'H')​
74 ····​{74 ····​{
75 ······​state_·​=·​http_version_t_1;​75 ······​state_·​=·​http_version_t_1;​
76 ······​return·boost:​:​indeterminate;​76 ······​return·​indeterminate;​
77 ····​}77 ····​}
78 ····​else78 ····​else
79 ····​{79 ····​{
80 ······​return·false;​80 ······​return·bad;​
81 ····​}81 ····​}
82 ··​case·​http_version_t_1:​82 ··​case·​http_version_t_1:​
83 ····​if·​(input·​==·​'T')​83 ····​if·​(input·​==·​'T')​
84 ····​{84 ····​{
85 ······​state_·​=·​http_version_t_2;​85 ······​state_·​=·​http_version_t_2;​
86 ······​return·boost:​:​indeterminate;​86 ······​return·​indeterminate;​
87 ····​}87 ····​}
88 ····​else88 ····​else
89 ····​{89 ····​{
90 ······​return·false;​90 ······​return·bad;​
91 ····​}91 ····​}
92 ··​case·​http_version_t_2:​92 ··​case·​http_version_t_2:​
93 ····​if·​(input·​==·​'T')​93 ····​if·​(input·​==·​'T')​
94 ····​{94 ····​{
95 ······​state_·​=·​http_version_p;​95 ······​state_·​=·​http_version_p;​
96 ······​return·boost:​:​indeterminate;​96 ······​return·​indeterminate;​
97 ····​}97 ····​}
98 ····​else98 ····​else
99 ····​{99 ····​{
100 ······​return·false;​100 ······​return·bad;​
101 ····​}101 ····​}
102 ··​case·​http_version_p:​102 ··​case·​http_version_p:​
103 ····​if·​(input·​==·​'P')​103 ····​if·​(input·​==·​'P')​
104 ····​{104 ····​{
105 ······​state_·​=·​http_version_slash;​105 ······​state_·​=·​http_version_slash;​
106 ······​return·boost:​:​indeterminate;​106 ······​return·​indeterminate;​
107 ····​}107 ····​}
108 ····​else108 ····​else
109 ····​{109 ····​{
110 ······​return·false;​110 ······​return·bad;​
111 ····​}111 ····​}
112 ··​case·​http_version_slash:​112 ··​case·​http_version_slash:​
113 ····​if·​(input·​==·​'/​')​113 ····​if·​(input·​==·​'/​')​
114 ····​{114 ····​{
115 ······​req.​http_version_major·​=·​0;​115 ······​req.​http_version_major·​=·​0;​
116 ······​req.​http_version_minor·​=·​0;​116 ······​req.​http_version_minor·​=·​0;​
117 ······​state_·​=·​http_version_major_st​art;​117 ······​state_·​=·​http_version_major_st​art;​
118 ······​return·boost:​:​indeterminate;​118 ······​return·​indeterminate;​
119 ····​}119 ····​}
120 ····​else120 ····​else
121 ····​{121 ····​{
122 ······​return·false;​122 ······​return·bad;​
123 ····​}123 ····​}
124 ··​case·​http_version_major_st​art:​124 ··​case·​http_version_major_st​art:​
125 ····​if·​(is_digit(input)​)​125 ····​if·​(is_digit(input)​)​
126 ····​{126 ····​{
127 ······​req.​http_version_major·​=·​req.​http_version_major·​*·​10·​+·​input·​-​·​'0';​127 ······​req.​http_version_major·​=·​req.​http_version_major·​*·​10·​+·​input·​-​·​'0';​
128 ······​state_·​=·​http_version_major;​128 ······​state_·​=·​http_version_major;​
129 ······​return·boost:​:​indeterminate;​129 ······​return·​indeterminate;​
130 ····​}130 ····​}
131 ····​else131 ····​else
132 ····​{132 ····​{
133 ······​return·false;​133 ······​return·bad;​
134 ····​}134 ····​}
135 ··​case·​http_version_major:​135 ··​case·​http_version_major:​
136 ····​if·​(input·​==·​'.​')​136 ····​if·​(input·​==·​'.​')​
137 ····​{137 ····​{
138 ······​state_·​=·​http_version_minor_st​art;​138 ······​state_·​=·​http_version_minor_st​art;​
139 ······​return·boost:​:​indeterminate;​139 ······​return·​indeterminate;​
140 ····​}140 ····​}
141 ····​else·​if·​(is_digit(input)​)​141 ····​else·​if·​(is_digit(input)​)​
142 ····​{142 ····​{
143 ······​req.​http_version_major·​=·​req.​http_version_major·​*·​10·​+·​input·​-​·​'0';​143 ······​req.​http_version_major·​=·​req.​http_version_major·​*·​10·​+·​input·​-​·​'0';​
144 ······​return·boost:​:​indeterminate;​144 ······​return·​indeterminate;​
145 ····​}145 ····​}
146 ····​else146 ····​else
147 ····​{147 ····​{
148 ······​return·false;​148 ······​return·bad;​
149 ····​}149 ····​}
150 ··​case·​http_version_minor_st​art:​150 ··​case·​http_version_minor_st​art:​
151 ····​if·​(is_digit(input)​)​151 ····​if·​(is_digit(input)​)​
152 ····​{152 ····​{
153 ······​req.​http_version_minor·​=·​req.​http_version_minor·​*·​10·​+·​input·​-​·​'0';​153 ······​req.​http_version_minor·​=·​req.​http_version_minor·​*·​10·​+·​input·​-​·​'0';​
154 ······​state_·​=·​http_version_minor;​154 ······​state_·​=·​http_version_minor;​
155 ······​return·boost:​:​indeterminate;​155 ······​return·​indeterminate;​
156 ····​}156 ····​}
157 ····​else157 ····​else
158 ····​{158 ····​{
159 ······​return·false;​159 ······​return·bad;​
160 ····​}160 ····​}
161 ··​case·​http_version_minor:​161 ··​case·​http_version_minor:​
162 ····​if·​(input·​==·​'\r')​162 ····​if·​(input·​==·​'\r')​
163 ····​{163 ····​{
164 ······​state_·​=·​expecting_newline_1;​164 ······​state_·​=·​expecting_newline_1;​
165 ······​return·boost:​:​indeterminate;​165 ······​return·​indeterminate;​
166 ····​}166 ····​}
167 ····​else·​if·​(is_digit(input)​)​167 ····​else·​if·​(is_digit(input)​)​
168 ····​{168 ····​{
169 ······​req.​http_version_minor·​=·​req.​http_version_minor·​*·​10·​+·​input·​-​·​'0';​169 ······​req.​http_version_minor·​=·​req.​http_version_minor·​*·​10·​+·​input·​-​·​'0';​
170 ······​return·boost:​:​indeterminate;​170 ······​return·​indeterminate;​
171 ····​}171 ····​}
172 ····​else172 ····​else
173 ····​{173 ····​{
174 ······​return·false;​174 ······​return·bad;​
175 ····​}175 ····​}
176 ··​case·​expecting_newline_1:​176 ··​case·​expecting_newline_1:​
177 ····​if·​(input·​==·​'\n')​177 ····​if·​(input·​==·​'\n')​
178 ····​{178 ····​{
179 ······​state_·​=·​header_line_start;​179 ······​state_·​=·​header_line_start;​
180 ······​return·boost:​:​indeterminate;​180 ······​return·​indeterminate;​
181 ····​}181 ····​}
182 ····​else182 ····​else
183 ····​{183 ····​{
184 ······​return·false;​184 ······​return·bad;​
185 ····​}185 ····​}
186 ··​case·​header_line_start:​186 ··​case·​header_line_start:​
187 ····​if·​(input·​==·​'\r')​187 ····​if·​(input·​==·​'\r')​
188 ····​{188 ····​{
189 ······​state_·​=·​expecting_newline_3;​189 ······​state_·​=·​expecting_newline_3;​
190 ······​return·boost:​:​indeterminate;​190 ······​return·​indeterminate;​
191 ····​}191 ····​}
192 ····​else·​if·​(!req.​headers.​empty()​·​&&·​(input·​==·​'·​'·​||·​input·​==·​'\t')​)​192 ····​else·​if·​(!req.​headers.​empty()​·​&&·​(input·​==·​'·​'·​||·​input·​==·​'\t')​)​
193 ····​{193 ····​{
194 ······​state_·​=·​header_lws;​194 ······​state_·​=·​header_lws;​
195 ······​return·boost:​:​indeterminate;​195 ······​return·​indeterminate;​
196 ····​}196 ····​}
197 ····​else·​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​197 ····​else·​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​
198 ····​{198 ····​{
199 ······​return·false;​199 ······​return·bad;​
200 ····​}200 ····​}
201 ····​else201 ····​else
202 ····​{202 ····​{
203 ······​req.​headers.​push_back(header()​)​;​203 ······​req.​headers.​push_back(header()​)​;​
204 ······​req.​headers.​back()​.​name.​push_back(input)​;​204 ······​req.​headers.​back()​.​name.​push_back(input)​;​
205 ······​state_·​=·​header_name;​205 ······​state_·​=·​header_name;​
206 ······​return·boost:​:​indeterminate;​206 ······​return·​indeterminate;​
207 ····​}207 ····​}
208 ··​case·​header_lws:​208 ··​case·​header_lws:​
209 ····​if·​(input·​==·​'\r')​209 ····​if·​(input·​==·​'\r')​
210 ····​{210 ····​{
211 ······​state_·​=·​expecting_newline_2;​211 ······​state_·​=·​expecting_newline_2;​
212 ······​return·boost:​:​indeterminate;​212 ······​return·​indeterminate;​
213 ····​}213 ····​}
214 ····​else·​if·​(input·​==·​'·​'·​||·​input·​==·​'\t')​214 ····​else·​if·​(input·​==·​'·​'·​||·​input·​==·​'\t')​
215 ····​{215 ····​{
216 ······​return·boost:​:​indeterminate;​216 ······​return·​indeterminate;​
217 ····​}217 ····​}
218 ····​else·​if·​(is_ctl(input)​)​218 ····​else·​if·​(is_ctl(input)​)​
219 ····​{219 ····​{
220 ······​return·false;​220 ······​return·bad;​
221 ····​}221 ····​}
222 ····​else222 ····​else
223 ····​{223 ····​{
224 ······​state_·​=·​header_value;​224 ······​state_·​=·​header_value;​
225 ······​req.​headers.​back()​.​value.​push_back(input)​;​225 ······​req.​headers.​back()​.​value.​push_back(input)​;​
226 ······​return·boost:​:​indeterminate;​226 ······​return·​indeterminate;​
227 ····​}227 ····​}
228 ··​case·​header_name:​228 ··​case·​header_name:​
229 ····​if·​(input·​==·​':​')​229 ····​if·​(input·​==·​':​')​
230 ····​{230 ····​{
231 ······​state_·​=·​space_before_header_v​alue;​231 ······​state_·​=·​space_before_header_v​alue;​
232 ······​return·boost:​:​indeterminate;​232 ······​return·​indeterminate;​
233 ····​}233 ····​}
234 ····​else·​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​234 ····​else·​if·​(!is_char(input)​·​||·​is_ctl(input)​·​||·​is_tspecial(input)​)​
235 ····​{235 ····​{
236 ······​return·false;​236 ······​return·bad;​
237 ····​}237 ····​}
238 ····​else238 ····​else
239 ····​{239 ····​{
240 ······​req.​headers.​back()​.​name.​push_back(input)​;​240 ······​req.​headers.​back()​.​name.​push_back(input)​;​
241 ······​return·boost:​:​indeterminate;​241 ······​return·​indeterminate;​
242 ····​}242 ····​}
243 ··​case·​space_before_header_v​alue:​243 ··​case·​space_before_header_v​alue:​
244 ····​if·​(input·​==·​'·​')​244 ····​if·​(input·​==·​'·​')​
245 ····​{245 ····​{
246 ······​state_·​=·​header_value;​246 ······​state_·​=·​header_value;​
247 ······​return·boost:​:​indeterminate;​247 ······​return·​indeterminate;​
248 ····​}248 ····​}
249 ····​else249 ····​else
250 ····​{250 ····​{
251 ······​return·false;​251 ······​return·bad;​
252 ····​}252 ····​}
253 ··​case·​header_value:​253 ··​case·​header_value:​
254 ····​if·​(input·​==·​'\r')​254 ····​if·​(input·​==·​'\r')​
255 ····​{255 ····​{
256 ······​state_·​=·​expecting_newline_2;​256 ······​state_·​=·​expecting_newline_2;​
257 ······​return·boost:​:​indeterminate;​257 ······​return·​indeterminate;​
258 ····​}258 ····​}
259 ····​else·​if·​(is_ctl(input)​)​259 ····​else·​if·​(is_ctl(input)​)​
260 ····​{260 ····​{
261 ······​return·false;​261 ······​return·bad;​
262 ····​}262 ····​}
263 ····​else263 ····​else
264 ····​{264 ····​{
265 ······​req.​headers.​back()​.​value.​push_back(input)​;​265 ······​req.​headers.​back()​.​value.​push_back(input)​;​
266 ······​return·boost:​:​indeterminate;​266 ······​return·​indeterminate;​
267 ····​}267 ····​}
268 ··​case·​expecting_newline_2:​268 ··​case·​expecting_newline_2:​
269 ····​if·​(input·​==·​'\n')​269 ····​if·​(input·​==·​'\n')​
270 ····​{270 ····​{
271 ······​state_·​=·​header_line_start;​271 ······​state_·​=·​header_line_start;​
272 ······​return·boost:​:​indeterminate;​272 ······​return·​indeterminate;​
273 ····​}273 ····​}
274 ····​else274 ····​else
275 ····​{275 ····​{
276 ······​return·false;​276 ······​return·bad;​
277 ····​}277 ····​}
278 ··​case·​expecting_newline_3:​278 ··​case·​expecting_newline_3:​
279 ····​return·​(input·​==·​'\n')​;​279 ····​return·​(input·​==·​'\n')​·?·good·:​·bad;​
280 ··​default:​280 ··​default:​
281 ····​return·false;​281 ····​return·bad;​
282 ··​}282 ··​}
283 }283 }
284 284
285 bool·​request_parser:​:​is_char(int·​c)​285 bool·​request_parser:​:​is_char(int·​c)​
286 {286 {
287 ··​return·​c·​>=·​0·​&&·​c·​<=·​127;​287 ··​return·​c·​>=·​0·​&&·​c·​<=·​127;​
288 }288 }
289 289
290 bool·​request_parser:​:​is_ctl(int·​c)​290 bool·​request_parser:​:​is_ctl(int·​c)​
291 {291 {
292 ··​return·​(c·​>=·​0·​&&·​c·​<=·​31)​·​||·​(c·​==·​127)​;​292 ··​return·​(c·​>=·​0·​&&·​c·​<=·​31)​·​||·​(c·​==·​127)​;​
293 }293 }
294 294
295 bool·​request_parser:​:​is_tspecial(int·​c)​295 bool·​request_parser:​:​is_tspecial(int·​c)​
296 {296 {
297 ··​switch·​(c)​297 ··​switch·​(c)​
298 ··​{298 ··​{
299 ··​case·​'(':​·​case·​')​':​·​case·​'<':​·​case·​'>':​·​case·​'@':​299 ··​case·​'(':​·​case·​')​':​·​case·​'<':​·​case·​'>':​·​case·​'@':​
300 ··​case·​',​':​·​case·​';​':​·​case·​':​':​·​case·​'\\':​·​case·​'"':​300 ··​case·​',​':​·​case·​';​':​·​case·​':​':​·​case·​'\\':​·​case·​'"':​
301 ··​case·​'/​':​·​case·​'[':​·​case·​']':​·​case·​'?':​·​case·​'=':​301 ··​case·​'/​':​·​case·​'[':​·​case·​']':​·​case·​'?':​·​case·​'=':​
302 ··​case·​'{':​·​case·​'}':​·​case·​'·​':​·​case·​'\t':​302 ··​case·​'{':​·​case·​'}':​·​case·​'·​':​·​case·​'\t':​
303 ····​return·​true;​303 ····​return·​true;​
304 ··​default:​304 ··​default:​
305 ····​return·​false;​305 ····​return·​false;​
306 ··​}306 ··​}
307 }307 }
308 308
309 bool·​request_parser:​:​is_digit(int·​c)​309 bool·​request_parser:​:​is_digit(int·​c)​
310 {310 {
311 ··​return·​c·​>=·​'0'·​&&·​c·​<=·​'9';​311 ··​return·​c·​>=·​'0'·​&&·​c·​<=·​'9';​
312 }312 }
313 313
314 }·​/​/​·​namespace·​server314 }·​/​/​·​namespace·​server
315 }·​/​/​·​namespace·​http315 }·​/​/​·​namespace·​http