<?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="statemgmt">
    <title>HTTP state management</title>
    <para>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.</para>
    <para>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.</para>
    <section>
        <title>HTTP cookies</title>
        <para>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.</para>
        <para>HttpClient uses the <interfacename>Cookie</interfacename> 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 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.</para>
        <para>The <interfacename>SetCookie</interfacename> interface represents a
                <literal>Set-Cookie</literal> response header sent by the origin server to the HTTP
            agent in order to maintain a conversational state.</para>
        <para>The <interfacename>ClientCookie</interfacename> interface extends <interfacename>
            Cookie</interfacename> 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 <literal>Cookie</literal>
            header because some cookie specifications require that the  <literal>Cookie</literal>
            header should include certain attributes only if they were specified in the
            <literal>Set-Cookie</literal> header.</para>
        <para>Here is an example of creating a client-side cookie object:</para>
        <programlisting><![CDATA[
BasicClientCookie cookie = new BasicClientCookie("name", "value");
// Set effective domain and path attributes
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
// Set attributes exactly as sent by the server
cookie.setAttribute(ClientCookie.PATH_ATTR, "/");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
]]></programlisting>
    </section>
    <section>
        <title>Cookie specifications</title>
        <para>The <interfacename>CookieSpec</interfacename> interface represents a cookie management
            specification. The cookie management specification is expected to enforce:</para>
        <itemizedlist>
            <listitem>
                <para>rules of parsing <literal>Set-Cookie</literal> headers.</para>
            </listitem>
            <listitem>
                <para>rules of validation of parsed cookies.</para>
            </listitem>
            <listitem>
                <para>formatting of <literal>Cookie</literal> header for a given host, port and path
                    of origin.</para>
            </listitem>
        </itemizedlist>
        <para>HttpClient ships with several <interfacename>CookieSpec</interfacename>
            implementations:</para>
        <itemizedlist>
            <listitem>
                <formalpara>
                    <title>Standard strict:</title>
                    <para>State management policy compliant with the syntax and semantics of
                        the well-behaved profile defined by RFC 6265, section 4.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>Standard:</title>
                    <para>State management policy compliant with a more relaxed profile defined
                        by RFC 6265, section 4 intended for interoperability with existing servers
                        that do not conform to the well behaved profile.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>Netscape draft (obsolete):</title>
                    <para>This policy conforms to the original draft specification published
                        by Netscape Communications. It should be avoided unless absolutely necessary
                        for compatibility with legacy code.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>RFC 2965 (obsolete):</title>
                    <para>State management policy compliant with the obsolete state management
                        specification defined by RFC 2965. Please do not use in new applications.
                    </para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>RFC 2109 (obsolete):</title>
                    <para>State management policy compliant with the obsolete state management
                        specification defined by RFC 2109. Please do not use in new applications.
                    </para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>Browser compatibility (obsolete):</title>
                    <para>This policy strives to closely mimic the (mis)behavior of older versions
                        of browser applications such as Microsoft Internet Explorer and Mozilla
                        FireFox. Please do not use in new applications.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>Default:</title>
                    <para>Default cookie policy is a synthetic policy that picks up either RFC 2965,
                        RFC 2109 or Netscape draft compliant implementation based on properties of
                        cookies sent with the HTTP response (such as version attribute,
                        now obsolete). This policy will be deprecated in favor of the
                        standard (RFC 6265 compliant) implementation in the next minor release
                        of HttpClient.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <title>Ignore cookies:</title>
                    <para>All cookies are ignored.</para>
                </formalpara>
            </listitem>
        </itemizedlist>
        <para>It is strongly recommended to use either <literal>Standard</literal> or
            <literal>Standard strict</literal> policy in new applications. Obsolete specifications
            should be used for compatibility with legacy systems only. Support for obsolete
            specifications will be removed in the next major release of HttpClient.
        </para>
    </section>
    <section>
        <title>Choosing cookie policy</title>
        <para>Cookie policy can be set at the HTTP client and overridden on the HTTP request level
            if required.</para>
        <programlisting><![CDATA[
RequestConfig globalConfig = RequestConfig.custom()
        .setCookieSpec(CookieSpecs.DEFAULT)
        .build();
CloseableHttpClient httpclient = HttpClients.custom()
        .setDefaultRequestConfig(globalConfig)
        .build();
RequestConfig localConfig = RequestConfig.copy(globalConfig)
        .setCookieSpec(CookieSpecs.STANDARD_STRICT)
        .build();
HttpGet httpGet = new HttpGet("/");
httpGet.setConfig(localConfig);
]]></programlisting>
    </section>
    <section>
        <title>Custom cookie policy</title>
        <para>In order to implement a custom cookie policy one should create a custom implementation
            of the <interfacename>CookieSpec</interfacename> interface, create a
                <interfacename>CookieSpecProvider</interfacename> 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.</para>
        <programlisting><![CDATA[
PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();

Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>create()
        .register(CookieSpecs.DEFAULT,
                new DefaultCookieSpecProvider(publicSuffixMatcher))
        .register(CookieSpecs.STANDARD,
                new RFC6265CookieSpecProvider(publicSuffixMatcher))
        .register("easy", new EasySpecProvider())
        .build();

RequestConfig requestConfig = RequestConfig.custom()
        .setCookieSpec("easy")
        .build();

CloseableHttpClient httpclient = HttpClients.custom()
        .setDefaultCookieSpecRegistry(r)
        .setDefaultRequestConfig(requestConfig)
        .build();
]]></programlisting>
    </section>
    <section>
        <title>Cookie persistence</title>
        <para>HttpClient can work with any physical representation of a persistent cookie store that
            implements the <interfacename>CookieStore</interfacename> interface. The default
                <interfacename>CookieStore</interfacename> implementation called
                <classname>BasicCookieStore</classname> is a simple implementation backed by a
                <classname>java.util.ArrayList</classname>. Cookies stored in an
                <classname>BasicClientCookie</classname> object are lost when the container object
            get garbage collected. Users can provide more complex implementations if
            necessary.</para>
        <programlisting><![CDATA[
// Create a local instance of cookie store
CookieStore cookieStore = new BasicCookieStore();
// Populate cookies if needed
BasicClientCookie cookie = new BasicClientCookie("name", "value");
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
cookieStore.addCookie(cookie);
// Set the store
CloseableHttpClient httpclient = HttpClients.custom()
        .setDefaultCookieStore(cookieStore)
        .build();
]]></programlisting>
    </section>
    <section>
        <title>HTTP state management and execution context</title>
        <para>In the course of HTTP request execution HttpClient adds the following state management
            related objects to the execution context:</para>
        <itemizedlist>
            <listitem>
                <formalpara>
                    <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>
            </listitem>
            <listitem>
                <formalpara>
                    <para><interfacename>CookieSpec</interfacename> instance representing the actual
                        cookie specification.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <para><classname>CookieOrigin</classname> instance representing the actual
                        details of the origin server.</para>
                </formalpara>
            </listitem>
            <listitem>
                <formalpara>
                    <para><interfacename>CookieStore</interfacename> instance representing the actual
                        cookie store. The value of this attribute set in the local context takes
                        precedence over the default one.</para>
                </formalpara>
            </listitem>
        </itemizedlist>
        <para>The local <interfacename>HttpContext</interfacename> 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. One can also use separate execution contexts 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</para>
        <programlisting><![CDATA[
CloseableHttpClient httpclient = <...>

Lookup<CookieSpecProvider> cookieSpecReg = <...>
CookieStore cookieStore = <...>

HttpClientContext context = HttpClientContext.create();
context.setCookieSpecRegistry(cookieSpecReg);
context.setCookieStore(cookieStore);
HttpGet httpget = new HttpGet("http://somehost/");
CloseableHttpResponse response1 = httpclient.execute(httpget, context);
<...>
// Cookie origin details
CookieOrigin cookieOrigin = context.getCookieOrigin();
// Cookie spec used
CookieSpec cookieSpec = context.getCookieSpec();
]]></programlisting>
    </section>
</chapter>
