/** * Equivalent to {@code new DefaultHttp2GoAwayFrame(error.code())}. * * @param error non-{@code null} reason for the go away */ public DefaultHttp2GoAwayFrame(Http2Error error) { this(error.code()); }
/** * * * @param error non-{@code null} reason for the go away * @param content non-{@code null} debug data */ public DefaultHttp2GoAwayFrame(Http2Error error, ByteBuf content) { this(error.code(), content); }
/** * Returns {@code true} if the connection has received a GOAWAY frame with non-zero error code. */ public boolean receivedErrorGoAway() { return goAwayReceived > Http2Error.NO_ERROR.code(); }
/** * Construct a reset message. * * @param error the non-{@code null} reason for reset */ public DefaultHttp2ResetFrame(Http2Error error) { errorCode = checkNotNull(error, "error").code(); }
@Override public void onRstStreamRead(final ChannelHandlerContext context, final int streamId, final long errorCode) { if (errorCode == Http2Error.REFUSED_STREAM.code()) { // This can happen if the server reduces MAX_CONCURRENT_STREAMS while we already have notifications in // flight. We may get multiple RST_STREAM frames per stream since we send multiple frames (HEADERS and // DATA) for each push notification, but we should only get one REFUSED_STREAM error; the rest should all be // STREAM_CLOSED. this.retryPushNotificationFromStream(context, streamId); } }
private static void processGoAwayWriteResult(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode, final ByteBuf debugData, ChannelFuture future) { try { if (future.isSuccess()) { if (errorCode != NO_ERROR.code()) { if (logger.isDebugEnabled()) { logger.debug("{} Sent GOAWAY: lastStreamId '{}', errorCode '{}', " + "debugData '{}'. Forcing shutdown of the connection.", ctx.channel(), lastStreamId, errorCode, debugData.toString(UTF_8), future.cause()); } ctx.close(); } } else { if (logger.isDebugEnabled()) { logger.debug("{} Sending GOAWAY failed: lastStreamId '{}', errorCode '{}', " + "debugData '{}'. Forcing shutdown of the connection.", ctx.channel(), lastStreamId, errorCode, debugData.toString(UTF_8), future.cause()); } ctx.close(); } } finally { // We're done with the debug data now. debugData.release(); } }
/** * Close the remote endpoint with with a {@code GO_AWAY} frame. Does <strong>not</strong> flush * immediately, this is the responsibility of the caller. */ private ChannelFuture goAway(ChannelHandlerContext ctx, Http2Exception cause) { long errorCode = cause != null ? cause.error().code() : NO_ERROR.code(); int lastKnownStream = connection().remote().lastStreamCreated(); return goAway(ctx, lastKnownStream, errorCode, Http2CodecUtil.toByteBuf(ctx, cause), ctx.newPromise()); }
@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); }
encoder.writeRstStream(ctx, streamId, Http2Error.CANCEL.code(), ctx.newPromise()); ctx.flush(); } else {
@Override public synchronized void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId, Http2Headers headers, int padding) throws Http2Exception { Http2ClientStream stream = (Http2ClientStream) streams.get(streamId); if (stream != null) { Handler<HttpClientRequest> pushHandler = stream.pushHandler(); if (pushHandler != null) { context.executeFromIO(v -> { String rawMethod = headers.method().toString(); HttpMethod method = HttpUtils.toVertxMethod(rawMethod); String uri = headers.path().toString(); String host = headers.authority() != null ? headers.authority().toString() : null; MultiMap headersMap = new Http2HeadersAdaptor(headers); Http2Stream promisedStream = handler.connection().stream(promisedStreamId); int port = remoteAddress().port(); HttpClientRequestPushPromise pushReq = new HttpClientRequestPushPromise(this, promisedStream, client, isSsl(), method, rawMethod, uri, host, port, headersMap); if (metrics != null) { pushReq.metric(metrics.responsePushed(queueMetric, metric(), localAddress(), remoteAddress(), pushReq)); } streams.put(promisedStreamId, pushReq.getStream()); pushHandler.handle(pushReq); }); return; } } handler.writeReset(promisedStreamId, Http2Error.CANCEL.code()); }
@Test public void testResetPushPromiseNoHandler() throws Exception { server.requestHandler(req -> { req.response().push(HttpMethod.GET, "/wibble", ar -> { assertTrue(ar.succeeded()); HttpServerResponse resp = ar.result(); resp.setChunked(true).write("content"); AtomicLong reset = new AtomicLong(); resp.exceptionHandler(err -> { if (err instanceof StreamResetException) { reset.set(((StreamResetException)err).getCode()); } }); resp.closeHandler(v -> { assertEquals(Http2Error.CANCEL.code(), reset.get()); testComplete(); }); }); }); startServer(); HttpClientRequest req = client.get(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, "/somepath", resp -> { }); req.end(); await(); }
@Test public void testResetActivePushPromise() throws Exception { server.requestHandler(req -> { req.response().push(HttpMethod.GET, "/wibble", ar -> { assertTrue(ar.succeeded()); HttpServerResponse response = ar.result(); response.exceptionHandler(err -> { if (err instanceof StreamResetException) { assertEquals(Http2Error.CANCEL.code(), ((StreamResetException) err).getCode()); testComplete(); } }); response.setChunked(true).write("some_content"); }); }); startServer(); HttpClientRequest req = client.get(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, "/somepath", onFailure(resp -> { })); req.pushHandler(pushedReq -> { pushedReq.handler(onSuccess(pushedResp -> { pushedResp.handler(buff -> { pushedReq.reset(Http2Error.CANCEL.code()); }); })); }); req.end(); await(); }
stream = encoder.connection().remote().createStream(streamId, true); } catch (Http2Exception e) { resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise()); return; resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise()); resetStream(ctx, stream, http2Ex.error().code(), ctx.newPromise());
@Test public void testResetPendingPushPromise() throws Exception { server.requestHandler(req -> { req.response().push(HttpMethod.GET, "/wibble", ar -> { assertFalse(ar.succeeded()); testComplete(); }); }); startServer(); client.close(); client = vertx.createHttpClient(clientOptions.setInitialSettings(new io.vertx.core.http.Http2Settings().setMaxConcurrentStreams(0L))); HttpClientRequest req = client.get(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, "/somepath", onFailure(resp -> {})); req.pushHandler(pushedReq -> { pushedReq.reset(Http2Error.CANCEL.code()); }); req.end(); await(); }
if (isWritable(stream)) { writeErrorResponse(ctx, streamId, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE); writer.writeRstStream(ctx, streamId, Http2Error.CANCEL.code(), ctx.voidPromise()); if (req.isOpen()) { req.close(ContentTooLargeException.get());
if (stream == null) { if (isMalformedRequest(headers)) { handler.writeReset(streamId, Http2Error.PROTOCOL_ERROR.code()); return;
@Override public synchronized void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId, Http2Headers headers, int padding) throws Http2Exception { Http2ClientStream stream = (Http2ClientStream) streams.get(streamId); if (stream != null) { Handler<HttpClientRequest> pushHandler = stream.pushHandler(); if (pushHandler != null) { context.executeFromIO(v -> { String rawMethod = headers.method().toString(); HttpMethod method = HttpUtils.toVertxMethod(rawMethod); String uri = headers.path().toString(); String host = headers.authority() != null ? headers.authority().toString() : null; MultiMap headersMap = new Http2HeadersAdaptor(headers); Http2Stream promisedStream = handler.connection().stream(promisedStreamId); int port = remoteAddress().port(); HttpClientRequestPushPromise pushReq = new HttpClientRequestPushPromise(this, promisedStream, client, isSsl(), method, rawMethod, uri, host, port, headersMap); if (metrics != null) { pushReq.metric(metrics.responsePushed(queueMetric, metric(), localAddress(), remoteAddress(), pushReq)); } streams.put(promisedStreamId, pushReq.getStream()); pushHandler.handle(pushReq); }); return; } } handler.writeReset(promisedStreamId, Http2Error.CANCEL.code()); }
@Test public void testResetPushPromiseNoHandler() throws Exception { server.requestHandler(req -> { req.response().push(HttpMethod.GET, "/wibble", ar -> { assertTrue(ar.succeeded()); HttpServerResponse resp = ar.result(); resp.setChunked(true).write("content"); AtomicLong reset = new AtomicLong(); resp.exceptionHandler(err -> { if (err instanceof StreamResetException) { reset.set(((StreamResetException)err).getCode()); } }); resp.closeHandler(v -> { assertEquals(Http2Error.CANCEL.code(), reset.get()); testComplete(); }); }); }); startServer(); HttpClientRequest req = client.get(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, "/somepath", resp -> { }); req.end(); await(); }
@Test public void testResetActivePushPromise() throws Exception { server.requestHandler(req -> { req.response().push(HttpMethod.GET, "/wibble", ar -> { assertTrue(ar.succeeded()); HttpServerResponse response = ar.result(); response.exceptionHandler(err -> { if (err instanceof StreamResetException) { assertEquals(Http2Error.CANCEL.code(), ((StreamResetException) err).getCode()); testComplete(); } }); response.setChunked(true).write("some_content"); }); }); startServer(); HttpClientRequest req = client.get(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, "/somepath", resp -> { fail(); }); req.pushHandler(pushedReq -> { pushedReq.handler(pushedResp -> { pushedResp.handler(buff -> { pushedReq.reset(Http2Error.CANCEL.code()); }); }); }); req.end(); await(); }
@Test public void testResetPendingPushPromise() throws Exception { server.requestHandler(req -> { req.response().push(HttpMethod.GET, "/wibble", ar -> { assertFalse(ar.succeeded()); testComplete(); }); }); startServer(); client.close(); client = vertx.createHttpClient(clientOptions.setInitialSettings(new io.vertx.core.http.Http2Settings().setMaxConcurrentStreams(0L))); HttpClientRequest req = client.get(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, "/somepath", resp -> { fail(); }); req.pushHandler(pushedReq -> { pushedReq.reset(Http2Error.CANCEL.code()); }); req.end(); await(); }