1 /* 2 * $Header: $ 3 * $Revision: 480424 $ 4 * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ 5 * ==================================================================== 6 * 7 * Licensed to the Apache Software Foundation (ASF) under one or more 8 * contributor license agreements. See the NOTICE file distributed with 9 * this work for additional information regarding copyright ownership. 10 * The ASF licenses this file to You under the Apache License, Version 2.0 11 * (the "License"); you may not use this file except in compliance with 12 * the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software 17 * distributed under the License is distributed on an "AS IS" BASIS, 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 * See the License for the specific language governing permissions and 20 * limitations under the License. 21 * ==================================================================== 22 * 23 * This software consists of voluntary contributions made by many 24 * individuals on behalf of the Apache Software Foundation. For more 25 * information on the Apache Software Foundation, please see 26 * <http://www.apache.org/>. 27 * 28 */ 29 30 package org.apache.commons.httpclient.cookie; 31 32 import junit.framework.Test; 33 import junit.framework.TestSuite; 34 35 import org.apache.commons.httpclient.Cookie; 36 import org.apache.commons.httpclient.Header; 37 38 import java.util.Date; 39 40 /** 41 * Test cases for RFC2965 cookie spec 42 * 43 * @author jain.samit@gmail.com (Samit Jain) 44 */ 45 public class TestCookieRFC2965Spec extends TestCookieBase { 46 47 // ------------------------------------------------------------ Constructor 48 TestCookieRFC2965Spec(String name)49 public TestCookieRFC2965Spec(String name) { 50 super(name); 51 } 52 53 // ------------------------------------------------------- TestCase Methods 54 suite()55 public static Test suite() { 56 return new TestSuite(TestCookieRFC2965Spec.class); 57 } 58 59 60 // ------------------------------------------------------- Test Cookie Parsing 61 62 /** 63 * Test <tt>parse</tt> with invalid params. 64 */ testParseInvalidParams()65 public void testParseInvalidParams() throws Exception { 66 CookieSpec cookiespec = new RFC2965Spec(); 67 try { 68 // invalid header 69 cookiespec.parse("www.domain.com", 80, "/", false, (Header) null /* header */); 70 fail("IllegalArgumentException must have been thrown"); 71 } catch (IllegalArgumentException expected) {} 72 73 Header header = new Header("Set-Cookie2", "name=value;Version=1"); 74 try { 75 // invalid request host 76 cookiespec.parse(null /* host */, 80, "/", false, header); 77 fail("IllegalArgumentException must have been thrown"); 78 } catch (IllegalArgumentException expected) {} 79 try { 80 // invalid request port 81 cookiespec.parse("www.domain.com", -32 /* port */, "/", false, header); 82 fail("IllegalArgumentException must have been thrown"); 83 } catch (IllegalArgumentException expected) {} 84 try { 85 // invalid request path 86 cookiespec.parse("www.domain.com", 80, null /* path */, false, header); 87 fail("IllegalArgumentException must have been thrown"); 88 } catch (IllegalArgumentException expected) {} 89 } 90 91 /** 92 * Test parsing cookie <tt>"Path"</tt> attribute. 93 */ testParsePath()94 public void testParsePath() throws Exception { 95 CookieSpec cookiespec = new RFC2965Spec(); 96 Header header = new Header("Set-Cookie2", "name=value;Path=/;Version=1;Path="); 97 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 98 assertNotNull(parsed); 99 assertEquals(1, parsed.length); 100 // only the first occurence of path attribute is considered, others ignored 101 Cookie2 cookie = (Cookie2) parsed[0]; 102 assertEquals("/", cookie.getPath()); 103 assertTrue(cookie.isPathAttributeSpecified()); 104 } 105 testParsePathDefault()106 public void testParsePathDefault() throws Exception { 107 CookieSpec cookiespec = new RFC2965Spec(); 108 // Path is OPTIONAL, defaults to the request path 109 Header header = new Header("Set-Cookie2", "name=value;Version=1"); 110 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/path" /* request path */, false, header); 111 assertNotNull(parsed); 112 assertEquals(1, parsed.length); 113 Cookie2 cookie = (Cookie2) parsed[0]; 114 assertEquals("/path", cookie.getPath()); 115 assertFalse(cookie.isPathAttributeSpecified()); 116 } 117 testParseNullPath()118 public void testParseNullPath() throws Exception { 119 CookieSpec cookiespec = new RFC2965Spec(); 120 Header header = new Header("Set-Cookie2", "name=value;Path=;Version=1"); 121 try { 122 cookiespec.parse("www.domain.com", 80, "/", false, header); 123 fail("MalformedCookieException should have been thrown"); 124 } catch (MalformedCookieException ex) { 125 // expected 126 } 127 } 128 testParseBlankPath()129 public void testParseBlankPath() throws Exception { 130 CookieSpec cookiespec = new RFC2965Spec(); 131 Header header = new Header("Set-Cookie2", "name=value;Path=\" \";Version=1"); 132 try { 133 cookiespec.parse("www.domain.com", 80, "/", false, header); 134 fail("MalformedCookieException should have been thrown"); 135 } catch (MalformedCookieException ex) { 136 // expected 137 } 138 } 139 /** 140 * Test parsing cookie <tt>"Domain"</tt> attribute. 141 */ testParseDomain()142 public void testParseDomain() throws Exception { 143 CookieSpec cookiespec = new RFC2965Spec(); 144 Header header = new Header("Set-Cookie2", "name=value;Domain=.domain.com;Version=1;Domain="); 145 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 146 assertNotNull(parsed); 147 assertEquals(1, parsed.length); 148 // only the first occurence of domain attribute is considered, others ignored 149 Cookie2 cookie = (Cookie2) parsed[0]; 150 assertEquals(".domain.com", cookie.getDomain()); 151 assertTrue(cookie.isDomainAttributeSpecified()); 152 153 // should put a leading dot if there is no dot in front of domain 154 header = new Header("Set-Cookie2", "name=value;Domain=domain.com;Version=1"); 155 parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 156 assertNotNull(parsed); 157 assertEquals(1, parsed.length); 158 cookie = (Cookie2) parsed[0]; 159 assertEquals(".domain.com", cookie.getDomain()); 160 } 161 testParseDomainDefault()162 public void testParseDomainDefault() throws Exception { 163 CookieSpec cookiespec = new RFC2965Spec(); 164 // Domain is OPTIONAL, defaults to the request host 165 Header header = new Header("Set-Cookie2", "name=value;Version=1"); 166 Cookie[] parsed = cookiespec.parse("www.domain.com" /* request host */, 80, "/", false, header); 167 assertNotNull(parsed); 168 assertEquals(1, parsed.length); 169 Cookie2 cookie = (Cookie2) parsed[0]; 170 assertEquals("www.domain.com", cookie.getDomain()); 171 assertFalse(cookie.isDomainAttributeSpecified()); 172 } 173 testParseNullDomain()174 public void testParseNullDomain() throws Exception { 175 CookieSpec cookiespec = new RFC2965Spec(); 176 // domain cannot be null 177 Header header = new Header("Set-Cookie2", "name=value;Domain=;Version=1"); 178 try { 179 cookiespec.parse("www.domain.com", 80, "/", false, header); 180 fail("MalformedCookieException should have been thrown"); 181 } catch (MalformedCookieException ex) { 182 // expected 183 } 184 } 185 testParseBlankDomain()186 public void testParseBlankDomain() throws Exception { 187 CookieSpec cookiespec = new RFC2965Spec(); 188 Header header = new Header("Set-Cookie2", "name=value;Domain=\" \";Version=1"); 189 try { 190 cookiespec.parse("www.domain.com", 80, "/", false, header); 191 fail("MalformedCookieException should have been thrown"); 192 } catch (MalformedCookieException ex) { 193 // expected 194 } 195 } 196 197 /** 198 * Test parsing cookie <tt>"Port"</tt> attribute. 199 */ testParsePort()200 public void testParsePort() throws Exception { 201 CookieSpec cookiespec = new RFC2965Spec(); 202 Header header = new Header("Set-Cookie2", "name=value;Port=\"80,800,8000\";Version=1;Port=nonsense"); 203 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 204 assertNotNull(parsed); 205 assertEquals(1, parsed.length); 206 // only the first occurence of port attribute is considered, others ignored 207 Cookie2 cookie = (Cookie2) parsed[0]; 208 int[] ports = cookie.getPorts(); 209 assertNotNull(ports); 210 assertEquals(3, ports.length); 211 assertEquals(80, ports[0]); 212 assertEquals(800, ports[1]); 213 assertEquals(8000, ports[2]); 214 assertTrue(cookie.isPortAttributeSpecified()); 215 } 216 testParsePortDefault()217 public void testParsePortDefault() throws Exception { 218 CookieSpec cookiespec = new RFC2965Spec(); 219 // Port is OPTIONAL, cookie can be accepted from any port 220 Header header = new Header("Set-Cookie2", "name=value;Version=1"); 221 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 222 assertNotNull(parsed); 223 assertEquals(1, parsed.length); 224 Cookie2 cookie = (Cookie2) parsed[0]; 225 assertFalse(cookie.isPortAttributeSpecified()); 226 } 227 testParseNullPort()228 public void testParseNullPort() throws Exception { 229 CookieSpec cookiespec = new RFC2965Spec(); 230 // null port defaults to request port 231 Header header = new Header("Set-Cookie2", "name=value;Port=;Version=1"); 232 Cookie[] parsed = cookiespec.parse("www.domain.com", 80 /* request port */, "/", false, header); 233 assertNotNull(parsed); 234 assertEquals(1, parsed.length); 235 Cookie2 cookie = (Cookie2) parsed[0]; 236 int[] ports = cookie.getPorts(); 237 assertNotNull(ports); 238 assertEquals(1, ports.length); 239 assertEquals(80, ports[0]); 240 assertTrue(cookie.isPortAttributeSpecified() && cookie.isPortAttributeBlank()); 241 } 242 testParseBlankPort()243 public void testParseBlankPort() throws Exception { 244 CookieSpec cookiespec = new RFC2965Spec(); 245 // blank port defaults to request port 246 Header header = new Header("Set-Cookie2", "name=value;Port=\" \";Version=1"); 247 Cookie[] parsed = cookiespec.parse("www.domain.com", 80 /* request port */, "/", false, header); 248 assertNotNull(parsed); 249 assertEquals(1, parsed.length); 250 Cookie2 cookie = (Cookie2) parsed[0]; 251 int[] ports = cookie.getPorts(); 252 assertNotNull(ports); 253 assertEquals(1, ports.length); 254 assertEquals(80, ports[0]); 255 assertTrue(cookie.isPortAttributeSpecified() && cookie.isPortAttributeBlank()); 256 } 257 testParseInvalidPort()258 public void testParseInvalidPort() throws Exception { 259 CookieSpec cookiespec = new RFC2965Spec(); 260 Header header = new Header("Set-Cookie2", "name=value;Port=nonsense;Version=1"); 261 try { 262 cookiespec.parse("www.domain.com", 80, "/", false, header); 263 fail("MalformedCookieException should have been thrown"); 264 } catch (MalformedCookieException ex) { 265 // expected 266 } 267 } 268 testParseNegativePort()269 public void testParseNegativePort() throws Exception { 270 CookieSpec cookiespec = new RFC2965Spec(); 271 Header header = new Header("Set-Cookie2", "name=value;Port=\"80,-800,8000\";Version=1"); 272 try { 273 cookiespec.parse("www.domain.com", 80, "/", false, header); 274 fail("MalformedCookieException should have been thrown"); 275 } catch (MalformedCookieException ex) { 276 // expected 277 } 278 } 279 280 /** 281 * test parsing cookie name/value. 282 */ testParseNameValue()283 public void testParseNameValue() throws Exception { 284 CookieSpec cookiespec = new RFC2965Spec(); 285 Header header = new Header("Set-Cookie2", "name=value;Version=1;"); 286 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 287 assertNotNull(parsed); 288 assertEquals(1, parsed.length); 289 Cookie2 cookie = (Cookie2) parsed[0]; 290 assertEquals("name", cookie.getName()); 291 assertEquals("value", cookie.getValue()); 292 } 293 294 /** 295 * test parsing cookie <tt>"Version"</tt> attribute. 296 */ testParseVersion()297 public void testParseVersion() throws Exception { 298 CookieSpec cookiespec = new RFC2965Spec(); 299 Header header = new Header("Set-Cookie2", "name=value;Version=1;"); 300 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 301 assertNotNull(parsed); 302 assertEquals(1, parsed.length); 303 Cookie2 cookie = (Cookie2) parsed[0]; 304 assertEquals(1, cookie.getVersion()); 305 assertTrue(cookie.isVersionAttributeSpecified()); 306 } 307 testParseNullVersion()308 public void testParseNullVersion() throws Exception { 309 CookieSpec cookiespec = new RFC2965Spec(); 310 // version cannot ne null 311 Header header = new Header("Set-Cookie2", "name=value;Version=;"); 312 try { 313 cookiespec.parse("www.domain.com", 80, "/", false, header); 314 fail("MalformedCookieException should have been thrown"); 315 } catch (MalformedCookieException ex) { 316 // expected 317 } 318 } 319 testParseNegativeVersion()320 public void testParseNegativeVersion() throws Exception { 321 CookieSpec cookiespec = new RFC2965Spec(); 322 Header header = new Header("Set-Cookie2", "name=value;Version=-1;"); 323 try { 324 cookiespec.parse("www.domain.com", 80, "/", false, header); 325 fail("MalformedCookieException should have been thrown"); 326 } catch (MalformedCookieException ex) { 327 // expected 328 } 329 } 330 /** 331 * test parsing cookie <tt>"Max-age"</tt> attribute. 332 */ testParseMaxage()333 public void testParseMaxage() throws Exception { 334 CookieSpec cookiespec = new RFC2965Spec(); 335 Header header = new Header("Set-Cookie2", "name=value;Max-age=3600;Version=1;Max-age=nonsense"); 336 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 337 assertNotNull(parsed); 338 assertEquals(1, parsed.length); 339 // only the first occurence of max-age attribute is considered, others ignored 340 Cookie2 cookie = (Cookie2) parsed[0]; 341 assertFalse(cookie.isExpired()); 342 } 343 testParseMaxageDefault()344 public void testParseMaxageDefault() throws Exception { 345 CookieSpec cookiespec = new RFC2965Spec(); 346 // Max-age is OPTIONAL, defaults to session cookie 347 Header header = new Header("Set-Cookie2", "name=value;Version=1"); 348 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 349 assertNotNull(parsed); 350 assertEquals(1, parsed.length); 351 Cookie2 cookie = (Cookie2) parsed[0]; 352 assertFalse(cookie.isPersistent()); 353 } 354 testParseNullMaxage()355 public void testParseNullMaxage() throws Exception { 356 CookieSpec cookiespec = new RFC2965Spec(); 357 Header header = new Header("Set-Cookie2", "name=value;Max-age=;Version=1"); 358 try { 359 cookiespec.parse("www.domain.com", 80, "/", false, header); 360 fail("MalformedCookieException should have been thrown"); 361 } catch (MalformedCookieException ex) { 362 // expected 363 } 364 } 365 testParseNegativeMaxage()366 public void testParseNegativeMaxage() throws Exception { 367 CookieSpec cookiespec = new RFC2965Spec(); 368 Header header = new Header("Set-Cookie2", "name=value;Max-age=-3600;Version=1;"); 369 try { 370 cookiespec.parse("www.domain.com", 80, "/", false, header); 371 fail("MalformedCookieException should have been thrown"); 372 } catch (MalformedCookieException ex) { 373 // expected 374 } 375 } 376 377 /** 378 * test parsing <tt>"Secure"</tt> attribute. 379 */ testParseSecure()380 public void testParseSecure() throws Exception { 381 CookieSpec cookiespec = new RFC2965Spec(); 382 Header header = new Header("Set-Cookie2", "name=value;Secure;Version=1"); 383 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 384 assertNotNull(parsed); 385 assertEquals(1, parsed.length); 386 Cookie2 cookie = (Cookie2) parsed[0]; 387 assertTrue(cookie.getSecure()); 388 } 389 390 /** 391 * test parsing <tt>"Discard"</tt> attribute. 392 */ testParseDiscard()393 public void testParseDiscard() throws Exception { 394 CookieSpec cookiespec = new RFC2965Spec(); 395 Header header = new Header("Set-Cookie2", "name=value;Discard;Max-age=36000;Version=1"); 396 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 397 assertNotNull(parsed); 398 assertEquals(1, parsed.length); 399 Cookie2 cookie = (Cookie2) parsed[0]; 400 // discard overrides max-age 401 assertFalse(cookie.isPersistent()); 402 403 // Discard is OPTIONAL, default behavior is dictated by max-age 404 header = new Header("Set-Cookie2", "name=value;Max-age=36000;Version=1"); 405 parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 406 assertNotNull(parsed); 407 assertEquals(1, parsed.length); 408 cookie = (Cookie2) parsed[0]; 409 assertTrue(cookie.isPersistent()); 410 } 411 412 /** 413 * test parsing <tt>"Comment"</tt>, <tt>"CommentURL"</tt> and 414 * <tt>"Secure"</tt> attributes. 415 */ testParseOtherAttributes()416 public void testParseOtherAttributes() throws Exception { 417 CookieSpec cookiespec = new RFC2965Spec(); 418 Header header = new Header("Set-Cookie2", "name=value;Comment=\"good cookie\";" + 419 "CommentURL=\"www.domain.com/goodcookie/\";Secure;Version=1"); 420 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 421 assertNotNull(parsed); 422 assertEquals(1, parsed.length); 423 Cookie2 cookie = (Cookie2) parsed[0]; 424 assertEquals("good cookie", cookie.getComment()); 425 assertEquals("www.domain.com/goodcookie/", cookie.getCommentURL()); 426 assertTrue(cookie.getSecure()); 427 428 // Comment, CommentURL, Secure are OPTIONAL 429 header = new Header("Set-Cookie2", "name=value;Version=1"); 430 parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 431 assertNotNull(parsed); 432 assertEquals(1, parsed.length); 433 cookie = (Cookie2) parsed[0]; 434 assertFalse(cookie.getSecure()); 435 } 436 437 /** 438 * Test parsing header with 2 cookies (separated by comma) 439 */ testCookiesWithComma()440 public void testCookiesWithComma() throws Exception { 441 CookieSpec cookiespec = new RFC2965Spec(); 442 Header header = new Header("Set-Cookie2", "a=b,c"); 443 Cookie[] parsed = cookiespec.parse("www.domain.com", 80, "/", false, header); 444 assertNotNull(parsed); 445 assertEquals(2, parsed.length); 446 assertEquals("a", parsed[0].getName()); 447 assertEquals("b", parsed[0].getValue()); 448 assertEquals("c", parsed[1].getName()); 449 assertEquals(null, parsed[1].getValue()); 450 } 451 452 // ------------------------------------------------------- Test Cookie Validation 453 454 /** 455 * Test <tt>Domain</tt> validation when domain is not specified 456 * in <tt>Set-Cookie2</tt> header. 457 */ testValidateNoDomain()458 public void testValidateNoDomain() throws Exception { 459 CookieSpec cookiespec = new RFC2965Spec(); 460 Header header = new Header("Set-Cookie2", "name=value;Version=1"); 461 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com" /* request host */, 80, "/", false, header); 462 assertNotNull(parsed); 463 assertEquals(1, parsed.length); 464 Cookie2 cookie = (Cookie2) parsed[0]; 465 // cookie domain must string match request host 466 assertEquals("www.domain.com", cookie.getDomain()); 467 } 468 469 /** 470 * Test <tt>Domain</tt> validation. Cookie domain attribute must have a 471 * leading dot. 472 */ testValidateDomainLeadingDot()473 public void testValidateDomainLeadingDot() throws Exception { 474 CookieSpec cookiespec = new RFC2965Spec(); 475 Header header = new Header("Set-Cookie2", "name=value;Domain=domain.com;Version=1"); 476 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com", 80, "/", false, header); 477 assertNotNull(parsed); 478 assertEquals(1, parsed.length); 479 Cookie2 cookie = (Cookie2) parsed[0]; 480 assertEquals(".domain.com", cookie.getDomain()); 481 } 482 483 /** 484 * Test <tt>Domain</tt> validation. Domain must have atleast one embedded dot. 485 */ testValidateDomainEmbeddedDot()486 public void testValidateDomainEmbeddedDot() throws Exception { 487 CookieSpec cookiespec = new RFC2965Spec(); 488 Header header = new Header("Set-Cookie2", "name=value; domain=.com; version=1"); 489 try { 490 cookieParse(cookiespec, "b.com", 80, "/", false, header); 491 fail("MalformedCookieException should have been thrown"); 492 } catch (MalformedCookieException expected) {} 493 494 header = new Header("Set-Cookie2", "name=value;Domain=domain.com;Version=1"); 495 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com", 80, "/", false, header); 496 assertNotNull(parsed); 497 assertEquals(1, parsed.length); 498 } 499 500 /** 501 * Test local <tt>Domain</tt> validation. Simple host names 502 * (without any dots) are valid only when cookie domain is specified 503 * as ".local". 504 */ testValidateDomainLocal()505 public void testValidateDomainLocal() throws Exception { 506 CookieSpec cookiespec = new RFC2965Spec(); 507 // when domain is specified as .local, simple host names are valid 508 Header header = new Header("Set-Cookie2", "name=value; domain=.local; version=1"); 509 Cookie[] parsed = cookieParse(cookiespec, "simplehost" /* request host */, 80, "/", false, header); 510 assertNotNull(parsed); 511 assertEquals(1, parsed.length); 512 Cookie2 cookie = (Cookie2) parsed[0]; 513 assertEquals(".local", cookie.getDomain()); 514 515 // when domain is NOT specified as .local, simple host names are invalid 516 header = new Header("Set-Cookie2", "name=value; domain=domain.com; version=1"); 517 try { 518 // since domain is not .local, this must fail 519 parsed = cookieParse(cookiespec, "simplehost" /* request host */, 80, "/", false, header); 520 fail("MalformedCookieException should have been thrown"); 521 } catch (MalformedCookieException expected) {} 522 } 523 524 525 /** 526 * Test <tt>Domain</tt> validation. Effective host name 527 * must domain-match domain attribute. 528 */ testValidateDomainEffectiveHost()529 public void testValidateDomainEffectiveHost() throws Exception { 530 CookieSpec cookiespec = new RFC2965Spec(); 531 532 // cookie domain does not domain-match request host 533 Header header = new Header("Set-Cookie2", "name=value; domain=.domain.com; version=1"); 534 try { 535 cookieParse(cookiespec, "www.domain.org" /* request host */, 80, "/", false, header); 536 fail("MalformedCookieException should have been thrown"); 537 } catch (MalformedCookieException expected) {} 538 539 // cookie domain domain-matches request host 540 header = new Header("Set-Cookie2", "name=value; domain=.domain.com; version=1"); 541 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com" /* request host */, 80, "/", false, header); 542 assertNotNull(parsed); 543 assertEquals(1, parsed.length); 544 } 545 546 /** 547 * Test local <tt>Domain</tt> validation. 548 * Effective host name minus domain must not contain any dots. 549 */ testValidateDomainIllegal()550 public void testValidateDomainIllegal() throws Exception { 551 CookieSpec cookiespec = new RFC2965Spec(); 552 Header header = new Header("Set-Cookie2", "name=value; domain=.domain.com; version=1"); 553 try { 554 cookieParse(cookiespec, "a.b.domain.com" /* request host */, 80, "/", false, header); 555 fail("MalformedCookieException should have been thrown"); 556 } catch (MalformedCookieException expected) {} 557 } 558 559 /** 560 * Test cookie <tt>Path</tt> validation. Cookie path attribute must path-match 561 * request path. 562 */ testValidatePath()563 public void testValidatePath() throws Exception { 564 CookieSpec cookiespec = new RFC2965Spec(); 565 Header header = new Header("Set-Cookie2", "name=value;path=/path;version=1"); 566 try { 567 cookieParse(cookiespec, "www.domain.com", 80, "/" /* request path */, false, header); 568 fail("MalformedCookieException exception should have been thrown"); 569 } catch (MalformedCookieException expected) {} 570 571 // path-matching is case-sensitive 572 header = new Header("Set-Cookie2", "name=value;path=/Path;version=1"); 573 try { 574 cookieParse(cookiespec, "www.domain.com", 80, "/path" /* request path */, false, header); 575 fail("MalformedCookieException exception should have been thrown"); 576 } catch (MalformedCookieException expected) {} 577 578 header = new Header("Set-Cookie2", "name=value;path=/path;version=1"); 579 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com", 580 80, "/path/path1" /* request path */, false, header); 581 assertNotNull(parsed); 582 assertEquals(1, parsed.length); 583 assertEquals("/path", parsed[0].getPath()); 584 } 585 586 /** 587 * Test cookie name validation. 588 */ testValidateCookieName()589 public void testValidateCookieName() throws Exception { 590 CookieSpec cookiespec = new RFC2965Spec(); 591 // cookie name must not contain blanks 592 Header header = new Header("Set-Cookie2", "invalid name=value; version=1"); 593 try { 594 cookieParse(cookiespec, "127.0.0.1", 80, "/", false, header); 595 fail("MalformedCookieException exception should have been thrown"); 596 } catch (MalformedCookieException expected) {} 597 598 // cookie name must not start with '$'. 599 header = new Header("Set-Cookie2", "$invalid_name=value; version=1"); 600 try { 601 cookieParse(cookiespec, "127.0.0.1", 80, "/", false, header); 602 fail("MalformedCookieException exception should have been thrown"); 603 } catch (MalformedCookieException expected) {} 604 605 // valid name 606 header = new Header("Set-Cookie2", "name=value; version=1"); 607 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com", 80, "/", false, header); 608 assertNotNull(parsed); 609 assertEquals(1, parsed.length); 610 Cookie2 cookie = (Cookie2) parsed[0]; 611 assertEquals("name", cookie.getName()); 612 assertEquals("value", cookie.getValue()); 613 } 614 615 /** 616 * Test cookie <tt>Port</tt> validation. Request port must be in the 617 * port attribute list. 618 */ testValidatePort()619 public void testValidatePort() throws Exception { 620 Header header = new Header("Set-Cookie2", "name=value; Port=\"80,800\"; version=1"); 621 CookieSpec cookiespec = new RFC2965Spec(); 622 try { 623 cookieParse(cookiespec, "www.domain.com", 8000 /* request port */, "/", false, header); 624 fail("MalformedCookieException should have been thrown"); 625 } catch (MalformedCookieException e) {} 626 627 // valid port list 628 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com", 80 /* request port */, "/", false, header); 629 assertNotNull(parsed); 630 assertEquals(1, parsed.length); 631 Cookie2 cookie = (Cookie2) parsed[0]; 632 int[] ports = cookie.getPorts(); 633 assertNotNull(ports); 634 assertEquals(2, ports.length); 635 assertEquals(80, ports[0]); 636 assertEquals(800, ports[1]); 637 } 638 639 /** 640 * Test cookie <tt>Version</tt> validation. 641 */ testValidateVersion()642 public void testValidateVersion() throws Exception { 643 CookieSpec cookiespec = new RFC2965Spec(); 644 // version attribute is REQUIRED 645 Header header = new Header("Set-Cookie2", "name=value"); 646 try { 647 cookieParse(cookiespec, "www.domain.com", 8000, "/", false, header); 648 fail("MalformedCookieException should have been thrown"); 649 } catch (MalformedCookieException e) {} 650 } 651 652 // ------------------------------------------------------- Test Cookie Matching 653 654 /** 655 * test cookie <tt>Path</tt> matching. Cookie path attribute must path-match 656 * path of the request URI. 657 */ testMatchPath()658 public void testMatchPath() throws Exception { 659 Cookie2 cookie = new Cookie2(".domain.com", "name", 660 "value", "/path" /* path */, null, false, new int[] {80}); 661 CookieSpec cookiespec = new RFC2965Spec(); 662 assertFalse(cookiespec.match("www.domain.com", 80, "/" /* request path */, false, cookie)); 663 assertTrue(cookiespec.match("www.domain.com", 80, "/path/path1" /* request path */, false, cookie)); 664 } 665 666 /** 667 * test cookie <tt>Domain</tt> matching. 668 */ testMatchDomain()669 public void testMatchDomain() throws Exception { 670 Cookie2 cookie = new Cookie2(".domain.com" /* domain */, "name", 671 "value", "/", null, false, new int[] {80}); 672 CookieSpec cookiespec = new RFC2965Spec(); 673 // effective host name minus domain must not contain any dots 674 assertFalse(cookiespec.match("a.b.domain.com" /* request host */, 80, "/", false, cookie)); 675 // The effective host name MUST domain-match the Domain 676 // attribute of the cookie. 677 assertFalse(cookiespec.match("www.domain.org" /* request host */, 80, "/", false, cookie)); 678 assertTrue(cookiespec.match("www.domain.com" /* request host */, 80, "/", false, cookie)); 679 } 680 681 /** 682 * test cookie local <tt>Domain</tt> matching. 683 */ testMatchDomainLocal()684 public void testMatchDomainLocal() throws Exception { 685 Cookie2 cookie = new Cookie2(".local" /* domain */, "name", 686 "value", "/", null, false, new int[] {80}); 687 CookieSpec cookiespec = new RFC2965Spec(); 688 assertTrue(cookiespec.match("host" /* request host */, 80, "/", false, cookie)); 689 assertFalse(cookiespec.match("host.com" /* request host */, 80, "/", false, cookie)); 690 } 691 692 /** 693 * test cookie <tt>Port</tt> matching. 694 */ testMatchPort()695 public void testMatchPort() throws Exception { 696 // cookie can be sent to any port if port attribute not specified 697 Cookie2 cookie = new Cookie2(".domain.com", "name", 698 "value", "/", null, false, null /* ports */); 699 CookieSpec cookiespec = new RFC2965Spec(); 700 cookie.setPortAttributeSpecified(false); 701 assertTrue(cookiespec.match("www.domain.com", 8080 /* request port */, "/", false, cookie)); 702 assertTrue(cookiespec.match("www.domain.com", 323 /* request port */, "/", false, cookie)); 703 704 // otherwise, request port must be in cookie's port list 705 cookie = new Cookie2(".domain.com", "name", 706 "value", "/", null, false, new int[] {80, 8080} /* ports */); 707 cookie.setPortAttributeSpecified(true); 708 assertFalse(cookiespec.match("www.domain.com", 434 /* request port */, "/", false, cookie)); 709 assertTrue(cookiespec.match("www.domain.com", 8080 /* request port */, "/", false, cookie)); 710 } 711 712 /** 713 * test cookie expiration. 714 */ testCookieExpiration()715 public void testCookieExpiration() throws Exception { 716 Date afterOneHour = new Date(System.currentTimeMillis() + 3600 * 1000L); 717 Cookie2 cookie = new Cookie2(".domain.com", "name", 718 "value", "/", afterOneHour /* expiry */, false, null); 719 CookieSpec cookiespec = new RFC2965Spec(); 720 assertTrue(cookiespec.match("www.domain.com", 80, "/", false, cookie)); 721 722 Date beforeOneHour = new Date(System.currentTimeMillis() - 3600 * 1000L); 723 cookie = new Cookie2(".domain.com", "name", 724 "value", "/", beforeOneHour /* expiry */, false, null); 725 assertFalse(cookiespec.match("www.domain.com", 80, "/", false, cookie)); 726 727 // discard attributes overrides cookie age, makes it a session cookie. 728 cookie.setDiscard(true); 729 assertFalse(cookie.isPersistent()); 730 assertTrue(cookiespec.match("www.domain.com", 80, "/", false, cookie)); 731 } 732 733 /** 734 * test cookie <tt>Secure</tt> attribute. 735 */ testCookieSecure()736 public void testCookieSecure() throws Exception { 737 CookieSpec cookiespec = new RFC2965Spec(); 738 // secure cookie can only be sent over a secure connection 739 Cookie2 cookie = new Cookie2(".domain.com", "name", 740 "value", "/", null, true /* secure */, null); 741 assertFalse(cookiespec.match("www.domain.com", 80, "/", false /* request secure */, cookie)); 742 assertTrue(cookiespec.match("www.domain.com", 80, "/", true /* request secure */, cookie)); 743 } 744 745 // ------------------------------------------------------- Test Cookie Formatting 746 testFormatInvalidCookie()747 public void testFormatInvalidCookie() throws Exception { 748 CookieSpec cookiespec = new RFC2965Spec(); 749 try { 750 cookiespec.formatCookie(null); 751 fail("IllegalArgumentException nust have been thrown"); 752 } catch (IllegalArgumentException expected) {} 753 } 754 755 /** 756 * Tests RFC 2965 compliant cookie formatting. 757 */ testRFC2965CookieFormatting()758 public void testRFC2965CookieFormatting() throws Exception { 759 CookieSpec cookiespec = new RFC2965Spec(); 760 Cookie2 cookie1 = new Cookie2(".domain.com", "name1", 761 "value", "/", null, false, new int[] {80,8080}); 762 cookie1.setVersion(1); 763 // domain, path, port specified 764 cookie1.setDomainAttributeSpecified(true); 765 cookie1.setPathAttributeSpecified(true); 766 cookie1.setPortAttributeSpecified(true); 767 assertEquals("$Version=\"1\"; name1=\"value\"; $Domain=\".domain.com\"; $Path=\"/\"; $Port=\"80,8080\"", 768 cookiespec.formatCookie(cookie1)); 769 770 Cookie2 cookie2 = new Cookie2(".domain.com", "name2", 771 "value", "/a/", null, false, new int[] {80,8080}); 772 cookie2.setVersion(2); 773 // domain, path specified but port unspecified 774 cookie2.setDomainAttributeSpecified(true); 775 cookie2.setPathAttributeSpecified(true); 776 cookie2.setPortAttributeSpecified(false); 777 assertEquals("$Version=\"2\"; name2=\"value\"; $Domain=\".domain.com\"; $Path=\"/a/\"", 778 cookiespec.formatCookie(cookie2)); 779 780 Cookie2 cookie3 = new Cookie2(".domain.com", "name3", 781 "value", "/a/b/", null, false, new int[] {80,8080}); 782 cookie3.setVersion(1); 783 // path specified, port specified but blank, domain unspecified 784 cookie3.setDomainAttributeSpecified(false); 785 cookie3.setPathAttributeSpecified(true); 786 cookie3.setPortAttributeSpecified(true); 787 cookie3.setPortAttributeBlank(true); 788 assertEquals("$Version=\"1\"; name3=\"value\"; $Path=\"/a/b/\"; $Port=\"\"", 789 cookiespec.formatCookie(cookie3)); 790 791 assertEquals("$Version=\"2\"; " + 792 "name3=\"value\"; $Path=\"/a/b/\"; $Port=\"\"; " + 793 "name2=\"value\"; $Domain=\".domain.com\"; $Path=\"/a/\"; " + 794 "name1=\"value\"; $Domain=\".domain.com\"; $Path=\"/\"; $Port=\"80,8080\"", 795 cookiespec.formatCookies(new Cookie[] {cookie3, cookie2, cookie1})); 796 } 797 798 /** 799 * Tests RFC 2965 compliant cookies formatting. 800 */ testRFC2965CookiesFormatting()801 public void testRFC2965CookiesFormatting() throws Exception { 802 CookieSpec cookiespec = new RFC2965Spec(); 803 Cookie2 cookie1 = new Cookie2(".domain.com", "name1", 804 "value1", "/", null, false, new int[] {80,8080}); 805 cookie1.setVersion(1); 806 // domain, path, port specified 807 cookie1.setDomainAttributeSpecified(true); 808 cookie1.setPathAttributeSpecified(true); 809 cookie1.setPortAttributeSpecified(true); 810 Cookie2 cookie2 = new Cookie2(".domain.com", "name2", 811 null, "/", null, false, null); 812 cookie2.setVersion(1); 813 // value null, domain, path, port specified 814 cookie2.setDomainAttributeSpecified(true); 815 cookie2.setPathAttributeSpecified(true); 816 cookie2.setPortAttributeSpecified(false); 817 Cookie[] cookies = new Cookie[] {cookie1, cookie2}; 818 assertEquals("$Version=\"1\"; name1=\"value1\"; $Domain=\".domain.com\"; $Path=\"/\"; $Port=\"80,8080\"; " + 819 "name2=\"\"; $Domain=\".domain.com\"; $Path=\"/\"", cookiespec.formatCookies(cookies)); 820 } 821 822 // ------------------------------------------------------- Backward compatibility tests 823 824 /** 825 * Test backward compatibility with <tt>Set-Cookie</tt> header. 826 */ testCompatibilityWithSetCookie()827 public void testCompatibilityWithSetCookie() throws Exception { 828 CookieSpec cookiespec = new RFC2965Spec(); 829 Header header = new Header("Set-Cookie", "name=value; domain=.domain.com; version=1"); 830 Cookie[] parsed = cookieParse(cookiespec, "www.domain.com", 80, "/", false, header); 831 assertNotNull(parsed); 832 assertEquals(1, parsed.length); 833 assertEquals("name", parsed[0].getName()); 834 assertEquals("value", parsed[0].getValue()); 835 assertEquals(".domain.com", parsed[0].getDomain()); 836 assertEquals("/", parsed[0].getPath()); 837 } 838 839 } 840 841