diff --git a/src/env-inl.h b/src/env-inl.h index dccfa7ce8c6549..1070c189df3dda 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -630,16 +630,6 @@ inline void Environment::set_http_parser_buffer_in_use(bool in_use) { http_parser_buffer_in_use_ = in_use; } -inline http2::Http2State* Environment::http2_state() const { - return http2_state_.get(); -} - -inline void Environment::set_http2_state( - std::unique_ptr buffer) { - CHECK(!http2_state_); // Should be set only once. - http2_state_ = std::move(buffer); -} - inline AliasedFloat64Array* Environment::fs_stats_field_array() { return &fs_stats_field_array_; } diff --git a/src/env.h b/src/env.h index a7a0981bb0e2b5..8934f432fdbeda 100644 --- a/src/env.h +++ b/src/env.h @@ -33,7 +33,6 @@ #include "handle_wrap.h" #include "node.h" #include "node_binding.h" -#include "node_http2_state.h" #include "node_main_instance.h" #include "node_options.h" #include "req_wrap.h" @@ -50,8 +49,6 @@ #include #include -struct nghttp2_rcbuf; - namespace node { namespace contextify { @@ -515,7 +512,8 @@ class IsolateData : public MemoryRetainer { #undef VP inline v8::Local async_wrap_provider(int index) const; - std::unordered_map> http_static_strs; + std::unordered_map> static_str_map; + inline v8::Isolate* isolate() const; IsolateData(const IsolateData&) = delete; IsolateData& operator=(const IsolateData&) = delete; @@ -1026,9 +1024,6 @@ class Environment : public MemoryRetainer { inline bool http_parser_buffer_in_use() const; inline void set_http_parser_buffer_in_use(bool in_use); - inline http2::Http2State* http2_state() const; - inline void set_http2_state(std::unique_ptr state); - EnabledDebugList* enabled_debug_list() { return &enabled_debug_list_; } inline AliasedFloat64Array* fs_stats_field_array(); @@ -1391,7 +1386,6 @@ class Environment : public MemoryRetainer { char* http_parser_buffer_ = nullptr; bool http_parser_buffer_in_use_ = false; - std::unique_ptr http2_state_; EnabledDebugList enabled_debug_list_; AliasedFloat64Array fs_stats_field_array_; diff --git a/src/node_http2.cc b/src/node_http2.cc index cd3b989a57e46e..d884be3e7553fc 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -4,7 +4,6 @@ #include "node.h" #include "node_buffer.h" #include "node_http2.h" -#include "node_http2_state.h" #include "node_http_common-inl.h" #include "node_mem-inl.h" #include "node_perf.h" @@ -113,7 +112,7 @@ Http2Scope::~Http2Scope() { // instances to configure an appropriate nghttp2_options struct. The class // uses a single TypedArray instance that is shared with the JavaScript side // to more efficiently pass values back and forth. -Http2Options::Http2Options(Environment* env, nghttp2_session_type type) { +Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { nghttp2_option* option; CHECK_EQ(nghttp2_option_new(&option), 0); CHECK_NOT_NULL(option); @@ -138,7 +137,7 @@ Http2Options::Http2Options(Environment* env, nghttp2_session_type type) { nghttp2_option_set_builtin_recv_extension_type(option, NGHTTP2_ORIGIN); } - AliasedUint32Array& buffer = env->http2_state()->options_buffer; + AliasedUint32Array& buffer = http2_state->options_buffer; uint32_t flags = buffer[IDX_OPTIONS_FLAGS]; if (flags & (1 << IDX_OPTIONS_MAX_DEFLATE_DYNAMIC_TABLE_SIZE)) { @@ -213,8 +212,8 @@ Http2Options::Http2Options(Environment* env, nghttp2_session_type type) { SetMaxSessionMemory(buffer[IDX_OPTIONS_MAX_SESSION_MEMORY] * 1000000); } -void Http2Session::Http2Settings::Init() { - AliasedUint32Array& buffer = env()->http2_state()->settings_buffer; +void Http2Session::Http2Settings::Init(Http2State* http2_state) { + AliasedUint32Array& buffer = http2_state->settings_buffer; uint32_t flags = buffer[IDX_SETTINGS_COUNT]; size_t n = 0; @@ -244,14 +243,14 @@ void Http2Session::Http2Settings::Init() { // The Http2Settings class is used to configure a SETTINGS frame that is // to be sent to the connected peer. The settings are set using a TypedArray // that is shared with the JavaScript side. -Http2Session::Http2Settings::Http2Settings(Environment* env, +Http2Session::Http2Settings::Http2Settings(Http2State* http2_state, Http2Session* session, Local obj, uint64_t start_time) - : AsyncWrap(env, obj, PROVIDER_HTTP2SETTINGS), + : AsyncWrap(http2_state->env(), obj, PROVIDER_HTTP2SETTINGS), session_(session), startTime_(start_time) { - Init(); + Init(http2_state); } // Generates a Buffer that contains the serialized payload of a SETTINGS @@ -272,10 +271,9 @@ Local Http2Session::Http2Settings::Pack() { // Updates the shared TypedArray with the current remote or local settings for // the session. -void Http2Session::Http2Settings::Update(Environment* env, - Http2Session* session, +void Http2Session::Http2Settings::Update(Http2Session* session, get_setting fn) { - AliasedUint32Array& buffer = env->http2_state()->settings_buffer; + AliasedUint32Array& buffer = session->http2_state()->settings_buffer; buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] = fn(**session, NGHTTP2_SETTINGS_HEADER_TABLE_SIZE); buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS] = @@ -293,8 +291,8 @@ void Http2Session::Http2Settings::Update(Environment* env, } // Initializes the shared TypedArray with the default settings values. -void Http2Session::Http2Settings::RefreshDefaults(Environment* env) { - AliasedUint32Array& buffer = env->http2_state()->settings_buffer; +void Http2Session::Http2Settings::RefreshDefaults(Http2State* http2_state) { + AliasedUint32Array& buffer = http2_state->settings_buffer; buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] = DEFAULT_SETTINGS_HEADER_TABLE_SIZE; @@ -469,16 +467,17 @@ void Http2Session::DecreaseAllocatedSize(size_t size) { current_nghttp2_memory_ -= size; } -Http2Session::Http2Session(Environment* env, +Http2Session::Http2Session(Http2State* http2_state, Local wrap, nghttp2_session_type type) - : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTP2SESSION), - session_type_(type) { + : AsyncWrap(http2_state->env(), wrap, AsyncWrap::PROVIDER_HTTP2SESSION), + session_type_(type), + http2_state_(http2_state) { MakeWeak(); statistics_.start_time = uv_hrtime(); // Capture the configuration options for this session - Http2Options opts(env, type); + Http2Options opts(http2_state, type); max_session_memory_ = opts.GetMaxSessionMemory(); @@ -521,13 +520,13 @@ Http2Session::Http2Session(Environment* env, // Make the js_fields_ property accessible to JS land. js_fields_store_ = - ArrayBuffer::NewBackingStore(env->isolate(), sizeof(SessionJSFields)); + ArrayBuffer::NewBackingStore(env()->isolate(), sizeof(SessionJSFields)); js_fields_ = new(js_fields_store_->Data()) SessionJSFields; - Local ab = ArrayBuffer::New(env->isolate(), js_fields_store_); + Local ab = ArrayBuffer::New(env()->isolate(), js_fields_store_); Local uint8_arr = Uint8Array::New(ab, 0, kSessionUint8FieldCount); - USE(wrap->Set(env->context(), env->fields_string(), uint8_arr)); + USE(wrap->Set(env()->context(), env()->fields_string(), uint8_arr)); } Http2Session::~Http2Session() { @@ -551,15 +550,17 @@ inline bool HasHttp2Observer(Environment* env) { } void Http2Stream::EmitStatistics() { + CHECK_NOT_NULL(session()); if (!HasHttp2Observer(env())) return; auto entry = - std::make_unique(env(), id_, statistics_); + std::make_unique( + session()->http2_state(), id_, statistics_); env()->SetImmediate([entry = move(entry)](Environment* env) { if (!HasHttp2Observer(env)) return; HandleScope handle_scope(env->isolate()); - AliasedFloat64Array& buffer = env->http2_state()->stream_stats_buffer; + AliasedFloat64Array& buffer = entry->http2_state()->stream_stats_buffer; buffer[IDX_STREAM_STATS_ID] = entry->id(); if (entry->first_byte() != 0) { buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTE] = @@ -592,12 +593,12 @@ void Http2Session::EmitStatistics() { if (!HasHttp2Observer(env())) return; auto entry = std::make_unique( - env(), statistics_, session_type_); + http2_state(), statistics_, session_type_); env()->SetImmediate([entry = std::move(entry)](Environment* env) { if (!HasHttp2Observer(env)) return; HandleScope handle_scope(env->isolate()); - AliasedFloat64Array& buffer = env->http2_state()->session_stats_buffer; + AliasedFloat64Array& buffer = entry->http2_state()->session_stats_buffer; buffer[IDX_SESSION_STATS_TYPE] = entry->type(); buffer[IDX_SESSION_STATS_PINGRTT] = entry->ping_rtt() / 1e6; buffer[IDX_SESSION_STATS_FRAMESRECEIVED] = entry->frame_count(); @@ -2334,7 +2335,8 @@ void HttpErrorString(const FunctionCallbackInfo& args) { // would be suitable, for instance, for creating the Base64 // output for an HTTP2-Settings header field. void PackSettings(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + Http2State* state = Unwrap(args.Data()); + Environment* env = state->env(); // TODO(addaleax): We should not be creating a full AsyncWrap for this. Local obj; if (!env->http2settings_constructor_template() @@ -2342,7 +2344,7 @@ void PackSettings(const FunctionCallbackInfo& args) { .ToLocal(&obj)) { return; } - Http2Session::Http2Settings settings(env, nullptr, obj); + Http2Session::Http2Settings settings(state, nullptr, obj); args.GetReturnValue().Set(settings.Pack()); } @@ -2350,8 +2352,8 @@ void PackSettings(const FunctionCallbackInfo& args) { // default SETTINGS. RefreshDefaultSettings updates that TypedArray with the // default values. void RefreshDefaultSettings(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - Http2Session::Http2Settings::RefreshDefaults(env); + Http2State* state = Unwrap(args.Data()); + Http2Session::Http2Settings::RefreshDefaults(state); } // Sets the next stream ID the Http2Session. If successful, returns true. @@ -2373,10 +2375,9 @@ void Http2Session::SetNextStreamID(const FunctionCallbackInfo& args) { // values established for each of the settings so those can be read in JS land. template void Http2Session::RefreshSettings(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); Http2Session* session; ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder()); - Http2Settings::Update(env, session, fn); + Http2Settings::Update(session, fn); Debug(session, "settings refreshed for session"); } @@ -2384,12 +2385,11 @@ void Http2Session::RefreshSettings(const FunctionCallbackInfo& args) { // information of the current Http2Session. This updates the values in the // TypedArray so those can be read in JS land. void Http2Session::RefreshState(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); Http2Session* session; ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder()); Debug(session, "refreshing state"); - AliasedFloat64Array& buffer = env->http2_state()->session_state_buffer; + AliasedFloat64Array& buffer = session->http2_state()->session_state_buffer; nghttp2_session* s = **session; @@ -2416,11 +2416,12 @@ void Http2Session::RefreshState(const FunctionCallbackInfo& args) { // Constructor for new Http2Session instances. void Http2Session::New(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + Http2State* state = Unwrap(args.Data()); + Environment* env = state->env(); CHECK(args.IsConstructCall()); int32_t val = args[0]->Int32Value(env->context()).ToChecked(); nghttp2_session_type type = static_cast(val); - Http2Session* session = new Http2Session(env, args.This(), type); + Http2Session* session = new Http2Session(state, args.This(), type); session->get_async_id(); // avoid compiler warning Debug(session, "session created"); } @@ -2645,13 +2646,14 @@ void Http2Stream::Priority(const FunctionCallbackInfo& args) { // information about the Http2Stream. This updates the values in that // TypedArray so that the state can be read by JS. void Http2Stream::RefreshState(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); Http2Stream* stream; ASSIGN_OR_RETURN_UNWRAP(&stream, args.Holder()); Debug(stream, "refreshing state"); - AliasedFloat64Array& buffer = env->http2_state()->stream_state_buffer; + CHECK_NOT_NULL(stream->session()); + AliasedFloat64Array& buffer = + stream->session()->http2_state()->stream_state_buffer; nghttp2_stream* str = **stream; nghttp2_session* s = **(stream->session()); @@ -2797,7 +2799,8 @@ void Http2Session::Settings(const FunctionCallbackInfo& args) { return; Http2Settings* settings = session->AddSettings( - MakeDetachedBaseObject(session->env(), session, obj, 0)); + MakeDetachedBaseObject( + session->http2_state(), session, obj, 0)); if (settings == nullptr) return args.GetReturnValue().Set(false); settings->Send(); @@ -2921,6 +2924,10 @@ void SetCallbackFunctions(const FunctionCallbackInfo& args) { #undef SET_FUNCTION } +void Http2State::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("root_buffer", root_buffer); +} + // Set up the process.binding('http2') binding. void Initialize(Local target, Local unused, @@ -2928,9 +2935,11 @@ void Initialize(Local target, void* priv) { Environment* env = Environment::GetCurrent(context); Isolate* isolate = env->isolate(); - HandleScope scope(isolate); + HandleScope handle_scope(isolate); - std::unique_ptr state(new Http2State(isolate)); + Environment::BindingScope binding_scope(env); + if (!binding_scope) return; + Http2State* state = binding_scope.data; #define SET_STATE_TYPEDARRAY(name, field) \ target->Set(context, \ @@ -2953,8 +2962,6 @@ void Initialize(Local target, "sessionStats", state->session_stats_buffer.GetJSArray()); #undef SET_STATE_TYPEDARRAY - env->set_http2_state(std::move(state)); - NODE_DEFINE_CONSTANT(target, kBitfield); NODE_DEFINE_CONSTANT(target, kSessionPriorityListenerCount); NODE_DEFINE_CONSTANT(target, kSessionFrameErrorListenerCount); diff --git a/src/node_http2.h b/src/node_http2.h index b07f9cf4130d7b..f9a0cae85ff2ae 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -189,7 +189,8 @@ class Http2Scope { // configured. class Http2Options { public: - Http2Options(Environment* env, nghttp2_session_type type); + Http2Options(Http2State* http2_state, + nghttp2_session_type type); ~Http2Options() = default; @@ -541,7 +542,7 @@ class Http2Session : public AsyncWrap, public StreamListener, public mem::NgLibMemoryManager { public: - Http2Session(Environment* env, + Http2Session(Http2State* http2_state, v8::Local wrap, nghttp2_session_type type = NGHTTP2_SESSION_SERVER); ~Http2Session() override; @@ -674,6 +675,9 @@ class Http2Session : public AsyncWrap, return env()->event_loop(); } + Http2State* http2_state() { + return http2_state_.get(); + } BaseObjectPtr PopPing(); Http2Ping* AddPing(BaseObjectPtr ping); @@ -871,6 +875,9 @@ class Http2Session : public AsyncWrap, uint32_t invalid_frame_count_ = 0; void PushOutgoingBuffer(NgHttp2StreamWrite&& write); + + BaseObjectPtr http2_state_; + void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length); void ClearOutgoing(int status); @@ -881,11 +888,11 @@ class Http2Session : public AsyncWrap, class Http2SessionPerformanceEntry : public performance::PerformanceEntry { public: Http2SessionPerformanceEntry( - Environment* env, + Http2State* http2_state, const Http2Session::Statistics& stats, nghttp2_session_type type) : performance::PerformanceEntry( - env, "Http2Session", "http2", + http2_state->env(), "Http2Session", "http2", stats.start_time, stats.end_time), ping_rtt_(stats.ping_rtt), @@ -896,7 +903,8 @@ class Http2SessionPerformanceEntry : public performance::PerformanceEntry { stream_count_(stats.stream_count), max_concurrent_streams_(stats.max_concurrent_streams), stream_average_duration_(stats.stream_average_duration), - session_type_(type) { } + session_type_(type), + http2_state_(http2_state) { } uint64_t ping_rtt() const { return ping_rtt_; } uint64_t data_sent() const { return data_sent_; } @@ -907,6 +915,7 @@ class Http2SessionPerformanceEntry : public performance::PerformanceEntry { size_t max_concurrent_streams() const { return max_concurrent_streams_; } double stream_average_duration() const { return stream_average_duration_; } nghttp2_session_type type() const { return session_type_; } + Http2State* http2_state() const { return http2_state_.get(); } void Notify(v8::Local obj) { performance::PerformanceEntry::Notify(env(), kind(), obj); @@ -922,17 +931,18 @@ class Http2SessionPerformanceEntry : public performance::PerformanceEntry { size_t max_concurrent_streams_; double stream_average_duration_; nghttp2_session_type session_type_; + BaseObjectPtr http2_state_; }; class Http2StreamPerformanceEntry : public performance::PerformanceEntry { public: Http2StreamPerformanceEntry( - Environment* env, + Http2State* http2_state, int32_t id, const Http2Stream::Statistics& stats) : performance::PerformanceEntry( - env, "Http2Stream", "http2", + http2_state->env(), "Http2Stream", "http2", stats.start_time, stats.end_time), id_(id), @@ -940,7 +950,8 @@ class Http2StreamPerformanceEntry first_byte_(stats.first_byte), first_byte_sent_(stats.first_byte_sent), sent_bytes_(stats.sent_bytes), - received_bytes_(stats.received_bytes) { } + received_bytes_(stats.received_bytes), + http2_state_(http2_state) { } int32_t id() const { return id_; } uint64_t first_header() const { return first_header_; } @@ -948,6 +959,7 @@ class Http2StreamPerformanceEntry uint64_t first_byte_sent() const { return first_byte_sent_; } uint64_t sent_bytes() const { return sent_bytes_; } uint64_t received_bytes() const { return received_bytes_; } + Http2State* http2_state() const { return http2_state_.get(); } void Notify(v8::Local obj) { performance::PerformanceEntry::Notify(env(), kind(), obj); @@ -960,6 +972,7 @@ class Http2StreamPerformanceEntry uint64_t first_byte_sent_; uint64_t sent_bytes_; uint64_t received_bytes_; + BaseObjectPtr http2_state_; }; class Http2Session::Http2Ping : public AsyncWrap { @@ -987,7 +1000,7 @@ class Http2Session::Http2Ping : public AsyncWrap { // structs. class Http2Session::Http2Settings : public AsyncWrap { public: - Http2Settings(Environment* env, + Http2Settings(Http2State* http2_state, Http2Session* session, v8::Local obj, uint64_t start_time = uv_hrtime()); @@ -1006,15 +1019,14 @@ class Http2Session::Http2Settings : public AsyncWrap { v8::Local Pack(); // Resets the default values in the settings buffer - static void RefreshDefaults(Environment* env); + static void RefreshDefaults(Http2State* http2_state); // Update the local or remote settings for the given session - static void Update(Environment* env, - Http2Session* session, + static void Update(Http2Session* session, get_setting fn); private: - void Init(); + void Init(Http2State* http2_state); Http2Session* session_; uint64_t startTime_; size_t count_ = 0; diff --git a/src/node_http2_state.h b/src/node_http2_state.h index 1ba3677f47a4f6..80efb40cd27589 100644 --- a/src/node_http2_state.h +++ b/src/node_http2_state.h @@ -5,6 +5,8 @@ #include "aliased_buffer.h" +struct nghttp2_rcbuf; + namespace node { namespace http2 { @@ -78,42 +80,43 @@ namespace http2 { IDX_SESSION_STATS_COUNT }; -class Http2State { +class Http2State : public BaseObject { public: - explicit Http2State(v8::Isolate* isolate) : - root_buffer( - isolate, - sizeof(http2_state_internal)), - session_state_buffer( - isolate, - offsetof(http2_state_internal, session_state_buffer), - IDX_SESSION_STATE_COUNT, - root_buffer), - stream_state_buffer( - isolate, - offsetof(http2_state_internal, stream_state_buffer), - IDX_STREAM_STATE_COUNT, - root_buffer), - stream_stats_buffer( - isolate, - offsetof(http2_state_internal, stream_stats_buffer), - IDX_STREAM_STATS_COUNT, - root_buffer), - session_stats_buffer( - isolate, - offsetof(http2_state_internal, session_stats_buffer), - IDX_SESSION_STATS_COUNT, - root_buffer), - options_buffer( - isolate, - offsetof(http2_state_internal, options_buffer), - IDX_OPTIONS_FLAGS + 1, - root_buffer), - settings_buffer( - isolate, - offsetof(http2_state_internal, settings_buffer), - IDX_SETTINGS_COUNT + 1, - root_buffer) { + Http2State(Environment* env, v8::Local obj) + : BaseObject(env, obj), + root_buffer( + env->isolate(), + sizeof(http2_state_internal)), + session_state_buffer( + env->isolate(), + offsetof(http2_state_internal, session_state_buffer), + IDX_SESSION_STATE_COUNT, + root_buffer), + stream_state_buffer( + env->isolate(), + offsetof(http2_state_internal, stream_state_buffer), + IDX_STREAM_STATE_COUNT, + root_buffer), + stream_stats_buffer( + env->isolate(), + offsetof(http2_state_internal, stream_stats_buffer), + IDX_STREAM_STATS_COUNT, + root_buffer), + session_stats_buffer( + env->isolate(), + offsetof(http2_state_internal, session_stats_buffer), + IDX_SESSION_STATS_COUNT, + root_buffer), + options_buffer( + env->isolate(), + offsetof(http2_state_internal, options_buffer), + IDX_OPTIONS_FLAGS + 1, + root_buffer), + settings_buffer( + env->isolate(), + offsetof(http2_state_internal, settings_buffer), + IDX_SETTINGS_COUNT + 1, + root_buffer) { } AliasedUint8Array root_buffer; @@ -124,6 +127,10 @@ class Http2State { AliasedUint32Array options_buffer; AliasedUint32Array settings_buffer; + void MemoryInfo(MemoryTracker* tracker) const override; + SET_SELF_SIZE(Http2State) + SET_MEMORY_INFO_NAME(Http2State) + private: struct http2_state_internal { // doubles first so that they are always sizeof(double)-aligned diff --git a/src/node_http_common-inl.h b/src/node_http_common-inl.h index d63cdf79a4b468..2c76dc3a1fd372 100644 --- a/src/node_http_common-inl.h +++ b/src/node_http_common-inl.h @@ -143,7 +143,7 @@ v8::MaybeLocal NgHeader::GetName( // If header_name is not nullptr, then it is a known header with // a statically defined name. We can safely internalize it here. if (header_name != nullptr) { - auto& static_str_map = env_->isolate_data()->http_static_strs; + auto& static_str_map = env_->isolate_data()->static_str_map; v8::Eternal eternal = static_str_map[header_name]; if (eternal.IsEmpty()) { v8::Local str = OneByteString(env_->isolate(), header_name); diff --git a/src/node_http_common.h b/src/node_http_common.h index 41b5f419d94338..d2bdddd93f4649 100644 --- a/src/node_http_common.h +++ b/src/node_http_common.h @@ -409,7 +409,7 @@ class NgRcBufPointer : public MemoryRetainer { NgRcBufPointer ptr) { Environment* env = allocator->env(); if (ptr.IsStatic()) { - auto& static_str_map = env->isolate_data()->http_static_strs; + auto& static_str_map = env->isolate_data()->static_str_map; const char* header_name = reinterpret_cast(ptr.data()); v8::Eternal& eternal = static_str_map[header_name]; if (eternal.IsEmpty()) {