422 lines
13 KiB
C
422 lines
13 KiB
C
|
|
#ifndef TFE_HTTP_H
|
|||
|
|
#define TFE_HTTP_H
|
|||
|
|
|
|||
|
|
#include <vector>
|
|||
|
|
#include <memory>
|
|||
|
|
#include <map>
|
|||
|
|
#include <string>
|
|||
|
|
#include <list>
|
|||
|
|
|
|||
|
|
#include "util.h"
|
|||
|
|
#include "easylogging++.h"
|
|||
|
|
|
|||
|
|
class HttpConnection;
|
|||
|
|
class HttpSession;
|
|||
|
|
class HttpRequest;
|
|||
|
|
class HttpResponse;
|
|||
|
|
|
|||
|
|
class Http
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
/* 回调函数调用 */
|
|||
|
|
using connection_cb_t = std::function<void(Http & ht, HttpConnection & ct)>;
|
|||
|
|
|
|||
|
|
/* 回调函数设置 */
|
|||
|
|
void SetHttpConnectionNewCallback(connection_cb_t cb)
|
|||
|
|
{ connection_new_cb_ = cb; }
|
|||
|
|
void SetHttpConnectionCloseCallback(connection_cb_t cb)
|
|||
|
|
{ connection_close_cb_ = cb; }
|
|||
|
|
|
|||
|
|
/* 回调函数调用 */
|
|||
|
|
void TriggerConnectionNew(HttpConnection & ct)
|
|||
|
|
{ return connection_new_cb_(*this, ct); }
|
|||
|
|
void TriggerConnectionClose(HttpConnection & ct)
|
|||
|
|
{ return connection_close_cb_(*this, ct); }
|
|||
|
|
|
|||
|
|
static std::unique_ptr<Http> Factory(TfeConfigParser & cfg);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
connection_cb_t connection_new_cb_;
|
|||
|
|
connection_cb_t connection_close_cb_;
|
|||
|
|
|
|||
|
|
/* 压缩降级选项 */
|
|||
|
|
std::vector<std::string> accept_encoding_strip_list_;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class HttpHeaders
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
HttpHeaders() = default;
|
|||
|
|
virtual ~HttpHeaders() = default;
|
|||
|
|
|
|||
|
|
using str_field_t = std::string;
|
|||
|
|
using str_value_t = std::string;
|
|||
|
|
|
|||
|
|
virtual void Add(const str_field_t & str_field, const str_value_t & str_value) = 0;
|
|||
|
|
virtual void Set(const str_field_t & str_field, const str_value_t & str_value) = 0;
|
|||
|
|
virtual void Remove(const str_field_t & str_field) = 0;
|
|||
|
|
|
|||
|
|
using for_each_cb_t = std::function<bool(const str_field_t &, const str_value_t &)>;
|
|||
|
|
|
|||
|
|
virtual bool ForEachHeader(for_each_cb_t cb) const = 0;
|
|||
|
|
virtual bool ForEachValueOfHeader(const str_field_t & str_field, for_each_cb_t cb) const = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class HttpRequest
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
HttpRequest() = default;
|
|||
|
|
virtual ~HttpRequest() = default;
|
|||
|
|
|
|||
|
|
/* URL读取、设置接口 */
|
|||
|
|
virtual const std::string & Url() const = 0;
|
|||
|
|
virtual void Url(const std::string & url) = 0;
|
|||
|
|
|
|||
|
|
virtual const std::string & Uri() const = 0;
|
|||
|
|
virtual void Uri(const std::string & url) = 0;
|
|||
|
|
|
|||
|
|
/* HttpHeaders */
|
|||
|
|
virtual HttpHeaders & Headers() = 0;
|
|||
|
|
virtual const HttpHeaders & cHeaders() const = 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() const = 0;
|
|||
|
|
virtual void Body(body_content_ptr_t body) = 0;
|
|||
|
|
|
|||
|
|
/* Body的Stolen接口 */
|
|||
|
|
virtual body_content_ptr_t StolenBody() = 0;
|
|||
|
|
|
|||
|
|
/* Bypass,标记本请求为直通
|
|||
|
|
* 当请求标记为直通时,转发数据,不再调用业务处理函数 */
|
|||
|
|
virtual bool Bypass() = 0;
|
|||
|
|
virtual void Bypass(bool is_bypass) = 0;
|
|||
|
|
|
|||
|
|
/* ReadOnly,标记本请求为只读。
|
|||
|
|
* 当一个请求为只读请求时,业务不应修改它的内容,底层处理Readonly的请求时,应直接转发不缓存 */
|
|||
|
|
virtual bool ReadOnly() = 0;
|
|||
|
|
virtual void ReadOnly(bool is_readonly) = 0;
|
|||
|
|
|
|||
|
|
/* Forward,标记本请求应被转发到对端
|
|||
|
|
* 当请求标记为不转发时,该请求被丢弃 */
|
|||
|
|
virtual bool Forward() = 0;
|
|||
|
|
virtual void Forward(bool is_forward) = 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;
|
|||
|
|
|
|||
|
|
/* 构建接口,根据结构化数据构建HTTP请求头部 */
|
|||
|
|
virtual void Construct() = 0;
|
|||
|
|
|
|||
|
|
/* 调试接口 */
|
|||
|
|
virtual std::string DumpToString() = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class HttpResponse
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
enum section_t
|
|||
|
|
{
|
|||
|
|
kSectionHeader,
|
|||
|
|
kSectionBody,
|
|||
|
|
kSectionMessage,
|
|||
|
|
kSectionMax
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum section_state_t
|
|||
|
|
{
|
|||
|
|
kStateBegin,
|
|||
|
|
kStateReading,
|
|||
|
|
kStateComplete,
|
|||
|
|
kStateStream,
|
|||
|
|
kStateCalled,
|
|||
|
|
kStateStolen
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
HttpResponse() = default;
|
|||
|
|
virtual ~HttpResponse() = default;
|
|||
|
|
|
|||
|
|
/* 响应码 */
|
|||
|
|
virtual int ResponseCode() = 0;
|
|||
|
|
virtual void ResponseCode(int cde) = 0;
|
|||
|
|
|
|||
|
|
/* HttpHeaders */
|
|||
|
|
virtual HttpHeaders & Headers() = 0;
|
|||
|
|
virtual const HttpHeaders & cHeaders() const = 0;
|
|||
|
|
|
|||
|
|
/* Request Body */
|
|||
|
|
using body_content_t = std::vector<char>;
|
|||
|
|
using body_content_ptr_t = std::unique_ptr<body_content_t>;
|
|||
|
|
|
|||
|
|
/* Body读取、设置接口 */
|
|||
|
|
virtual const std::vector<const body_content_t *> Body() const = 0;
|
|||
|
|
virtual void Body(std::vector<body_content_ptr_t> body) = 0;
|
|||
|
|
virtual std::vector<body_content_ptr_t> StolenBody() = 0;
|
|||
|
|
|
|||
|
|
/* ReadOnly,标记本请求为只读。
|
|||
|
|
* 当一个请求为只读请求时,业务不应修改它的内容,底层处理Readonly的请求时,应直接转发不缓存 */
|
|||
|
|
virtual bool ReadOnly() = 0;
|
|||
|
|
virtual void ReadOnly(bool is_readonly) = 0;
|
|||
|
|
|
|||
|
|
/* Forward,标记本请求应被转发到对端
|
|||
|
|
* 当请求标记为不转发时,该请求被丢弃 */
|
|||
|
|
virtual bool Forward() = 0;
|
|||
|
|
virtual void Forward(bool is_forward) = 0;
|
|||
|
|
|
|||
|
|
/* Bypass,标记本应答为直通
|
|||
|
|
* 当应答标记为直通时,转发数据,不再调用业务处理函数 */
|
|||
|
|
virtual bool Bypass() = 0;
|
|||
|
|
virtual void Bypass(bool is_bypass) = 0;
|
|||
|
|
|
|||
|
|
virtual section_state_t SectionState(section_t section) = 0;
|
|||
|
|
/* 构建指令,根据Object构建对应的Memory */
|
|||
|
|
virtual void Construct() = 0;
|
|||
|
|
|
|||
|
|
/* 调试接口 */
|
|||
|
|
virtual std::string DumpToString() = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class HttpConnection
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
HttpConnection() = default;
|
|||
|
|
virtual ~HttpConnection() = default;
|
|||
|
|
|
|||
|
|
using http_connection_cb_t = std::function<void(HttpSession &)>;
|
|||
|
|
|
|||
|
|
/* 回调函数设置 */
|
|||
|
|
virtual void SetSessionNewCallback(http_connection_cb_t cb)
|
|||
|
|
{ session_new_cb_ = cb; }
|
|||
|
|
virtual void SetSessionCloseCallback(http_connection_cb_t cb)
|
|||
|
|
{ session_close_cb_ = cb; }
|
|||
|
|
|
|||
|
|
/* 四元组信息获取 */
|
|||
|
|
virtual const struct sockaddr * SockAddrSource() const = 0;
|
|||
|
|
virtual const struct sockaddr * SockAddrDest() const = 0;
|
|||
|
|
|
|||
|
|
virtual void Write(std::unique_ptr<HttpSession> http_session) = 0;
|
|||
|
|
virtual void Close() = 0;
|
|||
|
|
|
|||
|
|
protected:
|
|||
|
|
http_connection_cb_t session_new_cb_{nullptr};
|
|||
|
|
http_connection_cb_t session_close_cb_{nullptr};
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class HttpSession
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
explicit HttpSession(HttpConnection & connection) : http_connection_(connection) {}
|
|||
|
|
virtual ~HttpSession() { __dump_session(); }
|
|||
|
|
|
|||
|
|
using http_session_cb_t = std::function<void(HttpSession &)>;
|
|||
|
|
|
|||
|
|
HttpRequest & request() const
|
|||
|
|
{ return *request_; }
|
|||
|
|
|
|||
|
|
void request(std::unique_ptr<HttpRequest> req)
|
|||
|
|
{ request_ = std::move(req); }
|
|||
|
|
|
|||
|
|
HttpResponse & response() const
|
|||
|
|
{ return *response_; }
|
|||
|
|
|
|||
|
|
void response(std::unique_ptr<HttpResponse> rsp)
|
|||
|
|
{ response_ = std::move(rsp); }
|
|||
|
|
|
|||
|
|
HttpConnection & connection() const
|
|||
|
|
{ return http_connection_; }
|
|||
|
|
|
|||
|
|
virtual void SetRequestHeadAerCallback(http_session_cb_t cb)
|
|||
|
|
{ request_header_cb_ = cb; }
|
|||
|
|
virtual void SetRequestBodyCallback(http_session_cb_t cb)
|
|||
|
|
{ request_body_cb_ = cb; }
|
|||
|
|
virtual void SetResponseHeaderCallback(http_session_cb_t cb)
|
|||
|
|
{ response_header_cb_ = cb; }
|
|||
|
|
virtual void SetResponseBodyCallback(http_session_cb_t cb)
|
|||
|
|
{ response_body_cb_ = cb; }
|
|||
|
|
|
|||
|
|
virtual void CallRequestHeaderCallback()
|
|||
|
|
{ __call_session_callback(request_header_cb_, tag_request_header_cb_); }
|
|||
|
|
virtual void CallRequestBodyCallback()
|
|||
|
|
{ __call_session_callback(request_body_cb_, tag_request_body_cb_); }
|
|||
|
|
virtual void CallResponseHeaderCallback()
|
|||
|
|
{ __call_session_callback(response_header_cb_, tag_response_header_cb_); }
|
|||
|
|
virtual void CallResponseBodyCallback()
|
|||
|
|
{ __call_session_callback(response_body_cb_, tag_response_body_cb_); }
|
|||
|
|
|
|||
|
|
enum CallbackTag
|
|||
|
|
{
|
|||
|
|
kCallbackTagIgnore,
|
|||
|
|
kCallbackTagNormal,
|
|||
|
|
kCallBackTagOnlyOnce,
|
|||
|
|
kCallbackTagRepeat
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
virtual void SetRequestHeaderTag(enum CallbackTag tag)
|
|||
|
|
{ tag_request_header_cb_ = tag; }
|
|||
|
|
virtual void SetRequestBodyTag(enum CallbackTag tag)
|
|||
|
|
{ tag_request_body_cb_ = tag; }
|
|||
|
|
virtual void SetResponseHeaderTag(enum CallbackTag tag)
|
|||
|
|
{ tag_response_header_cb_ = tag; }
|
|||
|
|
virtual void SetResponseBodyTag(enum CallbackTag tag)
|
|||
|
|
{ tag_response_body_cb_ = tag; }
|
|||
|
|
|
|||
|
|
/* 丢弃这一Session,不转发 */
|
|||
|
|
virtual void Drop()
|
|||
|
|
{
|
|||
|
|
/* Disable all callbacks */
|
|||
|
|
SetRequestHeaderTag(kCallbackTagIgnore);
|
|||
|
|
SetRequestBodyTag(kCallbackTagIgnore);
|
|||
|
|
SetResponseHeaderTag(kCallbackTagIgnore);
|
|||
|
|
SetResponseBodyTag(kCallbackTagIgnore);
|
|||
|
|
|
|||
|
|
/* Tag, please drop this session */
|
|||
|
|
need_to_drop_ = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 直通,不再处理这一Session中的任何内容 */
|
|||
|
|
virtual void Bypass()
|
|||
|
|
{
|
|||
|
|
/* Disable all callbacks */
|
|||
|
|
SetRequestHeaderTag(kCallbackTagIgnore);
|
|||
|
|
SetRequestBodyTag(kCallbackTagIgnore);
|
|||
|
|
SetResponseHeaderTag(kCallbackTagIgnore);
|
|||
|
|
SetResponseBodyTag(kCallbackTagIgnore);
|
|||
|
|
|
|||
|
|
need_to_drop_ = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual bool NeedToDrop()
|
|||
|
|
{
|
|||
|
|
return need_to_drop_;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual bool NeedToBypass()
|
|||
|
|
{
|
|||
|
|
return (tag_request_header_cb_ == kCallbackTagIgnore &&
|
|||
|
|
tag_request_body_cb_ == kCallbackTagIgnore &&
|
|||
|
|
tag_response_header_cb_ == kCallbackTagIgnore &&
|
|||
|
|
tag_response_body_cb_ == kCallbackTagIgnore) && (!need_to_drop_);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected:
|
|||
|
|
HttpConnection & http_connection_;
|
|||
|
|
std::unique_ptr<HttpRequest> request_{nullptr};
|
|||
|
|
std::unique_ptr<HttpResponse> response_{nullptr};
|
|||
|
|
std::shared_ptr<void> context_{nullptr};
|
|||
|
|
|
|||
|
|
/* Session Callbacks */
|
|||
|
|
http_session_cb_t request_header_cb_{nullptr};
|
|||
|
|
http_session_cb_t request_body_cb_{nullptr};
|
|||
|
|
http_session_cb_t response_header_cb_{nullptr};
|
|||
|
|
http_session_cb_t response_body_cb_{nullptr};
|
|||
|
|
|
|||
|
|
/* Call tag */
|
|||
|
|
enum CallbackTag tag_request_header_cb_{kCallBackTagOnlyOnce};
|
|||
|
|
enum CallbackTag tag_request_body_cb_{kCallbackTagNormal};
|
|||
|
|
enum CallbackTag tag_response_header_cb_{kCallBackTagOnlyOnce};
|
|||
|
|
enum CallbackTag tag_response_body_cb_{kCallbackTagNormal};
|
|||
|
|
|
|||
|
|
/* Drop tag */
|
|||
|
|
bool need_to_drop_{false};
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void __call_session_callback(const http_session_cb_t & cb, enum CallbackTag & cb_tag)
|
|||
|
|
{
|
|||
|
|
while (cb_tag != kCallbackTagIgnore)
|
|||
|
|
{
|
|||
|
|
cb(*this);
|
|||
|
|
if (cb_tag == kCallbackTagNormal) break;
|
|||
|
|
if (cb_tag == kCallBackTagOnlyOnce) cb_tag = kCallbackTagIgnore;
|
|||
|
|
if (cb_tag == kCallbackTagRepeat) cb_tag = kCallBackTagOnlyOnce;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __dump_session()
|
|||
|
|
{
|
|||
|
|
auto str_src_addr = sockaddr_to_string(http_connection_.SockAddrSource());
|
|||
|
|
auto str_dst_addr = sockaddr_to_string(http_connection_.SockAddrDest());
|
|||
|
|
|
|||
|
|
auto str_request = request_->DumpToString();
|
|||
|
|
auto str_response = response_->DumpToString();
|
|||
|
|
|
|||
|
|
std::string status{};
|
|||
|
|
if (NeedToDrop()) status += "DROP";
|
|||
|
|
if (NeedToBypass()) status += "BYPASS";
|
|||
|
|
|
|||
|
|
CLOG(DEBUG, "HttpSessionTrace") << str_src_addr << str_dst_addr
|
|||
|
|
<< str_request << str_response << status;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
std::unique_ptr<HttpRequest> HttpRequestFactory(int primary_version, int second_version);
|
|||
|
|
std::unique_ptr<HttpResponse> HttpResponseFactory(short major_version, short minor_version);
|
|||
|
|
|
|||
|
|
#include "pxyconn.h"
|
|||
|
|
|
|||
|
|
class Http1Connection : public HttpConnection
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
Http1Connection(struct bufferevent * bev_downstream, struct bufferevent * bev_upstream,
|
|||
|
|
const struct sockaddr_storage & source, const struct sockaddr_storage & dest)
|
|||
|
|
: bev_downstream_(bev_downstream), bev_upstream_(bev_upstream), sockaddr_source_(source), sockaddr_dest_(dest)
|
|||
|
|
{}
|
|||
|
|
|
|||
|
|
~Http1Connection() = default;
|
|||
|
|
|
|||
|
|
void Close() override
|
|||
|
|
{ need_to_close_ = true; };
|
|||
|
|
|
|||
|
|
bool NeedToClose()
|
|||
|
|
{ return need_to_close_; }
|
|||
|
|
|
|||
|
|
int on_connection_read_request(pxy_conn_ctx_t * conn_ctx, pxy_conn_desc_t * conn_this,
|
|||
|
|
pxy_conn_desc_t * conn_other);
|
|||
|
|
int on_connection_read_response(pxy_conn_ctx_t * conn_ctx, pxy_conn_desc_t * conn_this,
|
|||
|
|
pxy_conn_desc_t * conn_other);
|
|||
|
|
int on_connection_close(pxy_conn_ctx_t * conn_ctx, struct bufferevent * bev);
|
|||
|
|
|
|||
|
|
void Write(std::unique_ptr<HttpSession> http_session) override;
|
|||
|
|
|
|||
|
|
const sockaddr * SockAddrSource() const override;
|
|||
|
|
const sockaddr * SockAddrDest() const override;
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
enum direction
|
|||
|
|
{
|
|||
|
|
kDirectionRequest,
|
|||
|
|
kDirectionResponse
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
using http_sessions_t = std::list<std::unique_ptr<HttpSession>>;
|
|||
|
|
http_sessions_t http_sessions_{};
|
|||
|
|
|
|||
|
|
HttpSession * create_new_session();
|
|||
|
|
HttpSession * last_uncomplete_session(enum direction dir);
|
|||
|
|
|
|||
|
|
void drop_last_session();
|
|||
|
|
void drop_first_session();
|
|||
|
|
bool need_to_close_{false};
|
|||
|
|
|
|||
|
|
/* connection info */
|
|||
|
|
struct sockaddr_storage sockaddr_source_;
|
|||
|
|
struct sockaddr_storage sockaddr_dest_;
|
|||
|
|
|
|||
|
|
/* upstream bev */
|
|||
|
|
struct bufferevent * bev_upstream_;
|
|||
|
|
struct bufferevent * bev_downstream_;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif //TFE_HTTP_H
|