nghttpd: Add --trailer to send trailer header fields
This commit is contained in:
parent
4c55a2340b
commit
80a7523b49
|
@ -809,6 +809,7 @@ void Http2Handler::terminate_session(uint32_t error_code) {
|
||||||
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||||
nghttp2_data_source *source, void *user_data) {
|
nghttp2_data_source *source, void *user_data) {
|
||||||
|
int rv;
|
||||||
auto hd = static_cast<Http2Handler *>(user_data);
|
auto hd = static_cast<Http2Handler *>(user_data);
|
||||||
auto stream = hd->get_stream(stream_id);
|
auto stream = hd->get_stream(stream_id);
|
||||||
|
|
||||||
|
@ -829,6 +830,20 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
if (nread == 0 || stream->body_left <= 0) {
|
if (nread == 0 || stream->body_left <= 0) {
|
||||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||||
|
|
||||||
|
auto config = hd->get_config();
|
||||||
|
if (!config->trailer.empty()) {
|
||||||
|
*data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
|
||||||
|
std::vector<nghttp2_nv> nva;
|
||||||
|
nva.reserve(config->trailer.size());
|
||||||
|
for (auto &kv : config->trailer) {
|
||||||
|
nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
|
||||||
|
}
|
||||||
|
rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
|
||||||
|
if (rv != 0) {
|
||||||
|
*data_flags &= ~NGHTTP2_DATA_FLAG_NO_END_STREAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nghttp2_session_get_stream_remote_close(session, stream_id) == 0) {
|
if (nghttp2_session_get_stream_remote_close(session, stream_id) == 0) {
|
||||||
remove_stream_read_timeout(stream);
|
remove_stream_read_timeout(stream);
|
||||||
remove_stream_write_timeout(stream);
|
remove_stream_write_timeout(stream);
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace nghttp2 {
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
std::map<std::string, std::vector<std::string>> push;
|
std::map<std::string, std::vector<std::string>> push;
|
||||||
|
Headers trailer;
|
||||||
std::string htdocs;
|
std::string htdocs;
|
||||||
std::string host;
|
std::string host;
|
||||||
std::string private_key_file;
|
std::string private_key_file;
|
||||||
|
|
|
@ -140,6 +140,11 @@ Options:
|
||||||
--early-response
|
--early-response
|
||||||
Start sending response when request HEADERS is received,
|
Start sending response when request HEADERS is received,
|
||||||
rather than complete request is received.
|
rather than complete request is received.
|
||||||
|
--trailer=<HEADER>
|
||||||
|
Add a trailer header to a response. <HEADER> must not
|
||||||
|
include pseudo header field (header field name starting
|
||||||
|
with ':'). The trailer is sent only if a response has
|
||||||
|
body part. Example: --trailer 'foo: bar'.
|
||||||
--version Display version information and exit.
|
--version Display version information and exit.
|
||||||
-h, --help Display this help and exit.
|
-h, --help Display this help and exit.
|
||||||
|
|
||||||
|
@ -170,6 +175,7 @@ int main(int argc, char **argv) {
|
||||||
{"version", no_argument, &flag, 3},
|
{"version", no_argument, &flag, 3},
|
||||||
{"dh-param-file", required_argument, &flag, 4},
|
{"dh-param-file", required_argument, &flag, 4},
|
||||||
{"early-response", no_argument, &flag, 5},
|
{"early-response", no_argument, &flag, 5},
|
||||||
|
{"trailer", required_argument, &flag, 6},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:va:", long_options,
|
int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:va:", long_options,
|
||||||
|
@ -254,6 +260,30 @@ int main(int argc, char **argv) {
|
||||||
// early-response
|
// early-response
|
||||||
config.early_response = true;
|
config.early_response = true;
|
||||||
break;
|
break;
|
||||||
|
case 6: {
|
||||||
|
// trailer option
|
||||||
|
auto header = optarg;
|
||||||
|
auto value = strchr(optarg, ':');
|
||||||
|
if (!value) {
|
||||||
|
std::cerr << "--trailer: 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 << "--trailer: invalid header - value missing: " << optarg
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
config.trailer.emplace_back(header, value, false);
|
||||||
|
util::inp_strlower(config.trailer.back().name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue