HTTPS: Keep-Alive connection to downstream servers.
Reset status = 0 when entering s_status state in htparse_run
This commit is contained in:
parent
9303cca430
commit
695dd50612
|
@ -1118,6 +1118,7 @@ htparser_run(htparser * p, htparse_hooks * hooks, const char * data, size_t len)
|
||||||
if (p->type == htp_type_request) {
|
if (p->type == htp_type_request) {
|
||||||
p->state = s_spaces_after_digit;
|
p->state = s_spaces_after_digit;
|
||||||
} else if (p->type == htp_type_response) {
|
} else if (p->type == htp_type_response) {
|
||||||
|
p->status = 0;
|
||||||
p->state = s_status;
|
p->state = s_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ Downstream::Downstream(Upstream *upstream, int stream_id, int priority)
|
||||||
bev_(0),
|
bev_(0),
|
||||||
stream_id_(stream_id),
|
stream_id_(stream_id),
|
||||||
priority_(priority),
|
priority_(priority),
|
||||||
|
counter_(1),
|
||||||
ioctrl_(0),
|
ioctrl_(0),
|
||||||
request_state_(INITIAL),
|
request_state_(INITIAL),
|
||||||
request_major_(1),
|
request_major_(1),
|
||||||
|
@ -53,6 +54,7 @@ Downstream::Downstream(Upstream *upstream, int stream_id, int priority)
|
||||||
response_major_(1),
|
response_major_(1),
|
||||||
response_minor_(1),
|
response_minor_(1),
|
||||||
chunked_response_(false),
|
chunked_response_(false),
|
||||||
|
response_connection_close_(false),
|
||||||
response_htp_(htparser_new()),
|
response_htp_(htparser_new()),
|
||||||
response_body_buf_(0)
|
response_body_buf_(0)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +84,41 @@ Downstream::~Downstream()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Downstream::get_counter() const
|
||||||
|
{
|
||||||
|
return counter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Downstream::reuse(int stream_id)
|
||||||
|
{
|
||||||
|
stream_id_ = stream_id;
|
||||||
|
++counter_;
|
||||||
|
request_state_ = INITIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Downstream::idle()
|
||||||
|
{
|
||||||
|
stream_id_ = -1;
|
||||||
|
priority_ = 0;
|
||||||
|
ioctrl_.force_resume_read();
|
||||||
|
request_state_ = IDLE;
|
||||||
|
request_method_.clear();
|
||||||
|
request_path_.clear();
|
||||||
|
request_major_ = 1;
|
||||||
|
request_minor_ = 1;
|
||||||
|
chunked_request_ = false;
|
||||||
|
request_connection_close_ = false;
|
||||||
|
request_headers_.clear();
|
||||||
|
|
||||||
|
response_state_ = INITIAL;
|
||||||
|
response_http_status_ = 0;
|
||||||
|
response_major_ = 1;
|
||||||
|
response_minor_ = 1;
|
||||||
|
chunked_response_ = false;
|
||||||
|
response_connection_close_ = false;
|
||||||
|
response_headers_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void Downstream::pause_read(IOCtrlReason reason)
|
void Downstream::pause_read(IOCtrlReason reason)
|
||||||
{
|
{
|
||||||
ioctrl_.pause_read(reason);
|
ioctrl_.pause_read(reason);
|
||||||
|
@ -110,8 +147,8 @@ void check_transfer_encoding_chunked(bool *chunked,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void check_request_connection(bool *connection_close,
|
void check_connection_close(bool *connection_close,
|
||||||
const Headers::value_type &item)
|
const Headers::value_type &item)
|
||||||
{
|
{
|
||||||
if(util::strieq(item.first.c_str(), "connection")) {
|
if(util::strieq(item.first.c_str(), "connection")) {
|
||||||
if(util::strifind(item.second.c_str(), "close")) {
|
if(util::strifind(item.second.c_str(), "close")) {
|
||||||
|
@ -134,7 +171,7 @@ void Downstream::set_last_request_header_value(const std::string& value)
|
||||||
Headers::value_type &item = request_headers_.back();
|
Headers::value_type &item = request_headers_.back();
|
||||||
item.second = value;
|
item.second = value;
|
||||||
check_transfer_encoding_chunked(&chunked_request_, item);
|
check_transfer_encoding_chunked(&chunked_request_, item);
|
||||||
check_request_connection(&request_connection_close_, item);
|
check_connection_close(&request_connection_close_, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::set_request_method(const std::string& method)
|
void Downstream::set_request_method(const std::string& method)
|
||||||
|
@ -255,7 +292,9 @@ int Downstream::push_request_headers()
|
||||||
}
|
}
|
||||||
hdrs += "\r\n";
|
hdrs += "\r\n";
|
||||||
}
|
}
|
||||||
hdrs += "Connection: close\r\n";
|
if(request_connection_close_) {
|
||||||
|
hdrs += "Connection: close\r\n";
|
||||||
|
}
|
||||||
if(!xff_found) {
|
if(!xff_found) {
|
||||||
hdrs += "X-Forwarded-For: ";
|
hdrs += "X-Forwarded-For: ";
|
||||||
hdrs += upstream_->get_client_handler()->get_ipaddr();
|
hdrs += upstream_->get_client_handler()->get_ipaddr();
|
||||||
|
@ -327,6 +366,7 @@ void Downstream::set_last_response_header_value(const std::string& value)
|
||||||
Headers::value_type &item = response_headers_.back();
|
Headers::value_type &item = response_headers_.back();
|
||||||
item.second = value;
|
item.second = value;
|
||||||
check_transfer_encoding_chunked(&chunked_response_, item);
|
check_transfer_encoding_chunked(&chunked_response_, item);
|
||||||
|
check_connection_close(&response_connection_close_, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Downstream::get_response_http_status() const
|
unsigned int Downstream::get_response_http_status() const
|
||||||
|
@ -364,6 +404,11 @@ bool Downstream::get_chunked_response() const
|
||||||
return chunked_response_;
|
return chunked_response_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Downstream::get_response_connection_close() const
|
||||||
|
{
|
||||||
|
return response_connection_close_;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int htp_hdrs_completecb(htparser *htp)
|
int htp_hdrs_completecb(htparser *htp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,9 @@ public:
|
||||||
void pause_read(IOCtrlReason reason);
|
void pause_read(IOCtrlReason reason);
|
||||||
bool resume_read(IOCtrlReason reason);
|
bool resume_read(IOCtrlReason reason);
|
||||||
void force_resume_read();
|
void force_resume_read();
|
||||||
|
void idle();
|
||||||
|
void reuse(int stream_id);
|
||||||
|
int get_counter() const;
|
||||||
// downstream request API
|
// downstream request API
|
||||||
const Headers& get_request_headers() const;
|
const Headers& get_request_headers() const;
|
||||||
void add_request_header(const std::string& name, const std::string& value);
|
void add_request_header(const std::string& name, const std::string& value);
|
||||||
|
@ -78,7 +81,8 @@ public:
|
||||||
HEADER_COMPLETE,
|
HEADER_COMPLETE,
|
||||||
MSG_COMPLETE,
|
MSG_COMPLETE,
|
||||||
STREAM_CLOSED,
|
STREAM_CLOSED,
|
||||||
CONNECT_FAIL
|
CONNECT_FAIL,
|
||||||
|
IDLE
|
||||||
};
|
};
|
||||||
void set_request_state(int state);
|
void set_request_state(int state);
|
||||||
int get_request_state() const;
|
int get_request_state() const;
|
||||||
|
@ -93,6 +97,7 @@ public:
|
||||||
int get_response_major() const;
|
int get_response_major() const;
|
||||||
int get_response_minor() const;
|
int get_response_minor() const;
|
||||||
bool get_chunked_response() const;
|
bool get_chunked_response() const;
|
||||||
|
bool get_response_connection_close() const;
|
||||||
int parse_http_response();
|
int parse_http_response();
|
||||||
void set_response_state(int state);
|
void set_response_state(int state);
|
||||||
int get_response_state() const;
|
int get_response_state() const;
|
||||||
|
@ -103,6 +108,7 @@ private:
|
||||||
bufferevent *bev_;
|
bufferevent *bev_;
|
||||||
int32_t stream_id_;
|
int32_t stream_id_;
|
||||||
int priority_;
|
int priority_;
|
||||||
|
int counter_;
|
||||||
IOControl ioctrl_;
|
IOControl ioctrl_;
|
||||||
int request_state_;
|
int request_state_;
|
||||||
std::string request_method_;
|
std::string request_method_;
|
||||||
|
@ -118,6 +124,7 @@ private:
|
||||||
int response_major_;
|
int response_major_;
|
||||||
int response_minor_;
|
int response_minor_;
|
||||||
bool chunked_response_;
|
bool chunked_response_;
|
||||||
|
bool response_connection_close_;
|
||||||
Headers response_headers_;
|
Headers response_headers_;
|
||||||
htparser *response_htp_;
|
htparser *response_htp_;
|
||||||
// This buffer is used to temporarily store downstream response
|
// This buffer is used to temporarily store downstream response
|
||||||
|
|
|
@ -76,8 +76,14 @@ int htp_msg_begin(htparser *htp)
|
||||||
HttpsUpstream *upstream;
|
HttpsUpstream *upstream;
|
||||||
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
||||||
upstream->reset_current_header_length();
|
upstream->reset_current_header_length();
|
||||||
Downstream *downstream = new Downstream(upstream, 0, 0);
|
Downstream *downstream = upstream->get_top_downstream();
|
||||||
upstream->add_downstream(downstream);
|
if(downstream) {
|
||||||
|
// Keep-Alived connection
|
||||||
|
downstream->reuse(0);
|
||||||
|
} else {
|
||||||
|
downstream = new Downstream(upstream, 0, 0);
|
||||||
|
upstream->add_downstream(downstream);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -160,11 +166,13 @@ int htp_hdrs_completecb(htparser *htp)
|
||||||
downstream->push_request_headers();
|
downstream->push_request_headers();
|
||||||
downstream->set_request_state(Downstream::HEADER_COMPLETE);
|
downstream->set_request_state(Downstream::HEADER_COMPLETE);
|
||||||
|
|
||||||
int rv = downstream->start_connection();
|
if(downstream->get_counter() == 1) {
|
||||||
if(rv != 0) {
|
int rv = downstream->start_connection();
|
||||||
LOG(ERROR) << "Upstream connection failed";
|
if(rv != 0) {
|
||||||
downstream->set_request_state(Downstream::CONNECT_FAIL);
|
LOG(ERROR) << "Upstream connection failed";
|
||||||
return 1;
|
downstream->set_request_state(Downstream::CONNECT_FAIL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -298,12 +306,21 @@ void https_downstream_readcb(bufferevent *bev, void *ptr)
|
||||||
Downstream *downstream = reinterpret_cast<Downstream*>(ptr);
|
Downstream *downstream = reinterpret_cast<Downstream*>(ptr);
|
||||||
HttpsUpstream *upstream;
|
HttpsUpstream *upstream;
|
||||||
upstream = static_cast<HttpsUpstream*>(downstream->get_upstream());
|
upstream = static_cast<HttpsUpstream*>(downstream->get_upstream());
|
||||||
|
if(downstream->get_request_state() == Downstream::IDLE) {
|
||||||
|
upstream->pop_downstream();
|
||||||
|
delete downstream;
|
||||||
|
return;
|
||||||
|
}
|
||||||
int rv = downstream->parse_http_response();
|
int rv = downstream->parse_http_response();
|
||||||
if(rv == 0) {
|
if(rv == 0) {
|
||||||
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
assert(downstream == upstream->get_top_downstream());
|
assert(downstream == upstream->get_top_downstream());
|
||||||
upstream->pop_downstream();
|
if(downstream->get_response_connection_close()) {
|
||||||
delete downstream;
|
upstream->pop_downstream();
|
||||||
|
delete downstream;
|
||||||
|
} else {
|
||||||
|
downstream->idle();
|
||||||
|
}
|
||||||
upstream->resume_read(SHRPX_MSG_BLOCK);
|
upstream->resume_read(SHRPX_MSG_BLOCK);
|
||||||
} else {
|
} else {
|
||||||
ClientHandler *handler = upstream->get_client_handler();
|
ClientHandler *handler = upstream->get_client_handler();
|
||||||
|
@ -344,27 +361,28 @@ void https_downstream_eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
LOG(INFO) << "Downstream connection established. downstream "
|
LOG(INFO) << "Downstream connection established. downstream "
|
||||||
<< downstream;
|
<< downstream;
|
||||||
}
|
}
|
||||||
}
|
} else if(events & BEV_EVENT_EOF) {
|
||||||
if(events & BEV_EVENT_EOF) {
|
|
||||||
if(ENABLE_LOG) {
|
if(ENABLE_LOG) {
|
||||||
LOG(INFO) << "Downstream EOF. stream_id="
|
LOG(INFO) << "Downstream EOF. stream_id="
|
||||||
<< downstream->get_stream_id();
|
<< downstream->get_stream_id();
|
||||||
}
|
}
|
||||||
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
if(downstream->get_request_state() != Downstream::IDLE) {
|
||||||
// Server may indicate the end of the request by EOF
|
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
||||||
if(ENABLE_LOG) {
|
// Server may indicate the end of the request by EOF
|
||||||
LOG(INFO) << "Assuming downstream content-length is 0 byte";
|
if(ENABLE_LOG) {
|
||||||
|
LOG(INFO) << "Assuming downstream content-length is 0 byte";
|
||||||
|
}
|
||||||
|
upstream->on_downstream_body_complete(downstream);
|
||||||
|
//downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
|
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
// Nothing to do
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
if(ENABLE_LOG) {
|
||||||
|
LOG(INFO) << "Treated as downstream error";
|
||||||
|
}
|
||||||
|
upstream->error_reply(502);
|
||||||
}
|
}
|
||||||
upstream->on_downstream_body_complete(downstream);
|
|
||||||
//downstream->set_response_state(Downstream::MSG_COMPLETE);
|
|
||||||
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
|
||||||
// Nothing to do
|
|
||||||
} else {
|
|
||||||
// error
|
|
||||||
if(ENABLE_LOG) {
|
|
||||||
LOG(INFO) << "Treated as downstream error";
|
|
||||||
}
|
|
||||||
upstream->error_reply(502);
|
|
||||||
}
|
}
|
||||||
upstream->pop_downstream();
|
upstream->pop_downstream();
|
||||||
delete downstream;
|
delete downstream;
|
||||||
|
|
Loading…
Reference in New Issue