public Http2Connection connection() { return encoder.connection(); }
@Override public Http2Connection connection() { return delegate.connection(); }
public PrefaceDecoder(ChannelHandlerContext ctx) throws Exception { clientPrefaceString = clientPrefaceString(encoder.connection()); // This handler was just added to the context. In case it was handled after // the connection became active, send the connection preface now. sendPreface(ctx); }
/** * Returns {@code true} if the stream with the given {@code streamId} has been created and is writable. * Note that this method will return {@code false} for the stream which was not created yet. */ private boolean isStreamPresentAndWritable(int streamId) { final Http2Stream stream = encoder.connection().stream(streamId); if (stream == null) { return false; } switch (stream.state()) { case RESERVED_LOCAL: case OPEN: case HALF_CLOSED_REMOTE: return true; default: // The response has been sent already. return false; } }
protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings) { this.initialSettings = checkNotNull(initialSettings, "initialSettings"); this.decoder = checkNotNull(decoder, "decoder"); this.encoder = checkNotNull(encoder, "encoder"); if (encoder.connection() != decoder.connection()) { throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object"); } }
Http2ResponseDecoder(Channel channel, Http2ConnectionEncoder encoder, HttpClientFactory clientFactory) { super(channel, InboundTrafficController.ofHttp2(channel, clientFactory.http2InitialConnectionWindowSize())); conn = encoder.connection(); this.encoder = encoder; goAwayHandler = new Http2GoAwayHandler(); }
@Override protected ChannelFuture doWriteReset(int id, int streamId, Http2Error error) { final Http2Stream stream = encoder.connection().stream(streamId); // Send a RST_STREAM frame only for an active stream which did not send a RST_STREAM frame already. if (stream != null && !stream.isResetSent()) { return encoder.writeRstStream(ctx, streamId, error.code(), ctx.newPromise()); } return ctx.writeAndFlush(Unpooled.EMPTY_BUFFER); }
@Override public HttpConnection setWindowSize(int windowSize) { try { Http2Stream stream = handler.encoder().connection().connectionStream(); int delta = windowSize - this.windowSize; handler.decoder().flowController().incrementWindowSize(stream, delta); this.windowSize = windowSize; return this; } catch (Http2Exception e) { throw new VertxException(e); } }
@Override public void push(final String method, final String path, final Map<String, Object> headers) { ctx.channel().eventLoop().execute(() -> { AsciiString streamIdHeader = HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(); Http2Connection connection = encoder.connection(); int nextStreamId = connection.local().incrementAndGetNextStreamId(); Http2Headers h2headers = new DefaultHttp2Headers() .path(path) .method(method) .authority(authority) .scheme(scheme); headers.forEach((n, v) -> h2headers.add(n, v.toString())); encoder.writePushPromise(ctx, streamId, nextStreamId, h2headers, 0, ctx.newPromise()); // TODO: Is there another way of handling a push promise? DefaultFullHttpRequest pushRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(method.toUpperCase()), path, Unpooled.EMPTY_BUFFER, new DefaultHttpHeaders(false).set(streamIdHeader, nextStreamId), EmptyHttpHeaders.INSTANCE); ctx.pipeline().fireChannelRead(pushRequest); ctx.pipeline().fireChannelReadComplete(); }); }
@Override protected ChannelFuture doWriteData(int id, int streamId, HttpData data, boolean endStream) { if (isStreamPresentAndWritable(streamId)) { // Write to an existing stream. return encoder.writeData(ctx, streamId, toByteBuf(data), 0, endStream, ctx.newPromise()); } if (encoder.connection().local().mayHaveCreatedStream(streamId)) { // Can't write to an outdated (closed) stream. ReferenceCountUtil.safeRelease(data); return data.isEmpty() ? ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) : newFailedFuture(ClosedPublisherException.get()); } // Cannot start a new stream with a DATA frame. It must start with a HEADERS frame. ReferenceCountUtil.safeRelease(data); return newFailedFuture(new IllegalStateException( "cannot start a new stream " + streamId + " with a DATA frame")); }
/** * Sets the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} to use. */ protected B codec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) { enforceConstraint("codec", "server", isServer); enforceConstraint("codec", "maxReservedStreams", maxReservedStreams); enforceConstraint("codec", "connection", connection); enforceConstraint("codec", "frameLogger", frameLogger); enforceConstraint("codec", "validateHeaders", validateHeaders); enforceConstraint("codec", "headerSensitivityDetector", headerSensitivityDetector); enforceConstraint("codec", "encoderEnforceMaxConcurrentStreams", encoderEnforceMaxConcurrentStreams); checkNotNull(decoder, "decoder"); checkNotNull(encoder, "encoder"); if (decoder.connection() != encoder.connection()) { throw new IllegalArgumentException("The specified encoder and decoder have different connections."); } this.decoder = decoder; this.encoder = encoder; return self(); }
private void writeErrorResponse(ChannelHandlerContext ctx, int streamId, HttpResponseStatus status) throws Http2Exception { final byte[] content = status.toString().getBytes(StandardCharsets.UTF_8); writer.writeHeaders( ctx, streamId, new DefaultHttp2Headers(false) .status(status.codeAsText()) .set(HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8.toString()) .setInt(HttpHeaderNames.CONTENT_LENGTH, content.length), 0, false, ctx.voidPromise()); writer.writeData(ctx, streamId, Unpooled.wrappedBuffer(content), 0, true, ctx.voidPromise()); final Http2Stream stream = writer.connection().stream(streamId); if (stream != null && writer.flowController().hasFlowControlled(stream)) { // Ensure to flush the error response if it's flow-controlled so that it is sent // before an RST_STREAM frame. writer.flowController().writePendingBytes(); } }
@Override protected ChannelFuture doWriteHeaders(int id, int streamId, HttpHeaders headers, boolean endStream) { final Http2Connection conn = encoder.connection(); final boolean server = conn.isServer(); if (isStreamPresentAndWritable(streamId)) { // Writing to an existing stream. return encoder.writeHeaders(ctx, streamId, ArmeriaHttpUtil.toNettyHttp2(headers, server), 0, endStream, ctx.newPromise()); } if (server) { // One of the following cases: // - Stream has been closed already. // - (bug) Server tried to send a response HEADERS frame before receiving a request HEADERS frame. return newFailedFuture(ClosedPublisherException.get()); } if (conn.local().mayHaveCreatedStream(streamId)) { // Stream has been closed. return newFailedFuture(ClosedPublisherException.get()); } // Client starts a new stream. return encoder.writeHeaders( ctx, streamId, ArmeriaHttpUtil.toNettyHttp2(headers, server), 0, endStream, ctx.newPromise()); }
final Http2Stream stream = writer.connection().stream(streamId); if (isWritable(stream)) { writeErrorResponse(ctx, streamId, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE);
stream = encoder.connection().remote().createStream(streamId, true); } catch (Http2Exception e) { resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
@Override public HttpConnection setWindowSize(int windowSize) { try { Http2Stream stream = handler.encoder().connection().connectionStream(); int delta = windowSize - this.windowSize; handler.decoder().flowController().incrementWindowSize(stream, delta); this.windowSize = windowSize; return this; } catch (Http2Exception e) { throw new VertxException(e); } }
@Override public Http2Connection connection() { return delegate.connection(); }
public PrefaceDecoder(ChannelHandlerContext ctx) throws Exception { clientPrefaceString = clientPrefaceString(encoder.connection()); // This handler was just added to the context. In case it was handled after // the connection became active, send the connection preface now. sendPreface(ctx); }
protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings) { this.initialSettings = checkNotNull(initialSettings, "initialSettings"); this.decoder = checkNotNull(decoder, "decoder"); this.encoder = checkNotNull(encoder, "encoder"); if (encoder.connection() != decoder.connection()) { throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object"); } }
protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings) { this.initialSettings = checkNotNull(initialSettings, "initialSettings"); this.decoder = checkNotNull(decoder, "decoder"); this.encoder = checkNotNull(encoder, "encoder"); if (encoder.connection() != decoder.connection()) { throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object"); } }