1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27
28 package org.apache.hc.client5.http.impl.cookie;
29
30 import java.io.Serializable;
31 import java.time.Instant;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.Locale;
35 import java.util.Map;
36
37 import org.apache.hc.client5.http.cookie.SetCookie;
38 import org.apache.hc.client5.http.utils.DateUtils;
39 import org.apache.hc.core5.util.Args;
40
41 /**
42 * Default implementation of {@link SetCookie}.
43 *
44 * @since 4.0
45 */
46 public final class BasicClientCookie implements SetCookie, Cloneable, Serializable {
47
48 private static final long serialVersionUID = -3869795591041535538L;
49
50 /**
51 * Default Constructor taking a name and a value. The value may be null.
52 *
53 * @param name The name.
54 * @param value The value.
55 */
56 public BasicClientCookie(final String name, final String value) {
57 super();
58 Args.notNull(name, "Name");
59 this.name = name;
60 this.attribs = new HashMap<>();
61 this.value = value;
62 }
63
64 /**
65 * Returns the name.
66 *
67 * @return String name The name
68 */
69 @Override
70 public String getName() {
71 return this.name;
72 }
73
74 /**
75 * Returns the value.
76 *
77 * @return String value The current value.
78 */
79 @Override
80 public String getValue() {
81 return this.value;
82 }
83
84 /**
85 * Sets the value
86 *
87 * @param value
88 */
89 @Override
90 public void setValue(final String value) {
91 this.value = value;
92 }
93
94 /**
95 * Returns the expiration {@link Date} of the cookie, or {@code null}
96 * if none exists.
97 * <p><strong>Note:</strong> the object returned by this method is
98 * considered immutable. Changing it (e.g. using setTime()) could result
99 * in undefined behaviour. Do so at your peril. </p>
100 * @return Expiration {@link Date}, or {@code null}.
101 *
102 * @see #setExpiryDate(java.util.Date)
103 *
104 * @deprecated Use {@link #getExpiryInstant()}
105 */
106 @Deprecated
107 @Override
108 public Date getExpiryDate() {
109 return DateUtils.toDate(cookieExpiryDate);
110 }
111
112 /**
113 * {@inheritDoc}
114 */
115 @Override
116 public Instant getExpiryInstant() {
117 return cookieExpiryDate;
118 }
119
120 /**
121 * Sets expiration date.
122 * <p><strong>Note:</strong> the object returned by this method is considered
123 * immutable. Changing it (e.g. using setTime()) could result in undefined
124 * behaviour. Do so at your peril.</p>
125 *
126 * @param expiryDate the {@link Date} after which this cookie is no longer valid.
127 *
128 * @deprecated Use {{@link #setExpiryDate(Instant)}}
129 *
130 */
131 @Deprecated
132 @Override
133 public void setExpiryDate (final Date expiryDate) {
134 cookieExpiryDate = DateUtils.toInstant(expiryDate);
135 }
136
137 /**
138 * Sets expiration date.
139 * <p><strong>Note:</strong> the object returned by this method is considered
140 * immutable. Changing it (e.g. using setTime()) could result in undefined behaviour. Do so at
141 * your peril.</p>
142 *
143 * @param expiryInstant the {@link Instant} after which this cookie is no longer valid.
144 * @see #getExpiryInstant()
145 * @since 5.2
146 */
147 @Override
148 public void setExpiryDate (final Instant expiryInstant) {
149 cookieExpiryDate = expiryInstant;
150 }
151
152
153 /**
154 * Returns {@code false} if the cookie should be discarded at the end
155 * of the "session"; {@code true} otherwise.
156 *
157 * @return {@code false} if the cookie should be discarded at the end
158 * of the "session"; {@code true} otherwise
159 */
160 @Override
161 public boolean isPersistent() {
162 return null != cookieExpiryDate;
163 }
164
165
166 /**
167 * Returns domain attribute of the cookie.
168 *
169 * @return the value of the domain attribute
170 *
171 * @see #setDomain(java.lang.String)
172 */
173 @Override
174 public String getDomain() {
175 return cookieDomain;
176 }
177
178 /**
179 * Sets the domain attribute.
180 *
181 * @param domain The value of the domain attribute
182 *
183 * @see #getDomain
184 */
185 @Override
186 public void setDomain(final String domain) {
187 if (domain != null) {
188 cookieDomain = domain.toLowerCase(Locale.ROOT);
189 } else {
190 cookieDomain = null;
191 }
192 }
193
194
195 /**
196 * Returns the path attribute of the cookie
197 *
198 * @return The value of the path attribute.
199 *
200 * @see #setPath(java.lang.String)
201 */
202 @Override
203 public String getPath() {
204 return cookiePath;
205 }
206
207 /**
208 * Sets the path attribute.
209 *
210 * @param path The value of the path attribute
211 *
212 * @see #getPath
213 *
214 */
215 @Override
216 public void setPath(final String path) {
217 cookiePath = path;
218 }
219
220 /**
221 * @return {@code true} if this cookie should only be sent over secure connections.
222 * @see #setSecure(boolean)
223 */
224 @Override
225 public boolean isSecure() {
226 return isSecure;
227 }
228
229 /**
230 * Sets the secure attribute of the cookie.
231 * <p>
232 * When {@code true} the cookie should only be sent
233 * using a secure protocol (https). This should only be set when
234 * the cookie's originating server used a secure protocol to set the
235 * cookie's value.
236 *
237 * @param secure The value of the secure attribute
238 *
239 * @see #isSecure()
240 */
241 @Override
242 public void setSecure (final boolean secure) {
243 isSecure = secure;
244 }
245
246 /**
247 * Sets the http-only attribute of the cookie.
248 *
249 * @param httpOnly true if this cookie is to be marked as
250 * {@code httpOnly}, false otherwise
251 *
252 * @since 5.2
253 */
254 @Override
255 public void setHttpOnly(final boolean httpOnly) {
256 this.httpOnly = httpOnly;
257 }
258
259 /**
260 * Returns true if this cookie has expired.
261 * @param date Current time
262 *
263 * @return {@code true} if the cookie has expired.
264 *
265 * @deprecated Use {@link #isExpired(Instant)}
266 */
267 @Deprecated
268 @Override
269 public boolean isExpired(final Date date) {
270 Args.notNull(date, "Date");
271 return cookieExpiryDate != null
272 && cookieExpiryDate.compareTo(DateUtils.toInstant(date)) <= 0;
273 }
274
275 /**
276 * Returns true if this cookie has expired.
277 * @param instant Current time
278 *
279 * @return {@code true} if the cookie has expired.
280 */
281 @Override
282 public boolean isExpired(final Instant instant) {
283 Args.notNull(instant, "Instant");
284 return cookieExpiryDate != null
285 && cookieExpiryDate.compareTo(instant) <= 0;
286 }
287
288 /**
289 * @since 4.4
290 *
291 * @deprecated Use {@link #getCreationInstant()}.
292 */
293 @Deprecated
294 @Override
295 public Date getCreationDate() {
296 return DateUtils.toDate(creationDate);
297 }
298
299 /**
300 * @since 5.2
301 */
302 @Override
303 public Instant getCreationInstant() {
304 return creationDate;
305 }
306
307 /**
308 * @return true if this Cookie has been marked as {@code httpOnly}, false otherwise
309 * @see #setHttpOnly(boolean)
310 * @since 5.2
311 */
312 @Override
313 public boolean isHttpOnly() {
314 return httpOnly;
315 }
316
317 /**
318 * @since 4.4
319 * @deprecated Use {@link #setCreationDate(Instant)}
320 */
321 @Deprecated
322 public void setCreationDate(final Date creationDate) {
323 this.creationDate = DateUtils.toInstant(creationDate);
324 }
325
326 /**
327 * @since 5.2
328 */
329 public void setCreationDate(final Instant creationDate) {
330 this.creationDate = creationDate;
331 }
332
333 public void setAttribute(final String name, final String value) {
334 this.attribs.put(name, value);
335 }
336
337 @Override
338 public String getAttribute(final String name) {
339 return this.attribs.get(name);
340 }
341
342 @Override
343 public boolean containsAttribute(final String name) {
344 return this.attribs.containsKey(name);
345 }
346
347 /**
348 * @since 4.4
349 */
350 public boolean removeAttribute(final String name) {
351 return this.attribs.remove(name) != null;
352 }
353
354 @Override
355 public Object clone() throws CloneNotSupportedException {
356 final BasicClientCookie clone = (BasicClientCookie) super.clone();
357 clone.attribs = new HashMap<>(this.attribs);
358 return clone;
359 }
360
361 @Override
362 public String toString() {
363 final StringBuilder buffer = new StringBuilder();
364 buffer.append("[name: ");
365 buffer.append(this.name);
366 buffer.append("; ");
367 buffer.append("value: ");
368 buffer.append(this.value);
369 buffer.append("; ");
370 buffer.append("domain: ");
371 buffer.append(this.cookieDomain);
372 buffer.append("; ");
373 buffer.append("path: ");
374 buffer.append(this.cookiePath);
375 buffer.append("; ");
376 buffer.append("expiry: ");
377 buffer.append(this.cookieExpiryDate);
378 buffer.append("]");
379 return buffer.toString();
380 }
381
382 // ----------------------------------------------------- Instance Variables
383
384 /** Cookie name */
385 private final String name;
386
387 /** Cookie attributes as specified by the origin server */
388 private Map<String, String> attribs;
389
390 /** Cookie value */
391 private String value;
392
393 /** Domain attribute. */
394 private String cookieDomain;
395
396 /** Expiration {@link Instant}. */
397 private Instant cookieExpiryDate;
398
399 /** Path attribute. */
400 private String cookiePath;
401
402 /** My secure flag. */
403 private boolean isSecure;
404
405 private Instant creationDate;
406
407 /** The {@code httpOnly} flag. */
408 private boolean httpOnly;
409
410 }
411