import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,52 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
/**
*
* @since 4.0
*/
@Immutable
public abstract class AbstractCookieAttributeHandler implements CookieAttributeHandler {
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
// Do nothing
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
// Always match
return true;
}
}

View file

@ -0,0 +1,104 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.util.Args;
/**
* Abstract cookie specification which can delegate the job of parsing,
* validation or matching cookie attributes to a number of arbitrary
* {@link CookieAttributeHandler}s.
*
*
* @since 4.0
*/
@NotThreadSafe // HashMap is not thread-safe
public abstract class AbstractCookieSpec implements CookieSpec {
/**
* Stores attribute name -> attribute handler mappings
*/
private final Map<String, CookieAttributeHandler> attribHandlerMap;
/**
* Default constructor
* */
public AbstractCookieSpec() {
super();
this.attribHandlerMap = new HashMap<String, CookieAttributeHandler>(10);
}
public void registerAttribHandler(
final String name, final CookieAttributeHandler handler) {
Args.notNull(name, "Attribute name");
Args.notNull(handler, "Attribute handler");
this.attribHandlerMap.put(name, handler);
}
/**
* Finds an attribute handler {@link CookieAttributeHandler} for the
* given attribute. Returns <tt>null</tt> if no attribute handler is
* found for the specified attribute.
*
* @param name attribute name. e.g. Domain, Path, etc.
* @return an attribute handler or <tt>null</tt>
*/
protected CookieAttributeHandler findAttribHandler(final String name) {
return this.attribHandlerMap.get(name);
}
/**
* Gets attribute handler {@link CookieAttributeHandler} for the
* given attribute.
*
* @param name attribute name. e.g. Domain, Path, etc.
* @throws IllegalStateException if handler not found for the
* specified attribute.
*/
protected CookieAttributeHandler getAttribHandler(final String name) {
final CookieAttributeHandler handler = findAttribHandler(name);
if (handler == null) {
throw new IllegalStateException("Handler not registered for " +
name + " attribute.");
} else {
return handler;
}
}
protected Collection<CookieAttributeHandler> getAttribHandlers() {
return this.attribHandlerMap.values();
}
}

View file

@ -0,0 +1,361 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
* Default implementation of {@link SetCookie}.
*
* @since 4.0
*/
@NotThreadSafe
public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Serializable {
private static final long serialVersionUID = -3869795591041535538L;
/**
* Default Constructor taking a name and a value. The value may be null.
*
* @param name The name.
* @param value The value.
*/
public BasicClientCookie(final String name, final String value) {
super();
Args.notNull(name, "Name");
this.name = name;
this.attribs = new HashMap<String, String>();
this.value = value;
}
/**
* Returns the name.
*
* @return String name The name
*/
public String getName() {
return this.name;
}
/**
* Returns the value.
*
* @return String value The current value.
*/
public String getValue() {
return this.value;
}
/**
* Sets the value
*
* @param value
*/
public void setValue(final String value) {
this.value = value;
}
/**
* Returns the comment describing the purpose of this cookie, or
* <tt>null</tt> if no such comment has been defined.
*
* @return comment
*
* @see #setComment(String)
*/
public String getComment() {
return cookieComment;
}
/**
* If a user agent (web browser) presents this cookie to a user, the
* cookie's purpose will be described using this comment.
*
* @param comment
*
* @see #getComment()
*/
public void setComment(final String comment) {
cookieComment = comment;
}
/**
* Returns null. Cookies prior to RFC2965 do not set this attribute
*/
public String getCommentURL() {
return null;
}
/**
* Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
* if none exists.
* <p><strong>Note:</strong> the object returned by this method is
* considered immutable. Changing it (e.g. using setTime()) could result
* in undefined behaviour. Do so at your peril. </p>
* @return Expiration {@link Date}, or <tt>null</tt>.
*
* @see #setExpiryDate(java.util.Date)
*
*/
public Date getExpiryDate() {
return cookieExpiryDate;
}
/**
* Sets expiration date.
* <p><strong>Note:</strong> the object returned by this method is considered
* immutable. Changing it (e.g. using setTime()) could result in undefined
* behaviour. Do so at your peril.</p>
*
* @param expiryDate the {@link Date} after which this cookie is no longer valid.
*
* @see #getExpiryDate
*
*/
public void setExpiryDate (final Date expiryDate) {
cookieExpiryDate = expiryDate;
}
/**
* Returns <tt>false</tt> if the cookie should be discarded at the end
* of the "session"; <tt>true</tt> otherwise.
*
* @return <tt>false</tt> if the cookie should be discarded at the end
* of the "session"; <tt>true</tt> otherwise
*/
public boolean isPersistent() {
return (null != cookieExpiryDate);
}
/**
* Returns domain attribute of the cookie.
*
* @return the value of the domain attribute
*
* @see #setDomain(java.lang.String)
*/
public String getDomain() {
return cookieDomain;
}
/**
* Sets the domain attribute.
*
* @param domain The value of the domain attribute
*
* @see #getDomain
*/
public void setDomain(final String domain) {
if (domain != null) {
cookieDomain = domain.toLowerCase(Locale.ENGLISH);
} else {
cookieDomain = null;
}
}
/**
* Returns the path attribute of the cookie
*
* @return The value of the path attribute.
*
* @see #setPath(java.lang.String)
*/
public String getPath() {
return cookiePath;
}
/**
* Sets the path attribute.
*
* @param path The value of the path attribute
*
* @see #getPath
*
*/
public void setPath(final String path) {
cookiePath = path;
}
/**
* @return <code>true</code> if this cookie should only be sent over secure connections.
* @see #setSecure(boolean)
*/
public boolean isSecure() {
return isSecure;
}
/**
* Sets the secure attribute of the cookie.
* <p>
* When <tt>true</tt> the cookie should only be sent
* using a secure protocol (https). This should only be set when
* the cookie's originating server used a secure protocol to set the
* cookie's value.
*
* @param secure The value of the secure attribute
*
* @see #isSecure()
*/
public void setSecure (final boolean secure) {
isSecure = secure;
}
/**
* Returns null. Cookies prior to RFC2965 do not set this attribute
*/
public int[] getPorts() {
return null;
}
/**
* Returns the version of the cookie specification to which this
* cookie conforms.
*
* @return the version of the cookie.
*
* @see #setVersion(int)
*
*/
public int getVersion() {
return cookieVersion;
}
/**
* Sets the version of the cookie specification to which this
* cookie conforms.
*
* @param version the version of the cookie.
*
* @see #getVersion
*/
public void setVersion(final int version) {
cookieVersion = version;
}
/**
* Returns true if this cookie has expired.
* @param date Current time
*
* @return <tt>true</tt> if the cookie has expired.
*/
public boolean isExpired(final Date date) {
Args.notNull(date, "Date");
return (cookieExpiryDate != null
&& cookieExpiryDate.getTime() <= date.getTime());
}
public void setAttribute(final String name, final String value) {
this.attribs.put(name, value);
}
public String getAttribute(final String name) {
return this.attribs.get(name);
}
public boolean containsAttribute(final String name) {
return this.attribs.get(name) != null;
}
@Override
public Object clone() throws CloneNotSupportedException {
final BasicClientCookie clone = (BasicClientCookie) super.clone();
clone.attribs = new HashMap<String, String>(this.attribs);
return clone;
}
@Override
public String toString() {
final StringBuilder buffer = new StringBuilder();
buffer.append("[version: ");
buffer.append(Integer.toString(this.cookieVersion));
buffer.append("]");
buffer.append("[name: ");
buffer.append(this.name);
buffer.append("]");
buffer.append("[value: ");
buffer.append(this.value);
buffer.append("]");
buffer.append("[domain: ");
buffer.append(this.cookieDomain);
buffer.append("]");
buffer.append("[path: ");
buffer.append(this.cookiePath);
buffer.append("]");
buffer.append("[expiry: ");
buffer.append(this.cookieExpiryDate);
buffer.append("]");
return buffer.toString();
}
// ----------------------------------------------------- Instance Variables
/** Cookie name */
private final String name;
/** Cookie attributes as specified by the origin server */
private Map<String, String> attribs;
/** Cookie value */
private String value;
/** Comment attribute. */
private String cookieComment;
/** Domain attribute. */
private String cookieDomain;
/** Expiration {@link Date}. */
private Date cookieExpiryDate;
/** Path attribute. */
private String cookiePath;
/** My secure flag. */
private boolean isSecure;
/** The version of the cookie specification I was created from. */
private int cookieVersion;
}

View file

@ -0,0 +1,101 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Date;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.SetCookie2;
/**
* Default implementation of {@link SetCookie2}.
*
* @since 4.0
*/
@NotThreadSafe
public class BasicClientCookie2 extends BasicClientCookie implements SetCookie2 {
private static final long serialVersionUID = -7744598295706617057L;
private String commentURL;
private int[] ports;
private boolean discard;
/**
* Default Constructor taking a name and a value. The value may be null.
*
* @param name The name.
* @param value The value.
*/
public BasicClientCookie2(final String name, final String value) {
super(name, value);
}
@Override
public int[] getPorts() {
return this.ports;
}
public void setPorts(final int[] ports) {
this.ports = ports;
}
@Override
public String getCommentURL() {
return this.commentURL;
}
public void setCommentURL(final String commentURL) {
this.commentURL = commentURL;
}
public void setDiscard(final boolean discard) {
this.discard = discard;
}
@Override
public boolean isPersistent() {
return !this.discard && super.isPersistent();
}
@Override
public boolean isExpired(final Date date) {
return this.discard || super.isExpired(date);
}
@Override
public Object clone() throws CloneNotSupportedException {
final BasicClientCookie2 clone = (BasicClientCookie2) super.clone();
if (this.ports != null) {
clone.ports = this.ports.clone();
}
return clone;
}
}

