@@ -845,6 +845,10 @@ function requestOnConnect(headersList, options) { |
845 | 845 | } |
846 | 846 | } |
847 | 847 |
|
| 848 | +function requestOnError(error) { |
| 849 | + this.destroy(error); |
| 850 | +} |
| 851 | + |
848 | 852 | // Validates that priority options are correct, specifically: |
849 | 853 | // 1. options.weight must be a number |
850 | 854 | // 2. options.parent must be a positive number |
@@ -1160,7 +1164,7 @@ function setupHandle(socket, type, options) { |
1160 | 1164 | process.nextTick(emit, this, 'connect', this, socket); |
1161 | 1165 | } |
1162 | 1166 |
|
1163 | | -// Emits a close event followed by an error event if err is truthy. Used |
| 1167 | +// Emits an error event followed by a close event if err is truthy. Used |
1164 | 1168 | // by Http2Session.prototype.destroy() |
1165 | 1169 | function emitClose(self, error) { |
1166 | 1170 | if (error) |
@@ -1231,17 +1235,16 @@ function closeSession(session, code, error) { |
1231 | 1235 | session.setTimeout(0); |
1232 | 1236 | session.removeAllListeners('timeout'); |
1233 | 1237 |
|
| 1238 | + const socket = session[kSocket]; |
| 1239 | + const handle = session[kHandle]; |
| 1240 | + |
1234 | 1241 | // Destroy any pending and open streams |
1235 | 1242 | if (state.pendingStreams.size > 0 || state.streams.size > 0) { |
1236 | 1243 | const cancel = new ERR_HTTP2_STREAM_CANCEL(error); |
1237 | 1244 | state.pendingStreams.forEach((stream) => stream.destroy(cancel)); |
1238 | 1245 | state.streams.forEach((stream) => stream.destroy(error)); |
1239 | 1246 | } |
1240 | 1247 |
|
1241 | | - // Disassociate from the socket and server. |
1242 | | - const socket = session[kSocket]; |
1243 | | - const handle = session[kHandle]; |
1244 | | - |
1245 | 1248 | // Destroy the handle if it exists at this point. |
1246 | 1249 | if (handle !== undefined) { |
1247 | 1250 | handle.ondone = finishSessionClose.bind(null, session, error); |
@@ -1816,11 +1819,15 @@ class ClientHttp2Session extends Http2Session { |
1816 | 1819 | request(headersParam, options) { |
1817 | 1820 | debugSessionObj(this, 'initiating request'); |
1818 | 1821 |
|
1819 | | - if (this.destroyed) |
1820 | | - throw new ERR_HTTP2_INVALID_SESSION(); |
1821 | | - |
1822 | | - if (this.closed) |
1823 | | - throw new ERR_HTTP2_GOAWAY_SESSION(); |
| 1822 | + // Keep argument validation synchronous, but defer session-state failures |
| 1823 | + // to the returned stream so request retries from stream callbacks do not |
| 1824 | + // throw before session lifecycle handlers run. |
| 1825 | + let requestError; |
| 1826 | + if (this.destroyed) { |
| 1827 | + requestError = new ERR_HTTP2_INVALID_SESSION(); |
| 1828 | + } else if (this.closed) { |
| 1829 | + requestError = new ERR_HTTP2_GOAWAY_SESSION(); |
| 1830 | + } |
1824 | 1831 |
|
1825 | 1832 | this[kUpdateTimer](); |
1826 | 1833 |
|
@@ -1906,19 +1913,24 @@ class ClientHttp2Session extends Http2Session { |
1906 | 1913 | } |
1907 | 1914 | } |
1908 | 1915 |
|
1909 | | - const onConnect = reqAsync.bind(requestOnConnect.bind(stream, headersList, options)); |
1910 | | - if (this.connecting) { |
1911 | | - if (this[kPendingRequestCalls] !== null) { |
1912 | | - this[kPendingRequestCalls].push(onConnect); |
| 1916 | + if (requestError) { |
| 1917 | + process.nextTick(reqAsync.bind(requestOnError.bind(stream, requestError))); |
| 1918 | + } else { |
| 1919 | + const onConnect = reqAsync.bind( |
| 1920 | + requestOnConnect.bind(stream, headersList, options)); |
| 1921 | + if (this.connecting) { |
| 1922 | + if (this[kPendingRequestCalls] !== null) { |
| 1923 | + this[kPendingRequestCalls].push(onConnect); |
| 1924 | + } else { |
| 1925 | + this[kPendingRequestCalls] = [onConnect]; |
| 1926 | + this.once('connect', () => { |
| 1927 | + this[kPendingRequestCalls].forEach((f) => f()); |
| 1928 | + this[kPendingRequestCalls] = null; |
| 1929 | + }); |
| 1930 | + } |
1913 | 1931 | } else { |
1914 | | - this[kPendingRequestCalls] = [onConnect]; |
1915 | | - this.once('connect', () => { |
1916 | | - this[kPendingRequestCalls].forEach((f) => f()); |
1917 | | - this[kPendingRequestCalls] = null; |
1918 | | - }); |
| 1932 | + onConnect(); |
1919 | 1933 | } |
1920 | | - } else { |
1921 | | - onConnect(); |
1922 | 1934 | } |
1923 | 1935 |
|
1924 | 1936 | if (onClientStreamCreatedChannel.hasSubscribers) { |
|