@@ -11,6 +11,10 @@ import org.openapitools.jackson.nullable.JsonNullableModule;
1111{ {/openApiNullable} }
1212
1313import java.io.InputStream;
14+ import java.io.IOException;
15+ { {#useGzipFeature} }
16+ import java.io.ByteArrayOutputStream;
17+ { {/useGzipFeature} }
1418import java.net.URI;
1519import java.net.URLEncoder;
1620import java.net.http.HttpClient;
@@ -25,6 +29,13 @@ import java.util.Collections;
2529import java.util.List;
2630import java.util.StringJoiner;
2731import java.util.function.Consumer;
32+ import java.util.Optional;
33+ import java.util.zip.GZIPInputStream;
34+ { {#useGzipFeature} }
35+ import java.util.function.Supplier;
36+ import java.util.Objects;
37+ import java.util.zip.GZIPOutputStream;
38+ { {/useGzipFeature} }
2839import java.util.stream.Collectors;
2940
3041import static java.nio.charset.StandardCharsets.UTF_8;
@@ -54,7 +65,7 @@ public class ApiClient {
5465 protected String basePath;
5566 protected Consumer< HttpRequest.Builder> interceptor;
5667 protected Consumer< HttpResponse< InputStream>> responseInterceptor;
57- protected Consumer< HttpResponse< String >> asyncResponseInterceptor;
68+ protected Consumer< HttpResponse< InputStream >> asyncResponseInterceptor;
5869 protected Duration readTimeout;
5970 protected Duration connectTimeout;
6071
@@ -378,7 +389,7 @@ public class ApiClient {
378389 * of null resets the interceptor to a no-op.
379390 * @return This object.
380391 */
381- public ApiClient setAsyncResponseInterceptor(Consumer<HttpResponse <String >> interceptor) {
392+ public ApiClient setAsyncResponseInterceptor(Consumer<HttpResponse <InputStream >> interceptor) {
382393 this.asyncResponseInterceptor = interceptor;
383394 return this;
384395 }
@@ -388,7 +399,7 @@ public class ApiClient {
388399 *
389400 * @return The custom interceptor that was set, or null if there isn't any.
390401 */
391- public Consumer<HttpResponse <String >> getAsyncResponseInterceptor() {
402+ public Consumer<HttpResponse <InputStream >> getAsyncResponseInterceptor() {
392403 return asyncResponseInterceptor;
393404 }
394405
@@ -448,4 +459,127 @@ public class ApiClient {
448459 public Duration getConnectTimeout() {
449460 return connectTimeout;
450461 }
462+
463+ public static InputStream getResponseBody(HttpResponse<InputStream > response) throws IOException {
464+ if (response == null) {
465+ return null;
466+ }
467+ InputStream body = response.body();
468+ if (body == null) {
469+ return null;
470+ }
471+ Optional<String > encoding = response.headers().firstValue("Content-Encoding");
472+ if (encoding.isPresent()) {
473+ for (String token : encoding.get().split(" ," )) {
474+ if (" gzip" .equalsIgnoreCase(token.trim())) {
475+ return new GZIPInputStream(body);
476+ }
477+ }
478+ }
479+ return body;
480+ }
481+
482+ { {#useGzipFeature} }
483+ public static HttpRequest.BodyPublisher gzipRequestBody(Supplier<InputStream > bodySupplier) {
484+ Objects.requireNonNull(bodySupplier, " bodySupplier must not be null" );
485+ return HttpRequest.BodyPublishers.ofInputStream(() -> new GzipCompressingInputStream(bodySupplier));
486+ }
487+
488+ private static final class GzipCompressingInputStream extends InputStream {
489+ private final Supplier< InputStream> supplier;
490+ private final byte[] readBuffer = new byte[8192];
491+ private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
492+ private InputStream source;
493+ private GZIPOutputStream gzipStream;
494+ private byte[] currentChunk = new byte[0];
495+ private int chunkPosition = 0;
496+ private boolean finished = false ;
497+
498+ private GzipCompressingInputStream(Supplier< InputStream> supplier) {
499+ this.supplier = Objects.requireNonNull(supplier, " bodySupplier must not be null" );
500+ }
501+
502+ private void ensureInitialized() throws IOException {
503+ if (source == null) {
504+ source = Objects.requireNonNull(supplier.get(), " bodySupplier returned null InputStream" );
505+ gzipStream = new GZIPOutputStream(buffer, true );
506+ }
507+ }
508+
509+ private boolean fillBuffer() throws IOException {
510+ ensureInitialized();
511+ while (chunkPosition >= currentChunk.length) {
512+ buffer.reset();
513+ if (finished) {
514+ return false ;
515+ }
516+ int bytesRead = source.read(readBuffer);
517+ if (bytesRead == -1) {
518+ gzipStream.finish();
519+ gzipStream.close();
520+ source.close();
521+ finished = true ;
522+ } else {
523+ gzipStream.write(readBuffer, 0, bytesRead);
524+ gzipStream.flush();
525+ }
526+ currentChunk = buffer.toByteArray();
527+ chunkPosition = 0;
528+ if (currentChunk.length == 0 && !finished) {
529+ continue;
530+ }
531+ if (currentChunk.length == 0 && finished) {
532+ return false ;
533+ }
534+ return true;
535+ }
536+ return true;
537+ }
538+
539+ @Override
540+ public int read() throws IOException {
541+ if (! fillBuffer()) {
542+ return -1;
543+ }
544+ return currentChunk[chunkPosition++] & 0xFF;
545+ }
546+
547+ @Override
548+ public int read(byte[] b, int off, int len) throws IOException {
549+ if (! fillBuffer()) {
550+ return -1;
551+ }
552+ int bytesToCopy = Math.min(len, currentChunk.length - chunkPosition);
553+ System.arraycopy(currentChunk, chunkPosition, b, off, bytesToCopy);
554+ chunkPosition += bytesToCopy;
555+ return bytesToCopy;
556+ }
557+
558+ @Override
559+ public void close() throws IOException {
560+ IOException exception = null;
561+ if (source != null) {
562+ try {
563+ source.close();
564+ } catch (IOException e) {
565+ exception = e;
566+ } finally {
567+ source = null;
568+ }
569+ }
570+ if (gzipStream != null) {
571+ try {
572+ gzipStream.close();
573+ } catch (IOException e) {
574+ exception = exception == null ? e : exception;
575+ } finally {
576+ gzipStream = null;
577+ }
578+ }
579+ if (exception != null) {
580+ throw exception;
581+ }
582+ }
583+ }
584+ { {/useGzipFeature} }
451585}
0 commit comments