@@ -62,87 +62,98 @@ public static void runCompressorsTest(String endpoint, String acceptEncoding, St
62
62
// Why not use RestAssured? Because it doesn't let you configure Accept-Encoding easily
63
63
// and when it comes to Brotli, not at all.
64
64
// 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 ();
89
66
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" );
92
94
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." );
97
99
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 );
100
102
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 );
111
118
}
112
- assertEquals (TEXT , decompress (actualEncoding , response .body ().getBytes ()), "Unexpected body text." );
113
- } catch (InterruptedException | ExecutionException e ) {
114
- fail (e );
119
+ } finally {
120
+ vertx .close ();
115
121
}
116
122
}
117
123
118
124
public static void runDecompressorsTest (String endpoint , String acceptEncoding , String contentEncoding ,
119
125
String method ) {
120
126
LOG .infof ("Endpoint %s; Accept-Encoding: %s; Content-Encoding: %s; Method: %s" ,
121
127
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 ();
138
129
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 ();
146
157
}
147
158
}
148
159
@@ -178,18 +189,29 @@ public static String decompress(String algorithm, byte[] payload) {
178
189
if (algorithm != null && !"identity" .equalsIgnoreCase (algorithm )) {
179
190
final EmbeddedChannel channel ;
180
191
if ("gzip" .equalsIgnoreCase (algorithm )) {
181
- channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .GZIP ));
192
+ channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .GZIP , 0 ));
182
193
} else if ("deflate" .equalsIgnoreCase (algorithm )) {
183
- channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .ZLIB ));
194
+ channel = new EmbeddedChannel (newZlibDecoder (ZlibWrapper .ZLIB , 0 ));
184
195
} else if ("br" .equalsIgnoreCase (algorithm )) {
185
196
channel = new EmbeddedChannel (new BrotliDecoder ());
186
197
} else {
187
198
throw new RuntimeException ("Unexpected compression used by server: " + algorithm );
188
199
}
200
+
189
201
channel .writeInbound (Unpooled .copiedBuffer (payload ));
190
202
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 ();
193
215
} else {
194
216
return new String (payload , StandardCharsets .UTF_8 );
195
217
}
0 commit comments