1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/cookie/RFC2965Spec.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,256 @@ 1.4 +/* 1.5 + * ==================================================================== 1.6 + * 1.7 + * Licensed to the Apache Software Foundation (ASF) under one or more 1.8 + * contributor license agreements. See the NOTICE file distributed with 1.9 + * this work for additional information regarding copyright ownership. 1.10 + * The ASF licenses this file to You under the Apache License, Version 2.0 1.11 + * (the "License"); you may not use this file except in compliance with 1.12 + * the License. You may obtain a copy of the License at 1.13 + * 1.14 + * http://www.apache.org/licenses/LICENSE-2.0 1.15 + * 1.16 + * Unless required by applicable law or agreed to in writing, software 1.17 + * distributed under the License is distributed on an "AS IS" BASIS, 1.18 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.19 + * See the License for the specific language governing permissions and 1.20 + * limitations under the License. 1.21 + * ==================================================================== 1.22 + * 1.23 + * This software consists of voluntary contributions made by many 1.24 + * individuals on behalf of the Apache Software Foundation. For more 1.25 + * information on the Apache Software Foundation, please see 1.26 + * <http://www.apache.org/>. 1.27 + * 1.28 + */ 1.29 + 1.30 +package ch.boye.httpclientandroidlib.impl.cookie; 1.31 + 1.32 +import java.util.ArrayList; 1.33 +import java.util.HashMap; 1.34 +import java.util.List; 1.35 +import java.util.Locale; 1.36 +import java.util.Map; 1.37 + 1.38 +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; 1.39 + 1.40 +import ch.boye.httpclientandroidlib.Header; 1.41 +import ch.boye.httpclientandroidlib.HeaderElement; 1.42 +import ch.boye.httpclientandroidlib.NameValuePair; 1.43 +import ch.boye.httpclientandroidlib.cookie.ClientCookie; 1.44 +import ch.boye.httpclientandroidlib.cookie.Cookie; 1.45 +import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler; 1.46 +import ch.boye.httpclientandroidlib.cookie.CookieOrigin; 1.47 +import ch.boye.httpclientandroidlib.cookie.CookieSpec; 1.48 +import ch.boye.httpclientandroidlib.cookie.MalformedCookieException; 1.49 +import ch.boye.httpclientandroidlib.cookie.SM; 1.50 +import ch.boye.httpclientandroidlib.message.BufferedHeader; 1.51 +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; 1.52 + 1.53 +/** 1.54 + * RFC 2965 compliant {@link CookieSpec} implementation. 1.55 + * 1.56 + * @since 4.0 1.57 + */ 1.58 +@NotThreadSafe // superclass is @NotThreadSafe 1.59 +public class RFC2965Spec extends RFC2109Spec { 1.60 + 1.61 + /** 1.62 + * Default constructor 1.63 + * 1.64 + */ 1.65 + public RFC2965Spec() { 1.66 + this(null, false); 1.67 + } 1.68 + 1.69 + public RFC2965Spec(final String[] datepatterns, boolean oneHeader) { 1.70 + super(datepatterns, oneHeader); 1.71 + registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2965DomainAttributeHandler()); 1.72 + registerAttribHandler(ClientCookie.PORT_ATTR, new RFC2965PortAttributeHandler()); 1.73 + registerAttribHandler(ClientCookie.COMMENTURL_ATTR, new RFC2965CommentUrlAttributeHandler()); 1.74 + registerAttribHandler(ClientCookie.DISCARD_ATTR, new RFC2965DiscardAttributeHandler()); 1.75 + registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2965VersionAttributeHandler()); 1.76 + } 1.77 + 1.78 + @Override 1.79 + public List<Cookie> parse( 1.80 + final Header header, 1.81 + CookieOrigin origin) throws MalformedCookieException { 1.82 + if (header == null) { 1.83 + throw new IllegalArgumentException("Header may not be null"); 1.84 + } 1.85 + if (origin == null) { 1.86 + throw new IllegalArgumentException("Cookie origin may not be null"); 1.87 + } 1.88 + if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE2)) { 1.89 + throw new MalformedCookieException("Unrecognized cookie header '" 1.90 + + header.toString() + "'"); 1.91 + } 1.92 + origin = adjustEffectiveHost(origin); 1.93 + HeaderElement[] elems = header.getElements(); 1.94 + return createCookies(elems, origin); 1.95 + } 1.96 + 1.97 + @Override 1.98 + protected List<Cookie> parse( 1.99 + final HeaderElement[] elems, 1.100 + CookieOrigin origin) throws MalformedCookieException { 1.101 + origin = adjustEffectiveHost(origin); 1.102 + return createCookies(elems, origin); 1.103 + } 1.104 + 1.105 + private List<Cookie> createCookies( 1.106 + final HeaderElement[] elems, 1.107 + final CookieOrigin origin) throws MalformedCookieException { 1.108 + List<Cookie> cookies = new ArrayList<Cookie>(elems.length); 1.109 + for (HeaderElement headerelement : elems) { 1.110 + String name = headerelement.getName(); 1.111 + String value = headerelement.getValue(); 1.112 + if (name == null || name.length() == 0) { 1.113 + throw new MalformedCookieException("Cookie name may not be empty"); 1.114 + } 1.115 + 1.116 + BasicClientCookie2 cookie = new BasicClientCookie2(name, value); 1.117 + cookie.setPath(getDefaultPath(origin)); 1.118 + cookie.setDomain(getDefaultDomain(origin)); 1.119 + cookie.setPorts(new int [] { origin.getPort() }); 1.120 + // cycle through the parameters 1.121 + NameValuePair[] attribs = headerelement.getParameters(); 1.122 + 1.123 + // Eliminate duplicate attributes. The first occurrence takes precedence 1.124 + // See RFC2965: 3.2 Origin Server Role 1.125 + Map<String, NameValuePair> attribmap = 1.126 + new HashMap<String, NameValuePair>(attribs.length); 1.127 + for (int j = attribs.length - 1; j >= 0; j--) { 1.128 + NameValuePair param = attribs[j]; 1.129 + attribmap.put(param.getName().toLowerCase(Locale.ENGLISH), param); 1.130 + } 1.131 + for (Map.Entry<String, NameValuePair> entry : attribmap.entrySet()) { 1.132 + NameValuePair attrib = entry.getValue(); 1.133 + String s = attrib.getName().toLowerCase(Locale.ENGLISH); 1.134 + 1.135 + cookie.setAttribute(s, attrib.getValue()); 1.136 + 1.137 + CookieAttributeHandler handler = findAttribHandler(s); 1.138 + if (handler != null) { 1.139 + handler.parse(cookie, attrib.getValue()); 1.140 + } 1.141 + } 1.142 + cookies.add(cookie); 1.143 + } 1.144 + return cookies; 1.145 + } 1.146 + 1.147 + @Override 1.148 + public void validate(final Cookie cookie, CookieOrigin origin) 1.149 + throws MalformedCookieException { 1.150 + if (cookie == null) { 1.151 + throw new IllegalArgumentException("Cookie may not be null"); 1.152 + } 1.153 + if (origin == null) { 1.154 + throw new IllegalArgumentException("Cookie origin may not be null"); 1.155 + } 1.156 + origin = adjustEffectiveHost(origin); 1.157 + super.validate(cookie, origin); 1.158 + } 1.159 + 1.160 + @Override 1.161 + public boolean match(final Cookie cookie, CookieOrigin origin) { 1.162 + if (cookie == null) { 1.163 + throw new IllegalArgumentException("Cookie may not be null"); 1.164 + } 1.165 + if (origin == null) { 1.166 + throw new IllegalArgumentException("Cookie origin may not be null"); 1.167 + } 1.168 + origin = adjustEffectiveHost(origin); 1.169 + return super.match(cookie, origin); 1.170 + } 1.171 + 1.172 + /** 1.173 + * Adds valid Port attribute value, e.g. "8000,8001,8002" 1.174 + */ 1.175 + @Override 1.176 + protected void formatCookieAsVer(final CharArrayBuffer buffer, 1.177 + final Cookie cookie, int version) { 1.178 + super.formatCookieAsVer(buffer, cookie, version); 1.179 + // format port attribute 1.180 + if (cookie instanceof ClientCookie) { 1.181 + // Test if the port attribute as set by the origin server is not blank 1.182 + String s = ((ClientCookie) cookie).getAttribute(ClientCookie.PORT_ATTR); 1.183 + if (s != null) { 1.184 + buffer.append("; $Port"); 1.185 + buffer.append("=\""); 1.186 + if (s.trim().length() > 0) { 1.187 + int[] ports = cookie.getPorts(); 1.188 + if (ports != null) { 1.189 + for (int i = 0, len = ports.length; i < len; i++) { 1.190 + if (i > 0) { 1.191 + buffer.append(","); 1.192 + } 1.193 + buffer.append(Integer.toString(ports[i])); 1.194 + } 1.195 + } 1.196 + } 1.197 + buffer.append("\""); 1.198 + } 1.199 + } 1.200 + } 1.201 + 1.202 + /** 1.203 + * Set 'effective host name' as defined in RFC 2965. 1.204 + * <p> 1.205 + * If a host name contains no dots, the effective host name is 1.206 + * that name with the string .local appended to it. Otherwise 1.207 + * the effective host name is the same as the host name. Note 1.208 + * that all effective host names contain at least one dot. 1.209 + * 1.210 + * @param origin origin where cookie is received from or being sent to. 1.211 + * @return 1.212 + */ 1.213 + private static CookieOrigin adjustEffectiveHost(final CookieOrigin origin) { 1.214 + String host = origin.getHost(); 1.215 + 1.216 + // Test if the host name appears to be a fully qualified DNS name, 1.217 + // IPv4 address or IPv6 address 1.218 + boolean isLocalHost = true; 1.219 + for (int i = 0; i < host.length(); i++) { 1.220 + char ch = host.charAt(i); 1.221 + if (ch == '.' || ch == ':') { 1.222 + isLocalHost = false; 1.223 + break; 1.224 + } 1.225 + } 1.226 + if (isLocalHost) { 1.227 + host += ".local"; 1.228 + return new CookieOrigin( 1.229 + host, 1.230 + origin.getPort(), 1.231 + origin.getPath(), 1.232 + origin.isSecure()); 1.233 + } else { 1.234 + return origin; 1.235 + } 1.236 + } 1.237 + 1.238 + @Override 1.239 + public int getVersion() { 1.240 + return 1; 1.241 + } 1.242 + 1.243 + @Override 1.244 + public Header getVersionHeader() { 1.245 + CharArrayBuffer buffer = new CharArrayBuffer(40); 1.246 + buffer.append(SM.COOKIE2); 1.247 + buffer.append(": "); 1.248 + buffer.append("$Version="); 1.249 + buffer.append(Integer.toString(getVersion())); 1.250 + return new BufferedHeader(buffer); 1.251 + } 1.252 + 1.253 + @Override 1.254 + public String toString() { 1.255 + return "rfc2965"; 1.256 + } 1.257 + 1.258 +} 1.259 +