| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1009,6 +1009,21 @@ int Http2Session::OnInvalidFrame(nghttp2_session* handle, | |||
| 1009 | 1009 | return 0; | |
| 1010 | 1010 | } | |
| 1011 | 1011 | ||
| 1012 | + // Remove the headers reference. | ||
| 1013 | + // Implicitly calls nghttp2_rcbuf_decref | ||
| 1014 | + void Http2Session::DecrefHeaders(const nghttp2_frame* frame) { | ||
| 1015 | + int32_t id = GetFrameID(frame); | ||
| 1016 | + BaseObjectPtr<Http2Stream> stream = FindStream(id); | ||
| 1017 | + | ||
| 1018 | + if (stream && !stream->is_destroyed() && stream->headers_count() > 0) { | ||
| 1019 | + Debug(this, "freeing headers for stream %d", id); | ||
| 1020 | + stream->ClearHeaders(); | ||
| 1021 | + CHECK_EQ(stream->headers_count(), 0); | ||
| 1022 | + DecrementCurrentSessionMemory(stream->current_headers_length_); | ||
| 1023 | + stream->current_headers_length_ = 0; | ||
| 1024 | + } | ||
| 1025 | + } | ||
| 1026 | + | ||
| 1012 | 1027 | // If nghttp2 is unable to send a queued up frame, it will call this callback | |
| 1013 | 1028 | // to let us know. If the failure occurred because we are in the process of | |
| 1014 | 1029 | // closing down the session or stream, we go ahead and ignore it. We don't | |
@@ -1029,6 +1044,11 @@ int Http2Session::OnFrameNotSent(nghttp2_session* handle, | |||
| 1029 | 1044 | error_code == NGHTTP2_ERR_STREAM_CLOSED || | |
| 1030 | 1045 | error_code == NGHTTP2_ERR_STREAM_CLOSING || | |
| 1031 | 1046 | session->js_fields_->frame_error_listener_count == 0) { | |
| 1047 | + // Nghttp2 contains header limit of 65536. When this value is exceeded the | ||
| 1048 | + // pipeline is stopped and we should remove the current headers reference | ||
| 1049 | + // to destroy the session completely. | ||
| 1050 | + // Further information see: https://github.com/nodejs/node/issues/35233 | ||
| 1051 | + session->DecrefHeaders(frame); | ||
| 1032 | 1052 | return 0; | |
| 1033 | 1053 | } | |
| 1034 | 1054 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -401,6 +401,10 @@ class Http2Stream : public AsyncWrap, | |||
| 401 | 401 | size_t i = 0; | |
| 402 | 402 | for (const auto& header : current_headers_ ) | |
| 403 | 403 | fn(header, i++); | |
| 404 | + ClearHeaders(); | ||
| 405 | + } | ||
| 406 | + | ||
| 407 | + void ClearHeaders() { | ||
| 404 | 408 | current_headers_.clear(); | |
| 405 | 409 | } | |
| 406 | 410 | ||
@@ -787,6 +791,8 @@ class Http2Session : public AsyncWrap, | |||
| 787 | 791 | void HandleAltSvcFrame(const nghttp2_frame* frame); | |
| 788 | 792 | void HandleOriginFrame(const nghttp2_frame* frame); | |
| 789 | 793 | ||
| 794 | + void DecrefHeaders(const nghttp2_frame* frame); | ||
| 795 | + | ||
| 790 | 796 | // nghttp2 callbacks | |
| 791 | 797 | static int OnBeginHeadersCallback( | |
| 792 | 798 | nghttp2_session* session, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,46 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + if (!common.hasCrypto) | ||
| 5 | + common.skip('missing crypto'); | ||
| 6 | + const h2 = require('http2'); | ||
| 7 | + | ||
| 8 | + const server = h2.createServer(); | ||
| 9 | + | ||
| 10 | + server.on('stream', common.mustNotCall()); | ||
| 11 | + server.on('error', common.mustNotCall()); | ||
| 12 | + | ||
| 13 | + server.listen(0, common.mustCall(() => { | ||
| 14 | + | ||
| 15 | + // Setting the maxSendHeaderBlockLength > nghttp2 threshold | ||
| 16 | + // cause a 'sessionError' and no memory leak when session destroy | ||
| 17 | + const options = { | ||
| 18 | + maxSendHeaderBlockLength: 100000 | ||
| 19 | + }; | ||
| 20 | + | ||
| 21 | + const client = h2.connect(`http://localhost:${server.address().port}`, | ||
| 22 | + options); | ||
| 23 | + client.on('error', common.expectsError({ | ||
| 24 | + code: 'ERR_HTTP2_SESSION_ERROR', | ||
| 25 | + name: 'Error', | ||
| 26 | + message: 'Session closed with error code 9' | ||
| 27 | + })); | ||
| 28 | + | ||
| 29 | + const req = client.request({ | ||
| 30 | + // Greater than 65536 bytes | ||
| 31 | + 'test-header': 'A'.repeat(90000) | ||
| 32 | + }); | ||
| 33 | + req.on('response', common.mustNotCall()); | ||
| 34 | + | ||
| 35 | + req.on('close', common.mustCall(() => { | ||
| 36 | + client.close(); | ||
| 37 | + server.close(); | ||
| 38 | + })); | ||
| 39 | + | ||
| 40 | + req.on('error', common.expectsError({ | ||
| 41 | + code: 'ERR_HTTP2_SESSION_ERROR', | ||
| 42 | + name: 'Error', | ||
| 43 | + message: 'Session closed with error code 9' | ||
| 44 | + })); | ||
| 45 | + req.end(); | ||
| 46 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments