5 // Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #include "request_parser.hpp"
12 #include "request.hpp"
17 request_parser::request_parser()
18 : state_(method_start)
22 void request_parser::reset()
24 state_ = method_start;
27 boost::tribool request_parser::consume(request& req, char input)
32 if (!is_char(input) || is_ctl(input) || is_tspecial(input))
39 req.method.push_back(input);
40 return boost::indeterminate;
46 return boost::indeterminate;
48 else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
54 req.method.push_back(input);
55 return boost::indeterminate;
60 state_ = http_version_h;
61 return boost::indeterminate;
63 else if (is_ctl(input))
69 req.uri.push_back(input);
70 return boost::indeterminate;
75 state_ = http_version_t_1;
76 return boost::indeterminate;
82 case http_version_t_1:
85 state_ = http_version_t_2;
86 return boost::indeterminate;
92 case http_version_t_2:
95 state_ = http_version_p;
96 return boost::indeterminate;
105 state_ = http_version_slash;
106 return boost::indeterminate;
112 case http_version_slash:
115 req.http_version_major = 0;
116 req.http_version_minor = 0;
117 state_ = http_version_major_start;
118 return boost::indeterminate;
124 case http_version_major_start:
127 req.http_version_major = req.http_version_major * 10 + input - '0';
128 state_ = http_version_major;
129 return boost::indeterminate;
135 case http_version_major:
138 state_ = http_version_minor_start;
139 return boost::indeterminate;
141 else if (is_digit(input))
143 req.http_version_major = req.http_version_major * 10 + input - '0';
144 return boost::indeterminate;
150 case http_version_minor_start:
153 req.http_version_minor = req.http_version_minor * 10 + input - '0';
154 state_ = http_version_minor;
155 return boost::indeterminate;
161 case http_version_minor:
164 state_ = expecting_newline_1;
165 return boost::indeterminate;
167 else if (is_digit(input))
169 req.http_version_minor = req.http_version_minor * 10 + input - '0';
170 return boost::indeterminate;
176 case expecting_newline_1:
179 state_ = header_line_start;
180 return boost::indeterminate;
186 case header_line_start:
189 state_ = expecting_newline_3;
190 return boost::indeterminate;
192 else if (!req.headers.empty() && (input == ' ' || input == '\t'))
195 return boost::indeterminate;
197 else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
203 req.headers.push_back(header());
204 req.headers.back().name.push_back(input);
205 state_ = header_name;
206 return boost::indeterminate;
211 state_ = expecting_newline_2;
212 return boost::indeterminate;
214 else if (input == ' ' || input == '\t')
216 return boost::indeterminate;
218 else if (is_ctl(input))
224 state_ = header_value;
225 req.headers.back().value.push_back(input);
226 return boost::indeterminate;
231 state_ = space_before_header_value;
232 return boost::indeterminate;
234 else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
240 req.headers.back().name.push_back(input);
241 return boost::indeterminate;
243 case space_before_header_value:
246 state_ = header_value;
247 return boost::indeterminate;
256 state_ = expecting_newline_2;
257 return boost::indeterminate;
259 else if (is_ctl(input))
265 req.headers.back().value.push_back(input);
266 return boost::indeterminate;
268 case expecting_newline_2:
271 state_ = header_line_start;
272 return boost::indeterminate;
278 case expecting_newline_3:
279 return (input == '\n');
285 bool request_parser::is_char(int c)
287 return c >= 0 && c <= 127;
290 bool request_parser::is_ctl(int c)
292 return (c >= 0 && c <= 31) || (c == 127);
295 bool request_parser::is_tspecial(int c)
299 case '(': case ')': case '<': case '>': case '@':
300 case ',': case ';': case ':': case '\\': case '"':
301 case '/': case '[': case ']': case '?': case '=':
302 case '{': case '}': case ' ': case '\t':
309 bool request_parser::is_digit(int c)
311 return c >= '0' && c <= '9';
314 } // namespace server