| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
| <title>Chapter 3. HTTP state management</title><link rel="stylesheet" type="text/css" href="css/hc-tutorial.css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.76.1"><link rel="home" href="index.html" title="HttpClient Tutorial"><link rel="up" href="index.html" title="HttpClient Tutorial"><link rel="prev" href="connmgmt.html" title="Chapter 2. Connection management"><link rel="next" href="authentication.html" title="Chapter 4. HTTP authentication"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:fo="http://www.w3.org/1999/XSL/Format" class="banner"><a class="bannerLeft" href="http://www.apache.org/" title="Apache Software Foundation"><img style="border:none;" src="images/asf_logo_wide.gif"></a><a class="bannerRight" href="http://hc.apache.org/httpcomponents-client-ga/" title="Apache HttpComponents Client"><img style="border:none;" src="images/hc_logo.png"></a><div class="clear"></div></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 3. HTTP state management</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="connmgmt.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="authentication.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 3. HTTP state management"><div class="titlepage"><div><div><h2 class="title"><a name="statemgmt"></a>Chapter 3. HTTP state management</h2></div></div></div> |
| |
| <p>Originally HTTP was designed as a stateless, request / response oriented protocol that |
| made no special provisions for stateful sessions spanning across several logically related |
| request / response exchanges. As HTTP protocol grew in popularity and adoption more and more |
| systems began to use it for applications it was never intended for, for instance as a |
| transport for e-commerce applications. Thus, the support for state management became a |
| necessity.</p> |
| <p>Netscape Communications, at that time a leading developer of web client and server |
| software, implemented support for HTTP state management in their products based on a |
| proprietary specification. Later, Netscape tried to standardise the mechanism by publishing |
| a specification draft. Those efforts contributed to the formal specification defined through |
| the RFC standard track. However, state management in a significant number of applications is |
| still largely based on the Netscape draft and is incompatible with the official |
| specification. All major developers of web browsers felt compelled to retain compatibility |
| with those applications greatly contributing to the fragmentation of standards |
| compliance.</p> |
| <div class="section" title="3.1. HTTP cookies"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e669"></a>3.1. HTTP cookies</h2></div></div></div> |
| |
| <p>An HTTP cookie is a token or short packet of state information that the HTTP agent and the |
| target server can exchange to maintain a session. Netscape engineers used to refer to it |
| as a "magic cookie" and the name stuck.</p> |
| <p>HttpClient uses the <code class="interfacename">Cookie</code> interface to represent an |
| abstract cookie token. In its simplest form an HTTP cookie is merely a name / value pair. |
| Usually an HTTP cookie also contains a number of attributes such as version, a domain |
| for which is valid, a path that specifies the subset of URLs on the origin server to |
| which this cookie applies, and the maximum period of time for which the cookie is valid.</p> |
| <p>The <code class="interfacename">SetCookie</code> interface represents a |
| <code class="literal">Set-Cookie</code> response header sent by the origin server to the HTTP |
| agent in order to maintain a conversational state. |
| The <code class="interfacename">SetCookie2</code> interface extends SetCookie with |
| <code class="literal">Set-Cookie2</code> specific methods.</p> |
| <p>The <code class="interfacename">ClientCookie</code> interface extends |
| <code class="interfacename">Cookie</code> interface with additional client specific |
| functionality such as the ability to retrieve original cookie attributes exactly as they were |
| specified by the origin server. This is important for generating the |
| <code class="literal">Cookie</code> header because some cookie specifications require that the |
| <code class="literal">Cookie</code> header should include certain attributes only if they were |
| specified in the <code class="literal">Set-Cookie</code> or <code class="literal">Set-Cookie2</code> |
| header.</p> |
| <div class="section" title="3.1.1. Cookie versions"><div class="titlepage"><div><div><h3 class="title"><a name="d5e686"></a>3.1.1. Cookie versions</h3></div></div></div> |
| |
| <p>Cookies compatible with Netscape draft specification but non-compliant with the |
| official specification are considered to be of version 0. Standard compliant cookies |
| are expected to have version 1. HttpClient may handle cookies differently depending |
| on the version.</p> |
| <p>Here is an example of re-creating a Netscape cookie:</p> |
| <pre class="programlisting"> |
| BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value"); |
| netscapeCookie.setVersion(0); |
| netscapeCookie.setDomain(".mycompany.com"); |
| netscapeCookie.setPath("/"); |
| </pre> |
| <p>Here is an example of re-creating a standard cookie. Please note that standard |
| compliant cookie must retain all attributes as sent by the origin server:</p> |
| <pre class="programlisting"> |
| BasicClientCookie stdCookie = new BasicClientCookie("name", "value"); |
| stdCookie.setVersion(1); |
| stdCookie.setDomain(".mycompany.com"); |
| stdCookie.setPath("/"); |
| stdCookie.setSecure(true); |
| // Set attributes EXACTLY as sent by the server |
| stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1"); |
| stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com"); |
| </pre> |
| <p>Here is an example of re-creating a <code class="literal">Set-Cookie2</code> compliant |
| cookie. Please note that standard compliant cookie must retain all attributes as |
| sent by the origin server:</p> |
| <pre class="programlisting"> |
| BasicClientCookie2 stdCookie = new BasicClientCookie2("name", "value"); |
| stdCookie.setVersion(1); |
| stdCookie.setDomain(".mycompany.com"); |
| stdCookie.setPorts(new int[] {80,8080}); |
| stdCookie.setPath("/"); |
| stdCookie.setSecure(true); |
| // Set attributes EXACTLY as sent by the server |
| stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1"); |
| stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com"); |
| stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080"); |
| </pre> |
| </div> |
| </div> |
| <div class="section" title="3.2. Cookie specifications"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e696"></a>3.2. Cookie specifications</h2></div></div></div> |
| |
| <p>The <code class="interfacename">CookieSpec</code> interface represents a cookie management |
| specification. The cookie management specification is expected to enforce:</p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| <p>rules of parsing <code class="literal">Set-Cookie</code> and optionally |
| <code class="literal">Set-Cookie2</code> headers.</p> |
| </li><li class="listitem"> |
| <p>rules of validation of parsed cookies.</p> |
| </li><li class="listitem"> |
| <p>formatting of <code class="literal">Cookie</code> header for a given host, port and path |
| of origin.</p> |
| </li></ul></div> |
| <p>HttpClient ships with several <code class="interfacename">CookieSpec</code> |
| implementations:</p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| <p title="Netscape draft:"> |
| <b>Netscape draft: </b> |
| This specification conforms to the original draft specification published |
| by Netscape Communications. It should be avoided unless absolutely necessary |
| for compatibility with legacy code. |
| </p> |
| </li><li class="listitem"> |
| <p title="RFC 2109:"> |
| <b>RFC 2109: </b> |
| Older version of the official HTTP state management specification |
| superseded by RFC 2965. |
| </p> |
| </li><li class="listitem"> |
| <p title="RFC 2965:"> |
| <b>RFC 2965: </b> |
| The official HTTP state management specification. |
| </p> |
| </li><li class="listitem"> |
| <p title="Browser compatibility:"> |
| <b>Browser compatibility: </b> |
| This implementation strives to closely mimic the (mis)behavior of common web |
| browser applications such as Microsoft Internet Explorer and Mozilla |
| FireFox. |
| </p> |
| </li><li class="listitem"> |
| <p title="Best match:"> |
| <b>Best match: </b> |
| 'Meta' cookie specification that picks up a cookie policy based on the |
| format of cookies sent with the HTTP response. It basically aggregates all |
| above implementations into one class. |
| </p> |
| </li><li class="listitem"> |
| <p title="Ignore cookies:"> |
| <b>Ignore cookies: </b> |
| All cookies are ignored. |
| </p> |
| </li></ul></div> |
| <p>It is strongly recommended to use the <code class="literal">Best Match</code> policy and let |
| HttpClient pick up an appropriate compliance level at runtime based on the execution |
| context.</p> |
| </div> |
| <div class="section" title="3.3. HTTP cookie and state management parameters"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e739"></a>3.3. HTTP cookie and state management parameters</h2></div></div></div> |
| |
| <p>These are parameters that be used to customize HTTP state management and the behaviour of |
| individual cookie specifications:</p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| <p title="CookieSpecPNames.DATE_PATTERNS='http.protocol.cookie-datepatterns':"> |
| <b><code class="constant">CookieSpecPNames.DATE_PATTERNS</code>='http.protocol.cookie-datepatterns': </b> |
| defines valid date patterns to be used for parsing non-standard |
| <code class="literal">expires</code> attribute. Only required for compatibility |
| with non-compliant servers that still use <code class="literal">expires</code> defined |
| in the Netscape draft instead of the standard <code class="literal">max-age</code> |
| attribute. This parameter expects a value of type |
| <code class="interfacename">java.util.Collection</code>. The collection |
| elements must be of type <code class="classname">java.lang.String</code> compatible |
| with the syntax of <code class="classname">java.text.SimpleDateFormat</code>. If |
| this parameter is not set the choice of a default value is |
| <code class="interfacename">CookieSpec</code> implementation specific. |
| </p> |
| </li><li class="listitem"> |
| <p title="CookieSpecPNames.SINGLE_COOKIE_HEADER='http.protocol.single-cookie-header':"> |
| <b><code class="constant">CookieSpecPNames.SINGLE_COOKIE_HEADER</code>='http.protocol.single-cookie-header': </b> |
| defines whether cookies should be forced into a single |
| <code class="literal">Cookie</code> request header. Otherwise, each cookie is |
| formatted as a separate <code class="literal">Cookie</code> header. This parameter |
| expects a value of type <code class="classname">java.lang.Boolean</code>. If this |
| parameter is not set, the choice of a default value is CookieSpec |
| implementation specific. Please note this parameter applies to strict cookie |
| specifications (RFC 2109 and RFC 2965) only. Browser compatibility and |
| netscape draft policies will always put all cookies into one request |
| header. |
| </p> |
| </li><li class="listitem"> |
| <p title="ClientPNames.COOKIE_POLICY='http.protocol.cookie-policy':"> |
| <b><code class="constant">ClientPNames.COOKIE_POLICY</code>='http.protocol.cookie-policy': </b> |
| defines the name of a cookie specification to be used for HTTP state |
| management. This parameter expects a value of type |
| <code class="classname">java.lang.String</code>. If this parameter is not set, |
| valid date patterns are <code class="interfacename">CookieSpec</code> |
| implementation specific. |
| </p> |
| </li></ul></div> |
| </div> |
| <div class="section" title="3.4. Cookie specification registry"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e770"></a>3.4. Cookie specification registry</h2></div></div></div> |
| |
| <p>HttpClient maintains a registry of available cookie specifications using |
| the <code class="classname">CookieSpecRegistry</code> class. The following specifications are |
| registered per default:</p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| <p title="compatibility:"> |
| <b>compatibility: </b> |
| Browser compatibility (lenient policy). |
| </p> |
| </li><li class="listitem"> |
| <p title="netscape:"> |
| <b>netscape: </b> |
| Netscape draft. |
| </p> |
| </li><li class="listitem"> |
| <p title="rfc2109:"> |
| <b>rfc2109: </b> |
| RFC 2109 (outdated strict policy). |
| </p> |
| </li><li class="listitem"> |
| <p title="rfc2965:"> |
| <b>rfc2965: </b> |
| RFC 2965 (standard conformant strict policy). |
| </p> |
| </li><li class="listitem"> |
| <p title="best-match:"> |
| <b>best-match: </b> |
| Best match meta-policy. |
| </p> |
| </li><li class="listitem"> |
| <p title="ignoreCookies:"> |
| <b>ignoreCookies: </b> |
| All cookies are ignored. |
| </p> |
| </li></ul></div> |
| </div> |
| <div class="section" title="3.5. Choosing cookie policy"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e799"></a>3.5. Choosing cookie policy</h2></div></div></div> |
| |
| <p>Cookie policy can be set at the HTTP client and overridden on the HTTP request level |
| if required.</p> |
| <pre class="programlisting"> |
| HttpClient httpclient = new DefaultHttpClient(); |
| // force strict cookie policy per default |
| httpclient.getParams().setParameter( |
| ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2965); |
| |
| HttpGet httpget = new HttpGet("http://www.broken-server.com/"); |
| // Override the default policy for this request |
| httpget.getParams().setParameter( |
| ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY); |
| </pre> |
| </div> |
| <div class="section" title="3.6. Custom cookie policy"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e803"></a>3.6. Custom cookie policy</h2></div></div></div> |
| |
| <p>In order to implement a custom cookie policy one should create a custom implementation |
| of the <code class="interfacename">CookieSpec</code> interface, create a |
| <code class="interfacename">CookieSpecFactory</code> implementation to create and |
| initialize instances of the custom specification and register the factory with |
| HttpClient. Once the custom specification has been registered, it can be activated the |
| same way as a standard cookie specification.</p> |
| <pre class="programlisting"> |
| CookieSpecFactory csf = new CookieSpecFactory() { |
| public CookieSpec newInstance(HttpParams params) { |
| return new BrowserCompatSpec() { |
| @Override |
| public void validate(Cookie cookie, CookieOrigin origin) |
| throws MalformedCookieException { |
| // Oh, I am easy |
| } |
| }; |
| } |
| }; |
| |
| DefaultHttpClient httpclient = new DefaultHttpClient(); |
| httpclient.getCookieSpecs().register("easy", csf); |
| httpclient.getParams().setParameter( |
| ClientPNames.COOKIE_POLICY, "easy"); |
| </pre> |
| </div> |
| <div class="section" title="3.7. Cookie persistence"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e809"></a>3.7. Cookie persistence</h2></div></div></div> |
| |
| <p>HttpClient can work with any physical representation of a persistent cookie store that |
| implements the <code class="interfacename">CookieStore</code> interface. The default |
| <code class="interfacename">CookieStore</code> implementation called |
| <code class="classname">BasicCookieStore</code> is a simple implementation backed by a |
| <code class="classname">java.util.ArrayList</code>. Cookies stored in an |
| <code class="classname">BasicClientCookie</code> object are lost when the container object |
| get garbage collected. Users can provide more complex implementations if |
| necessary.</p> |
| <pre class="programlisting"> |
| DefaultHttpClient httpclient = new DefaultHttpClient(); |
| // Create a local instance of cookie store |
| CookieStore cookieStore = new MyCookieStore(); |
| // Populate cookies if needed |
| BasicClientCookie cookie = new BasicClientCookie("name", "value"); |
| cookie.setVersion(0); |
| cookie.setDomain(".mycompany.com"); |
| cookie.setPath("/"); |
| cookieStore.addCookie(cookie); |
| // Set the store |
| httpclient.setCookieStore(cookieStore); |
| </pre> |
| </div> |
| <div class="section" title="3.8. HTTP state management and execution context"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e818"></a>3.8. HTTP state management and execution context</h2></div></div></div> |
| |
| <p>In the course of HTTP request execution HttpClient adds the following state management |
| related objects to the execution context:</p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| <p title="ClientContext.COOKIESPEC_REGISTRY='http.cookiespec-registry':"> |
| <b><code class="constant">ClientContext.COOKIESPEC_REGISTRY</code>='http.cookiespec-registry': </b> |
| <code class="classname">CookieSpecRegistry</code> instance representing the actual |
| cookie specification registry. The value of this attribute set in the local |
| context takes precedence over the default one. |
| </p> |
| </li><li class="listitem"> |
| <p title="ClientContext.COOKIE_SPEC='http.cookie-spec':"> |
| <b><code class="constant">ClientContext.COOKIE_SPEC</code>='http.cookie-spec': </b> |
| <code class="interfacename">CookieSpec</code> instance representing the actual |
| cookie specification. |
| </p> |
| </li><li class="listitem"> |
| <p title="ClientContext.COOKIE_ORIGIN='http.cookie-origin':"> |
| <b><code class="constant">ClientContext.COOKIE_ORIGIN</code>='http.cookie-origin': </b> |
| <code class="classname">CookieOrigin</code> instance representing the actual |
| details of the origin server. |
| </p> |
| </li><li class="listitem"> |
| <p title="ClientContext.COOKIE_STORE='http.cookie-store':"> |
| <b><code class="constant">ClientContext.COOKIE_STORE</code>='http.cookie-store': </b> |
| <code class="interfacename">CookieStore</code> instance representing the actual |
| cookie store. The value of this attribute set in the local context takes |
| precedence over the default one. |
| </p> |
| </li></ul></div> |
| <p>The local <code class="interfacename">HttpContext</code> object can be used to customize |
| the HTTP state management context prior to request execution, or to examine its state after |
| the request has been executed:</p> |
| <pre class="programlisting"> |
| HttpClient httpclient = new DefaultHttpClient(); |
| HttpContext localContext = new BasicHttpContext(); |
| HttpGet httpget = new HttpGet("http://localhost:8080/"); |
| HttpResponse response = httpclient.execute(httpget, localContext); |
| |
| CookieOrigin cookieOrigin = (CookieOrigin) localContext.getAttribute( |
| ClientContext.COOKIE_ORIGIN); |
| System.out.println("Cookie origin: " + cookieOrigin); |
| CookieSpec cookieSpec = (CookieSpec) localContext.getAttribute( |
| ClientContext.COOKIE_SPEC); |
| System.out.println("Cookie spec used: " + cookieSpec); |
| </pre> |
| </div> |
| <div class="section" title="3.9. Per user / thread state management"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e849"></a>3.9. Per user / thread state management</h2></div></div></div> |
| |
| <p>One can use an individual local execution context in order to implement per user (or |
| per thread) state management. A cookie specification registry and cookie store defined in |
| the local context will take precedence over the default ones set at the HTTP client |
| level.</p> |
| <pre class="programlisting"> |
| HttpClient httpclient = new DefaultHttpClient(); |
| // Create a local instance of cookie store |
| CookieStore cookieStore = new BasicCookieStore(); |
| // Create local HTTP context |
| HttpContext localContext = new BasicHttpContext(); |
| // Bind custom cookie store to the local context |
| localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); |
| HttpGet httpget = new HttpGet("http://www.google.com/"); |
| // Pass local context as a parameter |
| HttpResponse response = httpclient.execute(httpget, localContext); |
| </pre> |
| </div> |
| </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="connmgmt.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="authentication.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 2. Connection management </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 4. HTTP authentication</td></tr></table></div></body></html> |