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