@@ -62,87 +62,98 @@ public static void runCompressorsTest(String endpoint, String acceptEncoding, St
6262 // Why not use RestAssured? Because it doesn't let you configure Accept-Encoding easily
6363 // and when it comes to Brotli, not at all.
6464 // No, given().header("Accept-Encoding", acceptEncoding) doesn't cut it.
65- final WebClient client = WebClient .create (Vertx .vertx (), new WebClientOptions ()
66- .setLogActivity (true )
67- .setFollowRedirects (true )
68- // Vert.x Web Client
69- // -----------------
70- // Why not use the client's built-in decompression support?
71- // Why you do decompression manually here?
72- // Because it then removes the original content-encoding header,
73- // and it fakes in a transfer-encoding header the server has never sent. Sad.
74- // RestAssured didn't let us configure Accept-Encoding easily, but at least
75- // it didn't mess with the response headers.
76- .setDecompressionSupported (false ));
77- final CompletableFuture <HttpResponse <Buffer >> future = new CompletableFuture <>();
78- client .requestAbs (HttpMethod .GET , endpoint )
79- .putHeader (HttpHeaders .ACCEPT_ENCODING .toString (), acceptEncoding )
80- .putHeader (HttpHeaders .ACCEPT .toString (), "*/*" )
81- .putHeader (HttpHeaders .USER_AGENT .toString (), "Tester" )
82- .send (ar -> {
83- if (ar .succeeded ()) {
84- future .complete (ar .result ());
85- } else {
86- future .completeExceptionally (ar .cause ());
87- }
88- });
65+ Vertx vertx = Vertx .vertx ();
8966 try {
90- final HttpResponse <Buffer > response = future .get ();
91- final String actualEncoding = response .headers ().get ("content-encoding" );
67+ final WebClient client = WebClient .create (vertx , new WebClientOptions ()
68+ .setLogActivity (true )
69+ .setFollowRedirects (true )
70+ // Vert.x Web Client
71+ // -----------------
72+ // Why not use the client's built-in decompression support?
73+ // Why you do decompression manually here?
74+ // Because it then removes the original content-encoding header,
75+ // and it fakes in a transfer-encoding header the server has never sent. Sad.
76+ // RestAssured didn't let us configure Accept-Encoding easily, but at least
77+ // it didn't mess with the response headers.
78+ .setDecompressionSupported (false ));
79+ final CompletableFuture <HttpResponse <Buffer >> future = new CompletableFuture <>();
80+ client .requestAbs (HttpMethod .GET , endpoint )
81+ .putHeader (HttpHeaders .ACCEPT_ENCODING .toString (), acceptEncoding )
82+ .putHeader (HttpHeaders .ACCEPT .toString (), "*/*" )
83+ .putHeader (HttpHeaders .USER_AGENT .toString (), "Tester" )
84+ .send (ar -> {
85+ if (ar .succeeded ()) {
86+ future .complete (ar .result ());
87+ } else {
88+ future .completeExceptionally (ar .cause ());
89+ }
90+ });
91+ try {
92+ final HttpResponse <Buffer > response = future .get ();
93+ final String actualEncoding = response .headers ().get ("content-encoding" );
9294
93- assertEquals (OK .code (), response .statusCode (),
94- "Http status must be OK." );
95- assertEquals (contentEncoding , actualEncoding ,
96- "Unexpected compressor selected." );
95+ assertEquals (OK .code (), response .statusCode (),
96+ "Http status must be OK." );
97+ assertEquals (contentEncoding , actualEncoding ,
98+ "Unexpected compressor selected." );
9799
98- final int receivedLength = parseInt (response .headers ().get ("content-length" ));
99- final int expectedLength = parseInt (contentLength );
100+ final int receivedLength = parseInt (response .headers ().get ("content-length" ));
101+ final int expectedLength = parseInt (contentLength );
100102
101- if (contentEncoding == null ) {
102- assertEquals (expectedLength , receivedLength ,
103- "No compression was expected, so the content-length must match exactly." );
104- } else {
105- final int expectedLengthWithTolerance = expectedLength + (expectedLength / 100 * COMPRESSION_TOLERANCE_PERCENT );
106- assertTrue (receivedLength <= expectedLengthWithTolerance ,
107- "Compression apparently failed: receivedLength: " + receivedLength +
108- " was supposed to be less or equal to expectedLength: " +
109- expectedLength + " plus " + COMPRESSION_TOLERANCE_PERCENT + "% tolerance, i.e. "
110- + expectedLengthWithTolerance + "." );
103+ if (contentEncoding == null ) {
104+ assertEquals (expectedLength , receivedLength ,
105+ "No compression was expected, so the content-length must match exactly." );
106+ } else {
107+ final int expectedLengthWithTolerance = expectedLength
108+ + (expectedLength / 100 * COMPRESSION_TOLERANCE_PERCENT );
109+ assertTrue (receivedLength <= expectedLengthWithTolerance ,
110+ "Compression apparently failed: receivedLength: " + receivedLength +
111+ " was supposed to be less or equal to expectedLength: " +
112+ expectedLength + " plus " + COMPRESSION_TOLERANCE_PERCENT + "% tolerance, i.e. "
113+ + expectedLengthWithTolerance + "." );
114+ }
115+ assertEquals (TEXT , decompress (actualEncoding , response .body ().getBytes ()), "Unexpected body text." );
116+ } catch (InterruptedException | ExecutionException e ) {
117+ fail (e );
111118 }
112- assertEquals (TEXT , decompress (actualEncoding , response .body ().getBytes ()), "Unexpected body text." );
113- } catch (InterruptedException | ExecutionException e ) {
114- fail (e );
119+ } finally {
120+ vertx .close ();
115121 }
116122 }
117123
118124 public static void runDecompressorsTest (String endpoint , String acceptEncoding , String contentEncoding ,
119125 String method ) {
120126 LOG .infof ("Endpoint %s; Accept-Encoding: %s; Content-Encoding: %s; Method: %s" ,
121127 endpoint , acceptEncoding , contentEncoding , method );
122- final WebClient client = WebClient .create (Vertx .vertx (), new WebClientOptions ()
123- .setLogActivity (true )
124- .setFollowRedirects (true )
125- .setDecompressionSupported (false ));
126- final CompletableFuture <HttpResponse <Buffer >> future = new CompletableFuture <>();
127- client .postAbs (endpoint )
128- .putHeader (HttpHeaders .CONTENT_ENCODING .toString (), contentEncoding )
129- .putHeader (HttpHeaders .ACCEPT .toString (), "*/*" )
130- .putHeader (HttpHeaders .USER_AGENT .toString (), "Tester" )
131- .sendBuffer (compress (contentEncoding , TEXT ), ar -> {
132- if (ar .succeeded ()) {
133- future .complete (ar .result ());
134- } else {
135- future .completeExceptionally (ar .cause ());
136- }
137- });
128+ Vertx vertx = Vertx .vertx ();
138129 try {
139- final HttpResponse <Buffer > response = future .get ();
140- final String actualEncoding = response .headers ().get ("content-encoding" );
141- final String body = decompress (actualEncoding , response .body ().getBytes ());
142- assertEquals (OK .code (), response .statusCode (), "Http status must be OK." );
143- assertEquals (TEXT , body , "Unexpected body text." );
144- } catch (InterruptedException | ExecutionException e ) {
145- fail (e );
130+ final WebClient client = WebClient .create (vertx , new WebClientOptions ()
131+ .setLogActivity (true )
132+ .setFollowRedirects (true )
133+ .setDecompressionSupported (false ));
134+ final CompletableFuture <HttpResponse <Buffer >> future = new CompletableFuture <>();
135+ client .postAbs (endpoint )
136+ .putHeader (HttpHeaders .CONTENT_ENCODING .toString (), contentEncoding )
137+ .putHeader (HttpHeaders .ACCEPT .toString (), "*/*" )
138+ .putHeader (HttpHeaders .USER_AGENT .toString (), "Tester" )
139+ .sendBuffer (compress (contentEncoding , TEXT ), ar -> {
140+ if (ar .succeeded ()) {
141+ future .complete (ar .result ());
142+ } else {
143+ future .completeExceptionally (ar .cause ());
144+ }
145+ });
146+ try {
147+ final HttpResponse <Buffer > response = future .get ();
148+ final String actualEncoding = response .headers ().get ("content-encoding" );
149+ final String body = decompress (actualEncoding , response .body ().getBytes ());
150+ assertEquals (OK .code (), response .statusCode (), "Http status must be OK." );
151+ assertEquals (TEXT , body , "Unexpected body text." );
152+ } catch (InterruptedException | ExecutionException e ) {
153+ fail (e );
154+ }
155+ } finally {
156+ vertx .close ();
146157 }
147158 }
148159
@@ -178,18 +189,29 @@ public static String decompress(String algorithm, byte[] payload) {
178189 if (algorithm != null && !"identity" .equalsIgnoreCase (algorithm )) {
179190 final EmbeddedChannel channel ;
180191 if ("gzip" .equalsIgnoreCase (algorithm )) {
181- channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .GZIP ));
192+ channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .GZIP , 0 ));
182193 } else if ("deflate" .equalsIgnoreCase (algorithm )) {
183- channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .ZLIB ));
194+ channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .ZLIB , 0 ));
184195 } else if ("br" .equalsIgnoreCase (algorithm )) {
185196 channel = new EmbeddedChannel (new BrotliDecoder ());
186197 } else {
187198 throw new RuntimeException ("Unexpected compression used by server: " + algorithm );
188199 }
200+
189201 channel .writeInbound (Unpooled .copiedBuffer (payload ));
190202 channel .finish ();
191- final ByteBuf decompressed = channel .readInbound ();
192- return decompressed .readCharSequence (decompressed .readableBytes (), StandardCharsets .UTF_8 ).toString ();
203+
204+ // Read all output buffers - decompression might produce multiple buffers
205+ final StringBuilder result = new StringBuilder ();
206+ ByteBuf decompressed ;
207+ while ((decompressed = channel .readInbound ()) != null ) {
208+ try {
209+ result .append (decompressed .readCharSequence (decompressed .readableBytes (), StandardCharsets .UTF_8 ));
210+ } finally {
211+ decompressed .release ();
212+ }
213+ }
214+ return result .toString ();
193215 } else {
194216 return new String (payload , StandardCharsets .UTF_8 );
195217 }
0 commit comments