|
| 1 | +<!-- |
| 2 | + Licensed to the Apache Software Foundation (ASF) under one |
| 3 | + or more contributor license agreements. See the NOTICE file |
| 4 | + distributed with this work for additional information |
| 5 | + regarding copyright ownership. The ASF licenses this file |
| 6 | + to you under the Apache License, Version 2.0 (the |
| 7 | + "License"); you may not use this file except in compliance |
| 8 | + with the License. You may obtain a copy of the License at |
| 9 | +
|
| 10 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | +
|
| 12 | + Unless required by applicable law or agreed to in writing, |
| 13 | + software distributed under the License is distributed on an |
| 14 | + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | + KIND, either express or implied. See the License for the |
| 16 | + specific language governing permissions and limitations |
| 17 | + under the License. |
| 18 | +--> |
| 19 | + |
| 20 | +Async content compression & decompression |
| 21 | +========================================= |
| 22 | + |
| 23 | +Starting with HttpClient 5.6 the async transport can transparently **compress** |
| 24 | +request bodies and **decompress** response bodies. The logic lives in the |
| 25 | +message-exchange layer, so application code keeps working with plain (already |
| 26 | +decoded) entities. |
| 27 | + |
| 28 | +Capabilities |
| 29 | +------------ |
| 30 | + |
| 31 | +- Automatic `Accept-Encoding` negotiation when content compression is enabled |
| 32 | + and the request does not already carry this header. |
| 33 | +- Transparent response decompression for `Content-Encoding` values |
| 34 | + `deflate`, `gzip`, and `x-gzip`. |
| 35 | +- Optional support for `zstd` and `br` (Brotli) encodings when the |
| 36 | + corresponding libraries are present on the classpath. |
| 37 | +- Streaming request compression via `DeflatingAsyncEntityProducer` and the |
| 38 | + codec-specific wrappers (for example `DeflatingGzipEntityProducer`). |
| 39 | + |
| 40 | +Supported codecs and dependencies |
| 41 | +--------------------------------- |
| 42 | + |
| 43 | +Deflate and GZIP are available out of the box. |
| 44 | + |
| 45 | +Zstandard and Brotli are only wired in when their optional dependencies are |
| 46 | +present: |
| 47 | + |
| 48 | +- **Zstandard** – `com.github.luben:zstd-jni` |
| 49 | +- **Brotli** – `com.aayushatharva.brotli4j:brotli4j` (plus a matching |
| 50 | + `brotli4j-native` artefact for the target platform) |
| 51 | + |
| 52 | +At runtime the async client checks the classpath and registers the extra codecs |
| 53 | +without creating a hard dependency on either library. |
| 54 | + |
| 55 | +Basic usage – transparent response decompression |
| 56 | +------------------------------------------------ |
| 57 | + |
| 58 | +By default async clients send an `Accept-Encoding` header and automatically |
| 59 | +decode compressed responses before handing them to the application. |
| 60 | +No extra code is required: |
| 61 | + |
| 62 | +```java |
| 63 | +try (final CloseableHttpAsyncClient client = HttpAsyncClients.createDefault()) { |
| 64 | + client.start(); |
| 65 | + |
| 66 | + final SimpleHttpRequest request = SimpleRequestBuilder.get("https://httpbin.org/gzip") |
| 67 | + .build(); |
| 68 | + |
| 69 | + final Future<Message<HttpResponse, String>> future = client.execute( |
| 70 | + SimpleRequestProducer.create(request), |
| 71 | + new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), |
| 72 | + null); |
| 73 | + |
| 74 | + final Message<HttpResponse, String> message = future.get(); |
| 75 | + System.out.println("status=" + message.getHead().getCode()); |
| 76 | + System.out.println("body:\n" + message.getBody()); |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +Mapping codecs to examples |
| 81 | +-------------------------- |
| 82 | + |
| 83 | +The async examples in the `org.apache.hc.client5.http.examples` package exercise |
| 84 | +the same codecs that are registered in `ContentCompressionAsyncExec`: |
| 85 | + |
| 86 | +```java |
| 87 | +.register(ContentCoding.GZIP.token(), InflatingGzipDataConsumer::new) |
| 88 | +.register(ContentCoding.X_GZIP.token(), InflatingGzipDataConsumer::new) |
| 89 | +.register(ContentCoding.DEFLATE.token(), d -> new InflatingAsyncDataConsumer(d, null)) |
| 90 | + |
| 91 | +// Optional – only when the libraries are present |
| 92 | +.register(ContentCoding.ZSTD.token(), InflatingZstdDataConsumer::new) |
| 93 | +.register(ContentCoding.BROTLI.token(), InflatingBrotliDataConsumer::new); |
| 94 | +``` |
| 95 | + |
| 96 | +The sections below link each `ContentCoding` token to a concrete runnable |
| 97 | +example, in the same spirit as the Observation examples page. |
| 98 | + |
| 99 | +GZIP (`gzip`, `x-gzip`) |
| 100 | +----------------------- |
| 101 | + |
| 102 | +- [AsyncClientGzipCompressionExample](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientGzipCompressionExample.java) |
| 103 | + |
| 104 | + Demonstrates streaming a request body compressed with **GZIP** using |
| 105 | + `DeflatingGzipEntityProducer`. The client sends a compressed POST while the |
| 106 | + async pipeline adds `Content-Encoding: gzip` automatically. |
| 107 | + |
| 108 | +- [AsyncClientGzipDecompressionExample](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientGzipDecompressionExample.java) |
| 109 | + |
| 110 | + Demonstrates **transparent GZIP response decompression**. The server returns |
| 111 | + `Content-Encoding: gzip`, the async chain wraps the downstream consumer with |
| 112 | + `InflatingGzipDataConsumer`, and application code only sees the plain body. |
| 113 | + |
| 114 | +These examples correspond directly to: |
| 115 | + |
| 116 | +```java |
| 117 | +.register(ContentCoding.GZIP.token(), InflatingGzipDataConsumer::new) |
| 118 | +.register(ContentCoding.X_GZIP.token(), InflatingGzipDataConsumer::new) |
| 119 | +``` |
| 120 | + |
| 121 | +DEFLATE (`deflate`) |
| 122 | +------------------- |
| 123 | + |
| 124 | +- [AsyncClientDeflateCompressionExample](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientDeflateCompressionExample.java) |
| 125 | + |
| 126 | + Demonstrates streaming a request body compressed with **deflate** using |
| 127 | + `DeflatingAsyncEntityProducer` wrapped around an arbitrary `AsyncEntityProducer`. |
| 128 | + |
| 129 | +- [AsyncClientInflateDecompressionExample](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientInflateDecompressionExample.java) |
| 130 | + |
| 131 | + Demonstrates **transparent deflate response decompression**. When the server |
| 132 | + responds with `Content-Encoding: deflate`, the async execution chain wraps |
| 133 | + the downstream consumer in `InflatingAsyncDataConsumer`. |
| 134 | + |
| 135 | +These examples correspond to: |
| 136 | + |
| 137 | +```java |
| 138 | +.register(ContentCoding.DEFLATE.token(), d -> new InflatingAsyncDataConsumer(d, null)) |
| 139 | +``` |
| 140 | + |
| 141 | +Zstandard (`zstd`) |
| 142 | +------------------ |
| 143 | + |
| 144 | +- [AsyncClientZstdCompressionExample](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientZstdCompressionExample.java) |
| 145 | + |
| 146 | + Shows streaming a request body compressed with **Zstandard** using |
| 147 | + `DeflatingZstdEntityProducer`, backed by the `zstd-jni` library. |
| 148 | + |
| 149 | +- [AsyncClientServerZstdExample](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientServerZstdExample.java) |
| 150 | + |
| 151 | + End-to-end client/server demo where the classic server always responds with |
| 152 | + `Content-Encoding: zstd` and the async client transparently decodes it via |
| 153 | + `InflatingZstdDataConsumer`. |
| 154 | + |
| 155 | +These examples correspond to the optional Zstandard decoder: |
| 156 | + |
| 157 | +```java |
| 158 | +.register(ContentCoding.ZSTD.token(), InflatingZstdDataConsumer::new) |
| 159 | +``` |
| 160 | + |
| 161 | +Brotli (`br`) |
| 162 | +------------- |
| 163 | + |
| 164 | +- [AsyncClientServerBrotliRoundTrip](https://github.com/apache/httpcomponents-client/tree/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientServerBrotliRoundTrip.java) |
| 165 | + |
| 166 | + Async client/server demo using **Brotli** in both directions: |
| 167 | + the client sends a Brotli-compressed request and the server responds with a |
| 168 | + Brotli-compressed body. The example uses `brotli4j` on the client side and |
| 169 | + Commons Compress for server-side decoding/encoding. |
| 170 | + |
| 171 | +This example matches the optional Brotli decoder registration (and the extra |
| 172 | +`Accept-Encoding: br` token): |
| 173 | + |
| 174 | +```java |
| 175 | +.register(ContentCoding.BROTLI.token(), InflatingBrotliDataConsumer::new); |
| 176 | +// ... |
| 177 | +tokens.add(ContentCoding.BROTLI.token()); |
| 178 | +``` |
| 179 | + |
| 180 | +Together, these examples show how each `ContentEncoding` registered in |
| 181 | +`ContentCompressionAsyncExec` maps to a concrete usage pattern in the async |
| 182 | +client. |
0 commit comments