00001
00002
00003
00004
00005
00006
00007
00008
00009 static const char rcsid[] __attribute__((used)) = "$Id: HTTPRequest.cpp 1197 2014-10-14 22:26:11Z sella $";
00010
00011 #include "HTTPRequest.h"
00012 #include "HTTP.h"
00013
00014 #include "../util/String.h"
00015
00016 using namespace sella::server;
00017 using namespace sella::util;
00018
00019 HTTPRequest::HTTPRequest(const HTTP &http) throw () :
00020 http(http),
00021 method(None),
00022 methodRaw(),
00023 methodOverride(None),
00024 methodOverrideRaw(),
00025 uri(),
00026 path(),
00027 query(),
00028 version(),
00029 headers(),
00030 host(),
00031 userAgent(),
00032 accept(),
00033 acceptCharset(),
00034 acceptEncoding(),
00035 acceptLanguage(),
00036 transferEncoding(),
00037 authorization(),
00038 connection(),
00039 cacheControl(),
00040 expect(),
00041 contentType(),
00042 contentLength(0),
00043 content()
00044 { }
00045
00046 HTTPRequest::~HTTPRequest() throw () { }
00047
00048 void HTTPRequest::parse(const std::string &buffer) throw (ServerException) {
00049 char buf[buffer.size() + 1];
00050 char *line, *nline, *token, *rest, *ptr = buf;
00051
00052 strncpy(buf, buffer.c_str(), sizeof(buf));
00053
00054 if ((line = strtok_r(ptr, "\r\n", &rest)) == NULL) {
00055 THROW_CODE(ServerException, Code::BadRequest, "Request was empty");
00056 }
00057
00058 TRACE(PACKAGE, "Request-Line: %s", line);
00059
00060 nline = rest;
00061
00062
00063 if ((token = strtok_r(ptr, " ", &rest)) != NULL) {
00064 if (strncmp("GET", token, 3) == 0) {
00065 method = Get;
00066 } else if (strncmp("POST", token, 4) == 0) {
00067 method = Post;
00068 } else if (strncmp("PUT", token, 3) == 0) {
00069 method = Put;
00070 } else if (strncmp("DELETE", token, 6) == 0) {
00071 method = Delete;
00072 } else if (strncmp("PATCH", token, 5) == 0) {
00073 method = Patch;
00074 } else if (strncmp("HEAD", token, 4) == 0) {
00075 method = Head;
00076 } else if (strncmp("OPTIONS", token, 7) == 0) {
00077 method = Options;
00078 } else if (strncmp("TRACE", token, 5) == 0) {
00079 method = Trace;
00080 } else if (strncmp("CONNECT", token, 7) == 0) {
00081 method = Connect;
00082 } else {
00083 method = Extension;
00084 }
00085
00086 methodRaw = token;
00087 } else {
00088 THROW_CODE(ServerException, Code::BadRequest, "Request syntax is malformed: %s", line);
00089 }
00090
00091 if ((token = strrchr(rest, ' ')) != NULL) {
00092 token[0] = 0;
00093 uri = rest;
00094 } else {
00095 THROW_CODE(ServerException, Code::BadRequest, "Request syntax is malformed: %s", line);
00096 }
00097
00098 if (strncmp("HTTP/", ++token, 5) == 0) {
00099 version = token;
00100 } else {
00101 THROW_CODE(ServerException, Code::BadRequest, "Request syntax is malformed: %s", line);
00102 }
00103
00104 if ((token = strchr(rest, '?')) != NULL) {
00105 token[0] = 0;
00106 query = token + 1;
00107 path = rest;
00108 } else {
00109 path = rest;
00110 }
00111
00112 ptr = nline;
00113
00114
00115 while ((line = strtok_r(ptr, "\r\n", &rest)) != NULL) {
00116
00117 if (strncasecmp("Host: ", line, 6) == 0) {
00118 host = line + 6;
00119 } else if (strncasecmp("User-Agent: ", line, 12) == 0) {
00120 userAgent = line + 12;
00121 } else if (strncasecmp("Accept: ", line, 8) == 0) {
00122 accept = String::split(line + 8, ",", false, false);
00123 } else if (strncasecmp("Accept-Charset: ", line, 16) == 0) {
00124 acceptCharset = String::split(line + 16, ",", false, false);
00125 } else if (strncasecmp("Accept-Language: ", line, 17) == 0) {
00126 acceptLanguage = String::split(line + 17, ",", false, false);
00127 } else if (strncasecmp("Accept-Encoding: ", line, 17) == 0) {
00128 acceptEncoding = String::split(line + 17, ",", false, false);
00129 } else if (strncasecmp("Authorization: ", line, 15) == 0) {
00130 authorization = line + 15;
00131 } else if (strncasecmp("Transfer-Encoding: ", line, 19) == 0) {
00132 transferEncoding = line + 19;
00133 } else if (strncasecmp("Connection: ", line, 12) == 0) {
00134 connection = line + 12;
00135 } else if (strncasecmp("Cache-Control: ", line, 15) == 0) {
00136 cacheControl = line + 15;
00137 } else if (strncasecmp("Expect: ", line, 8) == 0) {
00138 expect = line + 8;
00139 } else if (strncasecmp("Content-Type: ", line, 14) == 0) {
00140 contentType = line + 14;
00141 } else if (strncasecmp("Content-Length: ", line, 16) == 0) {
00142 try {
00143 contentLength = std::stoull(line + 16);
00144 } catch (std::exception &e) {
00145 THROW_CODE(ServerException, Code::BadRequest, "Content-Length is invalid: %s", line + 15);
00146 }
00147 } else if (strncasecmp("X-HTTP-Method-Override: ", line, 24) == 0) {
00148 methodOverrideRaw = line + 24;
00149 } else if (strncasecmp("X-HTTP-Method: ", line, 15) == 0) {
00150 methodOverrideRaw = line + 15;
00151 } else if (strncasecmp("X-METHOD-OVERRIDE: ", line, 19) == 0) {
00152 methodOverrideRaw = line + 19;
00153 }
00154
00155 headers.push_back(line);
00156
00157 ptr = rest;
00158
00159 if (rest != NULL && strncmp(rest, "\n\r\n", 3) == 0) {
00160 rest += 3;
00161
00162 break;
00163 }
00164 }
00165
00166 if (!methodOverrideRaw.empty()) {
00167 if (methodOverrideRaw.compare("GET")) {
00168 methodOverride = Get;
00169 } else if (methodOverrideRaw.compare("POST")) {
00170 methodOverride = Post;
00171 } else if (methodOverrideRaw.compare("PUT")) {
00172 methodOverride = Put;
00173 } else if (methodOverrideRaw.compare("DELETE")) {
00174 methodOverride = Delete;
00175 } else if (methodOverrideRaw.compare("PATCH")) {
00176 methodOverride = Patch;
00177 } else if (methodOverrideRaw.compare("HEAD")) {
00178 methodOverride = Head;
00179 } else if (methodOverrideRaw.compare("OPTIONS")) {
00180 methodOverride = Options;
00181 } else if (methodOverrideRaw.compare("TRACE")) {
00182 methodOverride = Trace;
00183 } else if (methodOverrideRaw.compare("CONNECT")) {
00184 methodOverride = Connect;
00185 } else {
00186 methodOverride = Extension;
00187 }
00188 }
00189
00190 if (host.empty()) {
00191 THROW_CODE(ServerException, Code::BadRequest, "Missing Host header");
00192 }
00193
00194 if (rest != NULL) {
00195 appendBody(std::string(rest));
00196 }
00197 }
00198
00199 void HTTPRequest::appendBody(const std::string &data) throw (ServerException) {
00200 if (content.size() + data.size() > http.getRequestBodyLimit()) {
00201 THROW_CODE(ServerException, Code::RequestEntityTooLarge, "The requested URI %s is larger than the configured limit of %zd bytes.", uri.c_str(), http.getRequestBodyLimit());
00202 }
00203
00204 content.reserve(content.size() + data.size());
00205 content.insert(content.end(), data.begin(), data.end());
00206 }
00207
00208 void HTTPRequest::appendBody(const std::vector<char> &data) throw (ServerException) {
00209 if (content.size() + data.size() > http.getRequestBodyLimit()) {
00210 THROW_CODE(ServerException, Code::RequestEntityTooLarge, "The requested URI %s is larger than the configured limit of %zd bytes.", uri.c_str(), http.getRequestBodyLimit());
00211 }
00212
00213 content.reserve(content.size() + data.size());
00214 content.insert(content.end(), data.begin(), data.end());
00215 }
00216
00217 HTTPRequest::Method HTTPRequest::getMethod(bool useOverride) const throw () {
00218 if (useOverride && methodOverride != None) {
00219 return methodOverride;
00220 }
00221
00222 return method;
00223 }
00224
00225 const std::string& HTTPRequest::getMethodRaw(bool useOverride) const throw () {
00226 if (useOverride && methodOverride != None) {
00227 return methodOverrideRaw;
00228 }
00229
00230 return methodRaw;
00231 }
00232
00233 HTTPRequest::Method HTTPRequest::getMethodOverride(void) const throw () {
00234 return methodOverride;
00235 }
00236
00237 const std::string& HTTPRequest::getMethodOverrideRaw(void) const throw () {
00238 return methodOverrideRaw;
00239 }
00240
00241 const std::string& HTTPRequest::getURI(void) const throw () {
00242 return uri;
00243 }
00244
00245 const std::string& HTTPRequest::getPath(void) const throw () {
00246 return path;
00247 }
00248
00249 const std::string& HTTPRequest::getQuery(void) const throw () {
00250 return query;
00251 }
00252
00253 const std::string& HTTPRequest::getVersion(void) const throw () {
00254 return version;
00255 }
00256
00257 const std::vector<std::string>& HTTPRequest::getHeaders() const throw () {
00258 return headers;
00259 }
00260
00261 const std::string HTTPRequest::getBody(void) const throw () {
00262 std::string buf(content.begin(), content.end());
00263
00264 return buf;
00265 }
00266
00267 const std::vector<char>& HTTPRequest::getContent(void) const throw () {
00268 return content;
00269 }
00270
00271 bool HTTPRequest::isContinue(void) const throw () {
00272 return !expect.compare("100-continue");
00273 }
00274
00275 bool HTTPRequest::isChunked(void) const throw () {
00276 return !transferEncoding.compare("chunked");
00277 }
00278
00279 bool HTTPRequest::empty(void) const throw () {
00280 return (method == None);
00281 }
00282
00283 void HTTPRequest::clear(void) throw () {
00284 method = None;
00285 methodRaw.clear();
00286 methodOverride = None;
00287 methodOverrideRaw.clear();
00288 uri.clear();
00289 path.clear();
00290 query.clear();
00291 version.clear();
00292 headers.clear();
00293 host.clear();
00294 userAgent.clear();
00295 accept.clear();
00296 acceptCharset.clear();
00297 acceptEncoding.clear();
00298 acceptLanguage.clear();
00299 transferEncoding.clear();
00300 authorization.clear();
00301 connection.clear();
00302 cacheControl.clear();
00303 expect.clear();
00304 contentType.clear();
00305 contentLength = 0;
00306 std::vector<char>().swap(content);
00307 }
00308
00309 std::string HTTPRequest::str(void) const throw () {
00310 return String::sprintf("%s %s %s\n%s\n%s", methodRaw.c_str(), uri.c_str(), version.c_str(), String::join(headers, '\n').c_str(), getBody().c_str());
00311 }
00312
00313 void HTTPRequest::print(void) const throw () {
00314 printf("[request]\n");
00315 printf("%s %s %s\n", methodRaw.c_str(), uri.c_str(), version.c_str());
00316
00317 for (auto h = headers.begin(); h != headers.end(); ++h) {
00318 printf("%s\n", h->c_str());
00319 }
00320
00321 #if 1
00322 printf("uri: %s\n", uri.c_str());
00323 printf("path: %s\n", path.c_str());
00324 printf("query: %s\n", query.c_str());
00325 #endif
00326
00327 printf("%s\n", getBody().c_str());
00328 }
00329
00330
00331
00332