nghttpx: Add options to dump HTTP headers in HTTP/2.0 upstream

This commit is contained in:
Tatsuhiro Tsujikawa 2013-11-17 23:52:19 +09:00
parent c22cb53b5e
commit faedc4381d
6 changed files with 109 additions and 0 deletions

View File

@ -374,6 +374,31 @@ int32_t determine_window_update_transmission(nghttp2_session *session,
return -1; return -1;
} }
void dump_nv(FILE *out, const char **nv)
{
for(size_t i = 0; nv[i]; i += 2) {
fwrite(nv[i], strlen(nv[i]), 1, out);
fwrite(": ", 2, 1, out);
fwrite(nv[i+1], strlen(nv[i+1]), 1, out);
fwrite("\n", 1, 1, out);
}
fwrite("\n", 1, 1, out);
fflush(out);
}
void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen)
{
for(size_t i = 0; i < nvlen; ++i) {
auto nv = &nva[i];
fwrite(nv->name, nv->namelen, 1, out);
fwrite(": ", 2, 1, out);
fwrite(nv->value, nv->valuelen, 1, out);
fwrite("\n", 1, 1, out);
}
fwrite("\n", 1, 1, out);
fflush(out);
}
} // namespace http2 } // namespace http2
} // namespace nghttp2 } // namespace nghttp2

View File

@ -27,6 +27,7 @@
#include "nghttp2_config.h" #include "nghttp2_config.h"
#include <cstdio>
#include <string> #include <string>
#include <vector> #include <vector>
@ -120,6 +121,13 @@ void build_http1_headers_from_norm_headers
int32_t determine_window_update_transmission(nghttp2_session *session, int32_t determine_window_update_transmission(nghttp2_session *session,
int32_t stream_id); int32_t stream_id);
// Dumps name/value pairs in |nv| to |out|. The |nv| must be
// terminated by nullptr.
void dump_nv(FILE *out, const char **nv);
// Dumps name/value pairs in |nva| to |out|.
void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen);
} // namespace http2 } // namespace http2
} // namespace nghttp2 } // namespace nghttp2

View File

@ -420,6 +420,8 @@ void fill_default_config()
mod_config()->verify_client_cacert = nullptr; mod_config()->verify_client_cacert = nullptr;
mod_config()->client_private_key_file = nullptr; mod_config()->client_private_key_file = nullptr;
mod_config()->client_cert_file = nullptr; mod_config()->client_cert_file = nullptr;
mod_config()->http2_upstream_dump_request_header = nullptr;
mod_config()->http2_upstream_dump_response_header = nullptr;
} }
} // namespace } // namespace
@ -675,6 +677,22 @@ void print_help(std::ostream& out)
<< " --no-via Don't append to Via header field. If Via\n" << " --no-via Don't append to Via header field. If Via\n"
<< " header field is received, it is left\n" << " header field is received, it is left\n"
<< " unaltered.\n" << " unaltered.\n"
<< " --frontend-http2-dump-request-header=<PATH>\n"
<< " Dumps request headers received by HTTP/2.0\n"
<< " frontend to the file denoted in PATH.\n"
<< " The output is done in HTTP/1 header field\n"
<< " format and each header block is followed by\n"
<< " an empty line.\n"
<< " This option is not thread safe and MUST NOT\n"
<< " be used with option -n=N, where N >= 2.\n"
<< " --frontend-http2-dump-response-header=<PATH>\n"
<< " Dumps response headers sent from HTTP/2.0\n"
<< " frontend to the file denoted in PATH.\n"
<< " The output is done in HTTP/1 header field\n"
<< " format and each header block is followed by\n"
<< " an empty line.\n"
<< " This option is not thread safe and MUST NOT\n"
<< " be used with option -n=N, where N >= 2.\n"
<< " -D, --daemon Run in a background. If -D is used, the\n" << " -D, --daemon Run in a background. If -D is used, the\n"
<< " current working directory is changed to '/'.\n" << " current working directory is changed to '/'.\n"
<< " --pid-file=<PATH> Set path to save PID of this program.\n" << " --pid-file=<PATH> Set path to save PID of this program.\n"
@ -750,6 +768,8 @@ int main(int argc, char **argv)
{"verify-client-cacert", required_argument, &flag, 40}, {"verify-client-cacert", required_argument, &flag, 40},
{"client-private-key-file", required_argument, &flag, 41}, {"client-private-key-file", required_argument, &flag, 41},
{"client-cert-file", required_argument, &flag, 42}, {"client-cert-file", required_argument, &flag, 42},
{"frontend-http2-dump-request-header", required_argument, &flag, 43},
{"frontend-http2-dump-response-header", required_argument, &flag, 44},
{nullptr, 0, nullptr, 0 } {nullptr, 0, nullptr, 0 }
}; };
@ -972,6 +992,18 @@ int main(int argc, char **argv)
// --client-cert-file // --client-cert-file
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT_CERT_FILE, optarg)); cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT_CERT_FILE, optarg));
break; break;
case 43:
// --frontend-http2-dump-request-header
cmdcfgs.push_back(std::make_pair
(SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
optarg));
break;
case 44:
// --frontend-http2-dump-response-header
cmdcfgs.push_back(std::make_pair
(SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
optarg));
break;
default: default:
break; break;
} }