View file

@ -0,0 +1,51 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class BasicCommentHandler extends AbstractCookieAttributeHandler {
public BasicCommentHandler() {
super();
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
cookie.setComment(value);
}
}

View file

@ -0,0 +1,116 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class BasicDomainHandler implements CookieAttributeHandler {
public BasicDomainHandler() {
super();
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for domain attribute");
}
if (value.trim().length() == 0) {
throw new MalformedCookieException("Blank value for domain attribute");
}
cookie.setDomain(value);
}
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
// Validate the cookies domain attribute. NOTE: Domains without
// any dots are allowed to support hosts on private LANs that don't
// have DNS names. Since they have no dots, to domain-match the
// request-host and domain must be identical for the cookie to sent
// back to the origin-server.
final String host = origin.getHost();
String domain = cookie.getDomain();
if (domain == null) {
throw new CookieRestrictionViolationException("Cookie domain may not be null");
}
if (host.contains(".")) {
// Not required to have at least two dots. RFC 2965.
// A Set-Cookie2 with Domain=ajax.com will be accepted.
// domain must match host
if (!host.endsWith(domain)) {
if (domain.startsWith(".")) {
domain = domain.substring(1, domain.length());
}
if (!host.equals(domain)) {
throw new CookieRestrictionViolationException(
"Illegal domain attribute \"" + domain
+ "\". Domain of origin: \"" + host + "\"");
}
}
} else {
if (!host.equals(domain)) {
throw new CookieRestrictionViolationException(
"Illegal domain attribute \"" + domain
+ "\". Domain of origin: \"" + host + "\"");
}
}
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String host = origin.getHost();
String domain = cookie.getDomain();
if (domain == null) {
return false;
}
if (host.equals(domain)) {
return true;
}
if (!domain.startsWith(".")) {
domain = '.' + domain;
}
return host.endsWith(domain) || host.equals(domain.substring(1));
}
}

View file

@ -0,0 +1,66 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Date;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.client.utils.DateUtils;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class BasicExpiresHandler extends AbstractCookieAttributeHandler {
/** Valid date patterns */
private final String[] datepatterns;
public BasicExpiresHandler(final String[] datepatterns) {
Args.notNull(datepatterns, "Array of date patterns");
this.datepatterns = datepatterns;
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for expires attribute");
}
final Date expiry = DateUtils.parseDate(value, this.datepatterns);
if (expiry == null) {
throw new MalformedCookieException("Unable to parse expires attribute: "
+ value);
}
cookie.setExpiryDate(expiry);
}
}

View file

@ -0,0 +1,67 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Date;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler {
public BasicMaxAgeHandler() {
super();
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for max-age attribute");
}
final int age;
try {
age = Integer.parseInt(value);
} catch (final NumberFormatException e) {
throw new MalformedCookieException ("Invalid max-age attribute: "
+ value);
}
if (age < 0) {
throw new MalformedCookieException ("Negative max-age attribute: "
+ value);
}
cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));
}
}

View file

@ -0,0 +1,87 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.TextUtils;
/**
*
* @since 4.0
*/
@Immutable
public class BasicPathHandler implements CookieAttributeHandler {
public BasicPathHandler() {
super();
}
public void parse(
final SetCookie cookie, final String value) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
cookie.setPath(!TextUtils.isBlank(value) ? value : "/");
}
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
if (!match(cookie, origin)) {
throw new CookieRestrictionViolationException(
"Illegal path attribute \"" + cookie.getPath()
+ "\". Path of origin: \"" + origin.getPath() + "\"");
}
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String targetpath = origin.getPath();
String topmostPath = cookie.getPath();
if (topmostPath == null) {
topmostPath = "/";
}
if (topmostPath.length() > 1 && topmostPath.endsWith("/")) {
topmostPath = topmostPath.substring(0, topmostPath.length() - 1);
}
boolean match = targetpath.startsWith (topmostPath);
// if there is a match and these values are not exactly the same we have
// to make sure we're not matcing "/foobar" and "/foo"
if (match && targetpath.length() != topmostPath.length()) {
if (!topmostPath.endsWith("/")) {
match = (targetpath.charAt(topmostPath.length()) == '/');
}
}
return match;
}
}

View file

@ -0,0 +1,60 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class BasicSecureHandler extends AbstractCookieAttributeHandler {
public BasicSecureHandler() {
super();
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
cookie.setSecure(true);
}
@Override
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
return !cookie.isSecure() || origin.isSecure();
}
}

View file

@ -0,0 +1,207 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.List;
import ch.boye.httpclientandroidlib.FormattedHeader;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SM;
import ch.boye.httpclientandroidlib.cookie.SetCookie2;
import ch.boye.httpclientandroidlib.message.ParserCursor;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
/**
* 'Meta' cookie specification that picks up a cookie policy based on
* the format of cookies sent with the HTTP response.
*
* @since 4.0
*/
@NotThreadSafe // CookieSpec fields are @NotThreadSafe
public class BestMatchSpec implements CookieSpec {
private final String[] datepatterns;
private final boolean oneHeader;
// Cached values of CookieSpec instances
private RFC2965Spec strict; // @NotThreadSafe
private RFC2109Spec obsoleteStrict; // @NotThreadSafe
private BrowserCompatSpec compat; // @NotThreadSafe
public BestMatchSpec(final String[] datepatterns, final boolean oneHeader) {
super();
this.datepatterns = datepatterns == null ? null : datepatterns.clone();
this.oneHeader = oneHeader;
}
public BestMatchSpec() {
this(null, false);
}
private RFC2965Spec getStrict() {
if (this.strict == null) {
this.strict = new RFC2965Spec(this.datepatterns, this.oneHeader);
}
return strict;
}
private RFC2109Spec getObsoleteStrict() {
if (this.obsoleteStrict == null) {
this.obsoleteStrict = new RFC2109Spec(this.datepatterns, this.oneHeader);
}
return obsoleteStrict;
}
private BrowserCompatSpec getCompat() {
if (this.compat == null) {
this.compat = new BrowserCompatSpec(this.datepatterns);
}
return compat;
}
public List<Cookie> parse(
final Header header,
final CookieOrigin origin) throws MalformedCookieException {
Args.notNull(header, "Header");
Args.notNull(origin, "Cookie origin");
HeaderElement[] helems = header.getElements();
boolean versioned = false;
boolean netscape = false;
for (final HeaderElement helem: helems) {
if (helem.getParameterByName("version") != null) {
versioned = true;
}
if (helem.getParameterByName("expires") != null) {
netscape = true;
}
}
if (netscape || !versioned) {
// Need to parse the header again, because Netscape style cookies do not correctly
// support multiple header elements (comma cannot be treated as an element separator)
final NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
final CharArrayBuffer buffer;
final ParserCursor cursor;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
cursor = new ParserCursor(
((FormattedHeader) header).getValuePos(),
buffer.length());
} else {
final String s = header.getValue();
if (s == null) {
throw new MalformedCookieException("Header value is null");
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
cursor = new ParserCursor(0, buffer.length());
}
helems = new HeaderElement[] { parser.parseHeader(buffer, cursor) };
return getCompat().parse(helems, origin);
} else {
if (SM.SET_COOKIE2.equals(header.getName())) {
return getStrict().parse(helems, origin);
} else {
return getObsoleteStrict().parse(helems, origin);
}
}
}
public void validate(
final Cookie cookie,
final CookieOrigin origin) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
if (cookie.getVersion() > 0) {
if (cookie instanceof SetCookie2) {
getStrict().validate(cookie, origin);
} else {
getObsoleteStrict().validate(cookie, origin);
}
} else {
getCompat().validate(cookie, origin);
}
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
if (cookie.getVersion() > 0) {
if (cookie instanceof SetCookie2) {
return getStrict().match(cookie, origin);
} else {
return getObsoleteStrict().match(cookie, origin);
}
} else {
return getCompat().match(cookie, origin);
}
}
public List<Header> formatCookies(final List<Cookie> cookies) {
Args.notNull(cookies, "List of cookies");
int version = Integer.MAX_VALUE;
boolean isSetCookie2 = true;
for (final Cookie cookie: cookies) {
if (!(cookie instanceof SetCookie2)) {
isSetCookie2 = false;
}
if (cookie.getVersion() < version) {
version = cookie.getVersion();
}
}
if (version > 0) {
if (isSetCookie2) {
return getStrict().formatCookies(cookies);
} else {
return getObsoleteStrict().formatCookies(cookies);
}
} else {
return getCompat().formatCookies(cookies);
}
}
public int getVersion() {
return getStrict().getVersion();
}
public Header getVersionHeader() {
return getStrict().getVersionHeader();
}
@Override
public String toString() {
return "best-match";
}
}

View file

