summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLu <[email protected]>2018-06-20 17:17:03 +0800
committerLu <[email protected]>2018-06-20 17:17:03 +0800
commitec4e81b9165d539c2328c0036b89641b74122541 (patch)
tree012666e6d47548f7b05f8578481a5b60c4f6e070
parentcd3eca7a277db00302675149b1416ba330de8065 (diff)
实现对Http 1.0/1.1请求内容的扫描,可以实现业务。
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/http.h17
-rw-r--r--src/http1.cc180
-rw-r--r--src/http2.cc4
-rw-r--r--src/httpscan.cc25
5 files changed, 172 insertions, 56 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f4ed9e7..2c26073 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,7 @@ find_package(OpenSSL REQUIRED)
add_library(tfe-library base64.cc build.cc cache.cc cachemgr.cc cachessess.cc compat.cc easylogging++.cc
cachedsess.cc cachetgcrt.cc cachefkcrt.cc cert.cc certstore.cc logger.cc cfgparser.cc
dynbuf.cc nat.cc opts.cc privsep.cc proxy.cc pxythrmgr.cc pxysslshut.cc pxyconn.cc
- ssl.cc sys.cc thrqueue.cc url.cc util.cc httpscan.cc httpaction.cc http2.cc http1.cc http.cc)
+ ssl.cc sys.cc thrqueue.cc url.cc util.cc httpscan.cc httpaction.cc http1.cc http.cc)
#pxyconn.cc
diff --git a/src/http.h b/src/http.h
index 13bb481..6562a3f 100644
--- a/src/http.h
+++ b/src/http.h
@@ -1,6 +1,7 @@
#ifndef TFE_HTTP_H
#define TFE_HTTP_H
+#include <vector>
#include <memory>
#include <map>
#include <string>
@@ -168,6 +169,15 @@ public:
using for_each_header_cb_t = std::function<void(const std::string & field, const std::string & value)>;
virtual void ForEachHeader(for_each_header_cb_t cb) = 0;
+ /* Request Body */
+ using body_content_t = std::vector<char>;
+ using body_content_ptr_t = std::unique_ptr<body_content_t>;
+
+ /* Body读取、设置接口 */
+ virtual const body_content_t * Body() = 0;
+ virtual void Body(body_content_ptr_t body) = 0;
+ virtual body_content_ptr_t StolenBody() = 0;
+
/* ReadOnly,标记本请求为只读。
* 当一个请求为只读请求时,业务不应修改它的内容,底层处理Readonly的请求时,应直接转发不缓存 */
virtual bool ReadOnly() = 0;
@@ -179,7 +189,12 @@ public:
virtual void Forward(bool is_forward) = 0;
/* 完整标记,该请求是否已经完整可用 */
- virtual bool Complete() = 0;
+ enum section_t { kSectionHeader, kSectionBody, kSecionMessage };
+ virtual bool Complete(section_t section) = 0;
+
+ /* HTTP版本 */
+ using version_t = std::tuple<short, short>;
+ virtual version_t Version() = 0;
};
class HttpResponse
diff --git a/src/http1.cc b/src/http1.cc
index 895b7d4..a8ce9f8 100644
--- a/src/http1.cc
+++ b/src/http1.cc
@@ -23,6 +23,10 @@
#include "util.h"
#include "easylogging++.h"
+class Http1RequestParserCallbacks;
+class Http1Request;
+class Http1Response;
+
class Http1Request : public HttpRequest
{
public:
@@ -44,89 +48,151 @@ public:
{ return forward_; }
void Forward(bool is_forward) override
{ forward_ = is_forward; }
+
virtual void ForEachHeader(for_each_header_cb_t cb);
- bool Complete() override
- { return request_complete_; }
+ bool Complete(section_t section) override;
const std::string & Url() const override;
void Url(const std::string & url) override;
+
const std::string & HeaderValue(const std::string & field) override;
void HeaderValue(const std::string & field, const std::string & value) override;
+ const body_content_t * Body() override
+ { return body_content_.get(); }
+ void Body(body_content_ptr_t body) override
+ { body_content_ = std::move(body); }
+ body_content_ptr_t StolenBody() override
+ { return std::move(body_content_); }
+
+ version_t Version() override
+ { return version_t{major_version, minor_version}; }
+
private:
+ /* Http Version */
+ short major_version{1};
+ short minor_version{0};
+
+ /* Url and Headers */
std::string str_uri{};
std::map<std::string, std::string> str_headers{};
std::string str_last_header_field_{};
+ /* Pointer to Request Body */
+ body_content_ptr_t body_content_{nullptr};
+
+ /* Tag */
bool request_header_complete_{false};
bool request_body_complete_{false};
- bool request_complete_{false};
bool forward_{true};
bool readonly_{false};
+ /* Underlay Buffer */
std::unique_ptr<struct http_parser> parser_{new struct http_parser};
evbuffer_unique_ptr_t evbuf_content_raw_{evbuffer_unique_ptr_t(evbuffer_new())};
+
+ /* Allow callback handlers to access internal data */
+ friend Http1RequestParserCallbacks;
};
-Http1Request::Http1Request()
+class Http1RequestParserCallbacks
{
- http_parser_init(parser_.get(), HTTP_REQUEST);
-}
+public:
+ static const http_parser_settings * CallbackSettings();
+ static int CallbackOnUri(http_parser * parser, const char * at, size_t length);
+ static int CallbackOnHeaderField(http_parser * parser, const char * at, size_t length);
+ static int CallbackOnHeaderValue(http_parser * parser, const char * at, size_t length);
+ static int CallbackOnBody(http_parser * parser, const char * at, size_t length);
+ static int CallbackOnHeaderComplete(http_parser * parser);
+ static int CallbackOnMessageComplete(http_parser * parser);
-ssize_t Http1Request::ConstructFromMemory(const char * buf, size_t buflen)
+private:
+ static Http1Request * __request_this_ptr(http_parser * parser)
+ { return static_cast<Http1Request *>(parser->data); }
+};
+
+const http_parser_settings * Http1RequestParserCallbacks::CallbackSettings()
{
- static http_data_cb __http_parser_cb_on_uri = [](http_parser * parser, const char * at, size_t length) -> int
+ static struct http_parser_settings __parser_setting =
{
- auto * __ptr_this = reinterpret_cast<Http1Request *>(parser->data);
- __ptr_this->str_uri = std::string(at, at + length);
- return 0;
+ on_message_begin : nullptr, /* on_message_begin */
+ on_url : CallbackOnUri, /* on_url */
+ on_status : nullptr, /* on_status */
+ on_header_field : CallbackOnHeaderField, /* on_header_field */
+ on_header_value : CallbackOnHeaderValue, /* on_header_value */
+ on_headers_complete : CallbackOnHeaderComplete, /* on_headers_complete */
+ on_body : CallbackOnBody, /* on_body */
+ on_message_complete : CallbackOnMessageComplete /* on_message_complete */
};
- static http_data_cb
- __http_parser_cb_on_header_field = [](http_parser * parser, const char * at, size_t length) -> int
- {
- auto * __ptr_this = reinterpret_cast<Http1Request *>(parser->data);
- __ptr_this->str_last_header_field_ = std::string(at, at + length);
- return 0;
- };
+ return &__parser_setting;
+}
- static http_data_cb
- __http_parser_cb_on_header_value = [](http_parser * parser, const char * at, size_t length) -> int
- {
- auto * __ptr_this = reinterpret_cast<Http1Request *>(parser->data);
- __ptr_this->str_headers[__ptr_this->str_last_header_field_] = std::string(at, at + length);
+int Http1RequestParserCallbacks::CallbackOnUri(http_parser * parser, const char * at, size_t length)
+{
+ __request_this_ptr(parser)->str_uri = std::string(at, at + length);
+ return 0;
+}
- /* 对于Host字段,合成URL */
- if (__ptr_this->str_last_header_field_ == "Host")
- {
- __ptr_this->str_uri = __ptr_this->str_headers[__ptr_this->str_last_header_field_] + __ptr_this->str_uri;
- }
+int Http1RequestParserCallbacks::CallbackOnHeaderField(http_parser * parser, const char * at, size_t length)
+{
+ __request_this_ptr(parser)->str_last_header_field_ = std::string(at, at + length);
+ return 0;
+}
- return 0;
- };
+int Http1RequestParserCallbacks::CallbackOnHeaderValue(http_parser * parser, const char * at, size_t length)
+{
+ auto * request_ptr = __request_this_ptr(parser);
+ request_ptr->str_headers[request_ptr->str_last_header_field_] = std::string(at, at + length);
- static http_cb __http_parser_cb_on_message_complete = [](http_parser * parser) -> int
+ /* 对于Host字段,合成URL */
+ if (request_ptr->str_last_header_field_ == "Host")
{
- auto * __ptr_this = reinterpret_cast<Http1Request *>(parser->data);
- __ptr_this->request_complete_ = true;
- return 0;
- };
+ request_ptr->str_uri = request_ptr->str_headers[request_ptr->str_last_header_field_] + request_ptr->str_uri;
+ }
- static struct http_parser_settings __parser_setting =
- {
- nullptr, /* on_message_begin */
- __http_parser_cb_on_uri, /* on_url */
- nullptr, /* on_status */
- __http_parser_cb_on_header_field, /* on_header_field */
- __http_parser_cb_on_header_value, /* on_header_value */
- __http_parser_cb_on_message_complete, /* on_headers_complete */
- nullptr, /* on_body */
- nullptr /* on_message_complete */
- };
+ return 0;
+}
+
+int Http1RequestParserCallbacks::CallbackOnBody(http_parser * parser, const char * at, size_t length)
+{
+ auto * request_ptr = __request_this_ptr(parser);
+
+ /* Alloc the content buffer, reserve the contanier */
+ request_ptr->body_content_ = std::make_unique<std::vector<char>>();
+ request_ptr->body_content_->reserve(length);
+
+ /* Copy content into request body buffer */
+ std::copy_n(at, length, std::back_inserter(*request_ptr->body_content_));
+ return 0;
+}
+int Http1RequestParserCallbacks::CallbackOnHeaderComplete(http_parser * parser)
+{
+ __request_this_ptr(parser)->request_header_complete_ = true;
+ __request_this_ptr(parser)->major_version = parser->http_major;
+ __request_this_ptr(parser)->minor_version = parser->http_minor;
+
+ return 0;
+}
+
+int Http1RequestParserCallbacks::CallbackOnMessageComplete(http_parser * parser)
+{
+ __request_this_ptr(parser)->request_body_complete_ = true;
+ return 0;
+}
+
+Http1Request::Http1Request()
+{
+ http_parser_init(parser_.get(), HTTP_REQUEST);
+}
+
+ssize_t Http1Request::ConstructFromMemory(const char * buf, size_t buflen)
+{
parser_->data = this;
- size_t sz_parsed = http_parser_execute(parser_.get(), &__parser_setting, buf, buflen);
+ size_t sz_parsed = http_parser_execute(parser_.get(),
+ Http1RequestParserCallbacks::CallbackSettings(), buf, buflen);
/* 解析错误 */
if (sz_parsed && parser_->http_errno > 0)
@@ -191,6 +257,13 @@ void Http1Request::HeaderValue(const std::string & field, const std::string & va
str_headers[field] = value;
}
+bool Http1Request::Complete(section_t section)
+{
+ if (section == kSectionHeader) return request_header_complete_;
+ if (section == kSectionBody) return request_body_complete_;
+ if (section == kSecionMessage) return request_body_complete_ && request_header_complete_;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HTTP Response Parser Implementation for HTTP 1.0/1.1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -286,6 +359,7 @@ public:
{ return parse_complete_; }
virtual void Construct() final;
void ResponseCode(int code) override;
+
const std::string & HeaderValue(const std::string & field) override;
void HeaderValue(const std::string & field, const std::string & value) override;
void ForEachHeader(for_each_header_cb_t cb) override;
@@ -455,9 +529,13 @@ int Http1Connection::on_connection_read_request(pxy_conn_ctx_t * conn_ctx, pxy_c
return 0;
}
- if (request.Complete())
+ if (request.Complete(HttpRequest::kSectionHeader))
{
http_session.CallRequestHeaderCallback();
+ }
+
+ if (request.Complete(HttpRequest::kSectionBody))
+ {
http_session.CallRequestBodyCallback();
}
@@ -467,7 +545,7 @@ int Http1Connection::on_connection_read_request(pxy_conn_ctx_t * conn_ctx, pxy_c
return 0;
}
- if (request.ReadOnly() || request.Complete())
+ if (request.ReadOnly() || request.Complete(HttpRequest::kSecionMessage))
{
evbuffer_add_buffer(upstream_evbuf, request.StolenEvbuf().release());
return 0;
@@ -503,7 +581,7 @@ HttpSession & Http1Connection::last_uncomplete_session()
/* 最后一个Session已经处理结束了,新建一个Session */
auto & __session = http_sessions_.back();
- if (__session->request().Complete())
+ if (__session->request().Complete(HttpRequest::kSecionMessage))
return create_new_session();
/* 否则,返回最后一个没有完全处理结束的Session */
@@ -537,7 +615,7 @@ void Http1Connection::Write(std::unique_ptr<HttpSession> http_session)
auto & http1_request = dynamic_cast<Http1Request &>(http_session->request());
auto & http1_response = dynamic_cast<Http1Response &>(http_session->response());
- if (http1_request.Complete())
+ if (http1_request.Complete(HttpRequest::kSecionMessage))
{
auto stolen_buffer = http1_request.StolenEvbuf();
bufferevent_write_buffer(bev_upstream_, stolen_buffer.release());
diff --git a/src/http2.cc b/src/http2.cc
index 3ef07b8..664fd6b 100644
--- a/src/http2.cc
+++ b/src/http2.cc
@@ -52,7 +52,7 @@ public:
void ReadOnly(bool is_readonly) override;
bool Forward() override;
void Forward(bool is_forward) override;
- bool Complete() override;
+ bool Complete(section_t section) override;
private:
using header_kv_t = std::pair<std::string, std::string>;
@@ -179,7 +179,7 @@ void Http2Request::Forward(bool is_forward)
}
-bool Http2Request::Complete()
+bool Http2Request::Complete(section_t section)
{
return false;
}
diff --git a/src/httpscan.cc b/src/httpscan.cc
index 407e1ba..8d0d4f8 100644
--- a/src/httpscan.cc
+++ b/src/httpscan.cc
@@ -34,7 +34,7 @@ HttpScan::HttpScan(struct tfe_instance * instance, struct tfe_config * config)
table_id_ctrl_ip = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_IP");
table_id_ctrl_http_url = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_URL");
table_id_ctrl_http_req_hdr = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_REQ_HDR");
- table_id_ctrl_http_req_body = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_URL");
+ table_id_ctrl_http_req_body = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_REQ_BODY");
table_id_ctrl_http_res_hdr = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_RES_HDR");
table_id_ctrl_http_res_body = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_RES_BODY");
@@ -194,6 +194,29 @@ void HttpScanSession::ScanRequestHeader(HttpSession * http_session_ctx)
void HttpScanSession::ScanRequestBody(HttpSession * http_session_ctx)
{
+ auto & http_request = http_session_ctx->request();
+
+ /* Body Content and length, prepare for maat */
+ const char * body_content_raw = http_request.Body()->data();
+ size_t body_content_length = http_request.Body()->size();
+
+ /* Dummy For maat */
+ int __dummy[MAAT_SCAN_RESULT_];
+
+ nr_maat_scan_result_ = Maat_full_scan_string(httpscan_module_ref_.maat_feather_ref,
+ httpscan_module_ref_.table_id_ctrl_http_req_body, CHARSET_UTF8, body_content_raw, (int)body_content_length,
+ maat_scan_result_, __dummy, MAAT_SCAN_RESULT_, &maat_scan_mid_, 0);
+
+ if (nr_maat_scan_result_ > 0)
+ {
+ http_session_ctx->SetRequestBodyTag(HttpSession::kCallbackTagRepeat);
+ return hit_config_and_do_action(http_session_ctx);
+ }
+ else if (nr_maat_scan_result_ == -1)
+ {
+ return hit_scan_error();
+ }
+
return;
}