diff options
| author | Lu <[email protected]> | 2018-07-27 16:10:50 +0800 |
|---|---|---|
| committer | Lu <[email protected]> | 2018-07-27 16:10:50 +0800 |
| commit | 2bcf031a15cb0565483273a5ade570d5c922ecdc (patch) | |
| tree | 8ae737311fb968a229b9e7210315ec4ac14527c2 | |
| parent | 3f3bd23e54538897ada98a255280a7e8ebf8f8a0 (diff) | |
修正发送伪造HTTP 451重定向报文格式构建错误的问题。
增加发送重定向报文后关闭TCP连接的功能。
| -rw-r--r-- | src/http.h | 14 | ||||
| -rw-r--r-- | src/http1.cc | 58 | ||||
| -rw-r--r-- | src/httpaction.cc | 10 |
3 files changed, 61 insertions, 21 deletions
@@ -202,7 +202,9 @@ public: virtual const struct sockaddr * SockAddrDest() const = 0; virtual void Write(std::unique_ptr<HttpSession> http_session) = 0; - virtual void Close() = 0; + + virtual void CloseImmediately() = 0; + virtual void ClosePeacefully(bool eof_upstream, bool eof_downstream) = 0; protected: http_connection_cb_t session_new_cb_{nullptr}; @@ -367,7 +369,7 @@ private: } }; -std::unique_ptr<HttpRequest> HttpRequestFactory(int primary_version, int second_version); +std::unique_ptr<HttpRequest> HttpRequestFactory(short major_version, short minor_version); std::unique_ptr<HttpResponse> HttpResponseFactory(short major_version, short minor_version); #include "pxyconn.h" @@ -382,9 +384,15 @@ public: ~Http1Connection() = default; - void Close() override + void CloseImmediately() override { need_to_close_ = true; }; + void ClosePeacefully(bool eof_upstream, bool eof_downstream) override + { + if (eof_upstream) bufferevent_trigger_event(bev_upstream_, BEV_EVENT_EOF, 0); + if (eof_downstream) bufferevent_trigger_event(bev_downstream_, BEV_EVENT_EOF, 0); + } + bool NeedToClose() { return need_to_close_; } diff --git a/src/http1.cc b/src/http1.cc index b9a3401..4bd89aa 100644 --- a/src/http1.cc +++ b/src/http1.cc @@ -88,7 +88,7 @@ public: const auto & __header_field = __iterate.first; const auto & __header_value = __iterate.second; - evbuffer_add_printf(__evbuffer_ptr.get(), "%s:%s\r\n", + evbuffer_add_printf(__evbuffer_ptr.get(), "%s: %s\r\n", __header_field.c_str(), __header_value.c_str()); } @@ -155,7 +155,7 @@ private: class Http1Request : public HttpRequest { public: - Http1Request(); + explicit Http1Request(short major_version, short minor_version); virtual ~Http1Request() = default; virtual ssize_t ConstructFromMemory(const char * buf, size_t buflen); @@ -344,7 +344,8 @@ int Http1RequestParserCallbacks::CallbackOnMessageComplete(http_parser * parser) return 0; } -Http1Request::Http1Request() +Http1Request::Http1Request(short major_version, short minor_version) : + major_version_(major_version), minor_version_(minor_version) { http_parser_init(parser_.get(), HTTP_REQUEST); } @@ -474,7 +475,29 @@ static const char * client_error_phrases[] = { /* 414 */ "Request-URI Too Large", /* 415 */ "Unsupported Media Type", /* 416 */ "Requested range not satisfiable", - /* 417 */ "Expectation Failed" + /* 417 */ "Expectation Failed", + /* 418 */ nullptr, + /* 419 */ nullptr, + /* 420 */ nullptr, + /* 421 */ "Misdirected Request", + /* 422 */ "Unprocessable Entity", + /* 423 */ "Locked", + /* 424 */ "Failed Dependency", + /* 425 */ nullptr, + /* 426 */ "Upgrade Required", + /* 427 */ nullptr, + /* 428 */ "Precondition Required", + /* 429 */ "Too Many Requests" +}; + +static const char * client_error_phrases_43x[] = { + /* 430 */ nullptr, + /* 431 */ "Request Header Fields Too Large" +}; + +static const char * client_error_phrases_45x[] = { + /* 450 */ nullptr, + /* 451 */ "Unavailable For Legal Reasons" }; static const char * server_error_phrases[] = { @@ -491,7 +514,9 @@ const char * __resp_code_to_str(int resp_code) if (resp_code >= 101 && resp_code <= 102) return informational_phrases[resp_code - 101]; if (resp_code >= 200 && resp_code <= 206) return success_phrases[resp_code - 200]; if (resp_code >= 300 && resp_code <= 307) return redirection_phrases[resp_code - 300]; - if (resp_code >= 400 && resp_code <= 417) return client_error_phrases[resp_code - 400]; + if (resp_code >= 400 && resp_code <= 429) return client_error_phrases[resp_code - 400]; + if (resp_code >= 430 && resp_code <= 431) return client_error_phrases_43x[resp_code - 430]; + if (resp_code >= 450 && resp_code <= 451) return client_error_phrases_45x[resp_code - 450]; if (resp_code >= 500 && resp_code <= 505) return server_error_phrases[resp_code - 500]; return nullptr; @@ -874,7 +899,7 @@ void Http1Response::Construct() /* 应答头部 */ headers_.ForEachHeader([this, evbuf_ptr](const std::string & str_field, const std::string & str_value) { - evbuffer_add_printf(evbuf_ptr, "%s:%s\r\n", str_field.c_str(), str_value.c_str()); + evbuffer_add_printf(evbuf_ptr, "%s: %s\r\n", str_field.c_str(), str_value.c_str()); return true; }); @@ -1158,27 +1183,27 @@ void Http1Connection::Write(std::unique_ptr<HttpSession> http_session) if (request.Complete(HttpRequest::kSecionMessage)) { auto stolen_buffer = request.StolenEvbuf(); - bufferevent_write_buffer(bev_upstream_, stolen_buffer.release()); + bufferevent_write_buffer(bev_upstream_, stolen_buffer.get()); } if (response.SectionState(response.kSectionMessage) == response.kStateComplete) { auto stolen_buffer = response.StolenEvBuf(); - bufferevent_write_buffer(bev_downstream_, stolen_buffer.release()); + bufferevent_write_buffer(bev_downstream_, stolen_buffer.get()); } return; } -std::unique_ptr<HttpRequest> HttpRequestFactory(int primary_version, int second_version) +std::unique_ptr<HttpRequest> HttpRequestFactory(short major_version, short minor_version) { - if (primary_version == 1 && second_version == 0) - return std::move(std::make_unique<Http1Request>()); - if (primary_version == 1 && second_version == 1) - return std::move(std::make_unique<Http1Request>()); + if (major_version == 1 && minor_version == 0) + return std::move(std::make_unique<Http1Request>(major_version, minor_version)); + if (major_version == 1 && minor_version == 1) + return std::move(std::make_unique<Http1Request>(major_version, minor_version)); - assert(0); - return nullptr; + throw std::invalid_argument(string_format("Invalid HTTP Version: %d, %d", + major_version, minor_version)); } std::unique_ptr<HttpResponse> HttpResponseFactory(short major_version, short minor_version) @@ -1188,6 +1213,7 @@ std::unique_ptr<HttpResponse> HttpResponseFactory(short major_version, short min if (major_version == 1 && minor_version == 1) return std::move(std::make_unique<Http1Response>(major_version, minor_version)); - return nullptr; + throw std::invalid_argument(string_format("Invalid HTTP Version: %d, %d", + major_version, minor_version)); } diff --git a/src/httpaction.cc b/src/httpaction.cc index 0d3fde4..b244879 100644 --- a/src/httpaction.cc +++ b/src/httpaction.cc @@ -368,6 +368,9 @@ void HttpActionRedirect::do_redirect_action(HttpSession * session) http_response.Headers().Add("Location", resp_location_); } + http_response.Headers().Add("Content-Type", "text/html; charset=utf-8"); + http_response.Headers().Add("Content-Length", std::to_string(resp_content_.length())); + /* 应答内容 */ if (is_resp_content_set) { @@ -380,11 +383,14 @@ void HttpActionRedirect::do_redirect_action(HttpSession * session) http_response.Body(std::move(body_segment_vec)); } + + /* 调试记录 */ - str_dump_ = string_format("%d %s", resp_code_, resp_location_.c_str()); + str_dump_ += string_format("%d %s", resp_code_, resp_location_.c_str()); http_response.Construct(); http_connection.Write(std::move(http_session)); + http_connection.ClosePeacefully(true, false); /* 丢弃当前的HTTP Session */ session->Drop(); @@ -420,7 +426,7 @@ private: void HttpActionBlock::do_block_action(HttpSession * session) { - session->connection().Close(); + session->connection().CloseImmediately(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
