History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/net/InMemoryCookieStore.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/net/InMemoryCookieStore.java+393−0
@@ -0,0 +1,393 @@
1+/*
2+ * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
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 java.net;
27+
28+import java.net.URI;
29+import java.net.CookieStore;
30+import java.net.HttpCookie;
31+import java.net.URISyntaxException;
32+import java.util.List;
33+import java.util.Map;
34+import java.util.ArrayList;
35+import java.util.HashMap;
36+import java.util.Collections;
37+import java.util.Iterator;
38+import java.util.concurrent.locks.ReentrantLock;
39+
40+/**
41+ * A simple in-memory java.net.CookieStore implementation
42+ *
43+ * @author Edward Wang
44+ * @since 1.6
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
88+ if (cookie.getMaxAge() != 0) {
89+ cookieJar.add(cookie);
90+ // and add it to domain index
91+ if (cookie.getDomain() != null) {
92+ addIndex(domainIndex, cookie.getDomain(), cookie);
93+ }
94+ // add it to uri index, too
95+ addIndex(uriIndex, getEffectiveURI(uri), cookie);
96+ }
97+ } finally {
98+ lock.unlock();
99+ }
100+ }
101+
102+
103+ /**
104+ * Get all cookies, which:
105+ * 1) given uri domain-matches with, or, associated with
106+ * given uri when added to the cookie store.
107+ * 3) not expired.
108+ * See RFC 2965 sec. 3.3.4 for more detail.
109+ */
110+ public List<HttpCookie> get(URI uri) {
111+ // argument can't be null
112+ if (uri == null) {
113+ throw new NullPointerException("uri is null");
114+ }
115+
116+ List<HttpCookie> cookies = new ArrayList<HttpCookie>();
117+ boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
118+ lock.lock();
119+ try {
120+ // check domainIndex first
121+ getInternal1(cookies, domainIndex, uri.getHost(), secureLink);
122+ // check uriIndex then
123+ getInternal2(cookies, uriIndex, getEffectiveURI(uri), secureLink);
124+ } finally {
125+ lock.unlock();
126+ }
127+
128+ return cookies;
129+ }
130+
131+ /**
132+ * Get all cookies in cookie store, except those have expired
133+ */
134+ public List<HttpCookie> getCookies() {
135+ List<HttpCookie> rt;
136+
137+ lock.lock();
138+ try {
139+ Iterator<HttpCookie> it = cookieJar.iterator();
140+ while (it.hasNext()) {
141+ if (it.next().hasExpired()) {
142+ it.remove();
143+ }
144+ }
145+ } finally {
146+ rt = Collections.unmodifiableList(cookieJar);
147+ lock.unlock();
148+ }
149+
150+ return rt;
151+ }
152+
153+ /**
154+ * Get all URIs, which are associated with at least one cookie
155+ * of this cookie store.
156+ */
157+ public List<URI> getURIs() {
158+ List<URI> uris = new ArrayList<URI>();
159+
160+ lock.lock();
161+ try {
162+ Iterator<URI> it = uriIndex.keySet().iterator();
163+ while (it.hasNext()) {
164+ URI uri = it.next();
165+ List<HttpCookie> cookies = uriIndex.get(uri);
166+ if (cookies == null || cookies.size() == 0) {
167+ // no cookies list or an empty list associated with
168+ // this uri entry, delete it
169+ it.remove();
170+ }
171+ }
172+ } finally {
173+ uris.addAll(uriIndex.keySet());
174+ lock.unlock();
175+ }
176+
177+ return uris;
178+ }
179+
180+
181+ /**
182+ * Remove a cookie from store
183+ */
184+ public boolean remove(URI uri, HttpCookie ck) {
185+ // argument can't be null
186+ if (ck == null) {
187+ throw new NullPointerException("cookie is null");
188+ }
189+
190+ boolean modified = false;
191+ lock.lock();
192+ try {
193+ modified = cookieJar.remove(ck);
194+ } finally {
195+ lock.unlock();
196+ }
197+
198+ return modified;
199+ }
200+
201+
202+ /**
203+ * Remove all cookies in this cookie store.
204+ */
205+ public boolean removeAll() {
206+ lock.lock();
207+ try {
208+ cookieJar.clear();
209+ domainIndex.clear();
210+ uriIndex.clear();
211+ } finally {
212+ lock.unlock();
213+ }
214+
215+ return true;
216+ }
217+
218+
219+ /* ---------------- Private operations -------------- */
220+
221+
222+ /*
223+ * This is almost the same as HttpCookie.domainMatches except for
224+ * one difference: It won't reject cookies when the 'H' part of the
225+ * domain contains a dot ('.').
226+ * I.E.: RFC 2965 section 3.3.2 says that if host is x.y.domain.com
227+ * and the cookie domain is .domain.com, then it should be rejected.
228+ * However that's not how the real world works. Browsers don't reject and
229+ * some sites, like yahoo.com do actually expect these cookies to be
230+ * passed along.
231+ * And should be used for 'old' style cookies (aka Netscape type of cookies)
232+ */
233+ private boolean netscapeDomainMatches(String domain, String host)
234+ {
235+ if (domain == null || host == null) {
236+ return false;
237+ }
238+
239+ // if there's no embedded dot in domain and domain is not .local
240+ boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
241+ int embeddedDotInDomain = domain.indexOf('.');
242+ if (embeddedDotInDomain == 0) {
243+ embeddedDotInDomain = domain.indexOf('.', 1);
244+ }
245+ if (!isLocalDomain && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) {
246+ return false;
247+ }
248+
249+ // if the host name contains no dot and the domain name is .local
250+ int firstDotInHost = host.indexOf('.');
251+ if (firstDotInHost == -1 && isLocalDomain) {
252+ return true;
253+ }
254+
255+ int domainLength = domain.length();
256+ int lengthDiff = host.length() - domainLength;
257+ if (lengthDiff == 0) {
258+ // if the host name and the domain name are just string-compare euqal
259+ return host.equalsIgnoreCase(domain);
260+ } else if (lengthDiff > 0) {
261+ // need to check H & D component
262+ String H = host.substring(0, lengthDiff);
263+ String D = host.substring(lengthDiff);
264+
265+ return (D.equalsIgnoreCase(domain));
266+ } else if (lengthDiff == -1) {
267+ // if domain is actually .host
268+ return (domain.charAt(0) == '.' &&
269+ host.equalsIgnoreCase(domain.substring(1)));
270+ }
271+
272+ return false;
273+ }
274+
275+ private void getInternal1(List<HttpCookie> cookies, Map<String, List<HttpCookie>> cookieIndex,
276+ String host, boolean secureLink) {
277+ // Use a separate list to handle cookies that need to be removed so
278+ // that there is no conflict with iterators.
279+ ArrayList<HttpCookie> toRemove = new ArrayList<HttpCookie>();
280+ for (Map.Entry<String, List<HttpCookie>> entry : cookieIndex.entrySet()) {
281+ String domain = entry.getKey();
282+ List<HttpCookie> lst = entry.getValue();
283+ for (HttpCookie c : lst) {
284+ if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
285+ (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
286+ if ((cookieJar.indexOf(c) != -1)) {
287+ // the cookie still in main cookie store
288+ if (!c.hasExpired()) {
289+ // don't add twice and make sure it's the proper
290+ // security level
291+ if ((secureLink || !c.getSecure()) &&
292+ !cookies.contains(c)) {
293+ cookies.add(c);
294+ }
295+ } else {
296+ toRemove.add(c);
297+ }
298+ } else {
299+ // the cookie has beed removed from main store,
300+ // so also remove it from domain indexed store
301+ toRemove.add(c);
302+ }
303+ }
304+ }
305+ // Clear up the cookies that need to be removed
306+ for (HttpCookie c : toRemove) {
307+ lst.remove(c);
308+ cookieJar.remove(c);
309+
310+ }
311+ toRemove.clear();
312+ }
313+ }
314+
315+ // @param cookies [OUT] contains the found cookies
316+ // @param cookieIndex the index
317+ // @param comparator the prediction to decide whether or not
318+ // a cookie in index should be returned
319+ private <T> void getInternal2(List<HttpCookie> cookies,
320+ Map<T, List<HttpCookie>> cookieIndex,
321+ Comparable<T> comparator, boolean secureLink)
322+ {
323+ for (T index : cookieIndex.keySet()) {
324+ if (comparator.compareTo(index) == 0) {
325+ List<HttpCookie> indexedCookies = cookieIndex.get(index);
326+ // check the list of cookies associated with this domain
327+ if (indexedCookies != null) {
328+ Iterator<HttpCookie> it = indexedCookies.iterator();
329+ while (it.hasNext()) {
330+ HttpCookie ck = it.next();
331+ if (cookieJar.indexOf(ck) != -1) {
332+ // the cookie still in main cookie store
333+ if (!ck.hasExpired()) {
334+ // don't add twice
335+ if ((secureLink || !ck.getSecure()) &&
336+ !cookies.contains(ck))
337+ cookies.add(ck);
338+ } else {
339+ it.remove();
340+ cookieJar.remove(ck);
341+ }
342+ } else {
343+ // the cookie has beed removed from main store,
344+ // so also remove it from domain indexed store
345+ it.remove();
346+ }
347+ }
348+ } // end of indexedCookies != null
349+ } // end of comparator.compareTo(index) == 0
350+ } // end of cookieIndex iteration
351+ }
352+
353+ // add 'cookie' indexed by 'index' into 'indexStore'
354+ private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
355+ T index,
356+ HttpCookie cookie)
357+ {
358+ if (index != null) {
359+ List<HttpCookie> cookies = indexStore.get(index);
360+ if (cookies != null) {
361+ // there may already have the same cookie, so remove it first
362+ cookies.remove(cookie);
363+
364+ cookies.add(cookie);
365+ } else {
366+ cookies = new ArrayList<HttpCookie>();
367+ cookies.add(cookie);
368+ indexStore.put(index, cookies);
369+ }
370+ }
371+ }
372+
373+
374+ //
375+ // for cookie purpose, the effective uri should only be http://host
376+ // the path will be taken into account when path-match algorithm applied
377+ //
378+ private URI getEffectiveURI(URI uri) {
379+ URI effectiveURI = null;
380+ try {
381+ effectiveURI = new URI("http",
382+ uri.getHost(),
383+ null, // path component
384+ null, // query component
385+ null // fragment component
386+ );
387+ } catch (URISyntaxException ignored) {
388+ effectiveURI = uri;
389+ }
390+
391+ return effectiveURI;
392+ }
393+}