diff options
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/http.h | 17 | ||||
| -rw-r--r-- | src/http1.cc | 180 | ||||
| -rw-r--r-- | src/http2.cc | 4 | ||||
| -rw-r--r-- | src/httpscan.cc | 25 |
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 @@ -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; } |
