1 // 2 // request_parser.cpp 3 // ~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 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 server3 { 16 request_parser()17request_parser::request_parser() 18 : state_(method_start) 19 { 20 } 21 reset()22void request_parser::reset() 23 { 24 state_ = method_start; 25 } 26 consume(request & req,char input)27boost::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 is_char(int c)285bool request_parser::is_char(int c) 286 { 287 return c >= 0 && c <= 127; 288 } 289 is_ctl(int c)290bool request_parser::is_ctl(int c) 291 { 292 return (c >= 0 && c <= 31) || (c == 127); 293 } 294 is_tspecial(int c)295bool 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 is_digit(int c)309bool request_parser::is_digit(int c) 310 { 311 return c >= '0' && c <= '9'; 312 } 313 314 } // namespace server3 315 } // namespace http 316