Updated HttpClient tutorial to 4.3 APIs (fundamentals, auth, caching and fluent facade chapters)

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1514003 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2013-08-14 18:41:58 +00:00
parent 71ef668258
commit a418347845
9 changed files with 364 additions and 629 deletions

View File

@ -42,80 +42,38 @@ class MyLineParser extends BasicLineParser {
@Override
public Header parseHeader(
final CharArrayBuffer buffer) throws ParseException {
CharArrayBuffer buffer) throws ParseException {
try {
return super.parseHeader(buffer);
} catch (ParseException ex) {
// Suppress ParseException exception
return new BasicHeader("invalid", buffer.toString());
return new BasicHeader(buffer.toString(), null);
}
}
}
]]></programlisting>
</listitem>
<listitem>
<para>Provide a custom <interfacename>OperatedClientConnection</interfacename>
implementation. Replace default request / response parsers, request / response
formatters with custom ones as required. Implement different message writing /
reading code if necessary.</para>
<para>Provide a custom <interfacename>HttpConnectionFactory</interfacename>
implementation. Replace default request writer and / or response parser
with custom ones as required. </para>
<programlisting><![CDATA[
class MyClientConnection extends DefaultClientConnection {
@Override
protected HttpMessageParser createResponseParser(
final SessionInputBuffer buffer,
final HttpResponseFactory responseFactory,
final HttpParams params) {
return new DefaultResponseParser(
buffer,
new MyLineParser(),
responseFactory,
params);
}
}
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory =
new ManagedHttpClientConnectionFactory(
new DefaultHttpRequestWriterFactory(),
new DefaultHttpResponseParserFactory(
new MyLineParser(), new DefaultHttpResponseFactory()));
]]></programlisting>
</listitem>
<listitem>
<para>Provide a custom <interfacename>ClientConnectionOperator</interfacename>
interface implementation in order to create connections of new class. Implement
different socket initialization code if necessary.</para>
<para>Configure HttpClient to use the custom connection factory.</para>
<programlisting><![CDATA[
class MyClientConnectionOperator extends DefaultClientConnectionOperator {
public MyClientConnectionOperator(final SchemeRegistry sr) {
super(sr);
}
@Override
public OperatedClientConnection createConnection() {
return new MyClientConnection();
}
}
]]></programlisting>
</listitem>
<listitem>
<para>Provide a custom <interfacename>ClientConnectionManager</interfacename>
interface implementation in order to create connection operator of new
class.</para>
<programlisting><![CDATA[
class MyClientConnManager extends SingleClientConnManager {
public MyClientConnManager(
final HttpParams params,
final SchemeRegistry sr) {
super(params, sr);
}
@Override
protected ClientConnectionOperator createConnectionOperator(
final SchemeRegistry sr) {
return new MyClientConnectionOperator(sr);
}
}
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
connFactory);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.build();
]]></programlisting>
</listitem>
</itemizedlist>
@ -145,73 +103,62 @@ class MyClientConnManager extends SingleClientConnManager {
connection based authentication schemes such as <literal>NTLM</literal> or that of
the SSL session with client authentication turned on. If both are unavailable, null
token will be returned.</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("http://localhost:8080/");
CloseableHttpResponse response = httpclient.execute(httpget, context);
try {
Principal principal = context.getUserToken(Principal.class);
System.out.println(principal);
} finally {
response.close();
}
]]></programlisting>
<para>Users can provide a custom implementation if the default one does not satisfy
their needs:</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.setUserTokenHandler(new UserTokenHandler() {
UserTokenHandler userTokenHandler = new UserTokenHandler() {
public Object getUserToken(HttpContext context) {
return context.getAttribute("my-token");
}
});
};
CloseableHttpClient httpclient = HttpClients.custom()
.setUserTokenHandler(userTokenHandler)
.build();
]]></programlisting>
</section>
<section>
<title>User token and execution context</title>
<para>In the course of HTTP request execution HttpClient adds the following user
identity related objects to the execution context: </para>
<itemizedlist>
<listitem>
<formalpara>
<title><constant>ClientContext.USER_TOKEN</constant>='http.user-token':</title>
<para>Object instance representing the actual user identity, usually
expected to be an instance of <interfacename>Principle</interfacename>
interface</para>
</formalpara>
</listitem>
</itemizedlist>
<para>One can find out whether or not the connection used to execute the request was
stateful by examining the content of the local HTTP context after the request has
been executed.</para>
<title>Persistent stateful connections</title>
<para>Please note that a persistent connection that carries a state object can be reused
only if the same state object is bound to the execution context when requests
are executed. So, it is really important to ensure the either same context is
reused for execution of subsequent HTTP requests by the same user or the user
token is bound to the context prior to request execution.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
Object userToken = localContext.getAttribute(ClientContext.USER_TOKEN);
System.out.println(userToken);
]]></programlisting>
<section>
<title>Persistent stateful connections</title>
<para>Please note that a persistent connection that carries a state object can be reused
only if the same state object is bound to the execution context when requests
are executed. So, it is really important to ensure the either same context is
reused for execution of subsequent HTTP requests by the same user or the user
token is bound to the context prior to request execution.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext1 = new BasicHttpContext();
HttpGet httpget1 = new HttpGet("http://localhost:8080/");
HttpResponse response1 = httpclient.execute(httpget1, localContext1);
HttpEntity entity1 = response1.getEntity();
EntityUtils.consume(entity1);
Principal principal = (Principal) localContext1.getAttribute(
ClientContext.USER_TOKEN);
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClientContext context1 = HttpClientContext.create();
HttpGet httpget1 = new HttpGet("http://localhost:8080/");
CloseableHttpResponse response1 = httpclient.execute(httpget1, context1);
try {
HttpEntity entity1 = response1.getEntity();
} finally {
response1.close();
}
Principal principal = context1.getUserToken(Principal.class);
HttpContext localContext2 = new BasicHttpContext();
localContext2.setAttribute(ClientContext.USER_TOKEN, principal);
HttpGet httpget2 = new HttpGet("http://localhost:8080/");
HttpResponse response2 = httpclient.execute(httpget2, localContext2);
HttpEntity entity2 = response2.getEntity();
EntityUtils.consume(entity2);
HttpClientContext context2 = HttpClientContext.create();
context2.setUserToken(principal);
HttpGet httpget2 = new HttpGet("http://localhost:8080/");
CloseableHttpResponse response2 = httpclient.execute(httpget2, context2);
try {
HttpEntity entity2 = response2.getEntity();
} finally {
response2.close();
}
]]></programlisting>
</section>
</section>
</section>
</chapter>

