1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.client;
20
21 import java.text.ParseException;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Locale;
27 import java.util.TimeZone;
28 import java.util.concurrent.TimeUnit;
29
30 import org.eclipse.jetty.http.HttpCookie;
31
32 public class HttpCookieParser
33 {
34 private static final String[] DATE_PATTERNS = new String[]
35 {
36 "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'",
37 "EEE',' dd MMM yyyy HH:mm:ss 'GMT'",
38 "EEE MMM dd yyyy HH:mm:ss 'GMT'Z"
39 };
40
41 private HttpCookieParser()
42 {
43 }
44
45 public static List<HttpCookie> parseCookies(String headerValue)
46 {
47 if (headerValue.toLowerCase(Locale.ENGLISH).contains("expires="))
48 {
49 HttpCookie cookie = parseCookie(headerValue, 0);
50 if (cookie != null)
51 return Collections.singletonList(cookie);
52 else
53 return Collections.emptyList();
54 }
55 else
56 {
57 List<HttpCookie> result = new ArrayList<>();
58 List<String> cookieStrings = splitCookies(headerValue);
59 for (String cookieString : cookieStrings)
60 {
61 HttpCookie cookie = parseCookie(cookieString, 1);
62 if (cookie != null)
63 result.add(cookie);
64 }
65 return result;
66 }
67 }
68
69 private static List<String> splitCookies(String headerValue)
70 {
71
72 List<String> result = new ArrayList<>();
73 int start = 0;
74 int quotes = 0;
75 for (int i = 0; i < headerValue.length(); ++i)
76 {
77 char c = headerValue.charAt(i);
78 if (c == ',' && quotes % 2 == 0)
79 {
80 result.add(headerValue.substring(start, i));
81 start = i + 1;
82 }
83 else if (c == '"')
84 {
85 ++quotes;
86 }
87 }
88 result.add(headerValue.substring(start));
89 return result;
90 }
91
92 private static HttpCookie parseCookie(String cookieString, int version)
93 {
94 String[] cookieParts = cookieString.split(";");
95
96 String nameValue = cookieParts[0];
97 int equal = nameValue.indexOf('=');
98 if (equal < 1)
99 return null;
100
101 String name = nameValue.substring(0, equal).trim();
102 String value = nameValue.substring(equal + 1);
103 String domain = null;
104 String path = "/";
105 long maxAge = -1;
106 boolean httpOnly = false;
107 boolean secure = false;
108 String comment = null;
109 for (int i = 1; i < cookieParts.length; ++i)
110 {
111 try
112 {
113 String[] attributeParts = cookieParts[i].split("=", 2);
114 String attributeName = attributeParts[0].trim().toLowerCase(Locale.ENGLISH);
115 String attributeValue = attributeParts.length < 2 ? "" : attributeParts[1].trim();
116 switch (attributeName)
117 {
118 case "domain":
119 {
120 domain = attributeValue;
121 break;
122 }
123 case "path":
124 {
125 path = attributeValue;
126 break;
127 }
128 case "max-age":
129 {
130 maxAge = Long.parseLong(attributeValue);
131 break;
132 }
133 case "expires":
134 {
135 maxAge = parseDate(attributeValue);
136 break;
137 }
138 case "secure":
139 {
140 secure = true;
141 break;
142 }
143 case "httponly":
144 {
145 httpOnly = true;
146 }
147 case "comment":
148 {
149 comment = attributeValue;
150 break;
151 }
152 case "version":
153 {
154 version = Integer.parseInt(attributeValue);
155 break;
156 }
157 default:
158 {
159
160 break;
161 }
162 }
163 }
164 catch (NumberFormatException x)
165 {
166
167 }
168 }
169
170 return new HttpCookie(name, value, domain, path, maxAge, httpOnly, secure, comment, version);
171 }
172
173 private static long parseDate(String attributeValue)
174 {
175 for (String pattern : DATE_PATTERNS)
176 {
177 try
178 {
179 SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.US);
180 dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
181 long result = TimeUnit.MILLISECONDS.toSeconds(dateFormat.parse(attributeValue).getTime() - System.currentTimeMillis());
182 if (result < 0)
183 return 0;
184 }
185 catch (ParseException x)
186 {
187
188 }
189 }
190 return 0;
191 }
192 }