diff --git a/examples/spdycat.cc b/examples/spdycat.cc index 8fb3b491..3690be8c 100644 --- a/examples/spdycat.cc +++ b/examples/spdycat.cc @@ -72,6 +72,7 @@ struct Config { std::string certfile; std::string keyfile; int window_bits; + std::map headers; Config():null_out(false), remote_name(false), verbose(false), get_assets(false), stat(false), spdy_version(-1), timeout(-1), window_bits(-1) @@ -223,11 +224,11 @@ struct SpdySession { Config config; extern bool ssl_debug; -void submit_request(Spdylay& sc, const std::string& hostport, Request* req) +void submit_request(Spdylay& sc, const std::string& hostport, const std::map &headers, Request* req) { uri::UriStruct& us = req->us; std::string path = us.dir+us.file+us.query; - int r = sc.submit_request(hostport, path, 3, req); + int r = sc.submit_request(hostport, path, headers, 3, req); assert(r == 0); } @@ -246,7 +247,7 @@ void update_html_parser(SpdySession *spdySession, Request *req, req->us.protocol == us.protocol && req->us.host == us.host && req->us.port == us.port) { spdySession->add_request(us, req->level+1); - submit_request(*spdySession->sc, spdySession->hostport, + submit_request(*spdySession->sc, spdySession->hostport, config.headers, spdySession->reqvec.back()); } } @@ -511,7 +512,7 @@ int communicate(const std::string& host, uint16_t port, assert(rv == 0); } for(int i = 0, n = spdySession.reqvec.size(); i < n; ++i) { - submit_request(sc, spdySession.hostport, spdySession.reqvec[i]); + submit_request(sc, spdySession.hostport, config.headers, spdySession.reqvec[i]); } pollfds[0].fd = fd; ctl_poll(pollfds, &sc); @@ -645,6 +646,7 @@ void print_help(std::ostream& out) << " same with the linking resource will be\n" << " downloaded.\n" << " -s, --stat Print statistics.\n" + << " -H, --header Add a header to the requests.\n" << " --cert= Use the specified client certificate file.\n" << " The file must be in PEM format.\n" << " --key= Use the client private key file. The file\n" @@ -669,10 +671,11 @@ int main(int argc, char **argv) {"cert", required_argument, &flag, 1 }, {"key", required_argument, &flag, 2 }, {"help", no_argument, 0, 'h' }, + {"header", required_argument, 0, 'H' }, {0, 0, 0, 0 } }; int option_index = 0; - int c = getopt_long(argc, argv, "Oanhv23st:w:", long_options, + int c = getopt_long(argc, argv, "OanhH:v23st:w:", long_options, &option_index); if(c == -1) { break; @@ -711,6 +714,27 @@ int main(int argc, char **argv) } break; } + case 'H': { + char *header = optarg; + char *value = strchr( optarg, ':' ); + if ( ! 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.headers.insert( std::pair( header, value ) ); + } case 'a': #ifdef HAVE_LIBXML2 config.get_assets = true; diff --git a/examples/spdylay_ssl.cc b/examples/spdylay_ssl.cc index 6faacf9c..1270f900 100644 --- a/examples/spdylay_ssl.cc +++ b/examples/spdylay_ssl.cc @@ -122,20 +122,71 @@ void* Spdylay::user_data() } int Spdylay::submit_request(const std::string& hostport, - const std::string& path, uint8_t pri, + const std::string& path, + const std::map &headers, + uint8_t pri, void *stream_user_data) { - const char *nv[] = { + enum eStaticHeaderPosition + { + POS_METHOD = 0, + POS_PATH, + POS_VERSION, + POS_SCHEME, + POS_HOST, + POS_ACCEPT, + POS_USERAGENT + }; + + const char *static_nv[] = { ":method", "GET", ":path", path.c_str(), ":version", "HTTP/1.1", ":scheme", "https", ":host", hostport.c_str(), "accept", "*/*", - "user-agent", "spdylay/" SPDYLAY_VERSION, - NULL + "user-agent", "spdylay/" SPDYLAY_VERSION }; - return spdylay_submit_request(session_, pri, nv, NULL, stream_user_data); + + int hardcoded_entry_count = sizeof(static_nv) / sizeof(*static_nv); + int header_count = headers.size(); + int total_entry_count = hardcoded_entry_count + header_count * 2; + + const char **nv = new const char*[total_entry_count + 1]; + + memcpy(nv, static_nv, hardcoded_entry_count * sizeof(*static_nv)); + + std::map::const_iterator i = headers.begin(); + std::map::const_iterator end = headers.end(); + + int pos = hardcoded_entry_count; + + while( i != end ) { + const char *key = (*i).first.c_str(); + const char *value = (*i).second.c_str(); + if ( strcasecmp( key, "accept" ) == 0 ) { + nv[POS_ACCEPT*2+1] = value; + } + else if ( strcasecmp( key, "user-agent" ) == 0 ) { + nv[POS_USERAGENT*2+1] = value; + } + else if ( strcasecmp( key, "host" ) == 0 ) { + nv[POS_HOST*2+1] = value; + } + else { + nv[pos] = key; + nv[pos+1] = value; + pos += 2; + } + ++i; + } + nv[pos] = NULL; + + int r = spdylay_submit_request(session_, pri, nv, NULL, stream_user_data); + + delete [] nv; + + return r; } int Spdylay::submit_settings(int flags, spdylay_settings_entry *iv, size_t niv) diff --git a/examples/spdylay_ssl.h b/examples/spdylay_ssl.h index 18add5ab..7be81b1f 100644 --- a/examples/spdylay_ssl.h +++ b/examples/spdylay_ssl.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -54,7 +55,7 @@ public: bool want_write(); bool finish(); int fd() const; - int submit_request(const std::string& hostport, const std::string& path, + int submit_request(const std::string& hostport, const std::string& path, const std::map& headers, uint8_t pri, void *stream_user_data); int submit_settings(int flags, spdylay_settings_entry *iv, size_t niv); bool would_block(int r);