| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3766e04 commit 9c85ada
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1652,6 +1652,15 @@ changes: | |||
| 1652 | 1652 | * `options` {Object} | |
| 1653 | 1653 | * `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size | |
| 1654 | 1654 | for deflating header fields. **Default:** `4Kib` | |
| 1655 | + * `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session` | ||
| 1656 | + is permitted to use. The value is expressed in terms of number of megabytes, | ||
| 1657 | + e.g. `1` equal 1 megabyte. The minimum value allowed is `1`. **Default:** | ||
| 1658 | + `10`. This is a credit based limit, existing `Http2Stream`s may cause this | ||
| 1659 | + limit to be exceeded, but new `Http2Stream` instances will be rejected | ||
| 1660 | + while this limit is exceeded. The current number of `Http2Stream` sessions, | ||
| 1661 | + the current memory use of the header compression tables, current data | ||
| 1662 | + queued to be sent, and unacknowledged PING and SETTINGS frames are all | ||
| 1663 | + counted towards the current limit. | ||
| 1655 | 1664 | * `maxHeaderListPairs` {number} Sets the maximum number of header entries. | |
| 1656 | 1665 | **Default:** `128`. The minimum value is `4`. | |
| 1657 | 1666 | * `maxOutstandingPings` {number} Sets the maximum number of outstanding, | |
@@ -1730,6 +1739,15 @@ changes: | |||
| 1730 | 1739 | `false`. See the [`'unknownProtocol'`][] event. See [ALPN negotiation][]. | |
| 1731 | 1740 | * `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size | |
| 1732 | 1741 | for deflating header fields. **Default:** `4Kib` | |
| 1742 | + * `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session` | ||
| 1743 | + is permitted to use. The value is expressed in terms of number of megabytes, | ||
| 1744 | + e.g. `1` equal 1 megabyte. The minimum value allowed is `1`. **Default:** | ||
| 1745 | + `10`. This is a credit based limit, existing `Http2Stream`s may cause this | ||
| 1746 | + limit to be exceeded, but new `Http2Stream` instances will be rejected | ||
| 1747 | + while this limit is exceeded. The current number of `Http2Stream` sessions, | ||
| 1748 | + the current memory use of the header compression tables, current data | ||
| 1749 | + queued to be sent, and unacknowledged PING and SETTINGS frames are all | ||
| 1750 | + counted towards the current limit. | ||
| 1733 | 1751 | * `maxHeaderListPairs` {number} Sets the maximum number of header entries. | |
| 1734 | 1752 | **Default:** `128`. The minimum value is `4`. | |
| 1735 | 1753 | * `maxOutstandingPings` {number} Sets the maximum number of outstanding, | |
@@ -1813,6 +1831,15 @@ changes: | |||
| 1813 | 1831 | * `options` {Object} | |
| 1814 | 1832 | * `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size | |
| 1815 | 1833 | for deflating header fields. **Default:** `4Kib` | |
| 1834 | + * `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session` | ||
| 1835 | + is permitted to use. The value is expressed in terms of number of megabytes, | ||
| 1836 | + e.g. `1` equal 1 megabyte. The minimum value allowed is `1`. **Default:** | ||
| 1837 | + `10`. This is a credit based limit, existing `Http2Stream`s may cause this | ||
| 1838 | + limit to be exceeded, but new `Http2Stream` instances will be rejected | ||
| 1839 | + while this limit is exceeded. The current number of `Http2Stream` sessions, | ||
| 1840 | + the current memory use of the header compression tables, current data | ||
| 1841 | + queued to be sent, and unacknowledged PING and SETTINGS frames are all | ||
| 1842 | + counted towards the current limit. | ||
| 1816 | 1843 | * `maxHeaderListPairs` {number} Sets the maximum number of header entries. | |
| 1817 | 1844 | **Default:** `128`. The minimum value is `1`. | |
| 1818 | 1845 | * `maxOutstandingPings` {number} Sets the maximum number of outstanding, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -175,7 +175,8 @@ const IDX_OPTIONS_PADDING_STRATEGY = 4; | |||
| 175 | 175 | const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5; | |
| 176 | 176 | const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6; | |
| 177 | 177 | const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7; | |
| 178 | - const IDX_OPTIONS_FLAGS = 8; | ||
| 178 | + const IDX_OPTIONS_MAX_SESSION_MEMORY = 8; | ||
| 179 | + const IDX_OPTIONS_FLAGS = 9; | ||
| 179 | 180 | ||
| 180 | 181 | function updateOptionsBuffer(options) { | |
| 181 | 182 | var flags = 0; | |
@@ -219,6 +220,11 @@ function updateOptionsBuffer(options) { | |||
| 219 | 220 | optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS] = | |
| 220 | 221 | Math.max(1, options.maxOutstandingSettings); | |
| 221 | 222 | } | |
| 223 | + if (typeof options.maxSessionMemory === 'number') { | ||
| 224 | + flags |= (1 << IDX_OPTIONS_MAX_SESSION_MEMORY); | ||
| 225 | + optionsBuffer[IDX_OPTIONS_MAX_SESSION_MEMORY] = | ||
| 226 | + Math.max(1, options.maxSessionMemory); | ||
| 227 | + } | ||
| 222 | 228 | optionsBuffer[IDX_OPTIONS_FLAGS] = flags; | |
| 223 | 229 | } | |
| 224 | 230 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -174,6 +174,18 @@ Http2Options::Http2Options(Environment* env) { | |||
| 174 | 174 | if (flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS)) { | |
| 175 | 175 | SetMaxOutstandingSettings(buffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS]); | |
| 176 | 176 | } | |
| 177 | + | ||
| 178 | + // The HTTP2 specification places no limits on the amount of memory | ||
| 179 | + // that a session can consume. In order to prevent abuse, we place a | ||
| 180 | + // cap on the amount of memory a session can consume at any given time. | ||
| 181 | + // this is a credit based system. Existing streams may cause the limit | ||
| 182 | + // to be temporarily exceeded but once over the limit, new streams cannot | ||
| 183 | + // created. | ||
| 184 | + // Important: The maxSessionMemory option in javascript is expressed in | ||
| 185 | + // terms of MB increments (i.e. the value 1 == 1 MB) | ||
| 186 | + if (flags & (1 << IDX_OPTIONS_MAX_SESSION_MEMORY)) { | ||
| 187 | + SetMaxSessionMemory(buffer[IDX_OPTIONS_MAX_SESSION_MEMORY] * 1e6); | ||
| 188 | + } | ||
| 177 | 189 | } | |
| 178 | 190 | ||
| 179 | 191 | void Http2Session::Http2Settings::Init() { | |
@@ -482,11 +494,13 @@ Http2Session::Http2Session(Environment* env, | |||
| 482 | 494 | // Capture the configuration options for this session | |
| 483 | 495 | Http2Options opts(env); | |
| 484 | 496 | ||
| 485 | - int32_t maxHeaderPairs = opts.GetMaxHeaderPairs(); | ||
| 497 | + max_session_memory_ = opts.GetMaxSessionMemory(); | ||
| 498 | + | ||
| 499 | + uint32_t maxHeaderPairs = opts.GetMaxHeaderPairs(); | ||
| 486 | 500 | max_header_pairs_ = | |
| 487 | 501 | type == NGHTTP2_SESSION_SERVER | |
| 488 | - ? std::max(maxHeaderPairs, 4) // minimum # of request headers | ||
| 489 | - : std::max(maxHeaderPairs, 1); // minimum # of response headers | ||
| 502 | + ? std::max(maxHeaderPairs, 4U) // minimum # of request headers | ||
| 503 | + : std::max(maxHeaderPairs, 1U); // minimum # of response headers | ||
| 490 | 504 | ||
| 491 | 505 | max_outstanding_pings_ = opts.GetMaxOutstandingPings(); | |
| 492 | 506 | max_outstanding_settings_ = opts.GetMaxOutstandingSettings(); | |
@@ -673,18 +687,21 @@ inline bool Http2Session::CanAddStream() { | |||
| 673 | 687 | size_t maxSize = | |
| 674 | 688 | std::min(streams_.max_size(), static_cast<size_t>(maxConcurrentStreams)); | |
| 675 | 689 | // We can add a new stream so long as we are less than the current | |
| 676 | - // maximum on concurrent streams | ||
| 677 | - return streams_.size() < maxSize; | ||
| 690 | + // maximum on concurrent streams and there's enough available memory | ||
| 691 | + return streams_.size() < maxSize && | ||
| 692 | + IsAvailableSessionMemory(sizeof(Http2Stream)); | ||
| 678 | 693 | } | |
| 679 | 694 | ||
| 680 | 695 | inline void Http2Session::AddStream(Http2Stream* stream) { | |
| 681 | 696 | CHECK_GE(++statistics_.stream_count, 0); | |
| 682 | 697 | streams_[stream->id()] = stream; | |
| 698 | + IncrementCurrentSessionMemory(stream->self_size()); | ||
| 683 | 699 | } | |
| 684 | 700 | ||
| 685 | 701 | ||
| 686 | - inline void Http2Session::RemoveStream(int32_t id) { | ||
| 687 | - streams_.erase(id); | ||
| 702 | + inline void Http2Session::RemoveStream(Http2Stream* stream) { | ||
| 703 | + streams_.erase(stream->id()); | ||
| 704 | + DecrementCurrentSessionMemory(stream->self_size()); | ||
| 688 | 705 | } | |
| 689 | 706 | ||
| 690 | 707 | // Used as one of the Padding Strategy functions. Will attempt to ensure | |
@@ -1678,7 +1695,7 @@ Http2Stream::Http2Stream( | |||
| 1678 | 1695 | ||
| 1679 | 1696 | Http2Stream::~Http2Stream() { | |
| 1680 | 1697 | if (session_ != nullptr) { | |
| 1681 | - session_->RemoveStream(id_); | ||
| 1698 | + session_->RemoveStream(this); | ||
| 1682 | 1699 | session_ = nullptr; | |
| 1683 | 1700 | } | |
| 1684 | 1701 | ||
@@ -2008,7 +2025,7 @@ inline int Http2Stream::DoWrite(WriteWrap* req_wrap, | |||
| 2008 | 2025 | i == nbufs - 1 ? req_wrap : nullptr, | |
| 2009 | 2026 | bufs[i] | |
| 2010 | 2027 | }); | |
| 2011 | - available_outbound_length_ += bufs[i].len; | ||
| 2028 | + IncrementAvailableOutboundLength(bufs[i].len); | ||
| 2012 | 2029 | } | |
| 2013 | 2030 | CHECK_NE(nghttp2_session_resume_data(**session_, id_), NGHTTP2_ERR_NOMEM); | |
| 2014 | 2031 | return 0; | |
@@ -2030,7 +2047,10 @@ inline bool Http2Stream::AddHeader(nghttp2_rcbuf* name, | |||
| 2030 | 2047 | if (this->statistics_.first_header == 0) | |
| 2031 | 2048 | this->statistics_.first_header = uv_hrtime(); | |
| 2032 | 2049 | size_t length = GetBufferLength(name) + GetBufferLength(value) + 32; | |
| 2033 | - if (current_headers_.size() == max_header_pairs_ || | ||
| 2050 | + // A header can only be added if we have not exceeded the maximum number | ||
| 2051 | + // of headers and the session has memory available for it. | ||
| 2052 | + if (!session_->IsAvailableSessionMemory(length) || | ||
| 2053 | + current_headers_.size() == max_header_pairs_ || | ||
| 2034 | 2054 | current_headers_length_ + length > max_header_length_) { | |
| 2035 | 2055 | return false; | |
| 2036 | 2056 | } | |
@@ -2174,7 +2194,7 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle, | |||
| 2174 | 2194 | // Just return the length, let Http2Session::OnSendData take care of | |
| 2175 | 2195 | // actually taking the buffers out of the queue. | |
| 2176 | 2196 | *flags |= NGHTTP2_DATA_FLAG_NO_COPY; | |
| 2177 | - stream->available_outbound_length_ -= amount; | ||
| 2197 | + stream->DecrementAvailableOutboundLength(amount); | ||
| 2178 | 2198 | } | |
| 2179 | 2199 | } | |
| 2180 | 2200 | ||
@@ -2197,6 +2217,15 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle, | |||
| 2197 | 2217 | return amount; | |
| 2198 | 2218 | } | |
| 2199 | 2219 | ||
| 2220 | + inline void Http2Stream::IncrementAvailableOutboundLength(size_t amount) { | ||
| 2221 | + available_outbound_length_ += amount; | ||
| 2222 | + session_->IncrementCurrentSessionMemory(amount); | ||
| 2223 | + } | ||
| 2224 | + | ||
| 2225 | + inline void Http2Stream::DecrementAvailableOutboundLength(size_t amount) { | ||
| 2226 | + available_outbound_length_ -= amount; | ||
| 2227 | + session_->DecrementCurrentSessionMemory(amount); | ||
| 2228 | + } | ||
| 2200 | 2229 | ||
| 2201 | 2230 | ||
| 2202 | 2231 | // Implementation of the JavaScript API | |
@@ -2690,6 +2719,7 @@ Http2Session::Http2Ping* Http2Session::PopPing() { | |||
| 2690 | 2719 | if (!outstanding_pings_.empty()) { | |
| 2691 | 2720 | ping = outstanding_pings_.front(); | |
| 2692 | 2721 | outstanding_pings_.pop(); | |
| 2722 | + DecrementCurrentSessionMemory(ping->self_size()); | ||
| 2693 | 2723 | } | |
| 2694 | 2724 | return ping; | |
| 2695 | 2725 | } | |
@@ -2698,6 +2728,7 @@ bool Http2Session::AddPing(Http2Session::Http2Ping* ping) { | |||
| 2698 | 2728 | if (outstanding_pings_.size() == max_outstanding_pings_) | |
| 2699 | 2729 | return false; | |
| 2700 | 2730 | outstanding_pings_.push(ping); | |
| 2731 | + IncrementCurrentSessionMemory(ping->self_size()); | ||
| 2701 | 2732 | return true; | |
| 2702 | 2733 | } | |
| 2703 | 2734 | ||
@@ -2706,6 +2737,7 @@ Http2Session::Http2Settings* Http2Session::PopSettings() { | |||
| 2706 | 2737 | if (!outstanding_settings_.empty()) { | |
| 2707 | 2738 | settings = outstanding_settings_.front(); | |
| 2708 | 2739 | outstanding_settings_.pop(); | |
| 2740 | + DecrementCurrentSessionMemory(settings->self_size()); | ||
| 2709 | 2741 | } | |
| 2710 | 2742 | return settings; | |
| 2711 | 2743 | } | |
@@ -2714,6 +2746,7 @@ bool Http2Session::AddSettings(Http2Session::Http2Settings* settings) { | |||
| 2714 | 2746 | if (outstanding_settings_.size() == max_outstanding_settings_) | |
| 2715 | 2747 | return false; | |
| 2716 | 2748 | outstanding_settings_.push(settings); | |
| 2749 | + IncrementCurrentSessionMemory(settings->self_size()); | ||
| 2717 | 2750 | return true; | |
| 2718 | 2751 | } | |
| 2719 | 2752 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -82,6 +82,9 @@ void inline debug_vfprintf(const char* format, ...) { | |||
| 82 | 82 | // Also strictly limit the number of outstanding SETTINGS frames a user sends | |
| 83 | 83 | #define DEFAULT_MAX_SETTINGS 10 | |
| 84 | 84 | ||
| 85 | + // Default maximum total memory cap for Http2Session. | ||
| 86 | + #define DEFAULT_MAX_SESSION_MEMORY 1e7; | ||
| 87 | + | ||
| 85 | 88 | // These are the standard HTTP/2 defaults as specified by the RFC | |
| 86 | 89 | #define DEFAULT_SETTINGS_HEADER_TABLE_SIZE 4096 | |
| 87 | 90 | #define DEFAULT_SETTINGS_ENABLE_PUSH 1 | |
@@ -500,8 +503,17 @@ class Http2Options { | |||
| 500 | 503 | return max_outstanding_settings_; | |
| 501 | 504 | } | |
| 502 | 505 | ||
| 506 | + void SetMaxSessionMemory(uint64_t max) { | ||
| 507 | + max_session_memory_ = max; | ||
| 508 | + } | ||
| 509 | + | ||
| 510 | + uint64_t GetMaxSessionMemory() { | ||
| 511 | + return max_session_memory_; | ||
| 512 | + } | ||
| 513 | + | ||
| 503 | 514 | private: | |
| 504 | 515 | nghttp2_option* options_; | |
| 516 | + uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY; | ||
| 505 | 517 | uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; | |
| 506 | 518 | padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE; | |
| 507 | 519 | size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS; | |
@@ -628,6 +640,9 @@ class Http2Stream : public AsyncWrap, | |||
| 628 | 640 | // Returns the stream identifier for this stream | |
| 629 | 641 | inline int32_t id() const { return id_; } | |
| 630 | 642 | ||
| 643 | + inline void IncrementAvailableOutboundLength(size_t amount); | ||
| 644 | + inline void DecrementAvailableOutboundLength(size_t amount); | ||
| 645 | + | ||
| 631 | 646 | inline bool AddHeader(nghttp2_rcbuf* name, | |
| 632 | 647 | nghttp2_rcbuf* value, | |
| 633 | 648 | uint8_t flags); | |
@@ -848,7 +863,7 @@ class Http2Session : public AsyncWrap { | |||
| 848 | 863 | inline void AddStream(Http2Stream* stream); | |
| 849 | 864 | ||
| 850 | 865 | // Removes a stream instance from this session | |
| 851 | - inline void RemoveStream(int32_t id); | ||
| 866 | + inline void RemoveStream(Http2Stream* stream); | ||
| 852 | 867 | ||
| 853 | 868 | // Write data to the session | |
| 854 | 869 | inline ssize_t Write(const uv_buf_t* bufs, size_t nbufs); | |
@@ -906,6 +921,30 @@ class Http2Session : public AsyncWrap { | |||
| 906 | 921 | Http2Settings* PopSettings(); | |
| 907 | 922 | bool AddSettings(Http2Settings* settings); | |
| 908 | 923 | ||
| 924 | + void IncrementCurrentSessionMemory(uint64_t amount) { | ||
| 925 | + current_session_memory_ += amount; | ||
| 926 | + } | ||
| 927 | + | ||
| 928 | + void DecrementCurrentSessionMemory(uint64_t amount) { | ||
| 929 | + current_session_memory_ -= amount; | ||
| 930 | + } | ||
| 931 | + | ||
| 932 | + // Returns the current session memory including the current size of both | ||
| 933 | + // the inflate and deflate hpack headers, the current outbound storage | ||
| 934 | + // queue, and pending writes. | ||
| 935 | + uint64_t GetCurrentSessionMemory() { | ||
| 936 | + uint64_t total = current_session_memory_ + sizeof(Http2Session); | ||
| 937 | + total += nghttp2_session_get_hd_deflate_dynamic_table_size(session_); | ||
| 938 | + total += nghttp2_session_get_hd_inflate_dynamic_table_size(session_); | ||
| 939 | + total += outgoing_storage_.size(); | ||
| 940 | + return total; | ||
| 941 | + } | ||
| 942 | + | ||
| 943 | + // Return true if current_session_memory + amount is less than the max | ||
| 944 | + bool IsAvailableSessionMemory(uint64_t amount) { | ||
| 945 | + return GetCurrentSessionMemory() + amount <= max_session_memory_; | ||
| 946 | + } | ||
| 947 | + | ||
| 909 | 948 | struct Statistics { | |
| 910 | 949 | uint64_t start_time; | |
| 911 | 950 | uint64_t end_time; | |
@@ -1035,6 +1074,10 @@ class Http2Session : public AsyncWrap { | |||
| 1035 | 1074 | // The maximum number of header pairs permitted for streams on this session | |
| 1036 | 1075 | uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; | |
| 1037 | 1076 | ||
| 1077 | + // The maximum amount of memory allocated for this session | ||
| 1078 | + uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY; | ||
| 1079 | + uint64_t current_session_memory_ = 0; | ||
| 1080 | + | ||
| 1038 | 1081 | // The collection of active Http2Streams associated with this session | |
| 1039 | 1082 | std::unordered_map<int32_t, Http2Stream*> streams_; | |
| 1040 | 1083 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -50,6 +50,7 @@ namespace http2 { | |||
| 50 | 50 | IDX_OPTIONS_MAX_HEADER_LIST_PAIRS, | |
| 51 | 51 | IDX_OPTIONS_MAX_OUTSTANDING_PINGS, | |
| 52 | 52 | IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS, | |
| 53 | + IDX_OPTIONS_MAX_SESSION_MEMORY, | ||
| 53 | 54 | IDX_OPTIONS_FLAGS | |
| 54 | 55 | }; | |
| 55 | 56 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,7 +20,8 @@ const IDX_OPTIONS_PADDING_STRATEGY = 4; | |||
| 20 | 20 | const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5; | |
| 21 | 21 | const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6; | |
| 22 | 22 | const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7; | |
| 23 | - const IDX_OPTIONS_FLAGS = 8; | ||
| 23 | + const IDX_OPTIONS_MAX_SESSION_MEMORY = 8; | ||
| 24 | + const IDX_OPTIONS_FLAGS = 9; | ||
| 24 | 25 | ||
| 25 | 26 | { | |
| 26 | 27 | updateOptionsBuffer({ | |
@@ -31,7 +32,8 @@ const IDX_OPTIONS_FLAGS = 8; | |||
| 31 | 32 | paddingStrategy: 5, | |
| 32 | 33 | maxHeaderListPairs: 6, | |
| 33 | 34 | maxOutstandingPings: 7, | |
| 34 | - maxOutstandingSettings: 8 | ||
| 35 | + maxOutstandingSettings: 8, | ||
| 36 | + maxSessionMemory: 9 | ||
| 35 | 37 | }); | |
| 36 | 38 | ||
| 37 | 39 | strictEqual(optionsBuffer[IDX_OPTIONS_MAX_DEFLATE_DYNAMIC_TABLE_SIZE], 1); | |
@@ -42,6 +44,7 @@ const IDX_OPTIONS_FLAGS = 8; | |||
| 42 | 44 | strictEqual(optionsBuffer[IDX_OPTIONS_MAX_HEADER_LIST_PAIRS], 6); | |
| 43 | 45 | strictEqual(optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_PINGS], 7); | |
| 44 | 46 | strictEqual(optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS], 8); | |
| 47 | + strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SESSION_MEMORY], 9); | ||
| 45 | 48 | ||
| 46 | 49 | const flags = optionsBuffer[IDX_OPTIONS_FLAGS]; | |
| 47 | 50 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,44 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + if (!common.hasCrypto) | ||
| 5 | + common.skip('missing crypto'); | ||
| 6 | + | ||
| 7 | + const http2 = require('http2'); | ||
| 8 | + | ||
| 9 | + // Test that maxSessionMemory Caps work | ||
| 10 | + | ||
| 11 | + const largeBuffer = Buffer.alloc(1e6); | ||
| 12 | + | ||
| 13 | + const server = http2.createServer({ maxSessionMemory: 1 }); | ||
| 14 | + | ||
| 15 | + server.on('stream', common.mustCall((stream) => { | ||
| 16 | + stream.respond(); | ||
| 17 | + stream.end(largeBuffer); | ||
| 18 | + })); | ||
| 19 | + | ||
| 20 | + server.listen(0, common.mustCall(() => { | ||
| 21 | + const client = http2.connect(`http://localhost:${server.address().port}`); | ||
| 22 | + | ||
| 23 | + { | ||
| 24 | + const req = client.request(); | ||
| 25 | + | ||
| 26 | + req.on('response', () => { | ||
| 27 | + // This one should be rejected because the server is over budget | ||
| 28 | + // on the current memory allocation | ||
| 29 | + const req = client.request(); | ||
| 30 | + req.on('error', common.expectsError({ | ||
| 31 | + code: 'ERR_HTTP2_STREAM_ERROR', | ||
| 32 | + type: Error, | ||
| 33 | + message: 'Stream closed with error code 11' | ||
| 34 | + })); | ||
| 35 | + req.on('close', common.mustCall(() => { | ||
| 36 | + server.close(); | ||
| 37 | + client.destroy(); | ||
| 38 | + })); | ||
| 39 | + }); | ||
| 40 | + | ||
| 41 | + req.resume(); | ||
| 42 | + req.on('close', common.mustCall()); | ||
| 43 | + } | ||
| 44 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments