001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2010–2011 ApexIdentity Inc.
015 * Portions Copyright 2011-2014 ForgeRock AS.
016 */
017
018package org.forgerock.openig.http;
019
020import java.util.ArrayList;
021import java.util.Date;
022import java.util.List;
023
024/**
025 * An HTTP cookie. For more information, see the original <a href=
026 * "http://web.archive.org/web/20070805052634/http://wp.netscape.com/newsref/std/cookie_spec.html"
027 * > Netscape specification</a>, <a
028 * href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> and <a
029 * href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>.
030 */
031public class Cookie {
032    /** The name of the cookie. */
033    private String name;
034
035    /** The value of the cookie. */
036    private String value;
037
038    /** The intended use of a cookie. */
039    private String comment;
040
041    /** URL identifying the intended use of a cookie. */
042    private String commentURL;
043
044    /**
045     * Directs the user agent to discard the cookie unconditionally when it
046     * terminates.
047     */
048    private Boolean discard;
049
050    /** The domain for which the cookie is valid. */
051    private String domain;
052
053    /**
054     * The lifetime of the cookie, expressed as the date and time of expiration.
055     */
056    private Date expires;
057
058    /**
059     * Directs the user agent to make the cookie inaccessible to client side
060     * script.
061     */
062    private Boolean httpOnly;
063
064    /** The lifetime of the cookie, expressed in seconds. */
065    private Integer maxAge;
066
067    /** The subset of URLs on the origin server to which this cookie applies. */
068    private String path;
069
070    /** Restricts the port(s) to which a cookie may be returned. */
071    private final List<Integer> port = new ArrayList<Integer>();
072
073    /**
074     * Directs the user agent to use only secure means to send back this cookie.
075     */
076    private Boolean secure;
077
078    /**
079     * The version of the state management mechanism to which this cookie
080     * conforms.
081     */
082    private Integer version;
083
084    /**
085     * Creates a new uninitialized cookie.
086     */
087    public Cookie() {
088        // Empty cookie.
089    }
090
091    @Override
092    public boolean equals(final Object obj) {
093        if (this == obj) {
094            return true;
095        }
096        if (!(obj instanceof Cookie)) {
097            return false;
098        }
099        final Cookie other = (Cookie) obj;
100        return objectsAreEqual(comment, other.comment)
101                && objectsAreEqual(commentURL, other.commentURL)
102                && objectsAreEqual(discard, other.discard) && objectsAreEqual(domain, other.domain)
103                && objectsAreEqual(expires, other.expires)
104                && objectsAreEqual(httpOnly, other.httpOnly)
105                && objectsAreEqual(maxAge, other.maxAge) && objectsAreEqual(name, other.name)
106                && objectsAreEqual(path, other.path) && objectsAreEqual(port, other.port)
107                && objectsAreEqual(secure, other.secure) && objectsAreEqual(value, other.value)
108                && objectsAreEqual(version, other.version);
109    }
110
111    /**
112     * Returns the intended use of a cookie.
113     *
114     * @return The intended use of a cookie.
115     */
116    public String getComment() {
117        return comment;
118    }
119
120    /**
121     * Returns the URL identifying the intended use of a cookie.
122     *
123     * @return The URL identifying the intended use of a cookie.
124     */
125    public String getCommentURL() {
126        return commentURL;
127    }
128
129    /**
130     * Returns {@code true} if the user agent should discard the cookie
131     * unconditionally when it terminates.
132     *
133     * @return {@code true} if the user agent should discard the cookie
134     *         unconditionally when it terminates.
135     */
136    public Boolean getDiscard() {
137        return discard;
138    }
139
140    /**
141     * Returns the domain for which the cookie is valid.
142     *
143     * @return The domain for which the cookie is valid.
144     */
145    public String getDomain() {
146        return domain;
147    }
148
149    /**
150     * Returns the lifetime of the cookie, expressed as the date and time of
151     * expiration.
152     *
153     * @return The lifetime of the cookie, expressed as the date and time of
154     *         expiration.
155     */
156    public Date getExpires() {
157        return expires;
158    }
159
160    /**
161     * Returns {@code true} if the user agent should make the cookie
162     * inaccessible to client side script.
163     *
164     * @return {@code true} if the user agent should make the cookie
165     *         inaccessible to client side script.
166     */
167    public Boolean getHttpOnly() {
168        return httpOnly;
169    }
170
171    /**
172     * Returns the lifetime of the cookie, expressed in seconds.
173     *
174     * @return The lifetime of the cookie, expressed in seconds.
175     */
176    public Integer getMaxAge() {
177        return maxAge;
178    }
179
180    /**
181     * Returns name of the cookie.
182     *
183     * @return The name of the cookie.
184     */
185    public String getName() {
186        return name;
187    }
188
189    /**
190     * Returns the subset of URLs on the origin server to which this cookie
191     * applies.
192     *
193     * @return The subset of URLs on the origin server to which this cookie
194     *         applies.
195     */
196    public String getPath() {
197        return path;
198    }
199
200    /**
201     * Returns the restricted list of port(s) to which a cookie may be returned.
202     *
203     * @return The restricted list of port(s) to which a cookie may be returned.
204     */
205    public List<Integer> getPort() {
206        return port;
207    }
208
209    /**
210     * Returns {@code true} if the user agent should use only secure means to
211     * send back this cookie.
212     *
213     * @return {@code true} if the user agent should use only secure means to
214     *         send back this cookie.
215     */
216    public Boolean getSecure() {
217        return secure;
218    }
219
220    /**
221     * Returns the value of the cookie.
222     *
223     * @return The value of the cookie.
224     */
225    public String getValue() {
226        return value;
227    }
228
229    /**
230     * Returns the version of the state management mechanism to which this
231     * cookie conforms.
232     *
233     * @return The version of the state management mechanism to which this
234     *         cookie conforms.
235     */
236    public Integer getVersion() {
237        return version;
238    }
239
240    @Override
241    public int hashCode() {
242        final int prime = 31;
243        int result = 1;
244        result = prime * result + (comment == null ? 0 : comment.hashCode());
245        result = prime * result + (commentURL == null ? 0 : commentURL.hashCode());
246        result = prime * result + (discard == null ? 0 : discard.hashCode());
247        result = prime * result + (domain == null ? 0 : domain.hashCode());
248        result = prime * result + (expires == null ? 0 : expires.hashCode());
249        result = prime * result + (httpOnly == null ? 0 : httpOnly.hashCode());
250        result = prime * result + (maxAge == null ? 0 : maxAge.hashCode());
251        result = prime * result + (name == null ? 0 : name.hashCode());
252        result = prime * result + (path == null ? 0 : path.hashCode());
253        result = prime * result + (port == null ? 0 : port.hashCode());
254        result = prime * result + (secure == null ? 0 : secure.hashCode());
255        result = prime * result + (value == null ? 0 : value.hashCode());
256        result = prime * result + (version == null ? 0 : version.hashCode());
257        return result;
258    }
259
260    /**
261     * Sets the intended use of a cookie.
262     *
263     * @param comment
264     *            The intended use of a cookie.
265     * @return This cookie.
266     */
267    public Cookie setComment(final String comment) {
268        this.comment = comment;
269        return this;
270    }
271
272    /**
273     * Sets the URL identifying the intended use of a cookie.
274     *
275     * @param commentURL
276     *            The URL identifying the intended use of a cookie.
277     * @return This cookie.
278     */
279    public Cookie setCommentURL(final String commentURL) {
280        this.commentURL = commentURL;
281        return this;
282    }
283
284    /**
285     * Sets the value indicating whether the user agent should discard the
286     * cookie unconditionally when it terminates.
287     *
288     * @param discard
289     *            {@code true} if the user agent should discard the cookie
290     *            unconditionally when it terminates.
291     * @return This cookie.
292     */
293    public Cookie setDiscard(final Boolean discard) {
294        this.discard = discard;
295        return this;
296    }
297
298    /**
299     * Sets the domain for which the cookie is valid.
300     *
301     * @param domain
302     *            The domain for which the cookie is valid.
303     * @return This cookie.
304     */
305    public Cookie setDomain(final String domain) {
306        this.domain = domain;
307        return this;
308    }
309
310    /**
311     * Sets the lifetime of the cookie, expressed as the date and time of
312     * expiration.
313     *
314     * @param expires
315     *            The lifetime of the cookie, expressed as the date and time of
316     *            expiration.
317     * @return This cookie.
318     */
319    public Cookie setExpires(final Date expires) {
320        this.expires = expires;
321        return this;
322    }
323
324    /**
325     * Sets the value indicating whether the user agent should make the cookie
326     * inaccessible to client side script.
327     *
328     * @param httpOnly
329     *            {@code true} if the user agent should make the cookie
330     *            inaccessible to client side script.
331     * @return this;
332     */
333    public Cookie setHttpOnly(final Boolean httpOnly) {
334        this.httpOnly = httpOnly;
335        return this;
336    }
337
338    /**
339     * Sets the lifetime of the cookie, expressed in seconds.
340     *
341     * @param maxAge
342     *            The lifetime of the cookie, expressed in seconds.
343     * @return This cookie.
344     */
345    public Cookie setMaxAge(final Integer maxAge) {
346        this.maxAge = maxAge;
347        return this;
348    }
349
350    /**
351     * Sets the name of the cookie.
352     *
353     * @param name
354     *            The name of the cookie.
355     * @return This cookie.
356     */
357    public Cookie setName(final String name) {
358        this.name = name;
359        return this;
360    }
361
362    /**
363     * Sets the subset of URLs on the origin server to which this cookie
364     * applies.
365     *
366     * @param path
367     *            The subset of URLs on the origin server to which this cookie
368     *            applies.
369     * @return This cookie.
370     */
371    public Cookie setPath(final String path) {
372        this.path = path;
373        return this;
374    }
375
376    /**
377     * Sets the value indicating whether the user agent should use only secure
378     * means to send back this cookie.
379     *
380     * @param secure
381     *            {@code true} if the user agent should use only secure means to
382     *            send back this cookie.
383     * @return This cookie.
384     */
385    public Cookie setSecure(final Boolean secure) {
386        this.secure = secure;
387        return this;
388    }
389
390    /**
391     * Sets the value of the cookie.
392     *
393     * @param value
394     *            The value of the cookie.
395     * @return This cookie.
396     */
397    public Cookie setValue(final String value) {
398        this.value = value;
399        return this;
400    }
401
402    /**
403     * Sets the version of the state management mechanism to which this cookie
404     * conforms.
405     *
406     * @param version
407     *            The version of the state management mechanism to which this
408     *            cookie conforms.
409     * @return This cookie.
410     */
411    public Cookie setVersion(final Integer version) {
412        this.version = version;
413        return this;
414    }
415
416    @Override
417    public String toString() {
418        final StringBuilder builder = new StringBuilder();
419        builder.append("[");
420        if (name != null) {
421            builder.append("name=").append(name).append(" ");
422        }
423        if (value != null) {
424            builder.append("value=").append(value).append(" ");
425        }
426        if (comment != null) {
427            builder.append("comment=").append(comment).append(" ");
428        }
429        if (commentURL != null) {
430            builder.append("commentURL=").append(commentURL).append(" ");
431        }
432        if (discard != null) {
433            builder.append("discard=").append(discard).append(" ");
434        }
435        if (domain != null) {
436            builder.append("domain=").append(domain).append(" ");
437        }
438        if (expires != null) {
439            builder.append("expires=").append(expires).append(" ");
440        }
441        if (httpOnly != null) {
442            builder.append("httpOnly=").append(httpOnly).append(" ");
443        }
444        if (maxAge != null) {
445            builder.append("maxAge=").append(maxAge).append(" ");
446        }
447        if (path != null) {
448            builder.append("path=").append(path).append(" ");
449        }
450        if (port != null) {
451            builder.append("port=").append(port).append(" ");
452        }
453        if (secure != null) {
454            builder.append("secure=").append(secure).append(" ");
455        }
456        if (version != null) {
457            builder.append("version=").append(version);
458        }
459        builder.append("]");
460        return builder.toString();
461    }
462
463    private static boolean objectsAreEqual(final Object o1, final Object o2) {
464        if (o1 == null) {
465            return o2 == null;
466        } else {
467            return o1.equals(o2);
468        }
469    }
470
471}