View File

@ -105,6 +105,10 @@ const char SHRPX_OPT_VERIFY_CLIENT[] = "verify-client";
const char SHRPX_OPT_VERIFY_CLIENT_CACERT[] = "verify-client-cacert"; const char SHRPX_OPT_VERIFY_CLIENT_CACERT[] = "verify-client-cacert";
const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[] = "client-private-key-file"; const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[] = "client-private-key-file";
const char SHRPX_OPT_CLIENT_CERT_FILE[] = "client-cert-file"; const char SHRPX_OPT_CLIENT_CERT_FILE[] = "client-cert-file";
const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[] =
"frontend-http2-dump-request-header";
const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[] =
"frontend-http2-dump-response-header";
namespace { namespace {
Config *config = nullptr; Config *config = nullptr;
@ -172,6 +176,18 @@ bool is_secure(const char *filename)
} }
} // namespace } // namespace
namespace {
FILE* open_file_for_write(const char *filename)
{
auto f = fopen(filename, "wb");
if(f == NULL) {
LOG(ERROR) << "Failed to open " << filename << " for writing. Cause: "
<< strerror(errno);
}
return f;
}
} // namespace
std::string read_passwd_from_file(const char *filename) std::string read_passwd_from_file(const char *filename)
{ {
std::string line; std::string line;
@ -419,6 +435,18 @@ int parse_config(const char *opt, const char *optarg)
set_config_str(&mod_config()->client_private_key_file, optarg); set_config_str(&mod_config()->client_private_key_file, optarg);
} else if(util::strieq(opt, SHRPX_OPT_CLIENT_CERT_FILE)) { } else if(util::strieq(opt, SHRPX_OPT_CLIENT_CERT_FILE)) {
set_config_str(&mod_config()->client_cert_file, optarg); set_config_str(&mod_config()->client_cert_file, optarg);
} else if(util::strieq(opt, SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER)) {
auto f = open_file_for_write(optarg);
if(f == NULL) {
return -1;
}
mod_config()->http2_upstream_dump_request_header = f;
} else if(util::strieq(opt, SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER)) {
auto f = open_file_for_write(optarg);
if(f == NULL) {
return -1;
}
mod_config()->http2_upstream_dump_response_header = f;
} 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

@ -32,6 +32,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <cstdio>
#include <vector> #include <vector>
#include <event.h> #include <event.h>
@ -95,6 +96,8 @@ extern const char SHRPX_OPT_VERIFY_CLIENT[];
extern const char SHRPX_OPT_VERIFY_CLIENT_CACERT[]; extern const char SHRPX_OPT_VERIFY_CLIENT_CACERT[];
extern const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[]; extern const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[];
extern const char SHRPX_OPT_CLIENT_CERT_FILE[]; extern const char SHRPX_OPT_CLIENT_CERT_FILE[];
extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[];
extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[];
union sockaddr_union { union sockaddr_union {
sockaddr sa; sockaddr sa;
@ -195,6 +198,8 @@ struct Config {
char *verify_client_cacert; char *verify_client_cacert;
char *client_private_key_file; char *client_private_key_file;
char *client_cert_file; char *client_cert_file;
FILE *http2_upstream_dump_request_header;
FILE *http2_upstream_dump_response_header;
}; };
const Config* get_config(); const Config* get_config();

View File

@ -254,6 +254,11 @@ int on_frame_recv_callback
<< "\n" << ss.str(); << "\n" << ss.str();
} }
if(get_config()->http2_upstream_dump_request_header) {
http2::dump_nv(get_config()->http2_upstream_dump_request_header,
frame->headers.nva, frame->headers.nvlen);
}
if(!http2::check_http2_headers(nva)) { if(!http2::check_http2_headers(nva)) {
upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR); upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
return 0; return 0;
@ -968,6 +973,12 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream)
<< downstream->get_stream_id() << "\n" << downstream->get_stream_id() << "\n"
<< ss.str(); << ss.str();
} }
if(get_config()->http2_upstream_dump_response_header) {
http2::dump_nv(get_config()->http2_upstream_dump_response_header,
nv.data());
}
nghttp2_data_provider data_prd; nghttp2_data_provider data_prd;
data_prd.source.ptr = downstream; data_prd.source.ptr = downstream;
data_prd.read_callback = downstream_data_read_callback; data_prd.read_callback = downstream_data_read_callback;