Merge branch 'kennypeng-header_add_override'
This commit is contained in:
commit
4bc5e55113
125
src/h2load.cc
125
src/h2load.cc
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue