Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
CookieJar |
|
| 5.5;5,5 | ||||
CookieJar$Cookie |
|
| 5.5;5,5 |
1 | // | |
2 | // $Id: CookieJar.java 816 2009-06-26 18:49:10Z etienne_sf $ | |
3 | // | |
4 | // jupload - A file upload applet. | |
5 | // | |
6 | // Copyright 2007 The JUpload Team | |
7 | // | |
8 | // Created: 08.06.2007 | |
9 | // Creator: felfert | |
10 | // Last modified: $Date: 2009-06-26 20:49:10 +0200 (ven., 26 juin 2009) $ | |
11 | // | |
12 | // This program is free software; you can redistribute it and/or modify | |
13 | // it under the terms of the GNU General Public License as published by | |
14 | // the Free Software Foundation; either version 2 of the License, or | |
15 | // (at your option) any later version. | |
16 | // | |
17 | // This program is distributed in the hope that it will be useful, | |
18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | // GNU General Public License for more details. | |
21 | // | |
22 | // You should have received a copy of the GNU General Public License | |
23 | // along with this program; if not, write to the Free Software | |
24 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 | ||
26 | package wjhk.jupload2.upload.helper; | |
27 | ||
28 | import java.net.URL; | |
29 | import java.text.ParseException; | |
30 | import java.text.SimpleDateFormat; | |
31 | import java.util.HashMap; | |
32 | import java.util.StringTokenizer; | |
33 | import java.util.regex.Matcher; | |
34 | import java.util.regex.Pattern; | |
35 | ||
36 | import wjhk.jupload2.policies.UploadPolicy; | |
37 | ||
38 | /** | |
39 | * This class implements a container for multiple cookies in a single domain. | |
40 | * | |
41 | * @author felfert | |
42 | */ | |
43 | public class CookieJar { | |
44 | ||
45 | 0 | final static Pattern pNvPair = Pattern.compile( |
46 | "^\\s*([^=\\s]+)(\\s*=\\s*(.+))*$", Pattern.CASE_INSENSITIVE); | |
47 | ||
48 | /** | |
49 | * The current upload policy, always useful. | |
50 | */ | |
51 | 0 | private UploadPolicy uploadPolicy = null; |
52 | ||
53 | 0 | private HashMap<String, Cookie> jar = new HashMap<String, Cookie>(); |
54 | ||
55 | 0 | private String domain = null; |
56 | ||
57 | 0 | private static class Cookie implements Cloneable { |
58 | ||
59 | 0 | String domain = null; |
60 | ||
61 | 0 | String name = null; |
62 | ||
63 | 0 | String value = null; |
64 | ||
65 | 0 | String path = null; |
66 | ||
67 | 0 | long max_age = 0; |
68 | ||
69 | 0 | int version = 0; |
70 | ||
71 | 0 | int secure = 0; |
72 | ||
73 | 0 | Cookie() { |
74 | // | |
75 | 0 | } |
76 | ||
77 | /** | |
78 | * @throws CloneNotSupportedException | |
79 | * @see java.lang.Object#clone() | |
80 | */ | |
81 | @Override | |
82 | public Cookie clone() throws CloneNotSupportedException { | |
83 | 0 | Cookie ret = (Cookie) super.clone(); |
84 | 0 | ret.domain = this.domain; |
85 | 0 | ret.name = this.name; |
86 | 0 | ret.value = this.value; |
87 | 0 | ret.path = this.path; |
88 | 0 | ret.max_age = this.max_age; |
89 | 0 | ret.version = this.version; |
90 | 0 | ret.secure = this.secure; |
91 | 0 | return ret; |
92 | } | |
93 | ||
94 | /** | |
95 | * Retrieves the hash value of this cookie. Cookies are hashed by name | |
96 | * and path. | |
97 | * | |
98 | * @return The hash value of this cookie. | |
99 | */ | |
100 | public String getKey() { | |
101 | 0 | String ret = this.name; |
102 | 0 | if (null != this.path) |
103 | 0 | ret += this.path; |
104 | 0 | return ret; |
105 | } | |
106 | ||
107 | /** | |
108 | * Returns a single client cookie header element | |
109 | * | |
110 | * @param path The path of the corresponding request URI | |
111 | * @param secure 1, if the current connection is secure (SSL), 0 | |
112 | * otherwise | |
113 | * @return The part of the cookie header or an empty string | |
114 | */ | |
115 | public String getHeader(String path, int secure) { | |
116 | 0 | StringBuffer sb = new StringBuffer(); |
117 | 0 | if ((null == this.path || this.path.equals("/") || this.path |
118 | 0 | .startsWith(path)) |
119 | && (this.secure <= secure) | |
120 | 0 | && (this.max_age > System.currentTimeMillis())) { |
121 | 0 | if (this.version > 0) { |
122 | 0 | sb.append("$Version=").append(this.version).append("; "); |
123 | 0 | sb.append(this.name).append("=").append(this.value).append( |
124 | ";"); | |
125 | 0 | if (null != this.path) |
126 | 0 | sb.append(" $Path=").append(this.path).append(";"); |
127 | 0 | if (null != this.domain) |
128 | 0 | sb.append(" $Domain=").append(this.domain).append(";"); |
129 | } else { | |
130 | 0 | sb.append(this.name).append("=").append(this.value).append( |
131 | ";"); | |
132 | } | |
133 | } | |
134 | 0 | return sb.toString(); |
135 | } | |
136 | ||
137 | } | |
138 | ||
139 | /* | |
140 | * ************************************************************************** | |
141 | * *************************** Start of CookieJar code | |
142 | * *********************** | |
143 | * *************************************************** | |
144 | * ************************** | |
145 | */ | |
146 | ||
147 | /** | |
148 | * The creator for this class. | |
149 | * | |
150 | * @param uploadPolicy The current upload policy | |
151 | */ | |
152 | 0 | public CookieJar(UploadPolicy uploadPolicy) { |
153 | 0 | this.uploadPolicy = uploadPolicy; |
154 | 0 | } |
155 | ||
156 | private String stripQuotes(String s) { | |
157 | 0 | if (s.startsWith("\"") && s.endsWith("\"")) |
158 | 0 | return s.substring(1, s.length() - 1); |
159 | 0 | return s; |
160 | } | |
161 | ||
162 | private boolean domainMatch(String cd) { | |
163 | 0 | if (cd == null) { |
164 | 0 | return false; |
165 | } else { | |
166 | 0 | if (!cd.startsWith(".")) { |
167 | 0 | int dot = cd.indexOf('.'); |
168 | 0 | if (dot >= 0) |
169 | 0 | cd = cd.substring(dot); |
170 | ||
171 | } | |
172 | 0 | return cd.equals(this.domain); |
173 | } | |
174 | } | |
175 | ||
176 | /** | |
177 | * Sets the domain for this cookie jar. If set, only cookies matching the | |
178 | * specified domain are handled. | |
179 | * | |
180 | * @param domain The domain of this instance | |
181 | */ | |
182 | public void setDomain(String domain) { | |
183 | 0 | if (!domain.startsWith(".")) { |
184 | 0 | int dot = domain.indexOf('.'); |
185 | 0 | if (dot >= 0) |
186 | 0 | domain = domain.substring(dot); |
187 | ||
188 | } | |
189 | 0 | this.domain = domain; |
190 | 0 | } |
191 | ||
192 | /** | |
193 | * Builds a RFC 2109 compliant client cookie header for the specified URL. | |
194 | * | |
195 | * @param url The URL for which the cookie header is to be used. | |
196 | * @return A client cookie header (including the "Cookie: " prefix) or null | |
197 | * if no cookies are to be set. | |
198 | */ | |
199 | public String buildCookieHeader(URL url) { | |
200 | 0 | String domain = url.getHost(); |
201 | 0 | int dot = domain.indexOf('.'); |
202 | 0 | if (dot >= 0) |
203 | 0 | domain = domain.substring(dot); |
204 | 0 | if (domain.equals(this.domain)) { |
205 | 0 | String path = url.getPath(); |
206 | 0 | int secure = url.getProtocol().equalsIgnoreCase("https") ? 1 : 0; |
207 | 0 | StringBuffer sb = new StringBuffer(); |
208 | 0 | for (String key : this.jar.keySet()) { |
209 | 0 | Cookie c = this.jar.get(key); |
210 | 0 | if (null != c) |
211 | 0 | sb.append(c.getHeader(path, secure)); |
212 | 0 | } |
213 | 0 | if (sb.length() > 0) { |
214 | 0 | sb.append("\r\n"); |
215 | 0 | return "Cookie: " + sb.toString(); |
216 | } | |
217 | } | |
218 | 0 | return null; |
219 | } | |
220 | ||
221 | /** | |
222 | * Parses a "Set-Cookie" header and creates/updates/deletes cookies | |
223 | * according to the parsed values. Parsing is done according to the | |
224 | * specification in RFC 2109 | |
225 | * | |
226 | * @param s The plain value of the "Set-Cookie" HTTP header. e.g.: without | |
227 | * the "Set-Cookie: " prefix. | |
228 | */ | |
229 | public void parseCookieHeader(String s) { | |
230 | 0 | StringTokenizer t = new StringTokenizer(s, ";"); |
231 | 0 | Cookie cookie = new Cookie(); |
232 | 0 | while (t.hasMoreTokens()) { |
233 | 0 | Matcher m = pNvPair.matcher(t.nextToken()); |
234 | 0 | if (m.matches()) { |
235 | 0 | String n = m.group(1); |
236 | 0 | String v = (m.groupCount() > 2 && m.group(3) != null) ? m |
237 | 0 | .group(3).trim() : ""; |
238 | 0 | if (n.compareToIgnoreCase("version") == 0) { |
239 | 0 | cookie.version = Integer.parseInt(v); |
240 | 0 | continue; |
241 | } | |
242 | 0 | if (n.compareToIgnoreCase("domain") == 0) { |
243 | 0 | cookie.domain = v; |
244 | 0 | continue; |
245 | } | |
246 | 0 | if (n.compareToIgnoreCase("path") == 0) { |
247 | 0 | cookie.path = v; |
248 | 0 | continue; |
249 | } | |
250 | 0 | if (n.compareToIgnoreCase("max-age") == 0) { |
251 | 0 | cookie.max_age = Integer.parseInt(v); |
252 | 0 | if (cookie.max_age < 0) |
253 | 0 | cookie.max_age = 0; |
254 | 0 | cookie.max_age *= 1000; |
255 | 0 | cookie.max_age += System.currentTimeMillis(); |
256 | 0 | continue; |
257 | } | |
258 | 0 | if (n.compareToIgnoreCase("expires") == 0) { |
259 | 0 | SimpleDateFormat df = new SimpleDateFormat( |
260 | "EEE, dd-MMM-yy HH:mm:ss zzz"); | |
261 | try { | |
262 | 0 | cookie.max_age = System.currentTimeMillis() |
263 | 0 | - df.parse(v).getTime(); |
264 | 0 | if (cookie.max_age < 0) |
265 | 0 | cookie.max_age = 0; |
266 | 0 | } catch (ParseException e) { |
267 | 0 | cookie.max_age = 0; |
268 | 0 | } |
269 | 0 | continue; |
270 | } | |
271 | 0 | if (n.compareToIgnoreCase("comment") == 0) { |
272 | // ignored | |
273 | 0 | continue; |
274 | } | |
275 | 0 | if (n.compareToIgnoreCase("secure") == 0) { |
276 | 0 | cookie.secure = 1; |
277 | 0 | continue; |
278 | } | |
279 | 0 | if (!n.startsWith("$")) { |
280 | 0 | if (null != cookie.name) { |
281 | 0 | if (cookie.version > 0) { |
282 | // Strip possible quotes | |
283 | 0 | cookie.domain = stripQuotes(cookie.domain); |
284 | 0 | cookie.path = stripQuotes(cookie.path); |
285 | // cookie.comment = stripQuotes(cookie.comment); | |
286 | // cookie.name = stripQuotes(cookie.name); | |
287 | // cookie.value = stripQuotes(cookie.value); | |
288 | } | |
289 | 0 | if (domainMatch(cookie.domain)) { |
290 | 0 | if (cookie.max_age > 0) { |
291 | 0 | this.jar.put(cookie.getKey(), cookie); |
292 | 0 | this.uploadPolicy.displayDebug( |
293 | "[CookieJar] Adding cookie: " | |
294 | 0 | + cookie.getKey() + ": " |
295 | + cookie, 50); | |
296 | ||
297 | } else { | |
298 | 0 | this.jar.put(cookie.getKey(), null); |
299 | 0 | this.uploadPolicy.displayDebug( |
300 | "[CookieJar] Ignoring cookie: " | |
301 | 0 | + cookie.getKey() + ": " |
302 | + cookie, 50); | |
303 | } | |
304 | } | |
305 | try { | |
306 | 0 | cookie = cookie.clone(); |
307 | 0 | } catch (CloneNotSupportedException e) { |
308 | 0 | cookie = new Cookie(); |
309 | 0 | } |
310 | } | |
311 | 0 | cookie.name = n; |
312 | 0 | cookie.value = v; |
313 | } | |
314 | } | |
315 | 0 | } |
316 | 0 | } |
317 | } |