2014-04-01 13:58:52 +00:00
|
|
|
#pragma once
|
|
|
|
|
2014-03-31 16:51:50 +00:00
|
|
|
#include <string>
|
2014-04-01 12:25:16 +00:00
|
|
|
#include <unordered_map>
|
2014-04-20 08:45:10 +00:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2014-09-22 20:34:22 +00:00
|
|
|
#include <algorithm>
|
2014-04-01 12:25:16 +00:00
|
|
|
|
2016-09-21 14:11:06 +00:00
|
|
|
#include "crow/http_parser_merged.h"
|
|
|
|
#include "crow/http_request.h"
|
2014-04-01 13:58:52 +00:00
|
|
|
|
2014-04-26 17:19:59 +00:00
|
|
|
namespace crow
|
2014-03-31 16:51:50 +00:00
|
|
|
{
|
2020-11-18 22:13:57 +00:00
|
|
|
/// A wrapper for `nodejs/http-parser`.
|
|
|
|
///
|
2021-11-25 11:45:38 +00:00
|
|
|
/// Used to generate a \ref crow.request from the TCP socket buffer.
|
|
|
|
template<typename Handler>
|
2014-03-31 16:51:50 +00:00
|
|
|
struct HTTPParser : public http_parser
|
|
|
|
{
|
|
|
|
static int on_message_begin(http_parser* self_)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2014-04-01 12:25:16 +00:00
|
|
|
self->clear();
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int on_url(http_parser* self_, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2021-11-25 11:45:38 +00:00
|
|
|
self->raw_url.insert(self->raw_url.end(), at, at + length);
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int on_header_field(http_parser* self_, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2014-04-01 12:25:16 +00:00
|
|
|
switch (self->header_building_state)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (!self->header_value.empty())
|
|
|
|
{
|
|
|
|
self->headers.emplace(std::move(self->header_field), std::move(self->header_value));
|
|
|
|
}
|
2021-11-25 11:45:38 +00:00
|
|
|
self->header_field.assign(at, at + length);
|
2014-04-01 12:25:16 +00:00
|
|
|
self->header_building_state = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
2021-11-25 11:45:38 +00:00
|
|
|
self->header_field.insert(self->header_field.end(), at, at + length);
|
2014-04-01 12:25:16 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int on_header_value(http_parser* self_, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2014-04-01 12:25:16 +00:00
|
|
|
switch (self->header_building_state)
|
|
|
|
{
|
|
|
|
case 0:
|
2021-11-25 11:45:38 +00:00
|
|
|
self->header_value.insert(self->header_value.end(), at, at + length);
|
2014-04-01 12:25:16 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
self->header_building_state = 0;
|
2021-11-25 11:45:38 +00:00
|
|
|
self->header_value.assign(at, at + length);
|
2014-04-01 12:25:16 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int on_headers_complete(http_parser* self_)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2014-04-01 12:25:16 +00:00
|
|
|
if (!self->header_field.empty())
|
|
|
|
{
|
|
|
|
self->headers.emplace(std::move(self->header_field), std::move(self->header_value));
|
|
|
|
}
|
2014-05-02 12:54:25 +00:00
|
|
|
self->process_header();
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int on_body(http_parser* self_, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2021-11-25 11:45:38 +00:00
|
|
|
self->body.insert(self->body.end(), at, at + length);
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int on_message_complete(http_parser* self_)
|
|
|
|
{
|
|
|
|
HTTPParser* self = static_cast<HTTPParser*>(self_);
|
2014-10-14 08:48:35 +00:00
|
|
|
|
|
|
|
// url params
|
|
|
|
self->url = self->raw_url.substr(0, self->raw_url.find("?"));
|
|
|
|
self->url_params = query_string(self->raw_url);
|
|
|
|
|
2014-04-01 12:25:16 +00:00
|
|
|
self->process_message();
|
2014-03-31 16:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2021-11-25 11:45:38 +00:00
|
|
|
HTTPParser(Handler* handler):
|
|
|
|
handler_(handler)
|
2014-08-15 02:06:00 +00:00
|
|
|
{
|
|
|
|
http_parser_init(this, HTTP_REQUEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
// return false on error
|
2020-11-18 22:13:57 +00:00
|
|
|
/// Parse a buffer into the different sections of an HTTP request.
|
2014-08-15 02:06:00 +00:00
|
|
|
bool feed(const char* buffer, int length)
|
|
|
|
{
|
|
|
|
const static http_parser_settings settings_{
|
2021-11-25 11:45:38 +00:00
|
|
|
on_message_begin,
|
|
|
|
on_url,
|
|
|
|
nullptr,
|
|
|
|
on_header_field,
|
|
|
|
on_header_value,
|
|
|
|
on_headers_complete,
|
|
|
|
on_body,
|
|
|
|
on_message_complete,
|
2014-08-15 02:06:00 +00:00
|
|
|
};
|
2014-03-31 16:51:50 +00:00
|
|
|
|
|
|
|
int nparsed = http_parser_execute(this, &settings_, buffer, length);
|
2021-11-01 09:02:25 +00:00
|
|
|
if (http_errno != HPE_OK)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2014-04-01 12:25:16 +00:00
|
|
|
return nparsed == length;
|
2014-03-31 16:51:50 +00:00
|
|
|
}
|
|
|
|
|
2014-04-01 12:25:16 +00:00
|
|
|
bool done()
|
2014-03-31 16:51:50 +00:00
|
|
|
{
|
2014-08-15 02:06:00 +00:00
|
|
|
return feed(nullptr, 0);
|
2014-03-31 16:51:50 +00:00
|
|
|
}
|
|
|
|
|
2014-04-01 12:25:16 +00:00
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
url.clear();
|
2014-10-14 08:48:35 +00:00
|
|
|
raw_url.clear();
|
2014-04-01 12:25:16 +00:00
|
|
|
header_building_state = 0;
|
|
|
|
header_field.clear();
|
|
|
|
header_value.clear();
|
|
|
|
headers.clear();
|
2014-09-22 20:34:22 +00:00
|
|
|
url_params.clear();
|
2014-04-01 12:25:16 +00:00
|
|
|
body.clear();
|
|
|
|
}
|
|
|
|
|
2014-05-02 12:54:25 +00:00
|
|
|
void process_header()
|
|
|
|
{
|
|
|
|
handler_->handle_header();
|
|
|
|
}
|
|
|
|
|
2014-04-01 12:25:16 +00:00
|
|
|
void process_message()
|
|
|
|
{
|
|
|
|
handler_->handle();
|
|
|
|
}
|
|
|
|
|
2020-11-18 22:13:57 +00:00
|
|
|
/// Take the parsed HTTP request data and convert it to a \ref crow.request
|
2014-05-02 12:54:25 +00:00
|
|
|
request to_request() const
|
2014-04-01 13:58:52 +00:00
|
|
|
{
|
2021-02-21 00:14:30 +00:00
|
|
|
return request{static_cast<HTTPMethod>(method), std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
|
2014-04-01 13:58:52 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 11:45:38 +00:00
|
|
|
bool is_upgrade() const
|
|
|
|
{
|
|
|
|
return upgrade;
|
|
|
|
}
|
2016-08-28 05:46:31 +00:00
|
|
|
|
2014-05-02 12:54:25 +00:00
|
|
|
bool check_version(int major, int minor) const
|
|
|
|
{
|
|
|
|
return http_major == major && http_minor == minor;
|
|
|
|
}
|
|
|
|
|
2014-10-14 08:48:35 +00:00
|
|
|
std::string raw_url;
|
2014-04-01 12:25:16 +00:00
|
|
|
std::string url;
|
2014-09-22 20:34:22 +00:00
|
|
|
|
2014-04-01 12:25:16 +00:00
|
|
|
int header_building_state = 0;
|
|
|
|
std::string header_field;
|
|
|
|
std::string header_value;
|
2014-09-10 21:32:41 +00:00
|
|
|
ci_map headers;
|
2020-11-18 22:13:57 +00:00
|
|
|
query_string url_params; ///< What comes after the `?` in the URL.
|
2014-04-01 12:25:16 +00:00
|
|
|
std::string body;
|
|
|
|
|
2020-11-18 22:13:57 +00:00
|
|
|
Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection).
|
2014-03-31 16:51:50 +00:00
|
|
|
};
|
2021-11-25 11:45:38 +00:00
|
|
|
} // namespace crow
|