• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package android.webkit;
2 
3 import java.io.UnsupportedEncodingException;
4 import java.net.URI;
5 import java.net.URISyntaxException;
6 import java.net.URLDecoder;
7 import java.text.DateFormat;
8 import java.text.ParseException;
9 import java.text.SimpleDateFormat;
10 import java.util.ArrayList;
11 import java.util.Date;
12 import java.util.List;
13 
14 /**
15  * Robolectric implementation of {@link android.webkit.CookieManager}.
16  *
17  * Basic implementation which does not fully implement RFC2109.
18  */
19 public class RoboCookieManager extends CookieManager {
20     private static final String HTTP = "http://";
21     private static final String HTTPS = "https://";
22     private static final String EXPIRATION_FIELD_NAME = "Expires";
23     private static final String SECURE_ATTR_NAME = "SECURE";
24     private final List<Cookie> store = new ArrayList<>();
25     private boolean accept;
26 
setCookie(String url, String value)27     @Override public void setCookie(String url, String value) {
28       List<Cookie> cookies = parseCookies(url, value);
29       for (Cookie cookie : cookies) {
30         store.add(cookie);
31       }
32     }
33 
34     @Override
setCookie(String s, String s1, ValueCallback<Boolean> valueCallback)35     public void setCookie(String s, String s1, ValueCallback<Boolean> valueCallback) {
36 
37     }
38 
39     @Override
setAcceptThirdPartyCookies(WebView webView, boolean b)40     public void setAcceptThirdPartyCookies(WebView webView, boolean b) {
41 
42     }
43 
44     @Override
acceptThirdPartyCookies(WebView webView)45     public boolean acceptThirdPartyCookies(WebView webView) {
46       return false;
47     }
48 
49     @Override
removeAllCookies(ValueCallback<Boolean> valueCallback)50     public void removeAllCookies(ValueCallback<Boolean> valueCallback) {
51       store.clear();
52     }
53 
54     @Override
flush()55     public void flush() {
56 
57     }
58 
59     @Override
removeSessionCookies(ValueCallback<Boolean> valueCallback)60     public void removeSessionCookies(ValueCallback<Boolean> valueCallback) {
61 
62     }
63 
getCookie(String url)64     @Override public String getCookie(String url) {
65       // Return null value for empty url
66       if (url == null || url.equals("")) {
67         return null;
68       }
69 
70       try {
71         url = URLDecoder.decode(url, "UTF-8");
72       } catch (UnsupportedEncodingException e) {
73         throw new RuntimeException(e);
74       }
75 
76       final List<Cookie> matchedCookies;
77       if (url.startsWith(".")) {
78         matchedCookies = filter(url.substring(1));
79       } else if (url.contains("//.")) {
80         matchedCookies = filter(url.substring(url.indexOf("//.") + 3));
81       } else {
82         matchedCookies = filter(getCookieHost(url), url.startsWith(HTTPS));
83       }
84       if (matchedCookies.isEmpty()) {
85         return null;
86       }
87 
88       StringBuilder cookieHeaderValue = new StringBuilder();
89       for (int i = 0, n = matchedCookies.size(); i < n; i++) {
90         Cookie cookie = matchedCookies.get(i);
91 
92         if (i > 0) {
93           cookieHeaderValue.append("; ");
94         }
95         cookieHeaderValue.append(cookie.getName());
96         String value = cookie.getValue();
97         if (value != null) {
98           cookieHeaderValue.append("=");
99           cookieHeaderValue.append(value);
100         }
101       }
102 
103       return cookieHeaderValue.toString();
104     }
105 
106     @Override
getCookie(String s, boolean b)107     public String getCookie(String s, boolean b) {
108       return null;
109     }
110 
filter(String domain)111     private List<Cookie> filter(String domain) {
112       return filter(domain, false);
113     }
114 
filter(String domain, boolean isSecure)115     private List<Cookie> filter(String domain, boolean isSecure) {
116       List<Cookie> matchedCookies = new ArrayList<>();
117       Date now = new Date();
118       for (Cookie cookie : store) {
119         if (cookie.isSameHost(domain)
120           && (isSecure == cookie.isSecure() || isSecure)) {
121             matchedCookies.add(cookie);
122         }
123       }
124       return matchedCookies;
125     }
126 
setAcceptCookie(boolean accept)127     @Override public void setAcceptCookie(boolean accept) {
128       this.accept = accept;
129     }
130 
acceptCookie()131     @Override public boolean acceptCookie() {
132       return this.accept;
133     }
134 
removeAllCookie()135     public void removeAllCookie() {
136       store.clear();
137     }
138 
removeExpiredCookie()139     public void removeExpiredCookie() {
140       List<Cookie> expired = new ArrayList<>();
141       Date now = new Date();
142 
143       for (Cookie cookie : store) {
144         if (cookie.isExpiredAt(now)) {
145           expired.add(cookie);
146         }
147       }
148 
149       store.removeAll(expired);
150     }
151 
hasCookies()152     @Override public boolean hasCookies() {
153       return !store.isEmpty();
154     }
155 
156     @Override
hasCookies(boolean b)157     public boolean hasCookies(boolean b) {
158       return false;
159     }
160 
removeSessionCookie()161     public void removeSessionCookie() {
162       synchronized (store) {
163         clearAndAddPersistentCookies();
164       }
165     }
166 
167     @Override
allowFileSchemeCookiesImpl()168     protected boolean allowFileSchemeCookiesImpl() {
169       return false;
170     }
171 
172     @Override
setAcceptFileSchemeCookiesImpl(boolean b)173     protected void setAcceptFileSchemeCookiesImpl(boolean b) {
174 
175     }
176 
clearAndAddPersistentCookies()177     private void clearAndAddPersistentCookies() {
178       List<Cookie> existing = new ArrayList<>(store);
179       store.clear();
180       for (Cookie cookie : existing) {
181         if (cookie.isPersistent()) {
182           store.add(cookie);
183         }
184       }
185     }
186 
parseCookies(String url, String cookieHeader)187     private List<Cookie> parseCookies(String url, String cookieHeader) {
188     String[] fields = cookieHeader.split(";", 0);
189 
190       List<String> parsedFields = new ArrayList<>();
191       Date expiration = null;
192       boolean isSecure = false;
193 
194       for (String field : fields) {
195         field = field.trim();
196         if (field.startsWith(EXPIRATION_FIELD_NAME)) {
197           expiration = getExpiration(field);
198         } else if (field.toUpperCase().equals(SECURE_ATTR_NAME)) {
199           isSecure = true;
200         } else {
201           parsedFields.add(field);
202         }
203       }
204 
205       String hostname = getCookieHost(url);
206       List<Cookie> cookies = new ArrayList<>();
207 
208       for (String cookie : parsedFields) {
209         if (expiration == null || expiration.compareTo(new Date()) >= 0) {
210           cookies.add(new Cookie(hostname, isSecure, cookie, expiration));
211         }
212       }
213 
214       return cookies;
215     }
216 
getCookieHost(String url)217     private String getCookieHost(String url) {
218       if (!(url.startsWith(HTTP) || url.startsWith(HTTPS))) {
219         url = HTTP + url;
220       }
221 
222       try {
223         return new URI(url).getHost();
224       } catch (URISyntaxException e) {
225         throw new IllegalArgumentException("wrong URL : " + url, e);
226       }
227     }
228 
getExpiration(String field)229     private Date getExpiration(String field) {
230       int equalsIndex = field.indexOf("=");
231 
232       if (equalsIndex < 0) {
233         return null;
234       }
235 
236       String date = field.substring(equalsIndex + 1);
237 
238       try {
239         DateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
240         return dateFormat.parse(date);
241       } catch (ParseException e) {
242         // No-op. Try to inferFromValue additional date formats.
243       }
244 
245       try {
246         DateFormat dateFormat = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz");
247         return dateFormat.parse(date);
248       } catch (ParseException e) {
249         return null; // Was not parsed by any date formatter.
250       }
251     }
252 
253     private static class Cookie {
254       private final String mName;
255       private final String mValue;
256       private final Date mExpiration;
257       private final String mHostname;
258       private final boolean mIsSecure;
259 
Cookie(String hostname, boolean isSecure, String cookie, Date expiration)260       public Cookie(String hostname, boolean isSecure, String cookie, Date expiration) {
261         mHostname = hostname;
262         mIsSecure = isSecure;
263         mExpiration = expiration;
264 
265         int equalsIndex = cookie.indexOf("=");
266         if (equalsIndex >= 0) {
267           mName = cookie.substring(0, equalsIndex);
268           mValue = cookie.substring(equalsIndex + 1);
269         } else {
270           mName = cookie;
271           mValue = null;
272         }
273       }
274 
getName()275       public String getName() {
276         return mName;
277       }
278 
getValue()279       public String getValue() {
280         return mValue;
281       }
282 
isExpiredAt(Date date)283       public boolean isExpiredAt(Date date) {
284         return mExpiration != null && mExpiration.compareTo(date) < 0;
285       }
286 
isPersistent()287       public boolean isPersistent() {
288         return mExpiration != null;
289       }
290 
isSameHost(String host)291       public boolean isSameHost(String host) {
292         return mHostname.endsWith(host);
293       }
294 
isSecure()295       public boolean isSecure() {
296         return mIsSecure;
297       }
298     }
299   }
300