Home | History | Annotate | Download | only in webkit
      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 
     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
     35     public void setCookie(String s, String s1, ValueCallback<Boolean> valueCallback) {
     36 
     37     }
     38 
     39     @Override
     40     public void setAcceptThirdPartyCookies(WebView webView, boolean b) {
     41 
     42     }
     43 
     44     @Override
     45     public boolean acceptThirdPartyCookies(WebView webView) {
     46       return false;
     47     }
     48 
     49     @Override
     50     public void removeAllCookies(ValueCallback<Boolean> valueCallback) {
     51 
     52     }
     53 
     54     @Override
     55     public void flush() {
     56 
     57     }
     58 
     59     @Override
     60     public void removeSessionCookies(ValueCallback<Boolean> valueCallback) {
     61 
     62     }
     63 
     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
    107     public String getCookie(String s, boolean b) {
    108       return null;
    109     }
    110 
    111     private List<Cookie> filter(String domain) {
    112       return filter(domain, false);
    113     }
    114 
    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 
    127     @Override public void setAcceptCookie(boolean accept) {
    128       this.accept = accept;
    129     }
    130 
    131     @Override public boolean acceptCookie() {
    132       return this.accept;
    133     }
    134 
    135     public void removeAllCookie() {
    136       store.clear();
    137     }
    138 
    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 
    152     @Override public boolean hasCookies() {
    153       return !store.isEmpty();
    154     }
    155 
    156     @Override
    157     public boolean hasCookies(boolean b) {
    158       return false;
    159     }
    160 
    161     public void removeSessionCookie() {
    162       synchronized (store) {
    163         clearAndAddPersistentCookies();
    164       }
    165     }
    166 
    167     @Override
    168     protected boolean allowFileSchemeCookiesImpl() {
    169       return false;
    170     }
    171 
    172     @Override
    173     protected void setAcceptFileSchemeCookiesImpl(boolean b) {
    174 
    175     }
    176 
    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 
    187     private List<Cookie> parseCookies(String url, String cookieHeader) {
    188       String[] fields = cookieHeader.split(";");
    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 
    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 
    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 
    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 
    275       public String getName() {
    276         return mName;
    277       }
    278 
    279       public String getValue() {
    280         return mValue;
    281       }
    282 
    283       public boolean isExpiredAt(Date date) {
    284         return mExpiration != null && mExpiration.compareTo(date) < 0;
    285       }
    286 
    287       public boolean isPersistent() {
    288         return mExpiration != null;
    289       }
    290 
    291       public boolean isSameHost(String host) {
    292         return mHostname.endsWith(host);
    293       }
    294 
    295       public boolean isSecure() {
    296         return mIsSecure;
    297       }
    298     }
    299   }