1 module hunt.http.codec.http.model.Cookie; 2 3 import hunt.lang.exception; 4 5 import std.array; 6 import std.conv; 7 import std.string; 8 9 class Cookie { 10 11 // 12 // The value of the cookie itself. 13 // 14 15 private string name; // NAME= ... "$Name" style is reserved 16 private string value; // value of NAME 17 18 // 19 // Attributes encoded in the header's cookie fields. 20 // 21 22 private string comment; // ;Comment=VALUE ... describes cookie's use 23 // ;Discard ... implied by maxAge < 0 24 private string domain; // ;Domain=VALUE ... domain that sees cookie 25 private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire 26 private string path; // ;Path=VALUE ... URLs that see the cookie 27 private bool secure; // ;Secure ... e.g. use SSL 28 private int _version = 0; // ;Version=1 ... means RFC 2109++ style 29 private bool _isHttpOnly = false; 30 31 this() { 32 33 } 34 35 /** 36 * Constructs a cookie with the specified name and value. 37 * 38 * <p> 39 * The name must conform to RFC 2109. However, vendors may provide a 40 * configuration option that allows cookie names conforming to the original 41 * Netscape Cookie Specification to be accepted. 42 * 43 * <p> 44 * The name of a cookie cannot be changed once the cookie has been created. 45 * 46 * <p> 47 * The value can be anything the server chooses to send. Its value is 48 * probably of interest only to the server. The cookie's value can be 49 * changed after creation with the <code>setValue</code> method. 50 * 51 * <p> 52 * By default, cookies are created according to the Netscape cookie 53 * specification. The version can be changed with the 54 * <code>setVersion</code> method. 55 * 56 * @param name 57 * the name of the cookie 58 * 59 * @param value 60 * the value of the cookie 61 * 62 * @throws IllegalArgumentException 63 * if the cookie name is null or empty or contains any illegal 64 * characters (for example, a comma, space, or semicolon) or 65 * matches a token reserved for use by the cookie protocol 66 * 67 * @see #setValue 68 * @see #setVersion 69 */ 70 this(string name, string value, int expires=-1, 71 string path = "/", string domain = null, 72 bool secure = false, bool httpOnly = true) { 73 if (name.empty) { 74 throw new IllegalArgumentException("the cookie name is empty"); 75 } 76 77 this.name = name; 78 this.value = value; 79 this.maxAge = expires; 80 this.path = path; 81 this.secure = secure; 82 this.domain = domain; 83 this._isHttpOnly = httpOnly; 84 } 85 86 /** 87 * Specifies a comment that describes a cookie's purpose. The comment is 88 * useful if the browser presents the cookie to the user. Comments are not 89 * supported by Netscape Version 0 cookies. 90 * 91 * @param purpose 92 * a <code>string</code> specifying the comment to display to the 93 * user 94 * 95 * @see #getComment 96 */ 97 void setComment(string purpose) { 98 comment = purpose; 99 } 100 101 /** 102 * Returns the comment describing the purpose of this cookie, or 103 * <code>null</code> if the cookie has no comment. 104 * 105 * @return the comment of the cookie, or <code>null</code> if unspecified 106 * 107 * @see #setComment 108 */ 109 string getComment() { 110 return comment; 111 } 112 113 /** 114 * 115 * Specifies the domain within which this cookie should be presented. 116 * 117 * <p> 118 * The form of the domain name is specified by RFC 2109. A domain name 119 * begins with a dot (<code>.foo.com</code>) and means that the cookie is 120 * visible to servers in a specified Domain Name System (DNS) zone (for 121 * example, <code>www.foo.com</code>, but not <code>a.b.foo.com</code>). By 122 * default, cookies are only returned to the server that sent them. 123 * 124 * @param domain 125 * the domain name within which this cookie is visible; form is 126 * according to RFC 2109 127 * 128 * @see #getDomain 129 */ 130 void setDomain(string domain) { 131 this.domain = domain.toLower(); // IE allegedly needs 132 // this 133 } 134 135 /** 136 * Gets the domain name of this Cookie. 137 * 138 * <p> 139 * Domain names are formatted according to RFC 2109. 140 * 141 * @return the domain name of this Cookie 142 * 143 * @see #setDomain 144 */ 145 string getDomain() { 146 return domain; 147 } 148 149 /** 150 * Sets the maximum age in seconds for this Cookie. 151 * 152 * <p> 153 * A positive value indicates that the cookie will expire after that many 154 * seconds have passed. Note that the value is the <i>maximum</i> age when 155 * the cookie will expire, not the cookie's current age. 156 * 157 * <p> 158 * A negative value means that the cookie is not stored persistently and 159 * will be deleted when the Web browser exits. A zero value causes the 160 * cookie to be deleted. 161 * 162 * @param expiry 163 * an integer specifying the maximum age of the cookie in 164 * seconds; if negative, means the cookie is not stored; if zero, 165 * deletes the cookie 166 * 167 * @see #getMaxAge 168 */ 169 void setMaxAge(int expiry) { 170 maxAge = expiry; 171 } 172 173 /** 174 * Gets the maximum age in seconds of this Cookie. 175 * 176 * <p> 177 * By default, <code>-1</code> is returned, which indicates that the cookie 178 * will persist until browser shutdown. 179 * 180 * @return an integer specifying the maximum age of the cookie in seconds; 181 * if negative, means the cookie persists until browser shutdown 182 * 183 * @see #setMaxAge 184 */ 185 int getMaxAge() { 186 return maxAge; 187 } 188 189 /** 190 * Specifies a path for the cookie to which the client should return the 191 * cookie. 192 * 193 * <p> 194 * The cookie is visible to all the pages in the directory you specify, and 195 * all the pages in that directory's subdirectories. A cookie's path, for 196 * example, <i>/catalog</i>, which makes the cookie visible to all 197 * directories on the server under <i>/catalog</i>. 198 * 199 * <p> 200 * Consult RFC 2109 (available on the Internet) for more information on 201 * setting path names for cookies. 202 * 203 * 204 * @param uri 205 * a <code>string</code> specifying a path 206 * 207 * @see #getPath 208 */ 209 void setPath(string uri) { 210 path = uri; 211 } 212 213 /** 214 * Returns the path on the server to which the browser returns this cookie. 215 * The cookie is visible to all subpaths on the server. 216 * 217 * @return a <code>string</code> specifying a path , for example, 218 * <i>/catalog</i> 219 * 220 * @see #setPath 221 */ 222 string getPath() { 223 return path; 224 } 225 226 /** 227 * Indicates to the browser whether the cookie should only be sent using a 228 * secure protocol, such as HTTPS or SSL. 229 * 230 * <p> 231 * The default value is <code>false</code>. 232 * 233 * @param flag 234 * if <code>true</code>, sends the cookie from the browser to the 235 * server only when using a secure protocol; if 236 * <code>false</code>, sent on any protocol 237 * 238 * @see #getSecure 239 */ 240 void setSecure(bool flag) { 241 secure = flag; 242 } 243 244 /** 245 * Returns <code>true</code> if the browser is sending cookies only over a 246 * secure protocol, or <code>false</code> if the browser can send cookies 247 * using any protocol. 248 * 249 * @return <code>true</code> if the browser uses a secure protocol, 250 * <code>false</code> otherwise 251 * 252 * @see #setSecure 253 */ 254 bool getSecure() { 255 return secure; 256 } 257 258 void setName(string name) { 259 this.name = name; 260 } 261 262 /** 263 * Returns the name of the cookie. The name cannot be changed after 264 * creation. 265 * 266 * @return the name of the cookie 267 */ 268 string getName() { 269 return name; 270 } 271 272 /** 273 * Assigns a new value to this Cookie. 274 * 275 * <p> 276 * If you use a binary value, you may want to use BASE64 encoding. 277 * 278 * <p> 279 * With Version 0 cookies, values should not contain white space, brackets, 280 * parentheses, equals signs, commas, double quotes, slashes, question 281 * marks, at signs, colons, and semicolons. Empty values may not behave the 282 * same way on all browsers. 283 * 284 * @param newValue 285 * the new value of the cookie 286 * 287 * @see #getValue 288 */ 289 void setValue(string newValue) { 290 value = newValue; 291 } 292 293 /** 294 * Gets the current value of this Cookie. 295 * 296 * @return the current value of this Cookie 297 * 298 * @see #setValue 299 */ 300 string getValue() { 301 return value; 302 } 303 304 /** 305 * Returns the version of the protocol this cookie complies with. Version 1 306 * complies with RFC 2109, and version 0 complies with the original cookie 307 * specification drafted by Netscape. Cookies provided by a browser use and 308 * identify the browser's cookie version. 309 * 310 * @return 0 if the cookie complies with the original Netscape 311 * specification; 1 if the cookie complies with RFC 2109 312 * 313 * @see #setVersion 314 */ 315 int getVersion() { 316 return _version; 317 } 318 319 /** 320 * Sets the version of the cookie protocol that this Cookie complies with. 321 * 322 * <p> 323 * Version 0 complies with the original Netscape cookie specification. 324 * Version 1 complies with RFC 2109. 325 * 326 * <p> 327 * Since RFC 2109 is still somewhat new, consider version 1 as experimental; 328 * do not use it yet on production sites. 329 * 330 * @param v 331 * 0 if the cookie should comply with the original Netscape 332 * specification; 1 if the cookie should comply with RFC 2109 333 * 334 * @see #getVersion 335 */ 336 void setVersion(int v) { 337 _version = v; 338 } 339 340 /** 341 * Overrides the standard <code>java.lang.Object.clone</code> method to 342 * return a copy of this Cookie. 343 */ 344 // Object clone() { 345 // try { 346 // return super.clone(); 347 // } catch (NotSupportedException e) { 348 // throw new RuntimeException(e.getMessage()); 349 // } 350 // } 351 352 /** 353 * Marks or unmarks this Cookie as <i>HttpOnly</i>. 354 * 355 * <p> 356 * If <tt>isHttpOnly</tt> is set to <tt>true</tt>, this cookie is marked as 357 * <i>HttpOnly</i>, by adding the <tt>HttpOnly</tt> attribute to it. 358 * 359 * <p> 360 * <i>HttpOnly</i> cookies are not supposed to be exposed to client-side 361 * scripting code, and may therefore help mitigate certain kinds of 362 * cross-site scripting attacks. 363 * 364 * @param isHttpOnly 365 * true if this cookie is to be marked as <i>HttpOnly</i>, false 366 * otherwise 367 * 368 */ 369 void setHttpOnly(bool isHttpOnly) { 370 this._isHttpOnly = isHttpOnly; 371 } 372 373 /** 374 * Checks whether this Cookie has been marked as <i>HttpOnly</i>. 375 * 376 * @return true if this Cookie has been marked as <i>HttpOnly</i>, false 377 * otherwise 378 * 379 */ 380 bool isHttpOnly() { 381 return _isHttpOnly; 382 } 383 384 override 385 string toString() { 386 return "Cookie [name=" ~ name ~ ", value=" ~ value ~ ", comment=" ~ comment ~ 387 ", domain=" ~ domain ~ ", maxAge=" ~ maxAge.to!string ~ ", path=" ~ path ~ ", secure=" ~ 388 to!string(secure) ~ ", version=" ~ to!string(_version) ~ ", isHttpOnly=" ~ 389 to!string(_isHttpOnly) ~ "]"; 390 } 391 392 }