< prev index next >

modules/javafx.web/src/main/java/com/sun/webkit/network/CookieStore.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.webkit.network;
  27 



  28 import java.util.LinkedHashMap;
  29 import java.util.Comparator;
  30 import java.util.Collections;
  31 import java.util.ArrayList;
  32 import java.util.HashMap;
  33 import java.util.Iterator;
  34 import java.util.List;
  35 import java.util.Map;
  36 import java.util.PriorityQueue;
  37 import java.util.Queue;
  38 import java.util.logging.Level;
  39 import java.util.logging.Logger;
  40 
  41 /**
  42  * A cookie store.
  43  */
  44 final class CookieStore {
  45 
  46     private static final Logger logger =
  47         Logger.getLogger(CookieStore.class.getName());
  48 
  49     private static final int MAX_BUCKET_SIZE = 50;
  50     private static final int TOTAL_COUNT_LOWER_THRESHOLD = 3000;
  51     private static final int TOTAL_COUNT_UPPER_THRESHOLD = 4000;
  52 
  53 
  54     /**
  55      * The mapping from domain names to cookie buckets.
  56      * Each cookie bucket stores the cookies associated with the
  57      * corresponding domain. Each cookie bucket is represented
  58      * by a Map<Cookie,Cookie> to facilitate retrieval of a cookie
  59      * by another cookie with the same name, domain, and path.
  60      */
  61     private final Map<String,Map<Cookie,Cookie>> buckets =
  62             new HashMap<String,Map<Cookie,Cookie>>();
  63 
  64     /**
  65      * The total number of cookies currently in the store.
  66      */
  67     private int totalCount = 0;


  87         if (storedCookie == null) {
  88             return null;
  89         }
  90         if (storedCookie.hasExpired()) {
  91             bucket.remove(storedCookie);
  92             totalCount--;
  93             log("Expired cookie removed by get", storedCookie, bucket);
  94             return null;
  95         }
  96         return storedCookie;
  97     }
  98 
  99 
 100     /**
 101      * Returns all the currently stored cookies that match the given query.
 102      */
 103     List<Cookie> get(String hostname, String path, boolean secureProtocol,
 104             boolean httpApi)
 105     {
 106         if (logger.isLoggable(Level.FINEST)) {
 107             logger.log(Level.FINEST, "hostname: [{0}], path: [{1}], "
 108                     + "secureProtocol: [{2}], httpApi: [{3}]", new Object[] {
 109                     hostname, path, secureProtocol, httpApi});
 110         }
 111 
 112         ArrayList<Cookie> result = new ArrayList<Cookie>();
 113 
 114         String domain = hostname;
 115         while (domain.length() > 0) {
 116             Map<Cookie,Cookie> bucket = buckets.get(domain);
 117             if (bucket != null) {
 118                 find(result, bucket, hostname, path, secureProtocol, httpApi);
 119             }
 120             int nextPoint = domain.indexOf('.');
 121             if (nextPoint != -1) {
 122                 domain = domain.substring(nextPoint + 1);
 123             } else {
 124                 break;
 125             }
 126         }
 127 
 128         Collections.sort(result, new GetComparator());
 129 
 130         long currentTime = System.currentTimeMillis();
 131         for (Cookie cookie : result) {
 132             cookie.setLastAccessTime(currentTime);
 133         }
 134 
 135         logger.log(Level.FINEST, "result: {0}", result);
 136         return result;
 137     }
 138 
 139     /**
 140      * Finds all the cookies that are stored in the given bucket and
 141      * match the given query.
 142      */
 143     private void find(List<Cookie> list, Map<Cookie,Cookie> bucket,
 144             String hostname, String path, boolean secureProtocol,
 145             boolean httpApi)
 146     {
 147         Iterator<Cookie> it = bucket.values().iterator();
 148         while (it.hasNext()) {
 149             Cookie cookie = it.next();
 150             if (cookie.hasExpired()) {
 151                 it.remove();
 152                 totalCount--;
 153                 log("Expired cookie removed by find", cookie, bucket);
 154                 continue;
 155             }


 209         } else {
 210             if (bucket.put(cookie, cookie) == null) {
 211                 totalCount++;
 212                 log("Cookie added", cookie, bucket);
 213                 if (bucket.size() > MAX_BUCKET_SIZE) {
 214                     purge(bucket);
 215                 }
 216                 if (totalCount > TOTAL_COUNT_UPPER_THRESHOLD) {
 217                     purge();
 218                 }
 219             } else {
 220                 log("Cookie updated", cookie, bucket);
 221             }
 222         }
 223     }
 224 
 225     /**
 226      * Removes excess cookies from a given bucket.
 227      */
 228     private void purge(Map<Cookie,Cookie> bucket) {
 229         logger.log(Level.FINEST, "Purging bucket: {0}", bucket.values());
 230 
 231         Cookie earliestCookie = null;
 232         Iterator<Cookie> it = bucket.values().iterator();
 233         while (it.hasNext()) {
 234             Cookie cookie = it.next();
 235             if (cookie.hasExpired()) {
 236                 it.remove();
 237                 totalCount--;
 238                 log("Expired cookie removed", cookie, bucket);
 239             } else {
 240                 if (earliestCookie == null || cookie.getLastAccessTime()
 241                         < earliestCookie.getLastAccessTime())
 242                 {
 243                     earliestCookie = cookie;
 244                 }
 245             }
 246         }
 247         if (bucket.size() > MAX_BUCKET_SIZE) {
 248             bucket.remove(earliestCookie);
 249             totalCount--;
 250             log("Excess cookie removed", earliestCookie, bucket);
 251         }
 252     }
 253 
 254     /**
 255      * Removes excess cookies globally.
 256      */
 257     private void purge() {
 258         logger.log(Level.FINEST, "Purging store");
 259 
 260         Queue<Cookie> removalQueue = new PriorityQueue<Cookie>(totalCount / 2,
 261                 new RemovalComparator());
 262 
 263         for (Map.Entry<String,Map<Cookie,Cookie>> entry : buckets.entrySet()) {
 264             Map<Cookie,Cookie> bucket = entry.getValue();
 265             Iterator<Cookie> it = bucket.values().iterator();
 266             while (it.hasNext()) {
 267                 Cookie cookie = it.next();
 268                 if (cookie.hasExpired()) {
 269                     it.remove();
 270                     totalCount--;
 271                     log("Expired cookie removed", cookie, bucket);
 272                 } else {
 273                     removalQueue.add(cookie);
 274                 }
 275             }
 276         }
 277 
 278         while (totalCount > TOTAL_COUNT_LOWER_THRESHOLD) {


 283                 totalCount--;
 284                 log("Excess cookie removed", cookie, bucket);
 285             }
 286         }
 287     }
 288 
 289     private static final class RemovalComparator implements Comparator<Cookie> {
 290         @Override
 291         public int compare(Cookie c1, Cookie c2) {
 292             return (int) (c1.getLastAccessTime() - c2.getLastAccessTime());
 293         }
 294     }
 295 
 296     /**
 297      * Logs a cookie event.
 298      */
 299     private void log(String message, Cookie cookie,
 300             Map<Cookie,Cookie> bucket)
 301     {
 302         if (logger.isLoggable(Level.FINEST)) {
 303             logger.log(Level.FINEST, "{0}: {1}, bucket size: {2}, "
 304                     + "total count: {3}",
 305                     new Object[] {message, cookie, bucket.size(), totalCount});
 306         }
 307     }
 308 }


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.webkit.network;
  27 
  28 import com.sun.javafx.logging.PlatformLogger;
  29 import com.sun.javafx.logging.PlatformLogger.Level;
  30 
  31 import java.util.LinkedHashMap;
  32 import java.util.Comparator;
  33 import java.util.Collections;
  34 import java.util.ArrayList;
  35 import java.util.HashMap;
  36 import java.util.Iterator;
  37 import java.util.List;
  38 import java.util.Map;
  39 import java.util.PriorityQueue;
  40 import java.util.Queue;


  41 
  42 /**
  43  * A cookie store.
  44  */
  45 final class CookieStore {
  46 
  47     private static final PlatformLogger logger =
  48             PlatformLogger.getLogger(CookieStore.class.getName());
  49 
  50     private static final int MAX_BUCKET_SIZE = 50;
  51     private static final int TOTAL_COUNT_LOWER_THRESHOLD = 3000;
  52     private static final int TOTAL_COUNT_UPPER_THRESHOLD = 4000;
  53 
  54 
  55     /**
  56      * The mapping from domain names to cookie buckets.
  57      * Each cookie bucket stores the cookies associated with the
  58      * corresponding domain. Each cookie bucket is represented
  59      * by a Map<Cookie,Cookie> to facilitate retrieval of a cookie
  60      * by another cookie with the same name, domain, and path.
  61      */
  62     private final Map<String,Map<Cookie,Cookie>> buckets =
  63             new HashMap<String,Map<Cookie,Cookie>>();
  64 
  65     /**
  66      * The total number of cookies currently in the store.
  67      */
  68     private int totalCount = 0;


  88         if (storedCookie == null) {
  89             return null;
  90         }
  91         if (storedCookie.hasExpired()) {
  92             bucket.remove(storedCookie);
  93             totalCount--;
  94             log("Expired cookie removed by get", storedCookie, bucket);
  95             return null;
  96         }
  97         return storedCookie;
  98     }
  99 
 100 
 101     /**
 102      * Returns all the currently stored cookies that match the given query.
 103      */
 104     List<Cookie> get(String hostname, String path, boolean secureProtocol,
 105             boolean httpApi)
 106     {
 107         if (logger.isLoggable(Level.FINEST)) {
 108             logger.finest("hostname: [{0}], path: [{1}], "
 109                     + "secureProtocol: [{2}], httpApi: [{3}]", new Object[] {
 110                     hostname, path, secureProtocol, httpApi});
 111         }
 112 
 113         ArrayList<Cookie> result = new ArrayList<Cookie>();
 114 
 115         String domain = hostname;
 116         while (domain.length() > 0) {
 117             Map<Cookie,Cookie> bucket = buckets.get(domain);
 118             if (bucket != null) {
 119                 find(result, bucket, hostname, path, secureProtocol, httpApi);
 120             }
 121             int nextPoint = domain.indexOf('.');
 122             if (nextPoint != -1) {
 123                 domain = domain.substring(nextPoint + 1);
 124             } else {
 125                 break;
 126             }
 127         }
 128 
 129         Collections.sort(result, new GetComparator());
 130 
 131         long currentTime = System.currentTimeMillis();
 132         for (Cookie cookie : result) {
 133             cookie.setLastAccessTime(currentTime);
 134         }
 135 
 136         logger.finest("result: {0}", result);
 137         return result;
 138     }
 139 
 140     /**
 141      * Finds all the cookies that are stored in the given bucket and
 142      * match the given query.
 143      */
 144     private void find(List<Cookie> list, Map<Cookie,Cookie> bucket,
 145             String hostname, String path, boolean secureProtocol,
 146             boolean httpApi)
 147     {
 148         Iterator<Cookie> it = bucket.values().iterator();
 149         while (it.hasNext()) {
 150             Cookie cookie = it.next();
 151             if (cookie.hasExpired()) {
 152                 it.remove();
 153                 totalCount--;
 154                 log("Expired cookie removed by find", cookie, bucket);
 155                 continue;
 156             }


 210         } else {
 211             if (bucket.put(cookie, cookie) == null) {
 212                 totalCount++;
 213                 log("Cookie added", cookie, bucket);
 214                 if (bucket.size() > MAX_BUCKET_SIZE) {
 215                     purge(bucket);
 216                 }
 217                 if (totalCount > TOTAL_COUNT_UPPER_THRESHOLD) {
 218                     purge();
 219                 }
 220             } else {
 221                 log("Cookie updated", cookie, bucket);
 222             }
 223         }
 224     }
 225 
 226     /**
 227      * Removes excess cookies from a given bucket.
 228      */
 229     private void purge(Map<Cookie,Cookie> bucket) {
 230         logger.finest("Purging bucket: {0}", bucket.values());
 231 
 232         Cookie earliestCookie = null;
 233         Iterator<Cookie> it = bucket.values().iterator();
 234         while (it.hasNext()) {
 235             Cookie cookie = it.next();
 236             if (cookie.hasExpired()) {
 237                 it.remove();
 238                 totalCount--;
 239                 log("Expired cookie removed", cookie, bucket);
 240             } else {
 241                 if (earliestCookie == null || cookie.getLastAccessTime()
 242                         < earliestCookie.getLastAccessTime())
 243                 {
 244                     earliestCookie = cookie;
 245                 }
 246             }
 247         }
 248         if (bucket.size() > MAX_BUCKET_SIZE) {
 249             bucket.remove(earliestCookie);
 250             totalCount--;
 251             log("Excess cookie removed", earliestCookie, bucket);
 252         }
 253     }
 254 
 255     /**
 256      * Removes excess cookies globally.
 257      */
 258     private void purge() {
 259         logger.finest("Purging store");
 260 
 261         Queue<Cookie> removalQueue = new PriorityQueue<Cookie>(totalCount / 2,
 262                 new RemovalComparator());
 263 
 264         for (Map.Entry<String,Map<Cookie,Cookie>> entry : buckets.entrySet()) {
 265             Map<Cookie,Cookie> bucket = entry.getValue();
 266             Iterator<Cookie> it = bucket.values().iterator();
 267             while (it.hasNext()) {
 268                 Cookie cookie = it.next();
 269                 if (cookie.hasExpired()) {
 270                     it.remove();
 271                     totalCount--;
 272                     log("Expired cookie removed", cookie, bucket);
 273                 } else {
 274                     removalQueue.add(cookie);
 275                 }
 276             }
 277         }
 278 
 279         while (totalCount > TOTAL_COUNT_LOWER_THRESHOLD) {


 284                 totalCount--;
 285                 log("Excess cookie removed", cookie, bucket);
 286             }
 287         }
 288     }
 289 
 290     private static final class RemovalComparator implements Comparator<Cookie> {
 291         @Override
 292         public int compare(Cookie c1, Cookie c2) {
 293             return (int) (c1.getLastAccessTime() - c2.getLastAccessTime());
 294         }
 295     }
 296 
 297     /**
 298      * Logs a cookie event.
 299      */
 300     private void log(String message, Cookie cookie,
 301             Map<Cookie,Cookie> bucket)
 302     {
 303         if (logger.isLoggable(Level.FINEST)) {
 304             logger.finest("{0}: {1}, bucket size: {2}, total count: {3}",

 305                     new Object[] {message, cookie, bucket.size(), totalCount});
 306         }
 307     }
 308 }
< prev index next >