Merged /httpcomponents/httpclient/branches/branch_4_1:r755593-811107

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@811110 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2009-09-03 20:33:15 +00:00
parent 9ce0d5d761
commit d384ec4e3a
5 changed files with 874 additions and 0 deletions

View File

@ -1,3 +1,10 @@
Changes since 4.0
-------------------
* [HTTPCLIENT-834] Transparent content encoding support.
Contributed by James Abley <james.abley at gmail.com>
Release 4.0
-------------------

View File

@ -0,0 +1,109 @@
/*
* $HeadURL$
* $Revision$
* $Date$
*
* ====================================================================
* 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.http.impl.client;
import java.io.IOException;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.protocol.HttpContext;
/**
* Class responsible for handling Content Encoding in HTTP. This takes the form of
* an {@link HttpRequestInterceptor} that will modify the {@link HttpRequest} if the client hasn't
* already specified an <code>Accept-Encoding</code> header. There is an accompanying
* {@link HttpResponseInterceptor} implementation that will only examine the {@link HttpResponse}
* if the {@link HttpRequestInterceptor} implementation did any modifications.
* <p>
* Instances of this class are stateless, therefore they're thread-safe and immutable.
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5
*/
class ContentEncodingProcessor implements HttpResponseInterceptor, HttpRequestInterceptor {
/**
* {@inheritDoc}
*/
public void process(
HttpRequest request, HttpContext context) throws HttpException, IOException {
/*
* If a client of this library has already set this header, presume that they did so for
* a reason and so this instance shouldn't handle the response at all.
*/
if (!request.containsHeader("Accept-Encoding")) {
/* Signal support for Accept-Encoding transfer encodings. */
// TODO add compress support.
request.addHeader("Accept-Encoding", "gzip,deflate");
/* Store the fact that the request was modified, so that we can potentially handle
* the response. */
context.setAttribute(ContentEncodingProcessor.class.getName(), Boolean.TRUE);
}
}
/**
* {@inheritDoc}
*/
public void process(
HttpResponse response, HttpContext context) throws HttpException, IOException {
if (context.getAttribute(ContentEncodingProcessor.class.getName()) != null) {
HttpEntity entity = response.getEntity();
if (entity != null) { // It wasn't a 304 Not Modified response, 204 No Content or similar
Header ceheader = entity.getContentEncoding();
if (ceheader != null) {
HeaderElement[] codecs = ceheader.getElements();
for (int i = 0, n = codecs.length; i < n; ++i) {
if ("gzip".equalsIgnoreCase(codecs[i].getName())) {
response.setEntity(new GzipDecompressingEntity(response.getEntity()));
return;
} else if ("deflate".equalsIgnoreCase(codecs[i].getName())) {
response.setEntity(new DeflateDecompressingEntity(response.getEntity()));
return;
}
// TODO add compress. identity is a no-op.
}
}
}
}
}
}

View File

