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