#ifndef SRC_NODE_HTTP2_H_#define SRC_NODE_HTTP2_H_#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS// FIXME(joyeecheung): nghttp2.h needs stdint.h to compile on Windows#include <cstdint>#include "nghttp2/nghttp2.h"#include "env.h"#include "allocated_buffer.h"#include "aliased_struct.h"#include "node_http2_state.h"#include "node_http_common.h"#include "node_mem.h"#include "node_perf.h"#include "stream_base.h"#include "string_bytes.h"#include <algorithm>#include <queue>namespace node {namespace http2 {// Constants in all caps are exported as user-facing constants// in JavaScript. Constants using the kName pattern are internal// only.// We strictly limit the number of outstanding unacknowledged PINGS a user// may send in order to prevent abuse. The current default cap is 10. The// user may set a different limit using a per Http2Session configuration// option.constexpr size_t kDefaultMaxPings = 10;// Also strictly limit the number of outstanding SETTINGS frames a user sendsconstexpr size_t kDefaultMaxSettings = 10;// Default maximum total memory cap for Http2Session.constexpr uint64_t kDefaultMaxSessionMemory = 10000000;// These are the standard HTTP/2 defaults as specified by the RFCconstexpr uint32_t DEFAULT_SETTINGS_HEADER_TABLE_SIZE = 4096;constexpr uint32_t DEFAULT_SETTINGS_ENABLE_PUSH = 1;constexpr uint32_t DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS = 0xffffffffu;constexpr uint32_t DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE = 65535;constexpr uint32_t DEFAULT_SETTINGS_MAX_FRAME_SIZE = 16384;constexpr uint32_t DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE = 65535;constexpr uint32_t DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0;constexpr uint32_t MAX_MAX_FRAME_SIZE = 16777215;constexpr uint32_t MIN_MAX_FRAME_SIZE = DEFAULT_SETTINGS_MAX_FRAME_SIZE;constexpr uint32_t MAX_INITIAL_WINDOW_SIZE = 2147483647;// Stream is not going to have any DATA framesconstexpr int STREAM_OPTION_EMPTY_PAYLOAD = 0x1;// Stream might have trailing headersconstexpr int STREAM_OPTION_GET_TRAILERS = 0x2;// Http2Stream internal statesconstexpr int kStreamStateNone = 0x0;constexpr int kStreamStateShut = 0x1;constexpr int kStreamStateReadStart = 0x2;constexpr int kStreamStateReadPaused = 0x4;constexpr int kStreamStateClosed = 0x8;constexpr int kStreamStateDestroyed = 0x10;constexpr int kStreamStateTrailers = 0x20;// Http2Session internal statesconstexpr int kSessionStateNone = 0x0;constexpr int kSessionStateHasScope = 0x1;constexpr int kSessionStateWriteScheduled = 0x2;constexpr int kSessionStateClosed = 0x4;constexpr int kSessionStateClosing = 0x8;constexpr int kSessionStateSending = 0x10;constexpr int kSessionStateWriteInProgress = 0x20;constexpr int kSessionStateReadingStopped = 0x40;constexpr int kSessionStateReceivePaused = 0x80;// The Padding Strategy determines the method by which extra padding is// selected for HEADERS and DATA frames. These are configurable via the// options passed in to a Http2Session object.enum PaddingStrategy {// No padding strategy. This is the default.PADDING_STRATEGY_NONE,// Attempts to ensure that the frame is 8-byte alignedPADDING_STRATEGY_ALIGNED,// Padding will ensure all data frames are maxFrameSizePADDING_STRATEGY_MAX,// Removed and turned into an alias because it is unreasonably expensive for// very little benefit.PADDING_STRATEGY_CALLBACK = PADDING_STRATEGY_ALIGNED};enum SessionType {NGHTTP2_SESSION_SERVER,NGHTTP2_SESSION_CLIENT};template <typename T, void(*fn)(T*)>struct Nghttp2Deleter {void operator()(T* ptr) const noexcept { fn(ptr); }};using Nghttp2OptionPointer =std::unique_ptr<nghttp2_option,Nghttp2Deleter<nghttp2_option, nghttp2_option_del>>;using Nghttp2SessionPointer =std::unique_ptr<nghttp2_session,Nghttp2Deleter<nghttp2_session, nghttp2_session_del>>;using Nghttp2SessionCallbacksPointer =std::unique_ptr<nghttp2_session_callbacks,Nghttp2Deleter<nghttp2_session_callbacks,nghttp2_session_callbacks_del>>;struct Http2HeadersTraits {typedef nghttp2_nv nv_t;};struct Http2RcBufferPointerTraits {typedef nghttp2_rcbuf rcbuf_t;typedef nghttp2_vec vector_t;static void inc(rcbuf_t* buf) {CHECK_NOT_NULL(buf);nghttp2_rcbuf_incref(buf);}static void dec(rcbuf_t* buf) {CHECK_NOT_NULL(buf);nghttp2_rcbuf_decref(buf);}static vector_t get_vec(rcbuf_t* buf) {CHECK_NOT_NULL(buf);return nghttp2_rcbuf_get_buf(buf);}static bool is_static(const rcbuf_t* buf) {CHECK_NOT_NULL(buf);return nghttp2_rcbuf_is_static(buf);}};using Http2Headers = NgHeaders<Http2HeadersTraits>;using Http2RcBufferPointer = NgRcBufPointer<Http2RcBufferPointerTraits>;struct NgHttp2StreamWrite : public MemoryRetainer {BaseObjectPtr<AsyncWrap> req_wrap;uv_buf_t buf;inline explicit NgHttp2StreamWrite(uv_buf_t buf_) : buf(buf_) {}inline NgHttp2StreamWrite(BaseObjectPtr<AsyncWrap> req_wrap, uv_buf_t buf_) :req_wrap(std::move(req_wrap)), buf(buf_) {}void MemoryInfo(MemoryTracker* tracker) const override;SET_MEMORY_INFO_NAME(NgHttp2StreamWrite)SET_SELF_SIZE(NgHttp2StreamWrite)};typedef uint32_t(*get_setting)(nghttp2_session* session,nghttp2_settings_id id);class Http2Ping;class Http2Session;class Http2Settings;class Http2Stream;class Origins;// This scope should be present when any call into nghttp2 that may schedule// data to be written to the underlying transport is made, and schedules// such a write automatically once the scope is exited.class Http2Scope {public:explicit Http2Scope(Http2Stream* stream);explicit Http2Scope(Http2Session* session);~Http2Scope();private:BaseObjectPtr<Http2Session> session_;};// The Http2Options class is used to parse the options object passed in to// a Http2Session object and convert those into an appropriate nghttp2_option// struct. This is the primary mechanism by which the Http2Session object is// configured.class Http2Options {public:Http2Options(Http2State* http2_state,SessionType type);~Http2Options() = default;nghttp2_option* operator*() const {return options_.get();}void set_max_header_pairs(uint32_t max) {max_header_pairs_ = max;}uint32_t max_header_pairs() const {return max_header_pairs_;}void set_padding_strategy(PaddingStrategy val) {padding_strategy_ = val;}PaddingStrategy padding_strategy() const {return padding_strategy_;}void set_max_outstanding_pings(size_t max) {max_outstanding_pings_ = max;}size_t max_outstanding_pings() const {return max_outstanding_pings_;}void set_max_outstanding_settings(size_t max) {max_outstanding_settings_ = max;}size_t max_outstanding_settings() const {return max_outstanding_settings_;}void set_max_session_memory(uint64_t max) {max_session_memory_ = max;}uint64_t max_session_memory() const {return max_session_memory_;}private:Nghttp2OptionPointer options_;uint64_t max_session_memory_ = kDefaultMaxSessionMemory;uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;PaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE;size_t max_outstanding_pings_ = kDefaultMaxPings;size_t max_outstanding_settings_ = kDefaultMaxSettings;};struct Http2Priority : public nghttp2_priority_spec {Http2Priority(Environment* env,v8::Local<v8::Value> parent,v8::Local<v8::Value> weight,v8::Local<v8::Value> exclusive);};class Http2StreamListener : public StreamListener {public:uv_buf_t OnStreamAlloc(size_t suggested_size) override;void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;};struct Http2HeaderTraits {typedef Http2RcBufferPointer rcbufferpointer_t;typedef Http2Session allocator_t;// HTTP/2 does not support identifying header names by token id.// HTTP/3 will, however, so we prepare for that now.static const char* ToHttpHeaderName(int32_t token) { return nullptr; }};using Http2Header = NgHeader<Http2HeaderTraits>;class Http2Stream : public AsyncWrap,public StreamBase {public:static Http2Stream* New(Http2Session* session,int32_t id,nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS,int options = 0);~Http2Stream() override;nghttp2_stream* operator*() const;nghttp2_stream* stream() const;Http2Session* session() { return session_.get(); }const Http2Session* session() const { return session_.get(); }// Required for StreamBaseint ReadStart() override;// Required for StreamBaseint ReadStop() override;// Required for StreamBaseShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;int DoShutdown(ShutdownWrap* req_wrap) override;bool HasWantsWrite() const override { return true; }// Initiate a response on this stream.int SubmitResponse(const Http2Headers& headers, int options);// Submit informational headers for this streamint SubmitInfo(const Http2Headers& headers);// Submit trailing headers for this streamint SubmitTrailers(const Http2Headers& headers);void OnTrailers();// Submit a PRIORITY frame for this streamint SubmitPriority(const Http2Priority& priority, bool silent = false);// Submits an RST_STREAM frame using the given codevoid SubmitRstStream(const uint32_t code);void FlushRstStream();// Submits a PUSH_PROMISE frame with this stream as the parent.Http2Stream* SubmitPushPromise(const Http2Headers& headers,int32_t* ret,int options = 0);void Close(int32_t code);// Destroy this stream instance and free all held memory.void Destroy();bool is_destroyed() const {return flags_ & kStreamStateDestroyed;}bool is_writable() const {return !(flags_ & kStreamStateShut);}bool is_paused() const {return flags_ & kStreamStateReadPaused;}bool is_closed() const {return flags_ & kStreamStateClosed;}bool has_trailers() const {return flags_ & kStreamStateTrailers;}void set_has_trailers(bool on = true) {if (on)flags_ |= kStreamStateTrailers;elseflags_ &= ~kStreamStateTrailers;}void set_closed() {flags_ |= kStreamStateClosed;}void set_destroyed() {flags_ |= kStreamStateDestroyed;}void set_not_writable() {flags_ |= kStreamStateShut;}void set_reading(bool on = true) {if (on) {flags_ |= kStreamStateReadStart;set_paused(false);} else {}}void set_paused(bool on = true) {if (on)flags_ |= kStreamStateReadPaused;elseflags_ &= ~kStreamStateReadPaused;}// Returns true if this stream is in the reading state, which occurs when// the kStreamStateReadStart flag has been set and the// kStreamStateReadPaused flag is *not* set.bool is_reading() const {return flags_ & kStreamStateReadStart && !is_paused();}// Returns the RST_STREAM code used to close this streamint32_t code() const { return code_; }// Returns the stream identifier for this streamint32_t id() const { return id_; }void IncrementAvailableOutboundLength(size_t amount);void DecrementAvailableOutboundLength(size_t amount);bool AddHeader(nghttp2_rcbuf* name, nghttp2_rcbuf* value, uint8_t flags);template <typename Fn>void TransferHeaders(Fn&& fn) {size_t i = 0;for (const auto& header : current_headers_ )fn(header, i++);current_headers_.clear();}size_t headers_count() const {return current_headers_.size();}nghttp2_headers_category headers_category() const {return current_headers_category_;}void StartHeaders(nghttp2_headers_category category);// Required for StreamBasebool IsAlive() override {return true;}// Required for StreamBasebool IsClosing() override {return false;}AsyncWrap* GetAsyncWrap() override { return this; }int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,uv_stream_t* send_handle) override;void MemoryInfo(MemoryTracker* tracker) const override;SET_MEMORY_INFO_NAME(Http2Stream)SET_SELF_SIZE(Http2Stream)std::string diagnostic_name() const override;// JavaScript APIstatic void GetID(const v8::FunctionCallbackInfo<v8::Value>& args);static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);static void Priority(const v8::FunctionCallbackInfo<v8::Value>& args);static void PushPromise(const v8::FunctionCallbackInfo<v8::Value>& args);static void RefreshState(const v8::FunctionCallbackInfo<v8::Value>& args);static void Info(const v8::FunctionCallbackInfo<v8::Value>& args);static void Trailers(const v8::FunctionCallbackInfo<v8::Value>& args);static void Respond(const v8::FunctionCallbackInfo<v8::Value>& args);static void RstStream(const v8::FunctionCallbackInfo<v8::Value>& args);class Provider;struct Statistics {uint64_t start_time;uint64_t end_time;uint64_t first_header; // Time first header was receiveduint64_t first_byte; // Time first DATA frame byte was receiveduint64_t first_byte_sent; // Time first DATA frame byte was sentuint64_t sent_bytes;uint64_t received_bytes;uint64_t id;};Statistics statistics_ = {};private:Http2Stream(Http2Session* session,v8::Local<v8::Object> obj,int32_t id,nghttp2_headers_category category,int options);void EmitStatistics();BaseObjectWeakPtr<Http2Session> session_; // The Parent HTTP/2 Sessionint32_t id_ = 0; // The Stream Identifierint32_t code_ = NGHTTP2_NO_ERROR; // The RST_STREAM code (if any)int flags_ = kStreamStateNone; // Internal state flagsuint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;uint32_t max_header_length_ = DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE;// The Current Headers block... As headers are received for this stream,// they are temporarily stored here until the OnFrameReceived is called// signalling the end of the HEADERS framenghttp2_headers_category current_headers_category_ = NGHTTP2_HCAT_HEADERS;uint32_t current_headers_length_ = 0; // total number of octetsstd::vector<Http2Header> current_headers_;// This keeps track of the amount of data read from the socket while the// socket was in paused mode. When `ReadStart()` is called (and not before// then), we tell nghttp2 that we consumed that data to get proper// backpressure handling.size_t inbound_consumed_data_while_paused_ = 0;// Outbound Data... This is the data written by the JS layer that is// waiting to be written out to the socket.std::queue<NgHttp2StreamWrite> queue_;size_t available_outbound_length_ = 0;Http2StreamListener stream_listener_;friend class Http2Session;};class Http2Stream::Provider {public:Provider(Http2Stream* stream, int options);explicit Provider(int options);virtual ~Provider();nghttp2_data_provider* operator*() {return !empty_ ? &provider_ : nullptr;}class FD;class Stream;protected:nghttp2_data_provider provider_;private:bool empty_ = false;};class Http2Stream::Provider::Stream : public Http2Stream::Provider {public:Stream(Http2Stream* stream, int options);explicit Stream(int options);static ssize_t OnRead(nghttp2_session* session,int32_t id,uint8_t* buf,size_t length,uint32_t* flags,nghttp2_data_source* source,void* user_data);};struct SessionJSFields {uint8_t bitfield;uint8_t priority_listener_count;uint8_t frame_error_listener_count;uint32_t max_invalid_frames = 1000;uint32_t max_rejected_streams = 100;};// Indices for js_fields_, which serves as a way to communicate data with JS// land fast. In particular, we store information about the number/presence// of certain event listeners in JS, and skip calls from C++ into JS if they// are missing.enum SessionUint8Fields {kBitfield = offsetof(SessionJSFields, bitfield), // See belowkSessionPriorityListenerCount =offsetof(SessionJSFields, priority_listener_count),kSessionFrameErrorListenerCount =offsetof(SessionJSFields, frame_error_listener_count),kSessionMaxInvalidFrames = offsetof(SessionJSFields, max_invalid_frames),kSessionMaxRejectedStreams = offsetof(SessionJSFields, max_rejected_streams),kSessionUint8FieldCount = sizeof(SessionJSFields)};enum SessionBitfieldFlags {kSessionHasRemoteSettingsListeners,kSessionRemoteSettingsIsUpToDate,kSessionHasPingListeners,kSessionHasAltsvcListeners};class Http2Session : public AsyncWrap,public StreamListener,public mem::NgLibMemoryManager<Http2Session, nghttp2_mem> {public:Http2Session(Http2State* http2_state,v8::Local<v8::Object> wrap,SessionType type = NGHTTP2_SESSION_SERVER);~Http2Session() override;StreamBase* underlying_stream() {return static_cast<StreamBase*>(stream_);}void Close(uint32_t code = NGHTTP2_NO_ERROR,bool socket_closed = false);void Consume(v8::Local<v8::Object> stream);void Goaway(uint32_t code, int32_t lastStreamID,const uint8_t* data, size_t len);void AltSvc(int32_t id,uint8_t* origin,size_t origin_len,uint8_t* value,size_t value_len);void Origin(const Origins& origins);uint8_t SendPendingData();// Submits a new request. If the request is a success, assigned// will be a pointer to the Http2Stream instance assigned.// This only works if the session is a client session.Http2Stream* SubmitRequest(const Http2Priority& priority,const Http2Headers& headers,int32_t* ret,int options = 0);SessionType type() const { return session_type_; }nghttp2_session* session() const { return session_.get(); }nghttp2_session* operator*() { return session_.get(); }uint32_t max_header_pairs() const { return max_header_pairs_; }const char* TypeName() const;bool is_destroyed() {return (flags_ & kSessionStateClosed) || session_ == nullptr;}void set_destroyed() {flags_ |= kSessionStateClosed;}#define IS_FLAG(name, flag) \bool is_##name() const { return flags_ & flag; } \void set_##name(bool on = true) { \if (on) \flags_ |= flag; \else \flags_ &= ~flag; \}IS_FLAG(in_scope, kSessionStateHasScope)IS_FLAG(write_scheduled, kSessionStateWriteScheduled)IS_FLAG(closing, kSessionStateClosing)IS_FLAG(sending, kSessionStateSending)IS_FLAG(write_in_progress, kSessionStateWriteInProgress)IS_FLAG(reading_stopped, kSessionStateReadingStopped)IS_FLAG(receive_paused, kSessionStateReceivePaused)#undef IS_FLAG// Schedule a write if nghttp2 indicates it wants to write to the socket.void MaybeScheduleWrite();// Stop reading if nghttp2 doesn't want to anymore.void MaybeStopReading();// Returns pointer to the stream, or nullptr if stream does not existBaseObjectPtr<Http2Stream> FindStream(int32_t id);bool CanAddStream();// Adds a stream instance to this sessionvoid AddStream(Http2Stream* stream);// Removes a stream instance from this sessionBaseObjectPtr<Http2Stream> RemoveStream(int32_t id);// Indicates whether there currently exist outgoing buffers for this stream.bool HasWritesOnSocketForStream(Http2Stream* stream);// Write data from stream_buf_ to the session.// This will call the error callback if an error occurs.void ConsumeHTTP2Data();void MemoryInfo(MemoryTracker* tracker) const override;SET_MEMORY_INFO_NAME(Http2Session)SET_SELF_SIZE(Http2Session)std::string diagnostic_name() const override;// Schedule an RstStream for after the current write finishes.void AddPendingRstStream(int32_t stream_id) {pending_rst_streams_.emplace_back(stream_id);}bool has_pending_rststream(int32_t stream_id) {return pending_rst_streams_.end() !=std::find(pending_rst_streams_.begin(),pending_rst_streams_.end(),stream_id);}// Handle reads/writes from the underlying network transport.uv_buf_t OnStreamAlloc(size_t suggested_size) override;void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;void OnStreamAfterWrite(WriteWrap* w, int status) override;// Implementation for mem::NgLibMemoryManagervoid CheckAllocatedSize(size_t previous_size) const;void IncreaseAllocatedSize(size_t size);void DecreaseAllocatedSize(size_t size);// The JavaScript APIstatic void New(const v8::FunctionCallbackInfo<v8::Value>& args);static void Consume(const v8::FunctionCallbackInfo<v8::Value>& args);static void Receive(const v8::FunctionCallbackInfo<v8::Value>& args);static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);static void Settings(const v8::FunctionCallbackInfo<v8::Value>& args);static void Request(const v8::FunctionCallbackInfo<v8::Value>& args);static void SetNextStreamID(const v8::FunctionCallbackInfo<v8::Value>& args);static void SetLocalWindowSize(const v8::FunctionCallbackInfo<v8::Value>& args);static void Goaway(const v8::FunctionCallbackInfo<v8::Value>& args);static void UpdateChunksSent(const v8::FunctionCallbackInfo<v8::Value>& args);static void RefreshState(const v8::FunctionCallbackInfo<v8::Value>& args);static void Ping(const v8::FunctionCallbackInfo<v8::Value>& args);static void AltSvc(const v8::FunctionCallbackInfo<v8::Value>& args);static void Origin(const v8::FunctionCallbackInfo<v8::Value>& args);template <get_setting fn>static void RefreshSettings(const v8::FunctionCallbackInfo<v8::Value>& args);uv_loop_t* event_loop() const {return env()->event_loop();}Http2State* http2_state() const { return http2_state_.get(); }BaseObjectPtr<Http2Ping> PopPing();bool AddPing(const uint8_t* data, v8::Local<v8::Function> callback);BaseObjectPtr<Http2Settings> PopSettings();bool AddSettings(v8::Local<v8::Function> callback);void IncrementCurrentSessionMemory(uint64_t amount) {current_session_memory_ += amount;}void DecrementCurrentSessionMemory(uint64_t amount) {DCHECK_LE(amount, current_session_memory_);current_session_memory_ -= amount;}// Tell our custom memory allocator that this rcbuf is independent of// this session now, and may outlive it.void StopTrackingRcbuf(nghttp2_rcbuf* buf);// Returns the current session memory including memory allocated by nghttp2,// the current outbound storage queue, and pending writes.uint64_t current_session_memory() const {uint64_t total = current_session_memory_ + sizeof(Http2Session);total += current_nghttp2_memory_;total += outgoing_storage_.size();return total;}// Return true if current_session_memory + amount is less than the maxbool has_available_session_memory(uint64_t amount) const {return current_session_memory() + amount <= max_session_memory_;}struct Statistics {uint64_t start_time;uint64_t end_time;uint64_t ping_rtt;uint64_t data_sent;uint64_t data_received;uint32_t frame_count;uint32_t frame_sent;int32_t stream_count;size_t max_concurrent_streams;double stream_average_duration;SessionType session_type;};Statistics statistics_ = {};private:void EmitStatistics();// Frame Padding Strategiesssize_t OnDWordAlignedPadding(size_t frameLength,size_t maxPayloadLen);ssize_t OnMaxFrameSizePadding(size_t frameLength,size_t maxPayloadLen);// Frame Handlerint HandleDataFrame(const nghttp2_frame* frame);void HandleGoawayFrame(const nghttp2_frame* frame);void HandleHeadersFrame(const nghttp2_frame* frame);void HandlePriorityFrame(const nghttp2_frame* frame);void HandleSettingsFrame(const nghttp2_frame* frame);void HandlePingFrame(const nghttp2_frame* frame);void HandleAltSvcFrame(const nghttp2_frame* frame);void HandleOriginFrame(const nghttp2_frame* frame);// nghttp2 callbacksstatic int OnBeginHeadersCallback(nghttp2_session* session,const nghttp2_frame* frame,void* user_data);static int OnHeaderCallback(nghttp2_session* session,const nghttp2_frame* frame,nghttp2_rcbuf* name,nghttp2_rcbuf* value,uint8_t flags,void* user_data);static int OnFrameReceive(nghttp2_session* session,const nghttp2_frame* frame,void* user_data);static int OnFrameNotSent(nghttp2_session* session,const nghttp2_frame* frame,int error_code,void* user_data);static int OnFrameSent(nghttp2_session* session,const nghttp2_frame* frame,void* user_data);static int OnStreamClose(nghttp2_session* session,int32_t id,uint32_t code,void* user_data);static int OnInvalidHeader(nghttp2_session* session,const nghttp2_frame* frame,nghttp2_rcbuf* name,nghttp2_rcbuf* value,uint8_t flags,void* user_data);static int OnDataChunkReceived(nghttp2_session* session,uint8_t flags,int32_t id,const uint8_t* data,size_t len,void* user_data);static ssize_t OnSelectPadding(nghttp2_session* session,const nghttp2_frame* frame,size_t maxPayloadLen,void* user_data);static int OnNghttpError(nghttp2_session* session,const char* message,size_t len,void* user_data);static int OnSendData(nghttp2_session* session,nghttp2_frame* frame,const uint8_t* framehd,size_t length,nghttp2_data_source* source,void* user_data);static int OnInvalidFrame(nghttp2_session* session,const nghttp2_frame* frame,int lib_error_code,void* user_data);struct Callbacks {explicit Callbacks(bool kHasGetPaddingCallback);Nghttp2SessionCallbacksPointer callbacks;};/* Use callback_struct_saved[kHasGetPaddingCallback ? 1 : 0] */static const Callbacks callback_struct_saved[2];// The underlying nghttp2_session handleNghttp2SessionPointer session_;// JS-accessible numeric fields, as indexed by SessionUint8Fields.AliasedStruct<SessionJSFields> js_fields_;// The session type: client or serverSessionType session_type_;// The maximum number of header pairs permitted for streams on this sessionuint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;// The maximum amount of memory allocated for this sessionuint64_t max_session_memory_ = kDefaultMaxSessionMemory;uint64_t current_session_memory_ = 0;// The amount of memory allocated by nghttp2 internalsuint64_t current_nghttp2_memory_ = 0;// The collection of active Http2Streams associated with this sessionstd::unordered_map<int32_t, BaseObjectPtr<Http2Stream>> streams_;int flags_ = kSessionStateNone;// The StreamBase instance being used for i/oPaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE;// use this to allow timeout tracking during long-lasting writesuint32_t chunks_sent_since_last_write_ = 0;uv_buf_t stream_buf_ = uv_buf_init(nullptr, 0);// When processing input data, either stream_buf_ab_ or stream_buf_allocation_// will be set. stream_buf_ab_ is lazily created from stream_buf_allocation_.v8::Global<v8::ArrayBuffer> stream_buf_ab_;AllocatedBuffer stream_buf_allocation_;size_t stream_buf_offset_ = 0;// Custom error code for errors that originated inside one of the callbacks// called by nghttp2_session_mem_recv.const char* custom_recv_error_code_ = nullptr;size_t max_outstanding_pings_ = kDefaultMaxPings;std::queue<BaseObjectPtr<Http2Ping>> outstanding_pings_;size_t max_outstanding_settings_ = kDefaultMaxSettings;std::queue<BaseObjectPtr<Http2Settings>> outstanding_settings_;std::vector<NgHttp2StreamWrite> outgoing_buffers_;std::vector<uint8_t> outgoing_storage_;size_t outgoing_length_ = 0;std::vector<int32_t> pending_rst_streams_;// Count streams that have been rejected while being opened. Exceeding a fixed// limit will result in the session being destroyed, as an indication of a// misbehaving peer. This counter is reset once new streams are being// accepted again.uint32_t rejected_stream_count_ = 0;// Also use the invalid frame count as a measure for rejecting input frames.uint32_t invalid_frame_count_ = 0;void PushOutgoingBuffer(NgHttp2StreamWrite&& write);BaseObjectPtr<Http2State> http2_state_;void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length);void ClearOutgoing(int status);friend class Http2Scope;friend class Http2StreamListener;};struct Http2SessionPerformanceEntryTraits {static constexpr performance::PerformanceEntryType kType =performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2;using Details = Http2Session::Statistics;static v8::MaybeLocal<v8::Object> GetDetails(Environment* env,const performance::PerformanceEntry<Http2SessionPerformanceEntryTraits>&entry);};struct Http2StreamPerformanceEntryTraits {static constexpr performance::PerformanceEntryType kType =performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2;using Details = Http2Stream::Statistics;static v8::MaybeLocal<v8::Object> GetDetails(Environment* env,const performance::PerformanceEntry<Http2StreamPerformanceEntryTraits>&entry);};using Http2SessionPerformanceEntry =performance::PerformanceEntry<Http2SessionPerformanceEntryTraits>;using Http2StreamPerformanceEntry =performance::PerformanceEntry<Http2StreamPerformanceEntryTraits>;class Http2Ping : public AsyncWrap {public:explicit Http2Ping(Http2Session* session,v8::Local<v8::Object> obj,v8::Local<v8::Function> callback);void MemoryInfo(MemoryTracker* tracker) const override;SET_MEMORY_INFO_NAME(Http2Ping)SET_SELF_SIZE(Http2Ping)void Send(const uint8_t* payload);void Done(bool ack, const uint8_t* payload = nullptr);void DetachFromSession();v8::Local<v8::Function> callback() const;private:BaseObjectWeakPtr<Http2Session> session_;v8::Global<v8::Function> callback_;uint64_t startTime_;};// The Http2Settings class is used to parse the settings passed in for// an Http2Session, converting those into an array of nghttp2_settings_entry// structs.class Http2Settings : public AsyncWrap {public:Http2Settings(Http2Session* session,v8::Local<v8::Object> obj,v8::Local<v8::Function> callback,uint64_t start_time = uv_hrtime());void MemoryInfo(MemoryTracker* tracker) const override;SET_MEMORY_INFO_NAME(Http2Settings)SET_SELF_SIZE(Http2Settings)void Send();void Done(bool ack);v8::Local<v8::Function> callback() const;// Returns a Buffer instance with the serialized SETTINGS payloadv8::Local<v8::Value> Pack();static v8::Local<v8::Value> Pack(Http2State* state);// Resets the default values in the settings bufferstatic void RefreshDefaults(Http2State* http2_state);// Update the local or remote settings for the given sessionstatic void Update(Http2Session* session,get_setting fn);private:static size_t Init(Http2State* http2_state,nghttp2_settings_entry* entries);static v8::Local<v8::Value> Pack(Environment* env,size_t count,const nghttp2_settings_entry* entries);BaseObjectWeakPtr<Http2Session> session_;v8::Global<v8::Function> callback_;uint64_t startTime_;size_t count_ = 0;nghttp2_settings_entry entries_[IDX_SETTINGS_COUNT];};class Origins {public:Origins(Environment* env,v8::Local<v8::String> origin_string,size_t origin_count);~Origins() = default;const nghttp2_origin_entry* operator*() const {return reinterpret_cast<const nghttp2_origin_entry*>(buf_.data());}size_t length() const {return count_;}private:size_t count_;AllocatedBuffer buf_;};#define HTTP2_HIDDEN_CONSTANTS(V) \V(NGHTTP2_HCAT_REQUEST) \V(NGHTTP2_HCAT_RESPONSE) \V(NGHTTP2_HCAT_PUSH_RESPONSE) \V(NGHTTP2_HCAT_HEADERS) \V(NGHTTP2_NV_FLAG_NONE) \V(NGHTTP2_NV_FLAG_NO_INDEX) \V(NGHTTP2_ERR_DEFERRED) \V(NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE) \V(NGHTTP2_ERR_INVALID_ARGUMENT) \V(NGHTTP2_ERR_STREAM_CLOSED) \V(NGHTTP2_ERR_NOMEM) \V(STREAM_OPTION_EMPTY_PAYLOAD) \V(STREAM_OPTION_GET_TRAILERS)#define HTTP2_ERROR_CODES(V) \V(NGHTTP2_NO_ERROR) \V(NGHTTP2_PROTOCOL_ERROR) \V(NGHTTP2_INTERNAL_ERROR) \V(NGHTTP2_FLOW_CONTROL_ERROR) \V(NGHTTP2_SETTINGS_TIMEOUT) \V(NGHTTP2_STREAM_CLOSED) \V(NGHTTP2_FRAME_SIZE_ERROR) \V(NGHTTP2_REFUSED_STREAM) \V(NGHTTP2_CANCEL) \V(NGHTTP2_COMPRESSION_ERROR) \V(NGHTTP2_CONNECT_ERROR) \V(NGHTTP2_ENHANCE_YOUR_CALM) \V(NGHTTP2_INADEQUATE_SECURITY) \V(NGHTTP2_HTTP_1_1_REQUIRED) \#define HTTP2_CONSTANTS(V) \V(NGHTTP2_ERR_FRAME_SIZE_ERROR) \V(NGHTTP2_SESSION_SERVER) \V(NGHTTP2_SESSION_CLIENT) \V(NGHTTP2_STREAM_STATE_IDLE) \V(NGHTTP2_STREAM_STATE_OPEN) \V(NGHTTP2_STREAM_STATE_RESERVED_LOCAL) \V(NGHTTP2_STREAM_STATE_RESERVED_REMOTE) \V(NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) \V(NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE) \V(NGHTTP2_STREAM_STATE_CLOSED) \V(NGHTTP2_FLAG_NONE) \V(NGHTTP2_FLAG_END_STREAM) \V(NGHTTP2_FLAG_END_HEADERS) \V(NGHTTP2_FLAG_ACK) \V(NGHTTP2_FLAG_PADDED) \V(NGHTTP2_FLAG_PRIORITY) \V(DEFAULT_SETTINGS_HEADER_TABLE_SIZE) \V(DEFAULT_SETTINGS_ENABLE_PUSH) \V(DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS) \V(DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE) \V(DEFAULT_SETTINGS_MAX_FRAME_SIZE) \V(DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE) \V(DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL) \V(MAX_MAX_FRAME_SIZE) \V(MIN_MAX_FRAME_SIZE) \V(MAX_INITIAL_WINDOW_SIZE) \V(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) \V(NGHTTP2_SETTINGS_ENABLE_PUSH) \V(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) \V(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE) \V(NGHTTP2_SETTINGS_MAX_FRAME_SIZE) \V(NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) \V(NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) \V(PADDING_STRATEGY_NONE) \V(PADDING_STRATEGY_ALIGNED) \V(PADDING_STRATEGY_MAX) \V(PADDING_STRATEGY_CALLBACK) \HTTP2_ERROR_CODES(V)#define HTTP2_SETTINGS(V) \V(HEADER_TABLE_SIZE) \V(ENABLE_PUSH) \V(MAX_CONCURRENT_STREAMS) \V(INITIAL_WINDOW_SIZE) \V(MAX_FRAME_SIZE) \V(MAX_HEADER_LIST_SIZE) \V(ENABLE_CONNECT_PROTOCOL) \} // namespace http2} // namespace node#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS#endif // SRC_NODE_HTTP2_H_
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。