@ -0,0 +1,174 @@
/*
* $HeadURL$
* $Revision$
* $Date$
*
* ====================================================================
* 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.http.impl.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;
/**
* {@link HttpEntityWrapper} responsible for handling deflate Content Coded responses. In RFC2616
* terms, <code>deflate</code> means a <code>zlib</code> stream as defined in RFC1950. Some server
* implementations have misinterpreted RFC2616 to mean that a <code>deflate</code> stream as
* defined in RFC1951 should be used (or maybe they did that since that's how IE behaves?). It's
* confusing that <code>deflate</code> in HTTP 1.1 means <code>zlib</code> streams rather than
* <code>deflate</code> streams. We handle both types in here, since that's what is seen on the
* internet. Moral - prefer <code>gzip</code>!
*/
class DeflateDecompressingEntity extends HttpEntityWrapper {
/**
* Creates a new {@link DeflateDecompressingEntity} which will wrap the specified
* {@link HttpEntity}.
*
* @param entity
* a non-null {@link HttpEntity} to be wrapped
*/
public DeflateDecompressingEntity(final HttpEntity entity) {
super(entity);
}
/**
* {@inheritDoc}
*/
@Override
public InputStream getContent() throws IOException {
InputStream wrapped = this.wrappedEntity.getContent();
/*
* A zlib stream will have a header.
*
* CMF | FLG [| DICTID ] | ...compressed data | ADLER32 |
*
* * CMF is one byte.
*
* * FLG is one byte.
*
* * DICTID is four bytes, and only present if FLG.FDICT is set.
*
* Sniff the content. Does it look like a zlib stream, with a CMF, etc? c.f. RFC1950,
* section 2.2. http://tools.ietf.org/html/rfc1950#page-4
*
* We need to see if it looks like a proper zlib stream, or whether it is just a deflate
* stream. RFC2616 calls zlib streams deflate. Confusing, isn't it? That's why some servers
* implement deflate Content-Encoding using deflate streams, rather than zlib streams.
*
* We could start looking at the bytes, but to be honest, someone else has already read
* the RFCs and implemented that for us. So we'll just use the JDK libraries and exception
* handling to do this. If that proves slow, then we could potentially change this to check
* the first byte - does it look like a CMF? What about the second byte - does it look like
* a FLG, etc.
*/
/* We read a small buffer to sniff the content. */
byte[] peeked = new byte[6];
PushbackInputStream pushback = new PushbackInputStream(wrapped, peeked.length);
int headerLength = pushback.read(peeked);
if (headerLength == -1) {
throw new IOException("Unable to read the response");
}
/* We try to read the first uncompressed byte. */
byte[] dummy = new byte[1];
Inflater inf = new Inflater();
try {
int n;
while ((n = inf.inflate(dummy)) == 0) {
if (inf.finished()) {
/* Not expecting this, so fail loudly. */
throw new IOException("Unable to read the response");
}
if (inf.needsDictionary()) {
/* Need dictionary - then it must be zlib stream with DICTID part? */
break;
}
if (inf.needsInput()) {
inf.setInput(peeked);
}
}
if (n == -1) {
throw new IOException("Unable to read the response");
}
/*
* We read something without a problem, so it's a valid zlib stream. Just need to reset
* and return an unused InputStream now.
*/
pushback.unread(peeked, 0, headerLength);
return new InflaterInputStream(pushback);
} catch (DataFormatException e) {
/* Presume that it's an RFC1951 deflate stream rather than RFC1950 zlib stream and try
* again. */
pushback.unread(peeked, 0, headerLength);
return new InflaterInputStream(pushback, new Inflater(true));
}
}
/**
* {@inheritDoc}
*/
@Override
public Header getContentEncoding() {
/* This HttpEntityWrapper has dealt with the Content-Encoding. */
return null;
}
/**
* {@inheritDoc}
*/
@Override
public long getContentLength() {
/* Length of inflated content is unknown. */
return -1;
}
}

View File

@ -0,0 +1,90 @@
/*
* $HeadURL$
* $Revision$
* $Date$
*
* ====================================================================
* 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.http.impl.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;
/**
* {@link HttpEntityWrapper} for handling gzip Content Coded responses.
*/
class GzipDecompressingEntity extends HttpEntityWrapper {
/**
* Creates a new {@link GzipDecompressingEntity} which will wrap the specified
* {@link HttpEntity}.
*
* @param entity
* the non-null {@link HttpEntity} to be wrapped
*/
public GzipDecompressingEntity(final HttpEntity entity) {
super(entity);
}
/**
* {@inheritDoc}
*/
@Override
public InputStream getContent() throws IOException, IllegalStateException {
// the wrapped entity's getContent() decides about repeatability
InputStream wrappedin = wrappedEntity.getContent();
return new GZIPInputStream(wrappedin);
}
/**
* {@inheritDoc}
*/
@Override
public Header getContentEncoding() {
/* This HttpEntityWrapper has dealt with the Content-Encoding. */
return null;
}
/**
* {@inheritDoc}
*/
@Override
public long getContentLength() {
/* length of ungzipped content is not known */
return -1;
}
}

View File