View File

@ -132,100 +132,6 @@ pwd
</listitem>
</itemizedlist>
</section>
<section>
<title>HTTP authentication parameters</title>
<para>These are parameters that be used to customize the HTTP authentication process and
behaviour of individual authentication schemes:</para>
<itemizedlist>
<listitem>
<formalpara>
<title><constant>ClientPNames.HANDLE_AUTHENTICATION</constant>='http.protocol.handle-authentication':</title>
<para>defines whether authentication should be handled automatically. This
parameter expects a value of type <classname>java.lang.Boolean</classname>.
If this parameter is not set, HttpClient will handle authentication
automatically.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>AuthPNames.CREDENTIAL_CHARSET</constant>='http.auth.credential-charset':</title>
<para>defines the charset to be used when encoding user credentials. This
parameter expects a value of type <literal>java.lang.String</literal>. If
this parameter is not set, <literal>US-ASCII</literal> will be used.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>AuthPNames.TARGET_AUTH_PREF</constant>='http.auth.target-scheme-pref':</title>
<para>Defines the order of preference for supported
<interfacename>AuthScheme</interfacename>s when authenticating with the
target host. This parameter expects a value of type
<interface>java.util.Collection</interface>. The collection is expected
to contain <classname>java.lang.String</classname> instances representing
an id of an authentication scheme.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>AuthPNames.PROXY_AUTH_PREF</constant>='http.auth.proxy-scheme-pref':</title>
<para>Defines the order of preference for supported
<interfacename>AuthScheme</interfacename>s when authenticating with the
proxy host. This parameter expects a value of type
<interface>java.util.Collection</interface>. The collection is expected
to contain <classname>java.lang.String</classname> instances representing
an id of an authentication scheme.</para>
</formalpara>
</listitem>
</itemizedlist>
<para>For example, one can force HttpClient to use a different order of preference for
authentication schemes</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient(ccm, params);
// Choose BASIC over DIGEST for proxy authentication
List<String> authpref = new ArrayList<String>();
authpref.add(AuthPolicy.BASIC);
authpref.add(AuthPolicy.DIGEST);
httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
]]></programlisting>
</section>
<section>
<title>Authentication scheme registry</title>
<para>HttpClient maintains a registry of available authentication schemes using
the <classname>AuthSchemeRegistry</classname> class. The following schemes are
registered per default:</para>
<itemizedlist>
<listitem>
<formalpara>
<title>AuthPolicy.BASIC:</title>
<para>Basic authentication</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>AuthPolicy.DIGEST:</title>
<para>Digest authentication</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>AuthPolicy.NTLM:</title>
<para>NTLMv1, NTLMv2, and NTLM2 Session authentication</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>AuthPolicy.SPNEGO:</title>
<para>SPNEGO authentication</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>AuthPolicy.KERBEROS:</title>
<para>Kerberos authentication</para>
</formalpara>
</listitem>
</itemizedlist>
</section>
<section>
<title>Credentials provider</title>
<para>Credentials providers are intended to maintain a set of user credentials and to be
@ -289,23 +195,20 @@ null
<itemizedlist>
<listitem>
<formalpara>
<title><constant>ClientContext.AUTHSCHEME_REGISTRY</constant>='http.authscheme-registry':</title>
<para><classname>AuthSchemeRegistry</classname> instance representing the actual
<para><interfacename>Lookup</interfacename> instance representing the actual
authentication scheme registry. The value of this attribute set in the local
context takes precedence over the default one.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientContext.CREDS_PROVIDER</constant>='http.auth.credentials-provider':</title>
<para><interfacename>CookieSpec</interfacename> instance representing the actual
credentials provider. The value of this attribute set in the local context
takes precedence over the default one.</para>
<para><interfacename>CredentialsProvider</interfacename> instance representing
the actual credentials provider. The value of this attribute set in the
local context takes precedence over the default one.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientContext.TARGET_AUTH_STATE</constant>='http.auth.target-scope':</title>
<para><classname>AuthState</classname> instance representing the actual target
authentication state. The value of this attribute set in the local context
takes precedence over the default one.</para>
@ -313,7 +216,6 @@ null
</listitem>
<listitem>
<formalpara>
<title><constant>ClientContext.PROXY_AUTH_STATE</constant>='http.auth.proxy-scope':</title>
<para><classname>AuthState</classname> instance representing the actual proxy
authentication state. The value of this attribute set in the local context
takes precedence over the default one.</para>
@ -321,7 +223,6 @@ null
</listitem>
<listitem>
<formalpara>
<title><constant>ClientContext.AUTH_CACHE</constant>='http.auth.auth-cache':</title>
<para><interfacename>AuthCache</interfacename> instance representing the actual
authentication data cache. The value of this attribute set in the local
context takes precedence over the default one.</para>
@ -332,18 +233,25 @@ null
the HTTP authentication context prior to request execution, or to examine its state after
the request has been executed:</para>
<programlisting><![CDATA[
HttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
CloseableHttpClient httpclient = <...>
AuthState proxyAuthState = (AuthState) localContext.getAttribute(
ClientContext.PROXY_AUTH_STATE);
CredentialsProvider credsProvider = <...>
Lookup<AuthSchemeProvider> authRegistry = <...>
AuthCache authCache = <...>
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthSchemeRegistry(authRegistry);
context.setAuthCache(authCache);
HttpGet httpget = new HttpGet("http://somehost/");
CloseableHttpResponse response1 = httpclient.execute(httpget, context);
<...>
AuthState proxyAuthState = context.getProxyAuthState();
System.out.println("Proxy auth state: " + proxyAuthState.getState());
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
AuthState targetAuthState = (AuthState) localContext.getAttribute(
ClientContext.TARGET_AUTH_STATE);
AuthState targetAuthState = context.getTargetAuthState();
System.out.println("Target auth state: " + targetAuthState.getState());
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());
@ -368,12 +276,12 @@ System.out.println("Target auth credentials: " + targetAuthState.getCredentials(
<para>Nonethess one can configure HttpClient to authenticate preemptively by prepopulating
the authentication data cache.</para>
<programlisting><![CDATA[
HttpHost targetHost = new HttpHost("localhost", 80, "http");
CloseableHttpClient httpclient = <...>
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
HttpHost targetHost = new HttpHost("localhost", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials("username", "password"));
// Create AuthCache instance
@ -383,14 +291,19 @@ BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
// Add AuthCache to the execution context
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
HttpGet httpget = new HttpGet("/");
for (int i = 0; i < 3; i++) {
HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
CloseableHttpResponse response = httpclient.execute(
targetHost, httpget, context);
try {
HttpEntity entity = response.getEntity();
} finally {
response.close();
}
}
]]></programlisting>
</section>
@ -428,28 +341,36 @@ for (int i = 0; i < 3; i++) {
connection to execute more expensive methods, especially those enclose a request
entity, such as <literal>POST</literal> or <literal>PUT</literal>. </para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
CloseableHttpClient httpclient = <...>
NTCredentials creds = new NTCredentials("user", "pwd", "myworkstation", "microsoft.com");
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new NTCredentials("user", "pwd", "myworkstation", "microsoft.com"));
HttpHost target = new HttpHost("www.microsoft.com", 80, "http");
// Make sure the same context is used to execute logically related requests
HttpContext localContext = new BasicHttpContext();
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
// Execute a cheap method first. This will trigger NTLM authentication
HttpGet httpget = new HttpGet("/ntlm-protected/info");
HttpResponse response1 = httpclient.execute(target, httpget, localContext);
HttpEntity entity1 = response1.getEntity();
EntityUtils.consume(entity1);
CloseableHttpResponse response1 = httpclient.execute(target, httpget, context);
try {
HttpEntity entity1 = response1.getEntity();
} finally {
response1.close();
}
// Execute an expensive method next reusing the same context (and connection)
HttpPost httppost = new HttpPost("/ntlm-protected/form");
httppost.setEntity(new StringEntity("lots and lots of data"));
HttpResponse response2 = httpclient.execute(target, httppost, localContext);
HttpEntity entity2 = response2.getEntity();
EntityUtils.consume(entity2);
CloseableHttpResponse response2 = httpclient.execute(target, httppost, context);
try {
HttpEntity entity2 = response2.getEntity();
} finally {
response2.close();
}
]]></programlisting>
</section>
</section>

View File

@ -29,29 +29,30 @@
<para>HttpClient Cache provides an HTTP/1.1-compliant caching layer to be
used with HttpClient--the Java equivalent of a browser cache. The
implementation follows the Decorator design pattern, where the
CachingHttpClient class is a drop-in replacement for
a DefaultHttpClient; requests that can be satisfied entirely from the cache
will not result in actual origin requests. Stale cache entries are
automatically validated with the origin where possible, using conditional GETs
and the If-Modified-Since and/or If-None-Match request headers.
implementation follows the Chain of Responsibility design pattern, where the
caching HttpClient implementation can serve a drop-in replacement for
the default non-caching HttpClient implementation; requests that can be
satisfied entirely from the cache will not result in actual origin requests.
Stale cache entries are automatically validated with the origin where possible,
using conditional GETs and the If-Modified-Since and/or If-None-Match request
headers.
</para>
<para>
HTTP/1.1 caching in general is designed to be <emphasis>semantically
transparent</emphasis>; that is, a cache should not change the meaning of
the request-response exchange between client and server. As such, it should
be safe to drop a CachingHttpClient into an existing compliant client-server
be safe to drop a caching HttpClient into an existing compliant client-server
relationship. Although the caching module is part of the client from an
HTTP protocol point of view, the implementation aims to be compatible with
the requirements placed on a transparent caching proxy.
</para>
<para>Finally, CachingHttpClient includes support the Cache-Control
<para>Finally, caching HttpClient includes support the Cache-Control
extensions specified by RFC 5861 (stale-if-error and stale-while-revalidate).
</para>
<para>When CachingHttpClient executes a request, it goes through the
<para>When caching HttpClient executes a request, it goes through the
following flow:</para>
<orderedlist>
@ -90,7 +91,7 @@
</listitem>
</orderedlist>
<para>When CachingHttpClient receives a response, it goes through the
<para>When caching HttpClient receives a response, it goes through the
following flow:</para>
<orderedlist>
@ -114,10 +115,10 @@
</listitem>
</orderedlist>
<para>It is important to note that CachingHttpClient is not, itself, an
implementation of HttpClient, but that it decorates an instance of an
HttpClient implementation. If you do not provide an implementation, it
will use DefaultHttpClient internally by default.</para>
<para>It is important to note that caching HttpClient is not, itself,
a different implementation of HttpClient, but that it works by inserting
itself as an additonal processing component to the request execution
pipeline.</para>
</section>
<section id="rfc2616compliance">
@ -135,41 +136,50 @@
<section>
<title>Example Usage</title>
<para>This is a simple example of how to set up a basic CachingHttpClient.
<para>This is a simple example of how to set up a basic caching HttpClient.
As configured, it will store a maximum of 1000 cached objects, each of
which may have a maximum body size of 8192 bytes. The numbers selected
here are for example only and not intended to be prescriptive or
considered as recommendations.</para>
<programlisting><![CDATA[
CacheConfig cacheConfig = new CacheConfig();
cacheConfig.setMaxCacheEntries(1000);
cacheConfig.setMaxObjectSizeBytes(8192);
CacheConfig cacheConfig = CacheConfig.custom()
.setMaxCacheEntries(1000)
.setMaxObjectSize(8192)
.build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(30000)
.setSocketTimeout(30000)
.build();
CloseableHttpClient cachingClient = caching HttpClients.custom()
.setCacheConfig(cacheConfig)
.setDefaultRequestConfig(requestConfig)
.build();
HttpClient cachingClient = new CachingHttpClient(new DefaultHttpClient(), cacheConfig);
HttpContext localContext = new BasicHttpContext();
HttpCacheContext context = HttpCacheContext.create();
HttpGet httpget = new HttpGet("http://www.mydomain.com/content/");
HttpResponse response = cachingClient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
CacheResponseStatus responseStatus = (CacheResponseStatus) localContext.getAttribute(
CachingHttpClient.CACHE_RESPONSE_STATUS);
switch (responseStatus) {
case CACHE_HIT:
System.out.println("A response was generated from the cache with no requests " +
"sent upstream");
break;
case CACHE_MODULE_RESPONSE:
System.out.println("The response was generated directly by the caching module");
break;
case CACHE_MISS:
System.out.println("The response came from an upstream server");
break;
case VALIDATED:
System.out.println("The response was generated from the cache after validating " +
"the entry with the origin server");
break;
CloseableHttpResponse response = cachingClient.execute(httpget, context);
try {
CacheResponseStatus responseStatus = context.getCacheResponseStatus();
switch (responseStatus) {
case CACHE_HIT:
System.out.println("A response was generated from the cache with " +
"no requests sent upstream");
break;
case CACHE_MODULE_RESPONSE:
System.out.println("The response was generated directly by the " +
"caching module");
break;
case CACHE_MISS:
System.out.println("The response came from an upstream server");
break;
case VALIDATED:
System.out.println("The response was generated from the cache " +
"after validating the entry with the origin server");
break;
}
} finally {
response.close();
}
]]>
</programlisting>
@ -178,11 +188,11 @@ case VALIDATED:
<section id="configuration">
<title>Configuration</title>
<para>As the CachingHttpClient is a decorator, much of the configuration you may
want to do can be done on the HttpClient used as the "backend" by the HttpClient
(this includes setting options like timeouts and connection pool sizes). For
caching-specific configuration, you can provide a CacheConfig instance to
customize behavior across the following areas:</para>
<para>The caching HttpClient inherits all configuration options and parameters
of the default non-caching implementation (this includes setting options like
timeouts and connection pool sizes). For caching-specific configuration, you can
provide a <classname>CacheConfig</classname> instance to customize behavior
across the following areas:</para>
<para><emphasis>Cache size.</emphasis> If the backend storage supports these limits,
you can specify the maximum number of cache entries as well as the maximum cacheable
@ -217,7 +227,7 @@ case VALIDATED:
<section id="storage">
<title>Storage Backends</title>
<para>The default implementation of CachingHttpClient stores cache entries and
<para>The default implementation of caching HttpClient stores cache entries and
cached response bodies in memory in the JVM of your application. While this
offers high performance, it may not be appropriate for your application due to
the limitation on size or because the cache entries are ephemeral and don't
@ -227,18 +237,17 @@ case VALIDATED:
<para>If none of those options are suitable for your application, it is
possible to provide your own storage backend by implementing the HttpCacheStorage
interface and then supplying that to CachingHttpClient at construction time. In
interface and then supplying that to caching HttpClient at construction time. In
this case, the cache entries will be stored using your scheme but you will get to
reuse all of the logic surrounding HTTP/1.1 compliance and cache handling.
Generally speaking, it should be possible to create an HttpCacheStorage
implementation out of anything that supports a key/value store (similar to the
Java Map interface) with the ability to apply atomic updates.</para>
<para>Finally, because the CachingHttpClient is a decorator for HttpClient,
it's entirely possible to set up a multi-tier caching hierarchy; for example,
wrapping an in-memory CachingHttpClient around one that stores cache entries on
disk or remotely in memcached, following a pattern similar to virtual memory,
L1/L2 processor caches, etc.
<para>Finally, with some extra efforts it's entirely possible to set up
a multi-tier caching hierarchy; for example, wrapping an in-memory caching
HttpClient around one that stores cache entries on disk or remotely in memcached,
following a pattern similar to virtual memory, L1/L2 processor caches, etc.
</para>
</section>
</chapter>

View File

@ -415,12 +415,12 @@ sf.connectSocket(timeout, socket, target, remoteAddress, null, clientContext);
<programlisting><![CDATA[
ConnectionSocketFactory plainsf = <...>
LayeredConnectionSocketFactory sslsf = <...>
Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf)
.register("https", sslsf)
.build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
HttpClients.custom()
.setConnectionManager(cm)
.build();

View File

@ -108,7 +108,8 @@ Document result = Request.Get("http://somehost/content")
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
ContentType contentType = ContentType.getOrDefault(entity);
if (!contentType.equals(ContentType.APPLICATION_XML)) {
throw new ClientProtocolException("Unexpected content type:" + contentType);
throw new ClientProtocolException("Unexpected content type:" +
contentType);
}
String charset = contentType.getCharset();
if (charset == null) {
@ -123,45 +124,6 @@ Document result = Request.Get("http://somehost/content")
}
});
]]>
</programlisting>
</section>
<section>
<title>Asynchronous execution</title>
<para>The fluent facade API can be used to execute multiple requests asynchronously using
background threads.
</para>
<programlisting><![CDATA[
ExecutorService threadpool = Executors.newFixedThreadPool(2);
Async async = Async.newInstance().use(threadpool);
Request[] requests = new Request[] {
Request.Get("http://www.google.com/"),
Request.Get("http://www.yahoo.com/"),
Request.Get("http://www.apache.com/"),
Request.Get("http://www.apple.com/")
};
Queue<Future<Content>> queue = new LinkedList<Future<Content>>();
for (final Request request: requests) {
Future<Content> future = async.execute(request, new FutureCallback<Content>() {
public void failed(final Exception ex) {
System.out.println(ex.getMessage() + ": " + request);
}
public void completed(final Content content) {
System.out.println("Request completed: " + request);
}
public void cancelled() {
}
});
queue.add(future);
}
// Process the queue
]]>
</programlisting>
</section>

