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