@ -0,0 +1,494 @@
/*
* $HeadURL$
* $Revision$
* $Date$
*
* ====================================================================
* 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.http.impl.client;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.Deflater;
/* Don't use Java 6 functionality, even in tests. */
//import java.util.zip.DeflaterInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.localserver.ServerTestBase;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.util.EntityUtils;
/**
* Test case for how Content Codings are processed. By default, we want to do the right thing and
* require no intervention from the user of HttpClient, but we still want to let clients do their
* own thing if they so wish.
*/
public class TestContentCodings extends ServerTestBase {
public TestContentCodings(String testName) {
super(testName);
}
/**
* Test for when we don't get an entity back; e.g. for a 204 or 304 response; nothing blows
* up with the new behaviour.
*
* @throws Exception
* if there was a problem
*/
public void testResponseWithNoContent() throws Exception {
this.localServer.register("*", new HttpRequestHandler() {
/**
* {@inheritDoc}
*/
public void handle(
HttpRequest request,
HttpResponse response,
HttpContext context) throws HttpException, IOException {
response.setStatusCode(HttpStatus.SC_NO_CONTENT);
}
});
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("/some-resource");
HttpResponse response = client.execute(getServerHttp(), request);
assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
assertNull(response.getEntity());
client.getConnectionManager().shutdown();
}
/**
* Test for when we are handling content from a server that has correctly interpreted RFC2616
* to return RFC1950 streams for <code>deflate</code> content coding.
*
* @throws Exception
* @see {@link DeflateDecompressingEntity}
*/
public void testDeflateSupportForServerReturningRfc1950Stream() throws Exception {
final String entityText = "Hello, this is some plain text coming back.";
this.localServer.register("*", createDeflateEncodingRequestHandler(entityText, false));
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("/some-resource");
HttpResponse response = client.execute(getServerHttp(), request);
assertEquals("The entity text is correctly transported", entityText,
EntityUtils.toString(response.getEntity()));
client.getConnectionManager().shutdown();
}
/**
* Test for when we are handling content from a server that has incorrectly interpreted RFC2616
* to return RFC1951 streams for <code>deflate</code> content coding.
*
* @throws Exception
* @see {@link DeflateDecompressingEntity}
*/
public void testDeflateSupportForServerReturningRfc1951Stream() throws Exception {
final String entityText = "Hello, this is some plain text coming back.";
this.localServer.register("*", createDeflateEncodingRequestHandler(entityText, true));
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("/some-resource");
HttpResponse response = client.execute(getServerHttp(), request);
assertEquals("The entity text is correctly transported", entityText,
EntityUtils.toString(response.getEntity()));
client.getConnectionManager().shutdown();
}
/**
* Test for a server returning gzipped content.
*
* @throws Exception
*/
public void testGzipSupport() throws Exception {
final String entityText = "Hello, this is some plain text coming back.";
this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("/some-resource");
HttpResponse response = client.execute(getServerHttp(), request);
assertEquals("The entity text is correctly transported", entityText,
EntityUtils.toString(response.getEntity()));
client.getConnectionManager().shutdown();
}
/**
* Try with a bunch of client threads, to check that it's thread-safe.
*
* @throws Exception
* if there was a problem
*/
public void testThreadSafetyOfContentCodings() throws Exception {
final String entityText = "Hello, this is some plain text coming back.";
this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
/*
* Create a load of workers which will access the resource. Half will use the default
* gzip behaviour; half will require identity entity.
*/
int clients = 100;
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, clients);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
final HttpClient httpClient = new DefaultHttpClient(cm, params);
ExecutorService executor = Executors.newFixedThreadPool(clients);
CountDownLatch startGate = new CountDownLatch(1);
CountDownLatch endGate = new CountDownLatch(clients);
List<WorkerTask> workers = new ArrayList<WorkerTask>();
for (int i = 0; i < clients; ++i) {
workers.add(new WorkerTask(httpClient, i % 2 == 0, startGate, endGate));
}
for (WorkerTask workerTask : workers) {
/* Set them all in motion, but they will block until we call startGate.countDown(). */
executor.execute(workerTask);
}
startGate.countDown();
/* Wait for the workers to complete. */
endGate.await();
for (WorkerTask workerTask : workers) {
if (workerTask.isFailed()) {
fail("A worker failed");
}
assertEquals(entityText, workerTask.getText());
}
}
public void testExistingProtocolInterceptorsAreNotAffected() throws Exception {
final String entityText = "Hello, this is some plain text coming back.";
this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("/some-resource");
client.addRequestInterceptor(new HttpRequestInterceptor() {
/**
* {@inheritDoc}
*/
public void process(
HttpRequest request, HttpContext context) throws HttpException, IOException {
request.addHeader("Accept-Encoding", "gzip");
}
});
/* Get around Java The Language's lack of mutable closures */
final boolean clientSawGzip[] = new boolean[1];
client.addResponseInterceptor(new HttpResponseInterceptor() {
/**
* {@inheritDoc}
*/
public void process(
HttpResponse response, HttpContext context) throws HttpException, IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
Header ce = entity.getContentEncoding();
if (ce != null) {
HeaderElement[] codecs = ce.getElements();
for (int i = 0, n = codecs.length; i < n; ++i) {
if ("gzip".equalsIgnoreCase(codecs[i].getName())) {
clientSawGzip[0] = true;
return;
}
}
}
}
}
});
client.execute(getServerHttp(), request);
assertTrue("Client which added the new custom protocol interceptor to handle gzip responses " +
"was unaffected.",
clientSawGzip[0]);
client.getConnectionManager().shutdown();
}
/**
* Creates a new {@link HttpRequestHandler} that will attempt to provide a deflate stream
* Content-Coding.
*
* @param entityText
* the non-null String entity text to be returned by the server
* @param rfc1951
* if true, then the stream returned will be a raw RFC1951 deflate stream, which
* some servers return as a result of misinterpreting the HTTP 1.1 RFC. If false,
* then it will return an RFC2616 compliant deflate encoded zlib stream.
* @return a non-null {@link HttpRequestHandler}
*/
private HttpRequestHandler createDeflateEncodingRequestHandler(
final String entityText, final boolean rfc1951) {
return new HttpRequestHandler() {
/**
* {@inheritDoc}
*/
public void handle(
HttpRequest request,
HttpResponse response,
HttpContext context) throws HttpException, IOException {
response.setEntity(new StringEntity(entityText));
response.addHeader("Content-Type", "text/plain");
Header[] acceptEncodings = request.getHeaders("Accept-Encoding");
for (Header header : acceptEncodings) {
for (HeaderElement element : header.getElements()) {
if ("deflate".equalsIgnoreCase(element.getName())) {
response.addHeader("Content-Encoding", "deflate");
/* Gack. DeflaterInputStream is Java 6. */
// response.setEntity(new InputStreamEntity(new DeflaterInputStream(new
// ByteArrayInputStream(
// entityText.getBytes("utf-8"))), -1));
byte[] uncompressed = entityText.getBytes("utf-8");
Deflater compressor = new Deflater(Deflater.DEFAULT_COMPRESSION, rfc1951);
compressor.setInput(uncompressed);
compressor.finish();
byte[] output = new byte[100];
int compressedLength = compressor.deflate(output);
byte[] compressed = new byte[compressedLength];
System.arraycopy(output, 0, compressed, 0, compressedLength);
response.setEntity(new InputStreamEntity(
new ByteArrayInputStream(compressed), compressedLength));
return;
}
}
}
}
};
}
/**
* Returns an {@link HttpRequestHandler} implementation that will attempt to provide a gzip
* Content-Encoding.
*
* @param entityText
* the non-null String entity to be returned by the server
* @return a non-null {@link HttpRequestHandler}
*/
private HttpRequestHandler createGzipEncodingRequestHandler(final String entityText) {
return new HttpRequestHandler() {
/**
* {@inheritDoc}
*/
public void handle(
HttpRequest request,
HttpResponse response,
HttpContext context) throws HttpException, IOException {
response.setEntity(new StringEntity(entityText));
response.addHeader("Content-Type", "text/plain");
Header[] acceptEncodings = request.getHeaders("Accept-Encoding");
for (Header header : acceptEncodings) {
for (HeaderElement element : header.getElements()) {
if ("gzip".equalsIgnoreCase(element.getName())) {
response.addHeader("Content-Encoding", "gzip");
/*
* We have to do a bit more work with gzip versus deflate, since
* Gzip doesn't appear to have an equivalent to DeflaterInputStream in
* the JDK.
*
* UPDATE: DeflaterInputStream is Java 6 anyway, so we have to do a bit
* of work there too!
*/
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
OutputStream out = new GZIPOutputStream(bytes);
ByteArrayInputStream uncompressed = new ByteArrayInputStream(
entityText.getBytes("utf-8"));
byte[] buf = new byte[60];
int n;
while ((n = uncompressed.read(buf)) != -1) {
out.write(buf, 0, n);
}
out.close();
byte[] arr = bytes.toByteArray();
response.setEntity(new InputStreamEntity(new ByteArrayInputStream(arr),
arr.length));
return;
}
}
}
}
};
}
/**
* Sub-ordinate task passed off to a different thread to be executed.
*
* @author jabley
*
*/
class WorkerTask implements Runnable {
/**
* The {@link HttpClient} used to make requests.
*/
private final HttpClient client;
/**
* The {@link HttpRequest} to be executed.
*/
private final HttpGet request;
/**
* Flag indicating if there were failures.
*/
private boolean failed = false;
/**
* The latch that this runnable instance should wait on.
*/
private final CountDownLatch startGate;
/**
* The latch that this runnable instance should countdown on when the runnable is finished.
*/
private final CountDownLatch endGate;
/**
* The text returned from the HTTP server.
*/
private String text;
WorkerTask(HttpClient client, boolean identity, CountDownLatch startGate, CountDownLatch endGate) {
this.client = client;
this.request = new HttpGet("/some-resource");
if (identity) {
request.addHeader("Accept-Encoding", "identity");
}
this.startGate = startGate;
this.endGate = endGate;
}
/**
* Returns the text of the HTTP entity.
*
* @return a String - may be null.
*/
public String getText() {
return this.text;
}
/**
* {@inheritDoc}
*/
public void run() {
try {
startGate.await();
try {
HttpResponse response = client.execute(TestContentCodings.this.getServerHttp(), request);
text = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
failed = true;
} finally {
endGate.countDown();
}
} catch (InterruptedException e) {
}
}
/**
* Returns true if this task failed, otherwise false.
*
* @return a flag
*/
boolean isFailed() {
return this.failed;
}
}
}