View Javadoc

    1   /*
    2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/HttpState.java,v 1.38 2004/12/20 11:50:54 olegk Exp $
    3    * $Revision: 561099 $
    4    * $Date: 2007-07-30 21:41:17 +0200 (Mon, 30 Jul 2007) $
    5    *
    6    * ====================================================================
    7    *
    8    *  Licensed to the Apache Software Foundation (ASF) under one or more
    9    *  contributor license agreements.  See the NOTICE file distributed with
    10   *  this work for additional information regarding copyright ownership.
    11   *  The ASF licenses this file to You under the Apache License, Version 2.0
    12   *  (the "License"); you may not use this file except in compliance with
    13   *  the License.  You may obtain a copy of the License at
    14   *
    15   *      http://www.apache.org/licenses/LICENSE-2.0
    16   *
    17   *  Unless required by applicable law or agreed to in writing, software
    18   *  distributed under the License is distributed on an "AS IS" BASIS,
    19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    20   *  See the License for the specific language governing permissions and
    21   *  limitations under the License.
    22   * ====================================================================
    23   *
    24   * This software consists of voluntary contributions made by many
    25   * individuals on behalf of the Apache Software Foundation.  For more
    26   * information on the Apache Software Foundation, please see
    27   * <http://www.apache.org/>.
    28   *
    29   */
    30
    31  package org.apache.commons.httpclient;
    32
    33  import java.util.ArrayList;
    34  import java.util.Date;
    35  import java.util.HashMap;
    36  import java.util.Map;
    37  import java.util.List;
    38  import java.util.Iterator;
    39  import org.apache.commons.httpclient.cookie.CookieSpec;
    40  import org.apache.commons.httpclient.cookie.CookiePolicy;
    41  import org.apache.commons.httpclient.auth.AuthScope;
    42  import org.apache.commons.logging.Log;
    43  import org.apache.commons.logging.LogFactory;
    44
    45  /**
    46   * <p>
    47   * A container for HTTP attributes that may persist from request
    48   * to request, such as {@link Cookie cookies} and authentication
    49   * {@link Credentials credentials}.
    50   * </p>
    51   *
    52   * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
    53   * @author Rodney Waldhoff
    54   * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    55   * @author Sean C. Sullivan
    56   * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
    57   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
    58   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
    59   * @author <a href="mailto:adrian@intencha.com">Adrian Sutton</a>
    60   *
    61   * @version $Revision: 561099 $ $Date: 2007-07-30 21:41:17 +0200 (Mon, 30 Jul 2007) $
    62   *
    63   */
    64  public class HttpState {
    65
    66      // ----------------------------------------------------- Instance Variables
    67
    68      /**
    69       * Map of {@link Credentials credentials} by realm that this
    70       * HTTP state contains.
    71       */
    72      protected HashMap credMap = new HashMap();
    73
    74      /**
    75       * Map of {@link Credentials proxy credentials} by realm that this
    76       * HTTP state contains
    77       */
    78      protected HashMap proxyCred = new HashMap();
    79
    80      /**
    81       * Array of {@link Cookie cookies} that this HTTP state contains.
    82       */
    83      protected ArrayList cookies = new ArrayList();
    84
    85      private boolean preemptive = false;
    86
    87      private int cookiePolicy = -1;
    88      // -------------------------------------------------------- Class Variables
    89
    90      /**
    91       * The boolean system property name to turn on preemptive authentication.
    92       * @deprecated This field and feature will be removed following HttpClient 3.0.
    93       */
    94      public static final String PREEMPTIVE_PROPERTY = "httpclient.authentication.preemptive";
    95
    96      /**
    97       * The default value for {@link #PREEMPTIVE_PROPERTY}.
    98       * @deprecated This field and feature will be removed following HttpClient 3.0.
    99       */
    100     public static final String PREEMPTIVE_DEFAULT = "false";
    101
    102     /** Log object for this class. */
    103     private static final Log LOG = LogFactory.getLog(HttpState.class);
    104
    105     /**
    106      * Default constructor.
    107      */
    108     public HttpState() {
    109         super();
    110     }
    111
    112     // ------------------------------------------------------------- Properties
    113
    114     /**
    115      * Adds an {@link Cookie HTTP cookie}, replacing any existing equivalent cookies.
    116      * If the given cookie has already expired it will not be added, but existing
    117      * values will still be removed.
    118      *
    119      * @param cookie the {@link Cookie cookie} to be added
    120      *
    121      * @see #addCookies(Cookie[])
    122      *
    123      */
    124     public synchronized void addCookie(Cookie cookie) {
    125         LOG.trace("enter HttpState.addCookie(Cookie)");
    126
    127         if (cookie != null) {
    128             // first remove any old cookie that is equivalent
    129             for (Iterator it = cookies.iterator(); it.hasNext();) {
    130                 Cookie tmp = (Cookie) it.next();
    131                 if (cookie.equals(tmp)) {
    132                     it.remove();
    133                     break;
    134                 }
    135             }
    136             if (!cookie.isExpired()) {
    137                 cookies.add(cookie);
    138             }
    139         }
    140     }
    141
    142     /**
    143      * Adds an array of {@link Cookie HTTP cookies}. Cookies are added individually and
    144      * in the given array order. If any of the given cookies has already expired it will
    145      * not be added, but existing values will still be removed.
    146      *
    147      * @param cookies the {@link Cookie cookies} to be added
    148      *
    149      * @see #addCookie(Cookie)
    150      *
    151      *
    152      */
    153     public synchronized void addCookies(Cookie[] cookies) {
    154         LOG.trace("enter HttpState.addCookies(Cookie[])");
    155
    156         if (cookies != null) {
    157             for (int i = 0; i < cookies.length; i++) {
    158                 this.addCookie(cookies[i]);
    159             }
    160         }
    161     }
    162
    163     /**
    164      * Returns an array of {@link Cookie cookies} that this HTTP
    165      * state currently contains.
    166      *
    167      * @return an array of {@link Cookie cookies}.
    168      *
    169      * @see #getCookies(String, int, String, boolean)
    170      *
    171      */
    172     public synchronized Cookie[] getCookies() {
    173         LOG.trace("enter HttpState.getCookies()");
    174         return (Cookie[]) (cookies.toArray(new Cookie[cookies.size()]));
    175     }
    176
    177     /**
    178      * Returns an array of {@link Cookie cookies} in this HTTP
    179      * state that match the given request parameters.
    180      *
    181      * @param domain the request domain
    182      * @param port the request port
    183      * @param path the request path
    184      * @param secure <code>true</code> when using HTTPS
    185      *
    186      * @return an array of {@link Cookie cookies}.
    187      *
    188      * @see #getCookies()
    189      *
    190      * @deprecated use CookieSpec#match(String, int, String, boolean, Cookie)
    191      */
    192     public synchronized Cookie[] getCookies(
    193         String domain,
    194         int port,
    195         String path,
    196         boolean secure
    197     ) {
    198         LOG.trace("enter HttpState.getCookies(String, int, String, boolean)");
    199
    200         CookieSpec matcher = CookiePolicy.getDefaultSpec();
    201         ArrayList list = new ArrayList(cookies.size());
    202         for (int i = 0, m = cookies.size(); i < m; i++) {
    203             Cookie cookie = (Cookie) (cookies.get(i));
    204             if (matcher.match(domain, port, path, secure, cookie)) {
    205                 list.add(cookie);
    206             }
    207         }
    208         return (Cookie[]) (list.toArray(new Cookie[list.size()]));
    209     }
    210
    211     /**
    212      * Removes all of {@link Cookie cookies} in this HTTP state
    213      * that have expired according to the current system time.
    214      *
    215      * @see #purgeExpiredCookies(java.util.Date)
    216      *
    217      */
    218     public synchronized boolean purgeExpiredCookies() {
    219         LOG.trace("enter HttpState.purgeExpiredCookies()");
    220         return purgeExpiredCookies(new Date());
    221     }
    222
    223     /**
    224      * Removes all of {@link Cookie cookies} in this HTTP state
    225      * that have expired by the specified {@link java.util.Date date}.
    226      *
    227      * @param date The {@link java.util.Date date} to compare against.
    228      *
    229      * @return true if any cookies were purged.
    230      *
    231      * @see Cookie#isExpired(java.util.Date)
    232      *
    233      * @see #purgeExpiredCookies()
    234      */
    235     public synchronized boolean purgeExpiredCookies(Date date) {
    236         LOG.trace("enter HttpState.purgeExpiredCookies(Date)");
    237         boolean removed = false;
    238         Iterator it = cookies.iterator();
    239         while (it.hasNext()) {
    240             if (((Cookie) (it.next())).isExpired(date)) {
    241                 it.remove();
    242                 removed = true;
    243             }
    244         }
    245         return removed;
    246     }
    247
    248
    249     /**
    250      * Returns the current {@link CookiePolicy cookie policy} for this
    251      * HTTP state.
    252      *
    253      * @return The {@link CookiePolicy cookie policy}.
    254      *
    255      * @deprecated Use
    256      *  {@link org.apache.commons.httpclient.params.HttpMethodParams#getCookiePolicy()},
    257      *  {@link HttpMethod#getParams()}.
    258      */
    259
    260     public int getCookiePolicy() {
    261         return this.cookiePolicy;
    262     }
    263
    264
    265     /**
    266      * Defines whether preemptive authentication should be
    267      * attempted.
    268      *
    269      * @param value <tt>true</tt> if preemptive authentication should be
    270      * attempted, <tt>false</tt> otherwise.
    271      *
    272      * @deprecated Use
    273      * {@link org.apache.commons.httpclient.params.HttpClientParams#setAuthenticationPreemptive(boolean)},
    274      * {@link HttpClient#getParams()}.
    275      */
    276
    277     public void setAuthenticationPreemptive(boolean value) {
    278         this.preemptive = value;
    279     }
    280
    281
    282     /**
    283      * Returns <tt>true</tt> if preemptive authentication should be
    284      * attempted, <tt>false</tt> otherwise.
    285      *
    286      * @return boolean flag.
    287      *
    288      * @deprecated Use
    289      * {@link org.apache.commons.httpclient.params.HttpClientParams#isAuthenticationPreemptive()},
    290      * {@link HttpClient#getParams()}.
    291      */
    292
    293     public boolean isAuthenticationPreemptive() {
    294         return this.preemptive;
    295     }
    296
    297
    298     /**
    299      * Sets the current {@link CookiePolicy cookie policy} for this HTTP
    300      * state to one of the following supported policies:
    301      * {@link CookiePolicy#COMPATIBILITY},
    302      * {@link CookiePolicy#NETSCAPE_DRAFT} or
    303      * {@link CookiePolicy#RFC2109}.
    304      *
    305      * @param policy new {@link CookiePolicy cookie policy}
    306      *
    307      * @deprecated
    308      *  Use {@link org.apache.commons.httpclient.params.HttpMethodParams#setCookiePolicy(String)},
    309      *  {@link HttpMethod#getParams()}.
    310      */
    311
    312     public void setCookiePolicy(int policy) {
    313         this.cookiePolicy = policy;
    314     }
    315
    316     /**
    317      * Sets the {@link Credentials credentials} for the given authentication
    318      * realm on the given host. The <code>null</code> realm signifies default
    319      * credentials for the given host, which should be used when no
    320      * {@link Credentials credentials} have been explictly supplied for the
    321      * challenging realm. The <code>null</code> host signifies default
    322      * credentials, which should be used when no {@link Credentials credentials}
    323      * have been explictly supplied for the challenging host. Any previous
    324      * credentials for the given realm on the given host will be overwritten.
    325      *
    326      * @param realm the authentication realm
    327      * @param host the host the realm belongs to
    328      * @param credentials the authentication {@link Credentials credentials}
    329      * for the given realm.
    330      *
    331      * @see #getCredentials(String, String)
    332      * @see #setProxyCredentials(String, String, Credentials)
    333      *
    334      * @deprecated use #setCredentials(AuthScope, Credentials)
    335      */
    336
    337     public synchronized void setCredentials(String realm, String host, Credentials credentials) {
    338         LOG.trace("enter HttpState.setCredentials(String, String, Credentials)");
    339         credMap.put(new AuthScope(host, AuthScope.ANY_PORT, realm, AuthScope.ANY_SCHEME), credentials);
    340     }
    341
    342     /**
    343      * Sets the {@link Credentials credentials} for the given authentication
    344      * scope. Any previous credentials for the given scope will be overwritten.
    345      *
    346      * @param authscope the {@link AuthScope authentication scope}
    347      * @param credentials the authentication {@link Credentials credentials}
    348      * for the given scope.
    349      *
    350      * @see #getCredentials(AuthScope)
    351      * @see #setProxyCredentials(AuthScope, Credentials)
    352      *
    353      * @since 3.0
    354      */
    355     public synchronized void setCredentials(final AuthScope authscope, final Credentials credentials) {
    356         if (authscope == null) {
    357             throw new IllegalArgumentException("Authentication scope may not be null");
    358         }
    359         LOG.trace("enter HttpState.setCredentials(AuthScope, Credentials)");
    360         credMap.put(authscope, credentials);
    361     }
    362
    363     /**
    364      * Find matching {@link Credentials credentials} for the given authentication scope.
    365      *
    366      * @param map the credentials hash map
    367      * @param token the {@link AuthScope authentication scope}
    368      * @return the credentials
    369      *
    370      */
    371     private static Credentials matchCredentials(final HashMap map, final AuthScope authscope) {
    372         // see if we get a direct hit
    373         Credentials creds = (Credentials)map.get(authscope);
    374         if (creds == null) {
    375             // Nope.
    376             // Do a full scan
    377             int bestMatchFactor  = -1;
    378             AuthScope bestMatch  = null;
    379             Iterator items = map.keySet().iterator();
    380             while (items.hasNext()) {
    381                 AuthScope current = (AuthScope)items.next();
    382                 int factor = authscope.match(current);
    383                 if (factor > bestMatchFactor) {
    384                     bestMatchFactor = factor;
    385                     bestMatch = current;
    386                 }
    387             }
    388             if (bestMatch != null) {
    389                 creds = (Credentials)map.get(bestMatch);
    390             }
    391         }
    392         return creds;
    393     }
    394
    395     /**
    396      * Get the {@link Credentials credentials} for the given authentication scope on the
    397      * given host.
    398      *
    399      * If the <i>realm</i> exists on <i>host</i>, return the coresponding credentials.
    400      * If the <i>host</i> exists with a <tt>null</tt> <i>realm</i>, return the corresponding
    401      * credentials.
    402      * If the <i>realm</i> exists with a <tt>null</tt> <i>host</i>, return the
    403      * corresponding credentials.  If the <i>realm</i> does not exist, return
    404      * the default Credentials.  If there are no default credentials, return
    405      * <code>null</code>.
    406      *
    407      * @param realm the authentication realm
    408      * @param host the host the realm is on
    409      * @return the credentials
    410      *
    411      * @see #setCredentials(String, String, Credentials)
    412      *
    413      * @deprecated use #getCredentials(AuthScope)
    414      */
    415
    416     public synchronized Credentials getCredentials(String realm, String host) {
    417         LOG.trace("enter HttpState.getCredentials(String, String");
    418         return matchCredentials(this.credMap,
    419             new AuthScope(host, AuthScope.ANY_PORT, realm, AuthScope.ANY_SCHEME));
    420     }
    421
    422     /**
    423      * Get the {@link Credentials credentials} for the given authentication scope.
    424      *
    425      * @param authscope the {@link AuthScope authentication scope}
    426      * @return the credentials
    427      *
    428      * @see #setCredentials(AuthScope, Credentials)
    429      *
    430      * @since 3.0
    431      */
    432     public synchronized Credentials getCredentials(final AuthScope authscope) {
    433         if (authscope == null) {
    434             throw new IllegalArgumentException("Authentication scope may not be null");
    435         }
    436         LOG.trace("enter HttpState.getCredentials(AuthScope)");
    437         return matchCredentials(this.credMap, authscope);
    438     }
    439
    440     /**
    441      * Sets the {@link Credentials credentials} for the given proxy authentication
    442      * realm on the given proxy host. The <code>null</code> proxy realm signifies
    443      * default credentials for the given proxy host, which should be used when no
    444      * {@link Credentials credentials} have been explictly supplied for the
    445      * challenging proxy realm. The <code>null</code> proxy host signifies default
    446      * credentials, which should be used when no {@link Credentials credentials}
    447      * have been explictly supplied for the challenging proxy host. Any previous
    448      * credentials for the given proxy realm on the given proxy host will be
    449      * overwritten.
    450      *
    451      * @param realm the authentication realm
    452      * @param proxyHost the proxy host
    453      * @param credentials the authentication credentials for the given realm
    454      *
    455      * @see #getProxyCredentials(AuthScope)
    456      * @see #setCredentials(AuthScope, Credentials)
    457      *
    458      * @deprecated use #setProxyCredentials(AuthScope, Credentials)
    459      */
    460     public synchronized void setProxyCredentials(
    461         String realm,
    462         String proxyHost,
    463         Credentials credentials
    464     ) {
    465         LOG.trace("enter HttpState.setProxyCredentials(String, String, Credentials");
    466         proxyCred.put(new AuthScope(proxyHost, AuthScope.ANY_PORT, realm, AuthScope.ANY_SCHEME), credentials);
    467     }
    468
    469     /**
    470      * Sets the {@link Credentials proxy credentials} for the given authentication
    471      * realm. Any previous credentials for the given realm will be overwritten.
    472      *
    473      * @param authscope the {@link AuthScope authentication scope}
    474      * @param credentials the authentication {@link Credentials credentials}
    475      * for the given realm.
    476      *
    477      * @see #getProxyCredentials(AuthScope)
    478      * @see #setCredentials(AuthScope, Credentials)
    479      *
    480      * @since 3.0
    481      */
    482     public synchronized void setProxyCredentials(final AuthScope authscope,
    483         final Credentials credentials)
    484     {
    485         if (authscope == null) {
    486             throw new IllegalArgumentException("Authentication scope may not be null");
    487         }
    488         LOG.trace("enter HttpState.setProxyCredentials(AuthScope, Credentials)");
    489         proxyCred.put(authscope, credentials);
    490     }
    491
    492     /**
    493      * Get the {@link Credentials credentials} for the proxy host with the given
    494      * authentication scope.
    495      *
    496      * If the <i>realm</i> exists on <i>host</i>, return the coresponding credentials.
    497      * If the <i>host</i> exists with a <tt>null</tt> <i>realm</i>, return the corresponding
    498      * credentials.
    499      * If the <i>realm</i> exists with a <tt>null</tt> <i>host</i>, return the
    500      * corresponding credentials.  If the <i>realm</i> does not exist, return
    501      * the default Credentials.  If there are no default credentials, return
    502      * <code>null</code>.
    503      *
    504      * @param realm the authentication realm
    505      * @param proxyHost the proxy host the realm is on
    506      * @return the credentials
    507      * @see #setProxyCredentials(String, String, Credentials)
    508      *
    509      * @deprecated use #getProxyCredentials(AuthScope)
    510      */
    511     public synchronized Credentials getProxyCredentials(String realm, String proxyHost) {
    512        LOG.trace("enter HttpState.getCredentials(String, String");
    513         return matchCredentials(this.proxyCred,
    514             new AuthScope(proxyHost, AuthScope.ANY_PORT, realm, AuthScope.ANY_SCHEME));
    515     }
    516
    517     /**
    518      * Get the {@link Credentials proxy credentials} for the given authentication scope.
    519      *
    520      * @param authscope the {@link AuthScope authentication scope}
    521      * @return the credentials
    522      *
    523      * @see #setProxyCredentials(AuthScope, Credentials)
    524      *
    525      * @since 3.0
    526      */
    527     public synchronized Credentials getProxyCredentials(final AuthScope authscope) {
    528         if (authscope == null) {
    529             throw new IllegalArgumentException("Authentication scope may not be null");
    530         }
    531         LOG.trace("enter HttpState.getProxyCredentials(AuthScope)");
    532         return matchCredentials(this.proxyCred, authscope);
    533     }
    534
    535     /**
    536      * Returns a string representation of this HTTP state.
    537      *
    538      * @return The string representation of the HTTP state.
    539      *
    540      * @see java.lang.Object#toString()
    541      */
    542     public synchronized String toString() {
    543         StringBuffer sbResult = new StringBuffer();
    544
    545         sbResult.append("[");
    546         sbResult.append(getCredentialsStringRepresentation(proxyCred));
    547         sbResult.append(" | ");
    548         sbResult.append(getCredentialsStringRepresentation(credMap));
    549         sbResult.append(" | ");
    550         sbResult.append(getCookiesStringRepresentation(cookies));
    551         sbResult.append("]");
    552
    553         String strResult = sbResult.toString();
    554
    555         return strResult;
    556     }
    557
    558     /**
    559      * Returns a string representation of the credentials.
    560      * @param credMap The credentials.
    561      * @return The string representation.
    562      */
    563     private static String getCredentialsStringRepresentation(final Map credMap) {
    564         StringBuffer sbResult = new StringBuffer();
    565         Iterator iter = credMap.keySet().iterator();
    566         while (iter.hasNext()) {
    567             Object key = iter.next();
    568             Credentials cred = (Credentials) credMap.get(key);
    569             if (sbResult.length() > 0) {
    570                 sbResult.append(", ");
    571             }
    572             sbResult.append(key);
    573             sbResult.append("#");
    574             sbResult.append(cred.toString());
    575         }
    576         return sbResult.toString();
    577     }
    578
    579     /**
    580      * Returns a string representation of the cookies.
    581      * @param cookies The cookies
    582      * @return The string representation.
    583      */
    584     private static String getCookiesStringRepresentation(final List cookies) {
    585         StringBuffer sbResult = new StringBuffer();
    586         Iterator iter = cookies.iterator();
    587         while (iter.hasNext()) {
    588             Cookie ck = (Cookie) iter.next();
    589             if (sbResult.length() > 0) {
    590                 sbResult.append("#");
    591             }
    592             sbResult.append(ck.toExternalForm());
    593         }
    594         return sbResult.toString();
    595     }
    596
    597     /**
    598      * Clears all credentials.
    599      */
    600     public void clearCredentials() {
    601         this.credMap.clear();
    602     }
    603
    604     /**
    605      * Clears all proxy credentials.
    606      */
    607     public void clearProxyCredentials() {
    608         this.proxyCred.clear();
    609     }
    610
    611     /**
    612      * Clears all cookies.
    613      */
    614     public synchronized void clearCookies() {
    615         this.cookies.clear();
    616     }
    617
    618     /**
    619      * Clears the state information (all cookies, credentials and proxy credentials).
    620      */
    621     public void clear() {
    622         clearCookies();
    623         clearCredentials();
    624         clearProxyCredentials();
    625     }
    626 }