1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
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
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
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
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
372 Credentials creds = (Credentials)map.get(authscope);
373 if (creds == null) {
374
375
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 }