@ -0,0 +1,86 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.CookieSpecFactory;
import ch.boye.httpclientandroidlib.cookie.CookieSpecProvider;
import ch.boye.httpclientandroidlib.cookie.params.CookieSpecPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* {@link CookieSpecProvider} implementation that creates and initializes
* {@link BestMatchSpec} instances.
*
* @since 4.0
*/
@Immutable
@SuppressWarnings("deprecation")
public class BestMatchSpecFactory implements CookieSpecFactory, CookieSpecProvider {
private final String[] datepatterns;
private final boolean oneHeader;
public BestMatchSpecFactory(final String[] datepatterns, final boolean oneHeader) {
super();
this.datepatterns = datepatterns;
this.oneHeader = oneHeader;
}
public BestMatchSpecFactory() {
this(null, false);
}
public CookieSpec newInstance(final HttpParams params) {
if (params != null) {
String[] patterns = null;
final Collection<?> param = (Collection<?>) params.getParameter(
CookieSpecPNames.DATE_PATTERNS);
if (param != null) {
patterns = new String[param.size()];
patterns = param.toArray(patterns);
}
final boolean singleHeader = params.getBooleanParameter(
CookieSpecPNames.SINGLE_COOKIE_HEADER, false);
return new BestMatchSpec(patterns, singleHeader);
} else {
return new BestMatchSpec();
}
}
public CookieSpec create(final HttpContext context) {
return new BestMatchSpec(this.datepatterns, this.oneHeader);
}
}

View file

@ -0,0 +1,219 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.ArrayList;
import java.util.List;
import ch.boye.httpclientandroidlib.FormattedHeader;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.client.utils.DateUtils;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SM;
import ch.boye.httpclientandroidlib.message.BasicHeaderElement;
import ch.boye.httpclientandroidlib.message.BasicHeaderValueFormatter;
import ch.boye.httpclientandroidlib.message.BufferedHeader;
import ch.boye.httpclientandroidlib.message.ParserCursor;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
/**
* Cookie specification that strives to closely mimic (mis)behavior of
* common web browser applications such as Microsoft Internet Explorer
* and Mozilla FireFox.
*
*
* @since 4.0
*/
@NotThreadSafe // superclass is @NotThreadSafe
public class BrowserCompatSpec extends CookieSpecBase {
private static final String[] DEFAULT_DATE_PATTERNS = new String[] {
DateUtils.PATTERN_RFC1123,
DateUtils.PATTERN_RFC1036,
DateUtils.PATTERN_ASCTIME,
"EEE, dd-MMM-yyyy HH:mm:ss z",
"EEE, dd-MMM-yyyy HH-mm-ss z",
"EEE, dd MMM yy HH:mm:ss z",
"EEE dd-MMM-yyyy HH:mm:ss z",
"EEE dd MMM yyyy HH:mm:ss z",
"EEE dd-MMM-yyyy HH-mm-ss z",
"EEE dd-MMM-yy HH:mm:ss z",
"EEE dd MMM yy HH:mm:ss z",
"EEE,dd-MMM-yy HH:mm:ss z",
"EEE,dd-MMM-yyyy HH:mm:ss z",
"EEE, dd-MM-yyyy HH:mm:ss z",
};
private final String[] datepatterns;
/** Default constructor */
public BrowserCompatSpec(final String[] datepatterns, final BrowserCompatSpecFactory.SecurityLevel securityLevel) {
super();
if (datepatterns != null) {
this.datepatterns = datepatterns.clone();
} else {
this.datepatterns = DEFAULT_DATE_PATTERNS;
}
switch (securityLevel) {
case SECURITYLEVEL_DEFAULT:
registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
break;
case SECURITYLEVEL_IE_MEDIUM:
registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler() {
@Override
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
// No validation
}
}
);
break;
default:
throw new RuntimeException("Unknown security level");
}
registerAttribHandler(ClientCookie.DOMAIN_ATTR, new BasicDomainHandler());
registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
this.datepatterns));
registerAttribHandler(ClientCookie.VERSION_ATTR, new BrowserCompatVersionAttributeHandler());
}
/** Default constructor */
public BrowserCompatSpec(final String[] datepatterns) {
this(datepatterns, BrowserCompatSpecFactory.SecurityLevel.SECURITYLEVEL_DEFAULT);
}
/** Default constructor */
public BrowserCompatSpec() {
this(null, BrowserCompatSpecFactory.SecurityLevel.SECURITYLEVEL_DEFAULT);
}
public List<Cookie> parse(final Header header, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(header, "Header");
Args.notNull(origin, "Cookie origin");
final String headername = header.getName();
if (!headername.equalsIgnoreCase(SM.SET_COOKIE)) {
throw new MalformedCookieException("Unrecognized cookie header '"
+ header.toString() + "'");
}
HeaderElement[] helems = header.getElements();
boolean versioned = false;
boolean netscape = false;
for (final HeaderElement helem: helems) {
if (helem.getParameterByName("version") != null) {
versioned = true;
}
if (helem.getParameterByName("expires") != null) {
netscape = true;
}
}
if (netscape || !versioned) {
// Need to parse the header again, because Netscape style cookies do not correctly
// support multiple header elements (comma cannot be treated as an element separator)
final NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
final CharArrayBuffer buffer;
final ParserCursor cursor;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
cursor = new ParserCursor(
((FormattedHeader) header).getValuePos(),
buffer.length());
} else {
final String s = header.getValue();
if (s == null) {
throw new MalformedCookieException("Header value is null");
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
cursor = new ParserCursor(0, buffer.length());
}
helems = new HeaderElement[] { parser.parseHeader(buffer, cursor) };
}
return parse(helems, origin);
}
private static boolean isQuoteEnclosed(final String s) {
return s != null && s.startsWith("\"") && s.endsWith("\"");
}
public List<Header> formatCookies(final List<Cookie> cookies) {
Args.notEmpty(cookies, "List of cookies");
final CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
buffer.append(SM.COOKIE);
buffer.append(": ");
for (int i = 0; i < cookies.size(); i++) {
final Cookie cookie = cookies.get(i);
if (i > 0) {
buffer.append("; ");
}
final String cookieName = cookie.getName();
final String cookieValue = cookie.getValue();
if (cookie.getVersion() > 0 && !isQuoteEnclosed(cookieValue)) {
BasicHeaderValueFormatter.INSTANCE.formatHeaderElement(
buffer,
new BasicHeaderElement(cookieName, cookieValue),
false);
} else {
// Netscape style cookies do not support quoted values
buffer.append(cookieName);
buffer.append("=");
if (cookieValue != null) {
buffer.append(cookieValue);
}
}
}
final List<Header> headers = new ArrayList<Header>(1);
headers.add(new BufferedHeader(buffer));
return headers;
}
public int getVersion() {
return 0;
}
public Header getVersionHeader() {
return null;
}
@Override
public String toString() {
return "compatibility";
}
}

View file

@ -0,0 +1,92 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.CookieSpecFactory;
import ch.boye.httpclientandroidlib.cookie.CookieSpecProvider;
import ch.boye.httpclientandroidlib.cookie.params.CookieSpecPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* {@link CookieSpecProvider} implementation that creates and initializes
* {@link BrowserCompatSpec} instances.
*
* @since 4.0
*/
@Immutable
@SuppressWarnings("deprecation")
public class BrowserCompatSpecFactory implements CookieSpecFactory, CookieSpecProvider {
public enum SecurityLevel {
SECURITYLEVEL_DEFAULT,
SECURITYLEVEL_IE_MEDIUM
}
private final String[] datepatterns;
private final SecurityLevel securityLevel;
public BrowserCompatSpecFactory(final String[] datepatterns, final SecurityLevel securityLevel) {
super();
this.datepatterns = datepatterns;
this.securityLevel = securityLevel;
}
public BrowserCompatSpecFactory(final String[] datepatterns) {
this(null, SecurityLevel.SECURITYLEVEL_DEFAULT);
}
public BrowserCompatSpecFactory() {
this(null, SecurityLevel.SECURITYLEVEL_DEFAULT);
}
public CookieSpec newInstance(final HttpParams params) {
if (params != null) {
String[] patterns = null;
final Collection<?> param = (Collection<?>) params.getParameter(
CookieSpecPNames.DATE_PATTERNS);
if (param != null) {
patterns = new String[param.size()];
patterns = param.toArray(patterns);
}
return new BrowserCompatSpec(patterns, securityLevel);
} else {
return new BrowserCompatSpec(null, securityLevel);
}
}
public CookieSpec create(final HttpContext context) {
return new BrowserCompatSpec(this.datepatterns);
}
}

View file

@ -0,0 +1,66 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
* <tt>"Version"</tt> cookie attribute handler for BrowserCompat cookie spec.
*
* @since 4.3
*/
@Immutable
public class BrowserCompatVersionAttributeHandler extends
AbstractCookieAttributeHandler {
public BrowserCompatVersionAttributeHandler() {
super();
}
/**
* Parse cookie version attribute.
*/
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for version attribute");
}
int version = 0;
try {
version = Integer.parseInt(value);
} catch (final NumberFormatException e) {
// Just ignore invalid versions
}
cookie.setVersion(version);
}
}

View file

