1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 1999 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. *
  54. * ====================================================================
  55. *
  56. * This source code implements specifications defined by the Java
  57. * Community Process. In order to remain compliant with the specification
  58. * DO NOT add / change / or delete method signatures!
  59. */
  60. package javax.servlet.http;
  61. import java.io.IOException;
  62. import java.text.MessageFormat;
  63. import java.util.ResourceBundle;
  64. /**
  65. *
  66. * Creates a cookie, a small amount of information sent by a servlet to
  67. * a Web browser, saved by the browser, and later sent back to the server.
  68. * A cookie's value can uniquely
  69. * identify a client, so cookies are commonly used for session management.
  70. *
  71. * <p>A cookie has a name, a single value, and optional attributes
  72. * such as a comment, path and domain qualifiers, a maximum age, and a
  73. * version number. Some Web browsers have bugs in how they handle the
  74. * optional attributes, so use them sparingly to improve the interoperability
  75. * of your servlets.
  76. *
  77. * <p>The servlet sends cookies to the browser by using the
  78. * {@link HttpServletResponse#addCookie} method, which adds
  79. * fields to HTTP response headers to send cookies to the
  80. * browser, one at a time. The browser is expected to
  81. * support 20 cookies for each Web server, 300 cookies total, and
  82. * may limit cookie size to 4 KB each.
  83. *
  84. * <p>The browser returns cookies to the servlet by adding
  85. * fields to HTTP request headers. Cookies can be retrieved
  86. * from a request by using the {@link HttpServletRequest#getCookies} method.
  87. * Several cookies might have the same name but different path attributes.
  88. *
  89. * <p>Cookies affect the caching of the Web pages that use them.
  90. * HTTP 1.0 does not cache pages that use cookies created with
  91. * this class. This class does not support the cache control
  92. * defined with HTTP 1.1.
  93. *
  94. * <p>This class supports both the Version 0 (by Netscape) and Version 1
  95. * (by RFC 2109) cookie specifications. By default, cookies are
  96. * created using Version 0 to ensure the best interoperability.
  97. *
  98. *
  99. * @author Various
  100. * @version $Version$
  101. *
  102. */
  103. // XXX would implement java.io.Serializable too, but can't do that
  104. // so long as sun.servlet.* must run on older JDK 1.02 JVMs which
  105. // don't include that support.
  106. public class Cookie implements Cloneable {
  107. private static final String LSTRING_FILE =
  108. "javax.servlet.http.LocalStrings";
  109. private static ResourceBundle lStrings =
  110. ResourceBundle.getBundle(LSTRING_FILE);
  111. //
  112. // The value of the cookie itself.
  113. //
  114. private String name; // NAME= ... "$Name" style is reserved
  115. private String value; // value of NAME
  116. //
  117. // Attributes encoded in the header's cookie fields.
  118. //
  119. private String comment; // ;Comment=VALUE ... describes cookie's use
  120. // ;Discard ... implied by maxAge < 0
  121. private String domain; // ;Domain=VALUE ... domain that sees cookie
  122. private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire
  123. private String path; // ;Path=VALUE ... URLs that see the cookie
  124. private boolean secure; // ;Secure ... e.g. use SSL
  125. private int version = 0; // ;Version=1 ... means RFC 2109++ style
  126. /**
  127. * Constructs a cookie with a specified name and value.
  128. *
  129. * <p>The name must conform to RFC 2109. That means it can contain
  130. * only ASCII alphanumeric characters and cannot contain commas,
  131. * semicolons, or white space or begin with a $ character. The cookie's
  132. * name cannot be changed after creation.
  133. *
  134. * <p>The value can be anything the server chooses to send. Its
  135. * value is probably of interest only to the server. The cookie's
  136. * value can be changed after creation with the
  137. * <code>setValue</code> method.
  138. *
  139. * <p>By default, cookies are created according to the Netscape
  140. * cookie specification. The version can be changed with the
  141. * <code>setVersion</code> method.
  142. *
  143. *
  144. * @param name a <code>String</code> specifying the name of the cookie
  145. *
  146. * @param value a <code>String</code> specifying the value of the cookie
  147. *
  148. * @throws IllegalArgumentException if the cookie name contains illegal characters
  149. * (for example, a comma, space, or semicolon)
  150. * or it is one of the tokens reserved for use
  151. * by the cookie protocol
  152. * @see #setValue
  153. * @see #setVersion
  154. *
  155. */
  156. public Cookie(String name, String value) {
  157. if (!isToken(name)
  158. || name.equalsIgnoreCase("Comment") // rfc2019
  159. || name.equalsIgnoreCase("Discard") // 2019++
  160. || name.equalsIgnoreCase("Domain")
  161. || name.equalsIgnoreCase("Expires") // (old cookies)
  162. || name.equalsIgnoreCase("Max-Age") // rfc2019
  163. || name.equalsIgnoreCase("Path")
  164. || name.equalsIgnoreCase("Secure")
  165. || name.equalsIgnoreCase("Version")
  166. ) {
  167. String errMsg = lStrings.getString("err.cookie_name_is_token");
  168. Object[] errArgs = new Object[1];
  169. errArgs[0] = name;
  170. errMsg = MessageFormat.format(errMsg, errArgs);
  171. throw new IllegalArgumentException(errMsg);
  172. }
  173. this.name = name;
  174. this.value = value;
  175. }
  176. /**
  177. *
  178. * Specifies a comment that describes a cookie's purpose.
  179. * The comment is useful if the browser presents the cookie
  180. * to the user. Comments
  181. * are not supported by Netscape Version 0 cookies.
  182. *
  183. * @param purpose a <code>String</code> specifying the comment
  184. * to display to the user
  185. *
  186. * @see #getComment
  187. *
  188. */
  189. public void setComment(String purpose) {
  190. comment = purpose;
  191. }
  192. /**
  193. * Returns the comment describing the purpose of this cookie, or
  194. * <code>null</code> if the cookie has no comment.
  195. *
  196. * @return a <code>String</code> containing the comment,
  197. * or <code>null</code> if none
  198. *
  199. * @see #setComment
  200. *
  201. */
  202. public String getComment() {
  203. return comment;
  204. }
  205. /**
  206. *
  207. * Specifies the domain within which this cookie should be presented.
  208. *
  209. * <p>The form of the domain name is specified by RFC 2109. A domain
  210. * name begins with a dot (<code>.foo.com</code>) and means that
  211. * the cookie is visible to servers in a specified Domain Name System
  212. * (DNS) zone (for example, <code>www.foo.com</code>, but not
  213. * <code>a.b.foo.com</code>). By default, cookies are only returned
  214. * to the server that sent them.
  215. *
  216. *
  217. * @param pattern a <code>String</code> containing the domain name
  218. * within which this cookie is visible;
  219. * form is according to RFC 2109
  220. *
  221. * @see #getDomain
  222. *
  223. */
  224. public void setDomain(String pattern) {
  225. domain = pattern.toLowerCase(); // IE allegedly needs this
  226. }
  227. /**
  228. * Returns the domain name set for this cookie. The form of
  229. * the domain name is set by RFC 2109.
  230. *
  231. * @return a <code>String</code> containing the domain name
  232. *
  233. * @see #setDomain
  234. *
  235. */
  236. public String getDomain() {
  237. return domain;
  238. }
  239. /**
  240. * Sets the maximum age of the cookie in seconds.
  241. *
  242. * <p>A positive value indicates that the cookie will expire
  243. * after that many seconds have passed. Note that the value is
  244. * the <i>maximum</i> age when the cookie will expire, not the cookie's
  245. * current age.
  246. *
  247. * <p>A negative value means
  248. * that the cookie is not stored persistently and will be deleted
  249. * when the Web browser exits. A zero value causes the cookie
  250. * to be deleted.
  251. *
  252. * @param expiry an integer specifying the maximum age of the
  253. * cookie in seconds; if negative, means
  254. * the cookie is not stored; if zero, deletes
  255. * the cookie
  256. *
  257. *
  258. * @see #getMaxAge
  259. *
  260. */
  261. public void setMaxAge(int expiry) {
  262. maxAge = expiry;
  263. }
  264. /**
  265. * Returns the maximum age of the cookie, specified in seconds,
  266. * By default, <code>-1</code> indicating the cookie will persist
  267. * until browser shutdown.
  268. *
  269. *
  270. * @return an integer specifying the maximum age of the
  271. * cookie in seconds; if negative, means
  272. * the cookie persists until browser shutdown
  273. *
  274. *
  275. * @see #setMaxAge
  276. *
  277. */
  278. public int getMaxAge() {
  279. return maxAge;
  280. }
  281. /**
  282. * Specifies a path for the cookie
  283. * to which the client should return the cookie.
  284. *
  285. * <p>The cookie is visible to all the pages in the directory
  286. * you specify, and all the pages in that directory's subdirectories.
  287. * A cookie's path must include the servlet that set the cookie,
  288. * for example, <i>/catalog</i>, which makes the cookie
  289. * visible to all directories on the server under <i>/catalog</i>.
  290. *
  291. * <p>Consult RFC 2109 (available on the Internet) for more
  292. * information on setting path names for cookies.
  293. *
  294. *
  295. * @param uri a <code>String</code> specifying a path
  296. *
  297. *
  298. * @see #getPath
  299. *
  300. */
  301. public void setPath(String uri) {
  302. path = uri;
  303. }
  304. /**
  305. * Returns the path on the server
  306. * to which the browser returns this cookie. The
  307. * cookie is visible to all subpaths on the server.
  308. *
  309. *
  310. * @return a <code>String</code> specifying a path that contains
  311. * a servlet name, for example, <i>/catalog</i>
  312. *
  313. * @see #setPath
  314. *
  315. */
  316. public String getPath() {
  317. return path;
  318. }
  319. /**
  320. * Indicates to the browser whether the cookie should only be sent
  321. * using a secure protocol, such as HTTPS or SSL.
  322. *
  323. * <p>The default value is <code>false</code>.
  324. *
  325. * @param flag if <code>true</code>, sends the cookie from the browser
  326. * to the server using only when using a secure protocol;
  327. * if <code>false</code>, sent on any protocol
  328. *
  329. * @see #getSecure
  330. *
  331. */
  332. public void setSecure(boolean flag) {
  333. secure = flag;
  334. }
  335. /**
  336. * Returns <code>true</code> if the browser is sending cookies
  337. * only over a secure protocol, or <code>false</code> if the
  338. * browser can send cookies using any protocol.
  339. *
  340. * @return <code>true</code> if the browser uses a secure protocol;
  341. * otherwise, <code>true</code>
  342. *
  343. * @see #setSecure
  344. *
  345. */
  346. public boolean getSecure() {
  347. return secure;
  348. }
  349. /**
  350. * Returns the name of the cookie. The name cannot be changed after
  351. * creation.
  352. *
  353. * @return a <code>String</code> specifying the cookie's name
  354. *
  355. */
  356. public String getName() {
  357. return name;
  358. }
  359. /**
  360. *
  361. * Assigns a new value to a cookie after the cookie is created.
  362. * If you use a binary value, you may want to use BASE64 encoding.
  363. *
  364. * <p>With Version 0 cookies, values should not contain white
  365. * space, brackets, parentheses, equals signs, commas,
  366. * double quotes, slashes, question marks, at signs, colons,
  367. * and semicolons. Empty values may not behave the same way
  368. * on all browsers.
  369. *
  370. * @param newValue a <code>String</code> specifying the new value
  371. *
  372. *
  373. * @see #getValue
  374. * @see Cookie
  375. *
  376. */
  377. public void setValue(String newValue) {
  378. value = newValue;
  379. }
  380. /**
  381. * Returns the value of the cookie.
  382. *
  383. * @return a <code>String</code> containing the cookie's
  384. * present value
  385. *
  386. * @see #setValue
  387. * @see Cookie
  388. *
  389. */
  390. public String getValue() {
  391. return value;
  392. }
  393. /**
  394. * Returns the version of the protocol this cookie complies
  395. * with. Version 1 complies with RFC 2109,
  396. * and version 0 complies with the original
  397. * cookie specification drafted by Netscape. Cookies provided
  398. * by a browser use and identify the browser's cookie version.
  399. *
  400. *
  401. * @return 0 if the cookie complies with the
  402. * original Netscape specification; 1
  403. * if the cookie complies with RFC 2109
  404. *
  405. * @see #setVersion
  406. *
  407. */
  408. public int getVersion() {
  409. return version;
  410. }
  411. /**
  412. * Sets the version of the cookie protocol this cookie complies
  413. * with. Version 0 complies with the original Netscape cookie
  414. * specification. Version 1 complies with RFC 2109.
  415. *
  416. * <p>Since RFC 2109 is still somewhat new, consider
  417. * version 1 as experimental; do not use it yet on production sites.
  418. *
  419. *
  420. * @param v 0 if the cookie should comply with
  421. * the original Netscape specification;
  422. * 1 if the cookie should comply with RFC 2109
  423. *
  424. * @see #getVersion
  425. *
  426. */
  427. public void setVersion(int v) {
  428. version = v;
  429. }
  430. // Note -- disabled for now to allow full Netscape compatibility
  431. // from RFC 2068, token special case characters
  432. //
  433. // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
  434. private static final String tspecials = ",;";
  435. /*
  436. * Tests a string and returns true if the string counts as a
  437. * reserved token in the Java language.
  438. *
  439. * @param value the <code>String</code> to be tested
  440. *
  441. * @return <code>true</code> if the <code>String</code> is
  442. * a reserved token; <code>false</code>
  443. * if it is not
  444. */
  445. private boolean isToken(String value) {
  446. int len = value.length();
  447. for (int i = 0; i < len; i++) {
  448. char c = value.charAt(i);
  449. if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
  450. return false;
  451. }
  452. return true;
  453. }
  454. /**
  455. *
  456. * Overrides the standard <code>java.lang.Object.clone</code>
  457. * method to return a copy of this cookie.
  458. *
  459. *
  460. */
  461. public Object clone() {
  462. try {
  463. return super.clone();
  464. } catch (CloneNotSupportedException e) {
  465. throw new RuntimeException(e.getMessage());
  466. }
  467. }
  468. }