View Javadoc

1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the 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.http;
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  public class DefaultCookie implements Cookie {
28  
29      private final String name;
30      private String value;
31      private String domain;
32      private String path;
33      private String comment;
34      private String commentUrl;
35      private boolean discard;
36      private Set<Integer> ports = Collections.emptySet();
37      private Set<Integer> unmodifiablePorts = ports;
38      private int maxAge = Integer.MIN_VALUE;
39      private int version;
40      private boolean secure;
41      private boolean httpOnly;
42  
43      /**
44       * Creates a new cookie with the specified name and value.
45       */
46      public DefaultCookie(String name, String value) {
47          if (name == null) {
48              throw new NullPointerException("name");
49          }
50          name = name.trim();
51          if (name.length() == 0) {
52              throw new IllegalArgumentException("empty name");
53          }
54  
55          for (int i = 0; i < name.length(); i ++) {
56              char c = name.charAt(i);
57              if (c > 127) {
58                  throw new IllegalArgumentException(
59                          "name contains non-ascii character: " + name);
60              }
61  
62              // Check prohibited characters.
63              switch (c) {
64              case '\t': case '\n': case 0x0b: case '\f': case '\r':
65              case ' ':  case ',':  case ';':  case '=':
66                  throw new IllegalArgumentException(
67                          "name contains one of the following prohibited characters: " +
68                          "=,; \\t\\r\\n\\v\\f: " + name);
69              }
70          }
71  
72          if (name.charAt(0) == '$') {
73              throw new IllegalArgumentException("name starting with '$' not allowed: " + name);
74          }
75  
76          this.name = name;
77          setValue(value);
78      }
79  
80      public String getName() {
81          return name;
82      }
83  
84      public String getValue() {
85          return value;
86      }
87  
88      public void setValue(String value) {
89          if (value == null) {
90              throw new NullPointerException("value");
91          }
92          this.value = value;
93      }
94  
95      public String getDomain() {
96          return domain;
97      }
98  
99      public void setDomain(String domain) {
100         this.domain = validateValue("domain", domain);
101     }
102 
103     public String getPath() {
104         return path;
105     }
106 
107     public void setPath(String path) {
108         this.path = validateValue("path", path);
109     }
110 
111     public String getComment() {
112         return comment;
113     }
114 
115     public void setComment(String comment) {
116         this.comment = validateValue("comment", comment);
117     }
118 
119     public String getCommentUrl() {
120         return commentUrl;
121     }
122 
123     public void setCommentUrl(String commentUrl) {
124         this.commentUrl = validateValue("commentUrl", commentUrl);
125     }
126 
127     public boolean isDiscard() {
128         return discard;
129     }
130 
131     public void setDiscard(boolean discard) {
132         this.discard = discard;
133     }
134 
135     public Set<Integer> getPorts() {
136         if (unmodifiablePorts == null) {
137             unmodifiablePorts = Collections.unmodifiableSet(ports);
138         }
139         return unmodifiablePorts;
140     }
141 
142     public void setPorts(int... ports) {
143         if (ports == null) {
144             throw new NullPointerException("ports");
145         }
146 
147         int[] portsCopy = ports.clone();
148         if (portsCopy.length == 0) {
149             unmodifiablePorts = this.ports = Collections.emptySet();
150         } else {
151             Set<Integer> newPorts = new TreeSet<Integer>();
152             for (int p: portsCopy) {
153                 if (p <= 0 || p > 65535) {
154                     throw new IllegalArgumentException("port out of range: " + p);
155                 }
156                 newPorts.add(p);
157             }
158             this.ports = newPorts;
159             unmodifiablePorts = null;
160         }
161     }
162 
163     public void setPorts(Iterable<Integer> ports) {
164         Set<Integer> newPorts = new TreeSet<Integer>();
165         for (int p: ports) {
166             if (p <= 0 || p > 65535) {
167                 throw new IllegalArgumentException("port out of range: " + p);
168             }
169             newPorts.add(p);
170         }
171         if (newPorts.isEmpty()) {
172             unmodifiablePorts = this.ports = Collections.emptySet();
173         } else {
174             this.ports = newPorts;
175             unmodifiablePorts = null;
176         }
177     }
178 
179     public int getMaxAge() {
180         return maxAge;
181     }
182 
183     public void setMaxAge(int maxAge) {
184         this.maxAge = maxAge;
185     }
186 
187     public int getVersion() {
188         return version;
189     }
190 
191     public void setVersion(int version) {
192         this.version = version;
193     }
194 
195     public boolean isSecure() {
196         return secure;
197     }
198 
199     public void setSecure(boolean secure) {
200         this.secure = secure;
201     }
202 
203     public boolean isHttpOnly() {
204         return httpOnly;
205     }
206 
207     public void setHttpOnly(boolean httpOnly) {
208         this.httpOnly = httpOnly;
209     }
210 
211     @Override
212     public int hashCode() {
213         return getName().hashCode();
214     }
215 
216     @Override
217     public boolean equals(Object o) {
218         if (!(o instanceof Cookie)) {
219             return false;
220         }
221 
222         Cookie that = (Cookie) o;
223         if (!getName().equalsIgnoreCase(that.getName())) {
224             return false;
225         }
226 
227         if (getPath() == null) {
228             if (that.getPath() != null) {
229                 return false;
230             }
231         } else if (that.getPath() == null) {
232             return false;
233         } else if (!getPath().equals(that.getPath())) {
234             return false;
235         }
236 
237         if (getDomain() == null) {
238             if (that.getDomain() != null) {
239                 return false;
240             }
241         } else if (that.getDomain() == null) {
242             return false;
243         } else {
244             return getDomain().equalsIgnoreCase(that.getDomain());
245         }
246 
247         return true;
248     }
249 
250     public int compareTo(Cookie c) {
251         int v;
252         v = getName().compareToIgnoreCase(c.getName());
253         if (v != 0) {
254             return v;
255         }
256 
257         if (getPath() == null) {
258             if (c.getPath() != null) {
259                 return -1;
260             }
261         } else if (c.getPath() == null) {
262             return 1;
263         } else {
264             v = getPath().compareTo(c.getPath());
265             if (v != 0) {
266                 return v;
267             }
268         }
269 
270         if (getDomain() == null) {
271             if (c.getDomain() != null) {
272                 return -1;
273             }
274         } else if (c.getDomain() == null) {
275             return 1;
276         } else {
277             v = getDomain().compareToIgnoreCase(c.getDomain());
278             return v;
279         }
280 
281         return 0;
282     }
283 
284     @Override
285     public String toString() {
286         StringBuilder buf = new StringBuilder();
287         buf.append(getName());
288         buf.append('=');
289         buf.append(getValue());
290         if (getDomain() != null) {
291             buf.append(", domain=");
292             buf.append(getDomain());
293         }
294         if (getPath() != null) {
295             buf.append(", path=");
296             buf.append(getPath());
297         }
298         if (getComment() != null) {
299             buf.append(", comment=");
300             buf.append(getComment());
301         }
302         if (getMaxAge() >= 0) {
303             buf.append(", maxAge=");
304             buf.append(getMaxAge());
305             buf.append('s');
306         }
307         if (isSecure()) {
308             buf.append(", secure");
309         }
310         if (isHttpOnly()) {
311             buf.append(", HTTPOnly");
312         }
313         return buf.toString();
314     }
315 
316     private static String validateValue(String name, String value) {
317         if (value == null) {
318             return null;
319         }
320         value = value.trim();
321         if (value.length() == 0) {
322             return null;
323         }
324         for (int i = 0; i < value.length(); i ++) {
325             char c = value.charAt(i);
326             switch (c) {
327             case '\r': case '\n': case '\f': case 0x0b: case ';':
328                 throw new IllegalArgumentException(
329                         name + " contains one of the following prohibited characters: " +
330                         ";\\r\\n\\f\\v (" + value + ')');
331             }
332         }
333         return value;
334     }
335 }
336