nghttpx: Specify altsvc info in one option and allow multiple occurrences

This commit is contained in:
Tatsuhiro Tsujikawa 2014-04-08 22:28:50 +09:00
parent 5b3deec186
commit f9f6cdc93d
5 changed files with 99 additions and 92 deletions

View File

@ -444,14 +444,6 @@ void fill_default_config()
mod_config()->upstream_frame_debug = false; mod_config()->upstream_frame_debug = false;
mod_config()->padding = 0; mod_config()->padding = 0;
mod_config()->altsvc_port = 0;
mod_config()->altsvc_protocol_id = nullptr;
mod_config()->altsvc_protocol_id_len = 0;
mod_config()->altsvc_host = nullptr;
mod_config()->altsvc_host_len = 0;
mod_config()->altsvc_origin = nullptr;
mod_config()->altsvc_origin_len = 0;
nghttp2_option_new(&mod_config()->http2_option); nghttp2_option_new(&mod_config()->http2_option);
nghttp2_option_set_no_auto_stream_window_update nghttp2_option_set_no_auto_stream_window_update
@ -764,19 +756,13 @@ Misc:
downstream request. downstream request.
--no-via Don't append to Via header field. If Via header --no-via Don't append to Via header field. If Via header
field is received, it is left unaltered. field is received, it is left unaltered.
--altsvc-port=<PORT> --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
Port number of alternative service advertised in Specify protocol ID, port, host and origin of
alt-svc header field or HTTP/2 ALTSVC frame. alternative service. <HOST> and <ORIGIN> are
--altsvc-protocol-id=<PROTOID> optional. They are advertised in alt-svc header
ALPN protocol identifier of alternative service field or HTTP/2 ALTSVC frame. This option can be
advertised in alt-svc header field or HTTP/2 used multiple times to specify multiple
ALTSVC frame. alternative services. Example: --altsvc=h2,443
--altsvc-host=<HOST>
Host name that alternative service is available
upon, which is advertised in HTTP/2 ALTSVC frame.
--altsvc-origin=<ORIGIN>
Origin that alternative service is applicable to,
which is advertised in HTTP/2 ALTSVC frame.
--frontend-http2-dump-request-header=<PATH> --frontend-http2-dump-request-header=<PATH>
Dumps request headers received by HTTP/2 frontend Dumps request headers received by HTTP/2 frontend
to the file denoted in <PATH>. The output is to the file denoted in <PATH>. The output is
@ -883,10 +869,7 @@ int main(int argc, char **argv)
{"worker-read-burst", required_argument, &flag, 51}, {"worker-read-burst", required_argument, &flag, 51},
{"worker-write-rate", required_argument, &flag, 52}, {"worker-write-rate", required_argument, &flag, 52},
{"worker-write-burst", required_argument, &flag, 53}, {"worker-write-burst", required_argument, &flag, 53},
{"altsvc-port", required_argument, &flag, 54}, {"altsvc", required_argument, &flag, 54},
{"altsvc-protocol-id", required_argument, &flag, 55},
{"altsvc-host", required_argument, &flag, 56},
{"altsvc-origin", required_argument, &flag, 57},
{nullptr, 0, nullptr, 0 } {nullptr, 0, nullptr, 0 }
}; };
@ -1144,20 +1127,8 @@ int main(int argc, char **argv)
cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_BURST, optarg); cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_BURST, optarg);
break; break;
case 54: case 54:
// --altsvc-port // --altsvc
cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC_PORT, optarg); cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC, optarg);
break;
case 55:
// --altsvc-protocol-id
cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC_PROTOCOL_ID, optarg);
break;
case 56:
// --altsvc-host
cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC_HOST, optarg);
break;
case 57:
// --altsvc-origin
cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC_ORIGIN, optarg);
break; break;
default: default:
break; break;

View File

