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