#ifndef TFE_HTTP_H #define TFE_HTTP_H #include #include #include #include #include #include "util.h" #include "easylogging++.h" class HttpConnection; class HttpSession; class HttpRequest; class HttpResponse; class Http { public: /* 回调函数调用 */ using connection_cb_t = std::function; /* 回调函数设置 */ 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 Factory(TfeConfigParser & cfg); private: connection_cb_t connection_new_cb_; connection_cb_t connection_close_cb_; /* 压缩降级选项 */ std::vector 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; 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; using body_content_ptr_t = std::unique_ptr; /* 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; 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; using body_content_ptr_t = std::unique_ptr; /* Body读取、设置接口 */ virtual const std::vector Body() const = 0; virtual void Body(std::vector body) = 0; virtual std::vector 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; /* 回调函数设置 */ 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 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; HttpRequest & request() const { return *request_; } void request(std::unique_ptr req) { request_ = std::move(req); } HttpResponse & response() const { return *response_; } void response(std::unique_ptr 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 request_{nullptr}; std::unique_ptr response_{nullptr}; std::shared_ptr 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 HttpRequestFactory(int primary_version, int second_version); std::unique_ptr 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 http_session) override; const sockaddr * SockAddrSource() const override; const sockaddr * SockAddrDest() const override; private: enum direction { kDirectionRequest, kDirectionResponse }; using http_sessions_t = std::list>; 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