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) {
p->state = s_spaces_after_digit;
} else if (p->type == htp_type_response) {
p->status = 0;
p->state = s_status;
}

View File

@ -42,6 +42,7 @@ Downstream::Downstream(Upstream *upstream, int stream_id, int priority)
bev_(0),
stream_id_(stream_id),
priority_(priority),
counter_(1),
ioctrl_(0),
request_state_(INITIAL),
request_major_(1),
@ -53,6 +54,7 @@ Downstream::Downstream(Upstream *upstream, int stream_id, int priority)
response_major_(1),
response_minor_(1),
chunked_response_(false),
response_connection_close_(false),
response_htp_(htparser_new()),
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)
{
ioctrl_.pause_read(reason);
@ -110,8 +147,8 @@ void check_transfer_encoding_chunked(bool *chunked,
} // namespace
namespace {
void check_request_connection(bool *connection_close,
const Headers::value_type &item)
void check_connection_close(bool *connection_close,
const Headers::value_type &item)
{
if(util::strieq(item.first.c_str(), "connection")) {
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();
item.second = value;
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)
@ -255,7 +292,9 @@ int Downstream::push_request_headers()
}
hdrs += "\r\n";
}
hdrs += "Connection: close\r\n";
if(request_connection_close_) {
hdrs += "Connection: close\r\n";
}
if(!xff_found) {
hdrs += "X-Forwarded-For: ";
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();
item.second = value;
check_transfer_encoding_chunked(&chunked_response_, item);
check_connection_close(&response_connection_close_, item);
}
unsigned int Downstream::get_response_http_status() const
@ -364,6 +404,11 @@ bool Downstream::get_chunked_response() const
return chunked_response_;
}
bool Downstream::get_response_connection_close() const
{
return response_connection_close_;
}
namespace {
int htp_hdrs_completecb(htparser *htp)
{

View File

@ -57,6 +57,9 @@ public:
void pause_read(IOCtrlReason reason);
bool resume_read(IOCtrlReason reason);
void force_resume_read();
void idle();
void reuse(int stream_id);
int get_counter() const;
// downstream request API
const Headers& get_request_headers() const;
void add_request_header(const std::string& name, const std::string& value);
@ -78,7 +81,8 @@ public:
HEADER_COMPLETE,
MSG_COMPLETE,
STREAM_CLOSED,
CONNECT_FAIL
CONNECT_FAIL,
IDLE
};
void set_request_state(int state);
int get_request_state() const;
@ -93,6 +97,7 @@ public:
int get_response_major() const;
int get_response_minor() const;
bool get_chunked_response() const;
bool get_response_connection_close() const;
int parse_http_response();
void set_response_state(int state);
int get_response_state() const;
@ -103,6 +108,7 @@ private:
bufferevent *bev_;
int32_t stream_id_;
int priority_;
int counter_;
IOControl ioctrl_;
int request_state_;
std::string request_method_;
@ -118,6 +124,7 @@ private:
int response_major_;
int response_minor_;
bool chunked_response_;
bool response_connection_close_;
Headers response_headers_;
htparser *response_htp_;
// This buffer is used to temporarily store downstream response

View File

@ -76,8 +76,14 @@ int htp_msg_begin(htparser *htp)
HttpsUpstream *upstream;
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
upstream->reset_current_header_length();
Downstream *downstream = new Downstream(upstream, 0, 0);
upstream->add_downstream(downstream);
Downstream *downstream = upstream->get_top_downstream();
if(downstream) {
// Keep-Alived connection
downstream->reuse(0);
} else {
downstream = new Downstream(upstream, 0, 0);
upstream->add_downstream(downstream);
}
return 0;
}
} // namespace
@ -160,11 +166,13 @@ int htp_hdrs_completecb(htparser *htp)
downstream->push_request_headers();
downstream->set_request_state(Downstream::HEADER_COMPLETE);
int rv = downstream->start_connection();
if(rv != 0) {
LOG(ERROR) << "Upstream connection failed";
downstream->set_request_state(Downstream::CONNECT_FAIL);
return 1;
if(downstream->get_counter() == 1) {
int rv = downstream->start_connection();
if(rv != 0) {
LOG(ERROR) << "Upstream connection failed";
downstream->set_request_state(Downstream::CONNECT_FAIL);
return 1;
}
}
return 0;
}
@ -298,12 +306,21 @@ void https_downstream_readcb(bufferevent *bev, void *ptr)
Downstream *downstream = reinterpret_cast<Downstream*>(ptr);
HttpsUpstream *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();
if(rv == 0) {
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
assert(downstream == upstream->get_top_downstream());
upstream->pop_downstream();
delete downstream;
if(downstream->get_response_connection_close()) {
upstream->pop_downstream();
delete downstream;
} else {
downstream->idle();
}
upstream->resume_read(SHRPX_MSG_BLOCK);
} else {
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 "
<< downstream;
}
}
if(events & BEV_EVENT_EOF) {
} else if(events & BEV_EVENT_EOF) {
if(ENABLE_LOG) {
LOG(INFO) << "Downstream EOF. stream_id="
<< downstream->get_stream_id();
}
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
// Server may indicate the end of the request by EOF
if(ENABLE_LOG) {
LOG(INFO) << "Assuming downstream content-length is 0 byte";
if(downstream->get_request_state() != Downstream::IDLE) {
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
// Server may indicate the end of the request by EOF
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();
delete downstream;