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: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(OLD_FILE_TIMESTAMP, file.lastModified());
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(403, e.getPayload().getStatus());
491 assertEquals("You do not have enough credit.", e.getPayload().getTitle());
492 assertEquals(
493 "Your current balance is 30, but that costs 50.",
494 e.getPayload().getDetail());
495 assertEquals(URI.create("/account/12345/msgs/abc"), e.getPayload().getInstance());
496 }
497 }
498
499 @Test
500 protected void testGet_RFC9457Response_with_missing_fields() throws Exception {
501 try {
502 transporter.get(new GetTask(URI.create("rfc9457/missing_fields.txt")));
503 fail("Expected error");
504 } catch (HttpRFC9457Exception e) {
505 assertEquals(403, e.getStatusCode());
506 assertEquals(e.getPayload().getType(), URI.create("about:blank"));
507 assertNull(e.getPayload().getStatus());
508 assertNull(e.getPayload().getTitle());
509 assertNull(e.getPayload().getDetail());
510 assertNull(e.getPayload().getInstance());
511 }
512 }
513
514 @Test
515 protected void testGet_SSL() throws Exception {
516 httpServer.addSslConnector();
517 newTransporter(httpServer.getHttpsUrl());
518 RecordingTransportListener listener = new RecordingTransportListener();
519 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
520 transporter.get(task);
521 assertEquals("test", task.getDataString());
522 assertEquals(0L, listener.getDataOffset());
523 assertEquals(4L, listener.getDataLength());
524 assertEquals(1, listener.getStartedCount());
525 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
526 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
527 }
528
529 @Test
530 protected void testGet_SSL_WithServerErrors() throws Exception {
531 httpServer.setServerErrorsBeforeWorks(1);
532 httpServer.addSslConnector();
533 newTransporter(httpServer.getHttpsUrl());
534 for (int i = 1; i < 3; i++) {
535 try {
536 RecordingTransportListener listener = new RecordingTransportListener();
537 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
538 transporter.get(task);
539 assertEquals("test", task.getDataString());
540 assertEquals(0L, listener.getDataOffset());
541 assertEquals(4L, listener.getDataLength());
542 assertEquals(1, listener.getStartedCount());
543 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
544 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
545 } catch (HttpTransporterException e) {
546 assertEquals(500, e.getStatusCode());
547 }
548 }
549 }
550
551 @Test
552 protected void testGet_HTTPS_Unknown_SecurityMode() throws Exception {
553 session.setConfigProperty(ConfigurationProperties.HTTPS_SECURITY_MODE, "unknown");
554 httpServer.addSelfSignedSslConnector();
555 try {
556 newTransporter(httpServer.getHttpsUrl());
557 fail("Unsupported security mode");
558 } catch (IllegalArgumentException a) {
559
560 }
561 }
562
563 @Test
564 protected void testGet_HTTPS_Insecure_SecurityMode() throws Exception {
565
566
567 session.setConfigProperty(
568 ConfigurationProperties.HTTPS_SECURITY_MODE, ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE);
569 httpServer.addSelfSignedSslConnector();
570 newTransporter(httpServer.getHttpsUrl());
571 RecordingTransportListener listener = new RecordingTransportListener();
572 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
573 transporter.get(task);
574 assertEquals("test", task.getDataString());
575 assertEquals(0L, listener.getDataOffset());
576 assertEquals(4L, listener.getDataLength());
577 assertEquals(1, listener.getStartedCount());
578 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
579 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
580 }
581
582 @Test
583 protected void testGet_HTTPS_HTTP2Only_Insecure_SecurityMode() throws Exception {
584
585
586 enableHttp2Protocol();
587 session.setConfigProperty(
588 ConfigurationProperties.HTTPS_SECURITY_MODE, ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE);
589 httpServer.addSelfSignedSslConnectorHttp2Only();
590 newTransporter(httpServer.getHttpsUrl());
591 RecordingTransportListener listener = new RecordingTransportListener();
592 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
593 transporter.get(task);
594 assertEquals("test", task.getDataString());
595 assertEquals(0L, listener.getDataOffset());
596 assertEquals(4L, listener.getDataLength());
597 assertEquals(1, listener.getStartedCount());
598 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
599 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
600 }
601
602 protected void enableHttp2Protocol() {}
603
604 @Test
605 protected void testGet_Redirect() throws Exception {
606 httpServer.addSslConnector();
607 RecordingTransportListener listener = new RecordingTransportListener();
608 GetTask task = new GetTask(URI.create("redirect/file.txt?scheme=https")).setListener(listener);
609 transporter.get(task);
610 assertEquals("test", task.getDataString());
611 assertEquals(0L, listener.getDataOffset());
612 assertEquals(4L, listener.getDataLength());
613 assertEquals(1, listener.getStartedCount());
614 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
615 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8));
616 }
617
618 @Test
619 protected void testGet_Resume() throws Exception {
620 File file = TestFileUtils.createTempFile("re");
621 RecordingTransportListener listener = new RecordingTransportListener();
622 GetTask task = new GetTask(URI.create("repo/resume.txt"))
623 .setDataPath(file.toPath(), true)
624 .setListener(listener);
625 transporter.get(task);
626 assertEquals("resumable", TestFileUtils.readString(file));
627 assertEquals(1L, listener.getStartedCount());
628 assertEquals(2L, listener.getDataOffset());
629 assertEquals(9, listener.getDataLength());
630 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
631 assertEquals("sumable", listener.getBaos().toString(StandardCharsets.UTF_8));
632 }
633
634 @Test
635 protected void testGet_ResumeLocalContentsOutdated() throws Exception {
636 File file = TestFileUtils.createTempFile("re");
637 file.setLastModified(System.currentTimeMillis() - 5 * 60 * 1000);
638 RecordingTransportListener listener = new RecordingTransportListener();
639 GetTask task = new GetTask(URI.create("repo/resume.txt"))
640 .setDataPath(file.toPath(), true)
641 .setListener(listener);
642 transporter.get(task);
643 assertEquals("resumable", TestFileUtils.readString(file));
644 assertEquals(1L, listener.getStartedCount());
645 assertEquals(0L, listener.getDataOffset());
646 assertEquals(9, listener.getDataLength());
647 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
648 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8));
649 }
650
651 @Test
652 protected void testGet_ResumeRangesNotSupportedByServer() throws Exception {
653 httpServer.setRangeSupport(false);
654 File file = TestFileUtils.createTempFile("re");
655 RecordingTransportListener listener = new RecordingTransportListener();
656 GetTask task = new GetTask(URI.create("repo/resume.txt"))
657 .setDataPath(file.toPath(), true)
658 .setListener(listener);
659 transporter.get(task);
660 assertEquals("resumable", TestFileUtils.readString(file));
661 assertEquals(1L, listener.getStartedCount());
662 assertEquals(0L, listener.getDataOffset());
663 assertEquals(9, listener.getDataLength());
664 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
665 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8));
666 }
667
668 @Test
669 protected void testGet_Checksums_Nexus() throws Exception {
670 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.NEXUS);
671 GetTask task = new GetTask(URI.create("repo/file.txt"));
672 transporter.get(task);
673 assertEquals("test", task.getDataString());
674 assertEquals(
675 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1"));
676 }
677
678 @Test
679 protected void testGet_Checksums_XChecksum() throws Exception {
680 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.XCHECKSUM);
681 GetTask task = new GetTask(URI.create("repo/file.txt"));
682 transporter.get(task);
683 assertEquals("test", task.getDataString());
684 assertEquals(
685 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1"));
686 }
687
688 @Test
689 protected void testGet_FileHandleLeak() throws Exception {
690 for (int i = 0; i < 100; i++) {
691 File file = TestFileUtils.createTempFile("failure");
692 transporter.get(new GetTask(URI.create("repo/file.txt")).setDataPath(file.toPath()));
693 assertTrue(file.delete(), i + ", " + file.getAbsolutePath());
694 }
695 }
696
697 @Test
698 protected void testGet_NotFound() throws Exception {
699 try {
700 transporter.get(new GetTask(URI.create("repo/missing.txt")));
701 fail("Expected error");
702 } catch (HttpTransporterException e) {
703 assertEquals(404, e.getStatusCode());
704 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
705 }
706 }
707
708 @Test
709 protected void testGet_Closed() throws Exception {
710 transporter.close();
711 try {
712 transporter.get(new GetTask(URI.create("repo/file.txt")));
713 fail("Expected error");
714 } catch (IllegalStateException e) {
715 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
716 }
717 }
718
719 @Test
720 protected void testGet_StartCancelled() throws Exception {
721 RecordingTransportListener listener = new RecordingTransportListener();
722 listener.cancelStart();
723 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
724 try {
725 transporter.get(task);
726 fail("Expected error");
727 } catch (TransferCancelledException e) {
728 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
729 }
730 assertEquals(0L, listener.getDataOffset());
731 assertEquals(4L, listener.getDataLength());
732 assertEquals(1, listener.getStartedCount());
733 assertEquals(0, listener.getProgressedCount());
734 }
735
736 @Test
737 protected void testGet_ProgressCancelled() throws Exception {
738 RecordingTransportListener listener = new RecordingTransportListener();
739 listener.cancelProgress();
740 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener);
741 try {
742 transporter.get(task);
743 fail("Expected error");
744 } catch (TransferCancelledException e) {
745 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
746 }
747 assertEquals(0L, listener.getDataOffset());
748 assertEquals(4L, listener.getDataLength());
749 assertEquals(1, listener.getStartedCount());
750 assertEquals(1, listener.getProgressedCount());
751 }
752
753 @Test
754 protected void testPut_FromMemory() throws Exception {
755 RecordingTransportListener listener = new RecordingTransportListener();
756 PutTask task =
757 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
758 transporter.put(task);
759 assertEquals(0L, listener.getDataOffset());
760 assertEquals(6L, listener.getDataLength());
761 assertEquals(1, listener.getStartedCount());
762 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
763 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
764 }
765
766 @Test
767 protected void testPut_FromFile() throws Exception {
768 File file = TestFileUtils.createTempFile("upload");
769 RecordingTransportListener listener = new RecordingTransportListener();
770 PutTask task =
771 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataPath(file.toPath());
772 transporter.put(task);
773 assertEquals(0L, listener.getDataOffset());
774 assertEquals(6L, listener.getDataLength());
775 assertEquals(1, listener.getStartedCount());
776 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
777 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
778 }
779
780 @Test
781 protected void testPut_EmptyResource() throws Exception {
782 RecordingTransportListener listener = new RecordingTransportListener();
783 PutTask task = new PutTask(URI.create("repo/file.txt")).setListener(listener);
784 transporter.put(task);
785 assertEquals(0L, listener.getDataOffset());
786 assertEquals(0L, listener.getDataLength());
787 assertEquals(1, listener.getStartedCount());
788 assertEquals(0, listener.getProgressedCount());
789 assertEquals("", TestFileUtils.readString(new File(repoDir, "file.txt")));
790 }
791
792 @Test
793 protected void testPut_EncodedResourcePath() throws Exception {
794 RecordingTransportListener listener = new RecordingTransportListener();
795 PutTask task = new PutTask(URI.create("repo/some%20space.txt"))
796 .setListener(listener)
797 .setDataString("OK");
798 transporter.put(task);
799 assertEquals(0L, listener.getDataOffset());
800 assertEquals(2L, listener.getDataLength());
801 assertEquals(1, listener.getStartedCount());
802 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
803 assertEquals("OK", TestFileUtils.readString(new File(repoDir, "some space.txt")));
804 }
805
806 @Test
807 protected void testPut_Authenticated_ExpectContinue() throws Exception {
808 httpServer.setAuthentication("testuser", "testpass");
809 auth = new AuthenticationBuilder()
810 .addUsername("testuser")
811 .addPassword("testpass")
812 .build();
813 newTransporter(httpServer.getHttpUrl());
814 RecordingTransportListener listener = new RecordingTransportListener();
815 PutTask task =
816 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
817 transporter.put(task);
818 assertEquals(0L, listener.getDataOffset());
819 assertEquals(6L, listener.getDataLength());
820 assertEquals(1, listener.getStartedCount());
821 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
822 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
823 }
824
825 @Test
826 protected void testPut_Authenticated_ExpectContinueBroken() throws Exception {
827
828 session.setConfigProperty(ConfigurationProperties.HTTP_SUPPORT_WEBDAV, true);
829 httpServer.setAuthentication("testuser", "testpass");
830 httpServer.setExpectSupport(HttpServer.ExpectContinue.BROKEN);
831 auth = new AuthenticationBuilder()
832 .addUsername("testuser")
833 .addPassword("testpass")
834 .build();
835 newTransporter(httpServer.getHttpUrl());
836 RecordingTransportListener listener = new RecordingTransportListener();
837 PutTask task =
838 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
839 transporter.put(task);
840 assertEquals(0L, listener.getDataOffset());
841 assertEquals(6L, listener.getDataLength());
842 assertEquals(1, listener.getStartedCount());
843 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
844 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
845 }
846
847 @Test
848 protected void testPut_Authenticated_ExpectContinueRejected() throws Exception {
849 httpServer.setAuthentication("testuser", "testpass");
850 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL);
851 auth = new AuthenticationBuilder()
852 .addUsername("testuser")
853 .addPassword("testpass")
854 .build();
855 newTransporter(httpServer.getHttpUrl());
856 RecordingTransportListener listener = new RecordingTransportListener();
857 PutTask task =
858 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
859 transporter.put(task);
860 assertEquals(0L, listener.getDataOffset());
861 assertEquals(6L, listener.getDataLength());
862 assertEquals(1, listener.getStartedCount());
863 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
864 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
865 }
866
867 @Test
868 protected void testPut_Authenticated_ExpectContinueDisabled() throws Exception {
869 session.setConfigProperty(ConfigurationProperties.HTTP_EXPECT_CONTINUE, false);
870 httpServer.setAuthentication("testuser", "testpass");
871 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL);
872 auth = new AuthenticationBuilder()
873 .addUsername("testuser")
874 .addPassword("testpass")
875 .build();
876 newTransporter(httpServer.getHttpUrl());
877 RecordingTransportListener listener = new RecordingTransportListener();
878 PutTask task =
879 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
880 transporter.put(task);
881 assertEquals(0L, listener.getDataOffset());
882 assertEquals(6L, listener.getDataLength());
883 assertEquals(1, listener.getStartedCount());
884 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
885 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
886 }
887
888 @Test
889 protected void testPut_Authenticated_ExpectContinueRejected_ExplicitlyConfiguredHeader() throws Exception {
890 Map<String, String> headers = new HashMap<>();
891 headers.put("Expect", "100-continue");
892 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers);
893 httpServer.setAuthentication("testuser", "testpass");
894 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL);
895 auth = new AuthenticationBuilder()
896 .addUsername("testuser")
897 .addPassword("testpass")
898 .build();
899 newTransporter(httpServer.getHttpUrl());
900 RecordingTransportListener listener = new RecordingTransportListener();
901 PutTask task =
902 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
903 transporter.put(task);
904 assertEquals(0L, listener.getDataOffset());
905 assertEquals(6L, listener.getDataLength());
906 assertEquals(1, listener.getStartedCount());
907 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
908 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
909 }
910
911 @Test
912 protected void testPut_Unauthenticated() throws Exception {
913 httpServer.setAuthentication("testuser", "testpass");
914 RecordingTransportListener listener = new RecordingTransportListener();
915 PutTask task =
916 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
917 try {
918 transporter.put(task);
919 fail("Expected error");
920 } catch (HttpTransporterException e) {
921 assertEquals(401, e.getStatusCode());
922 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
923 }
924 assertEquals(0, listener.getStartedCount());
925 assertEquals(0, listener.getProgressedCount());
926 }
927
928 @Test
929 protected void testPut_ProxyAuthenticated() throws Exception {
930 httpServer.setProxyAuthentication("testuser", "testpass");
931 Authentication auth = new AuthenticationBuilder()
932 .addUsername("testuser")
933 .addPassword("testpass")
934 .build();
935 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
936 newTransporter("http://bad.localhost:1/");
937 RecordingTransportListener listener = new RecordingTransportListener();
938 PutTask task =
939 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
940 transporter.put(task);
941 assertEquals(0L, listener.getDataOffset());
942 assertEquals(6L, listener.getDataLength());
943 assertEquals(1, listener.getStartedCount());
944 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
945 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
946 }
947
948 @Test
949 protected void testPut_ProxyUnauthenticated() throws Exception {
950 httpServer.setProxyAuthentication("testuser", "testpass");
951 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort());
952 newTransporter("http://bad.localhost:1/");
953 RecordingTransportListener listener = new RecordingTransportListener();
954 PutTask task =
955 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
956 try {
957 transporter.put(task);
958 fail("Expected error");
959 } catch (HttpTransporterException e) {
960 assertEquals(407, e.getStatusCode());
961 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
962 }
963 assertEquals(0, listener.getStartedCount());
964 assertEquals(0, listener.getProgressedCount());
965 }
966
967 @Test
968 protected void testPut_SSL() throws Exception {
969 httpServer.addSslConnector();
970 httpServer.setAuthentication("testuser", "testpass");
971 auth = new AuthenticationBuilder()
972 .addUsername("testuser")
973 .addPassword("testpass")
974 .build();
975 newTransporter(httpServer.getHttpsUrl());
976 RecordingTransportListener listener = new RecordingTransportListener();
977 PutTask task =
978 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
979 transporter.put(task);
980 assertEquals(0L, listener.getDataOffset());
981 assertEquals(6L, listener.getDataLength());
982 assertEquals(1, listener.getStartedCount());
983 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount());
984 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt")));
985 }
986
987 @Test
988 protected void testPut_FileHandleLeak() throws Exception {
989 for (int i = 0; i < 100; i++) {
990 File src = TestFileUtils.createTempFile("upload");
991 File dst = new File(repoDir, "file.txt");
992 transporter.put(new PutTask(URI.create("repo/file.txt")).setDataPath(src.toPath()));
993 assertTrue(src.delete(), i + ", " + src.getAbsolutePath());
994 assertTrue(dst.delete(), i + ", " + dst.getAbsolutePath());
995 }
996 }
997
998 @Test
999 protected void testPut_Closed() throws Exception {
1000 transporter.close();
1001 try {
1002 transporter.put(new PutTask(URI.create("repo/missing.txt")));
1003 fail("Expected error");
1004 } catch (IllegalStateException e) {
1005 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1006 }
1007 }
1008
1009 @Test
1010 protected void testPut_StartCancelled() throws Exception {
1011 RecordingTransportListener listener = new RecordingTransportListener();
1012 listener.cancelStart();
1013 PutTask task =
1014 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
1015 try {
1016 transporter.put(task);
1017 fail("Expected error");
1018 } catch (TransferCancelledException e) {
1019 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1020 }
1021 assertEquals(0L, listener.getDataOffset());
1022 assertEquals(6L, listener.getDataLength());
1023 assertEquals(1, listener.getStartedCount());
1024 assertEquals(0, listener.getProgressedCount());
1025 }
1026
1027 @Test
1028 protected void testPut_ProgressCancelled() throws Exception {
1029 RecordingTransportListener listener = new RecordingTransportListener();
1030 listener.cancelProgress();
1031 PutTask task =
1032 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
1033 try {
1034 transporter.put(task);
1035 fail("Expected error");
1036 } catch (TransferCancelledException e) {
1037 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1038 }
1039 assertEquals(0L, listener.getDataOffset());
1040 assertEquals(6L, listener.getDataLength());
1041 assertEquals(1, listener.getStartedCount());
1042 assertEquals(1, listener.getProgressedCount());
1043 }
1044
1045 @Test
1046 protected void testGetPut_AuthCache() throws Exception {
1047 httpServer.setAuthentication("testuser", "testpass");
1048 auth = new AuthenticationBuilder()
1049 .addUsername("testuser")
1050 .addPassword("testpass")
1051 .build();
1052 newTransporter(httpServer.getHttpUrl());
1053 GetTask get = new GetTask(URI.create("repo/file.txt"));
1054 transporter.get(get);
1055 RecordingTransportListener listener = new RecordingTransportListener();
1056 PutTask task =
1057 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload");
1058 transporter.put(task);
1059 assertEquals(1, listener.getStartedCount());
1060 }
1061
1062 @Test
1063 protected void testPut_PreemptiveIsDefault() throws Exception {
1064 httpServer.setAuthentication("testuser", "testpass");
1065 auth = new AuthenticationBuilder()
1066 .addUsername("testuser")
1067 .addPassword("testpass")
1068 .build();
1069 newTransporter(httpServer.getHttpUrl());
1070 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1071 transporter.put(task);
1072 assertEquals(1, httpServer.getLogEntries().size());
1073 }
1074
1075 @Test
1076 protected void testPut_AuthCache() throws Exception {
1077 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH, false);
1078 httpServer.setAuthentication("testuser", "testpass");
1079 auth = new AuthenticationBuilder()
1080 .addUsername("testuser")
1081 .addPassword("testpass")
1082 .build();
1083 newTransporter(httpServer.getHttpUrl());
1084 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1085 transporter.put(task);
1086 assertEquals(2, httpServer.getLogEntries().size());
1087 httpServer.getLogEntries().clear();
1088 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1089 transporter.put(task);
1090 assertEquals(1, httpServer.getLogEntries().size());
1091 }
1092
1093 @Test
1094 protected void testPut_AuthCache_Preemptive() throws Exception {
1095 httpServer.setAuthentication("testuser", "testpass");
1096 auth = new AuthenticationBuilder()
1097 .addUsername("testuser")
1098 .addPassword("testpass")
1099 .build();
1100 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true);
1101 newTransporter(httpServer.getHttpUrl());
1102 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1103 transporter.put(task);
1104 assertEquals(1, httpServer.getLogEntries().size());
1105 httpServer.getLogEntries().clear();
1106 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload");
1107 transporter.put(task);
1108 assertEquals(1, httpServer.getLogEntries().size());
1109 }
1110
1111 @Test
1112 @Timeout(20)
1113 protected void testConcurrency() throws Exception {
1114 httpServer.setAuthentication("testuser", "testpass");
1115 auth = new AuthenticationBuilder()
1116 .addUsername("testuser")
1117 .addPassword("testpass")
1118 .build();
1119 newTransporter(httpServer.getHttpUrl());
1120 final AtomicReference<Throwable> error = new AtomicReference<>();
1121 Thread[] threads = new Thread[20];
1122 for (int i = 0; i < threads.length; i++) {
1123 final String path = "repo/file.txt?i=" + i;
1124 threads[i] = new Thread(() -> {
1125 try {
1126 for (int j = 0; j < 100; j++) {
1127 GetTask task = new GetTask(URI.create(path));
1128 transporter.get(task);
1129 assertEquals("test", task.getDataString());
1130 }
1131 } catch (Throwable t) {
1132 error.compareAndSet(null, t);
1133 System.err.println(path);
1134 t.printStackTrace();
1135 }
1136 });
1137 threads[i].setName("Task-" + i);
1138 }
1139 for (Thread thread : threads) {
1140 thread.start();
1141 }
1142 for (Thread thread : threads) {
1143 thread.join();
1144 }
1145 assertNull(error.get(), String.valueOf(error.get()));
1146 }
1147
1148 @Test
1149 @Timeout(10)
1150 protected void testConnectTimeout() throws Exception {
1151 session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, 100);
1152 int port = 1;
1153 newTransporter("http://localhost:" + port);
1154 try {
1155 transporter.get(new GetTask(URI.create("repo/file.txt")));
1156 fail("Expected error");
1157 } catch (Exception e) {
1158
1159 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1160 }
1161 }
1162
1163 @Test
1164 @Timeout(10)
1165 protected void testRequestTimeout() throws Exception {
1166 session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, 100);
1167 ServerSocket server = new ServerSocket(0);
1168 try (server) {
1169 newTransporter("http://localhost:" + server.getLocalPort());
1170 try {
1171 transporter.get(new GetTask(URI.create("repo/file.txt")));
1172 fail("Expected error");
1173 } catch (Exception e) {
1174 assertTrue(e.getClass().getSimpleName().contains("Timeout"));
1175 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
1176 }
1177 }
1178 }
1179
1180 @Test
1181 protected void testUserAgent() throws Exception {
1182 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0");
1183 newTransporter(httpServer.getHttpUrl());
1184 transporter.get(new GetTask(URI.create("repo/file.txt")));
1185 assertEquals(1, httpServer.getLogEntries().size());
1186 for (HttpServer.LogEntry log : httpServer.getLogEntries()) {
1187 assertEquals("SomeTest/1.0", log.getHeaders().get("User-Agent"));
1188 }
1189 }
1190
1191 @Test
1192 protected void testCustomHeaders() throws Exception {
1193 Map<String, String> headers = new HashMap<>();
1194 headers.put("User-Agent", "Custom/1.0");
1195 headers.put("X-CustomHeader", "Custom-Value");
1196 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0");
1197 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers);
1198 newTransporter(httpServer.getHttpUrl());
1199 transporter.get(new GetTask(URI.create("repo/file.txt")));
1200 assertEquals(1, httpServer.getLogEntries().size());
1201 for (HttpServer.LogEntry log : httpServer.getLogEntries()) {
1202 for (Map.Entry<String, String> entry : headers.entrySet()) {
1203 assertEquals(entry.getValue(), log.getHeaders().get(entry.getKey()), entry.getKey());
1204 }
1205 }
1206 }
1207
1208 @Test
1209 protected void testServerAuthScope_NotUsedForProxy() throws Exception {
1210 String username = "testuser", password = "testpass";
1211 httpServer.setProxyAuthentication(username, password);
1212 auth = new AuthenticationBuilder()
1213 .addUsername(username)
1214 .addPassword(password)
1215 .build();
1216 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort());
1217 newTransporter("http://" + httpServer.getHost() + ":12/");
1218 try {
1219 transporter.get(new GetTask(URI.create("repo/file.txt")));
1220 fail("Server auth must not be used as proxy auth");
1221 } catch (HttpTransporterException e) {
1222 assertEquals(407, e.getStatusCode());
1223 } catch (IOException e) {
1224
1225 }
1226 }
1227
1228 @Test
1229 protected void testProxyAuthScope_NotUsedForServer() throws Exception {
1230 String username = "testuser", password = "testpass";
1231 httpServer.setAuthentication(username, password);
1232 Authentication auth = new AuthenticationBuilder()
1233 .addUsername(username)
1234 .addPassword(password)
1235 .build();
1236 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
1237 newTransporter("http://" + httpServer.getHost() + ":12/");
1238 try {
1239 transporter.get(new GetTask(URI.create("repo/file.txt")));
1240 fail("Proxy auth must not be used as server auth");
1241 } catch (HttpTransporterException e) {
1242 assertEquals(401, e.getStatusCode());
1243 } catch (IOException e) {
1244
1245 }
1246 }
1247
1248 @Test
1249 protected void testAuthSchemeReuse() throws Exception {
1250 httpServer.setAuthentication("testuser", "testpass");
1251 httpServer.setProxyAuthentication("proxyuser", "proxypass");
1252 session.setCache(new DefaultRepositoryCache());
1253 auth = new AuthenticationBuilder()
1254 .addUsername("testuser")
1255 .addPassword("testpass")
1256 .build();
1257 Authentication auth = new AuthenticationBuilder()
1258 .addUsername("proxyuser")
1259 .addPassword("proxypass")
1260 .build();
1261 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth);
1262 newTransporter("http://bad.localhost:1/");
1263 GetTask task = new GetTask(URI.create("repo/file.txt"));
1264 transporter.get(task);
1265 assertEquals("test", task.getDataString());
1266 assertEquals(3, httpServer.getLogEntries().size());
1267 httpServer.getLogEntries().clear();
1268 newTransporter("http://bad.localhost:1/");
1269 task = new GetTask(URI.create("repo/file.txt"));
1270 transporter.get(task);
1271 assertEquals("test", task.getDataString());
1272 assertEquals(1, httpServer.getLogEntries().size());
1273 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Authorization"));
1274 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Proxy-Authorization"));
1275 }
1276
1277 @Test
1278 protected void testAuthSchemePreemptive() throws Exception {
1279 httpServer.setAuthentication("testuser", "testpass");
1280 session.setCache(new DefaultRepositoryCache());
1281 auth = new AuthenticationBuilder()
1282 .addUsername("testuser")
1283 .addPassword("testpass")
1284 .build();
1285
1286 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, false);
1287 newTransporter(httpServer.getHttpUrl());
1288 GetTask task = new GetTask(URI.create("repo/file.txt"));
1289 transporter.get(task);
1290 assertEquals("test", task.getDataString());
1291
1292 assertEquals(2, httpServer.getLogEntries().size());
1293
1294 httpServer.getLogEntries().clear();
1295
1296 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true);
1297 newTransporter(httpServer.getHttpUrl());
1298 task = new GetTask(URI.create("repo/file.txt"));
1299 transporter.get(task);
1300 assertEquals("test", task.getDataString());
1301
1302 assertEquals(1, httpServer.getLogEntries().size());
1303 }
1304
1305 @Test
1306 void testInit_BadProtocol() {
1307 assertThrows(NoTransporterException.class, () -> newTransporter("bad:/void"));
1308 }
1309
1310 @Test
1311 void testInit_BadUrl() {
1312 assertThrows(NoTransporterException.class, () -> newTransporter("http://localhost:NaN"));
1313 }
1314
1315 @Test
1316 void testInit_CaseInsensitiveProtocol() throws Exception {
1317 newTransporter("http://localhost");
1318 newTransporter("HTTP://localhost");
1319 newTransporter("Http://localhost");
1320 newTransporter("https://localhost");
1321 newTransporter("HTTPS://localhost");
1322 newTransporter("HttpS://localhost");
1323 }
1324 }