00001 // 00002 // http_request_parser.cpp 00003 // ~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00009 // 00010 00011 #include "async_web_server_cpp/http_request_parser.hpp" 00012 00013 namespace async_web_server_cpp 00014 { 00015 HttpRequestParser::HttpRequestParser() 00016 : state_(method_start) 00017 { 00018 } 00019 00020 void HttpRequestParser::reset() 00021 { 00022 state_ = method_start; 00023 } 00024 00025 boost::tribool HttpRequestParser::consume(HttpRequest &req, char input) 00026 { 00027 switch (state_) 00028 { 00029 case method_start: 00030 if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 00031 { 00032 return false; 00033 } 00034 else 00035 { 00036 state_ = method; 00037 req.method.push_back(input); 00038 return boost::indeterminate; 00039 } 00040 case method: 00041 if (input == ' ') 00042 { 00043 state_ = uri; 00044 return boost::indeterminate; 00045 } 00046 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 00047 { 00048 return false; 00049 } 00050 else 00051 { 00052 req.method.push_back(input); 00053 return boost::indeterminate; 00054 } 00055 case uri: 00056 if (input == ' ') 00057 { 00058 state_ = http_version_h; 00059 return boost::indeterminate; 00060 } 00061 else if (is_ctl(input)) 00062 { 00063 return false; 00064 } 00065 else 00066 { 00067 req.uri.push_back(input); 00068 return boost::indeterminate; 00069 } 00070 case http_version_h: 00071 if (input == 'H') 00072 { 00073 state_ = http_version_t_1; 00074 return boost::indeterminate; 00075 } 00076 else 00077 { 00078 return false; 00079 } 00080 case http_version_t_1: 00081 if (input == 'T') 00082 { 00083 state_ = http_version_t_2; 00084 return boost::indeterminate; 00085 } 00086 else 00087 { 00088 return false; 00089 } 00090 case http_version_t_2: 00091 if (input == 'T') 00092 { 00093 state_ = http_version_p; 00094 return boost::indeterminate; 00095 } 00096 else 00097 { 00098 return false; 00099 } 00100 case http_version_p: 00101 if (input == 'P') 00102 { 00103 state_ = http_version_slash; 00104 return boost::indeterminate; 00105 } 00106 else 00107 { 00108 return false; 00109 } 00110 case http_version_slash: 00111 if (input == '/') 00112 { 00113 req.http_version_major = 0; 00114 req.http_version_minor = 0; 00115 state_ = http_version_major_start; 00116 return boost::indeterminate; 00117 } 00118 else 00119 { 00120 return false; 00121 } 00122 case http_version_major_start: 00123 if (is_digit(input)) 00124 { 00125 req.http_version_major = req.http_version_major * 10 + input - '0'; 00126 state_ = http_version_major; 00127 return boost::indeterminate; 00128 } 00129 else 00130 { 00131 return false; 00132 } 00133 case http_version_major: 00134 if (input == '.') 00135 { 00136 state_ = http_version_minor_start; 00137 return boost::indeterminate; 00138 } 00139 else if (is_digit(input)) 00140 { 00141 req.http_version_major = req.http_version_major * 10 + input - '0'; 00142 return boost::indeterminate; 00143 } 00144 else 00145 { 00146 return false; 00147 } 00148 case http_version_minor_start: 00149 if (is_digit(input)) 00150 { 00151 req.http_version_minor = req.http_version_minor * 10 + input - '0'; 00152 state_ = http_version_minor; 00153 return boost::indeterminate; 00154 } 00155 else 00156 { 00157 return false; 00158 } 00159 case http_version_minor: 00160 if (input == '\r') 00161 { 00162 state_ = expecting_newline_1; 00163 return boost::indeterminate; 00164 } 00165 else if (is_digit(input)) 00166 { 00167 req.http_version_minor = req.http_version_minor * 10 + input - '0'; 00168 return boost::indeterminate; 00169 } 00170 else 00171 { 00172 return false; 00173 } 00174 case expecting_newline_1: 00175 if (input == '\n') 00176 { 00177 state_ = header_line_start; 00178 return boost::indeterminate; 00179 } 00180 else 00181 { 00182 return false; 00183 } 00184 case header_line_start: 00185 if (input == '\r') 00186 { 00187 state_ = expecting_newline_3; 00188 return boost::indeterminate; 00189 } 00190 else if (!req.headers.empty() && (input == ' ' || input == '\t')) 00191 { 00192 state_ = header_lws; 00193 return boost::indeterminate; 00194 } 00195 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 00196 { 00197 return false; 00198 } 00199 else 00200 { 00201 req.headers.push_back(HttpHeader()); 00202 req.headers.back().name.push_back(input); 00203 state_ = header_name; 00204 return boost::indeterminate; 00205 } 00206 case header_lws: 00207 if (input == '\r') 00208 { 00209 state_ = expecting_newline_2; 00210 return boost::indeterminate; 00211 } 00212 else if (input == ' ' || input == '\t') 00213 { 00214 return boost::indeterminate; 00215 } 00216 else if (is_ctl(input)) 00217 { 00218 return false; 00219 } 00220 else 00221 { 00222 state_ = header_value; 00223 req.headers.back().value.push_back(input); 00224 return boost::indeterminate; 00225 } 00226 case header_name: 00227 if (input == ':') 00228 { 00229 state_ = space_before_header_value; 00230 return boost::indeterminate; 00231 } 00232 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 00233 { 00234 return false; 00235 } 00236 else 00237 { 00238 req.headers.back().name.push_back(input); 00239 return boost::indeterminate; 00240 } 00241 case space_before_header_value: 00242 if (input == ' ') 00243 { 00244 state_ = header_value; 00245 return boost::indeterminate; 00246 } 00247 else 00248 { 00249 return false; 00250 } 00251 case header_value: 00252 if (input == '\r') 00253 { 00254 state_ = expecting_newline_2; 00255 return boost::indeterminate; 00256 } 00257 else if (is_ctl(input)) 00258 { 00259 return false; 00260 } 00261 else 00262 { 00263 req.headers.back().value.push_back(input); 00264 return boost::indeterminate; 00265 } 00266 case expecting_newline_2: 00267 if (input == '\n') 00268 { 00269 state_ = header_line_start; 00270 return boost::indeterminate; 00271 } 00272 else 00273 { 00274 return false; 00275 } 00276 case expecting_newline_3: 00277 return (input == '\n'); 00278 default: 00279 return false; 00280 } 00281 } 00282 00283 bool HttpRequestParser::is_char(int c) 00284 { 00285 return c >= 0 && c <= 127; 00286 } 00287 00288 bool HttpRequestParser::is_ctl(int c) 00289 { 00290 return (c >= 0 && c <= 31) || (c == 127); 00291 } 00292 00293 bool HttpRequestParser::is_tspecial(int c) 00294 { 00295 switch (c) 00296 { 00297 case '(': 00298 case ')': 00299 case '<': 00300 case '>': 00301 case '@': 00302 case ',': 00303 case ';': 00304 case ':': 00305 case '\\': 00306 case '"': 00307 case '/': 00308 case '[': 00309 case ']': 00310 case '?': 00311 case '=': 00312 case '{': 00313 case '}': 00314 case ' ': 00315 case '\t': 00316 return true; 00317 default: 00318 return false; 00319 } 00320 } 00321 00322 bool HttpRequestParser::is_digit(int c) 00323 { 00324 return c >= '0' && c <= '9'; 00325 } 00326 00327 }