@ -0,0 +1,121 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.NameValuePair;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.util.Args;
/**
* Cookie management functions shared by all specification.
*
*
* @since 4.0
*/
@NotThreadSafe // AbstractCookieSpec is not thread-safe
public abstract class CookieSpecBase extends AbstractCookieSpec {
protected static String getDefaultPath(final CookieOrigin origin) {
String defaultPath = origin.getPath();
int lastSlashIndex = defaultPath.lastIndexOf('/');
if (lastSlashIndex >= 0) {
if (lastSlashIndex == 0) {
//Do not remove the very first slash
lastSlashIndex = 1;
}
defaultPath = defaultPath.substring(0, lastSlashIndex);
}
return defaultPath;
}
protected static String getDefaultDomain(final CookieOrigin origin) {
return origin.getHost();
}
protected List<Cookie> parse(final HeaderElement[] elems, final CookieOrigin origin)
throws MalformedCookieException {
final List<Cookie> cookies = new ArrayList<Cookie>(elems.length);
for (final HeaderElement headerelement : elems) {
final String name = headerelement.getName();
final String value = headerelement.getValue();
if (name == null || name.length() == 0) {
throw new MalformedCookieException("Cookie name may not be empty");
}
final BasicClientCookie cookie = new BasicClientCookie(name, value);
cookie.setPath(getDefaultPath(origin));
cookie.setDomain(getDefaultDomain(origin));
// cycle through the parameters
final NameValuePair[] attribs = headerelement.getParameters();
for (int j = attribs.length - 1; j >= 0; j--) {
final NameValuePair attrib = attribs[j];
final String s = attrib.getName().toLowerCase(Locale.ENGLISH);
cookie.setAttribute(s, attrib.getValue());
final CookieAttributeHandler handler = findAttribHandler(s);
if (handler != null) {
handler.parse(cookie, attrib.getValue());
}
}
cookies.add(cookie);
}
return cookies;
}
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
for (final CookieAttributeHandler handler: getAttribHandlers()) {
handler.validate(cookie, origin);
}
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
for (final CookieAttributeHandler handler: getAttribHandlers()) {
if (!handler.match(cookie, origin)) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,62 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
/**
* An exception to indicate an error parsing a date string.
*
* @see DateUtils
*
*
* @since 4.0
*
* @deprecated (4.3) no longer used.
*/
@Deprecated
@Immutable
public class DateParseException extends Exception {
private static final long serialVersionUID = 4417696455000643370L;
/**
*
*/
public DateParseException() {
super();
}
/**
* @param message the exception message
*/
public DateParseException(final String message) {
super(message);
}
}

View file

@ -0,0 +1,156 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Date;
import java.util.TimeZone;
import ch.boye.httpclientandroidlib.annotation.Immutable;
/**
* A utility class for parsing and formatting HTTP dates as used in cookies and
* other headers. This class handles dates as defined by RFC 2616 section
* 3.3.1 as well as some other common non-standard formats.
*
*
* @since 4.0
*
* @deprecated (4.3) Use {@link ch.boye.httpclientandroidlib.client.utils.DateUtils}.
*/
@Deprecated
@Immutable
public final class DateUtils {
/**
* Date format pattern used to parse HTTP date headers in RFC 1123 format.
*/
public static final String PATTERN_RFC1123 = ch.boye.httpclientandroidlib.client.utils.DateUtils.PATTERN_RFC1123;
/**
* Date format pattern used to parse HTTP date headers in RFC 1036 format.
*/
public static final String PATTERN_RFC1036 = ch.boye.httpclientandroidlib.client.utils.DateUtils.PATTERN_RFC1036;
/**
* Date format pattern used to parse HTTP date headers in ANSI C
* <code>asctime()</code> format.
*/
public static final String PATTERN_ASCTIME = ch.boye.httpclientandroidlib.client.utils.DateUtils.PATTERN_ASCTIME;
public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
/**
* Parses a date value. The formats used for parsing the date value are retrieved from
* the default http params.
*
* @param dateValue the date value to parse
*
* @return the parsed date
*
* @throws DateParseException if the value could not be parsed using any of the
* supported date formats
*/
public static Date parseDate(final String dateValue) throws DateParseException {
return parseDate(dateValue, null, null);
}
/**
* Parses the date value using the given date formats.
*
* @param dateValue the date value to parse
* @param dateFormats the date formats to use
*
* @return the parsed date
*
* @throws DateParseException if none of the dataFormats could parse the dateValue
*/
public static Date parseDate(final String dateValue, final String[] dateFormats)
throws DateParseException {
return parseDate(dateValue, dateFormats, null);
}
/**
* Parses the date value using the given date formats.
*
* @param dateValue the date value to parse
* @param dateFormats the date formats to use
* @param startDate During parsing, two digit years will be placed in the range
* <code>startDate</code> to <code>startDate + 100 years</code>. This value may
* be <code>null</code>. When <code>null</code> is given as a parameter, year
* <code>2000</code> will be used.
*
* @return the parsed date
*
* @throws DateParseException if none of the dataFormats could parse the dateValue
*/
public static Date parseDate(
final String dateValue,
final String[] dateFormats,
final Date startDate
) throws DateParseException {
final Date d = ch.boye.httpclientandroidlib.client.utils.DateUtils.parseDate(dateValue, dateFormats, startDate);
if (d == null) {
throw new DateParseException("Unable to parse the date " + dateValue);
}
return d;
}
/**
* Formats the given date according to the RFC 1123 pattern.
*
* @param date The date to format.
* @return An RFC 1123 formatted date string.
*
* @see #PATTERN_RFC1123
*/
public static String formatDate(final Date date) {
return ch.boye.httpclientandroidlib.client.utils.DateUtils.formatDate(date);
}
/**
* Formats the given date according to the specified pattern. The pattern
* must conform to that used by the {@link java.text.SimpleDateFormat simple
* date format} class.
*
* @param date The date to format.
* @param pattern The pattern to use for formatting the date.
* @return A formatted date string.
*
* @throws IllegalArgumentException If the given date pattern is invalid.
*
* @see java.text.SimpleDateFormat
*/
public static String formatDate(final Date date, final String pattern) {
return ch.boye.httpclientandroidlib.client.utils.DateUtils.formatDate(date, pattern);
}
/** This class should not be instantiated. */
private DateUtils() {
}
}

View file

@ -0,0 +1,63 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collections;
import java.util.List;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
/**
* CookieSpec that ignores all cookies
*
* @since 4.1
*/
@NotThreadSafe // superclass is @NotThreadSafe
public class IgnoreSpec extends CookieSpecBase {
public int getVersion() {
return 0;
}
public List<Cookie> parse(final Header header, final CookieOrigin origin)
throws MalformedCookieException {
return Collections.emptyList();
}
public List<Header> formatCookies(final List<Cookie> cookies) {
return Collections.emptyList();
}
public Header getVersionHeader() {
return null;
}
}

View file

@ -0,0 +1,58 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.CookieSpecFactory;
import ch.boye.httpclientandroidlib.cookie.CookieSpecProvider;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* {@link CookieSpecProvider} implementation that ignores all cookies.
*
* @since 4.1
*/
@Immutable
@SuppressWarnings("deprecation")
public class IgnoreSpecFactory implements CookieSpecFactory, CookieSpecProvider {
public IgnoreSpecFactory() {
super();
}
public CookieSpec newInstance(final HttpParams params) {
return new IgnoreSpec();
}
public CookieSpec create(final HttpContext context) {
return new IgnoreSpec();
}
}

View file

@ -0,0 +1,106 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Locale;
import java.util.StringTokenizer;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class NetscapeDomainHandler extends BasicDomainHandler {
public NetscapeDomainHandler() {
super();
}
@Override
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
super.validate(cookie, origin);
// Perform Netscape Cookie draft specific validation
final String host = origin.getHost();
final String domain = cookie.getDomain();
if (host.contains(".")) {
final int domainParts = new StringTokenizer(domain, ".").countTokens();
if (isSpecialDomain(domain)) {
if (domainParts < 2) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ domain
+ "\" violates the Netscape cookie specification for "
+ "special domains");
}
} else {
if (domainParts < 3) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ domain
+ "\" violates the Netscape cookie specification");
}
}
}
}
/**
* Checks if the given domain is in one of the seven special
* top level domains defined by the Netscape cookie specification.
* @param domain The domain.
* @return True if the specified domain is "special"
*/
private static boolean isSpecialDomain(final String domain) {
final String ucDomain = domain.toUpperCase(Locale.ENGLISH);
return ucDomain.endsWith(".COM")
|| ucDomain.endsWith(".EDU")
|| ucDomain.endsWith(".NET")
|| ucDomain.endsWith(".GOV")
|| ucDomain.endsWith(".MIL")
|| ucDomain.endsWith(".ORG")
|| ucDomain.endsWith(".INT");
}
@Override
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String host = origin.getHost();
final String domain = cookie.getDomain();
if (domain == null) {
return false;
}
return host.endsWith(domain);
}
}

View file

