/httpcomponents-client-4.1.3/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java

# · Java · 1014 lines · 752 code · 84 blank · 178 comment · 18 complexity · 49274b5fb9d204d51bbb9658e4cc3ef9 MD5 · raw file

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