1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.internal.transport.http;
11
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertTrue;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.Writer;
19 import java.net.HttpCookie;
20 import java.net.URL;
21 import java.nio.charset.StandardCharsets;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24 import java.nio.file.StandardCopyOption;
25 import java.time.Instant;
26 import java.util.Arrays;
27 import java.util.Date;
28 import java.util.LinkedHashSet;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.regex.Pattern;
32
33 import org.eclipse.jgit.internal.storage.file.LockFile;
34 import org.eclipse.jgit.util.http.HttpCookiesMatcher;
35 import org.hamcrest.CoreMatchers;
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.rules.TemporaryFolder;
40
41 public class NetscapeCookieFileTest {
42
43 @Rule
44 public TemporaryFolder folder = new TemporaryFolder();
45
46 private Path tmpFile;
47
48 private URL baseUrl;
49
50
51
52
53 private static long JAN_01_2030_NOON = Instant
54 .parse("2030-01-01T12:00:00.000Z").toEpochMilli();
55
56 @Before
57 public void setUp() throws IOException {
58
59
60 tmpFile = folder.newFile().toPath();
61 baseUrl = new URL("http://domain.com/my/path");
62 }
63
64 @Test
65 public void testMergeCookies() {
66 Set<HttpCookie> cookieSet1 = new LinkedHashSet<>();
67 HttpCookie cookie = new HttpCookie("key1", "valueFromSet1");
68 cookieSet1.add(cookie);
69 cookie = new HttpCookie("key2", "valueFromSet1");
70 cookieSet1.add(cookie);
71
72 Set<HttpCookie> cookieSet2 = new LinkedHashSet<>();
73 cookie = new HttpCookie("key1", "valueFromSet2");
74 cookieSet2.add(cookie);
75 cookie = new HttpCookie("key3", "valueFromSet2");
76 cookieSet2.add(cookie);
77
78 Set<HttpCookie> cookiesExpectedMergedSet = new LinkedHashSet<>();
79 cookie = new HttpCookie("key1", "valueFromSet1");
80 cookiesExpectedMergedSet.add(cookie);
81 cookie = new HttpCookie("key2", "valueFromSet1");
82 cookiesExpectedMergedSet.add(cookie);
83 cookie = new HttpCookie("key3", "valueFromSet2");
84 cookiesExpectedMergedSet.add(cookie);
85
86 assertThat(NetscapeCookieFile.mergeCookies(cookieSet1, cookieSet2),
87 HttpCookiesMatcher.containsInOrder(cookiesExpectedMergedSet));
88
89 assertThat(NetscapeCookieFile.mergeCookies(cookieSet1, null),
90 HttpCookiesMatcher.containsInOrder(cookieSet1));
91 }
92
93 @Test
94 public void testWriteToNewFile() throws IOException {
95 Set<HttpCookie> cookies = new LinkedHashSet<>();
96 cookies.add(new HttpCookie("key1", "value"));
97
98
99 HttpCookie cookie = new HttpCookie("key2", "value");
100 cookie.setSecure(true);
101 cookie.setDomain("mydomain.com");
102 cookie.setPath("/");
103 cookie.setMaxAge(1000);
104 cookies.add(cookie);
105 Date creationDate = new Date();
106 try (Writer writer = Files.newBufferedWriter(tmpFile,
107 StandardCharsets.US_ASCII)) {
108 NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
109 }
110
111 String expectedExpiration = String
112 .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000));
113
114 assertThat(Files.readAllLines(tmpFile, StandardCharsets.US_ASCII),
115 CoreMatchers
116 .equalTo(Arrays.asList("mydomain.com\tTRUE\t/\tTRUE\t"
117 + expectedExpiration + "\tkey2\tvalue")));
118 }
119
120 @Test
121 public void testWriteToExistingFile() throws IOException {
122 try (InputStream input = this.getClass()
123 .getResourceAsStream("cookies-simple1.txt")) {
124 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
125 }
126
127 Set<HttpCookie> cookies = new LinkedHashSet<>();
128 HttpCookie cookie = new HttpCookie("key2", "value2");
129 cookie.setMaxAge(1000);
130 cookies.add(cookie);
131 Date creationDate = new Date();
132 try (Writer writer = Files.newBufferedWriter(tmpFile,
133 StandardCharsets.US_ASCII)) {
134 NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
135 }
136 String expectedExpiration = String
137 .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000));
138
139 assertThat(Files.readAllLines(tmpFile, StandardCharsets.US_ASCII),
140 CoreMatchers.equalTo(
141 Arrays.asList("domain.com\tTRUE\t/my/path\tFALSE\t"
142 + expectedExpiration + "\tkey2\tvalue2")));
143 }
144
145 @Test(expected = IOException.class)
146 public void testWriteWhileSomeoneIsHoldingTheLock()
147 throws IllegalArgumentException, IOException, InterruptedException {
148 try (InputStream input = this.getClass()
149 .getResourceAsStream("cookies-simple1.txt")) {
150 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
151 }
152 NetscapeCookieFile cookieFile = new NetscapeCookieFile(tmpFile);
153
154 LockFile lockFile = new LockFile(tmpFile.toFile());
155 try {
156 assertTrue("Could not acquire lock", lockFile.lock());
157 cookieFile.write(baseUrl);
158 } finally {
159 lockFile.unlock();
160 }
161 }
162
163 @Test
164 public void testWriteAfterAnotherJgitProcessModifiedTheFile()
165 throws IOException, InterruptedException {
166 try (InputStream input = this.getClass()
167 .getResourceAsStream("cookies-simple1.txt")) {
168 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
169 }
170 NetscapeCookieFile cookieFile = new NetscapeCookieFile(tmpFile);
171 cookieFile.getCookies(true);
172
173 try (InputStream input = this.getClass()
174 .getResourceAsStream("cookies-simple2.txt")) {
175 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
176 }
177
178 cookieFile.write(baseUrl);
179
180
181
182
183 List<String> lines = Files.readAllLines(tmpFile,
184 StandardCharsets.US_ASCII);
185
186 assertEquals("Expected 3 lines", 3, lines.size());
187 assertStringMatchesPatternWithInexactNumber(lines.get(0),
188 "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey1\tvalueFromSimple2",
189 JAN_01_2030_NOON, 1000);
190 assertStringMatchesPatternWithInexactNumber(lines.get(1),
191 "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey3\tvalueFromSimple2",
192 JAN_01_2030_NOON, 1000);
193 assertStringMatchesPatternWithInexactNumber(lines.get(2),
194 "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey2\tvalueFromSimple1",
195 JAN_01_2030_NOON, 1000);
196 }
197
198 @SuppressWarnings("boxing")
199 private static final void assertStringMatchesPatternWithInexactNumber(
200 String string, String pattern, long expectedNumericValue,
201 long delta) {
202 java.util.regex.Matcher matcher = Pattern.compile(pattern)
203 .matcher(string);
204 assertTrue("Given string '" + string + "' does not match '" + pattern
205 + "'", matcher.matches());
206
207 Long actualNumericValue = Long.decode(matcher.group(1));
208
209 assertTrue(
210 "Value is supposed to be close to " + expectedNumericValue
211 + " but is " + actualNumericValue + ".",
212 Math.abs(expectedNumericValue - actualNumericValue) <= delta);
213 }
214
215 @Test
216 public void testWriteAndReadCycle() throws IOException {
217 Set<HttpCookie> cookies = new LinkedHashSet<>();
218
219 HttpCookie cookie = new HttpCookie("key1", "value1");
220 cookie.setPath("/some/path1");
221 cookie.setDomain("some-domain1");
222 cookie.setMaxAge(1000);
223 cookies.add(cookie);
224 cookie = new HttpCookie("key2", "value2");
225 cookie.setSecure(true);
226 cookie.setPath("/some/path2");
227 cookie.setDomain("some-domain2");
228 cookie.setMaxAge(1000);
229 cookie.setHttpOnly(true);
230 cookies.add(cookie);
231
232 Date creationDate = new Date();
233
234 try (Writer writer = Files.newBufferedWriter(tmpFile,
235 StandardCharsets.US_ASCII)) {
236 NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
237 }
238 Set<HttpCookie> actualCookies = new NetscapeCookieFile(tmpFile,
239 creationDate).getCookies(true);
240 assertThat(actualCookies, HttpCookiesMatcher.containsInOrder(cookies));
241 }
242
243 @Test
244 public void testReadAndWriteCycle() throws IOException {
245 try (InputStream input = this.getClass()
246 .getResourceAsStream("cookies-simple1.txt")) {
247 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
248 }
249
250 Date creationDate = new Date(
251 (System.currentTimeMillis() / 1000) * 1000);
252 Set<HttpCookie> cookies = new NetscapeCookieFile(tmpFile, creationDate)
253 .getCookies(true);
254 Path tmpFile2 = folder.newFile().toPath();
255 try (Writer writer = Files.newBufferedWriter(tmpFile2,
256 StandardCharsets.US_ASCII)) {
257 NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate);
258 }
259
260 assertEquals(Files.readAllLines(tmpFile), Files.readAllLines(tmpFile2));
261 }
262
263 @Test
264 public void testReadWithEmptyAndCommentLines() throws IOException {
265 try (InputStream input = this.getClass().getResourceAsStream(
266 "cookies-with-empty-and-comment-lines.txt")) {
267 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
268 }
269
270 Date creationDate = new Date();
271 Set<HttpCookie> cookies = new LinkedHashSet<>();
272
273 HttpCookie cookie = new HttpCookie("key2", "value2");
274 cookie.setDomain("some-domain2");
275 cookie.setPath("/some/path2");
276 cookie.setMaxAge((JAN_01_2030_NOON - creationDate.getTime()) / 1000);
277 cookie.setSecure(true);
278 cookie.setHttpOnly(true);
279 cookies.add(cookie);
280
281 cookie = new HttpCookie("key3", "value3");
282 cookie.setDomain("some-domain3");
283 cookie.setPath("/some/path3");
284 cookie.setMaxAge((JAN_01_2030_NOON - creationDate.getTime()) / 1000);
285 cookies.add(cookie);
286
287 Set<HttpCookie> actualCookies = new NetscapeCookieFile(tmpFile, creationDate)
288 .getCookies(true);
289 assertThat(actualCookies, HttpCookiesMatcher.containsInOrder(cookies));
290 }
291
292 @Test
293 public void testReadInvalidFile() throws IOException {
294 try (InputStream input = this.getClass()
295 .getResourceAsStream("cookies-invalid.txt")) {
296 Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING);
297 }
298
299 new NetscapeCookieFile(tmpFile)
300 .getCookies(true);
301 }
302 }