I am trying to use a HttpRequestInterceptor to adapt a request sent to a org.apache.http.impl.nio.client.CloseableHttpAsyncClient. I want to do request body compression (e.g. Content-Encoding: gzip for HttpRequest, not Accept-Encoding) following the example here: https://hc.apache.org/httpcomponents-client-4.2.x/httpclient/examples/org/apache/http/examples/client/ClientGZipContentCompression.java . The example is for response compression, but it looked like I could do the same thing to do request compression, and I need to handle response compression too.
After much debugging I realized the HttpRequestInterceptor would allow me to change the headers, but not the HttpEntity that was sent. The entity sent is always the original one passed into the AsyncHttpClient. On the server, I see the "Content-Type: gzip" and a "Content-Length" header for the gzipped length (Content-Length was set by the internal interceptors), but the bytes sent are the original values from the NByteArrayEntity, which leads to exceptions since Content-Length doesn't match actual length after GZIP. I tracked it down to the constructor for org.apache.http.nio.protocol.BasicAsyncRequestProducer. The BasicAsyncRequestProducer is created before the interceptors run. In the producer constructor, the entity from the request is stored as the producer. This occurs before the HttpRequestInterceptor has a chance to manipulate the entity. My idea for a patch would be to delay load the producer field until after the interceptors have run. Looking at the class, that would have to be in produceContent, before it checks for producer==null. Since the request is also a member, this would allow the producer to be set based on what's in the request when we actually produce the output, rather than what was in it when the whole processing chain started. Is patching the BasicAsyncRequestProducer the only way to do this or is there a simpler way that I am missing?