1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.cookie;
29
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33
34 import org.apache.http.Header;
35 import org.apache.http.HeaderElement;
36 import org.apache.http.annotation.NotThreadSafe;
37 import org.apache.http.client.utils.DateUtils;
38 import org.apache.http.cookie.ClientCookie;
39 import org.apache.http.cookie.Cookie;
40 import org.apache.http.cookie.CookieOrigin;
41 import org.apache.http.cookie.CookiePathComparator;
42 import org.apache.http.cookie.CookieRestrictionViolationException;
43 import org.apache.http.cookie.CookieSpec;
44 import org.apache.http.cookie.MalformedCookieException;
45 import org.apache.http.cookie.SM;
46 import org.apache.http.message.BufferedHeader;
47 import org.apache.http.util.Args;
48 import org.apache.http.util.CharArrayBuffer;
49
50
51
52
53
54
55
56
57
58
59 @NotThreadSafe
60 public class RFC2109Spec extends CookieSpecBase {
61
62 private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
63
64 private final static String[] DATE_PATTERNS = {
65 DateUtils.PATTERN_RFC1123,
66 DateUtils.PATTERN_RFC1036,
67 DateUtils.PATTERN_ASCTIME
68 };
69
70 private final String[] datepatterns;
71 private final boolean oneHeader;
72
73
74 public RFC2109Spec(final String[] datepatterns, final boolean oneHeader) {
75 super();
76 if (datepatterns != null) {
77 this.datepatterns = datepatterns.clone();
78 } else {
79 this.datepatterns = DATE_PATTERNS;
80 }
81 this.oneHeader = oneHeader;
82 registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2109VersionHandler());
83 registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
84 registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2109DomainHandler());
85 registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
86 registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
87 registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
88 registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
89 this.datepatterns));
90 }
91
92
93 public RFC2109Spec() {
94 this(null, false);
95 }
96
97 public List<Cookie> parse(final Header header, final CookieOrigin origin)
98 throws MalformedCookieException {
99 Args.notNull(header, "Header");
100 Args.notNull(origin, "Cookie origin");
101 if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE)) {
102 throw new MalformedCookieException("Unrecognized cookie header '"
103 + header.toString() + "'");
104 }
105 final HeaderElement[] elems = header.getElements();
106 return parse(elems, origin);
107 }
108
109 @Override
110 public void validate(final Cookie cookie, final CookieOrigin origin)
111 throws MalformedCookieException {
112 Args.notNull(cookie, "Cookie");
113 final String name = cookie.getName();
114 if (name.indexOf(' ') != -1) {
115 throw new CookieRestrictionViolationException("Cookie name may not contain blanks");
116 }
117 if (name.startsWith("$")) {
118 throw new CookieRestrictionViolationException("Cookie name may not start with $");
119 }
120 super.validate(cookie, origin);
121 }
122
123 public List<Header> formatCookies(List<Cookie> cookies) {
124 Args.notEmpty(cookies, "List of cookies");
125 if (cookies.size() > 1) {
126
127 cookies = new ArrayList<Cookie>(cookies);
128 Collections.sort(cookies, PATH_COMPARATOR);
129 }
130 if (this.oneHeader) {
131 return doFormatOneHeader(cookies);
132 } else {
133 return doFormatManyHeaders(cookies);
134 }
135 }
136
137 private List<Header> doFormatOneHeader(final List<Cookie> cookies) {
138 int version = Integer.MAX_VALUE;
139
140 for (final Cookie cookie : cookies) {
141 if (cookie.getVersion() < version) {
142 version = cookie.getVersion();
143 }
144 }
145 final CharArrayBuffer buffer = new CharArrayBuffer(40 * cookies.size());
146 buffer.append(SM.COOKIE);
147 buffer.append(": ");
148 buffer.append("$Version=");
149 buffer.append(Integer.toString(version));
150 for (final Cookie cooky : cookies) {
151 buffer.append("; ");
152 final Cookie cookie = cooky;
153 formatCookieAsVer(buffer, cookie, version);
154 }
155 final List<Header> headers = new ArrayList<Header>(1);
156 headers.add(new BufferedHeader(buffer));
157 return headers;
158 }
159
160 private List<Header> doFormatManyHeaders(final List<Cookie> cookies) {
161 final List<Header> headers = new ArrayList<Header>(cookies.size());
162 for (final Cookie cookie : cookies) {
163 final int version = cookie.getVersion();
164 final CharArrayBuffer buffer = new CharArrayBuffer(40);
165 buffer.append("Cookie: ");
166 buffer.append("$Version=");
167 buffer.append(Integer.toString(version));
168 buffer.append("; ");
169 formatCookieAsVer(buffer, cookie, version);
170 headers.add(new BufferedHeader(buffer));
171 }
172 return headers;
173 }
174
175
176
177
178
179
180
181
182
183
184 protected void formatParamAsVer(final CharArrayBuffer buffer,
185 final String name, final String value, final int version) {
186 buffer.append(name);
187 buffer.append("=");
188 if (value != null) {
189 if (version > 0) {
190 buffer.append('\"');
191 buffer.append(value);
192 buffer.append('\"');
193 } else {
194 buffer.append(value);
195 }
196 }
197 }
198
199
200
201
202
203
204
205
206 protected void formatCookieAsVer(final CharArrayBuffer buffer,
207 final Cookie cookie, final int version) {
208 formatParamAsVer(buffer, cookie.getName(), cookie.getValue(), version);
209 if (cookie.getPath() != null) {
210 if (cookie instanceof ClientCookie
211 && ((ClientCookie) cookie).containsAttribute(ClientCookie.PATH_ATTR)) {
212 buffer.append("; ");
213 formatParamAsVer(buffer, "$Path", cookie.getPath(), version);
214 }
215 }
216 if (cookie.getDomain() != null) {
217 if (cookie instanceof ClientCookie
218 && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
219 buffer.append("; ");
220 formatParamAsVer(buffer, "$Domain", cookie.getDomain(), version);
221 }
222 }
223 }
224
225 public int getVersion() {
226 return 1;
227 }
228
229 public Header getVersionHeader() {
230 return null;
231 }
232
233 @Override
234 public String toString() {
235 return "rfc2109";
236 }
237
238 }