1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http2;
17
18 import java.util.Date;
19 import java.util.Set;
20 import java.util.TreeSet;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class CookieEncoder {
55
56 private final Set<Cookie> cookies = new TreeSet<Cookie>();
57 private final boolean server;
58
59
60
61
62
63
64
65
66 public CookieEncoder(boolean server) {
67 this.server = server;
68 }
69
70
71
72
73
74 public void addCookie(String name, String value) {
75 cookies.add(new DefaultCookie(name, value));
76 }
77
78
79
80
81 public void addCookie(Cookie cookie) {
82 cookies.add(cookie);
83 }
84
85
86
87
88
89
90
91
92 public String encode() {
93 String answer;
94 if (server) {
95 answer = encodeServerSide();
96 } else {
97 answer = encodeClientSide();
98 }
99 cookies.clear();
100 return answer;
101 }
102
103 private String encodeServerSide() {
104 StringBuilder sb = new StringBuilder();
105
106 for (Cookie cookie: cookies) {
107 add(sb, cookie.getName(), cookie.getValue());
108
109 if (cookie.getMaxAge() >= 0) {
110 if (cookie.getVersion() == 0) {
111 addUnquoted(sb, CookieHeaderNames.EXPIRES,
112 new HttpHeaderDateFormat().format(
113 new Date(System.currentTimeMillis() +
114 cookie.getMaxAge() * 1000L)));
115 } else {
116 add(sb, CookieHeaderNames.MAX_AGE, cookie.getMaxAge());
117 }
118 }
119
120 if (cookie.getPath() != null) {
121 if (cookie.getVersion() > 0) {
122 add(sb, CookieHeaderNames.PATH, cookie.getPath());
123 } else {
124 addUnquoted(sb, CookieHeaderNames.PATH, cookie.getPath());
125 }
126 }
127
128 if (cookie.getDomain() != null) {
129 if (cookie.getVersion() > 0) {
130 add(sb, CookieHeaderNames.DOMAIN, cookie.getDomain());
131 } else {
132 addUnquoted(sb, CookieHeaderNames.DOMAIN, cookie.getDomain());
133 }
134 }
135 if (cookie.isSecure()) {
136 sb.append(CookieHeaderNames.SECURE);
137 sb.append((char) HttpCodecUtil.SEMICOLON);
138 }
139 if (cookie.isHttpOnly()) {
140 sb.append(CookieHeaderNames.HTTPONLY);
141 sb.append((char) HttpCodecUtil.SEMICOLON);
142 }
143 if (cookie.getVersion() >= 1) {
144 if (cookie.getComment() != null) {
145 add(sb, CookieHeaderNames.COMMENT, cookie.getComment());
146 }
147
148 add(sb, CookieHeaderNames.VERSION, 1);
149
150 if (cookie.getCommentUrl() != null) {
151 addQuoted(sb, CookieHeaderNames.COMMENTURL, cookie.getCommentUrl());
152 }
153
154 if (!cookie.getPorts().isEmpty()) {
155 sb.append(CookieHeaderNames.PORT);
156 sb.append((char) HttpCodecUtil.EQUALS);
157 sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
158 for (int port: cookie.getPorts()) {
159 sb.append(port);
160 sb.append((char) HttpCodecUtil.COMMA);
161 }
162 sb.setCharAt(sb.length() - 1, (char) HttpCodecUtil.DOUBLE_QUOTE);
163 sb.append((char) HttpCodecUtil.SEMICOLON);
164 }
165 if (cookie.isDiscard()) {
166 sb.append(CookieHeaderNames.DISCARD);
167 sb.append((char) HttpCodecUtil.SEMICOLON);
168 }
169 }
170 }
171
172 if (sb.length() > 0) {
173 sb.setLength(sb.length() - 1);
174 }
175
176 return sb.toString();
177 }
178
179 private String encodeClientSide() {
180 StringBuilder sb = new StringBuilder();
181
182 for (Cookie cookie: cookies) {
183 if (cookie.getVersion() >= 1) {
184 add(sb, '$' + CookieHeaderNames.VERSION, 1);
185 }
186
187 add(sb, cookie.getName(), cookie.getValue());
188
189 if (cookie.getPath() != null) {
190 add(sb, '$' + CookieHeaderNames.PATH, cookie.getPath());
191 }
192
193 if (cookie.getDomain() != null) {
194 add(sb, '$' + CookieHeaderNames.DOMAIN, cookie.getDomain());
195 }
196
197 if (cookie.getVersion() >= 1) {
198 if (!cookie.getPorts().isEmpty()) {
199 sb.append('$');
200 sb.append(CookieHeaderNames.PORT);
201 sb.append((char) HttpCodecUtil.EQUALS);
202 sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
203 for (int port: cookie.getPorts()) {
204 sb.append(port);
205 sb.append((char) HttpCodecUtil.COMMA);
206 }
207 sb.setCharAt(sb.length() - 1, (char) HttpCodecUtil.DOUBLE_QUOTE);
208 sb.append((char) HttpCodecUtil.SEMICOLON);
209 }
210 }
211 }
212
213 if (sb.length() > 0) {
214 sb.setLength(sb.length() - 1);
215 }
216
217 return sb.toString();
218 }
219
220 private static void add(StringBuilder sb, String name, String val) {
221 if (val == null) {
222 addQuoted(sb, name, "");
223 return;
224 }
225
226 for (int i = 0; i < val.length(); i ++) {
227 char c = val.charAt(i);
228 switch (c) {
229 case '\t': case ' ': case '"': case '(': case ')': case ',':
230 case '/': case ':': case ';': case '<': case '=': case '>':
231 case '?': case '@': case '[': case '\\': case ']':
232 case '{': case '}':
233 addQuoted(sb, name, val);
234 return;
235 }
236 }
237
238 addUnquoted(sb, name, val);
239 }
240
241 private static void addUnquoted(StringBuilder sb, String name, String val) {
242 sb.append(name);
243 sb.append((char) HttpCodecUtil.EQUALS);
244 sb.append(val);
245 sb.append((char) HttpCodecUtil.SEMICOLON);
246 }
247
248 private static void addQuoted(StringBuilder sb, String name, String val) {
249 if (val == null) {
250 val = "";
251 }
252
253 sb.append(name);
254 sb.append((char) HttpCodecUtil.EQUALS);
255 sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
256 sb.append(val.replace("\\", "\\\\").replace("\"", "\\\""));
257 sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
258 sb.append((char) HttpCodecUtil.SEMICOLON);
259 }
260
261 private static void add(StringBuilder sb, String name, int val) {
262 sb.append(name);
263 sb.append((char) HttpCodecUtil.EQUALS);
264 sb.append(val);
265 sb.append((char) HttpCodecUtil.SEMICOLON);
266 }
267 }