45 */
46 class InMemoryCookieStore implements CookieStore {
47 // the in-memory representation of cookies
48 private List<HttpCookie> cookieJar = null;
49
50 // the cookies are indexed by its domain and associated uri (if present)
51 // CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
52 // it won't be cleared in domainIndex & uriIndex. Double-check the
53 // presence of cookie when retrieve one form index store.
54 private Map<String, List<HttpCookie>> domainIndex = null;
55 private Map<URI, List<HttpCookie>> uriIndex = null;
56
57 // use ReentrantLock instead of syncronized for scalability
58 private ReentrantLock lock = null;
59
60
61 /**
62 * The default ctor
63 */
64 public InMemoryCookieStore() {
65 cookieJar = new ArrayList<HttpCookie>();
66 domainIndex = new HashMap<String, List<HttpCookie>>();
67 uriIndex = new HashMap<URI, List<HttpCookie>>();
68
69 lock = new ReentrantLock(false);
70 }
71
72 /**
73 * Add one cookie into cookie store.
74 */
75 public void add(URI uri, HttpCookie cookie) {
76 // pre-condition : argument can't be null
77 if (cookie == null) {
78 throw new NullPointerException("cookie is null");
79 }
80
81
82 lock.lock();
83 try {
84 // remove the ole cookie if there has had one
85 cookieJar.remove(cookie);
86
87 // add new cookie if it has a non-zero max-age
98 }
99 } finally {
100 lock.unlock();
101 }
102 }
103
104
105 /**
106 * Get all cookies, which:
107 * 1) given uri domain-matches with, or, associated with
108 * given uri when added to the cookie store.
109 * 3) not expired.
110 * See RFC 2965 sec. 3.3.4 for more detail.
111 */
112 public List<HttpCookie> get(URI uri) {
113 // argument can't be null
114 if (uri == null) {
115 throw new NullPointerException("uri is null");
116 }
117
118 List<HttpCookie> cookies = new ArrayList<HttpCookie>();
119 boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
120 lock.lock();
121 try {
122 // check domainIndex first
123 getInternal1(cookies, domainIndex, uri.getHost(), secureLink);
124 // check uriIndex then
125 getInternal2(cookies, uriIndex, getEffectiveURI(uri), secureLink);
126 } finally {
127 lock.unlock();
128 }
129
130 return cookies;
131 }
132
133 /**
134 * Get all cookies in cookie store, except those have expired
135 */
136 public List<HttpCookie> getCookies() {
137 List<HttpCookie> rt;
138
140 try {
141 Iterator<HttpCookie> it = cookieJar.iterator();
142 while (it.hasNext()) {
143 if (it.next().hasExpired()) {
144 it.remove();
145 }
146 }
147 } finally {
148 rt = Collections.unmodifiableList(cookieJar);
149 lock.unlock();
150 }
151
152 return rt;
153 }
154
155 /**
156 * Get all URIs, which are associated with at least one cookie
157 * of this cookie store.
158 */
159 public List<URI> getURIs() {
160 List<URI> uris = new ArrayList<URI>();
161
162 lock.lock();
163 try {
164 Iterator<URI> it = uriIndex.keySet().iterator();
165 while (it.hasNext()) {
166 URI uri = it.next();
167 List<HttpCookie> cookies = uriIndex.get(uri);
168 if (cookies == null || cookies.size() == 0) {
169 // no cookies list or an empty list associated with
170 // this uri entry, delete it
171 it.remove();
172 }
173 }
174 } finally {
175 uris.addAll(uriIndex.keySet());
176 lock.unlock();
177 }
178
179 return uris;
180 }
264 return host.equalsIgnoreCase(domain);
265 } else if (lengthDiff > 0) {
266 // need to check H & D component
267 String H = host.substring(0, lengthDiff);
268 String D = host.substring(lengthDiff);
269
270 return (D.equalsIgnoreCase(domain));
271 } else if (lengthDiff == -1) {
272 // if domain is actually .host
273 return (domain.charAt(0) == '.' &&
274 host.equalsIgnoreCase(domain.substring(1)));
275 }
276
277 return false;
278 }
279
280 private void getInternal1(List<HttpCookie> cookies, Map<String, List<HttpCookie>> cookieIndex,
281 String host, boolean secureLink) {
282 // Use a separate list to handle cookies that need to be removed so
283 // that there is no conflict with iterators.
284 ArrayList<HttpCookie> toRemove = new ArrayList<HttpCookie>();
285 for (Map.Entry<String, List<HttpCookie>> entry : cookieIndex.entrySet()) {
286 String domain = entry.getKey();
287 List<HttpCookie> lst = entry.getValue();
288 for (HttpCookie c : lst) {
289 if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
290 (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
291 if ((cookieJar.indexOf(c) != -1)) {
292 // the cookie still in main cookie store
293 if (!c.hasExpired()) {
294 // don't add twice and make sure it's the proper
295 // security level
296 if ((secureLink || !c.getSecure()) &&
297 !cookies.contains(c)) {
298 cookies.add(c);
299 }
300 } else {
301 toRemove.add(c);
302 }
303 } else {
304 // the cookie has beed removed from main store,
351 }
352 }
353 } // end of indexedCookies != null
354 } // end of comparator.compareTo(index) == 0
355 } // end of cookieIndex iteration
356 }
357
358 // add 'cookie' indexed by 'index' into 'indexStore'
359 private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
360 T index,
361 HttpCookie cookie)
362 {
363 if (index != null) {
364 List<HttpCookie> cookies = indexStore.get(index);
365 if (cookies != null) {
366 // there may already have the same cookie, so remove it first
367 cookies.remove(cookie);
368
369 cookies.add(cookie);
370 } else {
371 cookies = new ArrayList<HttpCookie>();
372 cookies.add(cookie);
373 indexStore.put(index, cookies);
374 }
375 }
376 }
377
378
379 //
380 // for cookie purpose, the effective uri should only be http://host
381 // the path will be taken into account when path-match algorithm applied
382 //
383 private URI getEffectiveURI(URI uri) {
384 URI effectiveURI = null;
385 try {
386 effectiveURI = new URI("http",
387 uri.getHost(),
388 null, // path component
389 null, // query component
390 null // fragment component
391 );
|
45 */
46 class InMemoryCookieStore implements CookieStore {
47 // the in-memory representation of cookies
48 private List<HttpCookie> cookieJar = null;
49
50 // the cookies are indexed by its domain and associated uri (if present)
51 // CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
52 // it won't be cleared in domainIndex & uriIndex. Double-check the
53 // presence of cookie when retrieve one form index store.
54 private Map<String, List<HttpCookie>> domainIndex = null;
55 private Map<URI, List<HttpCookie>> uriIndex = null;
56
57 // use ReentrantLock instead of syncronized for scalability
58 private ReentrantLock lock = null;
59
60
61 /**
62 * The default ctor
63 */
64 public InMemoryCookieStore() {
65 cookieJar = new ArrayList<>();
66 domainIndex = new HashMap<>();
67 uriIndex = new HashMap<>();
68
69 lock = new ReentrantLock(false);
70 }
71
72 /**
73 * Add one cookie into cookie store.
74 */
75 public void add(URI uri, HttpCookie cookie) {
76 // pre-condition : argument can't be null
77 if (cookie == null) {
78 throw new NullPointerException("cookie is null");
79 }
80
81
82 lock.lock();
83 try {
84 // remove the ole cookie if there has had one
85 cookieJar.remove(cookie);
86
87 // add new cookie if it has a non-zero max-age
98 }
99 } finally {
100 lock.unlock();
101 }
102 }
103
104
105 /**
106 * Get all cookies, which:
107 * 1) given uri domain-matches with, or, associated with
108 * given uri when added to the cookie store.
109 * 3) not expired.
110 * See RFC 2965 sec. 3.3.4 for more detail.
111 */
112 public List<HttpCookie> get(URI uri) {
113 // argument can't be null
114 if (uri == null) {
115 throw new NullPointerException("uri is null");
116 }
117
118 List<HttpCookie> cookies = new ArrayList<>();
119 boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
120 lock.lock();
121 try {
122 // check domainIndex first
123 getInternal1(cookies, domainIndex, uri.getHost(), secureLink);
124 // check uriIndex then
125 getInternal2(cookies, uriIndex, getEffectiveURI(uri), secureLink);
126 } finally {
127 lock.unlock();
128 }
129
130 return cookies;
131 }
132
133 /**
134 * Get all cookies in cookie store, except those have expired
135 */
136 public List<HttpCookie> getCookies() {
137 List<HttpCookie> rt;
138
140 try {
141 Iterator<HttpCookie> it = cookieJar.iterator();
142 while (it.hasNext()) {
143 if (it.next().hasExpired()) {
144 it.remove();
145 }
146 }
147 } finally {
148 rt = Collections.unmodifiableList(cookieJar);
149 lock.unlock();
150 }
151
152 return rt;
153 }
154
155 /**
156 * Get all URIs, which are associated with at least one cookie
157 * of this cookie store.
158 */
159 public List<URI> getURIs() {
160 List<URI> uris = new ArrayList<>();
161
162 lock.lock();
163 try {
164 Iterator<URI> it = uriIndex.keySet().iterator();
165 while (it.hasNext()) {
166 URI uri = it.next();
167 List<HttpCookie> cookies = uriIndex.get(uri);
168 if (cookies == null || cookies.size() == 0) {
169 // no cookies list or an empty list associated with
170 // this uri entry, delete it
171 it.remove();
172 }
173 }
174 } finally {
175 uris.addAll(uriIndex.keySet());
176 lock.unlock();
177 }
178
179 return uris;
180 }
264 return host.equalsIgnoreCase(domain);
265 } else if (lengthDiff > 0) {
266 // need to check H & D component
267 String H = host.substring(0, lengthDiff);
268 String D = host.substring(lengthDiff);
269
270 return (D.equalsIgnoreCase(domain));
271 } else if (lengthDiff == -1) {
272 // if domain is actually .host
273 return (domain.charAt(0) == '.' &&
274 host.equalsIgnoreCase(domain.substring(1)));
275 }
276
277 return false;
278 }
279
280 private void getInternal1(List<HttpCookie> cookies, Map<String, List<HttpCookie>> cookieIndex,
281 String host, boolean secureLink) {
282 // Use a separate list to handle cookies that need to be removed so
283 // that there is no conflict with iterators.
284 ArrayList<HttpCookie> toRemove = new ArrayList<>();
285 for (Map.Entry<String, List<HttpCookie>> entry : cookieIndex.entrySet()) {
286 String domain = entry.getKey();
287 List<HttpCookie> lst = entry.getValue();
288 for (HttpCookie c : lst) {
289 if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
290 (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
291 if ((cookieJar.indexOf(c) != -1)) {
292 // the cookie still in main cookie store
293 if (!c.hasExpired()) {
294 // don't add twice and make sure it's the proper
295 // security level
296 if ((secureLink || !c.getSecure()) &&
297 !cookies.contains(c)) {
298 cookies.add(c);
299 }
300 } else {
301 toRemove.add(c);
302 }
303 } else {
304 // the cookie has beed removed from main store,
351 }
352 }
353 } // end of indexedCookies != null
354 } // end of comparator.compareTo(index) == 0
355 } // end of cookieIndex iteration
356 }
357
358 // add 'cookie' indexed by 'index' into 'indexStore'
359 private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
360 T index,
361 HttpCookie cookie)
362 {
363 if (index != null) {
364 List<HttpCookie> cookies = indexStore.get(index);
365 if (cookies != null) {
366 // there may already have the same cookie, so remove it first
367 cookies.remove(cookie);
368
369 cookies.add(cookie);
370 } else {
371 cookies = new ArrayList<>();
372 cookies.add(cookie);
373 indexStore.put(index, cookies);
374 }
375 }
376 }
377
378
379 //
380 // for cookie purpose, the effective uri should only be http://host
381 // the path will be taken into account when path-match algorithm applied
382 //
383 private URI getEffectiveURI(URI uri) {
384 URI effectiveURI = null;
385 try {
386 effectiveURI = new URI("http",
387 uri.getHost(),
388 null, // path component
389 null, // query component
390 null // fragment component
391 );
|