@@ -650,6 +650,7 @@ Http2Session::~Http2Session() {
650650 stream.second ->session_ = nullptr ;
651651 nghttp2_session_del (session_);
652652 CHECK_EQ (current_nghttp2_memory_, 0 );
653+ free (stream_buf_allocation_.base );
653654}
654655
655656std::string Http2Session::diagnostic_name () const {
@@ -1259,7 +1260,17 @@ void Http2StreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
12591260 return ;
12601261 }
12611262
1262- CHECK (!session->stream_buf_ab_ .IsEmpty ());
1263+ Local<ArrayBuffer> ab;
1264+ if (session->stream_buf_ab_ .IsEmpty ()) {
1265+ ab = ArrayBuffer::New (env->isolate (),
1266+ session->stream_buf_allocation_ .base ,
1267+ session->stream_buf_allocation_ .len ,
1268+ v8::ArrayBufferCreationMode::kInternalized );
1269+ session->stream_buf_allocation_ = uv_buf_init (nullptr , 0 );
1270+ session->stream_buf_ab_ .Reset (env->isolate (), ab);
1271+ } else {
1272+ ab = session->stream_buf_ab_ .Get (env->isolate ());
1273+ }
12631274
12641275 // There is a single large array buffer for the entire data read from the
12651276 // network; create a slice of that array buffer and emit it as the
@@ -1271,7 +1282,7 @@ void Http2StreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
12711282 CHECK_LE (offset + buf.len , session->stream_buf_ .len );
12721283
12731284 Local<Object> buffer =
1274- Buffer::New (env, session-> stream_buf_ab_ , offset, nread).ToLocalChecked ();
1285+ Buffer::New (env, ab , offset, nread).ToLocalChecked ();
12751286
12761287 stream->CallJSOnreadMethod (nread, buffer);
12771288}
@@ -1803,32 +1814,41 @@ Http2Stream* Http2Session::SubmitRequest(
18031814}
18041815
18051816// Callback used to receive inbound data from the i/o stream
1806- void Http2Session::OnStreamRead (ssize_t nread, const uv_buf_t & buf ) {
1817+ void Http2Session::OnStreamRead (ssize_t nread, const uv_buf_t & buf_ ) {
18071818 HandleScope handle_scope (env ()->isolate ());
18081819 Context::Scope context_scope (env ()->context ());
18091820 Http2Scope h2scope (this );
18101821 CHECK_NOT_NULL (stream_);
18111822 Debug (this , " receiving %d bytes" , nread);
1812- IncrementCurrentSessionMemory (buf. len );
1823+ CHECK_EQ (stream_buf_allocation_. base , nullptr );
18131824 CHECK (stream_buf_ab_.IsEmpty ());
18141825
1815- OnScopeLeave on_scope_leave ([&]() {
1816- // Once finished handling this write, reset the stream buffer.
1817- // The memory has either been free()d or was handed over to V8.
1818- DecrementCurrentSessionMemory (buf.len );
1819- stream_buf_ab_ = Local<ArrayBuffer>();
1820- stream_buf_ = uv_buf_init (nullptr , 0 );
1821- });
1822-
18231826 // Only pass data on if nread > 0
18241827 if (nread <= 0 ) {
1825- free (buf .base );
1828+ free (buf_ .base );
18261829 if (nread < 0 ) {
18271830 PassReadErrorToPreviousListener (nread);
18281831 }
18291832 return ;
18301833 }
18311834
1835+ // Shrink to the actual amount of used data.
1836+ uv_buf_t buf = buf_;
1837+ buf.base = Realloc (buf.base , nread);
1838+
1839+ IncrementCurrentSessionMemory (nread);
1840+ OnScopeLeave on_scope_leave ([&]() {
1841+ // Once finished handling this write, reset the stream buffer.
1842+ // The memory has either been free()d or was handed over to V8.
1843+ // We use `nread` instead of `buf.size()` here, because the buffer is
1844+ // cleared as part of the `.ToArrayBuffer()` call below.
1845+ DecrementCurrentSessionMemory (nread);
1846+ stream_buf_ab_.Reset ();
1847+ free (stream_buf_allocation_.base );
1848+ stream_buf_allocation_ = uv_buf_init (nullptr , 0 );
1849+ stream_buf_ = uv_buf_init (nullptr , 0 );
1850+ });
1851+
18321852 // Make sure that there was no read previously active.
18331853 CHECK_NULL (stream_buf_.base );
18341854 CHECK_EQ (stream_buf_.len , 0 );
@@ -1845,13 +1865,10 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
18451865
18461866 Isolate* isolate = env ()->isolate ();
18471867
1848- // Create an array buffer for the read data. DATA frames will be emitted
1849- // as slices of this array buffer to avoid having to copy memory.
1850- stream_buf_ab_ =
1851- ArrayBuffer::New (isolate,
1852- buf.base ,
1853- nread,
1854- v8::ArrayBufferCreationMode::kInternalized );
1868+ // Store this so we can create an ArrayBuffer for read data from it.
1869+ // DATA frames will be emitted as slices of that ArrayBuffer to avoid having
1870+ // to copy memory.
1871+ stream_buf_allocation_ = buf;
18551872
18561873 statistics_.data_received += nread;
18571874 ssize_t ret = Write (&stream_buf_, 1 );
0 commit comments