3131
3232package io .grpc .transport .netty ;
3333
34+ import static io .netty .util .CharsetUtil .UTF_8 ;
35+
3436import com .google .common .base .Preconditions ;
3537
3638import io .grpc .Metadata ;
3739import io .grpc .Status ;
40+ import io .grpc .transport .HttpUtil ;
3841import io .netty .buffer .ByteBuf ;
3942import io .netty .channel .ChannelFuture ;
4043import io .netty .channel .ChannelFutureListener ;
@@ -82,6 +85,7 @@ public PendingStream(CreateStreamCommand command, ChannelPromise promise) {
8285 private final Deque <PendingStream > pendingStreams = new ArrayDeque <PendingStream >();
8386 private final Http2LocalFlowController inboundFlow ;
8487 private Throwable connectionError ;
88+ private Status goAwayStatus ;
8589 private ChannelHandlerContext ctx ;
8690
8791 public NettyClientHandler (Http2Connection connection ,
@@ -185,14 +189,31 @@ private void onRstStreamRead(int streamId)
185189 stream .transportReportStatus (Status .UNKNOWN , false , new Metadata .Trailers ());
186190 }
187191
192+ private void onGoAwayRead (long errorCode , ByteBuf debugData ) {
193+ Status status = HttpUtil .Http2Error .statusForCode ((int ) errorCode );
194+ if (debugData .isReadable ()) {
195+ // If a debug message was provided, use it.
196+ String msg = debugData .toString (UTF_8 );
197+ status = status .withDescription (msg );
198+ }
199+ goAwayStatus (status );
200+ }
201+
202+ @ Override
203+ public void close (ChannelHandlerContext ctx , ChannelPromise promise ) throws Exception {
204+ goAwayStatus (Status .UNAVAILABLE .withDescription ("Network channel closed by the client" ));
205+
206+ super .close (ctx , promise );
207+ }
208+
188209 /**
189210 * Handler for the Channel shutting down.
190211 */
191212 @ Override
192213 public void channelInactive (ChannelHandlerContext ctx ) throws Exception {
193214 try {
194215 // Fail any streams that are awaiting creation.
195- Status goAwayStatus = goAwayStatus ().withDescription ( "network channel closed" );
216+ goAwayStatus ( goAwayStatus ().augmentDescription ( "Network channel closed") );
196217 failPendingStreams (goAwayStatus );
197218
198219 // Report status to the application layer for any open streams
@@ -210,6 +231,7 @@ protected void onConnectionError(ChannelHandlerContext ctx, Throwable cause,
210231 Http2Exception http2Ex ) {
211232 // Save the error.
212233 connectionError = cause ;
234+ goAwayStatus (Status .fromThrowable (connectionError ));
213235
214236 super .onConnectionError (ctx , cause , http2Ex );
215237 }
@@ -317,7 +339,7 @@ private void goingAway() {
317339 */
318340 private void createPendingStreams () {
319341 Http2Connection connection = connection ();
320- Http2Connection .Endpoint local = connection .local ();
342+ Http2Connection .Endpoint < Http2LocalFlowController > local = connection .local ();
321343 Status goAwayStatus = goAwayStatus ();
322344 while (!pendingStreams .isEmpty ()) {
323345 final int streamId = local .nextStreamId ();
@@ -362,12 +384,16 @@ public void operationComplete(ChannelFuture future) throws Exception {
362384 * Returns the appropriate status used to represent the cause for GOAWAY.
363385 */
364386 private Status goAwayStatus () {
365- if (connectionError != null ) {
366- return Status . fromThrowable ( connectionError ) ;
387+ if (goAwayStatus != null ) {
388+ return goAwayStatus ;
367389 }
368390 return Status .UNAVAILABLE ;
369391 }
370392
393+ private void goAwayStatus (Status status ) {
394+ goAwayStatus = goAwayStatus == null ? status : goAwayStatus ;
395+ }
396+
371397 /**
372398 * Handles the successful creation of a new stream.
373399 */
@@ -452,5 +478,11 @@ public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorC
452478 throws Http2Exception {
453479 handler .onRstStreamRead (streamId );
454480 }
481+
482+ @ Override
483+ public void onGoAwayRead (ChannelHandlerContext ctx , int lastStreamId , long errorCode ,
484+ ByteBuf debugData ) throws Http2Exception {
485+ handler .onGoAwayRead (errorCode , debugData );
486+ }
455487 }
456488}
0 commit comments