View File

@ -38,7 +38,7 @@ CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
<...>
} finally {
response.close();
}
@ -283,7 +283,8 @@ important message
<para> In order to ensure proper release of system resources one must close either
the content stream associated with the entity or the response itself</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = <...>
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
@ -318,7 +319,8 @@ try {
remaining content and making the connection reusable is too high, in which case
one can terminate the content stream by closing the response.</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = <...>
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
@ -348,7 +350,8 @@ try {
strongly discouraged unless the response entities originate from a trusted HTTP
server and are known to be of limited length.</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = <...>
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
@ -452,8 +455,8 @@ httppost.setEntity(entity);
take care of ensuring release of the connection back to the connection manager
regardless whether the request execution succeeds or causes an exception.</para>
<programlisting><![CDATA[
HttpClient httpclient = <...>
HttpRequest request = <...>
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/json");
ResponseHandler<MyJsonObject> rh = new ResponseHandler<MyJsonObject>() {
@ -477,7 +480,64 @@ ResponseHandler<MyJsonObject> rh = new ResponseHandler<MyJsonObject>() {
return gson.fromJson(reader, MyJsonObject.class);
}
};
MyJsonObject myjson = client.execute(request, rh);
MyJsonObject myjson = client.execute(httpget, rh);
]]></programlisting>
</section>
</section>
<section>
<title>HttpClient interface</title>
<para><interfacename>HttpClient</interfacename> interface represents the most essential
contract for HTTP request execution. It imposes no restrictions or particular details on
the request execution process and leaves the specifics of connection management, state
management, authentication and redirect handling up to individual implementations. This
should make it easier to decorate the interface with additional functionality such as
response content caching.</para>
<para>Generally <interfacename>HttpClient</interfacename> implementations act as a facade
to a number of special purpose handler or strategy interface implementations
responsible for handling of a particular aspect of the HTTP protocol such as redirect
or authentication handling or making decision about connection persistence and keep
alive duration. This enables the users to selectively replace default implementation
of those aspects with custom, application specific ones.</para>
<programlisting><![CDATA[
ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(
HttpResponse response,
HttpContext context) {
long keepAlive = super.getKeepAliveDuration(response, context);
if (keepAlive == -1) {
// Keep connections alive 5 seconds if a keep-alive value
// has not be explicitly set by the server
keepAlive = 5000;
}
return keepAlive;
}
};
CloseableHttpClient httpclient = HttpClients.custom()
.setKeepAliveStrategy(keepAliveStrat)
.build();
]]></programlisting>
<section>
<title>HttpClient thread safety</title>
<para><interfacename>HttpClient</interfacename> implementations are expected to be
thread safe. It is recommended that the same instance of this class is reused for
multiple request executions.</para>
</section>
<section>
<title>HttpClient resource deallocation</title>
<para>When an instance <classname>CloseableHttpClient</classname> is no longer needed
and is about to go out of scope the connection manager associated with it must
be shut down by calling the <methodname>CloseableHttpClient#close()</methodname>
method.</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
<...>
} finally {
httpclient.close();
}
]]></programlisting>
</section>
</section>
@ -497,6 +557,64 @@ MyJsonObject myjson = client.execute(request, rh);
<para><interfacename>HttpContext</interfacename> can contain arbitrary objects and
therefore may be unsafe to share between multiple threads. It is recommended that
each thread of execution maintains its own context.</para>
<para>In the course of HTTP request execution HttpClient adds the following attributes to
the execution context:</para>
<itemizedlist>
<listitem>
<formalpara>
<para><interfacename>HttpConnection</interfacename> instance representing the
actual connection to the target server.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><classname>HttpHost</classname> instance representing the connection
target.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><classname>HttpRoute</classname> instance representing the complete
connection route</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><interfacename>HttpRequest</interfacename> instance representing the
actual HTTP request. The final HttpRequest object in the execution context
always represents the state of the message <emphasis>exactly</emphasis>
as it was sent to the target server. Per default HTTP/1.0 and HTTP/1.1
use relative request URIs. However if the request is sent via a proxy
in a non-tunneling mode then the URI will be absolute.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><interfacename>HttpResponse</interfacename> instance representing the
actual HTTP response.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><classname>java.lang.Boolean</classname> object representing the flag
indicating whether the actual request has been fully transmitted to the
connection target.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><classname>RequestConfig</classname> object representing the actual
request configuation.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<para><classname>URICollection</classname> object representing a collection
of all redirect locations received in the process of request
execution.</para>
</formalpara>
</listitem>
</itemizedlist>
<para>One can use <classname>HttpClientContext</classname> adaptor class to simplify
interractions with the context state.</para>
<programlisting><![CDATA[
@ -505,6 +623,7 @@ HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpHost target = clientContext.getTargetHost();
HttpRequest request = clientContext.getRequest();
HttpResponse response = clientContext.getResponse();
RequestConfig config = clientContext.getRequestConfig();
]]></programlisting>
<para>Multiple request sequences that represent a logically related session should be
executed with the same <interfacename>HttpContext</interfacename> instance to ensure
@ -514,8 +633,7 @@ HttpResponse response = clientContext.getResponse();
kept in the execution context and get propagatd to the consecutive requests sharing
the same context.</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = <...>
CloseableHttpClient httpclient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(1000)
.setConnectTimeout(1000)
@ -718,6 +836,46 @@ for (int i = 0; i < 10; i++) {
response.close();
}
}
]]></programlisting>
</section>
<section>
<title>Redirect handling</title>
<para>HttpClient handles all types of redirects automatically, except those explicitly
prohibited by the HTTP specification as requiring user intervention. <literal>See
Other</literal> (status code 303) redirects on <literal>POST</literal> and
<literal>PUT</literal> requests are converted to <literal>GET</literal> requests as
required by the HTTP specification. One can use a custom redirect strategy to relaxe
restrictions on automatic redirection of POST methods imposed by the HTTP
specification.</para>
<programlisting><![CDATA[
LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
CloseableHttpClient httpclient = HttpClients.custom()
.setRedirectStrategy(redirectStrategy)
.build();
]]></programlisting>
<para>HttpClient often has to rewrite the request message in the process of its execution.
Per default HTTP/1.0 and HTTP/1.1 generally use relative request URIs. Likewise,
original request may get redirected from location to another multiple times. The final
interpreted absolute HTTP location can be built using the original request and
the context. The utility method <classname>URIUtils#resolve</classname> can be used
to build the interpreted absolute URI used to generate the final request. This method
includes the last fragment identifier from the redirect requests or the original
request.</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("http://localhost:8080/");
CloseableHttpResponse response = httpclient.execute(httpget, context);
try {
HttpHost target = context.getTargetHost();
URICollection redirectLocations = context.getRedirectLocations();
URI location = URIUtils.resolve(httpget.getURI(), target,
redirectLocations != null ? redirectLocations.getAll() : null);
System.out.println("Final HTTP location: " + location.toASCIIString());
// Expected to be an absolute URI
} finally {
response.close();
}
]]></programlisting>
</section>
</chapter>

