00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <string>
00027 #include <cstdio>
00028 #include <cstdlib>
00029
00030 namespace Passenger {
00031
00032 using namespace std;
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 class HttpStatusExtractor {
00061 private:
00062 static const char CR = '\x0D';
00063 static const char LF = '\x0A';
00064
00065 string buffer;
00066 unsigned int searchStart;
00067 bool fullHeaderReceived;
00068 string statusLine;
00069
00070 bool extractStatusLine() {
00071 static const char statusHeaderName[] = "Status: ";
00072 string::size_type start_pos, newline_pos;
00073
00074 if (buffer.size() > sizeof(statusHeaderName) - 1
00075 && memcmp(buffer.c_str(), statusHeaderName, sizeof(statusHeaderName) - 1) == 0) {
00076
00077 start_pos = sizeof(statusHeaderName) - 1;
00078 newline_pos = buffer.find("\x0D\x0A", 0, 2) + 2;
00079 } else {
00080
00081
00082 start_pos = buffer.find("\x0D\x0AStatus: ");
00083 if (start_pos != string::npos) {
00084 start_pos += 2 + sizeof(statusHeaderName) - 1;
00085 newline_pos = buffer.find("\x0D\x0A", start_pos, 2) + 2;
00086 }
00087 }
00088 if (start_pos != string::npos) {
00089
00090 statusLine = buffer.substr(start_pos, newline_pos - start_pos);
00091 addStatusTextIfNecessary();
00092 return true;
00093 } else {
00094
00095
00096 return false;
00097 }
00098 }
00099
00100 void addStatusTextIfNecessary() {
00101 if (statusLine.find(' ') == string::npos) {
00102
00103 int statusCode = atoi(statusLine.c_str());
00104 switch (statusCode) {
00105 case 100:
00106 statusLine = "100 Continue\x0D\x0A";
00107 break;
00108 case 101:
00109 statusLine = "101 Switching Protocols\x0D\x0A";
00110 break;
00111 case 102:
00112 statusLine = "102 Processing\x0D\x0A";
00113 break;
00114 case 200:
00115 statusLine = "200 OK\x0D\x0A";
00116 break;
00117 case 201:
00118 statusLine = "201 Created\x0D\x0A";
00119 break;
00120 case 202:
00121 statusLine = "202 Accepted\x0D\x0A";
00122 break;
00123 case 203:
00124 statusLine = "203 Non-Authoritative Information\x0D\x0A";
00125 break;
00126 case 204:
00127 statusLine = "204 No Content\x0D\x0A";
00128 break;
00129 case 205:
00130 statusLine = "205 Reset Content\x0D\x0A";
00131 break;
00132 case 206:
00133 statusLine = "206 Partial Content\x0D\x0A";
00134 break;
00135 case 207:
00136 statusLine = "207 Multi-Status\x0D\x0A";
00137 break;
00138 case 300:
00139 statusLine = "300 Multiple Choices\x0D\x0A";
00140 break;
00141 case 301:
00142 statusLine = "301 Moved Permanently\x0D\x0A";
00143 break;
00144 case 302:
00145 statusLine = "302 Found\x0D\x0A";
00146 break;
00147 case 303:
00148 statusLine = "303 See Other\x0D\x0A";
00149 break;
00150 case 304:
00151 statusLine = "304 Not Modified\x0D\x0A";
00152 break;
00153 case 305:
00154 statusLine = "305 Use Proxy\x0D\x0A";
00155 break;
00156 case 306:
00157 statusLine = "306 Switch Proxy\x0D\x0A";
00158 break;
00159 case 307:
00160 statusLine = "307 Temporary Redirect\x0D\x0A";
00161 break;
00162 case 308:
00163
00164 statusLine = "308 Resume Incomplete\x0D\x0A";
00165 break;
00166 case 400:
00167 statusLine = "400 Bad Request\x0D\x0A";
00168 break;
00169 case 401:
00170 statusLine = "401 Unauthorized\x0D\x0A";
00171 break;
00172 case 402:
00173 statusLine = "402 Payment Required\x0D\x0A";
00174 break;
00175 case 403:
00176 statusLine = "403 Forbidden\x0D\x0A";
00177 break;
00178 case 404:
00179 statusLine = "404 Not Found\x0D\x0A";
00180 break;
00181 case 405:
00182 statusLine = "405 Method Not Allowed\x0D\x0A";
00183 break;
00184 case 406:
00185 statusLine = "406 Not Acceptable\x0D\x0A";
00186 break;
00187 case 407:
00188 statusLine = "407 Proxy Authentication Required\x0D\x0A";
00189 break;
00190 case 408:
00191 statusLine = "408 Request Timeout\x0D\x0A";
00192 break;
00193 case 409:
00194 statusLine = "409 Conflict\x0D\x0A";
00195 break;
00196 case 410:
00197 statusLine = "410 Gone\x0D\x0A";
00198 break;
00199 case 411:
00200 statusLine = "411 Length Required\x0D\x0A";
00201 break;
00202 case 412:
00203 statusLine = "412 Precondition Failed\x0D\x0A";
00204 break;
00205 case 413:
00206 statusLine = "413 Request Entity Too Large\x0D\x0A";
00207 break;
00208 case 414:
00209 statusLine = "414 Request-URI Too Long\x0D\x0A";
00210 break;
00211 case 415:
00212 statusLine = "415 Unsupported Media Type\x0D\x0A";
00213 break;
00214 case 416:
00215 statusLine = "416 Requested Range Not Satisfiable\x0D\x0A";
00216 break;
00217 case 417:
00218 statusLine = "417 Expectation Failed\x0D\x0A";
00219 break;
00220 case 418:
00221 statusLine = "418 Not A Funny April Fools Joke\x0D\x0A";
00222 break;
00223 case 422:
00224 statusLine = "422 Unprocessable Entity\x0D\x0A";
00225 break;
00226 case 423:
00227 statusLine = "423 Locked\x0D\x0A";
00228 break;
00229 case 424:
00230 statusLine = "424 Unordered Collection\x0D\x0A";
00231 break;
00232 case 426:
00233 statusLine = "426 Upgrade Required\x0D\x0A";
00234 break;
00235 case 449:
00236 statusLine = "449 Retry With\x0D\x0A";
00237 break;
00238 case 450:
00239 statusLine = "450 Blocked\x0D\x0A";
00240 break;
00241 case 500:
00242 statusLine = "500 Internal Server Error\x0D\x0A";
00243 break;
00244 case 501:
00245 statusLine = "501 Not Implemented\x0D\x0A";
00246 break;
00247 case 502:
00248 statusLine = "502 Bad Gateway\x0D\x0A";
00249 break;
00250 case 503:
00251 statusLine = "503 Service Unavailable\x0D\x0A";
00252 break;
00253 case 504:
00254 statusLine = "504 Gateway Timeout\x0D\x0A";
00255 break;
00256 case 505:
00257 statusLine = "505 HTTP Version Not Supported\x0D\x0A";
00258 break;
00259 case 506:
00260 statusLine = "506 Variant Also Negotiates\x0D\x0A";
00261 break;
00262 case 507:
00263 statusLine = "507 Insufficient Storage\x0D\x0A";
00264 break;
00265 case 509:
00266 statusLine = "509 Bandwidth Limit Exceeded\x0D\x0A";
00267 break;
00268 case 510:
00269 statusLine = "510 Not Extended\x0D\x0A";
00270 break;
00271 default:
00272 char temp[32];
00273 snprintf(temp, sizeof(temp),
00274 "%d Unknown Status Code\x0D\x0A",
00275 statusCode);
00276 temp[sizeof(temp) - 1] = '\0';
00277 statusLine = temp;
00278 }
00279 }
00280 }
00281
00282 public:
00283 HttpStatusExtractor() {
00284 searchStart = 0;
00285 fullHeaderReceived = false;
00286 statusLine = "200 OK\r\n";
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 bool feed(const char *data, unsigned int size) {
00312 if (fullHeaderReceived) {
00313 return true;
00314 }
00315 buffer.append(data, size);
00316 for (; buffer.size() >= 3 && searchStart < buffer.size() - 3; searchStart++) {
00317 if (buffer[searchStart] == CR &&
00318 buffer[searchStart + 1] == LF &&
00319 buffer[searchStart + 2] == CR &&
00320 buffer[searchStart + 3] == LF) {
00321 fullHeaderReceived = true;
00322 extractStatusLine();
00323 return true;
00324 }
00325 }
00326 return false;
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 string getStatusLine() const {
00339 return statusLine;
00340 }
00341
00342
00343
00344
00345 string getBuffer() const {
00346 return buffer;
00347 }
00348 };
00349
00350 }