@ -121,10 +121,7 @@ const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[] =
const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[] = "http2-no-cookie-crumbling"; const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[] = "http2-no-cookie-crumbling";
const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[] = "frontend-frame-debug"; const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[] = "frontend-frame-debug";
const char SHRPX_OPT_PADDING[] = "padding"; const char SHRPX_OPT_PADDING[] = "padding";
const char SHRPX_OPT_ALTSVC_PORT[] = "altsvc-port"; const char SHRPX_OPT_ALTSVC[] = "altsvc";
const char SHRPX_OPT_ALTSVC_PROTOCOL_ID[] = "altsvc-protocol-id";
const char SHRPX_OPT_ALTSVC_HOST[] = "altsvc-host";
const char SHRPX_OPT_ALTSVC_ORIGIN[] = "altsvc-origin";
namespace { namespace {
Config *config = nullptr; Config *config = nullptr;
@ -502,32 +499,50 @@ int parse_config(const char *opt, const char *optarg)
mod_config()->upstream_frame_debug = util::strieq(optarg, "yes"); mod_config()->upstream_frame_debug = util::strieq(optarg, "yes");
} else if(util::strieq(opt, SHRPX_OPT_PADDING)) { } else if(util::strieq(opt, SHRPX_OPT_PADDING)) {
mod_config()->padding = strtoul(optarg, nullptr, 10); mod_config()->padding = strtoul(optarg, nullptr, 10);
} else if(util::strieq(opt, SHRPX_OPT_ALTSVC_PORT)) { } else if(util::strieq(opt, SHRPX_OPT_ALTSVC)) {
errno = 0; size_t len;
auto port = strtoul(optarg, nullptr, 10); auto tokens = parse_config_str_list(&len, optarg);
if(errno == 0 && if(len < 2) {
1 <= port && port <= std::numeric_limits<uint16_t>::max()) { // Requires at least protocol_id and port
LOG(ERROR) << "altsvc: too few parameters: " << optarg;
mod_config()->altsvc_port = port;
} else {
LOG(ERROR) << "altsvc-port is invalid: " << optarg;
return -1; return -1;
} }
} else if(util::strieq(opt, SHRPX_OPT_ALTSVC_PROTOCOL_ID)) {
set_config_str(&mod_config()->altsvc_protocol_id, optarg);
mod_config()->altsvc_protocol_id_len = if(len > 4) {
strlen(get_config()->altsvc_protocol_id); // We only need protocol_id, port, host and origin
} else if(util::strieq(opt, SHRPX_OPT_ALTSVC_HOST)) { LOG(ERROR) << "altsvc: too many parameters: " << optarg;
set_config_str(&mod_config()->altsvc_host, optarg); return -1;
}
mod_config()->altsvc_host_len = strlen(get_config()->altsvc_host); errno = 0;
} else if(util::strieq(opt, SHRPX_OPT_ALTSVC_ORIGIN)) { auto port = strtoul(tokens[1], nullptr, 10);
set_config_str(&mod_config()->altsvc_origin, optarg);
if(errno != 0 || port < 1 || port > std::numeric_limits<uint16_t>::max()) {
LOG(ERROR) << "altsvc: port is invalid: " << tokens[1];
return -1;
}
AltSvc altsvc;
altsvc.port = port;
altsvc.protocol_id = tokens[0];
altsvc.protocol_id_len = strlen(altsvc.protocol_id);
if(len > 2) {
altsvc.host = tokens[2];
altsvc.host_len = strlen(altsvc.host);
if(len > 3) {
altsvc.origin = tokens[3];
altsvc.origin_len = strlen(altsvc.origin);
}
}
mod_config()->altsvcs.push_back(std::move(altsvc));
mod_config()->altsvc_origin_len = strlen(get_config()->altsvc_origin);
} else if(util::strieq(opt, "conf")) { } else if(util::strieq(opt, "conf")) {
LOG(WARNING) << "conf is ignored"; LOG(WARNING) << "conf is ignored";
} else { } else {

View File

@ -110,10 +110,7 @@ extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[];
extern const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[]; extern const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[];
extern const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[]; extern const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[];
extern const char SHRPX_OPT_PADDING[]; extern const char SHRPX_OPT_PADDING[];
extern const char SHRPX_OPT_ALTSVC_PORT[]; extern const char SHRPX_OPT_ALTSVC[];
extern const char SHRPX_OPT_ALTSVC_PROTOCOL_ID[];
extern const char SHRPX_OPT_ALTSVC_HOST[];
extern const char SHRPX_OPT_ALTSVC_ORIGIN[];
union sockaddr_union { union sockaddr_union {
sockaddr sa; sockaddr sa;
@ -127,9 +124,32 @@ enum shrpx_proto {
PROTO_HTTP PROTO_HTTP
}; };
struct AltSvc {
AltSvc()
: protocol_id(nullptr),
host(nullptr),
origin(nullptr),
protocol_id_len(0),
host_len(0),
origin_len(0),
port(0)
{}
char *protocol_id;
char *host;
char *origin;
size_t protocol_id_len;
size_t host_len;
size_t origin_len;
uint16_t port;
};
struct Config { struct Config {
// The list of (private key file, certificate file) pair // The list of (private key file, certificate file) pair
std::vector<std::pair<std::string, std::string>> subcerts; std::vector<std::pair<std::string, std::string>> subcerts;
std::vector<AltSvc> altsvcs;
sockaddr_union downstream_addr; sockaddr_union downstream_addr;
// binary form of http proxy host and port // binary form of http proxy host and port
sockaddr_union downstream_http_proxy_addr; sockaddr_union downstream_http_proxy_addr;
@ -176,9 +196,6 @@ struct Config {
char *client_cert_file; char *client_cert_file;
FILE *http2_upstream_dump_request_header; FILE *http2_upstream_dump_request_header;
FILE *http2_upstream_dump_response_header; FILE *http2_upstream_dump_response_header;
char *altsvc_protocol_id;
char *altsvc_host;
char *altsvc_origin;
nghttp2_option *http2_option; nghttp2_option *http2_option;
size_t downstream_addrlen; size_t downstream_addrlen;
size_t num_worker; size_t num_worker;
@ -202,9 +219,6 @@ struct Config {
// The number of elements in tls_proto_list // The number of elements in tls_proto_list
size_t tls_proto_list_len; size_t tls_proto_list_len;
size_t padding; size_t padding;
size_t altsvc_protocol_id_len;
size_t altsvc_host_len;
size_t altsvc_origin_len;
// downstream protocol; this will be determined by given options. // downstream protocol; this will be determined by given options.
shrpx_proto downstream_proto; shrpx_proto downstream_proto;
int syslog_facility; int syslog_facility;
@ -215,7 +229,6 @@ struct Config {
uint16_t downstream_port; uint16_t downstream_port;
// port in http proxy URI // port in http proxy URI
uint16_t downstream_http_proxy_port; uint16_t downstream_http_proxy_port;
uint16_t altsvc_port;
bool verbose; bool verbose;
bool daemon; bool daemon;
bool verify_client; bool verify_client;

View File

@ -547,25 +547,27 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
} }
} }
if(get_config()->altsvc_port != 0 && get_config()->altsvc_protocol_id) { if(!get_config()->altsvcs.empty()) {
// Set max_age to 24hrs, which is default for alt-svc header // Set max_age to 24hrs, which is default for alt-svc header
// field. // field.
for(auto& altsvc : get_config()->altsvcs) {
rv = nghttp2_submit_altsvc rv = nghttp2_submit_altsvc
(session_, NGHTTP2_FLAG_NONE, 0, (session_, NGHTTP2_FLAG_NONE, 0,
86400, 86400,
get_config()->altsvc_port, altsvc.port,
reinterpret_cast<const uint8_t*>(get_config()->altsvc_protocol_id), reinterpret_cast<const uint8_t*>(altsvc.protocol_id),
get_config()->altsvc_protocol_id_len, altsvc.protocol_id_len,
reinterpret_cast<const uint8_t*>(get_config()->altsvc_host), reinterpret_cast<const uint8_t*>(altsvc.host),
get_config()->altsvc_host_len, altsvc.host_len,
reinterpret_cast<const uint8_t*>(get_config()->altsvc_origin), reinterpret_cast<const uint8_t*>(altsvc.origin),
get_config()->altsvc_origin_len); altsvc.origin_len);
if(rv != 0) { if(rv != 0) {
ULOG(ERROR, this) << "nghttp2_submit_altsvc() returned error: " ULOG(ERROR, this) << "nghttp2_submit_altsvc() returned error: "
<< nghttp2_strerror(rv); << nghttp2_strerror(rv);
} }
} }
}
} }
Http2Upstream::~Http2Upstream() Http2Upstream::~Http2Upstream()

View File

@ -681,12 +681,18 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream)
if(downstream->get_norm_response_header("alt-svc") == end_headers) { if(downstream->get_norm_response_header("alt-svc") == end_headers) {
// We won't change or alter alt-svc from backend at the moment. // We won't change or alter alt-svc from backend at the moment.
if(get_config()->altsvc_port != 0 && get_config()->altsvc_protocol_id) { if(!get_config()->altsvcs.empty()) {
hdrs += "Alt-Svc: "; hdrs += "Alt-Svc: ";
hdrs += util::percent_encode_token(get_config()->altsvc_protocol_id);
for(auto& altsvc : get_config()->altsvcs) {
hdrs += util::percent_encode_token(altsvc.protocol_id);
hdrs += "="; hdrs += "=";
hdrs += util::utos(get_config()->altsvc_port); hdrs += util::utos(altsvc.port);
hdrs += "\r\n"; hdrs += ", ";
}
hdrs[hdrs.size() - 2] = '\r';
hdrs[hdrs.size() - 1] = '\n';
} }
} }