View File

@ -1,267 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<!--
====================================================================
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.
====================================================================
-->
<chapter id="httpagent">
<title>HTTP client service</title>
<section>
<title>HttpClient facade</title>
<para><interfacename>HttpClient</interfacename> interface represents the most essential
contract for HTTP request execution. It imposes no restrictions or particular details on
the request execution process and leaves the specifics of connection management, state
management, authentication and redirect handling up to individual implementations. This
should make it easier to decorate the interface with additional functionality such as
response content caching.</para>
<para><classname>DefaultHttpClient</classname> is the default implementation of the
<interfacename>HttpClient</interfacename> interface. This class acts as a facade to
a number of special purpose handler or strategy interface implementations responsible
for handling of a particular aspect of the HTTP protocol such as redirect or
authentication handling or making decision about connection persistence and keep alive
duration. This enables the users to selectively replace default implementation of those
aspects with custom, application specific ones.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(
HttpResponse response,
HttpContext context) {
long keepAlive = super.getKeepAliveDuration(response, context);
if (keepAlive == -1) {
// Keep connections alive 5 seconds if a keep-alive value
// has not be explicitly set by the server
keepAlive = 5000;
}
return keepAlive;
}
});
]]></programlisting>
<para><classname>DefaultHttpClient</classname> also maintains a list of protocol
interceptors intended for processing outgoing requests and incoming responses and
provides methods for managing those interceptors. New protocol interceptors can be
introduced to the protocol processor chain or removed from it if needed. Internally
protocol interceptors are stored in a simple <classname>java.util.ArrayList</classname>.
They are executed in the same natural order as they are added to the list.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.removeRequestInterceptorByClass(RequestUserAgent.class);
httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(
HttpRequest request, HttpContext context)
throws HttpException, IOException {
request.setHeader(HTTP.USER_AGENT, "My-own-client");
}
});
]]></programlisting>
<para><classname>DefaultHttpClient</classname> is thread safe. It is recommended that the
same instance of this class is reused for multiple request executions. When an instance
of <classname>DefaultHttpClient</classname> is no longer needed and is about to go out
of scope the connection manager associated with it must be shut down by calling the
<methodname>ClientConnectionManager#shutdown()</methodname> method.</para>
<programlisting><![CDATA[
HttpClient httpclient = new DefaultHttpClient();
// Do something useful
httpclient.getConnectionManager().shutdown();
]]></programlisting>
</section>
<section>
<title>HttpClient parameters</title>
<para>These are parameters that be used to customize the behaviour of the default HttpClient
implementation:</para>
<itemizedlist>
<listitem>
<formalpara>
<title><constant>ClientPNames.HANDLE_REDIRECTS</constant>='http.protocol.handle-redirects':</title>
<para>defines whether redirects should be handled automatically. This parameter
expects a value of type <classname>java.lang.Boolean</classname>. If this
parameter is not set HttpClient will handle redirects automatically.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.REJECT_RELATIVE_REDIRECT</constant>='http.protocol.reject-relative-redirect':</title>
<para>defines whether relative redirects should be rejected. HTTP specification
requires the location value be an absolute URI. This parameter expects a
value of type <classname>java.lang.Boolean</classname>. If this parameter is
not set relative redirects will be allowed.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.MAX_REDIRECTS</constant>='http.protocol.max-redirects':</title>
<para>defines the maximum number of redirects to be followed. The limit on
number of redirects is intended to prevent infinite loops caused by broken
server side scripts. This parameter expects a value of type
<classname>java.lang.Integer</classname>. If this parameter is not set
no more than 100 redirects will be allowed.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.ALLOW_CIRCULAR_REDIRECTS</constant>='http.protocol.allow-circular-redirects':</title>
<para>defines whether circular redirects (redirects to the same location) should
be allowed. The HTTP spec is not sufficiently clear whether circular
redirects are permitted, therefore optionally they can be enabled. This
parameter expects a value of type <classname>java.lang.Boolean</classname>.
If this parameter is not set circular redirects will be disallowed.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME</constant>='http.connection-manager.factory-class-name':</title>
<para>defines the class name of the default
<interfacename>ClientConnectionManager</interfacename> implementation.
This parameter expects a value of type
<classname>java.lang.String</classname>. If this parameter is not set
<classname>SingleClientConnManager</classname> will be used per
default.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.VIRTUAL_HOST</constant>='http.virtual-host':</title>
<para>defines the virtual host settings to be used in the <literal>Host</literal>
header instead of the physical host. This parameter expects a value of
type <classname>HttpHost</classname>. The HttpHost port does not have to
be specified as it will be derived from the target.
If this parameter is not set, the name or
IP address (and port if required) of the target host will be used.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.DEFAULT_HEADERS</constant>='http.default-headers':</title>
<para>defines the request headers to be sent per default with each request. This
parameter expects a value of type
<interfacename>java.util.Collection</interfacename> containing
<interfacename>Header</interfacename> objects.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title><constant>ClientPNames.DEFAULT_HOST</constant>='http.default-host':</title>
<para>defines the default host. The default value will be used if the target
host is not explicitly specified in the request URI (relative URIs). This
parameter expects a value of type <classname>HttpHost</classname>.</para>
</formalpara>
</listitem>
</itemizedlist>
</section>
<section>
<title>Automatic redirect handling</title>
<para>HttpClient handles all types of redirects automatically, except those explicitly
prohibited by the HTTP specification as requiring user intervention. <literal>See
Other</literal> (status code 303) redirects on <literal>POST</literal> and
<literal>PUT</literal> requests are converted to <literal>GET</literal> requests as
required by the HTTP specification.</para>
</section>
<section>
<title>HTTP client and execution context</title>
<para>The <classname>DefaultHttpClient</classname> treats HTTP requests as immutable objects
that are never supposed to change in the course of request execution. Instead, it
creates a private mutable copy of the original request object, whose properties can be
updated depending on the execution context. Therefore the final request properties such
as the target host and request URI can be determined by examining the content of the
local HTTP context after the request has been executed.</para>
<para>The final HttpRequest object in the execution context always represents
the state of the message _exactly_ as it was sent to the target server.
Per default HTTP/1.0 and HTTP/1.1 use relative request URIs. However if the request
is sent via a proxy in a non-tunneling mode then the URI will be absolute.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
HttpHost target = (HttpHost) localContext.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
HttpUriRequest req = (HttpUriRequest) localContext.getAttribute(
ExecutionContext.HTTP_REQUEST);
System.out.println("Target host: " + target);
System.out.println("Final request URI: " + req.getURI()); // relative URI (no proxy used)
System.out.println("Final request method: " + req.getMethod());
]]></programlisting>
<para>The final interpreted absolute HTTP location can be built using the original request
and the context. The utility method URIUtils.resolve(URI,HttpHost,URICollection)
can be used to build the interpreted absolute URI used to generate the final request.
This method includes the last fragment identifier from the redirect requests or
the original request.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, context);
HttpHost target = context.getTargetHost();
URICollection redirectLocations = context.getRedirectLocations();
URI location = URIUtils.resolve(httpget.getURI(), target,
redirectLocations != null ? redirectLocations.getAll() : null);
System.out.println("Final HTTP location: " + location.toASCIIString()); // absolute URI
]]></programlisting>
</section>
<section>
<title>Compressed response content</title>
<para>
The <classname>ContentEncodingHttpClient</classname> is a simple sub-class of
<classname>DefaultHttpClient</classname> which adds support indicating to servers that it will
support <literal>gzip</literal> and <literal>deflate</literal> compressed responses. It does
this via the existing published APIs of <link linkend="protocol_interceptors">HTTP Protocol
Interceptors </link>. Depending on the type of response (text will compress well versus
images, which are typically already well-compressed), this can speed up responses due to the
smaller amount of network traffic involved, along with saving bandwidth, which can be
important in mobile environments. The <classname>RequestAcceptEncoding</classname>
and <classname>ResponseContentEncoding</classname> interceptors used as also part of the
published API and can be used by other <interfacename>DefaultHttpClient</interfacename>
implementations. These provide transparent handling of <literal>gzip</literal> and
<literal>deflate</literal> encoding, so it will not be apparent to clients that this
processing has happened.
</para>
<programlisting><![CDATA[
ContentEncodingHttpClient httpclient = new ContentEncodingHttpClient();
HttpGet httpget = new HttpGet("http://www.yahoo.com/");
HttpResponse response = httpclient.execute(httpget);
Header h = rsp.getFirstHeader("Content-Encoding");
if (h != null) {
System.out.println("----------------------------------------");
System.out.println("Response is " + h.getValue() + " encoded");
System.out.println("----------------------------------------");
}
]]></programlisting>
<para>
One can also add the <classname>RequestAcceptEncoding</classname> and
<classname>ResponseContentEncoding</classname> interceptors to an instance of the
<classname>DefaultHttpClient</classname>, if desired.
</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.addRequestInterceptor(new RequestAcceptEncoding());
httpclient.addResponseInterceptor(new ResponseContentEncoding());
]]></programlisting>
</section>
</chapter>

