コード例 #1
0
  @Override
  public ChannelFuture resetStream(
      final ChannelHandlerContext ctx, int streamId, long errorCode, final ChannelPromise promise) {
    final Http2Stream stream = connection().stream(streamId);
    if (stream == null || stream.isResetSent()) {
      // Don't write a RST_STREAM frame if we are not aware of the stream, or if we have already
      // written one.
      return promise.setSuccess();
    }

    ChannelFuture future = frameWriter().writeRstStream(ctx, streamId, errorCode, promise);

    // Synchronously set the resetSent flag to prevent any subsequent calls
    // from resulting in multiple reset frames being sent.
    stream.resetSent();

    future.addListener(
        new ChannelFutureListener() {
          @Override
          public void operationComplete(ChannelFuture future) throws Exception {
            if (future.isSuccess()) {
              closeStream(stream, promise);
            } else {
              // The connection will be closed and so no need to change the resetSent flag to false.
              onConnectionError(ctx, future.cause(), null);
            }
          }
        });

    return future;
  }
コード例 #2
0
 /**
  * Closes the remote side of the given stream. If this causes the stream to be closed, adds a hook
  * to close the channel after the given future completes.
  *
  * @param stream the stream to be half closed.
  * @param future If closing, the future after which to close the channel.
  */
 @Override
 public void closeStreamRemote(Http2Stream stream, ChannelFuture future) {
   switch (stream.state()) {
     case HALF_CLOSED_REMOTE:
     case OPEN:
       stream.closeRemoteSide();
       break;
     default:
       closeStream(stream, future);
       break;
   }
 }
コード例 #3
0
 /**
  * Closes the local side of the given stream. If this causes the stream to be closed, adds a hook
  * to close the channel after the given future completes.
  *
  * @param stream the stream to be half closed.
  * @param future If closing, the future after which to close the channel.
  */
 @Override
 public void closeStreamLocal(Http2Stream stream, ChannelFuture future) {
   switch (stream.state()) {
     case HALF_CLOSED_LOCAL:
     case OPEN:
       stream.closeLocalSide();
       break;
     default:
       closeStream(stream, future);
       break;
   }
 }
コード例 #4
0
 @Override
 public void streamRemoved(Http2Stream stream) {
   final EmbeddedChannel decoder = stream.decompressor();
   if (decoder != null) {
     cleanup(stream, decoder);
   }
 }
コード例 #5
0
  @Override
  protected void notifyListenerOnDataRead(
      ChannelHandlerContext ctx,
      int streamId,
      ByteBuf data,
      int padding,
      boolean endOfStream,
      Http2FrameListener listener)
      throws Http2Exception {
    final Http2Stream stream = connection.stream(streamId);
    final EmbeddedChannel decoder = stream == null ? null : stream.decompressor();
    if (decoder == null) {
      super.notifyListenerOnDataRead(ctx, streamId, data, padding, endOfStream, listener);
    } else {
      // call retain here as it will call release after its written to the channel
      decoder.writeInbound(data.retain());
      ByteBuf buf = nextReadableBuf(decoder);
      if (buf == null) {
        if (endOfStream) {
          super.notifyListenerOnDataRead(
              ctx, streamId, Unpooled.EMPTY_BUFFER, padding, true, listener);
        }
        // END_STREAM is not set and the data could not be decoded yet.
        // The assumption has to be there will be more data frames to complete the decode.
        // We don't have enough information here to know if this is an error.
      } else {
        for (; ; ) {
          final ByteBuf nextBuf = nextReadableBuf(decoder);
          if (nextBuf == null) {
            super.notifyListenerOnDataRead(ctx, streamId, buf, padding, endOfStream, listener);
            break;
          } else {
            super.notifyListenerOnDataRead(ctx, streamId, buf, padding, false, listener);
          }
          buf = nextBuf;
        }
      }

      if (endOfStream) {
        cleanup(stream, decoder);
      }
    }
  }
コード例 #6
0
 /**
  * Release remaining content from the {@link EmbeddedChannel} and remove the decoder from the
  * {@link Http2Stream}.
  *
  * @param stream The stream for which {@code decoder} is the decompressor for
  * @param decoder The decompressor for {@code stream}
  */
 private static void cleanup(Http2Stream stream, EmbeddedChannel decoder) {
   if (decoder.finish()) {
     for (; ; ) {
       final ByteBuf buf = decoder.readInbound();
       if (buf == null) {
         break;
       }
       buf.release();
     }
   }
   stream.decompressor(null);
 }
コード例 #7
0
 /**
  * Checks if a new decoder object is needed for the stream identified by {@code streamId}. This
  * method will modify the {@code content-encoding} header contained in {@code builder}.
  *
  * @param streamId The identifier for the headers inside {@code builder}
  * @param builder Object representing headers which have been read
  * @param endOfStream Indicates if the stream has ended
  * @throws Http2Exception If the {@code content-encoding} is not supported
  */
 private void initDecoder(int streamId, Http2Headers headers, boolean endOfStream)
     throws Http2Exception {
   // Convert the names into a case-insensitive map.
   final Http2Stream stream = connection.stream(streamId);
   if (stream != null) {
     EmbeddedChannel decoder = stream.decompressor();
     if (decoder == null) {
       if (!endOfStream) {
         // Determine the content encoding.
         AsciiString contentEncoding = headers.get(CONTENT_ENCODING_LOWER_CASE);
         if (contentEncoding == null) {
           contentEncoding = IDENTITY;
         }
         decoder = newContentDecoder(contentEncoding);
         if (decoder != null) {
           stream.decompressor(decoder);
           // Decode the content and remove or replace the existing headers
           // so that the message looks like a decoded message.
           AsciiString targetContentEncoding = getTargetContentEncoding(contentEncoding);
           if (IDENTITY.equalsIgnoreCase(targetContentEncoding)) {
             headers.remove(CONTENT_ENCODING_LOWER_CASE);
           } else {
             headers.set(CONTENT_ENCODING_LOWER_CASE, targetContentEncoding);
           }
         }
       }
     } else if (endOfStream) {
       cleanup(stream, decoder);
     }
     if (decoder != null) {
       // The content length will be for the compressed data.  Since we will decompress the data
       // this content-length will not be correct.  Instead of queuing messages or delaying sending
       // header frames...just remove the content-length header
       headers.remove(CONTENT_LENGTH_LOWER_CASE);
     }
   }
 }
コード例 #8
0
  @Override
  public void closeStream(final Http2Stream stream, ChannelFuture future) {
    stream.close();

    if (future.isDone()) {
      checkCloseConnection(future);
    } else {
      future.addListener(
          new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
              checkCloseConnection(future);
            }
          });
    }
  }
コード例 #9
0
 @Override
 public void onStreamRemoved(Http2Stream stream) {
   removeMessage(stream.id());
 }