Skip to content

Commit

Permalink
reworked cookie handling, HttpClientCookie introduced (issue #764)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbri committed Apr 8, 2024
1 parent ea6c6de commit 4cf9821
Show file tree
Hide file tree
Showing 13 changed files with 292 additions and 151 deletions.
12 changes: 10 additions & 2 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,25 @@
<action type="update" dev="rbri">
INCOMPATIBLE CHANGE: Cookie moved from package 'org.htmlunit.util' to 'org.htmlunit.http'.
</action>
<action type="update" dev="rbri">
INCOMPATIBLE CHANGE: All convenience constructores removed from Cookie - the construction should
always be done with all properties.
</action>
<action type="update" dev="rbri">
INCOMPATIBLE CHANGE: DefaultCredentialsProvider moved from package 'org.htmlunit' to 'org.htmlunit.httpclient'.
</action>

<action type="add" dev="rbri" issue="#764">
HttpClientCookie added.
</action>
</release>

<release version="4.1.0" date="April xx, 2024" description="Bugfixes">
<action type="update" dev="rbri">
<action type="update" dev="rbri" issue="#764">
HttpClientConverter.parseUrlQuery(String, Charset) and toQueryFormFields(List<NameValuePair>, Charset) are deprecated.
Please use HttpUtils instead.
</action>
<action type="update" dev="rbri">
<action type="update" dev="rbri" issue="#764">
HttpClientConverter.formatDate(Date) and HttpClientConverter.parseDate(String) are deprecated.
Please use HttpUtils instead.
</action>
Expand Down
129 changes: 28 additions & 101 deletions src/main/java/org/htmlunit/http/Cookie.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@

import java.io.Serializable;
import java.util.Date;
import java.util.Locale;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.impl.cookie.BasicClientCookie;

/**
* A cookie. This class is immutable.
Expand All @@ -32,49 +31,14 @@
*/
public class Cookie implements Serializable {

private final ClientCookie httpClientCookie_;

/**
* Creates a new cookie with the specified name and value which applies to the specified domain.
* The new cookie applies to all paths, never expires and is not secure.
* @param domain the domain to which this cookie applies
* @param name the cookie name
* @param value the cookie name
*/
public Cookie(final String domain, final String name, final String value) {
this(domain, name, value, null, null, false);
}

/**
* Creates a new cookie with the specified name and value which applies to the specified domain,
* the specified path, and expires on the specified date.
* @param domain the domain to which this cookie applies
* @param name the cookie name
* @param value the cookie name
* @param path the path to which this cookie applies
* @param expires the date on which this cookie expires
* @param secure whether or not this cookie is secure (i.e. HTTPS vs HTTP)
*/
public Cookie(final String domain, final String name, final String value, final String path, final Date expires,
final boolean secure) {
this(domain, name, value, path, expires, secure, false, null);
}

/**
* Creates a new cookie with the specified name and value which applies to the specified domain,
* the specified path, and expires on the specified date.
* @param domain the domain to which this cookie applies
* @param name the cookie name
* @param value the cookie name
* @param path the path to which this cookie applies
* @param expires the date on which this cookie expires
* @param secure whether or not this cookie is secure (i.e. HTTPS vs HTTP)
* @param httpOnly whether or not this cookie should be only used for HTTP(S) headers
*/
public Cookie(final String domain, final String name, final String value, final String path, final Date expires,
final boolean secure, final boolean httpOnly) {
this(domain, name, value, path, expires, secure, httpOnly, null);
}
private final String domain_;
private final String name_;
private final String value_;
private final String path_;
private final Date expiryDate_;
private final boolean isSecure_;
private final boolean isHttpOnly_;
private final String samesite_;

/**
* Creates a new cookie with the specified name and value which applies to the specified domain,
Expand All @@ -94,50 +58,21 @@ public Cookie(final String domain, final String name, final String value, final
throw new IllegalArgumentException("Cookie domain must be specified");
}

final BasicClientCookie cookie = new BasicClientCookie(name, value == null ? "" : value);

cookie.setDomain(domain);
// BasicDomainHandler.match(Cookie, CookieOrigin) checks the attib also (see #333)
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, domain);

cookie.setPath(path);
if (expires != null) {
cookie.setExpiryDate(expires);
domain_ = domain.toLowerCase(Locale.ROOT);
name_ = name;
if (value == null) {
value_ = "";
}
cookie.setSecure(secure);
if (httpOnly) {
cookie.setAttribute("httponly", "true");
else {
value_ = value;
}
path_ = path;
expiryDate_ = expires;

if (sameSite != null) {
cookie.setAttribute("samesite", sameSite);
}
isSecure_ = secure;
isHttpOnly_ = httpOnly;

httpClientCookie_ = cookie;
}

/**
* Creates a new HtmlUnit cookie from the HttpClient cookie provided.
* @param clientCookie the HttpClient cookie
*/
public Cookie(final ClientCookie clientCookie) {
httpClientCookie_ = clientCookie;
}

/**
* Creates a new cookie with the specified name and value which applies to the specified domain,
* the specified path, and expires after the specified amount of time.
* @param domain the domain to which this cookie applies
* @param name the cookie name
* @param value the cookie name
* @param path the path to which this cookie applies
* @param maxAge the number of seconds for which this cookie is valid; <code>-1</code> indicates that the
* cookie should never expire; other negative numbers are not allowed
* @param secure whether or not this cookie is secure (i.e. HTTPS vs HTTP)
*/
public Cookie(final String domain, final String name, final String value, final String path, final int maxAge,
final boolean secure) {
this(domain, name, value, path, convertToExpiryDate(maxAge), secure);
samesite_ = sameSite;
}

private static Date convertToExpiryDate(final int maxAge) {
Expand All @@ -157,47 +92,47 @@ private static Date convertToExpiryDate(final int maxAge) {
* @return the cookie name
*/
public String getName() {
return httpClientCookie_.getName();
return name_;
}

/**
* Returns the cookie value.
* @return the cookie value
*/
public String getValue() {
return httpClientCookie_.getValue();
return value_;
}

/**
* Returns the domain to which this cookie applies ({@code null} for all domains).
* @return the domain to which this cookie applies ({@code null} for all domains)
*/
public String getDomain() {
return httpClientCookie_.getDomain();
return domain_;
}

/**
* Returns the path to which this cookie applies ({@code null} for all paths).
* @return the path to which this cookie applies ({@code null} for all paths)
*/
public String getPath() {
return httpClientCookie_.getPath();
return path_;
}

/**
* Returns the date on which this cookie expires ({@code null} if it never expires).
* @return the date on which this cookie expires ({@code null} if it never expires)
*/
public Date getExpires() {
return httpClientCookie_.getExpiryDate();
return expiryDate_;
}

/**
* Returns whether or not this cookie is secure (i.e. HTTPS vs HTTP).
* @return whether or not this cookie is secure (i.e. HTTPS vs HTTP)
*/
public boolean isSecure() {
return httpClientCookie_.isSecure();
return isSecure_;
}

/**
Expand All @@ -206,14 +141,14 @@ public boolean isSecure() {
* @return whether or not this cookie is HttpOnly (i.e. not available in JS).
*/
public boolean isHttpOnly() {
return httpClientCookie_.getAttribute("httponly") != null;
return isHttpOnly_;
}

/**
* @return the SameSite value or {@code null} if not set.
*/
public String getSameSite() {
return httpClientCookie_.getAttribute("samesite");
return samesite_;
}

/**
Expand Down Expand Up @@ -260,12 +195,4 @@ public int hashCode() {
.append(path)
.toHashCode();
}

/**
* Converts this cookie to an HttpClient cookie.
* @return an HttpClient version of this cookie
*/
public org.apache.http.cookie.Cookie toHttpClient() {
return httpClientCookie_;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public HtmlUnitCookieStore(final CookieManager manager) {
*/
@Override
public synchronized void addCookie(final Cookie cookie) {
manager_.addCookie(new org.htmlunit.http.Cookie((ClientCookie) cookie));
manager_.addCookie(new HttpClientCookie((ClientCookie) cookie));
}

/**
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/org/htmlunit/httpclient/HttpClientConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.message.BufferedHeader;
import org.apache.http.util.CharArrayBuffer;
Expand Down Expand Up @@ -265,7 +266,7 @@ public static List<org.htmlunit.http.Cookie> parseCookie(final String cookieStri

final List<org.htmlunit.http.Cookie> htmlUnitCookies = new ArrayList<>(cookies.size());
for (final Cookie cookie : cookies) {
final org.htmlunit.http.Cookie htmlUnitCookie = new org.htmlunit.http.Cookie((ClientCookie) cookie);
final org.htmlunit.http.Cookie htmlUnitCookie = new HttpClientCookie((ClientCookie) cookie);
htmlUnitCookies.add(htmlUnitCookie);
}
return htmlUnitCookies;
Expand All @@ -279,7 +280,7 @@ public static List<org.htmlunit.http.Cookie> parseCookie(final String cookieStri
public static List<Cookie> toHttpClient(final Collection<org.htmlunit.http.Cookie> cookies) {
final ArrayList<Cookie> array = new ArrayList<>(cookies.size());
for (final org.htmlunit.http.Cookie cookie : cookies) {
array.add(cookie.toHttpClient());
array.add(toHttpClient(cookie));
}
return array;
}
Expand All @@ -292,7 +293,7 @@ public static List<Cookie> toHttpClient(final Collection<org.htmlunit.http.Cooki
public static List<org.htmlunit.http.Cookie> fromHttpClient(final List<Cookie> cookies) {
final List<org.htmlunit.http.Cookie> list = new ArrayList<>(cookies.size());
for (final Cookie c : cookies) {
list.add(new org.htmlunit.http.Cookie((ClientCookie) c));
list.add(new HttpClientCookie((ClientCookie) c));
}
return list;
}
Expand All @@ -304,10 +305,34 @@ public static void addMatching(final Set<org.htmlunit.http.Cookie> cookies,
final CookieOrigin cookieOrigin = HttpClientConverter.buildCookieOrigin(normalizedUrl);
final CookieSpec cookieSpec = new HtmlUnitBrowserCompatCookieSpec(browserVersion);
for (final org.htmlunit.http.Cookie cookie : cookies) {
if (cookieSpec.match(cookie.toHttpClient(), cookieOrigin)) {
if (cookieSpec.match(toHttpClient(cookie), cookieOrigin)) {
matches.add(cookie);
}
}
}
}

private static ClientCookie toHttpClient(final org.htmlunit.http.Cookie cookie) {
if (cookie instanceof HttpClientCookie) {
return ((HttpClientCookie) cookie).getHttpClientCookie();
}

final BasicClientCookie httpClientCookie = new BasicClientCookie(cookie.getName(),
cookie.getValue() == null ? "" : cookie.getValue());

httpClientCookie.setDomain(cookie.getDomain());
httpClientCookie.setPath(cookie.getPath());
httpClientCookie.setExpiryDate(cookie.getExpires());

httpClientCookie.setSecure(cookie.isSecure());
if (cookie.isHttpOnly()) {
httpClientCookie.setAttribute("httponly", "true");
}

if (cookie.getSameSite() != null) {
httpClientCookie.setAttribute("samesite", cookie.getSameSite());
}

return httpClientCookie;
}
}
Loading

0 comments on commit 4cf9821

Please sign in to comment.