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 }
|