@@ -105,6 +105,8 @@ export class Http2SubchannelCall implements SubchannelCall {
105
105
106
106
private internalError : SystemError | null = null ;
107
107
108
+ private serverEndedCall = false ;
109
+
108
110
constructor (
109
111
private readonly http2Stream : http2 . ClientHttp2Stream ,
110
112
private readonly callEventTracker : CallEventTracker ,
@@ -182,6 +184,7 @@ export class Http2SubchannelCall implements SubchannelCall {
182
184
this . maybeOutputStatus ( ) ;
183
185
} ) ;
184
186
http2Stream . on ( 'close' , ( ) => {
187
+ this . serverEndedCall = true ;
185
188
/* Use process.next tick to ensure that this code happens after any
186
189
* "error" event that may be emitted at about the same time, so that
187
190
* we can bubble up the error message from that event. */
@@ -400,6 +403,7 @@ export class Http2SubchannelCall implements SubchannelCall {
400
403
}
401
404
402
405
private handleTrailers ( headers : http2 . IncomingHttpHeaders ) {
406
+ this . serverEndedCall = true ;
403
407
this . callEventTracker . onStreamEnd ( true ) ;
404
408
let headersString = '' ;
405
409
for ( const header of Object . keys ( headers ) ) {
@@ -445,7 +449,15 @@ export class Http2SubchannelCall implements SubchannelCall {
445
449
private destroyHttp2Stream ( ) {
446
450
// The http2 stream could already have been destroyed if cancelWithStatus
447
451
// is called in response to an internal http2 error.
448
- if ( ! this . http2Stream . destroyed ) {
452
+ if ( this . http2Stream . destroyed ) {
453
+ return ;
454
+ }
455
+ /* If the server ended the call, sending an RST_STREAM is redundant, so we
456
+ * just half close on the client side instead to finish closing the stream.
457
+ */
458
+ if ( this . serverEndedCall ) {
459
+ this . http2Stream . end ( ) ;
460
+ } else {
449
461
/* If the call has ended with an OK status, communicate that when closing
450
462
* the stream, partly to avoid a situation in which we detect an error
451
463
* RST_STREAM as a result after we have the status */
0 commit comments