2020-10-04 18:48:47 +00:00
|
|
|
#include "Common/Net/HTTPHeaders.h"
|
2014-12-14 23:00:16 +00:00
|
|
|
|
2016-05-26 05:21:24 +00:00
|
|
|
#include <algorithm>
|
2014-12-14 23:00:16 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2020-10-04 18:48:47 +00:00
|
|
|
#include "Common/Net/Sinks.h"
|
2014-12-14 23:00:16 +00:00
|
|
|
|
2020-08-15 13:51:41 +00:00
|
|
|
#include "Common/Log.h"
|
2020-10-04 18:48:47 +00:00
|
|
|
#include "Common/File/FileDescriptor.h"
|
2020-09-29 10:19:22 +00:00
|
|
|
#include "Common/StringUtils.h"
|
2020-08-15 13:51:41 +00:00
|
|
|
|
2014-12-14 23:00:16 +00:00
|
|
|
namespace http {
|
|
|
|
|
|
|
|
RequestHeader::RequestHeader()
|
|
|
|
: status(200), referer(0), user_agent(0),
|
|
|
|
resource(0), params(0), content_length(-1), first_header_(true) {
|
|
|
|
}
|
|
|
|
|
|
|
|
RequestHeader::~RequestHeader() {
|
|
|
|
delete [] referer;
|
|
|
|
delete [] user_agent;
|
|
|
|
delete [] resource;
|
|
|
|
delete [] params;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RequestHeader::GetParamValue(const char *param_name, std::string *value) const {
|
|
|
|
if (!params)
|
|
|
|
return false;
|
|
|
|
std::string p(params);
|
|
|
|
std::vector<std::string> v;
|
|
|
|
SplitString(p, '&', v);
|
|
|
|
for (size_t i = 0; i < v.size(); i++) {
|
|
|
|
std::vector<std::string> parts;
|
|
|
|
SplitString(v[i], '=', parts);
|
2021-01-01 16:51:46 +00:00
|
|
|
DEBUG_LOG(IO, "Param: %s Value: %s", parts[0].c_str(), parts[1].c_str());
|
2014-12-14 23:00:16 +00:00
|
|
|
if (parts[0] == param_name) {
|
|
|
|
*value = parts[1];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-26 05:21:24 +00:00
|
|
|
bool RequestHeader::GetOther(const char *name, std::string *value) const {
|
|
|
|
auto it = other.find(name);
|
|
|
|
if (it != other.end()) {
|
|
|
|
*value = it->second;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-14 23:00:16 +00:00
|
|
|
// Intended to be a mad fast parser. It's not THAT fast currently, there's still
|
|
|
|
// things to optimize, but meh.
|
|
|
|
int RequestHeader::ParseHttpHeader(const char *buffer) {
|
|
|
|
if (first_header_) {
|
|
|
|
// Step 1: Method
|
|
|
|
first_header_ = false;
|
|
|
|
if (!memcmp(buffer, "GET ", 4)) {
|
|
|
|
method = GET;
|
|
|
|
buffer += 4;
|
|
|
|
} else if (!memcmp(buffer, "HEAD ", 5)) {
|
|
|
|
method = HEAD;
|
|
|
|
buffer += 5;
|
|
|
|
} else if (!memcmp(buffer, "POST ", 5)) {
|
|
|
|
method = POST;
|
|
|
|
buffer += 5;
|
|
|
|
} else {
|
|
|
|
method = UNSUPPORTED;
|
2016-05-26 05:21:24 +00:00
|
|
|
status = 405;
|
2014-12-14 23:00:16 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
SkipSpace(&buffer);
|
|
|
|
|
|
|
|
// Step 2: Resource, params (what's after the ?, if any)
|
|
|
|
const char *endptr = strchr(buffer, ' ');
|
|
|
|
const char *q_ptr = strchr(buffer, '?');
|
|
|
|
|
|
|
|
int resource_name_len;
|
|
|
|
if (q_ptr)
|
|
|
|
resource_name_len = q_ptr - buffer;
|
|
|
|
else
|
|
|
|
resource_name_len = endptr - buffer;
|
|
|
|
if (!resource_name_len) {
|
|
|
|
status = 400;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
resource = new char[resource_name_len + 1];
|
|
|
|
memcpy(resource, buffer, resource_name_len);
|
|
|
|
resource[resource_name_len] = '\0';
|
|
|
|
if (q_ptr) {
|
|
|
|
int param_length = endptr - q_ptr - 1;
|
|
|
|
params = new char[param_length + 1];
|
|
|
|
memcpy(params, q_ptr + 1, param_length);
|
|
|
|
params[param_length] = '\0';
|
|
|
|
}
|
|
|
|
if (strstr(buffer, "HTTP/"))
|
|
|
|
type = FULL;
|
|
|
|
else
|
|
|
|
type = SIMPLE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have a real header to parse.
|
|
|
|
const char *colon = strchr(buffer, ':');
|
|
|
|
if (!colon) {
|
|
|
|
status = 400;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The header is formatted as key: value.
|
|
|
|
int key_len = colon - buffer;
|
2016-05-26 01:59:04 +00:00
|
|
|
const char *key = buffer;
|
2014-12-14 23:00:16 +00:00
|
|
|
|
|
|
|
// Go to after the colon to get the value.
|
|
|
|
buffer = colon + 1;
|
|
|
|
SkipSpace(&buffer);
|
2015-01-02 15:36:18 +00:00
|
|
|
int value_len = (int)strlen(buffer);
|
2014-12-14 23:00:16 +00:00
|
|
|
|
2016-05-26 01:59:04 +00:00
|
|
|
if (!strncasecmp(key, "User-Agent", key_len)) {
|
2014-12-14 23:00:16 +00:00
|
|
|
user_agent = new char[value_len + 1];
|
|
|
|
memcpy(user_agent, buffer, value_len + 1);
|
2021-01-01 16:51:46 +00:00
|
|
|
VERBOSE_LOG(IO, "user-agent: %s", user_agent);
|
2016-05-26 01:59:04 +00:00
|
|
|
} else if (!strncasecmp(key, "Referer", key_len)) {
|
2014-12-14 23:00:16 +00:00
|
|
|
referer = new char[value_len + 1];
|
|
|
|
memcpy(referer, buffer, value_len + 1);
|
2016-05-26 01:59:04 +00:00
|
|
|
} else if (!strncasecmp(key, "Content-Length", key_len)) {
|
2014-12-14 23:00:16 +00:00
|
|
|
content_length = atoi(buffer);
|
2021-01-01 16:51:46 +00:00
|
|
|
VERBOSE_LOG(IO, "Content-Length: %i", (int)content_length);
|
2016-05-26 05:21:24 +00:00
|
|
|
} else {
|
|
|
|
std::string key_str(key, key_len);
|
|
|
|
std::transform(key_str.begin(), key_str.end(), key_str.begin(), tolower);
|
|
|
|
other[key_str] = buffer;
|
2014-12-14 23:00:16 +00:00
|
|
|
}
|
|
|
|
|
2014-12-15 20:02:16 +00:00
|
|
|
return 0;
|
2014-12-14 23:00:16 +00:00
|
|
|
}
|
|
|
|
|
2016-05-26 02:02:38 +00:00
|
|
|
void RequestHeader::ParseHeaders(net::InputSink *sink) {
|
|
|
|
int line_count = 0;
|
|
|
|
std::string line;
|
|
|
|
while (sink->ReadLine(line)) {
|
|
|
|
if (line.length() == 0) {
|
|
|
|
// Blank line, this means end of headers.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseHttpHeader(line.c_str());
|
|
|
|
line_count++;
|
|
|
|
if (type == SIMPLE) {
|
|
|
|
// Done!
|
2021-01-01 16:51:46 +00:00
|
|
|
VERBOSE_LOG(IO, "Simple: Done parsing http request.");
|
2016-05-26 02:02:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-01 16:51:46 +00:00
|
|
|
VERBOSE_LOG(IO, "finished parsing request.");
|
2016-05-26 02:02:38 +00:00
|
|
|
ok = line_count > 1;
|
2014-12-14 23:00:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace http
|