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 <google/dense_hash_map>
00027
00028 #include <string>
00029 #include <map>
00030 #include <cstdlib>
00031
00032 #include "StaticString.h"
00033
00034 namespace Passenger {
00035
00036 using namespace std;
00037 using namespace google;
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 class ScgiRequestParser {
00089 public:
00090 enum State {
00091 READING_LENGTH_STRING,
00092 READING_HEADER_DATA,
00093 EXPECTING_COMMA,
00094 DONE,
00095 ERROR
00096 };
00097
00098 enum ErrorReason {
00099 NONE,
00100
00101
00102 LENGTH_STRING_TOO_LARGE,
00103
00104
00105 LIMIT_REACHED,
00106
00107
00108 INVALID_LENGTH_STRING,
00109
00110
00111
00112 HEADER_TERMINATOR_EXPECTED,
00113
00114
00115 INVALID_HEADER_DATA
00116 };
00117
00118 private:
00119 typedef dense_hash_map<StaticString, StaticString, StaticString::Hash> HeaderMap;
00120
00121 unsigned long maxSize;
00122
00123 State state;
00124 ErrorReason errorReason;
00125 char lengthStringBuffer[sizeof("4294967296")];
00126 unsigned int lengthStringBufferSize;
00127 unsigned long headerSize;
00128 string headerBuffer;
00129 HeaderMap headers;
00130
00131 static inline bool isDigit(char byte) {
00132 return byte >= '0' && byte <= '9';
00133 }
00134
00135
00136
00137
00138 bool parseHeaderData(const string &data, HeaderMap &output) {
00139 bool isName = true;
00140 const char *startOfString, *current, *end;
00141 StaticString key, value;
00142
00143 if (data.size() == 0) {
00144 return true;
00145 }
00146
00147 startOfString = data.c_str();
00148 end = data.c_str() + data.size();
00149
00150 if (*(end - 1) != '\0') {
00151 return false;
00152 }
00153
00154 for (current = data.c_str(); current != end; current++) {
00155 if (isName && *current == '\0') {
00156 key = StaticString(startOfString, current - startOfString);
00157 if (key.empty()) {
00158 return false;
00159 }
00160 startOfString = current + 1;
00161 isName = false;
00162 } else if (!isName && *current == '\0') {
00163 value = StaticString(startOfString, current - startOfString);
00164 startOfString = current + 1;
00165 isName = true;
00166
00167 output[key] = value;
00168 key = StaticString();
00169 value = StaticString();
00170 }
00171 }
00172
00173 return isName;
00174 }
00175
00176
00177
00178
00179
00180 unsigned int readHeaderData(const char *data, unsigned int size) {
00181 unsigned int bytesToRead;
00182
00183
00184
00185 if (size < headerSize - headerBuffer.size()) {
00186 bytesToRead = size;
00187 } else {
00188 bytesToRead = headerSize - headerBuffer.size();
00189 }
00190
00191 headerBuffer.append(data, bytesToRead);
00192
00193 if (headerBuffer.size() == headerSize) {
00194
00195 if (bytesToRead < size) {
00196 if (data[bytesToRead] == ',') {
00197 if (parseHeaderData(headerBuffer, headers)) {
00198 state = DONE;
00199 return bytesToRead + 1;
00200 } else {
00201 state = ERROR;
00202 errorReason = INVALID_HEADER_DATA;
00203 return bytesToRead;
00204 }
00205 } else {
00206 state = ERROR;
00207 errorReason = HEADER_TERMINATOR_EXPECTED;
00208 return bytesToRead;
00209 }
00210 } else {
00211 if (parseHeaderData(headerBuffer, headers)) {
00212 state = EXPECTING_COMMA;
00213 } else {
00214 state = ERROR;
00215 errorReason = INVALID_HEADER_DATA;
00216 }
00217 return bytesToRead;
00218 }
00219 } else {
00220
00221 return bytesToRead;
00222 }
00223 }
00224
00225 public:
00226
00227
00228
00229
00230
00231
00232 ScgiRequestParser(unsigned long maxSize = 0) {
00233 this->maxSize = maxSize;
00234 state = READING_LENGTH_STRING;
00235 errorReason = NONE;
00236 lengthStringBufferSize = 0;
00237 headerSize = 0;
00238 headers.set_empty_key("");
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 unsigned int feed(const char *data, unsigned int size) {
00257 unsigned int i;
00258
00259 switch (state) {
00260 case READING_LENGTH_STRING:
00261
00262 for (i = 0; i < size; i++) {
00263 char byte = data[i];
00264
00265 if (lengthStringBufferSize == sizeof(lengthStringBuffer) - 1) {
00266
00267 state = ERROR;
00268 errorReason = LENGTH_STRING_TOO_LARGE;
00269 return i;
00270 } else if (!isDigit(byte)) {
00271 if (byte == ':') {
00272
00273 state = READING_HEADER_DATA;
00274 lengthStringBuffer[lengthStringBufferSize] = '\0';
00275 headerSize = atol(lengthStringBuffer);
00276 if (maxSize > 0 && headerSize > maxSize) {
00277 state = ERROR;
00278 errorReason = LIMIT_REACHED;
00279 } else {
00280 headerBuffer.reserve(headerSize);
00281
00282
00283 return readHeaderData(data + i + 1, size - i - 1) + i + 1;
00284 }
00285 } else {
00286
00287 state = ERROR;
00288 errorReason = INVALID_LENGTH_STRING;
00289 return i;
00290 }
00291 } else {
00292 lengthStringBuffer[lengthStringBufferSize] = byte;
00293 lengthStringBufferSize++;
00294 }
00295 }
00296 return i;
00297
00298 case READING_HEADER_DATA:
00299 return readHeaderData(data, size);
00300
00301 case EXPECTING_COMMA:
00302 if (data[0] == ',') {
00303 state = DONE;
00304 return 1;
00305 } else {
00306 state = ERROR;
00307 errorReason = HEADER_TERMINATOR_EXPECTED;
00308 return 0;
00309 }
00310
00311 default:
00312 return 0;
00313 }
00314 }
00315
00316
00317
00318
00319 string getHeaderData() const {
00320 return headerBuffer;
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 StaticString getHeader(const StaticString &name) const {
00332 HeaderMap::const_iterator it(headers.find(name));
00333 if (it == headers.end()) {
00334 return "";
00335 } else {
00336 return it->second;
00337 }
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 bool hasHeader(const StaticString &name) const {
00347 return headers.find(name) != headers.end();
00348 }
00349
00350
00351
00352
00353 State getState() const {
00354 return state;
00355 }
00356
00357
00358
00359
00360
00361
00362 ErrorReason getErrorReason() const {
00363 return errorReason;
00364 }
00365
00366
00367
00368
00369
00370 bool acceptingInput() const {
00371 return state != DONE && state != ERROR;
00372 }
00373 };
00374
00375 }