Path: blob/trunk/java/src/org/openqa/selenium/Cookie.java
1865 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617package org.openqa.selenium;1819import java.io.Serializable;20import java.text.SimpleDateFormat;21import java.util.Date;22import java.util.Map;23import java.util.Objects;24import java.util.TimeZone;25import java.util.TreeMap;26import org.jspecify.annotations.NullMarked;27import org.jspecify.annotations.Nullable;2829@NullMarked30public class Cookie implements Serializable {31private static final long serialVersionUID = 4115876353625612383L;3233private final String name;34private final String value;35private final String path;36private final @Nullable String domain;37private final @Nullable Date expiry;38private final boolean isSecure;39private final boolean isHttpOnly;40private final @Nullable String sameSite;4142/**43* Creates an insecure non-httpOnly cookie with no domain specified.44*45* @param name The name of the cookie; may not be null or an empty string.46* @param value The cookie value; may not be null.47* @param path The path the cookie is visible to. If left blank or set to null, will be set to48* "/".49* @param expiry The cookie's expiration date; may be null.50* @see #Cookie(String, String, String, String, Date)51*/52public Cookie(String name, String value, @Nullable String path, @Nullable Date expiry) {53this(name, value, null, path, expiry);54}5556/**57* Creates an insecure non-httpOnly cookie.58*59* @param name The name of the cookie; may not be null or an empty string.60* @param value The cookie value; may not be null.61* @param domain The domain the cookie is visible to.62* @param path The path the cookie is visible to. If left blank or set to null, will be set to63* "/".64* @param expiry The cookie's expiration date; may be null.65* @see #Cookie(String, String, String, String, Date, boolean)66*/67public Cookie(68String name,69String value,70@Nullable String domain,71@Nullable String path,72@Nullable Date expiry) {73this(name, value, domain, path, expiry, false);74}7576/**77* Creates a non-httpOnly cookie.78*79* @param name The name of the cookie; may not be null or an empty string.80* @param value The cookie value; may not be null.81* @param domain The domain the cookie is visible to.82* @param path The path the cookie is visible to. If left blank or set to null, will be set to83* "/".84* @param expiry The cookie's expiration date; may be null.85* @param isSecure Whether this cookie requires a secure connection.86*/87public Cookie(88String name,89String value,90@Nullable String domain,91@Nullable String path,92@Nullable Date expiry,93boolean isSecure) {94this(name, value, domain, path, expiry, isSecure, false);95}9697/**98* Creates a cookie.99*100* @param name The name of the cookie; may not be null or an empty string.101* @param value The cookie value; may not be null.102* @param domain The domain the cookie is visible to.103* @param path The path the cookie is visible to. If left blank or set to null, will be set to104* "/".105* @param expiry The cookie's expiration date; may be null.106* @param isSecure Whether this cookie requires a secure connection.107* @param isHttpOnly Whether this cookie is a httpOnly cooke.108*/109public Cookie(110String name,111String value,112@Nullable String domain,113@Nullable String path,114@Nullable Date expiry,115boolean isSecure,116boolean isHttpOnly) {117this(name, value, domain, path, expiry, isSecure, isHttpOnly, null);118}119120/**121* Creates a cookie.122*123* @param name The name of the cookie; may not be null or an empty string.124* @param value The cookie value; may not be null.125* @param domain The domain the cookie is visible to.126* @param path The path the cookie is visible to. If left blank or set to null, will be set to127* "/".128* @param expiry The cookie's expiration date; may be null.129* @param isSecure Whether this cookie requires a secure connection.130* @param isHttpOnly Whether this cookie is a httpOnly cookie.131* @param sameSite The samesite attribute of this cookie; e.g. None, Lax, Strict.132*/133public Cookie(134String name,135String value,136@Nullable String domain,137@Nullable String path,138@Nullable Date expiry,139boolean isSecure,140boolean isHttpOnly,141@Nullable String sameSite) {142this.name = name;143this.value = value;144this.path = path == null || path.isEmpty() ? "/" : path;145146this.domain = stripPort(domain);147this.isSecure = isSecure;148this.isHttpOnly = isHttpOnly;149150if (expiry != null) {151// Expiration date is specified in seconds since (UTC) epoch time, so truncate the date.152this.expiry = new Date(expiry.getTime() / 1000 * 1000);153} else {154this.expiry = null;155}156157this.sameSite = sameSite;158}159160/**161* Create a cookie for the default path with the given name and value with no expiry set.162*163* @param name The cookie's name164* @param value The cookie's value165*/166public Cookie(String name, String value) {167this(name, value, "/", null);168}169170/**171* Create a cookie.172*173* @param name The cookie's name174* @param value The cookie's value175* @param path The path the cookie is for176*/177public Cookie(String name, String value, String path) {178this(name, value, path, null);179}180181public String getName() {182return name;183}184185public String getValue() {186return value;187}188189public @Nullable String getDomain() {190return domain;191}192193public String getPath() {194return path;195}196197public boolean isSecure() {198return isSecure;199}200201public boolean isHttpOnly() {202return isHttpOnly;203}204205public @Nullable Date getExpiry() {206return expiry == null ? null : new Date(expiry.getTime());207}208209public @Nullable String getSameSite() {210return sameSite;211}212213private static @Nullable String stripPort(@Nullable String domain) {214return (domain == null) ? null : domain.split(":")[0];215}216217public void validate() {218if (name == null || name.isEmpty() || value == null || path == null) {219throw new IllegalArgumentException(220"Required attributes are not set or " + "any non-null attribute set to null");221}222223if (name.indexOf(';') != -1) {224throw new IllegalArgumentException("Cookie names cannot contain a ';': " + name);225}226227if (domain != null && domain.contains(":")) {228throw new IllegalArgumentException("Domain should not contain a port: " + domain);229}230}231232/**233* JSON object keys are defined in234* https://w3c.github.io/webdriver/#dfn-table-for-cookie-conversion.235*/236public Map<String, Object> toJson() {237Map<String, Object> toReturn = new TreeMap<>();238239if (getDomain() != null) {240toReturn.put("domain", getDomain());241}242243if (getExpiry() != null) {244toReturn.put("expiry", getExpiry());245}246247if (getName() != null) {248toReturn.put("name", getName());249}250251if (getPath() != null) {252toReturn.put("path", getPath());253}254255if (getValue() != null) {256toReturn.put("value", getValue());257}258259toReturn.put("secure", isSecure());260toReturn.put("httpOnly", isHttpOnly());261262if (getSameSite() != null) {263toReturn.put("sameSite", getSameSite());264}265266return toReturn;267}268269@Override270public String toString() {271SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");272sdf.setTimeZone(TimeZone.getTimeZone("GMT"));273return name274+ "="275+ value276+ (expiry == null ? "" : "; expires=" + sdf.format(expiry))277+ ("".equals(path) ? "" : "; path=" + path)278+ (domain == null ? "" : "; domain=" + domain)279+ (isSecure ? ";secure;" : "")280+ (sameSite == null ? "" : "; sameSite=" + sameSite);281}282283/** Two cookies are equal if the name and value match */284@Override285public boolean equals(@Nullable Object o) {286if (this == o) {287return true;288}289if (!(o instanceof Cookie)) {290return false;291}292293Cookie cookie = (Cookie) o;294295if (!name.equals(cookie.name)) {296return false;297}298return Objects.equals(value, cookie.value);299}300301@Override302public int hashCode() {303return name.hashCode();304}305306public static class Builder {307308private final String name;309private final String value;310private @Nullable String path;311private @Nullable String domain;312private @Nullable Date expiry;313private boolean secure;314private boolean httpOnly;315private @Nullable String sameSite;316317public Builder(String name, String value) {318this.name = name;319this.value = value;320}321322public Builder domain(@Nullable String host) {323this.domain = stripPort(host);324return this;325}326327public Builder path(@Nullable String path) {328this.path = path;329return this;330}331332public Builder expiresOn(@Nullable Date expiry) {333this.expiry = expiry == null ? null : new Date(expiry.getTime());334return this;335}336337public Builder isSecure(boolean secure) {338this.secure = secure;339return this;340}341342public Builder isHttpOnly(boolean httpOnly) {343this.httpOnly = httpOnly;344return this;345}346347public Builder sameSite(@Nullable String sameSite) {348this.sameSite = sameSite;349return this;350}351352public Cookie build() {353return new Cookie(name, value, domain, path, expiry, secure, httpOnly, sameSite);354}355}356}357358359