@ -0,0 +1,138 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.ArrayList;
import java.util.List;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.NameValuePair;
import ch.boye.httpclientandroidlib.ParseException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.message.BasicHeaderElement;
import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
import ch.boye.httpclientandroidlib.message.ParserCursor;
import ch.boye.httpclientandroidlib.protocol.HTTP;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
/**
*
* @since 4.0
*/
@Immutable
public class NetscapeDraftHeaderParser {
public final static NetscapeDraftHeaderParser DEFAULT = new NetscapeDraftHeaderParser();
public NetscapeDraftHeaderParser() {
super();
}
public HeaderElement parseHeader(
final CharArrayBuffer buffer,
final ParserCursor cursor) throws ParseException {
Args.notNull(buffer, "Char array buffer");
Args.notNull(cursor, "Parser cursor");
final NameValuePair nvp = parseNameValuePair(buffer, cursor);
final List<NameValuePair> params = new ArrayList<NameValuePair>();
while (!cursor.atEnd()) {
final NameValuePair param = parseNameValuePair(buffer, cursor);
params.add(param);
}
return new BasicHeaderElement(
nvp.getName(),
nvp.getValue(), params.toArray(new NameValuePair[params.size()]));
}
private NameValuePair parseNameValuePair(
final CharArrayBuffer buffer, final ParserCursor cursor) {
boolean terminated = false;
int pos = cursor.getPos();
final int indexFrom = cursor.getPos();
final int indexTo = cursor.getUpperBound();
// Find name
String name = null;
while (pos < indexTo) {
final char ch = buffer.charAt(pos);
if (ch == '=') {
break;
}
if (ch == ';') {
terminated = true;
break;
}
pos++;
}
if (pos == indexTo) {
terminated = true;
name = buffer.substringTrimmed(indexFrom, indexTo);
} else {
name = buffer.substringTrimmed(indexFrom, pos);
pos++;
}
if (terminated) {
cursor.updatePos(pos);
return new BasicNameValuePair(name, null);
}
// Find value
String value = null;
int i1 = pos;
while (pos < indexTo) {
final char ch = buffer.charAt(pos);
if (ch == ';') {
terminated = true;
break;
}
pos++;
}
int i2 = pos;
// Trim leading white spaces
while (i1 < i2 && (HTTP.isWhitespace(buffer.charAt(i1)))) {
i1++;
}
// Trim trailing white spaces
while ((i2 > i1) && (HTTP.isWhitespace(buffer.charAt(i2 - 1)))) {
i2--;
}
value = buffer.substring(i1, i2);
if (terminated) {
pos++;
}
cursor.updatePos(pos);
return new BasicNameValuePair(name, value);
}
}

View file

@ -0,0 +1,171 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.ArrayList;
import java.util.List;
import ch.boye.httpclientandroidlib.FormattedHeader;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SM;
import ch.boye.httpclientandroidlib.message.BufferedHeader;
import ch.boye.httpclientandroidlib.message.ParserCursor;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
/**
* This {@link ch.boye.httpclientandroidlib.cookie.CookieSpec} implementation conforms to
* the original draft specification published by Netscape Communications.
* It should be avoided unless absolutely necessary for compatibility with
* legacy applications.
*
* @since 4.0
*/
@NotThreadSafe // superclass is @NotThreadSafe
public class NetscapeDraftSpec extends CookieSpecBase {
protected static final String EXPIRES_PATTERN = "EEE, dd-MMM-yy HH:mm:ss z";
private final String[] datepatterns;
/** Default constructor */
public NetscapeDraftSpec(final String[] datepatterns) {
super();
if (datepatterns != null) {
this.datepatterns = datepatterns.clone();
} else {
this.datepatterns = new String[] { EXPIRES_PATTERN };
}
registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
registerAttribHandler(ClientCookie.DOMAIN_ATTR, new NetscapeDomainHandler());
registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
this.datepatterns));
}
/** Default constructor */
public NetscapeDraftSpec() {
this(null);
}
/**
* Parses the Set-Cookie value into an array of <tt>Cookie</tt>s.
*
* <p>Syntax of the Set-Cookie HTTP Response Header:</p>
*
* <p>This is the format a CGI script would use to add to
* the HTTP headers a new piece of data which is to be stored by
* the client for later retrieval.</p>
*
* <PRE>
* Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
* </PRE>
*
* <p>Please note that the Netscape draft specification does not fully conform to the HTTP
* header format. Comma character if present in <code>Set-Cookie</code> will not be treated
* as a header element separator</p>
*
* @see <a href="http://web.archive.org/web/20020803110822/http://wp.netscape.com/newsref/std/cookie_spec.html">
* The Cookie Spec.</a>
*
* @param header the <tt>Set-Cookie</tt> received from the server
* @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie value
* @throws MalformedCookieException if an exception occurs during parsing
*/
public List<Cookie> parse(final Header header, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(header, "Header");
Args.notNull(origin, "Cookie origin");
if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE)) {
throw new MalformedCookieException("Unrecognized cookie header '"
+ header.toString() + "'");
}
final NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
final CharArrayBuffer buffer;
final ParserCursor cursor;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
cursor = new ParserCursor(
((FormattedHeader) header).getValuePos(),
buffer.length());
} else {
final String s = header.getValue();
if (s == null) {
throw new MalformedCookieException("Header value is null");
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
cursor = new ParserCursor(0, buffer.length());
}
return parse(new HeaderElement[] { parser.parseHeader(buffer, cursor) }, origin);
}
public List<Header> formatCookies(final List<Cookie> cookies) {
Args.notEmpty(cookies, "List of cookies");
final CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
buffer.append(SM.COOKIE);
buffer.append(": ");
for (int i = 0; i < cookies.size(); i++) {
final Cookie cookie = cookies.get(i);
if (i > 0) {
buffer.append("; ");
}
buffer.append(cookie.getName());
final String s = cookie.getValue();
if (s != null) {
buffer.append("=");
buffer.append(s);
}
}
final List<Header> headers = new ArrayList<Header>(1);
headers.add(new BufferedHeader(buffer));
return headers;
}
public int getVersion() {
return 0;
}
public Header getVersionHeader() {
return null;
}
@Override
public String toString() {
return "netscape";
}
}

View file

@ -0,0 +1,81 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.CookieSpecFactory;
import ch.boye.httpclientandroidlib.cookie.CookieSpecProvider;
import ch.boye.httpclientandroidlib.cookie.params.CookieSpecPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* {@link CookieSpecProvider} implementation that creates and initializes
* {@link NetscapeDraftSpec} instances.
*
* @since 4.0
*/
@Immutable
@SuppressWarnings("deprecation")
public class NetscapeDraftSpecFactory implements CookieSpecFactory, CookieSpecProvider {
private final String[] datepatterns;
public NetscapeDraftSpecFactory(final String[] datepatterns) {
super();
this.datepatterns = datepatterns;
}
public NetscapeDraftSpecFactory() {
this(null);
}
public CookieSpec newInstance(final HttpParams params) {
if (params != null) {
String[] patterns = null;
final Collection<?> param = (Collection<?>) params.getParameter(
CookieSpecPNames.DATE_PATTERNS);
if (param != null) {
patterns = new String[param.size()];
patterns = param.toArray(patterns);
}
return new NetscapeDraftSpec(patterns);
} else {
return new NetscapeDraftSpec();
}
}
public CookieSpec create(final HttpContext context) {
return new NetscapeDraftSpec(this.datepatterns);
}
}

View file

@ -0,0 +1,132 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import ch.boye.httpclientandroidlib.client.utils.Punycode;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
/**
* Wraps a CookieAttributeHandler and leverages its match method
* to never match a suffix from a black list. May be used to provide
* additional security for cross-site attack types by preventing
* cookies from apparent domains that are not publicly available.
* An uptodate list of suffixes can be obtained from
* <a href="http://publicsuffix.org/">publicsuffix.org</a>
*
* @since 4.0
*/
public class PublicSuffixFilter implements CookieAttributeHandler {
private final CookieAttributeHandler wrapped;
private Set<String> exceptions;
private Set<String> suffixes;
public PublicSuffixFilter(final CookieAttributeHandler wrapped) {
this.wrapped = wrapped;
}
/**
* Sets the suffix blacklist patterns.
* A pattern can be "com", "*.jp"
* TODO add support for patterns like "lib.*.us"
* @param suffixes
*/
public void setPublicSuffixes(final Collection<String> suffixes) {
this.suffixes = new HashSet<String>(suffixes);
}
/**
* Sets the exceptions from the blacklist. Exceptions can not be patterns.
* TODO add support for patterns
* @param exceptions
*/
public void setExceptions(final Collection<String> exceptions) {
this.exceptions = new HashSet<String>(exceptions);
}
/**
* Never matches if the cookie's domain is from the blacklist.
*/
public boolean match(final Cookie cookie, final CookieOrigin origin) {
if (isForPublicSuffix(cookie)) {
return false;
}
return wrapped.match(cookie, origin);
}
public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
wrapped.parse(cookie, value);
}
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
wrapped.validate(cookie, origin);
}
private boolean isForPublicSuffix(final Cookie cookie) {
String domain = cookie.getDomain();
if (domain.startsWith(".")) {
domain = domain.substring(1);
}
domain = Punycode.toUnicode(domain);
// An exception rule takes priority over any other matching rule.
if (this.exceptions != null) {
if (this.exceptions.contains(domain)) {
return false;
}
}
if (this.suffixes == null) {
return false;
}
do {
if (this.suffixes.contains(domain)) {
return true;
}
// patterns
if (domain.startsWith("*.")) {
domain = domain.substring(2);
}
final int nextdot = domain.indexOf('.');
if (nextdot == -1) {
break;
}
domain = "*" + domain.substring(nextdot);
} while (domain.length() > 0);
return false;
}
}

View file

