nghttpx: Use :authority and host instead of :host
This commit is contained in:
parent
c4ae19e2a0
commit
67553d47e0
17
src/http2.cc
17
src/http2.cc
|
@ -144,7 +144,6 @@ bool check_http2_allowed_header(const uint8_t *name, size_t namelen)
|
||||||
namespace {
|
namespace {
|
||||||
const char *DISALLOWED_HD[] = {
|
const char *DISALLOWED_HD[] = {
|
||||||
"connection",
|
"connection",
|
||||||
"host",
|
|
||||||
"keep-alive",
|
"keep-alive",
|
||||||
"proxy-connection",
|
"proxy-connection",
|
||||||
"te",
|
"te",
|
||||||
|
@ -161,7 +160,6 @@ namespace {
|
||||||
const char *IGN_HD[] = {
|
const char *IGN_HD[] = {
|
||||||
"connection",
|
"connection",
|
||||||
"expect",
|
"expect",
|
||||||
"host",
|
|
||||||
"http2-settings",
|
"http2-settings",
|
||||||
"keep-alive",
|
"keep-alive",
|
||||||
"proxy-connection",
|
"proxy-connection",
|
||||||
|
@ -247,12 +245,18 @@ const nghttp2_nv* get_header(const nghttp2_nv *nva, size_t nvlen,
|
||||||
|
|
||||||
std::string name_to_str(const nghttp2_nv *nv)
|
std::string name_to_str(const nghttp2_nv *nv)
|
||||||
{
|
{
|
||||||
return std::string(reinterpret_cast<const char*>(nv->name), nv->namelen);
|
if(nv) {
|
||||||
|
return std::string(reinterpret_cast<const char*>(nv->name), nv->namelen);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string value_to_str(const nghttp2_nv *nv)
|
std::string value_to_str(const nghttp2_nv *nv)
|
||||||
{
|
{
|
||||||
return std::string(reinterpret_cast<const char*>(nv->value), nv->valuelen);
|
if(nv) {
|
||||||
|
return std::string(reinterpret_cast<const char*>(nv->value), nv->valuelen);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool value_lws(const nghttp2_nv *nv)
|
bool value_lws(const nghttp2_nv *nv)
|
||||||
|
@ -269,6 +273,11 @@ bool value_lws(const nghttp2_nv *nv)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool non_empty_value(const nghttp2_nv* nv)
|
||||||
|
{
|
||||||
|
return nv && !http2::value_lws(nv) && http2::check_header_value(nv);
|
||||||
|
}
|
||||||
|
|
||||||
void copy_norm_headers_to_nv
|
void copy_norm_headers_to_nv
|
||||||
(std::vector<const char*>& nv,
|
(std::vector<const char*>& nv,
|
||||||
const std::vector<std::pair<std::string, std::string>>& headers)
|
const std::vector<std::pair<std::string, std::string>>& headers)
|
||||||
|
|
|
@ -89,6 +89,10 @@ std::string value_to_str(const nghttp2_nv *nv);
|
||||||
// Returns true if the value of |nv| includes only ' ' (0x20) or '\t'.
|
// Returns true if the value of |nv| includes only ' ' (0x20) or '\t'.
|
||||||
bool value_lws(const nghttp2_nv *nv);
|
bool value_lws(const nghttp2_nv *nv);
|
||||||
|
|
||||||
|
// Returns true if the value of |nv| is not empty value and not LWS
|
||||||
|
// and not contain illegal characters.
|
||||||
|
bool non_empty_value(const nghttp2_nv* nv);
|
||||||
|
|
||||||
// Appends headers in |headers| to |nv|. Certain headers, including
|
// Appends headers in |headers| to |nv|. Certain headers, including
|
||||||
// disallowed headers in HTTP/2.0 spec and headers which require
|
// disallowed headers in HTTP/2.0 spec and headers which require
|
||||||
// special handling (i.e. via), are not copied.
|
// special handling (i.e. via), are not copied.
|
||||||
|
|
|
@ -249,6 +249,26 @@ const std::string& Downstream::get_request_path() const
|
||||||
return request_path_;
|
return request_path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& Downstream::get_request_http2_scheme() const
|
||||||
|
{
|
||||||
|
return request_http2_scheme_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Downstream::set_request_http2_scheme(std::string scheme)
|
||||||
|
{
|
||||||
|
request_http2_scheme_ = std::move(scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Downstream::get_request_http2_authority() const
|
||||||
|
{
|
||||||
|
return request_http2_authority_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Downstream::set_request_http2_authority(std::string authority)
|
||||||
|
{
|
||||||
|
request_http2_authority_ = std::move(authority);
|
||||||
|
}
|
||||||
|
|
||||||
void Downstream::set_request_major(int major)
|
void Downstream::set_request_major(int major)
|
||||||
{
|
{
|
||||||
request_major_ = major;
|
request_major_ = major;
|
||||||
|
|
|
@ -104,7 +104,15 @@ public:
|
||||||
const std::string& get_request_method() const;
|
const std::string& get_request_method() const;
|
||||||
void set_request_path(std::string path);
|
void set_request_path(std::string path);
|
||||||
void append_request_path(const char *data, size_t len);
|
void append_request_path(const char *data, size_t len);
|
||||||
|
// Returns request path. For HTTP/1.1, this is request-target. For
|
||||||
|
// HTTP/2, this is :path header field value.
|
||||||
const std::string& get_request_path() const;
|
const std::string& get_request_path() const;
|
||||||
|
// Returns HTTP/2 :scheme header field value.
|
||||||
|
const std::string& get_request_http2_scheme() const;
|
||||||
|
void set_request_http2_scheme(std::string scheme);
|
||||||
|
// Returns HTTP/2 :authority header field value.
|
||||||
|
const std::string& get_request_http2_authority() const;
|
||||||
|
void set_request_http2_authority(std::string authority);
|
||||||
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;
|
||||||
|
@ -184,6 +192,8 @@ private:
|
||||||
int request_state_;
|
int request_state_;
|
||||||
std::string request_method_;
|
std::string request_method_;
|
||||||
std::string request_path_;
|
std::string request_path_;
|
||||||
|
std::string request_http2_scheme_;
|
||||||
|
std::string request_http2_authority_;
|
||||||
int request_major_;
|
int request_major_;
|
||||||
int request_minor_;
|
int request_minor_;
|
||||||
bool chunked_request_;
|
bool chunked_request_;
|
||||||
|
|
|
@ -222,22 +222,33 @@ int on_frame_recv_callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto host = http2::get_unique_header(nva, nvlen, ":host");
|
auto host = http2::get_unique_header(nva, nvlen, "host");
|
||||||
|
auto authority = http2::get_unique_header(nva, nvlen, ":authority");
|
||||||
auto path = http2::get_unique_header(nva, nvlen, ":path");
|
auto path = http2::get_unique_header(nva, nvlen, ":path");
|
||||||
auto method = http2::get_unique_header(nva, nvlen, ":method");
|
auto method = http2::get_unique_header(nva, nvlen, ":method");
|
||||||
auto scheme = http2::get_unique_header(nva, nvlen, ":scheme");
|
auto scheme = http2::get_unique_header(nva, nvlen, ":scheme");
|
||||||
bool is_connect = method &&
|
bool is_connect = method &&
|
||||||
util::streq("CONNECT", method->value, method->valuelen);
|
util::streq("CONNECT", method->value, method->valuelen);
|
||||||
if(!host || !path || !method ||
|
bool having_host = http2::non_empty_value(host);
|
||||||
http2::value_lws(host) || http2::value_lws(path) ||
|
bool having_authority = http2::non_empty_value(authority);
|
||||||
http2::value_lws(method) ||
|
|
||||||
(!is_connect && (!scheme || http2::value_lws(scheme))) ||
|
if(is_connect) {
|
||||||
!http2::check_header_value(host) ||
|
// Here we strictly require :authority header field.
|
||||||
!http2::check_header_value(path) ||
|
if(scheme || path || !having_authority) {
|
||||||
!http2::check_header_value(method) ||
|
upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
|
||||||
(scheme && !http2::check_header_value(scheme))) {
|
return 0;
|
||||||
upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
|
}
|
||||||
return 0;
|
} else {
|
||||||
|
// For proxy, :authority is required. Otherwise, we can accept
|
||||||
|
// :authority or host for methods.
|
||||||
|
if(!http2::non_empty_value(method) ||
|
||||||
|
!http2::non_empty_value(scheme) ||
|
||||||
|
(get_config()->spdy_proxy && !having_authority) ||
|
||||||
|
(!get_config()->spdy_proxy && !having_authority && !having_host) ||
|
||||||
|
!http2::non_empty_value(path)) {
|
||||||
|
upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!is_connect &&
|
if(!is_connect &&
|
||||||
(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
||||||
|
@ -251,21 +262,10 @@ int on_frame_recv_callback
|
||||||
}
|
}
|
||||||
|
|
||||||
downstream->set_request_method(http2::value_to_str(method));
|
downstream->set_request_method(http2::value_to_str(method));
|
||||||
|
downstream->set_request_http2_scheme(http2::value_to_str(scheme));
|
||||||
|
downstream->set_request_http2_authority(http2::value_to_str(authority));
|
||||||
|
downstream->set_request_path(http2::value_to_str(path));
|
||||||
|
|
||||||
// SpdyDownstreamConnection examines request path to find
|
|
||||||
// scheme. We construct abs URI for spdy_bridge mode as well as
|
|
||||||
// spdy_proxy mode.
|
|
||||||
if((get_config()->spdy_proxy || get_config()->spdy_bridge) &&
|
|
||||||
scheme && path->value[0] == '/') {
|
|
||||||
auto reqpath = http2::value_to_str(scheme);
|
|
||||||
reqpath += "://";
|
|
||||||
reqpath += http2::value_to_str(host);
|
|
||||||
reqpath += http2::value_to_str(path);
|
|
||||||
downstream->set_request_path(std::move(reqpath));
|
|
||||||
} else {
|
|
||||||
downstream->set_request_path(http2::value_to_str(path));
|
|
||||||
}
|
|
||||||
downstream->add_request_header("host", http2::value_to_str(host));
|
|
||||||
downstream->check_upgrade_request();
|
downstream->check_upgrade_request();
|
||||||
|
|
||||||
auto dconn = upstream->get_client_handler()->get_downstream_connection();
|
auto dconn = upstream->get_client_handler()->get_downstream_connection();
|
||||||
|
|
|
@ -116,13 +116,39 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream)
|
||||||
|
|
||||||
int HttpDownstreamConnection::push_request_headers()
|
int HttpDownstreamConnection::push_request_headers()
|
||||||
{
|
{
|
||||||
|
downstream_->normalize_request_headers();
|
||||||
|
auto end_headers = std::end(downstream_->get_request_headers());
|
||||||
// Assume that method and request path do not contain \r\n.
|
// Assume that method and request path do not contain \r\n.
|
||||||
std::string hdrs = downstream_->get_request_method();
|
std::string hdrs = downstream_->get_request_method();
|
||||||
hdrs += " ";
|
hdrs += " ";
|
||||||
hdrs += downstream_->get_request_path();
|
if(downstream_->get_request_method() == "CONNECT") {
|
||||||
|
if(!downstream_->get_request_http2_authority().empty()) {
|
||||||
|
hdrs += downstream_->get_request_http2_authority();
|
||||||
|
} else {
|
||||||
|
hdrs += downstream_->get_request_path();
|
||||||
|
}
|
||||||
|
} else if(get_config()->spdy_proxy &&
|
||||||
|
!downstream_->get_request_http2_scheme().empty() &&
|
||||||
|
!downstream_->get_request_http2_authority().empty() &&
|
||||||
|
downstream_->get_request_path().c_str()[0] == '/') {
|
||||||
|
// Construct absolute-form request target because we are going to
|
||||||
|
// send a request to a HTTP/1 proxy.
|
||||||
|
hdrs += downstream_->get_request_http2_scheme();
|
||||||
|
hdrs += "://";
|
||||||
|
hdrs += downstream_->get_request_http2_authority();
|
||||||
|
hdrs += downstream_->get_request_path();
|
||||||
|
} else {
|
||||||
|
// No proxy case. get_request_path() may be absolute-form but we
|
||||||
|
// don't care.
|
||||||
|
hdrs += downstream_->get_request_path();
|
||||||
|
}
|
||||||
hdrs += " HTTP/1.1\r\n";
|
hdrs += " HTTP/1.1\r\n";
|
||||||
downstream_->normalize_request_headers();
|
if(downstream_->get_norm_request_header("host") == end_headers &&
|
||||||
auto end_headers = std::end(downstream_->get_request_headers());
|
!downstream_->get_request_http2_authority().empty()) {
|
||||||
|
hdrs += "Host: ";
|
||||||
|
hdrs += downstream_->get_request_http2_authority();
|
||||||
|
hdrs += "\r\n";
|
||||||
|
}
|
||||||
http2::build_http1_headers_from_norm_headers
|
http2::build_http1_headers_from_norm_headers
|
||||||
(hdrs, downstream_->get_request_headers());
|
(hdrs, downstream_->get_request_headers());
|
||||||
|
|
||||||
|
@ -147,10 +173,13 @@ int HttpDownstreamConnection::push_request_headers()
|
||||||
}
|
}
|
||||||
if(downstream_->get_request_method() != "CONNECT") {
|
if(downstream_->get_request_method() != "CONNECT") {
|
||||||
hdrs += "X-Forwarded-Proto: ";
|
hdrs += "X-Forwarded-Proto: ";
|
||||||
if(util::istartsWith(downstream_->get_request_path(), "http:")) {
|
if(!downstream_->get_request_http2_scheme().empty()) {
|
||||||
hdrs += "http\r\n";
|
hdrs += downstream_->get_request_http2_scheme();
|
||||||
} else {
|
hdrs += "\r\n";
|
||||||
|
} else if(util::istartsWith(downstream_->get_request_path(), "https:")) {
|
||||||
hdrs += "https\r\n";
|
hdrs += "https\r\n";
|
||||||
|
} else {
|
||||||
|
hdrs += "http\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto expect = downstream_->get_norm_request_header("expect");
|
auto expect = downstream_->get_norm_request_header("expect");
|
||||||
|
|
|
@ -232,19 +232,43 @@ int SpdyDownstreamConnection::push_request_headers()
|
||||||
size_t nheader = downstream_->get_request_headers().size();
|
size_t nheader = downstream_->get_request_headers().size();
|
||||||
downstream_->normalize_request_headers();
|
downstream_->normalize_request_headers();
|
||||||
auto end_headers = std::end(downstream_->get_request_headers());
|
auto end_headers = std::end(downstream_->get_request_headers());
|
||||||
// 10 means :method, :scheme, :path and possible via and
|
// 12 means:
|
||||||
// x-forwarded-for header fields. We rename host header field as
|
// 1. :method
|
||||||
// :host.
|
// 2. :scheme
|
||||||
|
// 3. :path
|
||||||
|
// 4. :authority (optional)
|
||||||
|
// 5. via (optional)
|
||||||
|
// 6. x-forwarded-for (optional)
|
||||||
auto nv = std::vector<const char*>();
|
auto nv = std::vector<const char*>();
|
||||||
nv.reserve(nheader * 2 + 10 + 1);
|
nv.reserve(nheader * 2 + 10 + 1);
|
||||||
std::string via_value;
|
std::string via_value;
|
||||||
std::string xff_value;
|
std::string xff_value;
|
||||||
std::string scheme, path, query;
|
std::string scheme, authority, path, query;
|
||||||
if(downstream_->get_request_method() == "CONNECT") {
|
if(downstream_->get_request_method() == "CONNECT") {
|
||||||
// No :scheme header field for CONNECT method.
|
// The upstream may be HTTP/2 or HTTP/1
|
||||||
|
nv.push_back(":authority");
|
||||||
|
if(!downstream_->get_request_http2_authority().empty()) {
|
||||||
|
nv.push_back(downstream_->get_request_http2_authority().c_str());
|
||||||
|
} else {
|
||||||
|
nv.push_back(downstream_->get_request_path().c_str());
|
||||||
|
}
|
||||||
|
} else if(!downstream_->get_request_http2_scheme().empty()) {
|
||||||
|
// Here the upstream is HTTP/2
|
||||||
|
nv.push_back(":scheme");
|
||||||
|
nv.push_back(downstream_->get_request_http2_scheme().c_str());
|
||||||
nv.push_back(":path");
|
nv.push_back(":path");
|
||||||
nv.push_back(downstream_->get_request_path().c_str());
|
nv.push_back(downstream_->get_request_path().c_str());
|
||||||
|
if(!downstream_->get_request_http2_authority().empty()) {
|
||||||
|
nv.push_back(":authority");
|
||||||
|
nv.push_back(downstream_->get_request_http2_authority().c_str());
|
||||||
|
} else if(downstream_->get_norm_request_header("host") == end_headers) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
DCLOG(INFO, this) << "host header field missing";
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// The upstream is HTTP/1
|
||||||
http_parser_url u;
|
http_parser_url u;
|
||||||
const char *url = downstream_->get_request_path().c_str();
|
const char *url = downstream_->get_request_path().c_str();
|
||||||
memset(&u, 0, sizeof(u));
|
memset(&u, 0, sizeof(u));
|
||||||
|
@ -253,6 +277,7 @@ int SpdyDownstreamConnection::push_request_headers()
|
||||||
0, &u);
|
0, &u);
|
||||||
if(rv == 0) {
|
if(rv == 0) {
|
||||||
http2::copy_url_component(scheme, &u, UF_SCHEMA, url);
|
http2::copy_url_component(scheme, &u, UF_SCHEMA, url);
|
||||||
|
http2::copy_url_component(authority, &u, UF_HOST, url);
|
||||||
http2::copy_url_component(path, &u, UF_PATH, url);
|
http2::copy_url_component(path, &u, UF_PATH, url);
|
||||||
http2::copy_url_component(query, &u, UF_QUERY, url);
|
http2::copy_url_component(query, &u, UF_QUERY, url);
|
||||||
if(path.empty()) {
|
if(path.empty()) {
|
||||||
|
@ -277,6 +302,24 @@ int SpdyDownstreamConnection::push_request_headers()
|
||||||
} else {
|
} else {
|
||||||
nv.push_back(path.c_str());
|
nv.push_back(path.c_str());
|
||||||
}
|
}
|
||||||
|
if(!authority.empty()) {
|
||||||
|
// TODO properly check IPv6 numeric address
|
||||||
|
if(authority.find(":") != std::string::npos) {
|
||||||
|
authority = "[" + authority;
|
||||||
|
authority += "]";
|
||||||
|
}
|
||||||
|
if(u.field_set & (1 << UF_PORT)) {
|
||||||
|
authority += ":";
|
||||||
|
authority += util::utos(u.port);
|
||||||
|
}
|
||||||
|
nv.push_back(":authority");
|
||||||
|
nv.push_back(authority.c_str());
|
||||||
|
} else if(downstream_->get_norm_request_header("host") == end_headers) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
DCLOG(INFO, this) << "host header field missing";
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nv.push_back(":method");
|
nv.push_back(":method");
|
||||||
|
@ -284,16 +327,6 @@ int SpdyDownstreamConnection::push_request_headers()
|
||||||
|
|
||||||
http2::copy_norm_headers_to_nv(nv, downstream_->get_request_headers());
|
http2::copy_norm_headers_to_nv(nv, downstream_->get_request_headers());
|
||||||
|
|
||||||
auto host = downstream_->get_norm_request_header("host");
|
|
||||||
if(host == end_headers) {
|
|
||||||
if(LOG_ENABLED(INFO)) {
|
|
||||||
DCLOG(INFO, this) << "host header field missing";
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
nv.push_back(":host");
|
|
||||||
nv.push_back((*host).second.c_str());
|
|
||||||
|
|
||||||
bool content_length = false;
|
bool content_length = false;
|
||||||
if(downstream_->get_norm_request_header("content-length") != end_headers) {
|
if(downstream_->get_norm_request_header("content-length") != end_headers) {
|
||||||
content_length = true;
|
content_length = true;
|
||||||
|
|
|
@ -143,25 +143,24 @@ void on_ctrl_recv_callback
|
||||||
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
SpdyUpstream *upstream = reinterpret_cast<SpdyUpstream*>(user_data);
|
auto upstream = reinterpret_cast<SpdyUpstream*>(user_data);
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SPDYLAY_SYN_STREAM: {
|
case SPDYLAY_SYN_STREAM: {
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream) << "Received upstream SYN_STREAM stream_id="
|
ULOG(INFO, upstream) << "Received upstream SYN_STREAM stream_id="
|
||||||
<< frame->syn_stream.stream_id;
|
<< frame->syn_stream.stream_id;
|
||||||
}
|
}
|
||||||
Downstream *downstream;
|
auto downstream = new Downstream(upstream,
|
||||||
downstream = new Downstream(upstream,
|
frame->syn_stream.stream_id,
|
||||||
frame->syn_stream.stream_id,
|
frame->syn_stream.pri);
|
||||||
frame->syn_stream.pri);
|
|
||||||
upstream->add_downstream(downstream);
|
upstream->add_downstream(downstream);
|
||||||
downstream->init_response_body_buf();
|
downstream->init_response_body_buf();
|
||||||
|
|
||||||
char **nv = frame->syn_stream.nv;
|
auto nv = frame->syn_stream.nv;
|
||||||
const char *path = 0;
|
const char *path = nullptr;
|
||||||
const char *scheme = 0;
|
const char *scheme = nullptr;
|
||||||
const char *host = 0;
|
const char *host = nullptr;
|
||||||
const char *method = 0;
|
const char *method = nullptr;
|
||||||
const char *content_length = 0;
|
const char *content_length = 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) {
|
||||||
|
@ -170,7 +169,6 @@ void on_ctrl_recv_callback
|
||||||
scheme = nv[i+1];
|
scheme = nv[i+1];
|
||||||
} else if(strcmp(nv[i], ":method") == 0) {
|
} else if(strcmp(nv[i], ":method") == 0) {
|
||||||
method = nv[i+1];
|
method = nv[i+1];
|
||||||
downstream->set_request_method(nv[i+1]);
|
|
||||||
} else if(strcmp(nv[i], ":host") == 0) {
|
} else if(strcmp(nv[i], ":host") == 0) {
|
||||||
host = nv[i+1];
|
host = nv[i+1];
|
||||||
} else if(nv[i][0] != ':') {
|
} else if(nv[i][0] != ':') {
|
||||||
|
@ -180,36 +178,31 @@ void on_ctrl_recv_callback
|
||||||
downstream->add_request_header(nv[i], nv[i+1]);
|
downstream->add_request_header(nv[i], nv[i+1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool is_connect = method && strcmp("CONNECT", method) == 0;
|
||||||
if(!path || !host || !method ||
|
if(!path || !host || !method ||
|
||||||
!http2::check_header_value(host) ||
|
!http2::check_header_value(host) ||
|
||||||
!http2::check_header_value(path) ||
|
!http2::check_header_value(path) ||
|
||||||
!http2::check_header_value(method) ||
|
!http2::check_header_value(method) ||
|
||||||
(scheme && !http2::check_header_value(scheme))) {
|
(!is_connect && (!scheme || !http2::check_header_value(scheme)))) {
|
||||||
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Require content-length if FIN flag is not set.
|
// Require content-length if FIN flag is not set.
|
||||||
if(strcmp("CONNECT", method) != 0 &&
|
if(!is_connect && !content_length &&
|
||||||
(frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN) == 0 &&
|
(frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN) == 0) {
|
||||||
!content_length) {
|
|
||||||
upstream->rst_stream(downstream, SPDYLAY_PROTOCOL_ERROR);
|
upstream->rst_stream(downstream, SPDYLAY_PROTOCOL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// SpdyDownstreamConnection examines request path to find
|
|
||||||
// scheme. We construct abs URI for spdy_bridge mode as well as
|
downstream->set_request_method(method);
|
||||||
// spdy_proxy mode.
|
if(is_connect) {
|
||||||
if((get_config()->spdy_proxy || get_config()->spdy_bridge) &&
|
downstream->set_request_http2_authority(path);
|
||||||
scheme && path[0] == '/') {
|
|
||||||
std::string reqpath = scheme;
|
|
||||||
reqpath += "://";
|
|
||||||
reqpath += host;
|
|
||||||
reqpath += path;
|
|
||||||
downstream->set_request_path(std::move(reqpath));
|
|
||||||
} else {
|
} else {
|
||||||
|
downstream->set_request_http2_scheme(scheme);
|
||||||
|
downstream->set_request_http2_authority(host);
|
||||||
downstream->set_request_path(path);
|
downstream->set_request_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
downstream->add_request_header("host", host);
|
|
||||||
downstream->check_upgrade_request();
|
downstream->check_upgrade_request();
|
||||||
|
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
@ -222,8 +215,7 @@ void on_ctrl_recv_callback
|
||||||
<< "\n" << ss.str();
|
<< "\n" << ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamConnection *dconn;
|
auto dconn = upstream->get_client_handler()->get_downstream_connection();
|
||||||
dconn = upstream->get_client_handler()->get_downstream_connection();
|
|
||||||
int rv = dconn->attach_downstream(downstream);
|
int rv = dconn->attach_downstream(downstream);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
// If downstream connection fails, issue RST_STREAM.
|
// If downstream connection fails, issue RST_STREAM.
|
||||||
|
|
Loading…
Reference in New Issue