diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 807b8067..247b2368 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -515,8 +515,16 @@ std::vector parse_log_format(const char *optarg) { if (type == SHRPX_LOGF_NONE) { if (util::istartsWith(var_name, var_namelen, "http_")) { - type = SHRPX_LOGF_HTTP; - value = var_name + str_size("http_"); + if (util::streq("host", var_name + str_size("http_"), + var_namelen - str_size("http_"))) { + // Special handling of host header field. We will use + // :authority header field if host header is missing. This + // is a typical case in HTTP/2. + type = SHRPX_LOGF_AUTHORITY; + } else { + type = SHRPX_LOGF_HTTP; + value = var_name + str_size("http_"); + } } else { LOG(WARN) << "Unrecognized log format variable: " << std::string(var_name, var_namelen); diff --git a/src/shrpx_config_test.cc b/src/shrpx_config_test.cc index 6af69645..5138dba4 100644 --- a/src/shrpx_config_test.cc +++ b/src/shrpx_config_test.cc @@ -62,10 +62,11 @@ void test_shrpx_config_parse_header(void) { } void test_shrpx_config_parse_log_format(void) { - auto res = parse_log_format(R"($remote_addr - $remote_user [$time_local] )" - R"("$request" $status $body_bytes_sent )" - R"("${http_referer}" "$http_user_agent")"); - CU_ASSERT(14 == res.size()); + auto res = + parse_log_format(R"($remote_addr - $remote_user [$time_local] )" + R"("$request" $status $body_bytes_sent )" + R"("${http_referer}" $http_host "$http_user_agent")"); + CU_ASSERT(16 == res.size()); CU_ASSERT(SHRPX_LOGF_REMOTE_ADDR == res[0].type); @@ -96,13 +97,18 @@ void test_shrpx_config_parse_log_format(void) { CU_ASSERT(0 == strcmp("referer", res[10].value.get())); CU_ASSERT(SHRPX_LOGF_LITERAL == res[11].type); - CU_ASSERT(0 == strcmp("\" \"", res[11].value.get())); + CU_ASSERT(0 == strcmp("\" ", res[11].value.get())); - CU_ASSERT(SHRPX_LOGF_HTTP == res[12].type); - CU_ASSERT(0 == strcmp("user-agent", res[12].value.get())); + CU_ASSERT(SHRPX_LOGF_AUTHORITY == res[12].type); CU_ASSERT(SHRPX_LOGF_LITERAL == res[13].type); - CU_ASSERT(0 == strcmp("\"", res[13].value.get())); + CU_ASSERT(0 == strcmp(" \"", res[13].value.get())); + + CU_ASSERT(SHRPX_LOGF_HTTP == res[14].type); + CU_ASSERT(0 == strcmp("user-agent", res[14].value.get())); + + CU_ASSERT(SHRPX_LOGF_LITERAL == res[15].type); + CU_ASSERT(0 == strcmp("\"", res[15].value.get())); res = parse_log_format("$"); diff --git a/src/shrpx_log.cc b/src/shrpx_log.cc index ec8b27e8..b1f435e6 100644 --- a/src/shrpx_log.cc +++ b/src/shrpx_log.cc @@ -158,14 +158,38 @@ Log::~Log() { namespace { template -std::pair copy(const char *src, size_t avail, - OutputIterator oitr) { - auto nwrite = std::min(strlen(src), avail); +std::pair copy(const char *src, size_t srclen, + size_t avail, OutputIterator oitr) { + auto nwrite = std::min(srclen, avail); auto noitr = std::copy_n(src, nwrite, oitr); return std::make_pair(noitr, avail - nwrite); } } // namespace +namespace { +template +std::pair copy(const char *src, size_t avail, + OutputIterator oitr) { + return copy(src, strlen(src), avail, oitr); +} +} // namespace + +namespace { +template +std::pair copy(const std::string &src, size_t avail, + OutputIterator oitr) { + return copy(src.c_str(), src.size(), avail, oitr); +} +} // namespace + +namespace { +template +std::pair copy_l(const char (&src)[N], size_t avail, + OutputIterator oitr) { + return copy(src, N - 1, avail, oitr); +} +} // namespace + namespace { const char LOWER_XDIGITS[] = "0123456789abcdef"; } // namespace @@ -212,46 +236,57 @@ void upstream_accesslog(const std::vector &lfv, std::tie(p, avail) = copy(lgsp.remote_addr, avail, p); break; case SHRPX_LOGF_TIME_LOCAL: - std::tie(p, avail) = copy(time_local.c_str(), avail, p); + std::tie(p, avail) = copy(time_local, avail, p); break; case SHRPX_LOGF_TIME_ISO8601: - std::tie(p, avail) = copy(time_iso8601.c_str(), avail, p); + std::tie(p, avail) = copy(time_iso8601, avail, p); break; case SHRPX_LOGF_REQUEST: std::tie(p, avail) = copy(lgsp.method, avail, p); - std::tie(p, avail) = copy(" ", avail, p); + std::tie(p, avail) = copy_l(" ", avail, p); std::tie(p, avail) = copy(lgsp.path, avail, p); - std::tie(p, avail) = copy(" HTTP/", avail, p); - std::tie(p, avail) = copy(util::utos(lgsp.major).c_str(), avail, p); + std::tie(p, avail) = copy_l(" HTTP/", avail, p); + std::tie(p, avail) = copy(util::utos(lgsp.major), avail, p); if (lgsp.major < 2) { - std::tie(p, avail) = copy(".", avail, p); - std::tie(p, avail) = copy(util::utos(lgsp.minor).c_str(), avail, p); + std::tie(p, avail) = copy_l(".", avail, p); + std::tie(p, avail) = copy(util::utos(lgsp.minor), avail, p); } break; case SHRPX_LOGF_STATUS: - std::tie(p, avail) = copy(util::utos(lgsp.status).c_str(), avail, p); + std::tie(p, avail) = copy(util::utos(lgsp.status), avail, p); break; case SHRPX_LOGF_BODY_BYTES_SENT: - std::tie(p, avail) = - copy(util::utos(lgsp.body_bytes_sent).c_str(), avail, p); + std::tie(p, avail) = copy(util::utos(lgsp.body_bytes_sent), avail, p); break; case SHRPX_LOGF_HTTP: if (downstream) { auto hd = downstream->get_request_header(lf.value.get()); if (hd) { - std::tie(p, avail) = copy((*hd).value.c_str(), avail, p); + std::tie(p, avail) = copy((*hd).value, avail, p); break; } } - std::tie(p, avail) = copy("-", avail, p); + std::tie(p, avail) = copy_l("-", avail, p); + + break; + case SHRPX_LOGF_AUTHORITY: + if (downstream) { + auto &authority = downstream->get_request_http2_authority(); + if (!authority.empty()) { + std::tie(p, avail) = copy(authority, avail, p); + break; + } + } + + std::tie(p, avail) = copy_l("-", avail, p); break; case SHRPX_LOGF_REMOTE_PORT: std::tie(p, avail) = copy(lgsp.remote_port, avail, p); break; case SHRPX_LOGF_SERVER_PORT: - std::tie(p, avail) = copy(util::utos(lgsp.server_port).c_str(), avail, p); + std::tie(p, avail) = copy(util::utos(lgsp.server_port), avail, p); break; case SHRPX_LOGF_REQUEST_TIME: { auto t = std::chrono::duration_cast( @@ -265,31 +300,31 @@ void upstream_accesslog(const std::vector &lfv, sec += "."; sec += frac; - std::tie(p, avail) = copy(sec.c_str(), avail, p); + std::tie(p, avail) = copy(sec, avail, p); } break; case SHRPX_LOGF_PID: - std::tie(p, avail) = copy(util::utos(lgsp.pid).c_str(), avail, p); + std::tie(p, avail) = copy(util::utos(lgsp.pid), avail, p); break; case SHRPX_LOGF_ALPN: std::tie(p, avail) = copy(lgsp.alpn, avail, p); break; case SHRPX_LOGF_SSL_CIPHER: if (!lgsp.tls_info) { - std::tie(p, avail) = copy("-", avail, p); + std::tie(p, avail) = copy_l("-", avail, p); break; } std::tie(p, avail) = copy(lgsp.tls_info->cipher, avail, p); break; case SHRPX_LOGF_SSL_PROTOCOL: if (!lgsp.tls_info) { - std::tie(p, avail) = copy("-", avail, p); + std::tie(p, avail) = copy_l("-", avail, p); break; } std::tie(p, avail) = copy(lgsp.tls_info->protocol, avail, p); break; case SHRPX_LOGF_SSL_SESSION_ID: if (!lgsp.tls_info || lgsp.tls_info->session_id_length == 0) { - std::tie(p, avail) = copy("-", avail, p); + std::tie(p, avail) = copy_l("-", avail, p); break; } std::tie(p, avail) = @@ -298,11 +333,11 @@ void upstream_accesslog(const std::vector &lfv, break; case SHRPX_LOGF_SSL_SESSION_REUSED: if (!lgsp.tls_info) { - std::tie(p, avail) = copy("-", avail, p); + std::tie(p, avail) = copy_l("-", avail, p); break; } std::tie(p, avail) = - copy(lgsp.tls_info->session_reused ? "r" : ".", avail, p); + copy_l(lgsp.tls_info->session_reused ? "r" : ".", avail, p); break; case SHRPX_LOGF_NONE: break; diff --git a/src/shrpx_log.h b/src/shrpx_log.h index d08f1bec..2fae8d04 100644 --- a/src/shrpx_log.h +++ b/src/shrpx_log.h @@ -118,6 +118,7 @@ enum LogFragmentType { SHRPX_LOGF_STATUS, SHRPX_LOGF_BODY_BYTES_SENT, SHRPX_LOGF_HTTP, + SHRPX_LOGF_AUTHORITY, SHRPX_LOGF_REMOTE_PORT, SHRPX_LOGF_SERVER_PORT, SHRPX_LOGF_REQUEST_TIME,