1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.test.util.http;
20
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.UncheckedIOException;
26 import java.net.ServerSocket;
27 import java.net.URI;
28 import java.net.URL;
29 import java.nio.charset.StandardCharsets;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.nio.file.StandardCopyOption;
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.concurrent.atomic.AtomicReference;
37 import java.util.function.Supplier;
38
39 import org.eclipse.aether.ConfigurationProperties;
40 import org.eclipse.aether.DefaultRepositoryCache;
41 import org.eclipse.aether.DefaultRepositorySystemSession;
42 import org.eclipse.aether.DefaultSessionData;
43 import org.eclipse.aether.internal.impl.transport.http.DefaultChecksumExtractor;
44 import org.eclipse.aether.internal.impl.transport.http.Nx2ChecksumExtractor;
45 import org.eclipse.aether.internal.impl.transport.http.XChecksumExtractor;
46 import org.eclipse.aether.internal.test.util.TestFileUtils;
47 import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager;
48 import org.eclipse.aether.repository.Authentication;
49 import org.eclipse.aether.repository.Proxy;
50 import org.eclipse.aether.repository.RemoteRepository;
51 import org.eclipse.aether.spi.connector.transport.GetTask;
52 import org.eclipse.aether.spi.connector.transport.PeekTask;
53 import org.eclipse.aether.spi.connector.transport.PutTask;
54 import org.eclipse.aether.spi.connector.transport.Transporter;
55 import org.eclipse.aether.spi.connector.transport.http.ChecksumExtractor;
56 import org.eclipse.aether.spi.connector.transport.http.ChecksumExtractorStrategy;
57 import org.eclipse.aether.spi.connector.transport.http.HttpTransporter;
58 import org.eclipse.aether.spi.connector.transport.http.HttpTransporterException;
59 import org.eclipse.aether.spi.connector.transport.http.HttpTransporterFactory;
60 import org.eclipse.aether.spi.connector.transport.http.RFC9457.HttpRFC9457Exception;
61 import org.eclipse.aether.transfer.NoTransporterException;
62 import org.eclipse.aether.transfer.TransferCancelledException;
63 import org.eclipse.aether.util.repository.AuthenticationBuilder;
64 import org.junit.jupiter.api.AfterEach;
65 import org.junit.jupiter.api.BeforeEach;
66 import org.junit.jupiter.api.Test;
67 import org.junit.jupiter.api.TestInfo;
68 import org.junit.jupiter.api.Timeout;
69
70 import static java.util.Objects.requireNonNull;
71 import static org.junit.jupiter.api.Assertions.assertEquals;
72 import static org.junit.jupiter.api.Assertions.assertNotNull;
73 import static org.junit.jupiter.api.Assertions.assertNull;
74 import static org.junit.jupiter.api.Assertions.assertThrows;
75 import static org.junit.jupiter.api.Assertions.assertTrue;
76 import static org.junit.jupiter.api.Assertions.fail;
77
78
79
80
81 @SuppressWarnings({"checkstyle:MagicNumber", "checkstyle:MethodName"})
82 public class HttpTransporterTest {
83
84 protected static final Path KEY_STORE_PATH = Paths.get("target/keystore");
85
86 protected static final Path KEY_STORE_SELF_SIGNED_PATH = Paths.get("target/keystore-self-signed");
87
88 protected static final Path TRUST_STORE_PATH = Paths.get("target/trustStore");
89
90 static {
91
92 System.setProperty(
93 "javax.net.ssl.trustStore", KEY_STORE_PATH.toAbsolutePath().toString());
94 System.setProperty("javax.net.ssl.trustStorePassword", "server-pwd");
95 System.setProperty(
96 "javax.net.ssl.keyStore", TRUST_STORE_PATH.toAbsolutePath().toString());
97 System.setProperty("javax.net.ssl.keyStorePassword", "client-pwd");
98
99 System.setProperty("javax.net.ssl.trustStoreType", "jks");
100 System.setProperty("javax.net.ssl.keyStoreType", "jks");
101
102 }
103
104 private final Supplier<HttpTransporterFactory> transporterFactorySupplier;
105
106 protected DefaultRepositorySystemSession session;
107
108 protected HttpTransporterFactory factory;
109
110 protected HttpTransporter transporter;
111
112 protected Runnable closer;
113
114 protected File repoDir;
115
116 protected HttpServer httpServer;
117
118 protected Authentication auth;
119
120 protected Proxy proxy;
121
122 protected HttpTransporterTest(Supplier<HttpTransporterFactory> transporterFactorySupplier) {
123 this.transporterFactorySupplier = requireNonNull(transporterFactorySupplier);
124
125 if (!Files.isRegularFile(KEY_STORE_PATH)) {
126 URL keyStoreUrl = HttpTransporterTest.class.getClassLoader().getResource("ssl/server-store");
127 URL keyStoreSelfSignedUrl =
128 HttpTransporterTest.class.getClassLoader().getResource("ssl/server-store-selfsigned");
129 URL trustStoreUrl = HttpTransporterTest.class.getClassLoader().getResource("ssl/client-store");
130
131 try {
132 try (InputStream keyStoreStream = keyStoreUrl.openStream();
133 InputStream keyStoreSelfSignedStream = keyStoreSelfSignedUrl.openStream();
134 InputStream trustStoreStream = trustStoreUrl.openStream()) {
135 Files.copy(keyStoreStream, KEY_STORE_PATH, StandardCopyOption.REPLACE_EXISTING);
136 Files.copy(
137 keyStoreSelfSignedStream, KEY_STORE_SELF_SIGNED_PATH, StandardCopyOption.REPLACE_EXISTING);
138 Files.copy(trustStoreStream, TRUST_STORE_PATH, StandardCopyOption.REPLACE_EXISTING);
139 }
140 } catch (IOException e) {
141 throw new UncheckedIOException(e);
142 }
143 }
144 }
145
146 protected static ChecksumExtractor standardChecksumExtractor() {
147 HashMap<String, ChecksumExtractorStrategy> strategies = new HashMap<>();
148 strategies.put("1", new Nx2ChecksumExtractor());
149 strategies.put("2", new XChecksumExtractor());
150 return new DefaultChecksumExtractor(strategies);
151 }
152
153 protected RemoteRepository newRepo(String url) {
154 return new RemoteRepository.Builder("test", "default", url)
155 .setAuthentication(auth)
156 .setProxy(proxy)
157 .build();
158 }
159
160 protected void newTransporter(String url) throws Exception {
161 if (transporter != null) {
162 transporter.close();
163 transporter = null;
164 }
165 if (closer != null) {
166 closer.run();
167 closer = null;
168 }
169 session = new DefaultRepositorySystemSession(session);
170 session.setData(new DefaultSessionData());
171 transporter = factory.newInstance(session, newRepo(url));
172 }
173
174 protected static final long OLD_FILE_TIMESTAMP = 160660800000L;
175
176 @BeforeEach
177 protected void setUp(TestInfo testInfo) throws Exception {
178 System.out.println("=== " + testInfo.getDisplayName() + " ===");
179 session = new DefaultRepositorySystemSession(h -> {
180 this.closer = h;
181 return true;
182 });
183 session.setLocalRepositoryManager(new TestLocalRepositoryManager());
184 factory = transporterFactorySupplier.get();
185 repoDir = TestFileUtils.createTempDir();
186 TestFileUtils.writeString(new File(repoDir, "file.txt"), "test");
187 TestFileUtils.writeString(new File(repoDir, "dir/file.txt"), "test");
188 TestFileUtils.writeString(new File(repoDir, "dir/oldFile.txt"), "oldTest", OLD_FILE_TIMESTAMP);
189 TestFileUtils.writeString(new File(repoDir, "empty.txt"), "");
190 TestFileUtils.writeString(new File(repoDir, "some space.txt"), "space");
191 File resumable = new File(repoDir, "resume.txt");
192 TestFileUtils.writeString(resumable, "resumable");
193 resumable.setLastModified(System.currentTimeMillis() - 90 * 1000);
194 httpServer = new HttpServer().setRepoDir(repoDir).start();
195 newTransporter(httpServer.getHttpUrl());
196 }
197
198 @AfterEach
199 protected void tearDown() throws Exception {
200 if (transporter != null) {
201 transporter.close();
202 transporter = null;
203 }
204 if (closer != null) {
205 closer.run();
206 closer = null;
207 }
208 if (httpServer != null) {
209 httpServer.stop();
210 httpServer = null;
211 }
212 factory = null;
213 session = null;
214 }
215
216 @Test
217 protected void testClassify() {
218 assertEquals(Transporter.ERROR_OTHER, transporter.classify(new FileNotFoundException()));
219 assertEquals(Transporter.ERROR_OTHER, transporter.classify(new HttpTransporterException(403)));
220 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(new HttpTransporterException(404)));
221 }
222
223 @Test
224 protected void testPeek() throws Exception {
225 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
226 }
227
228 @Test
229 protected void testRetryHandler_defaultCount_positive() throws Exception {
230 httpServer.setConnectionsToClose(3);
231 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
232 }
233
234 @Test
235 protected void testRetryHandler_defaultCount_negative() throws Exception {
236 httpServer.setConnectionsToClose(4);
237 try {
238 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
239 fail("Expected error");
240 } catch (Exception expected) {
241 }
242 }
243
244 @Test
245 protected void testRetryHandler_explicitCount_positive() throws Exception {
246 session.setConfigProperty(ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT, 10);
247 newTransporter(httpServer.getHttpUrl());
248 httpServer.setConnectionsToClose(10);
249 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
250 }
251
252 @Test
253 protected void testRetryHandler_disabled() throws Exception {
254 session.setConfigProperty(ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT, 0);
255 newTransporter(httpServer.getHttpUrl());
256 httpServer.setConnectionsToClose(1);
257 try {
258 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
259 } catch (Exception expected) {
260 }
261 }
262
263 @Test
264 protected void testPeek_NotFound() throws Exception {
265 try {
266 transporter.peek(new PeekTask(URI.create("repo/missing.txt")));
267 fail("Expected error");
268 } catch (HttpTransporterException e) {
269 assertEquals(404, e.getStatusCode());
270 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
271 }
272 }
273
274 @Test
275 protected void testPeek_Closed() throws Exception {
276 transporter.close();
277 try {
278 transporter.peek(new PeekTask(URI.create("repo/missing.txt")));
279 fail("Expected error");
280 } catch (IllegalStateException e) {
281 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
282 }
283 }
284
285 @Test
286 protected void testPeek_Authenticated() throws Exception {
287 httpServer.setAuthentication("testuser", "testpass");
288 auth = new AuthenticationBuilder()
289 .addUsername("testuser")
290 .addPassword("testpass")
291 .build();
292 newTransporter(httpServer.getHttpUrl());
293 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
294 }
295
296 @Test
297 protected void testPeek_Unauthenticated() throws Exception {
298 httpServer.setAuthentication("testuser", "testpass");
299 try {
300 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
301 fail("Expected error");
302 } catch (HttpTransporterException e) {
303 assertEquals(401, e.getStatusCode());
304 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
305 }
306 }
307
308 @Test
309 protected void testPeek_ProxyAuthenticated() throws Exception {
310 httpServer.setProxyAuthentication("testuser", "testpass");
311 auth = new AuthenticationBuilder()
312 .addUsername("testuser")
313 .addPassword("testpass")
314 .build();
315 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
316 newTransporter("http://bad.localhost:1/");
317 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
318 }
319
320 @Test
321 protected void testPeek_ProxyUnauthenticated() throws Exception {
322 httpServer.setProxyAuthentication("testuser", "testpass");
323 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort());
324 newTransporter("http://bad.localhost:1/");
325 try {
326 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
327 fail("Expected error");
328 } catch (HttpTransporterException e) {
329 assertEquals(407, e.getStatusCode());
330 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
331 }
332 }
333
334 @Test
335 protected void testPeek_SSL() throws Exception {
336 httpServer.addSslConnector();
337 newTransporter(httpServer.getHttpsUrl());
338 transporter.peek(new PeekTask(URI.create("repo/file.txt")));
339 }
340
341 @Test
342 protected void testPeek_Redirect() throws Exception {
343 httpServer.addSslConnector();
344 transporter.peek(new PeekTask(URI.create("redirect/file.txt")));
345 transporter.peek(new PeekTask(URI.create("redirect/file.txt?scheme=https")));
346 }
347
348 @Test
349 protected void testGet_ToMemory() throws Exception {
350 RecordingTransportListener listener = new RecordingTransportListener();
351 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
352 transporter.get(task);
353 assertEquals("test", task.getDataString());
354 assertEquals(0L, listener.getDataOffset());
355 assertEquals(4L, listener.getDataLength());
356 assertEquals(1, listener.getStartedCount());
357 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
358 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
359 }
360
361 @Test
362 protected void testGet_ToFile() throws Exception {
363 File file = TestFileUtils.createTempFile("failure");
364 RecordingTransportListener listener = new RecordingTransportListener();
365 GetTask task = new GetTask(URI.create("repo/file.txt"))
366 .setDataPath(file.toPath())
367 .setListener(listener);
368 transporter.get(task);
369 assertEquals("test", TestFileUtils.readString(file));
370 assertEquals(0L, listener.getDataOffset());
371 assertEquals(4L, listener.getDataLength());
372 assertEquals(1, listener.getStartedCount());
373 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
374 assertEquals("test", listener.getBaos().toString(StandardCharsets.UTF_8));
375 }
376
377 @Test
378 protected void testGet_ToFileTimestamp() throws Exception {
379 File file = TestFileUtils.createTempFile("failure");
380 RecordingTransportListener listener = new RecordingTransportListener();
381 GetTask task = new GetTask(URI.create("repo/dir/oldFile.txt"))
382 .setDataPath(file.toPath())
383 .setListener(listener);
384 transporter.get(task);
385 assertEquals("oldTest", TestFileUtils.readString(file));
386 assertEquals(0L, listener.getDataOffset());
387 assertEquals(7L, listener.getDataLength());
388 assertEquals(1, listener.getStartedCount());
389 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
390 assertEquals("oldTest", listener.getBaos().toString(StandardCharsets.UTF_8));
391 assertEquals(file.lastModified(), OLD_FILE_TIMESTAMP);
392 }
393
394 @Test
395 protected void testGet_EmptyResource() throws Exception {
396 File file = TestFileUtils.createTempFile("failure");
397 RecordingTransportListener listener = new RecordingTransportListener();
398 GetTask task = new GetTask(URI.create("repo/empty.txt"))
399 .setDataPath(file.toPath())
400 .setListener(listener);
401 transporter.get(task);
402 assertEquals("", TestFileUtils.readString(file));
403 assertEquals(0L, listener.getDataOffset());
404 assertEquals(0L, listener.getDataLength());
405 assertEquals(1, listener.getStartedCount());
406 assertEquals(0, listener.getProgressedCount());
407 assertEquals("", listener.getBaos().toString(StandardCharsets.UTF_8));
408 }
409
410 @Test
411 protected void testGet_EncodedResourcePath() throws Exception {
412 GetTask task = new GetTask(URI.create("repo/some%20space.txt"));
413 transporter.get(task);
414 assertEquals("space", task.getDataString());
415 }
416
417 @Test
418 protected void testGet_Authenticated() throws Exception {
419 httpServer.setAuthentication("testuser", "testpass");
420 auth = new AuthenticationBuilder()
421 .addUsername("testuser")
422 .addPassword("testpass")
423 .build();
424 newTransporter(httpServer.getHttpUrl());
425 RecordingTransportListener listener = new RecordingTransportListener();
426 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
427 transporter.get(task);
428 assertEquals("test", task.getDataString());
429 assertEquals(0L, listener.getDataOffset());
430 assertEquals(4L, listener.getDataLength());
431 assertEquals(1, listener.getStartedCount());
432 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
433 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
434 }
435
436 @Test
437 protected void testGet_Unauthenticated() throws Exception {
438 httpServer.setAuthentication("testuser", "testpass");
439 try {
440 transporter.get(new GetTask(URI.create("repo/file.txt")));
441 fail("Expected error");
442 } catch (HttpTransporterException e) {
443 assertEquals(401, e.getStatusCode());
444 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
445 }
446 }
447
448 @Test
449 protected void testGet_ProxyAuthenticated() throws Exception {
450 httpServer.setProxyAuthentication("testuser", "testpass");
451 Authentication auth = new AuthenticationBuilder()
452 .addUsername("testuser")
453 .addPassword("testpass")
454 .build();
455 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
456 newTransporter("http://bad.localhost:1/");
457 RecordingTransportListener listener = new RecordingTransportListener();
458 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
459 transporter.get(task);
460 assertEquals("test", task.getDataString());
461 assertEquals(0L, listener.getDataOffset());
462 assertEquals(4L, listener.getDataLength());
463 assertEquals(1, listener.getStartedCount());
464 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
465 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
466 }
467
468 @Test
469 protected void testGet_ProxyUnauthenticated() throws Exception {
470 httpServer.setProxyAuthentication("testuser", "testpass");
471 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort());
472 newTransporter("http://bad.localhost:1/");
473 try {
474 transporter.get(new GetTask(URI.create("repo/file.txt")));
475 fail("Expected error");
476 } catch (HttpTransporterException e) {
477 assertEquals(407, e.getStatusCode());
478 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
479 }
480 }
481
482 @Test
483 protected void testGet_RFC9457Response() throws Exception {
484 try {
485 transporter.get(new GetTask(URI.create("rfc9457/file.txt")));
486 fail("Expected error");
487 } catch (HttpRFC9457Exception e) {
488 assertEquals(403, e.getStatusCode());
489 assertEquals(e.getPayload().getType(), URI.create("https://example.com/probs/out-of-credit"));
490 assertEquals(e.getPayload().getStatus(), 403);
491 assertEquals(e.getPayload().getTitle(), "You do not have enough credit.");
492 assertEquals(e.getPayload().getDetail(), "Your current balance is 30, but that costs 50.");
493 assertEquals(e.getPayload().getInstance(), URI.create("/account/12345/msgs/abc"));
494 }
495 }
496
497 @Test
498 protected void testGet_RFC9457Response_with_missing_fields() throws Exception {
499 try {
500 transporter.get(new GetTask(URI.create("rfc9457/missing_fields.txt")));
501 fail("Expected error");
502 } catch (HttpRFC9457Exception e) {
503 assertEquals(403, e.getStatusCode());
504 assertEquals(e.getPayload().getType(), URI.create("about:blank"));
505 assertNull(e.getPayload().getStatus());
506 assertNull(e.getPayload().getTitle());
507 assertNull(e.getPayload().getDetail());
508 assertNull(e.getPayload().getInstance());
509 }
510 }
511
512 @Test
513 protected void testGet_SSL() throws Exception {
514 httpServer.addSslConnector();
515 newTransporter(httpServer.getHttpsUrl());
516 RecordingTransportListener listener = new RecordingTransportListener();
517 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
518 transporter.get(task);
519 assertEquals("test", task.getDataString());
520 assertEquals(0L, listener.getDataOffset());
521 assertEquals(4L, listener.getDataLength());
522 assertEquals(1, listener.getStartedCount());
523 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
524 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
525 }
526
527 @Test
528 protected void testGet_SSL_WithServerErrors() throws Exception {
529 httpServer.setServerErrorsBeforeWorks(1);
530 httpServer.addSslConnector();
531 newTransporter(httpServer.getHttpsUrl());
532 for (int i = 1; i < 3; i++) {
533 try {
534 RecordingTransportListener listener = new RecordingTransportListener();
535 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
536 transporter.get(task);
537 assertEquals("test", task.getDataString());
538 assertEquals(0L, listener.getDataOffset());
539 assertEquals(4L, listener.getDataLength());
540 assertEquals(1, listener.getStartedCount());
541 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
542 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
543 } catch (HttpTransporterException e) {
544 assertEquals(500, e.getStatusCode());
545 }
546 }
547 }
548
549 @Test
550 protected void testGet_HTTPS_Unknown_SecurityMode() throws Exception {
551 session.setConfigProperty(ConfigurationProperties.HTTPS_SECURITY_MODE, "unknown");
552 httpServer.addSelfSignedSslConnector();
553 try {
554 newTransporter(httpServer.getHttpsUrl());
555 fail("Unsupported security mode");
556 } catch (IllegalArgumentException a) {
557
558 }
559 }
560
561 @Test
562 protected void testGet_HTTPS_Insecure_SecurityMode() throws Exception {
563
564
565 session.setConfigProperty(
566 ConfigurationProperties.HTTPS_SECURITY_MODE, ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE);
567 httpServer.addSelfSignedSslConnector();
568 newTransporter(httpServer.getHttpsUrl());
569 RecordingTransportListener listener = new RecordingTransportListener();
570 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
571 transporter.get(task);
572 assertEquals("test", task.getDataString());
573 assertEquals(0L, listener.getDataOffset());
574 assertEquals(4L, listener.getDataLength());
575 assertEquals(1, listener.getStartedCount());
576 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
577 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
578 }
579
580 @Test
581 protected void testGet_HTTPS_HTTP2Only_Insecure_SecurityMode() throws Exception {
582
583
584 enableHttp2Protocol();
585 session.setConfigProperty(
586 ConfigurationProperties.HTTPS_SECURITY_MODE, ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE);
587 httpServer.addSelfSignedSslConnectorHttp2Only();
588 newTransporter(httpServer.getHttpsUrl());
589 RecordingTransportListener listener = new RecordingTransportListener();
590 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
591 transporter.get(task);
592 assertEquals("test", task.getDataString());
593 assertEquals(0L, listener.getDataOffset());
594 assertEquals(4L, listener.getDataLength());
595 assertEquals(1, listener.getStartedCount());
596 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
597 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
598 }
599
600 protected void enableHttp2Protocol() {}
601
602 @Test
603 protected void testGet_Redirect() throws Exception {
604 httpServer.addSslConnector();
605 RecordingTransportListener listener = new RecordingTransportListener();
606 GetTask task = new GetTask(URI.create("redirect/file.txt?scheme=https")).setListener(listener);
607 transporter.get(task);
608 assertEquals("test", task.getDataString());
609 assertEquals(0L, listener.getDataOffset());
610 assertEquals(4L, listener.getDataLength());
611 assertEquals(1, listener.getStartedCount());
612 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
613 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
614 }
615
616 @Test
617 protected void testGet_Resume() throws Exception {
618 File file = TestFileUtils.createTempFile("re");
619 RecordingTransportListener listener = new RecordingTransportListener();
620 GetTask task = new GetTask(URI.create("repo/resume.txt"))
621 .setDataPath(file.toPath(), true)
622 .setListener(listener);
623 transporter.get(task);
624 assertEquals("resumable", TestFileUtils.readString(file));
625 assertEquals(1L, listener.getStartedCount());
626 assertEquals(2L, listener.getDataOffset());
627 assertEquals(9, listener.getDataLength());
628 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
629 assertEquals("sumable", listener.getBaos().toString(StandardCharsets.UTF_8));
630 }
631
632 @Test
633 protected void testGet_ResumeLocalContentsOutdated() throws Exception {
634 File file = TestFileUtils.createTempFile("re");
635 file.setLastModified(System.currentTimeMillis() - 5 * 60 * 1000);
636 RecordingTransportListener listener = new RecordingTransportListener();
637 GetTask task = new GetTask(URI.create("repo/resume.txt"))
638 .setDataPath(file.toPath(), true)
639 .setListener(listener);
640 transporter.get(task);
641 assertEquals("resumable", TestFileUtils.readString(file));
642 assertEquals(1L, listener.getStartedCount());
643 assertEquals(0L, listener.getDataOffset());
644 assertEquals(9, listener.getDataLength());
645 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
646 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8));
647 }
648
649 @Test
650 protected void testGet_ResumeRangesNotSupportedByServer() throws Exception {
651 httpServer.setRangeSupport(false);
652 File file = TestFileUtils.createTempFile("re");
653 RecordingTransportListener listener = new RecordingTransportListener();
654 GetTask task = new GetTask(URI.create("repo/resume.txt"))
655 .setDataPath(file.toPath(), true)
656 .setListener(listener);
657 transporter.get(task);
658 assertEquals("resumable", TestFileUtils.readString(file));
659 assertEquals(1L, listener.getStartedCount());
660 assertEquals(0L, listener.getDataOffset());
661 assertEquals(9, listener.getDataLength());
662 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
663 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8));
664 }
665
666 @Test
667 protected void testGet_Checksums_Nexus() throws Exception {
668 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.NEXUS);
669 GetTask task = new GetTask(URI.create("repo/file.txt"));
670 transporter.get(task);
671 assertEquals("test", task.getDataString());
672 assertEquals(
673 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1"));
674 }
675
676 @Test
677 protected void testGet_Checksums_XChecksum() throws Exception {
678 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.XCHECKSUM);
679 GetTask task = new GetTask(URI.create("repo/file.txt"));
680 transporter.get(task);
681 assertEquals("test", task.getDataString());
682 assertEquals(
683 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1"));
684 }
685
686 @Test
687 protected void testGet_FileHandleLeak() throws Exception {
688 for (int i = 0; i < 100; i++) {
689 File file = TestFileUtils.createTempFile("failure");
690 transporter.get(new GetTask(URI.create("repo/file.txt")).setDataPath(file.toPath()));
691 assertTrue(file.delete(), i + ", " + file.getAbsolutePath());
692 }
693 }
694
695 @Test
696 protected void testGet_NotFound() throws Exception {
697 try {
698 transporter.get(new GetTask(URI.create("repo/missing.txt")));
699 fail("Expected error");
700 } catch (HttpTransporterException e) {
701 assertEquals(404, e.getStatusCode());
702 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
703 }
704 }
705
706 @Test
707 protected void testGet_Closed() throws Exception {
708 transporter.close();
709 try {
710 transporter.get(new GetTask(URI.create("repo/file.txt")));
711 fail("Expected error");
712 } catch (IllegalStateException e) {
713 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
714 }
715 }
716
717 @Test
718 protected void testGet_StartCancelled() throws Exception {
719 RecordingTransportListener listener = new RecordingTransportListener();
720 listener.cancelStart();
721 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
722 try {
723 transporter.get(task);
724 fail("Expected error");
725 } catch (TransferCancelledException e) {
726 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
727 }
728 assertEquals(0L, listener.getDataOffset());
729 assertEquals(4L, listener.getDataLength());
730 assertEquals(1, listener.getStartedCount());
731 assertEquals(0, listener.getProgressedCount());
732 }
733
734 @Test
735 protected void testGet_ProgressCancelled() throws Exception {
736 RecordingTransportListener listener = new RecordingTransportListener();
737 listener.cancelProgress();
738 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
739 try {
740 transporter.get(task);
741 fail("Expected error");
742 } catch (TransferCancelledException e) {
743 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
744 }
745 assertEquals(0L, listener.getDataOffset());
746 assertEquals(4L, listener.getDataLength());
747 assertEquals(1, listener.getStartedCount());
748 assertEquals(1, listener.getProgressedCount());
749 }
750
751 @Test
752 protected void testPut_FromMemory() throws Exception {
753 RecordingTransportListener listener = new RecordingTransportListener();
754 PutTask task =
755 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
756 transporter.put(task);
757 assertEquals(0L, listener.getDataOffset());
758 assertEquals(6L, listener.getDataLength());
759 assertEquals(1, listener.getStartedCount());
760 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
761 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
762 }
763
764 @Test
765 protected void testPut_FromFile() throws Exception {
766 File file = TestFileUtils.createTempFile("upload");
767 RecordingTransportListener listener = new RecordingTransportListener();
768 PutTask task =
769 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataPath(file.toPath());
770 transporter.put(task);
771 assertEquals(0L, listener.getDataOffset());
772 assertEquals(6L, listener.getDataLength());
773 assertEquals(1, listener.getStartedCount());
774 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
775 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
776 }
777
778 @Test
779 protected void testPut_EmptyResource() throws Exception {
780 RecordingTransportListener listener = new RecordingTransportListener();
781 PutTask task = new PutTask(URI.create("repo/file.txt")).setListener(listener);
782 transporter.put(task);
783 assertEquals(0L, listener.getDataOffset());
784 assertEquals(0L, listener.getDataLength());
785 assertEquals(1, listener.getStartedCount());
786 assertEquals(0, listener.getProgressedCount());
787 assertEquals("", TestFileUtils.readString(new File(repoDir, "file.txt")));
788 }
789
790 @Test
791 protected void testPut_EncodedResourcePath() throws Exception {
792 RecordingTransportListener listener = new RecordingTransportListener();
793 PutTask task = new PutTask(URI.create("repo/some%20space.txt"))
794 .setListener(listener)
795 .setDataString("OK");
796 transporter.put(task);
797 assertEquals(0L, listener.getDataOffset());
798 assertEquals(2L, listener.getDataLength());
799 assertEquals(1, listener.getStartedCount());
800 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
801 assertEquals("OK", TestFileUtils.readString(new File(repoDir, "some space.txt")));
802 }
803
804 @Test
805 protected void testPut_Authenticated_ExpectContinue() throws Exception {
806 httpServer.setAuthentication("testuser", "testpass");
807 auth = new AuthenticationBuilder()
808 .addUsername("testuser")
809 .addPassword("testpass")
810 .build();
811 newTransporter(httpServer.getHttpUrl());
812 RecordingTransportListener listener = new RecordingTransportListener();
813 PutTask task =
814 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
815 transporter.put(task);
816 assertEquals(0L, listener.getDataOffset());
817 assertEquals(6L, listener.getDataLength());
818 assertEquals(1, listener.getStartedCount());
819 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
820 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
821 }
822
823 @Test
824 protected void testPut_Authenticated_ExpectContinueBroken() throws Exception {
825
826 session.setConfigProperty(ConfigurationProperties.HTTP_SUPPORT_WEBDAV, true);
827 httpServer.setAuthentication("testuser", "testpass");
828 httpServer.setExpectSupport(HttpServer.ExpectContinue.BROKEN);
829 auth = new AuthenticationBuilder()
830 .addUsername("testuser")
831 .addPassword("testpass")
832 .build();
833 newTransporter(httpServer.getHttpUrl());
834 RecordingTransportListener listener = new RecordingTransportListener();
835 PutTask task =
836 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
837 transporter.put(task);
838 assertEquals(0L, listener.getDataOffset());
839 assertEquals(6L, listener.getDataLength());
840 assertEquals(1, listener.getStartedCount());
841 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
842 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
843 }
844
845 @Test
846 protected void testPut_Authenticated_ExpectContinueRejected() throws Exception {
847 httpServer.setAuthentication("testuser", "testpass");
848 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL);
849 auth = new AuthenticationBuilder()
850 .addUsername("testuser")
851 .addPassword("testpass")
852 .build();
853 newTransporter(httpServer.getHttpUrl());
854 RecordingTransportListener listener = new RecordingTransportListener();
855 PutTask task =
856 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
857 transporter.put(task);
858 assertEquals(0L, listener.getDataOffset());
859 assertEquals(6L, listener.getDataLength());
860 assertEquals(1, listener.getStartedCount());
861 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
862 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
863 }
864
865 @Test
866 protected void testPut_Authenticated_ExpectContinueDisabled() throws Exception {
867 session.setConfigProperty(ConfigurationProperties.HTTP_EXPECT_CONTINUE, false);
868 httpServer.setAuthentication("testuser", "testpass");
869 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL);
870 auth = new AuthenticationBuilder()
871 .addUsername("testuser")
872 .addPassword("testpass")
873 .build();
874 newTransporter(httpServer.getHttpUrl());
875 RecordingTransportListener listener = new RecordingTransportListener();
876 PutTask task =
877 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
878 transporter.put(task);
879 assertEquals(0L, listener.getDataOffset());
880 assertEquals(6L, listener.getDataLength());
881 assertEquals(1, listener.getStartedCount());
882 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
883 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
884 }
885
886 @Test
887 protected void testPut_Authenticated_ExpectContinueRejected_ExplicitlyConfiguredHeader() throws Exception {
888 Map<String, String> headers = new HashMap<>();
889 headers.put("Expect", "100-continue");
890 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers);
891 httpServer.setAuthentication("testuser", "testpass");
892 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL);
893 auth = new AuthenticationBuilder()
894 .addUsername("testuser")
895 .addPassword("testpass")
896 .build();
897 newTransporter(httpServer.getHttpUrl());
898 RecordingTransportListener listener = new RecordingTransportListener();
899 PutTask task =
900 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
901 transporter.put(task);
902 assertEquals(0L, listener.getDataOffset());
903 assertEquals(6L, listener.getDataLength());
904 assertEquals(1, listener.getStartedCount());
905 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
906 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
907 }
908
909 @Test
910 protected void testPut_Unauthenticated() throws Exception {
911 httpServer.setAuthentication("testuser", "testpass");
912 RecordingTransportListener listener = new RecordingTransportListener();
913 PutTask task =
914 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
915 try {
916 transporter.put(task);
917 fail("Expected error");
918 } catch (HttpTransporterException e) {
919 assertEquals(401, e.getStatusCode());
920 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
921 }
922 assertEquals(0, listener.getStartedCount());
923 assertEquals(0, listener.getProgressedCount());
924 }
925
926 @Test
927 protected void testPut_ProxyAuthenticated() throws Exception {
928 httpServer.setProxyAuthentication("testuser", "testpass");
929 Authentication auth = new AuthenticationBuilder()
930 .addUsername("testuser")
931 .addPassword("testpass")
932 .build();
933 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
934 newTransporter("http://bad.localhost:1/");
935 RecordingTransportListener listener = new RecordingTransportListener();
936 PutTask task =
937 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
938 transporter.put(task);
939 assertEquals(0L, listener.getDataOffset());
940 assertEquals(6L, listener.getDataLength());
941 assertEquals(1, listener.getStartedCount());
942 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
943 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
944 }
945
946 @Test
947 protected void testPut_ProxyUnauthenticated() throws Exception {
948 httpServer.setProxyAuthentication("testuser", "testpass");
949 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort());
950 newTransporter("http://bad.localhost:1/");
951 RecordingTransportListener listener = new RecordingTransportListener();
952 PutTask task =
953 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
954 try {
955 transporter.put(task);
956 fail("Expected error");
957 } catch (HttpTransporterException e) {
958 assertEquals(407, e.getStatusCode());
959 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
960 }
961 assertEquals(0, listener.getStartedCount());
962 assertEquals(0, listener.getProgressedCount());
963 }
964
965 @Test
966 protected void testPut_SSL() throws Exception {
967 httpServer.addSslConnector();
968 httpServer.setAuthentication("testuser", "testpass");
969 auth = new AuthenticationBuilder()
970 .addUsername("testuser")
971 .addPassword("testpass")
972 .build();
973 newTransporter(httpServer.getHttpsUrl());
974 RecordingTransportListener listener = new RecordingTransportListener();
975 PutTask task =
976 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
977 transporter.put(task);
978 assertEquals(0L, listener.getDataOffset());
979 assertEquals(6L, listener.getDataLength());
980 assertEquals(1, listener.getStartedCount());
981 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
982 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
983 }
984
985 @Test
986 protected void testPut_FileHandleLeak() throws Exception {
987 for (int i = 0; i < 100; i++) {
988 File src = TestFileUtils.createTempFile("upload");
989 File dst = new File(repoDir, "file.txt");
990 transporter.put(new PutTask(URI.create("repo/file.txt")).setDataPath(src.toPath()));
991 assertTrue(src.delete(), i + ", " + src.getAbsolutePath());
992 assertTrue(dst.delete(), i + ", " + dst.getAbsolutePath());
993 }
994 }
995
996 @Test
997 protected void testPut_Closed() throws Exception {
998 transporter.close();
999 try {
1000 transporter.put(new PutTask(URI.create("repo/missing.txt")));
1001 fail("Expected error");
1002 } catch (IllegalStateException e) {
1003 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1004 }
1005 }
1006
1007 @Test
1008 protected void testPut_StartCancelled() throws Exception {
1009 RecordingTransportListener listener = new RecordingTransportListener();
1010 listener.cancelStart();
1011 PutTask task =
1012 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
1013 try {
1014 transporter.put(task);
1015 fail("Expected error");
1016 } catch (TransferCancelledException e) {
1017 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1018 }
1019 assertEquals(0L, listener.getDataOffset());
1020 assertEquals(6L, listener.getDataLength());
1021 assertEquals(1, listener.getStartedCount());
1022 assertEquals(0, listener.getProgressedCount());
1023 }
1024
1025 @Test
1026 protected void testPut_ProgressCancelled() throws Exception {
1027 RecordingTransportListener listener = new RecordingTransportListener();
1028 listener.cancelProgress();
1029 PutTask task =
1030 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
1031 try {
1032 transporter.put(task);
1033 fail("Expected error");
1034 } catch (TransferCancelledException e) {
1035 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1036 }
1037 assertEquals(0L, listener.getDataOffset());
1038 assertEquals(6L, listener.getDataLength());
1039 assertEquals(1, listener.getStartedCount());
1040 assertEquals(1, listener.getProgressedCount());
1041 }
1042
1043 @Test
1044 protected void testGetPut_AuthCache() throws Exception {
1045 httpServer.setAuthentication("testuser", "testpass");
1046 auth = new AuthenticationBuilder()
1047 .addUsername("testuser")
1048 .addPassword("testpass")
1049 .build();
1050 newTransporter(httpServer.getHttpUrl());
1051 GetTask get = new GetTask(URI.create("repo/file.txt"));
1052 transporter.get(get);
1053 RecordingTransportListener listener = new RecordingTransportListener();
1054 PutTask task =
1055 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
1056 transporter.put(task);
1057 assertEquals(1, listener.getStartedCount());
1058 }
1059
1060 @Test
1061 protected void testPut_PreemptiveIsDefault() throws Exception {
1062 httpServer.setAuthentication("testuser", "testpass");
1063 auth = new AuthenticationBuilder()
1064 .addUsername("testuser")
1065 .addPassword("testpass")
1066 .build();
1067 newTransporter(httpServer.getHttpUrl());
1068 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1069 transporter.put(task);
1070 assertEquals(1, httpServer.getLogEntries().size());
1071 }
1072
1073 @Test
1074 protected void testPut_AuthCache() throws Exception {
1075 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH, false);
1076 httpServer.setAuthentication("testuser", "testpass");
1077 auth = new AuthenticationBuilder()
1078 .addUsername("testuser")
1079 .addPassword("testpass")
1080 .build();
1081 newTransporter(httpServer.getHttpUrl());
1082 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1083 transporter.put(task);
1084 assertEquals(2, httpServer.getLogEntries().size());
1085 httpServer.getLogEntries().clear();
1086 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1087 transporter.put(task);
1088 assertEquals(1, httpServer.getLogEntries().size());
1089 }
1090
1091 @Test
1092 protected void testPut_AuthCache_Preemptive() throws Exception {
1093 httpServer.setAuthentication("testuser", "testpass");
1094 auth = new AuthenticationBuilder()
1095 .addUsername("testuser")
1096 .addPassword("testpass")
1097 .build();
1098 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true);
1099 newTransporter(httpServer.getHttpUrl());
1100 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1101 transporter.put(task);
1102 assertEquals(1, httpServer.getLogEntries().size());
1103 httpServer.getLogEntries().clear();
1104 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1105 transporter.put(task);
1106 assertEquals(1, httpServer.getLogEntries().size());
1107 }
1108
1109 @Test
1110 @Timeout(20)
1111 protected void testConcurrency() throws Exception {
1112 httpServer.setAuthentication("testuser", "testpass");
1113 auth = new AuthenticationBuilder()
1114 .addUsername("testuser")
1115 .addPassword("testpass")
1116 .build();
1117 newTransporter(httpServer.getHttpUrl());
1118 final AtomicReference<Throwable> error = new AtomicReference<>();
1119 Thread[] threads = new Thread[20];
1120 for (int i = 0; i < threads.length; i++) {
1121 final String path = "repo/file.txt?i=" + i;
1122 threads[i] = new Thread(() -> {
1123 try {
1124 for (int j = 0; j < 100; j++) {
1125 GetTask task = new GetTask(URI.create(path));
1126 transporter.get(task);
1127 assertEquals("test", task.getDataString());
1128 }
1129 } catch (Throwable t) {
1130 error.compareAndSet(null, t);
1131 System.err.println(path);
1132 t.printStackTrace();
1133 }
1134 });
1135 threads[i].setName("Task-" + i);
1136 }
1137 for (Thread thread : threads) {
1138 thread.start();
1139 }
1140 for (Thread thread : threads) {
1141 thread.join();
1142 }
1143 assertNull(error.get(), String.valueOf(error.get()));
1144 }
1145
1146 @Test
1147 @Timeout(10)
1148 protected void testConnectTimeout() throws Exception {
1149 session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, 100);
1150 int port = 1;
1151 newTransporter("http://localhost:" + port);
1152 try {
1153 transporter.get(new GetTask(URI.create("repo/file.txt")));
1154 fail("Expected error");
1155 } catch (Exception e) {
1156
1157 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1158 }
1159 }
1160
1161 @Test
1162 @Timeout(10)
1163 protected void testRequestTimeout() throws Exception {
1164 session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, 100);
1165 ServerSocket server = new ServerSocket(0);
1166 try (server) {
1167 newTransporter("http://localhost:" + server.getLocalPort());
1168 try {
1169 transporter.get(new GetTask(URI.create("repo/file.txt")));
1170 fail("Expected error");
1171 } catch (Exception e) {
1172 assertTrue(e.getClass().getSimpleName().contains("Timeout"));
1173 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1174 }
1175 }
1176 }
1177
1178 @Test
1179 protected void testUserAgent() throws Exception {
1180 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0");
1181 newTransporter(httpServer.getHttpUrl());
1182 transporter.get(new GetTask(URI.create("repo/file.txt")));
1183 assertEquals(1, httpServer.getLogEntries().size());
1184 for (HttpServer.LogEntry log : httpServer.getLogEntries()) {
1185 assertEquals("SomeTest/1.0", log.getHeaders().get("User-Agent"));
1186 }
1187 }
1188
1189 @Test
1190 protected void testCustomHeaders() throws Exception {
1191 Map<String, String> headers = new HashMap<>();
1192 headers.put("User-Agent", "Custom/1.0");
1193 headers.put("X-CustomHeader", "Custom-Value");
1194 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0");
1195 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers);
1196 newTransporter(httpServer.getHttpUrl());
1197 transporter.get(new GetTask(URI.create("repo/file.txt")));
1198 assertEquals(1, httpServer.getLogEntries().size());
1199 for (HttpServer.LogEntry log : httpServer.getLogEntries()) {
1200 for (Map.Entry<String, String> entry : headers.entrySet()) {
1201 assertEquals(entry.getValue(), log.getHeaders().get(entry.getKey()), entry.getKey());
1202 }
1203 }
1204 }
1205
1206 @Test
1207 protected void testServerAuthScope_NotUsedForProxy() throws Exception {
1208 String username = "testuser", password = "testpass";
1209 httpServer.setProxyAuthentication(username, password);
1210 auth = new AuthenticationBuilder()
1211 .addUsername(username)
1212 .addPassword(password)
1213 .build();
1214 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort());
1215 newTransporter("http://" + httpServer.getHost() + ":12/");
1216 try {
1217 transporter.get(new GetTask(URI.create("repo/file.txt")));
1218 fail("Server auth must not be used as proxy auth");
1219 } catch (HttpTransporterException e) {
1220 assertEquals(407, e.getStatusCode());
1221 } catch (IOException e) {
1222
1223 }
1224 }
1225
1226 @Test
1227 protected void testProxyAuthScope_NotUsedForServer() throws Exception {
1228 String username = "testuser", password = "testpass";
1229 httpServer.setAuthentication(username, password);
1230 Authentication auth = new AuthenticationBuilder()
1231 .addUsername(username)
1232 .addPassword(password)
1233 .build();
1234 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
1235 newTransporter("http://" + httpServer.getHost() + ":12/");
1236 try {
1237 transporter.get(new GetTask(URI.create("repo/file.txt")));
1238 fail("Proxy auth must not be used as server auth");
1239 } catch (HttpTransporterException e) {
1240 assertEquals(401, e.getStatusCode());
1241 } catch (IOException e) {
1242
1243 }
1244 }
1245
1246 @Test
1247 protected void testAuthSchemeReuse() throws Exception {
1248 httpServer.setAuthentication("testuser", "testpass");
1249 httpServer.setProxyAuthentication("proxyuser", "proxypass");
1250 session.setCache(new DefaultRepositoryCache());
1251 auth = new AuthenticationBuilder()
1252 .addUsername("testuser")
1253 .addPassword("testpass")
1254 .build();
1255 Authentication auth = new AuthenticationBuilder()
1256 .addUsername("proxyuser")
1257 .addPassword("proxypass")
1258 .build();
1259 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
1260 newTransporter("http://bad.localhost:1/");
1261 GetTask task = new GetTask(URI.create("repo/file.txt"));
1262 transporter.get(task);
1263 assertEquals("test", task.getDataString());
1264 assertEquals(3, httpServer.getLogEntries().size());
1265 httpServer.getLogEntries().clear();
1266 newTransporter("http://bad.localhost:1/");
1267 task = new GetTask(URI.create("repo/file.txt"));
1268 transporter.get(task);
1269 assertEquals("test", task.getDataString());
1270 assertEquals(1, httpServer.getLogEntries().size());
1271 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Authorization"));
1272 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Proxy-Authorization"));
1273 }
1274
1275 @Test
1276 protected void testAuthSchemePreemptive() throws Exception {
1277 httpServer.setAuthentication("testuser", "testpass");
1278 session.setCache(new DefaultRepositoryCache());
1279 auth = new AuthenticationBuilder()
1280 .addUsername("testuser")
1281 .addPassword("testpass")
1282 .build();
1283
1284 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, false);
1285 newTransporter(httpServer.getHttpUrl());
1286 GetTask task = new GetTask(URI.create("repo/file.txt"));
1287 transporter.get(task);
1288 assertEquals("test", task.getDataString());
1289
1290 assertEquals(2, httpServer.getLogEntries().size());
1291
1292 httpServer.getLogEntries().clear();
1293
1294 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true);
1295 newTransporter(httpServer.getHttpUrl());
1296 task = new GetTask(URI.create("repo/file.txt"));
1297 transporter.get(task);
1298 assertEquals("test", task.getDataString());
1299
1300 assertEquals(1, httpServer.getLogEntries().size());
1301 }
1302
1303 @Test
1304 void testInit_BadProtocol() {
1305 assertThrows(NoTransporterException.class, () -> newTransporter("bad:/void"));
1306 }
1307
1308 @Test
1309 void testInit_BadUrl() {
1310 assertThrows(NoTransporterException.class, () -> newTransporter("http://localhost:NaN"));
1311 }
1312
1313 @Test
1314 void testInit_CaseInsensitiveProtocol() throws Exception {
1315 newTransporter("http://localhost");
1316 newTransporter("HTTP://localhost");
1317 newTransporter("Http://localhost");
1318 newTransporter("https://localhost");
1319 newTransporter("HTTPS://localhost");
1320 newTransporter("HttpS://localhost");
1321 }
1322 }