-
Notifications
You must be signed in to change notification settings - Fork 972
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[HTTPCLIENT-1843] - Delegate compression handling to Apache Commons C…
…ompress * Integrated Apache Commons Compress into CompressorFactory to handle compression and decompression of HTTP entities using supported algorithms (gzip, deflate, etc.).
- Loading branch information
1 parent
aad0e9a
commit 0c68966
Showing
33 changed files
with
1,171 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
...t/java/org/apache/hc/client5/testing/sync/compress/CompressedResponseHandlingExample.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* ==================================================================== | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
* ==================================================================== | ||
* | ||
* This software consists of voluntary contributions made by many | ||
* individuals on behalf of the Apache Software Foundation. For more | ||
* information on the Apache Software Foundation, please see | ||
* <http://www.apache.org/>. | ||
* | ||
*/ | ||
|
||
package org.apache.hc.client5.testing.sync.compress; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import org.apache.hc.client5.http.entity.CompressorFactory; | ||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; | ||
import org.apache.hc.client5.http.impl.classic.HttpClients; | ||
import org.apache.hc.core5.http.ClassicHttpRequest; | ||
import org.apache.hc.core5.http.ContentType; | ||
import org.apache.hc.core5.http.HttpEntity; | ||
import org.apache.hc.core5.http.HttpHeaders; | ||
import org.apache.hc.core5.http.HttpHost; | ||
import org.apache.hc.core5.http.io.entity.EntityUtils; | ||
import org.apache.hc.core5.http.io.entity.StringEntity; | ||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; | ||
import org.apache.hc.core5.io.CloseMode; | ||
import org.apache.hc.core5.testing.classic.ClassicTestServer; | ||
|
||
|
||
/** | ||
* Demonstrates handling of HTTP responses with content compression using Apache HttpClient. | ||
* <p> | ||
* This example sets up a local test server that simulates compressed HTTP responses. It then | ||
* creates a custom HttpClient configured to handle compression. The client makes a request to | ||
* the test server, receives a compressed response, and decompresses the content to verify the | ||
* process. | ||
* <p> | ||
* The main focus of this example is to illustrate the use of a custom HttpClient that can | ||
* handle compressed HTTP responses transparently, simulating a real-world scenario where | ||
* responses from a server might be compressed to reduce bandwidth usage. | ||
*/ | ||
public class CompressedResponseHandlingExample { | ||
|
||
public static void main(final String[] args) { | ||
|
||
final ClassicTestServer server = new ClassicTestServer(); | ||
try { | ||
server.register("/compressed", (request, response, context) -> { | ||
final String uncompressedContent = "This is the uncompressed response content"; | ||
response.setEntity(compress(uncompressedContent, "gzip")); | ||
response.addHeader(HttpHeaders.CONTENT_ENCODING, "gzip"); | ||
}); | ||
|
||
server.start(); | ||
|
||
final HttpHost target = new HttpHost("localhost", server.getPort()); | ||
|
||
final List<String> encodingList = Arrays.asList("gz", "deflate"); | ||
|
||
try (final CloseableHttpClient httpclient = HttpClients | ||
.custom() | ||
.setEncodings(encodingList) | ||
.build()) { | ||
final ClassicHttpRequest httpGet = ClassicRequestBuilder.get() | ||
.setHttpHost(target) | ||
.setPath("/compressed") | ||
.build(); | ||
|
||
System.out.println("Executing request " + httpGet.getMethod() + " " + httpGet.getUri()); | ||
httpclient.execute(httpGet, response -> { | ||
System.out.println("----------------------------------------"); | ||
System.out.println(httpGet + "->" + response.getCode() + " " + response.getReasonPhrase()); | ||
|
||
final HttpEntity responseEntity = response.getEntity(); | ||
final String responseBody = EntityUtils.toString(responseEntity); | ||
System.out.println("Response content: " + responseBody); | ||
|
||
return null; | ||
}); | ||
} | ||
|
||
} catch (final Exception e) { | ||
e.printStackTrace(); | ||
} finally { | ||
server.shutdown(CloseMode.GRACEFUL); | ||
} | ||
} | ||
|
||
|
||
private static HttpEntity compress(final String data, final String name) { | ||
final StringEntity originalEntity = new StringEntity(data, ContentType.TEXT_PLAIN); | ||
return CompressorFactory.INSTANCE.compressEntity(originalEntity, name); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
httpclient5/src/main/java/org/apache/hc/client5/http/entity/CompressingEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
* ==================================================================== | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
* ==================================================================== | ||
* | ||
* This software consists of voluntary contributions made by many | ||
* individuals on behalf of the Apache Software Foundation. For more | ||
* information on the Apache Software Foundation, please see | ||
* <http://www.apache.org/>. | ||
* | ||
*/ | ||
package org.apache.hc.client5.http.entity; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
|
||
import org.apache.commons.compress.compressors.CompressorException; | ||
import org.apache.hc.core5.http.HttpEntity; | ||
import org.apache.hc.core5.http.io.entity.HttpEntityWrapper; | ||
import org.apache.hc.core5.util.Args; | ||
|
||
|
||
/** | ||
* An {@link HttpEntity} wrapper that applies compression to the content before writing it to | ||
* an output stream. This class supports various compression algorithms based on the | ||
* specified content encoding. | ||
* | ||
* <p>Compression is performed using {@link CompressorFactory}, which returns a corresponding | ||
* {@link OutputStream} for the requested compression type. This class does not support | ||
* reading the content directly through {@link #getContent()} as the content is always compressed | ||
* during write operations.</p> | ||
* | ||
* @since 5.5 | ||
*/ | ||
public class CompressingEntity extends HttpEntityWrapper { | ||
|
||
/** | ||
* The content encoding type, e.g., "gzip", "deflate", etc. | ||
*/ | ||
private final String contentEncoding; | ||
|
||
/** | ||
* Creates a new {@link CompressingEntity} that compresses the wrapped entity's content | ||
* using the specified content encoding. | ||
* | ||
* @param entity the {@link HttpEntity} to wrap and compress; must not be {@code null}. | ||
* @param contentEncoding the content encoding to use for compression, e.g., "gzip". | ||
*/ | ||
public CompressingEntity(final HttpEntity entity, final String contentEncoding) { | ||
super(entity); | ||
this.contentEncoding = Args.notNull(contentEncoding, "Content encoding"); | ||
} | ||
|
||
/** | ||
* Returns the content encoding used for compression. | ||
* | ||
* @return the content encoding (e.g., "gzip", "deflate"). | ||
*/ | ||
@Override | ||
public String getContentEncoding() { | ||
return contentEncoding; | ||
} | ||
|
||
|
||
/** | ||
* Returns whether the entity is chunked. This is determined by the wrapped entity. | ||
* | ||
* @return {@code true} if the entity is chunked, {@code false} otherwise. | ||
*/ | ||
@Override | ||
public boolean isChunked() { | ||
return super.isChunked(); | ||
} | ||
|
||
|
||
/** | ||
* This method is unsupported because the content is meant to be compressed during the | ||
* {@link #writeTo(OutputStream)} operation. | ||
* | ||
* @throws UnsupportedOperationException always, as this method is not supported. | ||
*/ | ||
@Override | ||
public InputStream getContent() throws IOException { | ||
throw new UnsupportedOperationException("Reading content is not supported for CompressingEntity"); | ||
} | ||
|
||
/** | ||
* Writes the compressed content to the provided {@link OutputStream}. Compression is performed | ||
* using the content encoding provided during entity construction. | ||
* | ||
* @param outStream the {@link OutputStream} to which the compressed content will be written; must not be {@code null}. | ||
* @throws IOException if an I/O error occurs during compression or writing. | ||
* @throws UnsupportedOperationException if the specified compression type is not supported. | ||
*/ | ||
@Override | ||
public void writeTo(final OutputStream outStream) throws IOException { | ||
Args.notNull(outStream, "Output stream"); | ||
|
||
// Get the compressor based on the specified content encoding | ||
final OutputStream compressorStream; | ||
try { | ||
compressorStream = CompressorFactory.INSTANCE.getCompressorOutputStream(contentEncoding, outStream); | ||
} catch (final CompressorException e) { | ||
throw new IOException("Error initializing decompression stream", e); | ||
} | ||
|
||
if (compressorStream != null) { | ||
// Write compressed data | ||
super.writeTo(compressorStream); | ||
// Close the compressor stream after writing | ||
compressorStream.close(); | ||
} else { | ||
throw new UnsupportedOperationException("Unsupported compression: " + contentEncoding); | ||
} | ||
} | ||
} |
Oops, something went wrong.