@ -0,0 +1,127 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import ch.boye.httpclientandroidlib.annotation.Immutable;
/**
* Parses the list from <a href="http://publicsuffix.org/">publicsuffix.org</a>
* and configures a PublicSuffixFilter.
*
* @since 4.0
*/
@Immutable
public class PublicSuffixListParser {
private static final int MAX_LINE_LEN = 256;
private final PublicSuffixFilter filter;
PublicSuffixListParser(final PublicSuffixFilter filter) {
this.filter = filter;
}
/**
* Parses the public suffix list format.
* When creating the reader from the file, make sure to
* use the correct encoding (the original list is in UTF-8).
*
* @param list the suffix list. The caller is responsible for closing the reader.
* @throws IOException on error while reading from list
*/
public void parse(final Reader list) throws IOException {
final Collection<String> rules = new ArrayList<String>();
final Collection<String> exceptions = new ArrayList<String>();
final BufferedReader r = new BufferedReader(list);
final StringBuilder sb = new StringBuilder(256);
boolean more = true;
while (more) {
more = readLine(r, sb);
String line = sb.toString();
if (line.length() == 0) {
continue;
}
if (line.startsWith("//"))
{
continue; //entire lines can also be commented using //
}
if (line.startsWith("."))
{
line = line.substring(1); // A leading dot is optional
}
// An exclamation mark (!) at the start of a rule marks an exception to a previous wildcard rule
final boolean isException = line.startsWith("!");
if (isException) {
line = line.substring(1);
}
if (isException) {
exceptions.add(line);
} else {
rules.add(line);
}
}
filter.setPublicSuffixes(rules);
filter.setExceptions(exceptions);
}
/**
*
* @param r
* @param sb
* @return false when the end of the stream is reached
* @throws IOException
*/
private boolean readLine(final Reader r, final StringBuilder sb) throws IOException {
sb.setLength(0);
int b;
boolean hitWhitespace = false;
while ((b = r.read()) != -1) {
final char c = (char) b;
if (c == '\n') {
break;
}
// Each line is only read up to the first whitespace
if (Character.isWhitespace(c)) {
hitWhitespace = true;
}
if (!hitWhitespace) {
sb.append(c);
}
if (sb.length() > MAX_LINE_LEN)
{
throw new IOException("Line too long"); // prevent excess memory usage
}
}
return (b != -1);
}
}

View file

@ -0,0 +1,120 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Locale;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class RFC2109DomainHandler implements CookieAttributeHandler {
public RFC2109DomainHandler() {
super();
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for domain attribute");
}
if (value.trim().length() == 0) {
throw new MalformedCookieException("Blank value for domain attribute");
}
cookie.setDomain(value);
}
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
String host = origin.getHost();
final String domain = cookie.getDomain();
if (domain == null) {
throw new CookieRestrictionViolationException("Cookie domain may not be null");
}
if (!domain.equals(host)) {
int dotIndex = domain.indexOf('.');
if (dotIndex == -1) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ domain
+ "\" does not match the host \""
+ host + "\"");
}
// domain must start with dot
if (!domain.startsWith(".")) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ domain
+ "\" violates RFC 2109: domain must start with a dot");
}
// domain must have at least one embedded dot
dotIndex = domain.indexOf('.', 1);
if (dotIndex < 0 || dotIndex == domain.length() - 1) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ domain
+ "\" violates RFC 2109: domain must contain an embedded dot");
}
host = host.toLowerCase(Locale.ENGLISH);
if (!host.endsWith(domain)) {
throw new CookieRestrictionViolationException(
"Illegal domain attribute \"" + domain
+ "\". Domain of origin: \"" + host + "\"");
}
// host minus domain may not contain any dots
final String hostWithoutDomain = host.substring(0, host.length() - domain.length());
if (hostWithoutDomain.indexOf('.') != -1) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ domain
+ "\" violates RFC 2109: host minus domain may not contain any dots");
}
}
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String host = origin.getHost();
final String domain = cookie.getDomain();
if (domain == null) {
return false;
}
return host.equals(domain) || (domain.startsWith(".") && host.endsWith(domain));
}
}

View file

@ -0,0 +1,240 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.client.utils.DateUtils;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookiePathComparator;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SM;
import ch.boye.httpclientandroidlib.message.BufferedHeader;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
/**
* RFC 2109 compliant {@link ch.boye.httpclientandroidlib.cookie.CookieSpec} implementation.
* This is an older version of the official HTTP state management specification
* superseded by RFC 2965.
*
* @see RFC2965Spec
*
* @since 4.0
*/
@NotThreadSafe // superclass is @NotThreadSafe
public class RFC2109Spec extends CookieSpecBase {
private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
private final static String[] DATE_PATTERNS = {
DateUtils.PATTERN_RFC1123,
DateUtils.PATTERN_RFC1036,
DateUtils.PATTERN_ASCTIME
};
private final String[] datepatterns;
private final boolean oneHeader;
/** Default constructor */
public RFC2109Spec(final String[] datepatterns, final boolean oneHeader) {
super();
if (datepatterns != null) {
this.datepatterns = datepatterns.clone();
} else {
this.datepatterns = DATE_PATTERNS;
}
this.oneHeader = oneHeader;
registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2109VersionHandler());
registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2109DomainHandler());
registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
this.datepatterns));
}
/** Default constructor */
public RFC2109Spec() {
this(null, false);
}
public List<Cookie> parse(final Header header, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(header, "Header");
Args.notNull(origin, "Cookie origin");
if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE)) {
throw new MalformedCookieException("Unrecognized cookie header '"
+ header.toString() + "'");
}
final HeaderElement[] elems = header.getElements();
return parse(elems, origin);
}
@Override
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
final String name = cookie.getName();
if (name.indexOf(' ') != -1) {
throw new CookieRestrictionViolationException("Cookie name may not contain blanks");
}
if (name.startsWith("$")) {
throw new CookieRestrictionViolationException("Cookie name may not start with $");
}
super.validate(cookie, origin);
}
public List<Header> formatCookies(final List<Cookie> cookies) {
Args.notEmpty(cookies, "List of cookies");
List<Cookie> cookieList;
if (cookies.size() > 1) {
// Create a mutable copy and sort the copy.
cookieList = new ArrayList<Cookie>(cookies);
Collections.sort(cookieList, PATH_COMPARATOR);
} else {
cookieList = cookies;
}
if (this.oneHeader) {
return doFormatOneHeader(cookieList);
} else {
return doFormatManyHeaders(cookieList);
}
}
private List<Header> doFormatOneHeader(final List<Cookie> cookies) {
int version = Integer.MAX_VALUE;
// Pick the lowest common denominator
for (final Cookie cookie : cookies) {
if (cookie.getVersion() < version) {
version = cookie.getVersion();
}
}
final CharArrayBuffer buffer = new CharArrayBuffer(40 * cookies.size());
buffer.append(SM.COOKIE);
buffer.append(": ");
buffer.append("$Version=");
buffer.append(Integer.toString(version));
for (final Cookie cooky : cookies) {
buffer.append("; ");
final Cookie cookie = cooky;
formatCookieAsVer(buffer, cookie, version);
}
final List<Header> headers = new ArrayList<Header>(1);
headers.add(new BufferedHeader(buffer));
return headers;
}
private List<Header> doFormatManyHeaders(final List<Cookie> cookies) {
final List<Header> headers = new ArrayList<Header>(cookies.size());
for (final Cookie cookie : cookies) {
final int version = cookie.getVersion();
final CharArrayBuffer buffer = new CharArrayBuffer(40);
buffer.append("Cookie: ");
buffer.append("$Version=");
buffer.append(Integer.toString(version));
buffer.append("; ");
formatCookieAsVer(buffer, cookie, version);
headers.add(new BufferedHeader(buffer));
}
return headers;
}
/**
* Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
* header as defined in RFC 2109 for backward compatibility with cookie
* version 0
* @param buffer The char array buffer to use for output
* @param name The cookie name
* @param value The cookie value
* @param version The cookie version
*/
protected void formatParamAsVer(final CharArrayBuffer buffer,
final String name, final String value, final int version) {
buffer.append(name);
buffer.append("=");
if (value != null) {
if (version > 0) {
buffer.append('\"');
buffer.append(value);
buffer.append('\"');
} else {
buffer.append(value);
}
}
}
/**
* Return a string suitable for sending in a <tt>"Cookie"</tt> header
* as defined in RFC 2109 for backward compatibility with cookie version 0
* @param buffer The char array buffer to use for output
* @param cookie The {@link Cookie} to be formatted as string
* @param version The version to use.
*/
protected void formatCookieAsVer(final CharArrayBuffer buffer,
final Cookie cookie, final int version) {
formatParamAsVer(buffer, cookie.getName(), cookie.getValue(), version);
if (cookie.getPath() != null) {
if (cookie instanceof ClientCookie
&& ((ClientCookie) cookie).containsAttribute(ClientCookie.PATH_ATTR)) {
buffer.append("; ");
formatParamAsVer(buffer, "$Path", cookie.getPath(), version);
}
}
if (cookie.getDomain() != null) {
if (cookie instanceof ClientCookie
&& ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
buffer.append("; ");
formatParamAsVer(buffer, "$Domain", cookie.getDomain(), version);
}
}
}
public int getVersion() {
return 1;
}
public Header getVersionHeader() {
return null;
}
@Override
public String toString() {
return "rfc2109";
}
}

View file

