Merge branch 'kennypeng-header_add_override'

This commit is contained in:
Tatsuhiro Tsujikawa 2014-10-22 21:30:31 +09:00
commit 4bc5e55113
2 changed files with 114 additions and 13 deletions

View File

@ -33,6 +33,7 @@
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <fstream>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <future> #include <future>
@ -605,7 +606,8 @@ void print_version(std::ostream& out)
namespace { namespace {
void print_usage(std::ostream& out) void print_usage(std::ostream& out)
{ {
out << R"(Usage: h2load [OPTIONS]... <URI>... out << R"(
Usage: h2load [OPTIONS]... [URI]...
benchmarking tool for HTTP/2 and SPDY server)" << std::endl; benchmarking tool for HTTP/2 and SPDY server)" << std::endl;
} }
} // namespace } // namespace
@ -630,6 +632,15 @@ Options:
<< config.nclients << R"( << config.nclients << R"(
-t, --threads=<N> Number of native threads. Default: )" -t, --threads=<N> Number of native threads. Default: )"
<< config.nthreads << R"( << config.nthreads << R"(
-i, --input-file=<FILE>
Path of a file with multiple URIs are seperated
by EOLs. This option will disable URIs getting
from stdin. URIs are used in this order for each
client. All URIs are used, then first URI is
used and then 2nd URI, and so on. The scheme,
host and port in the subsequent URIs, if present,
are ignored. Those in the first URI are used
solely.
-m, --max-concurrent-streams=(auto|<N>) -m, --max-concurrent-streams=(auto|<N>)
Max concurrent streams to issue per session. If Max concurrent streams to issue per session. If
"auto" is given, the number of given URIs is "auto" is given, the number of given URIs is
@ -642,6 +653,8 @@ Options:
(2**<N>)-1. For SPDY, if <N> is strictly less (2**<N>)-1. For SPDY, if <N> is strictly less
than 16, this option is ignored. Otherwise than 16, this option is ignored. Otherwise
2**<N> is used for SPDY. 2**<N> is used for SPDY.
-H, --header=<HEADER>
Add/Override a header to the requests.
-p, --no-tls-proto=<PROTOID> -p, --no-tls-proto=<PROTOID>
Specify ALPN identifier of the protocol to be Specify ALPN identifier of the protocol to be
used when accessing http URI without SSL/TLS.)"; used when accessing http URI without SSL/TLS.)";
@ -674,6 +687,8 @@ int main(int argc, char **argv)
{"max-concurrent-streams", required_argument, nullptr, 'm'}, {"max-concurrent-streams", required_argument, nullptr, 'm'},
{"window-bits", required_argument, nullptr, 'w'}, {"window-bits", required_argument, nullptr, 'w'},
{"connection-window-bits", required_argument, nullptr, 'W'}, {"connection-window-bits", required_argument, nullptr, 'W'},
{"input-file", required_argument, nullptr, 'i'},
{"header", required_argument, nullptr, 'H'},
{"no-tls-proto", required_argument, nullptr, 'p'}, {"no-tls-proto", required_argument, nullptr, 'p'},
{"verbose", no_argument, nullptr, 'v'}, {"verbose", no_argument, nullptr, 'v'},
{"help", no_argument, nullptr, 'h'}, {"help", no_argument, nullptr, 'h'},
@ -681,7 +696,7 @@ int main(int argc, char **argv)
{nullptr, 0, nullptr, 0 } {nullptr, 0, nullptr, 0 }
}; };
int option_index = 0; int option_index = 0;
auto c = getopt_long(argc, argv, "hvW:c:m:n:p:t:w:", long_options, auto c = getopt_long(argc, argv, "hvW:c:m:n:p:t:w:H:i:", long_options,
&option_index); &option_index);
if(c == -1) { if(c == -1) {
break; break;
@ -727,6 +742,35 @@ int main(int argc, char **argv)
} }
break; break;
} }
case 'H': {
char *header = optarg;
// Skip first possible ':' in the header name
char *value = strchr( optarg + 1, ':' );
if ( ! value || (header[0] == ':' && header + 1 == value)) {
std::cerr << "-H: invalid header: " << optarg
<< std::endl;
exit(EXIT_FAILURE);
}
*value = 0;
value++;
while( isspace( *value ) ) { value++; }
if ( *value == 0 ) {
// This could also be a valid case for suppressing a header
// similar to curl
std::cerr << "-H: invalid header - value missing: " << optarg
<< std::endl;
exit(EXIT_FAILURE);
}
// Note that there is no processing currently to handle multiple
// message-header fields with the same field name
config.custom_headers.emplace_back(header, value);
util::inp_strlower(config.custom_headers.back().first);
break;
}
case 'i': {
config.ifile = std::string(optarg);
break;
}
case 'p': case 'p':
if(util::strieq(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, optarg)) { if(util::strieq(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, optarg)) {
config.no_tls_proto = Config::PROTO_HTTP2; config.no_tls_proto = Config::PROTO_HTTP2;
@ -766,8 +810,10 @@ int main(int argc, char **argv)
} }
if(argc == optind) { if(argc == optind) {
std::cerr << "no URI given" << std::endl; if(config.ifile.empty()){
exit(EXIT_FAILURE); std::cerr << "no URI or input file given" << std::endl;
exit(EXIT_FAILURE);
}
} }
if(config.nreqs == 0) { if(config.nreqs == 0) {
@ -828,7 +874,25 @@ int main(int argc, char **argv)
// this URI and ignore those in the remaining URIs if present. // this URI and ignore those in the remaining URIs if present.
http_parser_url u; http_parser_url u;
memset(&u, 0, sizeof(u)); memset(&u, 0, sizeof(u));
auto uri = argv[optind]; auto uri = "";
std::ifstream uri_file;
std::string line_uri;
if (config.ifile.empty()) {
uri = argv[optind];
} else {
if (std::ifstream(config.ifile)) {
uri_file.open(config.ifile, std::ifstream::in);
// get first line as first uri
std::getline (uri_file, line_uri);
uri = (char *)line_uri.c_str();
} else {
std::cerr << "cannot read input file: " << config.ifile << std::endl;
exit(EXIT_FAILURE);
}
}
if(http_parser_parse_url(uri, strlen(uri), 0, &u) != 0 || if(http_parser_parse_url(uri, strlen(uri), 0, &u) != 0 ||
!util::has_uri_field(u, UF_SCHEMA) || !util::has_uri_field(u, UF_HOST)) { !util::has_uri_field(u, UF_SCHEMA) || !util::has_uri_field(u, UF_HOST)) {
std::cerr << "invalid URI: " << uri << std::endl; std::cerr << "invalid URI: " << uri << std::endl;
@ -847,18 +911,35 @@ int main(int argc, char **argv)
reqlines.push_back(get_reqline(uri, u)); reqlines.push_back(get_reqline(uri, u));
++optind; if (config.ifile.empty()) {
for(int i = optind; i < argc; ++i) { ++optind;
memset(&u, 0, sizeof(u)); for(int i = optind; i < argc; ++i) {
memset(&u, 0, sizeof(u));
auto uri = argv[i]; auto uri = argv[i];
if(http_parser_parse_url(uri, strlen(uri), 0, &u) != 0) { if(http_parser_parse_url(uri, strlen(uri), 0, &u) != 0) {
std::cerr << "invalid URI: " << uri << std::endl; std::cerr << "invalid URI: " << uri << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
reqlines.push_back(get_reqline(uri, u));
} }
} else {
if(uri_file.is_open()) {
//load rest uris from file
while(std::getline (uri_file, line_uri)) {
auto uri = (char *)line_uri.c_str();
reqlines.push_back(get_reqline(uri, u)); if(http_parser_parse_url(uri, strlen(uri), 0, &u) != 0) {
std::cerr << "invalid URI in input file: " << uri << std::endl;
exit(EXIT_FAILURE);
}
reqlines.push_back(get_reqline(uri, u));
}
uri_file.close();
}
} }
if(config.max_concurrent_streams == -1) { if(config.max_concurrent_streams == -1) {
@ -875,6 +956,24 @@ int main(int argc, char **argv)
} }
shared_nva.emplace_back(":method", "GET"); shared_nva.emplace_back(":method", "GET");
//list overridalbe headers
std::vector<std::string> override_hdrs = {":host", ":scheme", ":method"};
for(auto& kv : config.custom_headers) {
if(std::find(override_hdrs.begin(), override_hdrs.end(), kv.first) != override_hdrs.end()) {
// override header
for(auto& nv : shared_nva) {
if( (nv.name == ":authority" && kv.first == ":host")
|| (nv.name == kv.first) ) {
nv.value = kv.second;
}
}
} else {
// add additional headers
shared_nva.emplace_back(kv.first.c_str(), kv.second.c_str());
}
}
for(auto& req : reqlines) { for(auto& req : reqlines) {
// For nghttp2 // For nghttp2
std::vector<nghttp2_nv> nva; std::vector<nghttp2_nv> nva;

View File

@ -50,8 +50,10 @@ class Session;
struct Config { struct Config {
std::vector<std::vector<nghttp2_nv>> nva; std::vector<std::vector<nghttp2_nv>> nva;
std::vector<std::vector<const char*>> nv; std::vector<std::vector<const char*>> nv;
std::vector<std::pair<std::string, std::string>> custom_headers;
std::string scheme; std::string scheme;
std::string host; std::string host;
std::string ifile;
addrinfo *addrs; addrinfo *addrs;
size_t nreqs; size_t nreqs;
size_t nclients; size_t nclients;