View File

@ -32,10 +32,14 @@
<firstname>Oleg</firstname>
<surname>Kalnichevski</surname>
</author>
<author>
<firstname>Jonathan</firstname>
<surname>Moore</surname>
</author>
</authorgroup>
<legalnotice>
<para>
<formalpara>
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
@ -43,18 +47,18 @@
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
</para>
<para>
</formalpara>
<formalpara>
<ulink url="http://www.apache.org/licenses/LICENSE-2.0"/>
</para>
<para>
</formalpara>
<formalpara>
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.
</para>
</formalpara>
</legalnotice>
</bookinfo>
@ -65,7 +69,6 @@
<xi:include href="connmgmt.xml"/>
<xi:include href="statemgmt.xml"/>
<xi:include href="authentication.xml"/>
<xi:include href="httpagent.xml"/>
<xi:include href="fluent.xml"/>
<xi:include href="caching.xml"/>
<xi:include href="advanced.xml"/>

View File

@ -205,9 +205,11 @@ CookieSpecProvider easySpecProvider = new CookieSpecProvider() {
}
};
Registry<CookieSpecProvider> cookieSpecReg = RegistryBuilder.<CookieSpecProvider>create()
.register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
.register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory())
Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>create()
.register(CookieSpecs.BEST_MATCH,
new BestMatchSpecFactory())
.register(CookieSpecs.BROWSER_COMPATIBILITY,
new BrowserCompatSpecFactory())
.register("easy", easySpecProvider)
.build();
@ -216,7 +218,7 @@ RequestConfig requestConfig = RequestConfig.custom()
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieSpecRegistry(cookieSpecReg)
.setDefaultCookieSpecRegistry(r)
.setDefaultRequestConfig(requestConfig)
.build();
]]></programlisting>
@ -253,7 +255,7 @@ CloseableHttpClient httpclient = HttpClients.custom()
<itemizedlist>
<listitem>
<formalpara>
<para><classname>CookieSpecRegistry</classname> instance representing the actual
<para><interfacename>Lookup</interfacename> instance representing the actual
cookie specification registry. The value of this attribute set in the local
context takes precedence over the default one.</para>
</formalpara>
@ -287,13 +289,13 @@ CloseableHttpClient httpclient = HttpClients.custom()
<programlisting><![CDATA[
CloseableHttpClient httpclient = <...>
Registry<CookieSpecProvider> cookieSpecReg = <...>
Lookup<CookieSpecProvider> cookieSpecReg = <...>
CookieStore cookieStore = <...>
HttpClientContext context = HttpClientContext.create();
context.setCookieSpecRegistry(cookieSpecReg);
context.setCookieStore(cookieStore);
HttpGet httpget = new HttpGet("http://localhost/1");
HttpGet httpget = new HttpGet("http://somehost/");
CloseableHttpResponse response1 = httpclient.execute(httpget, context);
<...>
// Cookie origin details