From: Remi Gacogne Date: Fri, 5 May 2023 15:10:14 +0000 (+0200) Subject: dnsdist: Small optimization for nghttp2 headers X-Git-Tag: rec-5.0.0-alpha1~19^2~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=83abf7f6b68dfb8473c83054d3a670becef321a6;p=thirdparty%2Fpdns.git dnsdist: Small optimization for nghttp2 headers --- diff --git a/pdns/dnsdistdist/dnsdist-nghttp2-in.cc b/pdns/dnsdistdist/dnsdist-nghttp2-in.cc index 8e225ee2ca..578cdc6d73 100644 --- a/pdns/dnsdistdist/dnsdist-nghttp2-in.cc +++ b/pdns/dnsdistdist/dnsdist-nghttp2-in.cc @@ -387,32 +387,32 @@ ssize_t IncomingHTTP2Connection::send_callback(nghttp2_session* session, const u return length; } -static const std::unordered_map s_constants{ - {"200-value", "200"}, - {"method-name", ":method"}, - {"method-value", "POST"}, - {"scheme-name", ":scheme"}, - {"scheme-value", "https"}, - {"authority-name", ":authority"}, - {"x-forwarded-for-name", "x-forwarded-for"}, - {"path-name", ":path"}, - {"content-length-name", "content-length"}, - {"status-name", ":status"}, - {"location-name", "location"}, - {"accept-name", "accept"}, - {"accept-value", "application/dns-message"}, - {"cache-control-name", "cache-control"}, - {"content-type-name", "content-type"}, - {"content-type-value", "application/dns-message"}, - {"user-agent-name", "user-agent"}, - {"user-agent-value", "nghttp2-" NGHTTP2_VERSION "/dnsdist"}, - {"x-forwarded-port-name", "x-forwarded-port"}, - {"x-forwarded-proto-name", "x-forwarded-proto"}, - {"x-forwarded-proto-value-dns-over-udp", "dns-over-udp"}, - {"x-forwarded-proto-value-dns-over-tcp", "dns-over-tcp"}, - {"x-forwarded-proto-value-dns-over-tls", "dns-over-tls"}, - {"x-forwarded-proto-value-dns-over-http", "dns-over-http"}, - {"x-forwarded-proto-value-dns-over-https", "dns-over-https"}, +static const std::array(NGHTTP2Headers::HeaderConstantIndexes::COUNT)> s_headerConstants{ + "200", + ":method", + "POST", + ":scheme", + "https", + ":authority", + "x-forwarded-for", + ":path", + "content-length", + ":status", + "location", + "accept", + "application/dns-message", + "cache-control", + "content-type", + "application/dns-message", + "user-agent", + "nghttp2-" NGHTTP2_VERSION "/dnsdist", + "x-forwarded-port", + "x-forwarded-proto", + "dns-over-udp", + "dns-over-tcp", + "dns-over-tls", + "dns-over-http", + "dns-over-https" }; static const std::string s_authorityHeaderName(":authority"); @@ -421,10 +421,10 @@ static const std::string s_methodHeaderName(":method"); static const std::string s_schemeHeaderName(":scheme"); static const std::string s_xForwardedForHeaderName("x-forwarded-for"); -void NGHTTP2Headers::addStaticHeader(std::vector& headers, const std::string& nameKey, const std::string& valueKey) +void NGHTTP2Headers::addStaticHeader(std::vector& headers, NGHTTP2Headers::HeaderConstantIndexes nameKey, NGHTTP2Headers::HeaderConstantIndexes valueKey) { - const auto& name = s_constants.at(nameKey); - const auto& value = s_constants.at(valueKey); + const auto& name = s_headerConstants.at(static_cast(nameKey)); + const auto& value = s_headerConstants.at(static_cast(valueKey)); headers.push_back({const_cast(reinterpret_cast(name.c_str())), const_cast(reinterpret_cast(value.c_str())), name.size(), value.size(), NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE}); } @@ -434,9 +434,9 @@ void NGHTTP2Headers::addCustomDynamicHeader(std::vector& headers, co headers.push_back({const_cast(reinterpret_cast(name.data())), const_cast(reinterpret_cast(value.data())), name.size(), value.size(), NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE}); } -void NGHTTP2Headers::addDynamicHeader(std::vector& headers, const std::string& nameKey, const std::string_view& value) +void NGHTTP2Headers::addDynamicHeader(std::vector& headers, NGHTTP2Headers::HeaderConstantIndexes nameKey, const std::string_view& value) { - const auto& name = s_constants.at(nameKey); + const auto& name = s_headerConstants.at(static_cast(nameKey)); NGHTTP2Headers::addCustomDynamicHeader(headers, name, value); } @@ -511,18 +511,20 @@ bool IncomingHTTP2Connection::sendResponse(IncomingHTTP2Connection::StreamID str std::string location; /* remember that dynamic header values should be kept alive until we have called nghttp2_submit_response(), at least */ + /* status, content-type, cache-control, content-length */ + headers.reserve(4); if (responseCode == 200) { - NGHTTP2Headers::addStaticHeader(headers, "status-name", "200-value"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::STATUS_NAME, NGHTTP2Headers::HeaderConstantIndexes::OK_200_VALUE); ++df->d_validresponses; ++df->d_http2Stats.d_nb200Responses; if (addContentType) { if (contentType.empty()) { - NGHTTP2Headers::addStaticHeader(headers, "content-type-name", "content-type-value"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_VALUE); } else { - NGHTTP2Headers::addDynamicHeader(headers, "content-type-name", contentType); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, contentType); } } @@ -530,18 +532,18 @@ bool IncomingHTTP2Connection::sendResponse(IncomingHTTP2Connection::StreamID str uint32_t minTTL = getDNSPacketMinTTL(reinterpret_cast(responseBody.data()), responseBody.size()); if (minTTL != std::numeric_limits::max()) { cacheControlValue = "max-age=" + std::to_string(minTTL); - NGHTTP2Headers::addDynamicHeader(headers, "cache-control-name", cacheControlValue); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CACHE_CONTROL_NAME, cacheControlValue); } } } else { responseCodeStr = std::to_string(responseCode); - NGHTTP2Headers::addDynamicHeader(headers, "status-name", responseCodeStr); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::STATUS_NAME, responseCodeStr); if (responseCode >= 300 && responseCode < 400) { location = std::string(reinterpret_cast(responseBody.data()), responseBody.size()); - NGHTTP2Headers::addDynamicHeader(headers, "content-type-name", "text/html; charset=utf-8"); - NGHTTP2Headers::addDynamicHeader(headers, "location-name", location); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, "text/html; charset=utf-8"); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::LOCATION_NAME, location); static const std::string s_redirectStart{"Moved

The document has moved here"}; responseBody.reserve(s_redirectStart.size() + responseBody.size() + s_redirectEnd.size()); @@ -570,7 +572,7 @@ bool IncomingHTTP2Connection::sendResponse(IncomingHTTP2Connection::StreamID str } if (!responseBody.empty()) { - NGHTTP2Headers::addDynamicHeader(headers, "content-type-name", "text/plain; charset=utf-8"); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, "text/plain; charset=utf-8"); } else { static const std::string invalid{"invalid DNS query"}; @@ -599,7 +601,7 @@ bool IncomingHTTP2Connection::sendResponse(IncomingHTTP2Connection::StreamID str } const std::string contentLength = std::to_string(responseBody.size()); - NGHTTP2Headers::addDynamicHeader(headers, "content-length-name", contentLength); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_LENGTH_NAME, contentLength); for (const auto& [key, value] : customResponseHeaders) { NGHTTP2Headers::addCustomDynamicHeader(headers, key, value); @@ -918,7 +920,7 @@ int IncomingHTTP2Connection::on_begin_headers_callback(nghttp2_session* session, } IncomingHTTP2Connection* conn = reinterpret_cast(user_data); - auto insertPair = conn->d_currentStreams.insert({frame->hd.stream_id, PendingQuery()}); + auto insertPair = conn->d_currentStreams.emplace(frame->hd.stream_id, PendingQuery()); if (!insertPair.second) { /* there is a stream ID collision, something is very wrong! */ vinfolog("Stream ID collision (%d) on connection from %d", frame->hd.stream_id, conn->d_ci.remote.toStringWithPort()); diff --git a/pdns/dnsdistdist/dnsdist-nghttp2-in.hh b/pdns/dnsdistdist/dnsdist-nghttp2-in.hh index 3ee1c96d10..a8e68777c1 100644 --- a/pdns/dnsdistdist/dnsdist-nghttp2-in.hh +++ b/pdns/dnsdistdist/dnsdist-nghttp2-in.hh @@ -106,8 +106,37 @@ private: class NGHTTP2Headers { public: - static void addStaticHeader(std::vector& headers, const std::string& nameKey, const std::string& valueKey); - static void addDynamicHeader(std::vector& headers, const std::string& nameKey, const std::string_view& value); + enum class HeaderConstantIndexes { + OK_200_VALUE = 0, + METHOD_NAME, + METHOD_VALUE, + SCHEME_NAME, + SCHEME_VALUE, + AUTHORITY_NAME, + X_FORWARDED_FOR_NAME, + PATH_NAME, + CONTENT_LENGTH_NAME, + STATUS_NAME, + LOCATION_NAME, + ACCEPT_NAME, + ACCEPT_VALUE, + CACHE_CONTROL_NAME, + CONTENT_TYPE_NAME, + CONTENT_TYPE_VALUE, + USER_AGENT_NAME, + USER_AGENT_VALUE, + X_FORWARDED_PORT_NAME, + X_FORWARDED_PROTO_NAME, + X_FORWARDED_PROTO_VALUE_DNS_OVER_UDP, + X_FORWARDED_PROTO_VALUE_DNS_OVER_TCP, + X_FORWARDED_PROTO_VALUE_DNS_OVER_TLS, + X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTP, + X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTPS, + COUNT + }; + + static void addStaticHeader(std::vector& headers, HeaderConstantIndexes nameKey, HeaderConstantIndexes valueKey); + static void addDynamicHeader(std::vector& headers, HeaderConstantIndexes nameKey, const std::string_view& value); static void addCustomDynamicHeader(std::vector& headers, const std::string& name, const std::string_view& value); }; diff --git a/pdns/dnsdistdist/dnsdist-nghttp2.cc b/pdns/dnsdistdist/dnsdist-nghttp2.cc index 692b732757..03fa0bfca5 100644 --- a/pdns/dnsdistdist/dnsdist-nghttp2.cc +++ b/pdns/dnsdistdist/dnsdist-nghttp2.cc @@ -84,9 +84,6 @@ private: static void handleReadableIOCallback(int fd, FDMultiplexer::funcparam_t& param); static void handleWritableIOCallback(int fd, FDMultiplexer::funcparam_t& param); - static void addStaticHeader(std::vector& headers, const std::string& nameKey, const std::string& valueKey); - static void addDynamicHeader(std::vector& headers, const std::string& nameKey, const std::string& value); - class PendingRequest { public: @@ -251,37 +248,37 @@ void DoHConnectionToBackend::queueQuery(std::shared_ptr& sender, headers.reserve(8 + (addXForwarded ? 3 : 0)); /* Pseudo-headers need to come first (rfc7540 8.1.2.1) */ - NGHTTP2Headers::addStaticHeader(headers, "method-name", "method-value"); - NGHTTP2Headers::addStaticHeader(headers, "scheme-name", "scheme-value"); - NGHTTP2Headers::addDynamicHeader(headers, "authority-name", d_ds->d_config.d_tlsSubjectName); - NGHTTP2Headers::addDynamicHeader(headers, "path-name", d_ds->d_config.d_dohPath); - NGHTTP2Headers::addStaticHeader(headers, "accept-name", "accept-value"); - NGHTTP2Headers::addStaticHeader(headers, "content-type-name", "content-type-value"); - NGHTTP2Headers::addStaticHeader(headers, "user-agent-name", "user-agent-value"); - NGHTTP2Headers::addDynamicHeader(headers, "content-length-name", payloadSize); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::METHOD_NAME, NGHTTP2Headers::HeaderConstantIndexes::METHOD_VALUE); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::SCHEME_NAME, NGHTTP2Headers::HeaderConstantIndexes::SCHEME_VALUE); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::AUTHORITY_NAME, d_ds->d_config.d_tlsSubjectName); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::PATH_NAME, d_ds->d_config.d_dohPath); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::ACCEPT_NAME, NGHTTP2Headers::HeaderConstantIndexes::ACCEPT_VALUE); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_VALUE); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::USER_AGENT_NAME, NGHTTP2Headers::HeaderConstantIndexes::USER_AGENT_VALUE); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_LENGTH_NAME, payloadSize); /* no need to add these headers for health-check queries */ if (addXForwarded && query.d_idstate.origRemote.getPort() != 0) { remote = query.d_idstate.origRemote.toString(); remotePort = std::to_string(query.d_idstate.origRemote.getPort()); - NGHTTP2Headers::addDynamicHeader(headers, "x-forwarded-for-name", remote); - NGHTTP2Headers::addDynamicHeader(headers, "x-forwarded-port-name", remotePort); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_FOR_NAME, remote); + NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PORT_NAME, remotePort); if (query.d_idstate.cs != nullptr) { if (query.d_idstate.cs->isUDP()) { - NGHTTP2Headers::addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-udp"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_UDP); } else if (query.d_idstate.cs->isDoH()) { if (query.d_idstate.cs->hasTLS()) { - NGHTTP2Headers::addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-https"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTPS); } else { - NGHTTP2Headers::addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-http"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTP); } } else if (query.d_idstate.cs->hasTLS()) { - NGHTTP2Headers::addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-tls"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_TLS); } else { - NGHTTP2Headers::addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-tcp"); + NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_TCP); } } }