@ -0,0 +1,86 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.CookieSpecFactory;
import ch.boye.httpclientandroidlib.cookie.CookieSpecProvider;
import ch.boye.httpclientandroidlib.cookie.params.CookieSpecPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* {@link CookieSpecProvider} implementation that creates and initializes
* {@link RFC2109Spec} instances.
*
* @since 4.0
*/
@Immutable
@SuppressWarnings("deprecation")
public class RFC2109SpecFactory implements CookieSpecFactory, CookieSpecProvider {
private final String[] datepatterns;
private final boolean oneHeader;
public RFC2109SpecFactory(final String[] datepatterns, final boolean oneHeader) {
super();
this.datepatterns = datepatterns;
this.oneHeader = oneHeader;
}
public RFC2109SpecFactory() {
this(null, false);
}
public CookieSpec newInstance(final HttpParams params) {
if (params != null) {
String[] patterns = null;
final Collection<?> param = (Collection<?>) params.getParameter(
CookieSpecPNames.DATE_PATTERNS);
if (param != null) {
patterns = new String[param.size()];
patterns = param.toArray(patterns);
}
final boolean singleHeader = params.getBooleanParameter(
CookieSpecPNames.SINGLE_COOKIE_HEADER, false);
return new RFC2109Spec(patterns, singleHeader);
} else {
return new RFC2109Spec();
}
}
public CookieSpec create(final HttpContext context) {
return new RFC2109Spec(this.datepatterns, this.oneHeader);
}
}

View file

@ -0,0 +1,74 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
*
* @since 4.0
*/
@Immutable
public class RFC2109VersionHandler extends AbstractCookieAttributeHandler {
public RFC2109VersionHandler() {
super();
}
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for version attribute");
}
if (value.trim().length() == 0) {
throw new MalformedCookieException("Blank value for version attribute");
}
try {
cookie.setVersion(Integer.parseInt(value));
} catch (final NumberFormatException e) {
throw new MalformedCookieException("Invalid version: "
+ e.getMessage());
}
}
@Override
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (cookie.getVersion() < 0) {
throw new CookieRestrictionViolationException("Cookie version may not be negative");
}
}
}

View file

@ -0,0 +1,66 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.cookie.SetCookie2;
/**
* <tt>"CommentURL"</tt> cookie attribute handler for RFC 2965 cookie spec.
*
* @since 4.0
*/
@Immutable
public class RFC2965CommentUrlAttributeHandler implements CookieAttributeHandler {
public RFC2965CommentUrlAttributeHandler() {
super();
}
public void parse(final SetCookie cookie, final String commenturl)
throws MalformedCookieException {
if (cookie instanceof SetCookie2) {
final SetCookie2 cookie2 = (SetCookie2) cookie;
cookie2.setCommentURL(commenturl);
}
}
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
return true;
}
}

View file

@ -0,0 +1,66 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.cookie.SetCookie2;
/**
* <tt>"Discard"</tt> cookie attribute handler for RFC 2965 cookie spec.
*
* @since 4.0
*/
@Immutable
public class RFC2965DiscardAttributeHandler implements CookieAttributeHandler {
public RFC2965DiscardAttributeHandler() {
super();
}
public void parse(final SetCookie cookie, final String commenturl)
throws MalformedCookieException {
if (cookie instanceof SetCookie2) {
final SetCookie2 cookie2 = (SetCookie2) cookie;
cookie2.setDiscard(true);
}
}
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
return true;
}
}

View file

@ -0,0 +1,185 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Locale;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.util.Args;
/**
* <tt>"Domain"</tt> cookie attribute handler for RFC 2965 cookie spec.
*
*
* @since 3.1
*/
@Immutable
public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
public RFC2965DomainAttributeHandler() {
super();
}
/**
* Parse cookie domain attribute.
*/
public void parse(
final SetCookie cookie, final String domain) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (domain == null) {
throw new MalformedCookieException(
"Missing value for domain attribute");
}
if (domain.trim().length() == 0) {
throw new MalformedCookieException(
"Blank value for domain attribute");
}
String s = domain;
s = s.toLowerCase(Locale.ENGLISH);
if (!domain.startsWith(".")) {
// Per RFC 2965 section 3.2.2
// "... If an explicitly specified value does not start with
// a dot, the user agent supplies a leading dot ..."
// That effectively implies that the domain attribute
// MAY NOT be an IP address of a host name
s = '.' + s;
}
cookie.setDomain(s);
}
/**
* Performs domain-match as defined by the RFC2965.
* <p>
* Host A's name domain-matches host B's if
* <ol>
* <ul>their host name strings string-compare equal; or</ul>
* <ul>A is a HDN string and has the form NB, where N is a non-empty
* name string, B has the form .B', and B' is a HDN string. (So,
* x.y.com domain-matches .Y.com but not Y.com.)</ul>
* </ol>
*
* @param host host name where cookie is received from or being sent to.
* @param domain The cookie domain attribute.
* @return true if the specified host matches the given domain.
*/
public boolean domainMatch(final String host, final String domain) {
final boolean match = host.equals(domain)
|| (domain.startsWith(".") && host.endsWith(domain));
return match;
}
/**
* Validate cookie domain attribute.
*/
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String host = origin.getHost().toLowerCase(Locale.ENGLISH);
if (cookie.getDomain() == null) {
throw new CookieRestrictionViolationException("Invalid cookie state: " +
"domain not specified");
}
final String cookieDomain = cookie.getDomain().toLowerCase(Locale.ENGLISH);
if (cookie instanceof ClientCookie
&& ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
// Domain attribute must start with a dot
if (!cookieDomain.startsWith(".")) {
throw new CookieRestrictionViolationException("Domain attribute \"" +
cookie.getDomain() + "\" violates RFC 2109: domain must start with a dot");
}
// Domain attribute must contain at least one embedded dot,
// or the value must be equal to .local.
final int dotIndex = cookieDomain.indexOf('.', 1);
if (((dotIndex < 0) || (dotIndex == cookieDomain.length() - 1))
&& (!cookieDomain.equals(".local"))) {
throw new CookieRestrictionViolationException(
"Domain attribute \"" + cookie.getDomain()
+ "\" violates RFC 2965: the value contains no embedded dots "
+ "and the value is not .local");
}
// The effective host name must domain-match domain attribute.
if (!domainMatch(host, cookieDomain)) {
throw new CookieRestrictionViolationException(
"Domain attribute \"" + cookie.getDomain()
+ "\" violates RFC 2965: effective host name does not "
+ "domain-match domain attribute.");
}
// effective host name minus domain must not contain any dots
final String effectiveHostWithoutDomain = host.substring(
0, host.length() - cookieDomain.length());
if (effectiveHostWithoutDomain.indexOf('.') != -1) {
throw new CookieRestrictionViolationException("Domain attribute \""
+ cookie.getDomain() + "\" violates RFC 2965: "
+ "effective host minus domain may not contain any dots");
}
} else {
// Domain was not specified in header. In this case, domain must
// string match request host (case-insensitive).
if (!cookie.getDomain().equals(host)) {
throw new CookieRestrictionViolationException("Illegal domain attribute: \""
+ cookie.getDomain() + "\"."
+ "Domain of origin: \""
+ host + "\"");
}
}
}
/**
* Match cookie domain attribute.
*/
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String host = origin.getHost().toLowerCase(Locale.ENGLISH);
final String cookieDomain = cookie.getDomain();
// The effective host name MUST domain-match the Domain
// attribute of the cookie.
if (!domainMatch(host, cookieDomain)) {
return false;
}
// effective host name minus domain must not contain any dots
final String effectiveHostWithoutDomain = host.substring(
0, host.length() - cookieDomain.length());
return effectiveHostWithoutDomain.indexOf('.') == -1;
}
}

View file

