nghttpx: Add options to dump HTTP headers in HTTP/2.0 upstream
This commit is contained in:
parent
c22cb53b5e
commit
faedc4381d
25
src/http2.cc
25
src/http2.cc
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
32
src/shrpx.cc
32
src/shrpx.cc
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue