1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.client.integration;
29
30 import java.io.ByteArrayInputStream;
31 import java.io.ByteArrayOutputStream;
32 import java.io.IOException;
33 import java.io.OutputStream;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.ExecutorService;
38 import java.util.concurrent.Executors;
39 import java.util.zip.Deflater;
40 import java.util.zip.GZIPOutputStream;
41
42 import org.apache.http.Consts;
43 import org.apache.http.Header;
44 import org.apache.http.HeaderElement;
45 import org.apache.http.HttpException;
46 import org.apache.http.HttpHost;
47 import org.apache.http.HttpRequest;
48 import org.apache.http.HttpResponse;
49 import org.apache.http.HttpStatus;
50 import org.apache.http.client.HttpClient;
51 import org.apache.http.client.methods.HttpGet;
52 import org.apache.http.entity.InputStreamEntity;
53 import org.apache.http.entity.StringEntity;
54 import org.apache.http.impl.client.BasicResponseHandler;
55 import org.apache.http.localserver.LocalServerTestBase;
56 import org.apache.http.protocol.HttpContext;
57 import org.apache.http.protocol.HttpRequestHandler;
58 import org.apache.http.util.EntityUtils;
59 import org.junit.Assert;
60 import org.junit.Test;
61
62
63
64
65
66
67 public class TestContentCodings extends LocalServerTestBase {
68
69
70
71
72
73
74
75
76 @Test
77 public void testResponseWithNoContent() throws Exception {
78 this.serverBootstrap.registerHandler("*", new HttpRequestHandler() {
79
80
81
82
83 @Override
84 public void handle(
85 final HttpRequest request,
86 final HttpResponse response,
87 final HttpContext context) throws HttpException, IOException {
88 response.setStatusCode(HttpStatus.SC_NO_CONTENT);
89 }
90 });
91
92 final HttpHost target = start();
93
94 final HttpGet request = new HttpGet("/some-resource");
95 final HttpResponse response = this.httpclient.execute(target, request);
96 Assert.assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
97 Assert.assertNull(response.getEntity());
98 }
99
100
101
102
103
104
105
106 @Test
107 public void testDeflateSupportForServerReturningRfc1950Stream() throws Exception {
108 final String entityText = "Hello, this is some plain text coming back.";
109
110 this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, false));
111
112 final HttpHost target = start();
113
114 final HttpGet request = new HttpGet("/some-resource");
115 final HttpResponse response = this.httpclient.execute(target, request);
116 Assert.assertEquals("The entity text is correctly transported", entityText,
117 EntityUtils.toString(response.getEntity()));
118 }
119
120
121
122
123
124
125
126 @Test
127 public void testDeflateSupportForServerReturningRfc1951Stream() throws Exception {
128 final String entityText = "Hello, this is some plain text coming back.";
129
130 this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, true));
131
132 final HttpHost target = start();
133
134 final HttpGet request = new HttpGet("/some-resource");
135 final HttpResponse response = this.httpclient.execute(target, request);
136 Assert.assertEquals("The entity text is correctly transported", entityText,
137 EntityUtils.toString(response.getEntity()));
138 }
139
140
141
142
143
144
145 @Test
146 public void testGzipSupport() throws Exception {
147 final String entityText = "Hello, this is some plain text coming back.";
148
149 this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
150
151 final HttpHost target = start();
152
153 final HttpGet request = new HttpGet("/some-resource");
154 final HttpResponse response = this.httpclient.execute(target, request);
155 Assert.assertEquals("The entity text is correctly transported", entityText,
156 EntityUtils.toString(response.getEntity()));
157 }
158
159
160
161
162
163
164
165 @Test
166 public void testThreadSafetyOfContentCodings() throws Exception {
167 final String entityText = "Hello, this is some plain text coming back.";
168
169 this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
170
171
172
173
174
175 final int clients = 100;
176
177 this.connManager.setMaxTotal(clients);
178
179 final HttpHost target = start();
180
181 final ExecutorService executor = Executors.newFixedThreadPool(clients);
182
183 final CountDownLatch startGate = new CountDownLatch(1);
184 final CountDownLatch endGate = new CountDownLatch(clients);
185
186 final List<WorkerTask> workers = new ArrayList<WorkerTask>();
187
188 for (int i = 0; i < clients; ++i) {
189 workers.add(new WorkerTask(this.httpclient, target, i % 2 == 0, startGate, endGate));
190 }
191
192 for (final WorkerTask workerTask : workers) {
193
194
195 executor.execute(workerTask);
196 }
197
198 startGate.countDown();
199
200
201 endGate.await();
202
203 for (final WorkerTask workerTask : workers) {
204 if (workerTask.isFailed()) {
205 Assert.fail("A worker failed");
206 }
207 Assert.assertEquals(entityText, workerTask.getText());
208 }
209 }
210
211 @Test
212 public void testHttpEntityWriteToForGzip() throws Exception {
213 final String entityText = "Hello, this is some plain text coming back.";
214
215 this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
216
217 final HttpHost target = start();
218
219 final HttpGet request = new HttpGet("/some-resource");
220 final HttpResponse response = this.httpclient.execute(target, request);
221 final ByteArrayOutputStream out = new ByteArrayOutputStream();
222
223 response.getEntity().writeTo(out);
224
225 Assert.assertEquals(entityText, out.toString("utf-8"));
226 }
227
228 @Test
229 public void testHttpEntityWriteToForDeflate() throws Exception {
230 final String entityText = "Hello, this is some plain text coming back.";
231
232 this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, true));
233
234 final HttpHost target = start();
235
236 final HttpGet request = new HttpGet("/some-resource");
237 final HttpResponse response = this.httpclient.execute(target, request);
238 final ByteArrayOutputStream out = new ByteArrayOutputStream();
239
240 response.getEntity().writeTo(out);
241
242 Assert.assertEquals(entityText, out.toString("utf-8"));
243 }
244
245 @Test
246 public void gzipResponsesWorkWithBasicResponseHandler() throws Exception {
247 final String entityText = "Hello, this is some plain text coming back.";
248
249 this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
250
251 final HttpHost target = start();
252
253 final HttpGet request = new HttpGet("/some-resource");
254 final String response = this.httpclient.execute(target, request, new BasicResponseHandler());
255 Assert.assertEquals("The entity text is correctly transported", entityText, response);
256 }
257
258 @Test
259 public void deflateResponsesWorkWithBasicResponseHandler() throws Exception {
260 final String entityText = "Hello, this is some plain text coming back.";
261
262 this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, false));
263
264 final HttpHost target = start();
265
266 final HttpGet request = new HttpGet("/some-resource");
267 final String response = this.httpclient.execute(target, request, new BasicResponseHandler());
268 Assert.assertEquals("The entity text is correctly transported", entityText, response);
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283 private HttpRequestHandler createDeflateEncodingRequestHandler(
284 final String entityText, final boolean rfc1951) {
285 return new HttpRequestHandler() {
286
287
288
289
290 @Override
291 public void handle(
292 final HttpRequest request,
293 final HttpResponse response,
294 final HttpContext context) throws HttpException, IOException {
295 response.setEntity(new StringEntity(entityText));
296 response.addHeader("Content-Type", "text/plain");
297 final Header[] acceptEncodings = request.getHeaders("Accept-Encoding");
298
299 for (final Header header : acceptEncodings) {
300 for (final HeaderElement element : header.getElements()) {
301 if ("deflate".equalsIgnoreCase(element.getName())) {
302 response.addHeader("Content-Encoding", "deflate");
303
304
305
306
307
308 final byte[] uncompressed = entityText.getBytes(Consts.UTF_8);
309 final Deflater compressor = new Deflater(Deflater.DEFAULT_COMPRESSION, rfc1951);
310 compressor.setInput(uncompressed);
311 compressor.finish();
312 final byte[] output = new byte[100];
313 final int compressedLength = compressor.deflate(output);
314 final byte[] compressed = new byte[compressedLength];
315 System.arraycopy(output, 0, compressed, 0, compressedLength);
316 response.setEntity(new InputStreamEntity(
317 new ByteArrayInputStream(compressed), compressedLength));
318 return;
319 }
320 }
321 }
322 }
323 };
324 }
325
326
327
328
329
330
331
332
333
334 private HttpRequestHandler createGzipEncodingRequestHandler(final String entityText) {
335 return new HttpRequestHandler() {
336
337
338
339
340 @Override
341 public void handle(
342 final HttpRequest request,
343 final HttpResponse response,
344 final HttpContext context) throws HttpException, IOException {
345 response.setEntity(new StringEntity(entityText));
346 response.addHeader("Content-Type", "text/plain");
347 final Header[] acceptEncodings = request.getHeaders("Accept-Encoding");
348
349 for (final Header header : acceptEncodings) {
350 for (final HeaderElement element : header.getElements()) {
351 if ("gzip".equalsIgnoreCase(element.getName())) {
352 response.addHeader("Content-Encoding", "gzip");
353
354
355
356
357
358
359
360
361
362 final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
363 final OutputStream out = new GZIPOutputStream(bytes);
364
365 final ByteArrayInputStream uncompressed = new ByteArrayInputStream(
366 entityText.getBytes(Consts.UTF_8));
367
368 final byte[] buf = new byte[60];
369
370 int n;
371 while ((n = uncompressed.read(buf)) != -1) {
372 out.write(buf, 0, n);
373 }
374
375 out.close();
376
377 final byte[] arr = bytes.toByteArray();
378 response.setEntity(new InputStreamEntity(new ByteArrayInputStream(arr),
379 arr.length));
380
381 return;
382 }
383 }
384 }
385 }
386 };
387 }
388
389
390
391
392
393
394
395 class WorkerTask implements Runnable {
396
397 private final HttpClient client;
398 private final HttpHost target;
399 private final HttpGet request;
400 private final CountDownLatch startGate;
401 private final CountDownLatch endGate;
402
403 private boolean failed = false;
404 private String text;
405
406 WorkerTask(final HttpClient client, final HttpHost target, final boolean identity, final CountDownLatch startGate, final CountDownLatch endGate) {
407 this.client = client;
408 this.target = target;
409 this.request = new HttpGet("/some-resource");
410 if (identity) {
411 request.addHeader("Accept-Encoding", "identity");
412 }
413 this.startGate = startGate;
414 this.endGate = endGate;
415 }
416
417
418
419
420
421
422 public String getText() {
423 return this.text;
424 }
425
426
427
428
429 @Override
430 public void run() {
431 try {
432 startGate.await();
433 try {
434 final HttpResponse response = client.execute(target, request);
435 text = EntityUtils.toString(response.getEntity());
436 } catch (final Exception e) {
437 failed = true;
438 } finally {
439 endGate.countDown();
440 }
441 } catch (final InterruptedException ignore) {
442 }
443 }
444
445
446
447
448
449
450 boolean isFailed() {
451 return this.failed;
452 }
453 }
454 }