Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
/**
* {@link org.apache.hc.core5.http.io.entity.HttpEntityWrapper} responsible for
* handling br Content Coded responses.
* @deprecated See {@link org.apache.hc.client5.http.entity.compress.ContentCodecRegistry#decoder(org.apache.hc.client5.http.entity.compress.ContentCoding)}
*
* @see GzipDecompressingEntity
* @since 5.2
*/
@Deprecated
public class BrotliDecompressingEntity extends DecompressingEntity {
/**
* Creates a new {@link DecompressingEntity}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@

/**
* {@link InputStreamFactory} for handling Brotli Content Coded responses.
*
* @deprecated See {@link org.apache.hc.client5.http.entity.compress.ContentCodecRegistry#decoder(org.apache.hc.client5.http.entity.compress.ContentCoding)}
* @since 5.2
*/
@Contract(threading = ThreadingBehavior.STATELESS)
@Deprecated
public class BrotliInputStreamFactory implements InputStreamFactory {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@

/**
* Common base class for decompressing {@link HttpEntity} implementations.
*
* @since 4.4
* @deprecated See {@link org.apache.hc.client5.http.entity.compress.ContentCodecRegistry#decoder(org.apache.hc.client5.http.entity.compress.ContentCoding)}
*/
@Deprecated
public class DecompressingEntity extends HttpEntityWrapper {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@
* rather than {@code deflate} streams. We handle both types in here,
* since that's what is seen on the internet. Moral - prefer
* {@code gzip}!
* @deprecated See {@link org.apache.hc.client5.http.entity.compress.ContentCodecRegistry#decoder(org.apache.hc.client5.http.entity.compress.ContentCoding)}
*
* @see GzipDecompressingEntity
*
* @since 4.1
*/
@Deprecated
public class DeflateDecompressingEntity extends DecompressingEntity {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@

/**
* {@link InputStreamFactory} for handling Deflate Content Coded responses.
*
* @deprecated Use {@link org.apache.hc.client5.http.entity.compress.ContentCodecRegistry#decoder(org.apache.hc.client5.http.entity.compress.ContentCoding)}
* @since 5.0
*/
@Deprecated
@Contract(threading = ThreadingBehavior.STATELESS)
public class DeflateInputStreamFactory implements InputStreamFactory {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
import java.util.Arrays;
import java.util.List;

import org.apache.hc.client5.http.entity.compress.ContentCodecRegistry;
import org.apache.hc.client5.http.entity.compress.ContentCoding;
import org.apache.hc.client5.http.entity.compress.ContentEncoderRegistry;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.NameValuePair;
Expand Down Expand Up @@ -439,12 +439,12 @@ public HttpEntity build() {
throw new IllegalStateException("No entity set");
}
if (compressWith != null) {
final ContentEncoderRegistry.EncoderFactory f = ContentEncoderRegistry.lookup(compressWith);
if (f == null) {
final HttpEntity compressed = ContentCodecRegistry.wrap(compressWith, e);
if (compressed == null) {
throw new UnsupportedOperationException(
"No encoder available for content-coding '" + compressWith.token() + '\'');
}
return f.wrap(e);
return compressed;
}
return e;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@

/**
* {@link InputStreamFactory} for handling GZIPContent Coded responses.
*
* @deprecated – the public extension point has moved to
* {@link org.apache.hc.client5.http.entity.compress.Decoder}.
* For built-in gzip support use
* {@code ContentCodecRegistry.decoder(ContentCoding.GZIP)} or
* wrap a stream directly with
* @since 5.0
*/
@Deprecated
@Contract(threading = ThreadingBehavior.STATELESS)
public class GZIPInputStreamFactory implements InputStreamFactory {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@
* {@link org.apache.hc.core5.http.io.entity.HttpEntityWrapper} for handling
* gzip Content Coded responses.
*
* @deprecated See {@link org.apache.hc.client5.http.entity.compress.ContentCodecRegistry#decoder(org.apache.hc.client5.http.entity.compress.ContentCoding)}
*
* @since 4.1
*/
@Deprecated
public class GzipDecompressingEntity extends DecompressingEntity {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@

/**
* Factory for decorated {@link InputStream}s.
*
* @deprecated Replaced by {@link org.apache.hc.client5.http.entity.compress.Decoder}.
* @since 4.4
*/
@Deprecated
public interface InputStreamFactory {

InputStream create(InputStream inputStream) throws IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@

/**
* Lazy initializes from an {@link InputStream} wrapper.
* @deprecated Superseded by {@link org.apache.hc.client5.http.entity.compress.DecompressingEntity}.
*/
@Deprecated
class LazyDecompressingInputStream extends FilterInputStream {

private final InputStreamFactory inputStreamFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@

import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.hc.client5.http.entity.InputStreamFactory;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.annotation.ThreadingBehavior;
Expand All @@ -56,8 +55,7 @@
*/
@Internal
@Contract(threading = ThreadingBehavior.STATELESS)
final class CommonsCompressDecoderFactory implements InputStreamFactory {

final class CommonsCompressDecoderFactory {

/**
* Map of codings that need extra JARs → the fully‐qualified class we test for
Expand All @@ -73,28 +71,24 @@ final class CommonsCompressDecoderFactory implements InputStreamFactory {
REQUIRED_CLASS_NAME = Collections.unmodifiableMap(m);
}

private final String encoding;

CommonsCompressDecoderFactory(final String encoding) {
this.encoding = encoding.toLowerCase(Locale.ROOT);
}

public String getContentEncoding() {
return encoding;
}

@Override
public InputStream create(final InputStream source) throws IOException {
try {
return new CompressorStreamFactory()
.createCompressorInputStream(encoding, source);
} catch (final CompressorException | LinkageError ex) {
throw new IOException(
"Unable to decode Content-Encoding '" + encoding + '\'', ex);
}
/**
* @return lazy decoder for the given IANA token (lower-case).
*/
static IOFunction<InputStream, InputStream> decoder(final String token) {
final String enc = token.toLowerCase(Locale.ROOT);
final CompressorStreamFactory factory = new CompressorStreamFactory();
return in -> {
try {
return factory.createCompressorInputStream(enc, in);
} catch (final CompressorException | LinkageError ex) {
throw new IOException("Unable to decode Content-Encoding '" + enc + '\'', ex);
}
};
}


/**
* Tests that required helper classes are present for a coding token.
*/
static boolean runtimeAvailable(final String token) {
final ContentCoding coding = ContentCoding.fromToken(token);
if (coding == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* ====================================================================
* 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.compress;

import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.UnaryOperator;
import java.util.zip.GZIPInputStream;

import org.apache.hc.client5.http.entity.DeflateInputStream;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.HttpEntity;
import org.brotli.dec.BrotliInputStream;


/**
* Run-time catalogue of built-in and Commons-Compress
* {@linkplain java.util.function.UnaryOperator encoders} / {@linkplain java.util.function.UnaryOperator decoders}.
*
* <p>Entries are wired once at class-load time and published through an
* unmodifiable map, so lookups are lock-free and thread-safe.</p>
*
* @since 5.6
*/
@Internal
@Contract(threading = ThreadingBehavior.STATELESS)
public final class ContentCodecRegistry {

private static final Map<ContentCoding, Codec> REGISTRY = build();

private static Map<ContentCoding, Codec> build() {
final Map<ContentCoding, Codec> m = new EnumMap<>(ContentCoding.class);

m.put(ContentCoding.GZIP,
new Codec(
// encoder
org.apache.hc.client5.http.entity.GzipCompressingEntity::new,
ent -> new DecompressingEntity(ent, GZIPInputStream::new)));
m.put(ContentCoding.DEFLATE,
new Codec(
org.apache.hc.client5.http.entity.DeflateCompressingEntity::new,
ent -> new DecompressingEntity(ent, DeflateInputStream::new)));

/* 2. Commons-Compress extras ---------------------------------- */
if (CommonsCompressSupport.isPresent()) {
for (final ContentCoding c : Arrays.asList(
ContentCoding.BROTLI,
ContentCoding.ZSTD,
ContentCoding.XZ,
ContentCoding.LZMA,
ContentCoding.LZ4_FRAMED,
ContentCoding.LZ4_BLOCK,
ContentCoding.BZIP2,
ContentCoding.PACK200,
ContentCoding.DEFLATE64)) {

if (CommonsCompressDecoderFactory.runtimeAvailable(c.token())) {
m.put(c, new Codec(
e -> new CommonsCompressingEntity(e, c.token()),
ent -> new DecompressingEntity(ent,
CommonsCompressDecoderFactory.decoder(c.token()))));
}
}
}

/* 3. Native Brotli fallback (decode-only) ---------------------- */
if (!m.containsKey(ContentCoding.BROTLI)
&& CommonsCompressDecoderFactory.runtimeAvailable(ContentCoding.BROTLI.token())) {
m.put(ContentCoding.BROTLI,
Codec.decodeOnly(ent ->
new DecompressingEntity(ent, BrotliInputStream::new)));
}

return Collections.unmodifiableMap(m);
}

public static HttpEntity wrap(final ContentCoding c, final HttpEntity src) {
final Codec k = REGISTRY.get(c);
return k != null && k.encoder != null ? k.encoder.apply(src) : null;
}

public static HttpEntity unwrap(final ContentCoding c, final HttpEntity src) {
final Codec k = REGISTRY.get(c);
return k != null && k.decoder != null ? k.decoder.apply(src) : null;
}

private ContentCodecRegistry() {
}

/**
* Returns the {@link java.util.function.UnaryOperator}&lt;HttpEntity&gt; for the given coding, or {@code null}.
*/
public static UnaryOperator<HttpEntity> decoder(final ContentCoding coding) {
final Codec c = REGISTRY.get(coding);
return c != null ? c.decoder : null;
}

/**
* Returns the {@link java.util.function.UnaryOperator}&lt;HttpEntity&gt; for the given coding, or {@code null}.
*/
public static UnaryOperator<HttpEntity> encoder(final ContentCoding coding) {
final Codec c = REGISTRY.get(coding);
return c != null ? c.encoder : null;
}

static final class Codec {
final UnaryOperator<HttpEntity> encoder;
final UnaryOperator<HttpEntity> decoder;

Codec(final UnaryOperator<HttpEntity> enc, final UnaryOperator<HttpEntity> dec) {
this.encoder = enc;
this.decoder = dec;
}

static Codec encodeOnly(final UnaryOperator<HttpEntity> e) {
return new Codec(e, null);
}

static Codec decodeOnly(final UnaryOperator<HttpEntity> d) {
return new Codec(null, d);
}
}

}
Loading
Loading