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
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$ $Date$
62 *
63 */
64 public class HttpState {
65
66
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
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
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
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
373 Credentials creds = (Credentials)map.get(authscope);
374 if (creds == null) {
375
376
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 }