1 7 8 package java.net; 9 10 import java.util.List ; 11 import java.util.StringTokenizer ; 12 import java.util.NoSuchElementException ; 13 import java.text.SimpleDateFormat ; 14 import java.util.TimeZone ; 15 import java.util.Date ; 16 17 import java.lang.NullPointerException ; 19 39 public final class HttpCookie implements Cloneable { 40 41 42 46 private String name; private String value; 49 53 private String comment; private String commentURL; private boolean toDiscard; private String domain; private long maxAge = MAX_AGE_UNSPECIFIED; private String path; private String portlist; private boolean secure; private int version = 1; 63 private long whenCreated = 0; 68 69 70 private final static long MAX_AGE_UNSPECIFIED = -1; 75 76 77 private final static String NETSCAPE_COOKIE_DATE_FORMAT = "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'"; 81 82 private final static String SET_COOKIE = "set-cookie:"; 86 private final static String SET_COOKIE2 = "set-cookie2:"; 87 88 89 90 91 121 122 public HttpCookie(String name, String value) { 123 name = name.trim(); 124 if (name.length() == 0 || !isToken(name) || isReserved(name)) { 125 throw new IllegalArgumentException ("Illegal cookie name"); 126 } 127 128 this.name = name; 129 this.value = value; 130 toDiscard = false; 131 secure = false; 132 133 whenCreated = System.currentTimeMillis(); 134 } 135 136 137 154 public static List <HttpCookie > parse(String header) { 155 int version = guessCookieVersion(header); 156 157 if (startsWithIgnoreCase(header, SET_COOKIE2)) { 159 header = header.substring(SET_COOKIE2.length()); 160 } else if (startsWithIgnoreCase(header, SET_COOKIE)) { 161 header = header.substring(SET_COOKIE.length()); 162 } 163 164 165 List <HttpCookie > cookies = new java.util.ArrayList <HttpCookie >(); 166 if (version == 0) { 170 HttpCookie cookie = parseInternal(header); 172 cookie.setVersion(0); 173 cookies.add(cookie); 174 } else { 175 List <String > cookieStrings = splitMultiCookies(header); 179 for (String cookieStr : cookieStrings) { 180 HttpCookie cookie = parseInternal(cookieStr); 181 cookie.setVersion(1); 182 cookies.add(cookie); 183 } 184 } 185 186 return cookies; 187 } 188 189 190 191 192 193 194 195 201 public boolean hasExpired() { 202 if (maxAge == 0) return true; 203 204 if (maxAge == MAX_AGE_UNSPECIFIED) return false; 208 209 long deltaSecond = (System.currentTimeMillis() - whenCreated) / 1000; 210 if (deltaSecond > maxAge) 211 return true; 212 else 213 return false; 214 } 215 216 229 230 public void setComment(String purpose) { 231 comment = purpose; 232 } 233 234 235 236 237 247 248 public String getComment() { 249 return comment; 250 } 251 252 253 265 266 public void setCommentURL(String purpose) { 267 commentURL = purpose; 268 } 269 270 271 272 273 283 284 public String getCommentURL() { 285 return commentURL; 286 } 287 288 289 297 298 public void setDiscard(boolean discard) { 299 toDiscard = discard; 300 } 301 302 303 304 305 312 313 public boolean getDiscard() { 314 return toDiscard; 315 } 316 317 318 326 327 public void setPortlist(String ports) { 328 portlist = ports; 329 } 330 331 332 333 334 341 342 public String getPortlist() { 343 return portlist; 344 } 345 346 365 366 public void setDomain(String pattern) { 367 if (pattern != null) 368 domain = pattern.toLowerCase(); 369 else 370 domain = pattern; 371 } 372 373 374 375 376 377 386 387 public String getDomain() { 388 return domain; 389 } 390 391 392 413 public void setMaxAge(long expiry) { 414 maxAge = expiry; 415 } 416 417 418 419 420 433 434 public long getMaxAge() { 435 return maxAge; 436 } 437 438 439 440 441 461 462 public void setPath(String uri) { 463 path = uri; 464 } 465 466 467 468 469 481 482 public String getPath() { 483 return path; 484 } 485 486 487 488 489 490 503 504 public void setSecure(boolean flag) { 505 secure = flag; 506 } 507 508 509 510 511 522 523 public boolean getSecure() { 524 return secure; 525 } 526 527 528 529 530 531 538 539 public String getName() { 540 return name; 541 } 542 543 544 545 546 547 564 565 public void setValue(String newValue) { 566 value = newValue; 567 } 568 569 570 571 572 581 582 public String getValue() { 583 return value; 584 } 585 586 587 588 589 604 605 public int getVersion() { 606 return version; 607 } 608 609 610 611 612 627 628 public void setVersion(int v) { 629 if (v != 0 && v != 1) { 630 throw new IllegalArgumentException ("cookie version should be 0 or 1"); 631 } 632 633 version = v; 634 } 635 636 637 686 public static boolean domainMatches(String domain, String host) { 687 if (domain == null || host == null) 688 return false; 689 690 boolean isLocalDomain = ".local".equalsIgnoreCase(domain); 692 int embeddedDotInDomain = domain.indexOf('.'); 693 if (embeddedDotInDomain == 0) 694 embeddedDotInDomain = domain.indexOf('.', 1); 695 if (!isLocalDomain 696 && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) 697 return false; 698 699 int firstDotInHost = host.indexOf('.'); 701 if (firstDotInHost == -1 && isLocalDomain) 702 return true; 703 704 int domainLength = domain.length(); 705 int lengthDiff = host.length() - domainLength; 706 if (lengthDiff == 0) { 707 return host.equalsIgnoreCase(domain); 709 } 710 else if (lengthDiff > 0) { 711 String H = host.substring(0, lengthDiff); 713 String D = host.substring(lengthDiff); 714 715 return (H.indexOf('.') == -1 && D.equalsIgnoreCase(domain)); 716 } 717 else if (lengthDiff == -1) { 718 return (domain.charAt(0) == '.' && 720 host.equalsIgnoreCase(domain.substring(1))); 721 } 722 723 return false; 724 } 725 726 727 734 public String toString() { 735 if (getVersion() > 0) { 736 return toRFC2965HeaderString(); 737 } else { 738 return toNetscapeHeaderString(); 739 } 740 } 741 742 743 754 public boolean equals(Object obj) { 755 if (obj == this) 756 return true; 757 if (!(obj instanceof HttpCookie )) 758 return false; 759 HttpCookie other = (HttpCookie )obj; 760 761 return equalsIgnoreCase(getName(), other.getName()) && 766 equalsIgnoreCase(getDomain(), other.getDomain()) && 767 equals(getPath(), other.getPath()); 768 } 769 770 771 784 public int hashCode() { 785 int h1 = name.toLowerCase().hashCode(); 786 int h2 = (domain!=null) ? domain.toLowerCase().hashCode() : 0; 787 int h3 = (path!=null) ? path.hashCode() : 0; 788 789 return h1 + h2 + h3; 790 } 791 792 797 public Object clone() { 798 try { 799 return super.clone(); 800 } catch (CloneNotSupportedException e) { 801 throw new RuntimeException (e.getMessage()); 802 } 803 } 804 805 806 807 808 private static final String tspecials = ",;"; 813 814 823 824 private static boolean isToken(String value) { 825 int len = value.length(); 826 827 for (int i = 0; i < len; i++) { 828 char c = value.charAt(i); 829 830 if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) 831 return false; 832 } 833 return true; 834 } 835 836 837 842 private static boolean isReserved(String name) { 843 if (name.equalsIgnoreCase("Comment") 844 || name.equalsIgnoreCase("CommentURL") || name.equalsIgnoreCase("Discard") || name.equalsIgnoreCase("Domain") 847 || name.equalsIgnoreCase("Expires") || name.equalsIgnoreCase("Max-Age") 849 || name.equalsIgnoreCase("Path") 850 || name.equalsIgnoreCase("Port") || name.equalsIgnoreCase("Secure") 852 || name.equalsIgnoreCase("Version") 853 || name.charAt(0) == '$') 854 { 855 return true; 856 } 857 858 return false; 859 } 860 861 862 872 private static HttpCookie parseInternal(String header) 873 { 874 HttpCookie cookie = null; 875 String namevaluePair = null; 876 877 StringTokenizer tokenizer = new StringTokenizer (header, ";"); 878 879 try { 882 namevaluePair = tokenizer.nextToken(); 883 int index = namevaluePair.indexOf('='); 884 if (index != -1) { 885 String name = namevaluePair.substring(0, index).trim(); 886 String value = namevaluePair.substring(index + 1).trim(); 887 cookie = new HttpCookie (name, stripOffSurroundingQuote(value)); 888 } else { 889 throw new IllegalArgumentException ("Invalid cookie name-value pair"); 891 } 892 } catch (NoSuchElementException ignored) { 893 throw new IllegalArgumentException ("Empty cookie header string"); 894 } 895 896 while (tokenizer.hasMoreTokens()) { 898 namevaluePair = tokenizer.nextToken(); 899 int index = namevaluePair.indexOf('='); 900 String name, value; 901 if (index != -1) { 902 name = namevaluePair.substring(0, index).trim(); 903 value = namevaluePair.substring(index + 1).trim(); 904 } else { 905 name = namevaluePair.trim(); 906 value = null; 907 } 908 909 assignAttribute(cookie, name, value); 911 } 912 913 return cookie; 914 } 915 916 917 921 static interface CookieAttributeAssignor { 922 public void assign(HttpCookie cookie, String attrName, String attrValue); 923 } 924 static java.util.Map <String , CookieAttributeAssignor> assignors = null; 925 static { 926 assignors = new java.util.HashMap <String , CookieAttributeAssignor>(); 927 assignors.put("comment", new CookieAttributeAssignor(){ 928 public void assign(HttpCookie cookie, String attrName, String attrValue) { 929 if (cookie.getComment() == null) cookie.setComment(attrValue); 930 } 931 }); 932 assignors.put("commenturl", new CookieAttributeAssignor(){ 933 public void assign(HttpCookie cookie, String attrName, String attrValue) { 934 if (cookie.getCommentURL() == null) cookie.setCommentURL(attrValue); 935 } 936 }); 937 assignors.put("discard", new CookieAttributeAssignor(){ 938 public void assign(HttpCookie cookie, String attrName, String attrValue) { 939 cookie.setDiscard(true); 940 } 941 }); 942 assignors.put("domain", new CookieAttributeAssignor(){ 943 public void assign(HttpCookie cookie, String attrName, String attrValue) { 944 if (cookie.getDomain() == null) cookie.setDomain(attrValue); 945 } 946 }); 947 assignors.put("max-age", new CookieAttributeAssignor(){ 948 public void assign(HttpCookie cookie, String attrName, String attrValue) { 949 try { 950 long maxage = Long.parseLong(attrValue); 951 if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) cookie.setMaxAge(maxage); 952 } catch (NumberFormatException ignored) { 953 throw new IllegalArgumentException ("Illegal cookie max-age attribute"); 954 } 955 } 956 }); 957 assignors.put("path", new CookieAttributeAssignor(){ 958 public void assign(HttpCookie cookie, String attrName, String attrValue) { 959 if (cookie.getPath() == null) cookie.setPath(attrValue); 960 } 961 }); 962 assignors.put("port", new CookieAttributeAssignor(){ 963 public void assign(HttpCookie cookie, String attrName, String attrValue) { 964 if (cookie.getPortlist() == null) cookie.setPortlist(attrValue); 965 } 966 }); 967 assignors.put("secure", new CookieAttributeAssignor(){ 968 public void assign(HttpCookie cookie, String attrName, String attrValue) { 969 cookie.setSecure(true); 970 } 971 }); 972 assignors.put("version", new CookieAttributeAssignor(){ 973 public void assign(HttpCookie cookie, String attrName, String attrValue) { 974 try { 975 int version = Integer.parseInt(attrValue); 976 cookie.setVersion(version); 977 } catch (NumberFormatException ignored) { 978 throw new IllegalArgumentException ("Illegal cookie version attribute"); 979 } 980 } 981 }); 982 assignors.put("expires", new CookieAttributeAssignor(){ public void assign(HttpCookie cookie, String attrName, String attrValue) { 984 if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) { 985 cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue)); 986 } 987 } 988 }); 989 } 990 private static void assignAttribute(HttpCookie cookie, 991 String attrName, 992 String attrValue) 993 { 994 attrValue = stripOffSurroundingQuote(attrValue); 996 997 CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase()); 998 if (assignor != null) { 999 assignor.assign(cookie, attrName, attrValue); 1000 } else { 1001 throw new IllegalArgumentException ("Illegal cookie attribute"); 1003 } 1004 } 1005 1006 1010 private String toNetscapeHeaderString() { 1011 StringBuilder sb = new StringBuilder (); 1012 1013 sb.append(getName() + "=" + getValue()); 1014 1015 return sb.toString(); 1016 } 1017 1018 1022 private String toRFC2965HeaderString() { 1023 StringBuilder sb = new StringBuilder (); 1024 1025 sb.append(getName()).append("=\"").append(getValue()).append('"'); 1026 if (getPath() != null) 1027 sb.append(";$Path=\"").append(getPath()).append('"'); 1028 if (getDomain() != null) 1029 sb.append(";$Domain=\"").append(getDomain()).append('"'); 1030 if (getPortlist() != null) 1031 sb.append(";$Port=\"").append(getPortlist()).append('"'); 1032 1033 return sb.toString(); 1034 } 1035 1036 1044 private long expiryDate2DeltaSeconds(String dateString) { 1045 SimpleDateFormat df = new SimpleDateFormat (NETSCAPE_COOKIE_DATE_FORMAT); 1046 df.setTimeZone(TimeZone.getTimeZone("GMT")); 1047 1048 try { 1049 Date date = df.parse(dateString); 1050 return (date.getTime() - whenCreated) / 1000; 1051 } catch (Exception e) { 1052 return 0; 1053 } 1054 } 1055 1056 1057 1058 1061 private static int guessCookieVersion(String header) { 1062 int version = 0; 1063 1064 header = header.toLowerCase(); 1065 if (header.indexOf("expires=") != -1) { 1066 version = 0; 1068 } else if (header.indexOf("version=") != -1) { 1069 version = 1; 1071 } else if (header.indexOf("max-age") != -1) { 1072 version = 1; 1074 } else if (startsWithIgnoreCase(header, SET_COOKIE2)) { 1075 version = 1; 1077 } 1078 1079 return version; 1080 } 1081 1082 private static String stripOffSurroundingQuote(String str) { 1083 if (str != null && str.length() > 0 && 1084 str.charAt(0) == '"' && str.charAt(str.length() - 1) == '"') { 1085 return str.substring(1, str.length() - 1); 1086 } else { 1087 return str; 1088 } 1089 } 1090 1091 private static boolean equalsIgnoreCase(String s, String t) { 1092 if (s == t) return true; 1093 if ((s != null) && (t != null)) { 1094 return s.equalsIgnoreCase(t); 1095 } 1096 return false; 1097 } 1098 1099 private static boolean equals(String s, String t) { 1100 if (s == t) return true; 1101 if ((s != null) && (t != null)) { 1102 return s.equals(t); 1103 } 1104 return false; 1105 } 1106 1107 private static boolean startsWithIgnoreCase(String s, String start) { 1108 if (s == null || start == null) return false; 1109 1110 if (s.length() >= start.length() && 1111 start.equalsIgnoreCase(s.substring(0, start.length()))) { 1112 return true; 1113 } 1114 1115 return false; 1116 } 1117 1118 1129 private static List <String > splitMultiCookies(String header) { 1130 List <String > cookies = new java.util.ArrayList <String >(); 1131 int quoteCount = 0; 1132 int p, q; 1133 1134 for (p = 0, q = 0; p < header.length(); p++) { 1135 char c = header.charAt(p); 1136 if (c == '"') quoteCount++; 1137 if (c == ',' && (quoteCount % 2 == 0)) { cookies.add(header.substring(q, p)); 1139 q = p + 1; 1140 } 1141 } 1142 1143 cookies.add(header.substring(q)); 1144 1145 return cookies; 1146 } 1147} 1148 1149 | Popular Tags |