HTTPS: Keep-Alive connection to downstream servers.

Reset status = 0 when entering s_status state in htparse_run
This commit is contained in:
Tatsuhiro Tsujikawa 2012-06-07 23:42:11 +09:00
parent 9303cca430
commit 695dd50612
4 changed files with 101 additions and 30 deletions

View File

@ -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;
} }

View File

@ -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)
{ {

View File

@ -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

View File

@ -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;