View Javadoc

1   /*
2    * Copyright 2009 Red Hat, Inc.
3    *
4    * Red Hat licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * License.  You may obtain a copy of the License at:
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.codec.http2;
17  
18  import java.util.Collections;
19  import java.util.Set;
20  import java.util.TreeSet;
21  
22  
23  
24  /**
25   * The default {@link Cookie} implementation.
26   *
27   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
28   * @author Andy Taylor (andy.taylor@jboss.org)
29   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
30   * @version $Rev: 619 $, $Date: 2010-11-11 20:30:06 +0100 (jeu., 11 nov. 2010) $
31   */
32  public class DefaultCookie implements Cookie {
33  
34      private static final Set<String> RESERVED_NAMES = new TreeSet<String>(CaseIgnoringComparator.INSTANCE);
35  
36      static {
37          RESERVED_NAMES.add("Domain");
38          RESERVED_NAMES.add("Path");
39          RESERVED_NAMES.add("Comment");
40          RESERVED_NAMES.add("CommentURL");
41          RESERVED_NAMES.add("Discard");
42          RESERVED_NAMES.add("Port");
43          RESERVED_NAMES.add("Max-Age");
44          RESERVED_NAMES.add("Expires");
45          RESERVED_NAMES.add("Version");
46          RESERVED_NAMES.add("Secure");
47          RESERVED_NAMES.add("HTTPOnly");
48      }
49  
50      private final String name;
51      private String value;
52      private String domain;
53      private String path;
54      private String comment;
55      private String commentUrl;
56      private boolean discard;
57      private Set<Integer> ports = Collections.emptySet();
58      private Set<Integer> unmodifiablePorts = ports;
59      private int maxAge = -1;
60      private int version;
61      private boolean secure;
62      private boolean httpOnly;
63  
64      /**
65       * Creates a new cookie with the specified name and value.
66       */
67      public DefaultCookie(String name, String value) {
68          if (name == null) {
69              throw new NullPointerException("name");
70          }
71          name = name.trim();
72          if (name.length() == 0) {
73              throw new IllegalArgumentException("empty name");
74          }
75  
76          for (int i = 0; i < name.length(); i ++) {
77              char c = name.charAt(i);
78              if (c > 127) {
79                  throw new IllegalArgumentException(
80                          "name contains non-ascii character: " + name);
81              }
82  
83              // Check prohibited characters.
84              switch (c) {
85              case '\t': case '\n': case 0x0b: case '\f': case '\r':
86              case ' ':  case ',':  case ';':  case '=':
87                  throw new IllegalArgumentException(
88                          "name contains one of the following prohibited characters: " +
89                          "=,; \\t\\r\\n\\v\\f: " + name);
90              }
91          }
92  
93          if (RESERVED_NAMES.contains(name)) {
94              throw new IllegalArgumentException("reserved name: " + name);
95          }
96  
97          this.name = name;
98          setValue(value);
99      }
100 
101     public String getName() {
102         return name;
103     }
104 
105     public String getValue() {
106         return value;
107     }
108 
109     public void setValue(String value) {
110         if (value == null) {
111             throw new NullPointerException("value");
112         }
113         this.value = value;
114     }
115 
116     public String getDomain() {
117         return domain;
118     }
119 
120     public void setDomain(String domain) {
121         this.domain = validateValue("domain", domain);
122     }
123 
124     public String getPath() {
125         return path;
126     }
127 
128     public void setPath(String path) {
129         this.path = validateValue("path", path);
130     }
131 
132     public String getComment() {
133         return comment;
134     }
135 
136     public void setComment(String comment) {
137         this.comment = validateValue("comment", comment);
138     }
139 
140     public String getCommentUrl() {
141         return commentUrl;
142     }
143 
144     public void setCommentUrl(String commentUrl) {
145         this.commentUrl = validateValue("commentUrl", commentUrl);
146     }
147 
148     public boolean isDiscard() {
149         return discard;
150     }
151 
152     public void setDiscard(boolean discard) {
153         this.discard = discard;
154     }
155 
156     public Set<Integer> getPorts() {
157         if (unmodifiablePorts == null) {
158             unmodifiablePorts = Collections.unmodifiableSet(ports);
159         }
160         return unmodifiablePorts;
161     }
162 
163     public void setPorts(int... ports) {
164         if (ports == null) {
165             throw new NullPointerException("ports");
166         }
167 
168         int[] portsCopy = ports.clone();
169         if (portsCopy.length == 0) {
170             unmodifiablePorts = this.ports = Collections.emptySet();
171         } else {
172             Set<Integer> newPorts = new TreeSet<Integer>();
173             for (int p: portsCopy) {
174                 if (p <= 0 || p > 65535) {
175                     throw new IllegalArgumentException("port out of range: " + p);
176                 }
177                 newPorts.add(Integer.valueOf(p));
178             }
179             this.ports = newPorts;
180             unmodifiablePorts = null;
181         }
182     }
183 
184     public void setPorts(Iterable<Integer> ports) {
185         Set<Integer> newPorts = new TreeSet<Integer>();
186         for (int p: ports) {
187             if (p <= 0 || p > 65535) {
188                 throw new IllegalArgumentException("port out of range: " + p);
189             }
190             newPorts.add(Integer.valueOf(p));
191         }
192         if (newPorts.isEmpty()) {
193             unmodifiablePorts = this.ports = Collections.emptySet();
194         } else {
195             this.ports = newPorts;
196             unmodifiablePorts = null;
197         }
198     }
199 
200     public int getMaxAge() {
201         return maxAge;
202     }
203 
204     public void setMaxAge(int maxAge) {
205         if (maxAge < -1) {
206             throw new IllegalArgumentException(
207                     "maxAge must be either -1, 0, or a positive integer: " +
208                     maxAge);
209         }
210         this.maxAge = maxAge;
211     }
212 
213     public int getVersion() {
214         return version;
215     }
216 
217     public void setVersion(int version) {
218         this.version = version;
219     }
220 
221     public boolean isSecure() {
222         return secure;
223     }
224 
225     public void setSecure(boolean secure) {
226         this.secure = secure;
227     }
228 
229     public boolean isHttpOnly() {
230         return httpOnly;
231     }
232 
233     public void setHttpOnly(boolean httpOnly) {
234         this.httpOnly = httpOnly;
235     }
236 
237     @Override
238     public int hashCode() {
239         return getName().hashCode();
240     }
241 
242     @Override
243     public boolean equals(Object o) {
244         if (!(o instanceof Cookie)) {
245             return false;
246         }
247 
248         Cookie that = (Cookie) o;
249         if (!getName().equalsIgnoreCase(that.getName())) {
250             return false;
251         }
252 
253         if (getPath() == null && that.getPath() != null) {
254             return false;
255         } else if (that.getPath() == null) {
256             return false;
257         }
258         if (!getPath().equals(that.getPath())) {
259             return false;
260         }
261 
262         if (getDomain() == null && that.getDomain() != null) {
263             return false;
264         } else if (that.getDomain() == null) {
265             return false;
266         }
267         if (!getDomain().equalsIgnoreCase(that.getDomain())) {
268             return false;
269         }
270 
271         return true;
272     }
273 
274     public int compareTo(Cookie c) {
275         int v;
276         v = getName().compareToIgnoreCase(c.getName());
277         if (v != 0) {
278             return v;
279         }
280 
281         if (getPath() == null && c.getPath() != null) {
282             return -1;
283         } else if (c.getPath() == null) {
284             return 1;
285         }
286         v = getPath().compareTo(c.getPath());
287         if (v != 0) {
288             return v;
289         }
290 
291         if (getDomain() == null && c.getDomain() != null) {
292             return -1;
293         } else if (c.getDomain() == null) {
294             return 1;
295         }
296         v = getDomain().compareToIgnoreCase(c.getDomain());
297         return v;
298     }
299 
300     @Override
301     public String toString() {
302         StringBuilder buf = new StringBuilder();
303         buf.append(getName());
304         buf.append('=');
305         buf.append(getValue());
306         if (getDomain() != null) {
307             buf.append(", domain=");
308             buf.append(getDomain());
309         }
310         if (getPath() != null) {
311             buf.append(", path=");
312             buf.append(getPath());
313         }
314         if (getComment() != null) {
315             buf.append(", comment=");
316             buf.append(getComment());
317         }
318         if (getMaxAge() >= 0) {
319             buf.append(", maxAge=");
320             buf.append(getMaxAge());
321             buf.append('s');
322         }
323         if (isSecure()) {
324             buf.append(", secure");
325         }
326         if (isHttpOnly()) {
327             buf.append(", HTTPOnly");
328         }
329         return buf.toString();
330     }
331 
332     private static String validateValue(String name, String value) {
333         if (value == null) {
334             return null;
335         }
336         value = value.trim();
337         if (value.length() == 0) {
338             return null;
339         }
340         for (int i = 0; i < value.length(); i ++) {
341             char c = value.charAt(i);
342             switch (c) {
343             case '\r': case '\n': case '\f': case 0x0b: case ';':
344                 throw new IllegalArgumentException(
345                         name + " contains one of the following prohibited characters: " +
346                         ";\\r\\n\\f\\v (" + value + ')');
347             }
348         }
349         return value;
350     }
351 }