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