From 753b34e03374e2f6bf6ba91cd4d1c8fb35b16508 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 24 Mar 2016 21:32:11 +0100 Subject: [PATCH] Http2 server doc and examples --- src/main/asciidoc/java/http.adoc | 322 +++++++++++++++++- src/main/java/examples/HTTP2Examples.java | 201 +++++++++++ .../java/io/vertx/core/http/package-info.java | 229 ++++++++++++- 3 files changed, 746 insertions(+), 6 deletions(-) create mode 100644 src/main/java/examples/HTTP2Examples.java diff --git a/src/main/asciidoc/java/http.adoc b/src/main/asciidoc/java/http.adoc index 18dd2793b..e63218a75 100644 --- a/src/main/asciidoc/java/http.adoc +++ b/src/main/asciidoc/java/http.adoc @@ -2,6 +2,11 @@ Vert.x allows you to easily write non blocking HTTP clients and servers. +Vert.x supports the HTTP/1.0, HTTP/1.1 and HTTP/2 protocols. + +The base API for HTTP is the same for HTTP/1.x and HTTP/2, specific API features are available for dealing with the +HTTP/2 protocol. + === Creating an HTTP Server The simplest way to create an HTTP server, using all default options is as follows: @@ -23,6 +28,34 @@ HttpServerOptions options = new HttpServerOptions().setMaxWebsocketFrameSize(100 HttpServer server = vertx.createHttpServer(options); ---- +=== Configuring an HTTP/2 server + +Vert.x supports HTTP/2 over TLS `h2` and over TCP `h2c`. + +To handle `h2` requests, TLS must be enabled with Application-Layer Protocol Negotiation: + +[source,java] +---- +HttpServerOptions options = new HttpServerOptions() + .setUseAlpn(true) + .setSsl(true) + .setKeyStoreOptions(new JksOptions().setPath("/path/to/my/keystore")); + +HttpServer server = vertx.createHttpServer(options); +---- + +ALPN is a TLS extension that negotiates the protocol before the client and the server start to exchange data. + +Clients that don't support ALPN will still be able to do a _classic_ SSL handshake. + +ALPN will usually agree on the `h2` protocol, although `http/1.1` can be used if the server or the client decides +so. + +To handle `h2c` requests, TLS must be disabled, the server will upgrade to HTTP/2 any request HTTP/1.1 that wants to +upgrade to HTTP/2. + +WARNING: most browsers won't support `h2c`, so for serving web sites you should use `h2` and not `h2c`. + === Start the Server Listening To tell the server to listen for incoming requests you use one of the `link:../../apidocs/io/vertx/core/http/HttpServer.html#listen--[listen]` @@ -163,6 +196,12 @@ System.out.println("User agent is " + headers.get("user-agent")); System.out.println("User agent is " + headers.get("User-Agent")); ---- +==== Request host + +Use `link:../../apidocs/io/vertx/core/http/HttpServerRequest.html#host--[host]` to return the host of the HTTP request. + +For HTTP/1.x requests the `host` header is returned, for HTTP/1 requests the `:authority` pseudo header is returned. + ==== Request parameters Use `link:../../apidocs/io/vertx/core/http/HttpServerRequest.html#params--[params]` to return the parameters of the HTTP request. @@ -331,6 +370,26 @@ request.uploadHandler(upload -> { WARNING: Make sure you check the filename in a production system to avoid malicious clients uploading files to arbitrary places on your filesystem. See <> for more information. +==== Receiving unknown HTTP/2 frames + +HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind +of frames to be sent and received. + +To receive unknown frames, you can use the `link:../../apidocs/io/vertx/core/http/HttpServerRequest.html#unknownFrameHandler-io.vertx.core.Handler-[unknownFrameHandler]` on the request, +this will get called every time an unknown frame arrives. Here's an example: + +[source,java] +---- +request.unknownFrameHandler(frame -> { + + System.out.println("Received a frame type=" + frame.type() + + " payload" + frame.payload().toString()); +}); +---- + +HTTP/2 frames are not subject to flow control - the frame handler will be called immediatly when an +unkown frame is received whether the request is paused or is not + === Sending back responses The server response object is an instance of `link:../../apidocs/io/vertx/core/http/HttpServerResponse.html[HttpServerResponse]` and is obtained from the @@ -348,6 +407,9 @@ You can also specify a custom status message with `link:../../apidocs/io/vertx/c If you don't specify a status message, the default one corresponding to the status code will be used. +NOTE: for HTTP/2 the status won't be present in the response since the protocol won't transmit the message +to the client + ==== Writing HTTP responses To write data to an HTTP response, you use one the `link:../../apidocs/io/vertx/core/http/HttpServerResponse.html#write-io.vertx.core.buffer.Buffer-[write]` operations. @@ -421,6 +483,8 @@ Non keep-alive connections will be automatically closed by Vert.x when the respo Keep-alive connections are not automatically closed by Vert.x by default. If you want keep-alive connections to be closed after an idle time, then you configure `link:../../apidocs/io/vertx/core/http/HttpServerOptions.html#setIdleTimeout-int-[setIdleTimeout]`. +HTTP/2 connections will GOAWAY frame before closing the response. + ==== Setting response headers HTTP response headers can be added to the response by adding them directly to the @@ -465,6 +529,8 @@ methods will result in a new HTTP chunk being written out. When in chunked mode you can also write HTTP response trailers to the response. These are actually written in the final chunk of the response. +NOTE: chunked response has no effect for an HTTP/2 stream + To add trailers to the response, add them directly to the `link:../../apidocs/io/vertx/core/http/HttpServerResponse.html#trailers--[trailers]`. [source,java] @@ -590,6 +656,93 @@ vertx.createHttpServer().requestHandler(request -> { }).listen(8080); ---- +==== Writing HTTP/2 frames + +HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind +of frames to be sent and received. + +To send such frames, you can use the `link:../../apidocs/io/vertx/core/http/HttpServerResponse.html#writeFrame-int-int-io.vertx.core.buffer.Buffer-[writeFrame]` on the response. +Here’s an example: + +[source,java] +---- +int frameType = 40; +int frameStatus = 10; +Buffer payload = Buffer.buffer("some data"); + +// Sending a frame to the client +response.writeFrame(frameType, frameStatus, payload); +---- + +These frames are sent immediatly and are not subject to flow control - when such frame is sent there it may be done +before other `DATA` frames. + +==== Stream reset + +HTTP/1.x does not allow a clean reset of a request or a response stream, for example when a client uploads +a resource already present on the server, the server needs to accept the entire response. + +HTTP/2 supports stream reset at any time during the request/response: + +[source,java] +---- +request.response().reset(); +---- + +By default the `NO_ERROR` (0) error code is sent, another code can sent instead: + +[source,java] +---- +request.response().reset(8); +---- + +The HTTP/2 specification defines the list of http://httpwg.org/specs/rfc7540.html#ErrorCodes[error codes] one can use. + +The request handler are notified of stream reset events with the `link:../../apidocs/io/vertx/core/http/HttpServerRequest.html#exceptionHandler-io.vertx.core.Handler-[request handler]` and +`link:../../apidocs/io/vertx/core/http/HttpServerResponse.html#exceptionHandler-io.vertx.core.Handler-[response handler]`: + +[source,java] +---- +request.response().exceptionHandler(err -> { + if (err instanceof StreamResetException) { + StreamResetException reset = (StreamResetException) err; + System.out.println("Stream reset " + reset.getCode()); + } +}); +---- + +==== Server push + +Server push is a new feature of HTTP/2 that enables sending multiple responses in parallel for a single client request. + +When a server process a request, it can push a request/response to the client: + +[source,java] +---- +HttpServerResponse response = request.response(); + +// Push main.js to the client +response.push(HttpMethod.GET, "/main.js", ar -> { + if (ar.succeeded()) { + + HttpServerResponse pushedResponse = ar.result(); + + // Send main.js response + pushedResponse. + putHeader("content-type", "application/json"). + end("alert(\"Push response hello\")"); + } else { + System.out.println("Could not push client resource " + ar.cause()); + } +}); + +// Send the requested resource +response.sendFile(""); +---- + +The `link:../../apidocs/io/vertx/core/http/HttpServerResponse.html#push-io.vertx.core.http.HttpMethod-java.lang.String-java.lang.String-io.vertx.core.Handler-[push]` method must be called before the initiating response ends, however +the pushed response can be written after. + === HTTP Compression Vert.x comes with support for HTTP Compression out of the box. @@ -629,6 +782,36 @@ HttpClientOptions options = new HttpClientOptions().setKeepAlive(false); HttpClient client = vertx.createHttpClient(options); ---- +Vert.x supports HTTP/2 over TLS `h2` and over TCP `h2c`. + +By default the http client performs HTTP/1.1 requests, to perform HTTP/2 requests the `link:../../apidocs/io/vertx/core/http/HttpClientOptions.html#setProtocolVersion-io.vertx.core.http.HttpVersion-[setProtocolVersion]` +must be set to `link:../../apidocs/io/vertx/core/http/HttpVersion.html#HTTP_2[HTTP_2]`. + +For `h2` requests, TLS must be enabled with _Application-Layer Protocol Negotiation_: + +[source,java] +---- +HttpClientOptions options = new HttpClientOptions(). + setProtocolVersion(HttpVersion.HTTP_2). + setSsl(true). + setUseAlpn(true). + setTrustAll(true); + +HttpClient client = vertx.createHttpClient(options); +---- + +For `h2c` requests, TLS must be disabled, the client will do an HTTP/1.1 requests and try an upgrade to HTTP/2: + +[source,java] +---- +HttpClientOptions options = new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_2); + +HttpClient client = vertx.createHttpClient(options); +---- + +The http server may not support HTTP/2, the actual version can be checked +with `link:../../apidocs/io/vertx/core/http/HttpClientResponse.html#version--[version]` when the response arrives. + === Making requests The http client is very flexible and there are various ways you can make requests with it. @@ -942,6 +1125,57 @@ file.endHandler(v -> request.end()); pump.start(); ---- +==== Writing HTTP/2 frames + +HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind +of frames to be sent and received. + +To send such frames, you can use the `link:../../apidocs/io/vertx/core/http/HttpClientRequest.html#write-io.vertx.core.buffer.Buffer-[write]` on the request. Here’s an example: + +[source,java] +---- +int frameType = 40; +int frameStatus = 10; +Buffer payload = Buffer.buffer("some data"); + +// Sending a frame to the server +request.writeFrame(frameType, frameStatus, payload); +---- + +==== Stream reset + +HTTP/1.x does not allow a clean reset of a request or a response stream, for example when a client uploads a resource already +present on the server, the server needs to accept the entire response. + +HTTP/2 supports stream reset at any time during the request/response: + +[source,java] +---- +request.reset(); +---- + +By default the NO_ERROR (0) error code is sent, another code can sent instead: + +[source,java] +---- +request.reset(8); +---- + +The HTTP/2 specification defines the list of http://httpwg.org/specs/rfc7540.html#ErrorCodes[error codes] one can use. + +The request handler are notified of stream reset events with the `link:../../apidocs/io/vertx/core/http/HttpClientRequest.html#exceptionHandler-io.vertx.core.Handler-[request handler]` and +`link:../../apidocs/io/vertx/core/http/HttpClientResponse.html#exceptionHandler-io.vertx.core.Handler-[response handler]`: + +[source,java] +---- +request.exceptionHandler(err -> { + if (err instanceof StreamResetException) { + StreamResetException reset = (StreamResetException) err; + System.out.println("Stream reset " + reset.getCode()); + } +}); +---- + === Handling http responses You receive an instance of `link:../../apidocs/io/vertx/core/http/HttpClientResponse.html[HttpClientResponse]` into the handler that you specify in of @@ -1150,6 +1384,77 @@ httpServer.requestHandler(request -> { }); ---- +==== Client push + +Server push is a new feature of HTTP/2 that enables sending multiple responses in parallel for a single client request. + +A push handler can be set on a request to receive the request/response pushed by the server: + +[source,java] +---- +HttpClientRequest request = client.get("/index.html", response -> { + // Process index.html response +}); + +// Set a push handler to be aware of any resource pushed by the server +request.pushHandler(pushedRequest -> { + + // A resource is pushed for this request + System.out.println("Server pushed " + pushedRequest.path()); + + // Set an handler for the response + pushedRequest.handler(pushedResponse -> { + System.out.println("The response for the pushed request"); + }); +}); + +// End the request +request.end(); +---- + +If the client does not want to receive a pushed request, it can reset the stream: + +[source,java] +---- +HttpClientRequest request = client.get("/index.html", response -> { + // Process index.html response +}); + +// Set a push handler to be aware of any resource pushed by the server +request.pushHandler(pushedRequest -> { + + // A resource is pushed for this request + System.out.println("Server pushed " + pushedRequest.path()); + + // Set an handler for the response + pushedRequest.handler(pushedResponse -> { + System.out.println("The response for the pushed request"); + }); +}); + +// End the request +request.end(); +---- + +When no handler is set, any stream pushed by the server will be automatically reset by the client. + +==== Receiving unknown HTTP/2 frames + +HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind of +frames to be sent and received. + +To receive unknown frames, you can use the unknownFrameHandler on the request, this will get called every time an unknown +frame arrives. Here’s an example: + +[source,java] +---- +response.unknownFrameHandler(frame -> { + + System.out.println("Received a frame type=" + frame.type() + + " payload" + frame.payload().toString()); +}); +---- + === Enabling compression on the client The http client comes with support for HTTP Compression out of the box. @@ -1178,12 +1483,12 @@ used when creating the client. By default compression is disabled. -=== Pooling and keep alive +=== HTTP/1.x pooling and keep alive Http keep alive allows http connections to be used for more than one request. This can be a more efficient use of connections when you're making multiple requests to the same server. -The http client supports pooling of connections, allowing you to reuse connections between requests. +For HTTP/1.x versions, the http client supports pooling of connections, allowing you to reuse connections between requests. For pooling to work, keep alive must be true using `link:../../apidocs/io/vertx/core/http/HttpClientOptions.html#setKeepAlive-boolean-[setKeepAlive]` on the options used when configuring the client. The default value is true. @@ -1202,7 +1507,7 @@ Keep alive connections will not be closed by the client automatically. To close Alternatively you can set idle timeout using `link:../../apidocs/io/vertx/core/http/HttpClientOptions.html#setIdleTimeout-int-[setIdleTimeout]` - any connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds. -=== Pipe-lining +=== HTTP/1.1 pipe-lining The client also supports pipe-lining of requests on a connection. @@ -1214,6 +1519,17 @@ By default pipe-lining is disabled. When pipe-lining is enabled requests will be written to connections without waiting for previous responses to return. +=== HTTP/2 multiplexing + +For HTTP/2, the http client uses a single connection for each server, all the requests to the same server are +multiplexed on the same connection. + +HTTP/2 connections will not be closed by the client automatically. To close them you can call `link:../../apidocs/io/vertx/core/http/HttpConnection.html#close--[close]` +or close the client instance. + +Alternatively you can set idle timeout using `link:../../apidocs/io/vertx/core/http/HttpClientOptions.html#setIdleTimeout-int-[setIdleTimeout]` - any +connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds. + === HttpClient usage The HttpClient can be used in a Verticle or embedded. diff --git a/src/main/java/examples/HTTP2Examples.java b/src/main/java/examples/HTTP2Examples.java new file mode 100644 index 000000000..19d372632 --- /dev/null +++ b/src/main/java/examples/HTTP2Examples.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2011-2013 The original author or authors + * ------------------------------------------------------ + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * The Apache License v2.0 is available at + * http://www.opensource.org/licenses/apache2.0.php + * + * You may elect to redistribute this code under either of these licenses. + */ + +package examples; + +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpClientResponse; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.http.HttpVersion; +import io.vertx.core.http.StreamResetException; +import io.vertx.core.net.JksOptions; + +/** + * @author Julien Viet + */ +public class HTTP2Examples { + + public void example0(Vertx vertx) { + HttpServerOptions options = new HttpServerOptions() + .setUseAlpn(true) + .setSsl(true) + .setKeyStoreOptions(new JksOptions().setPath("/path/to/my/keystore")); + + HttpServer server = vertx.createHttpServer(options); + } + + public void example1(HttpServerRequest request) { + + request.unknownFrameHandler(frame -> { + + System.out.println("Received a frame type=" + frame.type() + + " payload" + frame.payload().toString()); + }); + } + + public void example2(HttpServerResponse response) { + + int frameType = 40; + int frameStatus = 10; + Buffer payload = Buffer.buffer("some data"); + + // Sending a frame to the client + response.writeFrame(frameType, frameStatus, payload); + } + + public void example3(HttpServerRequest request) { + + // Reset the stream + request.response().reset(); + } + + public void example4(HttpServerRequest request) { + + // Cancel the stream + request.response().reset(8); + } + + public void example5(HttpServerRequest request) { + + request.response().exceptionHandler(err -> { + if (err instanceof StreamResetException) { + StreamResetException reset = (StreamResetException) err; + System.out.println("Stream reset " + reset.getCode()); + } + }); + } + + public void example6(HttpServerRequest request) { + + HttpServerResponse response = request.response(); + + // Push main.js to the client + response.push(HttpMethod.GET, "/main.js", ar -> { + if (ar.succeeded()) { + + HttpServerResponse pushedResponse = ar.result(); + + // Send main.js response + pushedResponse. + putHeader("content-type", "application/json"). + end("alert(\"Push response hello\")"); + } else { + System.out.println("Could not push client resource " + ar.cause()); + } + }); + + // Send the requested resource + response.sendFile(""); + } + + public void example7(Vertx vertx) { + + HttpClientOptions options = new HttpClientOptions(). + setProtocolVersion(HttpVersion.HTTP_2). + setSsl(true). + setUseAlpn(true). + setTrustAll(true); + + HttpClient client = vertx.createHttpClient(options); + } + + public void example8(Vertx vertx) { + + HttpClientOptions options = new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_2); + + HttpClient client = vertx.createHttpClient(options); + } + + public void example9(HttpClientRequest request) { + + int frameType = 40; + int frameStatus = 10; + Buffer payload = Buffer.buffer("some data"); + + // Sending a frame to the server + request.writeFrame(frameType, frameStatus, payload); + } + + public void example10(HttpClientRequest request) { + + request.reset(); + + } + + public void example11(HttpClientRequest request) { + + request.reset(8); + + } + + public void example12(HttpClientRequest request) { + + request.exceptionHandler(err -> { + if (err instanceof StreamResetException) { + StreamResetException reset = (StreamResetException) err; + System.out.println("Stream reset " + reset.getCode()); + } + }); + } + + public void example13(HttpClient client) { + + HttpClientRequest request = client.get("/index.html", response -> { + // Process index.html response + }); + + // Set a push handler to be aware of any resource pushed by the server + request.pushHandler(pushedRequest -> { + + // A resource is pushed for this request + System.out.println("Server pushed " + pushedRequest.path()); + + // Set an handler for the response + pushedRequest.handler(pushedResponse -> { + System.out.println("The response for the pushed request"); + }); + }); + + // End the request + request.end(); + } + + public void example13(HttpClientRequest request) { + request.pushHandler(pushedRequest -> { + if (pushedRequest.path().equals("/main.js")) { + pushedRequest.reset(); + } else { + // Handle it + } + }); + } + + public void example15(HttpClientResponse response) { + response.unknownFrameHandler(frame -> { + + System.out.println("Received a frame type=" + frame.type() + + " payload" + frame.payload().toString()); + }); + } +} diff --git a/src/main/java/io/vertx/core/http/package-info.java b/src/main/java/io/vertx/core/http/package-info.java index 1d945a3bf..973b031d0 100644 --- a/src/main/java/io/vertx/core/http/package-info.java +++ b/src/main/java/io/vertx/core/http/package-info.java @@ -19,6 +19,11 @@ * * Vert.x allows you to easily write non blocking HTTP clients and servers. * + * Vert.x supports the HTTP/1.0, HTTP/1.1 and HTTP/2 protocols. + * + * The base API for HTTP is the same for HTTP/1.x and HTTP/2, specific API features are available for dealing with the + * HTTP/2 protocol. + * * === Creating an HTTP Server * * The simplest way to create an HTTP server, using all default options is as follows: @@ -38,6 +43,29 @@ * {@link examples.HTTPExamples#example2} * ---- * + * === Configuring an HTTP/2 server + * + * Vert.x supports HTTP/2 over TLS `h2` and over TCP `h2c`. + * + * To handle `h2` requests, TLS must be enabled with Application-Layer Protocol Negotiation: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example0} + * ---- + * + * ALPN is a TLS extension that negotiates the protocol before the client and the server start to exchange data. + * + * Clients that don't support ALPN will still be able to do a _classic_ SSL handshake. + * + * ALPN will usually agree on the `h2` protocol, although `http/1.1` can be used if the server or the client decides + * so. + * + * To handle `h2c` requests, TLS must be disabled, the server will upgrade to HTTP/2 any request HTTP/1.1 that wants to + * upgrade to HTTP/2. + * + * WARNING: most browsers won't support `h2c`, so for serving web sites you should use `h2` and not `h2c`. + * * === Start the Server Listening * * To tell the server to listen for incoming requests you use one of the {@link io.vertx.core.http.HttpServer#listen} @@ -158,6 +186,12 @@ * {@link examples.HTTPExamples#example8} * ---- * + * ==== Request host + * + * Use {@link io.vertx.core.http.HttpServerRequest#host} to return the host of the HTTP request. + * + * For HTTP/1.x requests the `host` header is returned, for HTTP/1 requests the `:authority` pseudo header is returned. + * * ==== Request parameters * * Use {@link io.vertx.core.http.HttpServerRequest#params} to return the parameters of the HTTP request. @@ -296,6 +330,22 @@ * WARNING: Make sure you check the filename in a production system to avoid malicious clients uploading files * to arbitrary places on your filesystem. See <> for more information. * + * ==== Receiving unknown HTTP/2 frames + * + * HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind + * of frames to be sent and received. + * + * To receive unknown frames, you can use the {@link io.vertx.core.http.HttpServerRequest#unknownFrameHandler} on the request, + * this will get called every time an unknown frame arrives. Here's an example: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example1} + * ---- + * + * HTTP/2 frames are not subject to flow control - the frame handler will be called immediatly when an + * unkown frame is received whether the request is paused or is not + * * === Sending back responses * * The server response object is an instance of {@link io.vertx.core.http.HttpServerResponse} and is obtained from the @@ -313,6 +363,9 @@ * * If you don't specify a status message, the default one corresponding to the status code will be used. * + * NOTE: for HTTP/2 the status won't be present in the response since the protocol won't transmit the message + * to the client + * * ==== Writing HTTP responses * * To write data to an HTTP response, you use one the {@link io.vertx.core.http.HttpServerResponse#write} operations. @@ -380,6 +433,8 @@ * Keep-alive connections are not automatically closed by Vert.x by default. If you want keep-alive connections to be * closed after an idle time, then you configure {@link io.vertx.core.http.HttpServerOptions#setIdleTimeout}. * + * HTTP/2 connections will {@liteal GOAWAY} frame before closing the response. + * * ==== Setting response headers * * HTTP response headers can be added to the response by adding them directly to the @@ -419,6 +474,8 @@ * When in chunked mode you can also write HTTP response trailers to the response. These are actually written in * the final chunk of the response. * + * NOTE: chunked response has no effect for an HTTP/2 stream + * * To add trailers to the response, add them directly to the {@link io.vertx.core.http.HttpServerResponse#trailers}. * * [source,$lang] @@ -497,6 +554,65 @@ * {@link examples.HTTPExamples#example27} * ---- * + * ==== Writing HTTP/2 frames + * + * HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind + * of frames to be sent and received. + * + * To send such frames, you can use the {@link io.vertx.core.http.HttpServerResponse#writeFrame} on the response. + * Here’s an example: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example2} + * ---- + * + * These frames are sent immediatly and are not subject to flow control - when such frame is sent there it may be done + * before other {@literal DATA} frames. + * + * ==== Stream reset + * + * HTTP/1.x does not allow a clean reset of a request or a response stream, for example when a client uploads + * a resource already present on the server, the server needs to accept the entire response. + * + * HTTP/2 supports stream reset at any time during the request/response: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example3} + * ---- + * + * By default the `NO_ERROR` (0) error code is sent, another code can sent instead: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example4} + * ---- + * + * The HTTP/2 specification defines the list of http://httpwg.org/specs/rfc7540.html#ErrorCodes[error codes] one can use. + * + * The request handler are notified of stream reset events with the {@link io.vertx.core.http.HttpServerRequest#exceptionHandler request handler} and + * {@link io.vertx.core.http.HttpServerResponse#exceptionHandler response handler}: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example5} + * ---- + * + * ==== Server push + * + * Server push is a new feature of HTTP/2 that enables sending multiple responses in parallel for a single client request. + * + * When a server process a request, it can push a request/response to the client: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example6} + * ---- + * + * The {@link io.vertx.core.http.HttpServerResponse#push} method must be called before the initiating response ends, however + * the pushed response can be written after. + * * === HTTP Compression * * Vert.x comes with support for HTTP Compression out of the box. @@ -535,6 +651,28 @@ * {@link examples.HTTPExamples#example29} * ---- * + * Vert.x supports HTTP/2 over TLS `h2` and over TCP `h2c`. + * + * By default the http client performs HTTP/1.1 requests, to perform HTTP/2 requests the {@link io.vertx.core.http.HttpClientOptions#setProtocolVersion} + * must be set to {@link io.vertx.core.http.HttpVersion#HTTP_2}. + * + * For `h2` requests, TLS must be enabled with _Application-Layer Protocol Negotiation_: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example7} + * ---- + * + * For `h2c` requests, TLS must be disabled, the client will do an HTTP/1.1 requests and try an upgrade to HTTP/2: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example8} + * ---- + * + * The http server may not support HTTP/2, the actual version can be checked + * with {@link io.vertx.core.http.HttpClientResponse#version()} when the response arrives. + * * === Making requests * * The http client is very flexible and there are various ways you can make requests with it. @@ -745,6 +883,47 @@ * {@link examples.HTTPExamples#example44} * ---- * + * ==== Writing HTTP/2 frames + * + * HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind + * of frames to be sent and received. + * + * To send such frames, you can use the {@link io.vertx.core.http.HttpClientRequest#write} on the request. Here’s an example: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example9} + * ---- + * + * ==== Stream reset + * + * HTTP/1.x does not allow a clean reset of a request or a response stream, for example when a client uploads a resource already + * present on the server, the server needs to accept the entire response. + * + * HTTP/2 supports stream reset at any time during the request/response: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example10} + * ---- + * + * By default the NO_ERROR (0) error code is sent, another code can sent instead: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example11} + * ---- + * + * The HTTP/2 specification defines the list of http://httpwg.org/specs/rfc7540.html#ErrorCodes[error codes] one can use. + * + * The request handler are notified of stream reset events with the {@link io.vertx.core.http.HttpClientRequest#exceptionHandler request handler} and + * {@link io.vertx.core.http.HttpClientResponse#exceptionHandler response handler}: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example12} + * ---- + * * === Handling http responses * * You receive an instance of {@link io.vertx.core.http.HttpClientResponse} into the handler that you specify in of @@ -872,6 +1051,39 @@ * {@link examples.HTTPExamples#example50_2} * ---- * + * ==== Client push + * + * Server push is a new feature of HTTP/2 that enables sending multiple responses in parallel for a single client request. + * + * A push handler can be set on a request to receive the request/response pushed by the server: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example13} + * ---- + * + * If the client does not want to receive a pushed request, it can reset the stream: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example13} + * ---- + * + * When no handler is set, any stream pushed by the server will be automatically reset by the client. + * + * ==== Receiving unknown HTTP/2 frames + * + * HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind of + * frames to be sent and received. + * + * To receive unknown frames, you can use the unknownFrameHandler on the request, this will get called every time an unknown + * frame arrives. Here’s an example: + * + * [source,$lang] + * ---- + * {@link examples.HTTP2Examples#example15} + * ---- + * * === Enabling compression on the client * * The http client comes with support for HTTP Compression out of the box. @@ -900,12 +1112,12 @@ * * By default compression is disabled. * - * === Pooling and keep alive + * === HTTP/1.x pooling and keep alive * * Http keep alive allows http connections to be used for more than one request. This can be a more efficient use of * connections when you're making multiple requests to the same server. * - * The http client supports pooling of connections, allowing you to reuse connections between requests. + * For HTTP/1.x versions, the http client supports pooling of connections, allowing you to reuse connections between requests. * * For pooling to work, keep alive must be true using {@link io.vertx.core.http.HttpClientOptions#setKeepAlive(boolean)} * on the options used when configuring the client. The default value is true. @@ -924,7 +1136,7 @@ * Alternatively you can set idle timeout using {@link io.vertx.core.http.HttpClientOptions#setIdleTimeout(int)} - any * connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds. * - * === Pipe-lining + * === HTTP/1.1 pipe-lining * * The client also supports pipe-lining of requests on a connection. * @@ -936,6 +1148,17 @@ * * When pipe-lining is enabled requests will be written to connections without waiting for previous responses to return. * + * === HTTP/2 multiplexing + * + * For HTTP/2, the http client uses a single connection for each server, all the requests to the same server are + * multiplexed on the same connection. + * + * HTTP/2 connections will not be closed by the client automatically. To close them you can call {@link io.vertx.core.http.HttpConnection#close()} + * or close the client instance. + * + * Alternatively you can set idle timeout using {@link io.vertx.core.http.HttpClientOptions#setIdleTimeout(int)} - any + * connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds. + * * === HttpClient usage * * The HttpClient can be used in a Verticle or embedded.