@ -0,0 +1,160 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.StringTokenizer;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.cookie.SetCookie2;
import ch.boye.httpclientandroidlib.util.Args;
/**
* <tt>"Port"</tt> cookie attribute handler for RFC 2965 cookie spec.
*
* @since 4.0
*/
@Immutable
public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
public RFC2965PortAttributeHandler() {
super();
}
/**
* Parses the given Port attribute value (e.g. "8000,8001,8002")
* into an array of ports.
*
* @param portValue port attribute value
* @return parsed array of ports
* @throws MalformedCookieException if there is a problem in
* parsing due to invalid portValue.
*/
private static int[] parsePortAttribute(final String portValue)
throws MalformedCookieException {
final StringTokenizer st = new StringTokenizer(portValue, ",");
final int[] ports = new int[st.countTokens()];
try {
int i = 0;
while(st.hasMoreTokens()) {
ports[i] = Integer.parseInt(st.nextToken().trim());
if (ports[i] < 0) {
throw new MalformedCookieException ("Invalid Port attribute.");
}
++i;
}
} catch (final NumberFormatException e) {
throw new MalformedCookieException ("Invalid Port "
+ "attribute: " + e.getMessage());
}
return ports;
}
/**
* Returns <tt>true</tt> if the given port exists in the given
* ports list.
*
* @param port port of host where cookie was received from or being sent to.
* @param ports port list
* @return true returns <tt>true</tt> if the given port exists in
* the given ports list; <tt>false</tt> otherwise.
*/
private static boolean portMatch(final int port, final int[] ports) {
boolean portInList = false;
for (final int port2 : ports) {
if (port == port2) {
portInList = true;
break;
}
}
return portInList;
}
/**
* Parse cookie port attribute.
*/
public void parse(final SetCookie cookie, final String portValue)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (cookie instanceof SetCookie2) {
final SetCookie2 cookie2 = (SetCookie2) cookie;
if (portValue != null && portValue.trim().length() > 0) {
final int[] ports = parsePortAttribute(portValue);
cookie2.setPorts(ports);
}
}
}
/**
* Validate cookie port attribute. If the Port attribute was specified
* in header, the request port must be in cookie's port list.
*/
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final int port = origin.getPort();
if (cookie instanceof ClientCookie
&& ((ClientCookie) cookie).containsAttribute(ClientCookie.PORT_ATTR)) {
if (!portMatch(port, cookie.getPorts())) {
throw new CookieRestrictionViolationException(
"Port attribute violates RFC 2965: "
+ "Request port not found in cookie's port list.");
}
}
}
/**
* Match cookie port attribute. If the Port attribute is not specified
* in header, the cookie can be sent to any port. Otherwise, the request port
* must be in the cookie's port list.
*/
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final int port = origin.getPort();
if (cookie instanceof ClientCookie
&& ((ClientCookie) cookie).containsAttribute(ClientCookie.PORT_ATTR)) {
if (cookie.getPorts() == null) {
// Invalid cookie state: port not specified
return false;
}
if (!portMatch(port, cookie.getPorts())) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,239 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.NameValuePair;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SM;
import ch.boye.httpclientandroidlib.message.BufferedHeader;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
/**
* RFC 2965 compliant {@link ch.boye.httpclientandroidlib.cookie.CookieSpec} implementation.
*
* @since 4.0
*/
@NotThreadSafe // superclass is @NotThreadSafe
public class RFC2965Spec extends RFC2109Spec {
/**
* Default constructor
*
*/
public RFC2965Spec() {
this(null, false);
}
public RFC2965Spec(final String[] datepatterns, final boolean oneHeader) {
super(datepatterns, oneHeader);
registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2965DomainAttributeHandler());
registerAttribHandler(ClientCookie.PORT_ATTR, new RFC2965PortAttributeHandler());
registerAttribHandler(ClientCookie.COMMENTURL_ATTR, new RFC2965CommentUrlAttributeHandler());
registerAttribHandler(ClientCookie.DISCARD_ATTR, new RFC2965DiscardAttributeHandler());
registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2965VersionAttributeHandler());
}
@Override
public List<Cookie> parse(
final Header header,
final CookieOrigin origin) throws MalformedCookieException {
Args.notNull(header, "Header");
Args.notNull(origin, "Cookie origin");
if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE2)) {
throw new MalformedCookieException("Unrecognized cookie header '"
+ header.toString() + "'");
}
final HeaderElement[] elems = header.getElements();
return createCookies(elems, adjustEffectiveHost(origin));
}
@Override
protected List<Cookie> parse(
final HeaderElement[] elems,
final CookieOrigin origin) throws MalformedCookieException {
return createCookies(elems, adjustEffectiveHost(origin));
}
private List<Cookie> createCookies(
final HeaderElement[] elems,
final CookieOrigin origin) throws MalformedCookieException {
final List<Cookie> cookies = new ArrayList<Cookie>(elems.length);
for (final HeaderElement headerelement : elems) {
final String name = headerelement.getName();
final String value = headerelement.getValue();
if (name == null || name.length() == 0) {
throw new MalformedCookieException("Cookie name may not be empty");
}
final BasicClientCookie2 cookie = new BasicClientCookie2(name, value);
cookie.setPath(getDefaultPath(origin));
cookie.setDomain(getDefaultDomain(origin));
cookie.setPorts(new int [] { origin.getPort() });
// cycle through the parameters
final NameValuePair[] attribs = headerelement.getParameters();
// Eliminate duplicate attributes. The first occurrence takes precedence
// See RFC2965: 3.2 Origin Server Role
final Map<String, NameValuePair> attribmap =
new HashMap<String, NameValuePair>(attribs.length);
for (int j = attribs.length - 1; j >= 0; j--) {
final NameValuePair param = attribs[j];
attribmap.put(param.getName().toLowerCase(Locale.ENGLISH), param);
}
for (final Map.Entry<String, NameValuePair> entry : attribmap.entrySet()) {
final NameValuePair attrib = entry.getValue();
final String s = attrib.getName().toLowerCase(Locale.ENGLISH);
cookie.setAttribute(s, attrib.getValue());
final CookieAttributeHandler handler = findAttribHandler(s);
if (handler != null) {
handler.parse(cookie, attrib.getValue());
}
}
cookies.add(cookie);
}
return cookies;
}
@Override
public void validate(
final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
super.validate(cookie, adjustEffectiveHost(origin));
}
@Override
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
return super.match(cookie, adjustEffectiveHost(origin));
}
/**
* Adds valid Port attribute value, e.g. "8000,8001,8002"
*/
@Override
protected void formatCookieAsVer(final CharArrayBuffer buffer,
final Cookie cookie, final int version) {
super.formatCookieAsVer(buffer, cookie, version);
// format port attribute
if (cookie instanceof ClientCookie) {
// Test if the port attribute as set by the origin server is not blank
final String s = ((ClientCookie) cookie).getAttribute(ClientCookie.PORT_ATTR);
if (s != null) {
buffer.append("; $Port");
buffer.append("=\"");
if (s.trim().length() > 0) {
final int[] ports = cookie.getPorts();
if (ports != null) {
final int len = ports.length;
for (int i = 0; i < len; i++) {
if (i > 0) {
buffer.append(",");
}
buffer.append(Integer.toString(ports[i]));
}
}
}
buffer.append("\"");
}
}
}
/**
* Set 'effective host name' as defined in RFC 2965.
* <p>
* If a host name contains no dots, the effective host name is
* that name with the string .local appended to it. Otherwise
* the effective host name is the same as the host name. Note
* that all effective host names contain at least one dot.
*
* @param origin origin where cookie is received from or being sent to.
*/
private static CookieOrigin adjustEffectiveHost(final CookieOrigin origin) {
String host = origin.getHost();
// Test if the host name appears to be a fully qualified DNS name,
// IPv4 address or IPv6 address
boolean isLocalHost = true;
for (int i = 0; i < host.length(); i++) {
final char ch = host.charAt(i);
if (ch == '.' || ch == ':') {
isLocalHost = false;
break;
}
}
if (isLocalHost) {
host += ".local";
return new CookieOrigin(
host,
origin.getPort(),
origin.getPath(),
origin.isSecure());
} else {
return origin;
}
}
@Override
public int getVersion() {
return 1;
}
@Override
public Header getVersionHeader() {
final CharArrayBuffer buffer = new CharArrayBuffer(40);
buffer.append(SM.COOKIE2);
buffer.append(": ");
buffer.append("$Version=");
buffer.append(Integer.toString(getVersion()));
return new BufferedHeader(buffer);
}
@Override
public String toString() {
return "rfc2965";
}
}

View file

@ -0,0 +1,86 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import java.util.Collection;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.CookieSpec;
import ch.boye.httpclientandroidlib.cookie.CookieSpecFactory;
import ch.boye.httpclientandroidlib.cookie.CookieSpecProvider;
import ch.boye.httpclientandroidlib.cookie.params.CookieSpecPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* {@link CookieSpecProvider} implementation that creates and initializes
* {@link RFC2965Spec} instances.
*
* @since 4.0
*/
@Immutable
@SuppressWarnings("deprecation")
public class RFC2965SpecFactory implements CookieSpecFactory, CookieSpecProvider {
private final String[] datepatterns;
private final boolean oneHeader;
public RFC2965SpecFactory(final String[] datepatterns, final boolean oneHeader) {
super();
this.datepatterns = datepatterns;
this.oneHeader = oneHeader;
}
public RFC2965SpecFactory() {
this(null, false);
}
public CookieSpec newInstance(final HttpParams params) {
if (params != null) {
String[] patterns = null;
final Collection<?> param = (Collection<?>) params.getParameter(
CookieSpecPNames.DATE_PATTERNS);
if (param != null) {
patterns = new String[param.size()];
patterns = param.toArray(patterns);
}
final boolean singleHeader = params.getBooleanParameter(
CookieSpecPNames.SINGLE_COOKIE_HEADER, false);
return new RFC2965Spec(patterns, singleHeader);
} else {
return new RFC2965Spec();
}
}
public CookieSpec create(final HttpContext context) {
return new RFC2965Spec(this.datepatterns, this.oneHeader);
}
}

View file

@ -0,0 +1,94 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.impl.cookie;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.cookie.ClientCookie;
import ch.boye.httpclientandroidlib.cookie.Cookie;
import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
import ch.boye.httpclientandroidlib.cookie.SetCookie;
import ch.boye.httpclientandroidlib.cookie.SetCookie2;
import ch.boye.httpclientandroidlib.util.Args;
/**
* <tt>"Version"</tt> cookie attribute handler for RFC 2965 cookie spec.
*
* @since 4.0
*/
@Immutable
public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
public RFC2965VersionAttributeHandler() {
super();
}
/**
* Parse cookie version attribute.
*/
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException(
"Missing value for version attribute");
}
int version = -1;
try {
version = Integer.parseInt(value);
} catch (final NumberFormatException e) {
version = -1;
}
if (version < 0) {
throw new MalformedCookieException("Invalid cookie version.");
}
cookie.setVersion(version);
}
/**
* validate cookie version attribute. Version attribute is REQUIRED.
*/
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (cookie instanceof SetCookie2) {
if (cookie instanceof ClientCookie
&& !((ClientCookie) cookie).containsAttribute(ClientCookie.VERSION_ATTR)) {
throw new CookieRestrictionViolationException(
"Violates RFC 2965. Version attribute is required.");
}
}
}
public boolean match(final Cookie cookie, final CookieOrigin origin) {
return true;
}
}

View file

@ -0,0 +1,32 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
/**
* Default implementations of standard and common HTTP state
* management policies.
*/
package ch.boye.httpclientandroidlib.impl.cookie;