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.HttpAuthRealm;
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 * <p>
51 * Preemptive authentication can be turned on by using the property value of
52 * #PREEMPTIVE_PROPERTY. If left unspecified, it has the default value of
53 * #PREEMPTIVE_DEFAULT. This configurable behaviour conforms to rcf2617:
54 * </p>
55 *
56 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
57 * @author Rodney Waldhoff
58 * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
59 * @author Sean C. Sullivan
60 * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
61 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
62 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
63 * @author <a href="mailto:adrian@intencha.com">Adrian Sutton</a>
64 *
65 * @version $Revision: 1.33 $ $Date: 2004/05/13 04:03:25 $
66 *
67 */
68 public class HttpState {
69
70
71
72 /***
73 * Map of {@link Credentials credentials} by realm that this
74 * HTTP state contains.
75 */
76 private HashMap credMap = new HashMap();
77
78 /***
79 * Map of {@link Credentials proxy credentials} by realm that this
80 * HTTP state contains
81 */
82 private HashMap proxyCred = new HashMap();
83
84 /***
85 * Array of {@link Cookie cookies} that this HTTP state contains.
86 */
87 private ArrayList cookies = new ArrayList();
88
89 private boolean preemptive = false;
90
91 private int cookiePolicy = 0;
92
93
94 /*** Log object for this class. */
95 private static final Log LOG = LogFactory.getLog(HttpState.class);
96
97 /***
98 * Default constructor.
99 */
100 public HttpState() {
101 super();
102 }
103
104
105
106 /***
107 * Adds an {@link Cookie HTTP cookie}, replacing any existing equivalent cookies.
108 * If the given cookie has already expired it will not be added, but existing
109 * values will still be removed.
110 *
111 * @param cookie the {@link Cookie cookie} to be added
112 *
113 * @see #addCookies(Cookie[])
114 *
115 */
116 public synchronized void addCookie(Cookie cookie) {
117 LOG.trace("enter HttpState.addCookie(Cookie)");
118
119 if (cookie != null) {
120
121 for (Iterator it = cookies.iterator(); it.hasNext();) {
122 Cookie tmp = (Cookie) it.next();
123 if (cookie.equals(tmp)) {
124 it.remove();
125 break;
126 }
127 }
128 if (!cookie.isExpired()) {
129 cookies.add(cookie);
130 }
131 }
132 }
133
134 /***
135 * Adds an array of {@link Cookie HTTP cookies}. Cookies are added individually and
136 * in the given array order. If any of the given cookies has already expired it will
137 * not be added, but existing values will still be removed.
138 *
139 * @param cookies the {@link Cookie cookies} to be added
140 *
141 * @see #addCookie(Cookie)
142 *
143 *
144 */
145 public synchronized void addCookies(Cookie[] cookies) {
146 LOG.trace("enter HttpState.addCookies(Cookie[])");
147
148 if (cookies != null) {
149 for (int i = 0; i < cookies.length; i++) {
150 this.addCookie(cookies[i]);
151 }
152 }
153 }
154
155 /***
156 * Returns an array of {@link Cookie cookies} that this HTTP
157 * state currently contains.
158 *
159 * @return an array of {@link Cookie cookies}.
160 *
161 * @see #getCookies(String, int, String, boolean)
162 *
163 */
164 public synchronized Cookie[] getCookies() {
165 LOG.trace("enter HttpState.getCookies()");
166 return (Cookie[]) (cookies.toArray(new Cookie[cookies.size()]));
167 }
168
169 /***
170 * Returns an array of {@link Cookie cookies} in this HTTP
171 * state that match the given request parameters.
172 *
173 * @param domain the request domain
174 * @param port the request port
175 * @param path the request path
176 * @param secure <code>true</code> when using HTTPS
177 *
178 * @return an array of {@link Cookie cookies}.
179 *
180 * @see #getCookies()
181 *
182 * @deprecated use CookieSpec#match(String, int, String, boolean, Cookie)
183 */
184 public synchronized Cookie[] getCookies(
185 String domain,
186 int port,
187 String path,
188 boolean secure
189 ) {
190 LOG.trace("enter HttpState.getCookies(String, int, String, boolean)");
191
192 CookieSpec matcher = CookiePolicy.getDefaultSpec();
193 ArrayList list = new ArrayList(cookies.size());
194 for (int i = 0, m = cookies.size(); i < m; i++) {
195 Cookie cookie = (Cookie) (cookies.get(i));
196 if (matcher.match(domain, port, path, secure, cookie)) {
197 list.add(cookie);
198 }
199 }
200 return (Cookie[]) (list.toArray(new Cookie[list.size()]));
201 }
202
203 /***
204 * Removes all of {@link Cookie cookies} in this HTTP state
205 * that have expired according to the current system time.
206 *
207 * @see #purgeExpiredCookies(java.util.Date)
208 *
209 */
210 public synchronized boolean purgeExpiredCookies() {
211 LOG.trace("enter HttpState.purgeExpiredCookies()");
212 return purgeExpiredCookies(new Date());
213 }
214
215 /***
216 * Removes all of {@link Cookie cookies} in this HTTP state
217 * that have expired by the specified {@link java.util.Date date}.
218 *
219 * @param date The {@link java.util.Date date} to compare against.
220 *
221 * @return true if any cookies were purged.
222 *
223 * @see Cookie#isExpired(java.util.Date)
224 *
225 * @see #purgeExpiredCookies()
226 */
227 public synchronized boolean purgeExpiredCookies(Date date) {
228 LOG.trace("enter HttpState.purgeExpiredCookies(Date)");
229 boolean removed = false;
230 Iterator it = cookies.iterator();
231 while (it.hasNext()) {
232 if (((Cookie) (it.next())).isExpired(date)) {
233 it.remove();
234 removed = true;
235 }
236 }
237 return removed;
238 }
239
240
241 /***
242 * Returns the current {@link CookiePolicy cookie policy} for this
243 * HTTP state.
244 *
245 * @return The {@link CookiePolicy cookie policy}.
246 *
247 * @deprecated Use
248 * {@link org.apache.commons.httpclient.params.HttpMethodParams#getCookiePolicy()},
249 * {@link HttpMethod#getParams()}.
250 */
251
252 public int getCookiePolicy() {
253 return CookiePolicy.getDefaultPolicy();
254 }
255
256
257 /***
258 * Defines whether preemptive authentication should be
259 * attempted.
260 *
261 * @param value <tt>true</tt> if preemptive authentication should be
262 * attempted, <tt>false</tt> otherwise.
263 *
264 * @deprecated Use
265 * {@link org.apache.commons.httpclient.params.HttpClientParams#setAuthenticationPreemptive(boolean)},
266 * {@link HttpClient#getParams()}.
267 */
268
269 public void setAuthenticationPreemptive(boolean value) {
270 this.preemptive = value;
271 }
272
273
274 /***
275 * Returns <tt>true</tt> if preemptive authentication should be
276 * attempted, <tt>false</tt> otherwise.
277 *
278 * @return boolean flag.
279 *
280 * @deprecated Use
281 * {@link org.apache.commons.httpclient.params.HttpClientParams#isAuthenticationPreemptive()},
282 * {@link HttpClient#getParams()}.
283 */
284
285 public boolean isAuthenticationPreemptive() {
286 return this.preemptive;
287 }
288
289
290 /***
291 * Sets the current {@link CookiePolicy cookie policy} for this HTTP
292 * state to one of the following supported policies:
293 * {@link CookiePolicy#COMPATIBILITY},
294 * {@link CookiePolicy#NETSCAPE_DRAFT} or
295 * {@link CookiePolicy#RFC2109}.
296 *
297 * @param policy new {@link CookiePolicy cookie policy}
298 *
299 * @deprecated
300 * Use {@link org.apache.commons.httpclient.params.HttpMethodParams#setCookiePolicy(String)},
301 * {@link HttpMethod#getParams()}.
302 */
303
304 public void setCookiePolicy(int policy) {
305 this.cookiePolicy = policy;
306 }
307
308 /***
309 * Sets the {@link Credentials credentials} for the given authentication
310 * realm on the given host. The <code>null</code> realm signifies default
311 * credentials for the given host, which should be used when no
312 * {@link Credentials credentials} have been explictly supplied for the
313 * challenging realm. The <code>null</code> host signifies default
314 * credentials, which should be used when no {@link Credentials credentials}
315 * have been explictly supplied for the challenging host. Any previous
316 * credentials for the given realm on the given host will be overwritten.
317 *
318 * @param realm the authentication realm
319 * @param host the host the realm belongs to
320 * @param credentials the authentication {@link Credentials credentials}
321 * for the given realm.
322 *
323 * @see #getCredentials(String, String)
324 * @see #setProxyCredentials(String, String, Credentials)
325 */
326
327 public synchronized void setCredentials(String realm, String host, Credentials credentials) {
328 LOG.trace("enter HttpState.setCredentials(String, String, Credentials)");
329 credMap.put(new HttpAuthRealm(host, realm), credentials);
330 }
331
332 /***
333 * Sets the {@link Credentials credentials} for the given authentication
334 * realm. Any previous credentials for the given realm will be overwritten.
335 *
336 * @param realm the {@link HttpAuthRealm authentication realm}
337 * @param credentials the authentication {@link Credentials credentials}
338 * for the given realm.
339 *
340 * @see #getCredentials(HttpAuthRealm)
341 * @see #setProxyCredentials(HttpAuthRealm, Credentials)
342 *
343 * @since 3.0
344 */
345 public synchronized void setCredentials(final HttpAuthRealm realm, Credentials credentials) {
346 if (realm == null) {
347 throw new IllegalArgumentException("Authentication realm token may not be null");
348 }
349 LOG.trace("enter HttpState.setCredentials(HttpAuthRealm, Credentials)");
350 credMap.put(realm, credentials);
351 }
352
353 /***
354 * Find matching {@link Credentials credentials} for the given authentication realm.
355 *
356 * @param map the credentials hash map
357 * @param token the {@link HttpAuthRealm authentication realm token}
358 * @return the credentials
359 *
360 */
361 private static Credentials matchCredentials(HashMap map, HttpAuthRealm token) {
362 HttpAuthRealm key = token;
363 Credentials creds = (Credentials) map.get(key);
364 if (creds == null && token.getScheme() != null) {
365 key = new HttpAuthRealm(token.getHost(), token.getPort(), token.getRealm());
366 creds = (Credentials) map.get(key);
367 }
368 if (creds == null && token.getRealm() != null) {
369 key = new HttpAuthRealm(token.getHost(), token.getPort());
370 creds = (Credentials) map.get(key);
371 }
372 if (creds == null && token.getPort() >= 0) {
373 key = new HttpAuthRealm(token.getHost(), -1);
374 creds = (Credentials) map.get(key);
375 }
376 if (creds == null && token.getHost() != null) {
377 key = new HttpAuthRealm();
378 creds = (Credentials) map.get(key);
379 }
380 return creds;
381 }
382
383 /***
384 * Get the {@link Credentials credentials} for the given authentication realm on the
385 * given host.
386 *
387 * If the <i>realm</i> exists on <i>host</i>, return the coresponding credentials.
388 * If the <i>host</i> exists with a <tt>null</tt> <i>realm</i>, return the corresponding
389 * credentials.
390 * If the <i>realm</i> exists with a <tt>null</tt> <i>host</i>, return the
391 * corresponding credentials. If the <i>realm</i> does not exist, return
392 * the default Credentials. If there are no default credentials, return
393 * <code>null</code>.
394 *
395 * @param realm the authentication realm
396 * @param host the host the realm is on
397 * @return the credentials
398 *
399 * @see #setCredentials(String, String, Credentials)
400 */
401
402 public synchronized Credentials getCredentials(String realm, String host) {
403 LOG.trace("enter HttpState.getCredentials(String, String");
404 return matchCredentials(this.credMap, new HttpAuthRealm(host, realm));
405 }
406
407 /***
408 * Get the {@link Credentials credentials} for the given authentication realm.
409 *
410 * @param realm the {@link HttpAuthRealm authentication realm}
411 * @return the credentials
412 *
413 * @see #setCredentials(HttpAuthRealm, Credentials)
414 *
415 * @since 3.0
416 */
417 public synchronized Credentials getCredentials(HttpAuthRealm realm) {
418 if (realm == null) {
419 throw new IllegalArgumentException("Authentication realm token may not be null");
420 }
421 LOG.trace("enter HttpState.getCredentials(HttpAuthRealm)");
422 return matchCredentials(this.credMap, realm);
423 }
424
425 /***
426 * Sets the {@link Credentials credentials} for the given proxy authentication
427 * realm on the given proxy host. The <code>null</code> proxy realm signifies
428 * default credentials for the given proxy host, which should be used when no
429 * {@link Credentials credentials} have been explictly supplied for the
430 * challenging proxy realm. The <code>null</code> proxy host signifies default
431 * credentials, which should be used when no {@link Credentials credentials}
432 * have been explictly supplied for the challenging proxy host. Any previous
433 * credentials for the given proxy realm on the given proxy host will be
434 * overwritten.
435 *
436 * @param realm the authentication realm
437 * @param proxyHost the proxy host
438 * @param credentials the authentication credentials for the given realm
439 *
440 * @see #getProxyCredentials(String,String)
441 * @see #setCredentials(String, String, Credentials)
442 */
443 public synchronized void setProxyCredentials(
444 String realm,
445 String proxyHost,
446 Credentials credentials
447 ) {
448 LOG.trace("enter HttpState.setProxyCredentials(String, String, Credentials");
449 proxyCred.put(new HttpAuthRealm(proxyHost, realm), credentials);
450 }
451
452 /***
453 * Sets the {@link Credentials credentials} for the given proxy authentication
454 * realm. Any previous credentials for the given realm will be overwritten.
455 *
456 * @param realm the {@link HttpAuthRealm authentication realm}
457 * @param credentials the authentication {@link Credentials credentials}
458 * for the given realm.
459 *
460 * @see #getProxyCredentials(HttpAuthRealm)
461 * @see #setCredentials(HttpAuthRealm, Credentials)
462 *
463 * @since 3.0
464 */
465 public synchronized void setProxyCredentials(final HttpAuthRealm realm,
466 Credentials credentials)
467 {
468 if (realm == null) {
469 throw new IllegalArgumentException("Authentication realm token may not be null");
470 }
471 LOG.trace("enter HttpState.setProxyCredentials(HttpAuthRealm, Credentials)");
472 proxyCred.put(realm, credentials);
473 }
474
475 /***
476 * Get the {@link Credentials credentials} for the proxy host with the given
477 * authentication realm.
478 *
479 * If the <i>realm</i> exists on <i>host</i>, return the coresponding credentials.
480 * If the <i>host</i> exists with a <tt>null</tt> <i>realm</i>, return the corresponding
481 * credentials.
482 * If the <i>realm</i> exists with a <tt>null</tt> <i>host</i>, return the
483 * corresponding credentials. If the <i>realm</i> does not exist, return
484 * the default Credentials. If there are no default credentials, return
485 * <code>null</code>.
486 *
487 * @param realm the authentication realm
488 * @param proxyHost the proxy host the realm is on
489 * @return the credentials
490 * @see #setProxyCredentials(String, String, Credentials)
491 */
492 public synchronized Credentials getProxyCredentials(String realm, String proxyHost) {
493 LOG.trace("enter HttpState.getCredentials(String, String");
494 return matchCredentials(this.proxyCred, new HttpAuthRealm(proxyHost, realm));
495 }
496
497 /***
498 * Get the {@link Credentials credentials} for the given proxy authentication realm.
499 *
500 * @param realm the {@link HttpAuthRealm authentication realm}
501 * @return the credentials
502 *
503 * @see #setProxyCredentials(HttpAuthRealm, Credentials)
504 *
505 * @since 3.0
506 */
507 public synchronized Credentials getProxyCredentials(HttpAuthRealm realm) {
508 if (realm == null) {
509 throw new IllegalArgumentException("Authentication realm token may not be null");
510 }
511 LOG.trace("enter HttpState.getProxyCredentials(HttpAuthRealm)");
512 return matchCredentials(this.proxyCred, realm);
513 }
514
515 /***
516 * Returns a string representation of this HTTP state.
517 *
518 * @return The string representation of the HTTP state.
519 *
520 * @see java.lang.Object#toString()
521 */
522 public synchronized String toString() {
523 StringBuffer sbResult = new StringBuffer();
524
525 sbResult.append("[");
526 sbResult.append(getCredentialsStringRepresentation(proxyCred));
527 sbResult.append(" | ");
528 sbResult.append(getCredentialsStringRepresentation(credMap));
529 sbResult.append(" | ");
530 sbResult.append(getCookiesStringRepresentation(cookies));
531 sbResult.append("]");
532
533 String strResult = sbResult.toString();
534
535 return strResult;
536 }
537
538 /***
539 * Returns a string representation of the credentials.
540 * @param credMap The credentials.
541 * @return The string representation.
542 */
543 private static String getCredentialsStringRepresentation(final Map credMap) {
544 StringBuffer sbResult = new StringBuffer();
545 Iterator iter = credMap.keySet().iterator();
546 while (iter.hasNext()) {
547 Object key = iter.next();
548 Credentials cred = (Credentials) credMap.get(key);
549 if (sbResult.length() > 0) {
550 sbResult.append(", ");
551 }
552 sbResult.append(key);
553 sbResult.append("#");
554 sbResult.append(cred.toString());
555 }
556 return sbResult.toString();
557 }
558
559 /***
560 * Returns a string representation of the cookies.
561 * @param cookies The cookies
562 * @return The string representation.
563 */
564 private static String getCookiesStringRepresentation(final List cookies) {
565 StringBuffer sbResult = new StringBuffer();
566 Iterator iter = cookies.iterator();
567 while (iter.hasNext()) {
568 Cookie ck = (Cookie) iter.next();
569 if (sbResult.length() > 0) {
570 sbResult.append("#");
571 }
572 sbResult.append(ck.toExternalForm());
573 }
574 return sbResult.toString();
575 }
576 }