// The value of the cookie itself. privatefinal String name; // NAME= ... "$Name" style is reserved private String value; // value of NAME
// Attributes encoded in the header's cookie fields. private String comment; // Comment=VALUE ... describes cookie's use private String commentURL; // CommentURL="http URL" ... describes cookie's use privateboolean toDiscard; // Discard ... discard cookie unconditionally private String domain; // Domain=VALUE ... domain that sees cookie privatelong maxAge = MAX_AGE_UNSPECIFIED; // Max-Age=VALUE ... cookies auto-expire private String path; // Path=VALUE ... URLs that see the cookie private String portlist; // Port[="portlist"] ... the port cookie may be returned to privateboolean secure; // Secure ... e.g. use SSL privateboolean httpOnly; // HttpOnly ... i.e. not accessible to scripts privateint version = 1; // Version=1 ... RFC 2965 style
// The original header this cookie was constructed from, if it was // constructed by parsing a header, otherwise null. privatefinal String header;
// Hold the creation time (in seconds) of the http cookie for later // expiration calculation privatefinallong whenCreated;
// Since the positive and zero max-age have their meanings, // this value serves as a hint as 'not specify max-age' privatestaticfinallong MAX_AGE_UNSPECIFIED = -1;
// date formats used by Netscape's cookie draft // as well as formats seen on various sites privatestaticfinal String[] COOKIE_DATE_FORMATS = { "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'", "EEE',' dd MMM yyyy HH:mm:ss 'GMT'", "EEE MMM dd yyyy HH:mm:ss 'GMT'Z", "EEE',' dd-MMM-yy HH:mm:ss 'GMT'", "EEE',' dd MMM yy HH:mm:ss 'GMT'", "EEE MMM dd yy HH:mm:ss 'GMT'Z"
};
// Private version of parse() that will store the original header used to // create the cookie, in the cookie itself. This can be useful for filtering // Set-Cookie[2] headers, using the internal parsing logic defined in this // class. privatestatic List<HttpCookie> parse(String header, boolean retainHeader) {
int version = guessCookieVersion(header);
// if header start with set-cookie or set-cookie2, strip it off if (startsWithIgnoreCase(header, SET_COOKIE2)) {
header = header.substring(SET_COOKIE2.length());
} elseif (startsWithIgnoreCase(header, SET_COOKIE)) {
header = header.substring(SET_COOKIE.length());
}
List<HttpCookie> cookies = new java.util.ArrayList<>(); // The Netscape cookie may have a comma in its expires attribute, while // the comma is the delimiter in rfc 2965/2109 cookie header string. // so the parse logic is slightly different if (version == 0) { // Netscape draft cookie
HttpCookie cookie = parseInternal(header, retainHeader);
cookie.setVersion(0);
cookies.add(cookie);
} else { // rfc2965/2109 cookie // if header string contains more than one cookie, // it'll separate them with comma
List<String> cookieStrings = splitMultiCookies(header); for (String cookieStr : cookieStrings) {
HttpCookie cookie = parseInternal(cookieStr, retainHeader);
cookie.setVersion(1);
cookies.add(cookie);
}
}
return cookies;
}
// ---------------- Public operations --------------
// if there's no embedded dot in domain and domain is not .local boolean isLocalDomain = ".local".equalsIgnoreCase(domain); int embeddedDotInDomain = domain.indexOf('.'); if (embeddedDotInDomain == 0)
embeddedDotInDomain = domain.indexOf('.', 1); if (!isLocalDomain
&& (embeddedDotInDomain == -1 ||
embeddedDotInDomain == domain.length() - 1)) returnfalse;
// if the host name contains no dot and the domain name // is .local or host.local int firstDotInHost = host.indexOf('.'); if (firstDotInHost == -1 &&
(isLocalDomain ||
domain.equalsIgnoreCase(host + ".local"))) { returntrue;
}
int domainLength = domain.length(); int lengthDiff = host.length() - domainLength; if (lengthDiff == 0) { // if the host name and the domain name are just string-compare equal return host.equalsIgnoreCase(domain);
} elseif (lengthDiff > 0) { // need to check H & D component
String H = host.substring(0, lengthDiff);
String D = host.substring(lengthDiff);
// One http cookie is equal to another cookie (RFC 2965 sec. 3.3.3) if: // 1. they come from same domain (case-insensitive), // 2. have same name (case-insensitive), // 3. and have same path (case-sensitive). return equalsIgnoreCase(getName(), other.getName()) &&
equalsIgnoreCase(getDomain(), other.getDomain()) &&
Objects.equals(getPath(), other.getPath());
}
// Note -- disabled for now to allow full Netscape compatibility // from RFC 2068, token special case characters // // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; privatestaticfinal String tspecials = ",; "; // deliberately includes space
/* *Testsastringandreturnstrueifthestringcountsasatoken. * *@paramvalue *the{@codeString}tobetested * *@return{@codetrue}ifthe{@codeString}isatoken; *{@codefalse}ifitisnot
*/ privatestaticboolean isToken(String value) { int len = value.length();
for (int i = 0; i < len; i++) { char c = value.charAt(i);
if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) returnfalse;
} returntrue;
}
StringTokenizer tokenizer = new StringTokenizer(header, ";");
// there should always have at least on name-value pair; // it's cookie's name try {
namevaluePair = tokenizer.nextToken(); int index = namevaluePair.indexOf('='); if (index != -1) {
String name = namevaluePair.substring(0, index).trim();
String value = namevaluePair.substring(index + 1).trim(); if (retainHeader)
cookie = new HttpCookie(name,
stripOffSurroundingQuote(value),
header); else
cookie = new HttpCookie(name,
stripOffSurroundingQuote(value));
} else { // no "=" in name-value pair; it's an error thrownew IllegalArgumentException("Invalid cookie name-value pair");
}
} catch (NoSuchElementException ignored) { thrownew IllegalArgumentException("Empty cookie header string");
}
// remaining name-value pairs are cookie's attributes while (tokenizer.hasMoreTokens()) {
namevaluePair = tokenizer.nextToken(); int index = namevaluePair.indexOf('=');
String name, value; if (index != -1) {
name = namevaluePair.substring(0, index).trim();
value = namevaluePair.substring(index + 1).trim();
} else {
name = namevaluePair.trim();
value = null;
}
// assign attribute to cookie
assignAttribute(cookie, name, value);
}
return cookie;
}
/* *assigncookieattributevaluetoattributename; *useamaptosimulatemethoddispatch
*/ staticinterface CookieAttributeAssignor { publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue);
} staticfinal java.util.Map<String, CookieAttributeAssignor> assignors = new java.util.HashMap<>(); static {
assignors.put("comment", new CookieAttributeAssignor() { publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { if (cookie.getComment() == null)
cookie.setComment(attrValue);
}
});
assignors.put("commenturl", new CookieAttributeAssignor() { publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { if (cookie.getCommentURL() == null)
cookie.setCommentURL(attrValue);
}
});
assignors.put("discard", new CookieAttributeAssignor() { publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) {
cookie.setDiscard(true);
}
});
assignors.put("domain", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { if (cookie.getDomain() == null)
cookie.setDomain(attrValue);
}
});
assignors.put("max-age", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { try { long maxage = Long.parseLong(attrValue); if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED)
cookie.setMaxAge(maxage);
} catch (NumberFormatException ignored) { thrownew IllegalArgumentException( "Illegal cookie max-age attribute");
}
}
});
assignors.put("path", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { if (cookie.getPath() == null)
cookie.setPath(attrValue);
}
});
assignors.put("port", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { if (cookie.getPortlist() == null)
cookie.setPortlist(attrValue == null ? "" : attrValue);
}
});
assignors.put("secure", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) {
cookie.setSecure(true);
}
});
assignors.put("httponly", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) {
cookie.setHttpOnly(true);
}
});
assignors.put("version", new CookieAttributeAssignor(){ publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { try { int version = Integer.parseInt(attrValue);
cookie.setVersion(version);
} catch (NumberFormatException ignored) { // Just ignore bogus version, it will default to 0 or 1
}
}
});
assignors.put("expires", new CookieAttributeAssignor(){ // Netscape only publicvoid assign(HttpCookie cookie,
String attrName,
String attrValue) { if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) { long delta = cookie.expiryDate2DeltaSeconds(attrValue);
cookie.setMaxAge(delta > 0 ? delta : 0);
}
}
});
} privatestaticvoid assignAttribute(HttpCookie cookie,
String attrName,
String attrValue)
{ // strip off the surrounding "-sign if there's any
attrValue = stripOffSurroundingQuote(attrValue);
CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase()); if (assignor != null) {
assignor.assign(cookie, attrName, attrValue);
} else { // Ignore the attribute as per RFC 2965
}
}
static {
SharedSecrets.setJavaNetHttpCookieAccess( new JavaNetHttpCookieAccess() { public List<HttpCookie> parse(String header) { return HttpCookie.parse(header, true);
}
/* *@paramdateString *adatestringinoneoftheformatsdefinedinNetscapecookiespec * *@returndeltasecondsbetweenthiscookie'screationtimeandthetime *specifiedbydateString
*/ privatelong expiryDate2DeltaSeconds(String dateString) {
Calendar cal = new GregorianCalendar(GMT); for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) {
SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i],
Locale.US);
cal.set(1970, 0, 1, 0, 0, 0);
df.setTimeZone(GMT);
df.setLenient(false);
df.set2DigitYearStart(cal.getTime()); try {
cal.setTime(df.parse(dateString)); if (!COOKIE_DATE_FORMATS[i].contains("yyyy")) { // 2-digit years following the standard set // out it rfc 6265 int year = cal.get(Calendar.YEAR);
year %= 100; if (year < 70) {
year += 2000;
} else {
year += 1900;
}
cal.set(Calendar.YEAR, year);
} return (cal.getTimeInMillis() - whenCreated) / 1000;
} catch (Exception e) { // Ignore, try the next date format
}
} return0;
}
/* *trytoguessthecookieversionthroughset-cookieheaderstring
*/ privatestaticint guessCookieVersion(String header) { int version = 0;
header = header.toLowerCase(); if (header.contains("expires=")) { // only netscape cookie using 'expires'
version = 0;
} elseif (header.contains("version=")) { // version is mandatory for rfc 2965/2109 cookie
version = 1;
} elseif (header.contains("max-age")) { // rfc 2965/2109 use 'max-age'
version = 1;
} elseif (startsWithIgnoreCase(header, SET_COOKIE2)) { // only rfc 2965 cookie starts with 'set-cookie2'
version = 1;
}
privatestaticboolean equalsIgnoreCase(String s, String t) { if (s == t) returntrue; if ((s != null) && (t != null)) { return s.equalsIgnoreCase(t);
} returnfalse;
}
privatestaticboolean startsWithIgnoreCase(String s, String start) { if (s == null || start == null) returnfalse;
if (s.length() >= start.length() &&
start.equalsIgnoreCase(s.substring(0, start.length()))) { returntrue;
}
returnfalse;
}
/* *Splitcookieheaderstringaccordingtorfc2965: *1)splitwhereitisacomma; *2)butnotthecommasurroundingbydouble-quotes,whichisthecomma *insideportlistorembeddedURIs. * *@paramheader *thecookieheaderstringtosplit * *@returnlistofstrings;nevernull
*/ privatestatic List<String> splitMultiCookies(String header) {
List<String> cookies = new java.util.ArrayList<>(); int quoteCount = 0; int p, q;
for (p = 0, q = 0; p < header.length(); p++) { char c = header.charAt(p); if (c == '"') quoteCount++; if (c == ',' && (quoteCount % 2 == 0)) { // it is comma and not surrounding by double-quotes
cookies.add(header.substring(q, p));
q = p + 1;
}
}
cookies.add(header.substring(q));
return cookies;
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.44 Sekunden
(vorverarbeitet am 2026-10-11)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.