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