Added SPDY proxy mode.
To enable SPDY proxy, use --spdy-proxy option. At time of this writing, the only browser which supports SSL/SPDY proxy is Chrome. Removed Location and Host header field rewrite.
This commit is contained in:
parent
db8a62c0d7
commit
2c5f40b175
|
@ -343,6 +343,7 @@ void print_help(std::ostream& out)
|
||||||
<< " Default: WARNING\n"
|
<< " Default: WARNING\n"
|
||||||
<< " -D, --daemon Run in a background. If -D is used, the\n"
|
<< " -D, --daemon Run in a background. If -D is used, the\n"
|
||||||
<< " current working directory is changed to '/'.\n"
|
<< " current working directory is changed to '/'.\n"
|
||||||
|
<< " -s, --spdy-proxy SSL/SPDY proxy mode.\n"
|
||||||
<< " -h, --help Print this help.\n"
|
<< " -h, --help Print this help.\n"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
@ -367,11 +368,12 @@ int main(int argc, char **argv)
|
||||||
{"spdy-max-concurrent-streams", required_argument, 0, 'c' },
|
{"spdy-max-concurrent-streams", required_argument, 0, 'c' },
|
||||||
{"log-level", required_argument, 0, 'L' },
|
{"log-level", required_argument, 0, 'L' },
|
||||||
{"daemon", no_argument, 0, 'D' },
|
{"daemon", no_argument, 0, 'D' },
|
||||||
|
{"spdy-proxy", no_argument, 0, 's' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c = getopt_long(argc, argv, "DL:b:c:f:n:h", long_options,
|
int c = getopt_long(argc, argv, "DL:sb:c:f:n:h", long_options,
|
||||||
&option_index);
|
&option_index);
|
||||||
if(c == -1) {
|
if(c == -1) {
|
||||||
break;
|
break;
|
||||||
|
@ -413,6 +415,9 @@ int main(int argc, char **argv)
|
||||||
case 'c':
|
case 'c':
|
||||||
mod_config()->spdy_max_concurrent_streams = strtol(optarg, 0, 10);
|
mod_config()->spdy_max_concurrent_streams = strtol(optarg, 0, 10);
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
mod_config()->spdy_proxy = true;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -254,4 +254,10 @@ DownstreamConnection* ClientHandler::get_downstream_connection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ClientHandler::get_pending_write_length()
|
||||||
|
{
|
||||||
|
evbuffer *output = bufferevent_get_output(bev_);
|
||||||
|
return evbuffer_get_length(output);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
void pool_downstream_connection(DownstreamConnection *dconn);
|
void pool_downstream_connection(DownstreamConnection *dconn);
|
||||||
void remove_downstream_connection(DownstreamConnection *dconn);
|
void remove_downstream_connection(DownstreamConnection *dconn);
|
||||||
DownstreamConnection* get_downstream_connection();
|
DownstreamConnection* get_downstream_connection();
|
||||||
|
size_t get_pending_write_length();
|
||||||
private:
|
private:
|
||||||
bufferevent *bev_;
|
bufferevent *bev_;
|
||||||
SSL *ssl_;
|
SSL *ssl_;
|
||||||
|
|
|
@ -40,7 +40,8 @@ Config::Config()
|
||||||
downstream_hostport(0),
|
downstream_hostport(0),
|
||||||
downstream_addrlen(0),
|
downstream_addrlen(0),
|
||||||
num_worker(0),
|
num_worker(0),
|
||||||
spdy_max_concurrent_streams(0)
|
spdy_max_concurrent_streams(0),
|
||||||
|
spdy_proxy(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -67,6 +67,7 @@ struct Config {
|
||||||
timeval downstream_idle_read_timeout;
|
timeval downstream_idle_read_timeout;
|
||||||
size_t num_worker;
|
size_t num_worker;
|
||||||
size_t spdy_max_concurrent_streams;
|
size_t spdy_max_concurrent_streams;
|
||||||
|
bool spdy_proxy;
|
||||||
Config();
|
Config();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ void Downstream::set_last_request_header_value(const std::string& value)
|
||||||
item.second = value;
|
item.second = value;
|
||||||
check_transfer_encoding_chunked(&chunked_request_, item);
|
check_transfer_encoding_chunked(&chunked_request_, item);
|
||||||
check_expect_100_continue(&request_expect_100_continue_, item);
|
check_expect_100_continue(&request_expect_100_continue_, item);
|
||||||
check_connection_close(&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)
|
||||||
|
@ -174,11 +174,21 @@ void Downstream::set_request_method(const std::string& method)
|
||||||
request_method_ = method;
|
request_method_ = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& Downstream::get_request_method() const
|
||||||
|
{
|
||||||
|
return request_method_;
|
||||||
|
}
|
||||||
|
|
||||||
void Downstream::set_request_path(const std::string& path)
|
void Downstream::set_request_path(const std::string& path)
|
||||||
{
|
{
|
||||||
request_path_ = path;
|
request_path_ = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& Downstream::get_request_path() const
|
||||||
|
{
|
||||||
|
return request_path_;
|
||||||
|
}
|
||||||
|
|
||||||
void Downstream::set_request_major(int major)
|
void Downstream::set_request_major(int major)
|
||||||
{
|
{
|
||||||
request_major_ = major;
|
request_major_ = major;
|
||||||
|
@ -264,14 +274,10 @@ int Downstream::push_request_headers()
|
||||||
hdrs += request_path_;
|
hdrs += request_path_;
|
||||||
hdrs += " ";
|
hdrs += " ";
|
||||||
hdrs += "HTTP/1.1\r\n";
|
hdrs += "HTTP/1.1\r\n";
|
||||||
hdrs += "Host: ";
|
|
||||||
hdrs += get_config()->downstream_hostport;
|
|
||||||
hdrs += "\r\n";
|
|
||||||
std::string via_value;
|
std::string via_value;
|
||||||
for(Headers::const_iterator i = request_headers_.begin();
|
for(Headers::const_iterator i = request_headers_.begin();
|
||||||
i != request_headers_.end(); ++i) {
|
i != request_headers_.end(); ++i) {
|
||||||
if(util::strieq((*i).first.c_str(), "X-Forwarded-Proto") ||
|
if(util::strieq((*i).first.c_str(), "X-Forwarded-Proto") ||
|
||||||
util::strieq((*i).first.c_str(), "host") ||
|
|
||||||
util::strieq((*i).first.c_str(), "keep-alive") ||
|
util::strieq((*i).first.c_str(), "keep-alive") ||
|
||||||
util::strieq((*i).first.c_str(), "connection") ||
|
util::strieq((*i).first.c_str(), "connection") ||
|
||||||
util::strieq((*i).first.c_str(), "proxy-connection")) {
|
util::strieq((*i).first.c_str(), "proxy-connection")) {
|
||||||
|
@ -298,13 +304,20 @@ int Downstream::push_request_headers()
|
||||||
if(request_connection_close_) {
|
if(request_connection_close_) {
|
||||||
hdrs += "Connection: close\r\n";
|
hdrs += "Connection: close\r\n";
|
||||||
}
|
}
|
||||||
|
if(request_method_ != "CONNECT") {
|
||||||
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();
|
||||||
hdrs += "\r\n";
|
hdrs += "\r\n";
|
||||||
}
|
}
|
||||||
hdrs += "X-Forwarded-Proto: https\r\n";
|
hdrs += "X-Forwarded-Proto: ";
|
||||||
|
if(util::istartsWith(request_path_, "http:")) {
|
||||||
|
hdrs += "http";
|
||||||
|
} else {
|
||||||
|
hdrs += "https";
|
||||||
|
}
|
||||||
|
hdrs += "\r\n";
|
||||||
|
}
|
||||||
hdrs += "Via: ";
|
hdrs += "Via: ";
|
||||||
hdrs += via_value;
|
hdrs += via_value;
|
||||||
if(!via_value.empty()) {
|
if(!via_value.empty()) {
|
||||||
|
@ -388,7 +401,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);
|
//check_connection_close(&response_connection_close_, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Downstream::get_response_http_status() const
|
unsigned int Downstream::get_response_http_status() const
|
||||||
|
@ -421,6 +434,11 @@ int Downstream::get_response_minor() const
|
||||||
return response_minor_;
|
return response_minor_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Downstream::get_response_version() const
|
||||||
|
{
|
||||||
|
return response_major_*100+response_minor_;
|
||||||
|
}
|
||||||
|
|
||||||
bool Downstream::get_chunked_response() const
|
bool Downstream::get_chunked_response() const
|
||||||
{
|
{
|
||||||
return chunked_response_;
|
return chunked_response_;
|
||||||
|
@ -431,6 +449,11 @@ bool Downstream::get_response_connection_close() const
|
||||||
return response_connection_close_;
|
return response_connection_close_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Downstream::set_response_connection_close(bool f)
|
||||||
|
{
|
||||||
|
response_connection_close_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int htp_hdrs_completecb(htparser *htp)
|
int htp_hdrs_completecb(htparser *htp)
|
||||||
{
|
{
|
||||||
|
@ -439,6 +462,7 @@ int htp_hdrs_completecb(htparser *htp)
|
||||||
downstream->set_response_http_status(htparser_get_status(htp));
|
downstream->set_response_http_status(htparser_get_status(htp));
|
||||||
downstream->set_response_major(htparser_get_major(htp));
|
downstream->set_response_major(htparser_get_major(htp));
|
||||||
downstream->set_response_minor(htparser_get_minor(htp));
|
downstream->set_response_minor(htparser_get_minor(htp));
|
||||||
|
downstream->set_response_connection_close(!htparser_should_keep_alive(htp));
|
||||||
downstream->set_response_state(Downstream::HEADER_COMPLETE);
|
downstream->set_response_state(Downstream::HEADER_COMPLETE);
|
||||||
downstream->get_upstream()->on_downstream_header_complete(downstream);
|
downstream->get_upstream()->on_downstream_header_complete(downstream);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -470,6 +494,7 @@ int htp_bodycb(htparser *htp, const char *data, size_t len)
|
||||||
{
|
{
|
||||||
Downstream *downstream;
|
Downstream *downstream;
|
||||||
downstream = reinterpret_cast<Downstream*>(htparser_get_userdata(htp));
|
downstream = reinterpret_cast<Downstream*>(htparser_get_userdata(htp));
|
||||||
|
|
||||||
downstream->get_upstream()->on_downstream_body
|
downstream->get_upstream()->on_downstream_body
|
||||||
(downstream, reinterpret_cast<const uint8_t*>(data), len);
|
(downstream, reinterpret_cast<const uint8_t*>(data), len);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -481,6 +506,12 @@ int htp_body_completecb(htparser *htp)
|
||||||
{
|
{
|
||||||
Downstream *downstream;
|
Downstream *downstream;
|
||||||
downstream = reinterpret_cast<Downstream*>(htparser_get_userdata(htp));
|
downstream = reinterpret_cast<Downstream*>(htparser_get_userdata(htp));
|
||||||
|
|
||||||
|
if(downstream->tunnel_established()) {
|
||||||
|
// For tunneling, we remove timeouts.
|
||||||
|
downstream->get_downstream_connection()->remove_timeouts();
|
||||||
|
}
|
||||||
|
|
||||||
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
downstream->get_upstream()->on_downstream_body_complete(downstream);
|
downstream->get_upstream()->on_downstream_body_complete(downstream);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -515,9 +546,11 @@ int Downstream::parse_http_response()
|
||||||
bufferevent *bev = dconn_->get_bev();
|
bufferevent *bev = dconn_->get_bev();
|
||||||
evbuffer *input = bufferevent_get_input(bev);
|
evbuffer *input = bufferevent_get_input(bev);
|
||||||
unsigned char *mem = evbuffer_pullup(input, -1);
|
unsigned char *mem = evbuffer_pullup(input, -1);
|
||||||
|
|
||||||
size_t nread = htparser_run(response_htp_, &htp_hooks,
|
size_t nread = htparser_run(response_htp_, &htp_hooks,
|
||||||
reinterpret_cast<const char*>(mem),
|
reinterpret_cast<const char*>(mem),
|
||||||
evbuffer_get_length(input));
|
evbuffer_get_length(input));
|
||||||
|
|
||||||
evbuffer_drain(input, nread);
|
evbuffer_drain(input, nread);
|
||||||
if(htparser_get_error(response_htp_) == htparse_error_none) {
|
if(htparser_get_error(response_htp_) == htparse_error_none) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -587,4 +620,9 @@ void Downstream::set_recv_window_size(int32_t new_size)
|
||||||
recv_window_size_ = new_size;
|
recv_window_size_ = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Downstream::tunnel_established() const
|
||||||
|
{
|
||||||
|
return request_method_ == "CONNECT" && response_http_status_ == 200;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -66,12 +66,16 @@ public:
|
||||||
int32_t get_recv_window_size() const;
|
int32_t get_recv_window_size() const;
|
||||||
void inc_recv_window_size(int32_t amount);
|
void inc_recv_window_size(int32_t amount);
|
||||||
void set_recv_window_size(int32_t new_size);
|
void set_recv_window_size(int32_t new_size);
|
||||||
|
// Returns true if tunnel connection has been established.
|
||||||
|
bool tunnel_established() 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);
|
||||||
void set_last_request_header_value(const std::string& value);
|
void set_last_request_header_value(const std::string& value);
|
||||||
void set_request_method(const std::string& method);
|
void set_request_method(const std::string& method);
|
||||||
|
const std::string& get_request_method() const;
|
||||||
void set_request_path(const std::string& path);
|
void set_request_path(const std::string& path);
|
||||||
|
const std::string& get_request_path() const;
|
||||||
void set_request_major(int major);
|
void set_request_major(int major);
|
||||||
void set_request_minor(int minor);
|
void set_request_minor(int minor);
|
||||||
int get_request_major() const;
|
int get_request_major() const;
|
||||||
|
@ -103,8 +107,10 @@ public:
|
||||||
void set_response_minor(int minor);
|
void set_response_minor(int minor);
|
||||||
int get_response_major() const;
|
int get_response_major() const;
|
||||||
int get_response_minor() const;
|
int get_response_minor() const;
|
||||||
|
int get_response_version() const;
|
||||||
bool get_chunked_response() const;
|
bool get_chunked_response() const;
|
||||||
bool get_response_connection_close() const;
|
bool get_response_connection_close() const;
|
||||||
|
void set_response_connection_close(bool f);
|
||||||
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;
|
||||||
|
|
|
@ -110,6 +110,13 @@ void DownstreamConnection::start_waiting_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownstreamConnection::remove_timeouts()
|
||||||
|
{
|
||||||
|
if(bev_) {
|
||||||
|
bufferevent_set_timeouts(bev_, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Gets called when DownstreamConnection is pooled in ClientHandler.
|
// Gets called when DownstreamConnection is pooled in ClientHandler.
|
||||||
void idle_eventcb(bufferevent *bev, short events, void *arg)
|
void idle_eventcb(bufferevent *bev, short events, void *arg)
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
ClientHandler* get_client_handler();
|
ClientHandler* get_client_handler();
|
||||||
Downstream* get_downstream();
|
Downstream* get_downstream();
|
||||||
void start_waiting_response();
|
void start_waiting_response();
|
||||||
|
void remove_timeouts();
|
||||||
private:
|
private:
|
||||||
ClientHandler *client_handler_;
|
ClientHandler *client_handler_;
|
||||||
bufferevent *bev_;
|
bufferevent *bev_;
|
||||||
|
|
|
@ -71,11 +71,11 @@ void HttpsUpstream::reset_current_header_length()
|
||||||
namespace {
|
namespace {
|
||||||
int htp_msg_begin(htparser *htp)
|
int htp_msg_begin(htparser *htp)
|
||||||
{
|
{
|
||||||
if(ENABLE_LOG) {
|
|
||||||
LOG(INFO) << "Upstream https request start";
|
|
||||||
}
|
|
||||||
HttpsUpstream *upstream;
|
HttpsUpstream *upstream;
|
||||||
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
||||||
|
if(ENABLE_LOG) {
|
||||||
|
LOG(INFO) << "Upstream https request start " << upstream;
|
||||||
|
}
|
||||||
upstream->reset_current_header_length();
|
upstream->reset_current_header_length();
|
||||||
Downstream *downstream = new Downstream(upstream, 0, 0);
|
Downstream *downstream = new Downstream(upstream, 0, 0);
|
||||||
upstream->add_downstream(downstream);
|
upstream->add_downstream(downstream);
|
||||||
|
@ -111,14 +111,6 @@ int htp_hdrs_begincb(htparser *htp)
|
||||||
if(ENABLE_LOG) {
|
if(ENABLE_LOG) {
|
||||||
LOG(INFO) << "Upstream https request headers start";
|
LOG(INFO) << "Upstream https request headers start";
|
||||||
}
|
}
|
||||||
HttpsUpstream *upstream;
|
|
||||||
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
|
||||||
Downstream *downstream = upstream->get_last_downstream();
|
|
||||||
|
|
||||||
int version = htparser_get_major(htp)*100 + htparser_get_minor(htp);
|
|
||||||
if(version < 101) {
|
|
||||||
downstream->set_request_connection_close(true);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -148,16 +140,18 @@ int htp_hdr_valcb(htparser *htp, const char *data, size_t len)
|
||||||
namespace {
|
namespace {
|
||||||
int htp_hdrs_completecb(htparser *htp)
|
int htp_hdrs_completecb(htparser *htp)
|
||||||
{
|
{
|
||||||
if(ENABLE_LOG) {
|
|
||||||
LOG(INFO) << "Upstream https request headers complete";
|
|
||||||
}
|
|
||||||
HttpsUpstream *upstream;
|
HttpsUpstream *upstream;
|
||||||
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
upstream = reinterpret_cast<HttpsUpstream*>(htparser_get_userdata(htp));
|
||||||
|
if(ENABLE_LOG) {
|
||||||
|
LOG(INFO) << "Upstream https request headers complete " << upstream;
|
||||||
|
}
|
||||||
Downstream *downstream = upstream->get_last_downstream();
|
Downstream *downstream = upstream->get_last_downstream();
|
||||||
|
|
||||||
downstream->set_request_major(htparser_get_major(htp));
|
downstream->set_request_major(htparser_get_major(htp));
|
||||||
downstream->set_request_minor(htparser_get_minor(htp));
|
downstream->set_request_minor(htparser_get_minor(htp));
|
||||||
|
|
||||||
|
downstream->set_request_connection_close(!htparser_should_keep_alive(htp));
|
||||||
|
|
||||||
DownstreamConnection *dconn;
|
DownstreamConnection *dconn;
|
||||||
dconn = upstream->get_client_handler()->get_downstream_connection();
|
dconn = upstream->get_client_handler()->get_downstream_connection();
|
||||||
|
|
||||||
|
@ -238,7 +232,9 @@ int HttpsUpstream::on_read()
|
||||||
{
|
{
|
||||||
bufferevent *bev = handler_->get_bev();
|
bufferevent *bev = handler_->get_bev();
|
||||||
evbuffer *input = bufferevent_get_input(bev);
|
evbuffer *input = bufferevent_get_input(bev);
|
||||||
|
|
||||||
unsigned char *mem = evbuffer_pullup(input, -1);
|
unsigned char *mem = evbuffer_pullup(input, -1);
|
||||||
|
|
||||||
int nread = htparser_run(htp_, &htp_hooks,
|
int nread = htparser_run(htp_, &htp_hooks,
|
||||||
reinterpret_cast<const char*>(mem),
|
reinterpret_cast<const char*>(mem),
|
||||||
evbuffer_get_length(input));
|
evbuffer_get_length(input));
|
||||||
|
@ -347,11 +343,21 @@ void https_downstream_readcb(bufferevent *bev, void *ptr)
|
||||||
dconn->detach_downstream(downstream);
|
dconn->detach_downstream(downstream);
|
||||||
}
|
}
|
||||||
if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
|
if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
ClientHandler *handler = upstream->get_client_handler();
|
||||||
|
if(handler->get_should_close_after_write() &&
|
||||||
|
handler->get_pending_write_length() == 0) {
|
||||||
|
// If all upstream response body has already written out to
|
||||||
|
// the peer, we cannot use writecb for ClientHandler. In
|
||||||
|
// this case, we just delete handler here.
|
||||||
|
delete handler;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
upstream->pop_downstream();
|
upstream->pop_downstream();
|
||||||
delete downstream;
|
delete downstream;
|
||||||
// Process next HTTP request
|
// Process next HTTP request
|
||||||
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();
|
||||||
bufferevent *bev = handler->get_bev();
|
bufferevent *bev = handler->get_bev();
|
||||||
|
@ -411,10 +417,20 @@ void https_downstream_eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
||||||
// Server may indicate the end of the request by EOF
|
// Server may indicate the end of the request by EOF
|
||||||
if(ENABLE_LOG) {
|
if(ENABLE_LOG) {
|
||||||
LOG(INFO) << "Assuming downstream content-length is 0 byte";
|
LOG(INFO) << "Downstream body was ended by EOF";
|
||||||
}
|
}
|
||||||
upstream->on_downstream_body_complete(downstream);
|
upstream->on_downstream_body_complete(downstream);
|
||||||
//downstream->set_response_state(Downstream::MSG_COMPLETE);
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
|
|
||||||
|
ClientHandler *handler = upstream->get_client_handler();
|
||||||
|
if(handler->get_should_close_after_write() &&
|
||||||
|
handler->get_pending_write_length() == 0) {
|
||||||
|
// If all upstream response body has already written out to
|
||||||
|
// the peer, we cannot use writecb for ClientHandler. In this
|
||||||
|
// case, we just delete handler here.
|
||||||
|
delete handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
} else {
|
} else {
|
||||||
|
@ -522,8 +538,11 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream)
|
||||||
LOG(INFO) << "Downstream on_downstream_header_complete";
|
LOG(INFO) << "Downstream on_downstream_header_complete";
|
||||||
}
|
}
|
||||||
std::string via_value;
|
std::string via_value;
|
||||||
std::string location;
|
char temp[16];
|
||||||
std::string hdrs = "HTTP/1.1 ";
|
snprintf(temp, sizeof(temp), "HTTP/%d.%d ",
|
||||||
|
downstream->get_response_major(),
|
||||||
|
downstream->get_response_minor());
|
||||||
|
std::string hdrs = temp;
|
||||||
hdrs += http::get_status_string(downstream->get_response_http_status());
|
hdrs += http::get_status_string(downstream->get_response_http_status());
|
||||||
hdrs += "\r\n";
|
hdrs += "\r\n";
|
||||||
for(Headers::const_iterator i = downstream->get_response_headers().begin();
|
for(Headers::const_iterator i = downstream->get_response_headers().begin();
|
||||||
|
@ -534,8 +553,6 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream)
|
||||||
// These are ignored
|
// These are ignored
|
||||||
} else if(util::strieq((*i).first.c_str(), "via")) {
|
} else if(util::strieq((*i).first.c_str(), "via")) {
|
||||||
via_value = (*i).second;
|
via_value = (*i).second;
|
||||||
} else if(util::strieq((*i).first.c_str(), "location")) {
|
|
||||||
location = (*i).second;
|
|
||||||
} else {
|
} else {
|
||||||
hdrs += (*i).first;
|
hdrs += (*i).first;
|
||||||
hdrs += ": ";
|
hdrs += ": ";
|
||||||
|
@ -543,17 +560,17 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream)
|
||||||
hdrs += "\r\n";
|
hdrs += "\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!location.empty()) {
|
|
||||||
hdrs += "Location: ";
|
if(downstream->get_response_version() < 101) {
|
||||||
hdrs += http::modify_location_header_value(location);
|
if(!downstream->get_response_connection_close()) {
|
||||||
hdrs += "\r\n";
|
|
||||||
}
|
|
||||||
if(get_client_handler()->get_should_close_after_write()) {
|
|
||||||
hdrs += "Connection: close\r\n";
|
|
||||||
} else if(downstream->get_request_major() == 1 &&
|
|
||||||
downstream->get_request_minor() == 0) {
|
|
||||||
hdrs += "Connection: Keep-Alive\r\n";
|
hdrs += "Connection: Keep-Alive\r\n";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if(downstream->get_response_connection_close()) {
|
||||||
|
hdrs += "Connection: close\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hdrs += "Via: ";
|
hdrs += "Via: ";
|
||||||
hdrs += via_value;
|
hdrs += via_value;
|
||||||
if(!via_value.empty()) {
|
if(!via_value.empty()) {
|
||||||
|
@ -598,8 +615,8 @@ int HttpsUpstream::on_downstream_body_complete(Downstream *downstream)
|
||||||
if(ENABLE_LOG) {
|
if(ENABLE_LOG) {
|
||||||
LOG(INFO) << "Downstream on_downstream_body_complete";
|
LOG(INFO) << "Downstream on_downstream_body_complete";
|
||||||
}
|
}
|
||||||
if(downstream->get_request_connection_close()) {
|
if(downstream->get_response_connection_close()) {
|
||||||
ClientHandler *handler = downstream->get_upstream()->get_client_handler();
|
ClientHandler *handler = get_client_handler();
|
||||||
handler->set_should_close_after_write(true);
|
handler->set_should_close_after_write(true);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -103,7 +103,8 @@ void on_stream_close_callback
|
||||||
downstream->set_request_state(Downstream::STREAM_CLOSED);
|
downstream->set_request_state(Downstream::STREAM_CLOSED);
|
||||||
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
// At this point, downstream response was read
|
// At this point, downstream response was read
|
||||||
if(!downstream->get_response_connection_close()) {
|
if(!downstream->tunnel_established() &&
|
||||||
|
!downstream->get_response_connection_close()) {
|
||||||
// Keep-alive
|
// Keep-alive
|
||||||
DownstreamConnection *dconn;
|
DownstreamConnection *dconn;
|
||||||
dconn = downstream->get_downstream_connection();
|
dconn = downstream->get_downstream_connection();
|
||||||
|
@ -146,15 +147,39 @@ void on_ctrl_recv_callback
|
||||||
downstream->init_response_body_buf();
|
downstream->init_response_body_buf();
|
||||||
|
|
||||||
char **nv = frame->syn_stream.nv;
|
char **nv = frame->syn_stream.nv;
|
||||||
|
const char *path = 0;
|
||||||
|
const char *scheme = 0;
|
||||||
|
const char *host = 0;
|
||||||
|
const char *method = 0;
|
||||||
for(size_t i = 0; nv[i]; i += 2) {
|
for(size_t i = 0; nv[i]; i += 2) {
|
||||||
if(strcmp(nv[i], ":path") == 0) {
|
if(strcmp(nv[i], ":path") == 0) {
|
||||||
downstream->set_request_path(nv[i+1]);
|
path = nv[i+1];
|
||||||
|
} else if(strcmp(nv[i], ":scheme") == 0) {
|
||||||
|
scheme = nv[i+1];
|
||||||
} else if(strcmp(nv[i], ":method") == 0) {
|
} else if(strcmp(nv[i], ":method") == 0) {
|
||||||
|
method = nv[i+1];
|
||||||
downstream->set_request_method(nv[i+1]);
|
downstream->set_request_method(nv[i+1]);
|
||||||
|
} else if(strcmp(nv[i], ":host") == 0) {
|
||||||
|
host = nv[i+1];
|
||||||
} else if(nv[i][0] != ':') {
|
} else if(nv[i][0] != ':') {
|
||||||
downstream->add_request_header(nv[i], nv[i+1]);
|
downstream->add_request_header(nv[i], nv[i+1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!path || !host || !method) {
|
||||||
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(get_config()->spdy_proxy && scheme) {
|
||||||
|
std::string reqpath = scheme;
|
||||||
|
reqpath += "://";
|
||||||
|
reqpath += host;
|
||||||
|
reqpath += path;
|
||||||
|
downstream->set_request_path(reqpath);
|
||||||
|
} else {
|
||||||
|
downstream->set_request_path(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
downstream->add_request_header("host", host);
|
||||||
downstream->add_request_header("X-Forwarded-Spdy", "true");
|
downstream->add_request_header("X-Forwarded-Spdy", "true");
|
||||||
|
|
||||||
if(ENABLE_LOG) {
|
if(ENABLE_LOG) {
|
||||||
|
@ -411,11 +436,15 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
||||||
// Server may indicate the end of the request by EOF
|
// Server may indicate the end of the request by EOF
|
||||||
if(ENABLE_LOG) {
|
if(ENABLE_LOG) {
|
||||||
LOG(INFO) << "Assuming downstream content-length is 0 byte";
|
LOG(INFO) << "Downstream body was ended by EOF";
|
||||||
}
|
}
|
||||||
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
upstream->on_downstream_body_complete(downstream);
|
upstream->on_downstream_body_complete(downstream);
|
||||||
} else if(downstream->get_response_state() != Downstream::MSG_COMPLETE) {
|
upstream->send();
|
||||||
|
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
// For SSL tunneling?
|
||||||
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
|
} else {
|
||||||
// If stream was not closed, then we set MSG_COMPLETE and let
|
// If stream was not closed, then we set MSG_COMPLETE and let
|
||||||
// on_stream_close_callback delete downstream.
|
// on_stream_close_callback delete downstream.
|
||||||
upstream->error_reply(downstream, 502);
|
upstream->error_reply(downstream, 502);
|
||||||
|
@ -437,7 +466,10 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
downstream->set_downstream_connection(0);
|
downstream->set_downstream_connection(0);
|
||||||
delete dconn;
|
delete dconn;
|
||||||
dconn = 0;
|
dconn = 0;
|
||||||
if(downstream->get_response_state() != Downstream::MSG_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
// For SSL tunneling
|
||||||
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
|
} else {
|
||||||
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
||||||
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
} else {
|
} else {
|
||||||
|
@ -499,7 +531,9 @@ ssize_t spdy_data_read_callback(spdylay_session *session,
|
||||||
evbuffer *body = downstream->get_response_body_buf();
|
evbuffer *body = downstream->get_response_body_buf();
|
||||||
assert(body);
|
assert(body);
|
||||||
int nread = evbuffer_remove(body, buf, length);
|
int nread = evbuffer_remove(body, buf, length);
|
||||||
if(nread == 0 &&
|
// For tunneling, DATA stream is endless
|
||||||
|
if(!downstream->tunnel_established() &&
|
||||||
|
nread == 0 &&
|
||||||
downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
*eof = 1;
|
*eof = 1;
|
||||||
}
|
}
|
||||||
|
@ -590,7 +624,6 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream)
|
||||||
const char **nv = new const char*[nheader * 2 + 6 + 1];
|
const char **nv = new const char*[nheader * 2 + 6 + 1];
|
||||||
size_t hdidx = 0;
|
size_t hdidx = 0;
|
||||||
std::string via_value;
|
std::string via_value;
|
||||||
std::string location;
|
|
||||||
nv[hdidx++] = ":status";
|
nv[hdidx++] = ":status";
|
||||||
nv[hdidx++] = http::get_status_string(downstream->get_response_http_status());
|
nv[hdidx++] = http::get_status_string(downstream->get_response_http_status());
|
||||||
nv[hdidx++] = ":version";
|
nv[hdidx++] = ":version";
|
||||||
|
@ -604,20 +637,11 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream)
|
||||||
// These are ignored
|
// These are ignored
|
||||||
} else if(util::strieq((*i).first.c_str(), "via")) {
|
} else if(util::strieq((*i).first.c_str(), "via")) {
|
||||||
via_value = (*i).second;
|
via_value = (*i).second;
|
||||||
} else if(util::strieq((*i).first.c_str(), "location")) {
|
|
||||||
location = (*i).second;
|
|
||||||
} else {
|
} else {
|
||||||
nv[hdidx++] = (*i).first.c_str();
|
nv[hdidx++] = (*i).first.c_str();
|
||||||
nv[hdidx++] = (*i).second.c_str();
|
nv[hdidx++] = (*i).second.c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!location.empty()) {
|
|
||||||
nv[hdidx++] = "location";
|
|
||||||
// Assign location to store the result. Otherwise we lose the
|
|
||||||
// return value.
|
|
||||||
location = http::modify_location_header_value(location);
|
|
||||||
nv[hdidx++] = location.c_str();
|
|
||||||
}
|
|
||||||
if(!via_value.empty()) {
|
if(!via_value.empty()) {
|
||||||
via_value += ", ";
|
via_value += ", ";
|
||||||
}
|
}
|
||||||
|
@ -631,7 +655,9 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream)
|
||||||
for(size_t i = 0; nv[i]; i += 2) {
|
for(size_t i = 0; nv[i]; i += 2) {
|
||||||
ss << nv[i] << ": " << nv[i+1] << "\n";
|
ss << nv[i] << ": " << nv[i+1] << "\n";
|
||||||
}
|
}
|
||||||
LOG(INFO) << "Upstream spdy response headers\n" << ss.str();
|
LOG(INFO) << "Upstream spdy response headers id="
|
||||||
|
<< downstream->get_stream_id() << "\n"
|
||||||
|
<< ss.str();
|
||||||
}
|
}
|
||||||
spdylay_data_provider data_prd;
|
spdylay_data_provider data_prd;
|
||||||
data_prd.source.ptr = downstream;
|
data_prd.source.ptr = downstream;
|
||||||
|
|
|
@ -104,7 +104,7 @@ SSL_CTX* create_ssl_context()
|
||||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||||
verify_callback);
|
verify_callback);
|
||||||
}
|
}
|
||||||
// We speaks "http/1.1", "spdy/2" and "spdy/3".
|
// We speak "http/1.1", "spdy/2" and "spdy/3".
|
||||||
proto_list[0] = 6;
|
proto_list[0] = 6;
|
||||||
memcpy(&proto_list[1], "spdy/3", 6);
|
memcpy(&proto_list[1], "spdy/3", 6);
|
||||||
proto_list[7] = 6;
|
proto_list[7] = 6;
|
||||||
|
|
Loading…
Reference in New Issue