Boost C++ Libraries Home Libraries People FAQ More

Home | Reference | Tutorial | Examples | Design

http/server/request_parser.cpp

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

Home | Reference | Tutorial | Examples | Design