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: 561099 $ 4 * $Date: 2007-07-30 21:41:17 +0200 (Mon, 30 Jul 2007) $ 5 * 6 * ==================================================================== 7 * 8 * Licensed to the Apache Software Foundation (ASF) under one or more 9 * contributor license agreements. See the NOTICE file distributed with 10 * this work for additional information regarding copyright ownership. 11 * The ASF licenses this file to You under the Apache License, Version 2.0 12 * (the "License"); you may not use this file except in compliance with 13 * the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * ==================================================================== 23 * 24 * This software consists of voluntary contributions made by many 25 * individuals on behalf of the Apache Software Foundation. For more 26 * information on the Apache Software Foundation, please see 27 * <http://www.apache.org/>. 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: 561099 $ $Date: 2007-07-30 21:41:17 +0200 (Mon, 30 Jul 2007) $ 62 * 63 */ 64 public class HttpState { 65 66 // ----------------------------------------------------- Instance Variables 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 // -------------------------------------------------------- Class Variables 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 */ HttpState()108 public HttpState() { 109 super(); 110 } 111 112 // ------------------------------------------------------------- Properties 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 */ addCookie(Cookie cookie)124 public synchronized void addCookie(Cookie cookie) { 125 LOG.trace("enter HttpState.addCookie(Cookie)"); 126 127 if (cookie != null) { 128 // first remove any old cookie that is equivalent 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 */ addCookies(Cookie[] cookies)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 */ getCookies()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 */ getCookies( String domain, int port, String path, boolean secure )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 */ purgeExpiredCookies()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 */ purgeExpiredCookies(Date date)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 getCookiePolicy()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 setAuthenticationPreemptive(boolean value)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 isAuthenticationPreemptive()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 setCookiePolicy(int policy)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 setCredentials(String realm, String host, Credentials credentials)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 */ setCredentials(final AuthScope authscope, final Credentials credentials)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 */ matchCredentials(final HashMap map, final AuthScope authscope)371 private static Credentials matchCredentials(final HashMap map, final AuthScope authscope) { 372 // see if we get a direct hit 373 Credentials creds = (Credentials)map.get(authscope); 374 if (creds == null) { 375 // Nope. 376 // Do a full scan 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 getCredentials(String realm, String host)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 */ getCredentials(final AuthScope authscope)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 */ setProxyCredentials( String realm, String proxyHost, Credentials credentials )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 */ setProxyCredentials(final AuthScope authscope, final Credentials credentials)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 */ getProxyCredentials(String realm, String proxyHost)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 */ getProxyCredentials(final AuthScope authscope)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 */ toString()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 */ getCredentialsStringRepresentation(final Map credMap)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 */ getCookiesStringRepresentation(final List cookies)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 */ clearCredentials()600 public void clearCredentials() { 601 this.credMap.clear(); 602 } 603 604 /** 605 * Clears all proxy credentials. 606 */ clearProxyCredentials()607 public void clearProxyCredentials() { 608 this.proxyCred.clear(); 609 } 610 611 /** 612 * Clears all cookies. 613 */ clearCookies()614 public synchronized void clearCookies() { 615 this.cookies.clear(); 616 } 617 618 /** 619 * Clears the state information (all cookies, credentials and proxy credentials). 620 */ clear()621 public void clear() { 622 clearCookies(); 623 clearCredentials(); 624 clearProxyCredentials(); 625 } 626 } 627