123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- /*
- * Copyright (C) 2018, Konrad Windszus <konrad_w@gmx.de>
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package org.eclipse.jgit.internal.transport.http;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.Writer;
- import java.net.HttpCookie;
- import java.net.URL;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.nio.file.StandardCopyOption;
- import java.time.Instant;
- import java.util.Arrays;
- import java.util.Date;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Set;
- import java.util.regex.Pattern;
-
- import org.eclipse.jgit.internal.storage.file.LockFile;
- import org.eclipse.jgit.util.http.HttpCookiesMatcher;
- import org.hamcrest.CoreMatchers;
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.Rule;
- import org.junit.Test;
- import org.junit.rules.TemporaryFolder;
-
- public class NetscapeCookieFileTest {
-
- @Rule
- public TemporaryFolder folder = new TemporaryFolder();
-
- private Path tmpFile;
-
- private URL baseUrl;
-
- /**
- * This is the expiration date that is used in the test cookie files
- */
- private static long JAN_01_2030_NOON = Instant
- .parse("2030-01-01T12:00:00.000Z").toEpochMilli();
-
- @Before
- public void setUp() throws IOException {
- // this will not only return a new file name but also create new empty
- // file!
- tmpFile = folder.newFile().toPath();
- baseUrl = new URL("http://domain.com/my/path");
- }
-
- @Test
- public void testMergeCookies() {
- Set<HttpCookie> cookieSet1 = new LinkedHashSet<>();
- HttpCookie cookie = new HttpCookie("key1", "valueFromSet1");
- cookieSet1.add(cookie);
- cookie = new HttpCookie("key2", "valueFromSet1");
- cookieSet1.add(cookie);
-
- Set<HttpCookie> cookieSet2 = new LinkedHashSet<>();
- cookie = new HttpCookie("key1", "valueFromSet2");
- cookieSet2.add(cookie);
- cookie = new HttpCookie("key3", "valueFromSet2");
- cookieSet2.add(cookie);
-
- Set<HttpCookie> cookiesExpectedMergedSet = new LinkedHashSet<>();
- cookie = new HttpCookie("key1", "valueFromSet1");
- cookiesExpectedMergedSet.add(cookie);
- cookie = new HttpCookie("key2", "valueFromSet1");
- cookiesExpectedMergedSet.add(cookie);
- cookie = new HttpCookie("key3", "valueFromSet2");
- cookiesExpectedMergedSet.add(cookie);
-
- Assert.assertThat(
- NetscapeCookieFile.mergeCookies(cookieSet1, cookieSet2),
- HttpCookiesMatcher.containsInOrder(cookiesExpectedMergedSet));
-
- Assert.assertThat(NetscapeCookieFile.mergeCookies(cookieSet1, null),
- HttpCookiesMatcher.containsInOrder(cookieSet1));
- }
-
- @Test
- public void testWriteToNewFile() throws IOException {
- Set<HttpCookie> cookies = new LinkedHashSet<>();
- cookies.add(new HttpCookie("key1", "value"));
- // first cookie is a session cookie (and should be ignored)
-
- HttpCookie cookie = new HttpCookie("key2", "value");
- cookie.setSecure(true);
- cookie.setDomain("mydomain.com");
- cookie.setPath("/");
- cookie.setMaxAge(1000);
- cookies.add(cookie);
- Date creationDate = new Date();
- try (Writer writer = Files.newBufferedWriter(tmpFile,
- StandardCharsets.US_ASCII)) {
- NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
- }
-
- String expectedExpiration = String
- .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000));
-
- Assert.assertThat(
- Files.readAllLines(tmpFile, StandardCharsets.US_ASCII),
- CoreMatchers
- .equalTo(Arrays.asList("mydomain.com\tTRUE\t/\tTRUE\t"
- + expectedExpiration + "\tkey2\tvalue")));
- }
-
- @Test
- public void testWriteToExistingFile() throws IOException {
- try (InputStream input = this.getClass()
- .getResourceAsStream("cookies-simple1.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
-
- Set<HttpCookie> cookies = new LinkedHashSet<>();
- HttpCookie cookie = new HttpCookie("key2", "value2");
- cookie.setMaxAge(1000);
- cookies.add(cookie);
- Date creationDate = new Date();
- try (Writer writer = Files.newBufferedWriter(tmpFile,
- StandardCharsets.US_ASCII)) {
- NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
- }
- String expectedExpiration = String
- .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000));
-
- Assert.assertThat(
- Files.readAllLines(tmpFile, StandardCharsets.US_ASCII),
- CoreMatchers.equalTo(
- Arrays.asList("domain.com\tTRUE\t/my/path\tFALSE\t"
- + expectedExpiration + "\tkey2\tvalue2")));
- }
-
- @Test(expected = IOException.class)
- public void testWriteWhileSomeoneIsHoldingTheLock()
- throws IllegalArgumentException, IOException, InterruptedException {
- try (InputStream input = this.getClass()
- .getResourceAsStream("cookies-simple1.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
- NetscapeCookieFile cookieFile = new NetscapeCookieFile(tmpFile);
- // now imitate another process/thread holding the lock file
- LockFile lockFile = new LockFile(tmpFile.toFile());
- try {
- Assert.assertTrue("Could not acquire lock", lockFile.lock());
- cookieFile.write(baseUrl);
- } finally {
- lockFile.unlock();
- }
- }
-
- @Test
- public void testWriteAfterAnotherJgitProcessModifiedTheFile()
- throws IOException, InterruptedException {
- try (InputStream input = this.getClass()
- .getResourceAsStream("cookies-simple1.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
- NetscapeCookieFile cookieFile = new NetscapeCookieFile(tmpFile);
- cookieFile.getCookies(true);
- // now modify file externally
- try (InputStream input = this.getClass()
- .getResourceAsStream("cookies-simple2.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
- // now try to write
- cookieFile.write(baseUrl);
-
- // validate that the external changes are there as well
- // due to rounding errors (conversion from ms to sec to ms)
- // the expiration date might not be exact
- List<String> lines = Files.readAllLines(tmpFile,
- StandardCharsets.US_ASCII);
-
- Assert.assertEquals("Expected 3 lines", 3, lines.size());
- assertStringMatchesPatternWithInexactNumber(lines.get(0),
- "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey1\tvalueFromSimple2",
- JAN_01_2030_NOON, 1000);
- assertStringMatchesPatternWithInexactNumber(lines.get(1),
- "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey3\tvalueFromSimple2",
- JAN_01_2030_NOON, 1000);
- assertStringMatchesPatternWithInexactNumber(lines.get(2),
- "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey2\tvalueFromSimple1",
- JAN_01_2030_NOON, 1000);
- }
-
- @SuppressWarnings("boxing")
- private static final void assertStringMatchesPatternWithInexactNumber(
- String string, String pattern, long expectedNumericValue,
- long delta) {
- java.util.regex.Matcher matcher = Pattern.compile(pattern)
- .matcher(string);
- Assert.assertTrue("Given string '" + string + "' does not match '"
- + pattern + "'", matcher.matches());
- // extract numeric value
- Long actualNumericValue = Long.decode(matcher.group(1));
-
- Assert.assertTrue(
- "Value is supposed to be close to " + expectedNumericValue
- + " but is " + actualNumericValue + ".",
- Math.abs(expectedNumericValue - actualNumericValue) <= delta);
- }
-
- @Test
- public void testWriteAndReadCycle() throws IOException {
- Set<HttpCookie> cookies = new LinkedHashSet<>();
-
- HttpCookie cookie = new HttpCookie("key1", "value1");
- cookie.setPath("/some/path1");
- cookie.setDomain("some-domain1");
- cookie.setMaxAge(1000);
- cookies.add(cookie);
- cookie = new HttpCookie("key2", "value2");
- cookie.setSecure(true);
- cookie.setPath("/some/path2");
- cookie.setDomain("some-domain2");
- cookie.setMaxAge(1000);
- cookie.setHttpOnly(true);
- cookies.add(cookie);
-
- Date creationDate = new Date();
-
- try (Writer writer = Files.newBufferedWriter(tmpFile,
- StandardCharsets.US_ASCII)) {
- NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
- }
- Set<HttpCookie> actualCookies = new NetscapeCookieFile(tmpFile,
- creationDate).getCookies(true);
- Assert.assertThat(actualCookies,
- HttpCookiesMatcher.containsInOrder(cookies));
- }
-
- @Test
- public void testReadAndWriteCycle() throws IOException {
- try (InputStream input = this.getClass()
- .getResourceAsStream("cookies-simple1.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
- // round up to the next second (to prevent rounding errors)
- Date creationDate = new Date(
- (System.currentTimeMillis() / 1000) * 1000);
- Set<HttpCookie> cookies = new NetscapeCookieFile(tmpFile, creationDate)
- .getCookies(true);
- Path tmpFile2 = folder.newFile().toPath();
- try (Writer writer = Files.newBufferedWriter(tmpFile2,
- StandardCharsets.US_ASCII)) {
- NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
- }
- // compare original file with newly written one, they should not differ
- Assert.assertEquals(Files.readAllLines(tmpFile),
- Files.readAllLines(tmpFile2));
- }
-
- @Test
- public void testReadWithEmptyAndCommentLines() throws IOException {
- try (InputStream input = this.getClass().getResourceAsStream(
- "cookies-with-empty-and-comment-lines.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
-
- Date creationDate = new Date();
- Set<HttpCookie> cookies = new LinkedHashSet<>();
-
- HttpCookie cookie = new HttpCookie("key2", "value2");
- cookie.setDomain("some-domain2");
- cookie.setPath("/some/path2");
- cookie.setMaxAge((JAN_01_2030_NOON - creationDate.getTime()) / 1000);
- cookie.setSecure(true);
- cookie.setHttpOnly(true);
- cookies.add(cookie);
-
- cookie = new HttpCookie("key3", "value3");
- cookie.setDomain("some-domain3");
- cookie.setPath("/some/path3");
- cookie.setMaxAge((JAN_01_2030_NOON - creationDate.getTime()) / 1000);
- cookies.add(cookie);
-
- Set<HttpCookie> actualCookies = new NetscapeCookieFile(tmpFile, creationDate)
- .getCookies(true);
- Assert.assertThat(actualCookies,
- HttpCookiesMatcher.containsInOrder(cookies));
- }
-
- @Test
- public void testReadInvalidFile() throws IOException {
- try (InputStream input = this.getClass()
- .getResourceAsStream("cookies-invalid.txt")) {
- Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
- }
-
- new NetscapeCookieFile(tmpFile)
- .getCookies(true);
- }
- }
|