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