001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.test.util.http; 020 021import java.io.*; 022import java.net.ServerSocket; 023import java.net.URI; 024import java.net.URL; 025import java.nio.charset.StandardCharsets; 026import java.nio.file.Files; 027import java.nio.file.Path; 028import java.nio.file.Paths; 029import java.nio.file.StandardCopyOption; 030import java.util.HashMap; 031import java.util.Map; 032import java.util.concurrent.atomic.AtomicReference; 033import java.util.function.Supplier; 034 035import org.eclipse.aether.ConfigurationProperties; 036import org.eclipse.aether.DefaultRepositoryCache; 037import org.eclipse.aether.DefaultRepositorySystemSession; 038import org.eclipse.aether.DefaultSessionData; 039import org.eclipse.aether.internal.impl.transport.http.DefaultChecksumExtractor; 040import org.eclipse.aether.internal.impl.transport.http.Nx2ChecksumExtractor; 041import org.eclipse.aether.internal.impl.transport.http.XChecksumExtractor; 042import org.eclipse.aether.internal.test.util.TestFileUtils; 043import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager; 044import org.eclipse.aether.repository.Authentication; 045import org.eclipse.aether.repository.Proxy; 046import org.eclipse.aether.repository.RemoteRepository; 047import org.eclipse.aether.spi.connector.transport.GetTask; 048import org.eclipse.aether.spi.connector.transport.PeekTask; 049import org.eclipse.aether.spi.connector.transport.PutTask; 050import org.eclipse.aether.spi.connector.transport.Transporter; 051import org.eclipse.aether.spi.connector.transport.http.*; 052import org.eclipse.aether.transfer.NoTransporterException; 053import org.eclipse.aether.transfer.TransferCancelledException; 054import org.eclipse.aether.util.repository.AuthenticationBuilder; 055import org.junit.jupiter.api.*; 056 057import static java.util.Objects.requireNonNull; 058import static org.junit.jupiter.api.Assertions.*; 059 060/** 061 * Common set of tests against Http transporter. 062 */ 063@SuppressWarnings({"checkstyle:MagicNumber", "checkstyle:MethodName"}) 064public class HttpTransporterTest { 065 066 protected static final Path KEY_STORE_PATH = Paths.get("target/keystore"); 067 068 protected static final Path KEY_STORE_SELF_SIGNED_PATH = Paths.get("target/keystore-self-signed"); 069 070 protected static final Path TRUST_STORE_PATH = Paths.get("target/trustStore"); 071 072 static { 073 // Warning: "cross connected" with HttpServer! 074 System.setProperty( 075 "javax.net.ssl.trustStore", KEY_STORE_PATH.toAbsolutePath().toString()); 076 System.setProperty("javax.net.ssl.trustStorePassword", "server-pwd"); 077 System.setProperty( 078 "javax.net.ssl.keyStore", TRUST_STORE_PATH.toAbsolutePath().toString()); 079 System.setProperty("javax.net.ssl.keyStorePassword", "client-pwd"); 080 081 System.setProperty("javax.net.ssl.trustStoreType", "jks"); 082 System.setProperty("javax.net.ssl.keyStoreType", "jks"); 083 System.setProperty("javax.net.debug", "all"); 084 } 085 086 private final Supplier<HttpTransporterFactory> transporterFactorySupplier; 087 088 protected DefaultRepositorySystemSession session; 089 090 protected HttpTransporterFactory factory; 091 092 protected HttpTransporter transporter; 093 094 protected Runnable closer; 095 096 protected File repoDir; 097 098 protected HttpServer httpServer; 099 100 protected Authentication auth; 101 102 protected Proxy proxy; 103 104 protected HttpTransporterTest(Supplier<HttpTransporterFactory> transporterFactorySupplier) { 105 this.transporterFactorySupplier = requireNonNull(transporterFactorySupplier); 106 107 if (!Files.isRegularFile(KEY_STORE_PATH)) { 108 URL keyStoreUrl = HttpTransporterTest.class.getClassLoader().getResource("ssl/server-store"); 109 URL keyStoreSelfSignedUrl = 110 HttpTransporterTest.class.getClassLoader().getResource("ssl/server-store-selfsigned"); 111 URL trustStoreUrl = HttpTransporterTest.class.getClassLoader().getResource("ssl/client-store"); 112 113 try { 114 try (InputStream keyStoreStream = keyStoreUrl.openStream(); 115 InputStream keyStoreSelfSignedStream = keyStoreSelfSignedUrl.openStream(); 116 InputStream trustStoreStream = trustStoreUrl.openStream()) { 117 Files.copy(keyStoreStream, KEY_STORE_PATH, StandardCopyOption.REPLACE_EXISTING); 118 Files.copy( 119 keyStoreSelfSignedStream, KEY_STORE_SELF_SIGNED_PATH, StandardCopyOption.REPLACE_EXISTING); 120 Files.copy(trustStoreStream, TRUST_STORE_PATH, StandardCopyOption.REPLACE_EXISTING); 121 } 122 } catch (IOException e) { 123 throw new UncheckedIOException(e); 124 } 125 } 126 } 127 128 protected static ChecksumExtractor standardChecksumExtractor() { 129 HashMap<String, ChecksumExtractorStrategy> strategies = new HashMap<>(); 130 strategies.put("1", new Nx2ChecksumExtractor()); 131 strategies.put("2", new XChecksumExtractor()); 132 return new DefaultChecksumExtractor(strategies); 133 } 134 135 protected RemoteRepository newRepo(String url) { 136 return new RemoteRepository.Builder("test", "default", url) 137 .setAuthentication(auth) 138 .setProxy(proxy) 139 .build(); 140 } 141 142 protected void newTransporter(String url) throws Exception { 143 if (transporter != null) { 144 transporter.close(); 145 transporter = null; 146 } 147 if (closer != null) { 148 closer.run(); 149 closer = null; 150 } 151 session = new DefaultRepositorySystemSession(session); 152 session.setData(new DefaultSessionData()); 153 transporter = factory.newInstance(session, newRepo(url)); 154 } 155 156 protected static final long OLD_FILE_TIMESTAMP = 160660800000L; 157 158 @BeforeEach 159 protected void setUp(TestInfo testInfo) throws Exception { 160 System.out.println("=== " + testInfo.getDisplayName() + " ==="); 161 session = new DefaultRepositorySystemSession(h -> { 162 this.closer = h; 163 return true; 164 }); 165 session.setLocalRepositoryManager(new TestLocalRepositoryManager()); 166 factory = transporterFactorySupplier.get(); 167 repoDir = TestFileUtils.createTempDir(); 168 TestFileUtils.writeString(new File(repoDir, "file.txt"), "test"); 169 TestFileUtils.writeString(new File(repoDir, "dir/file.txt"), "test"); 170 TestFileUtils.writeString(new File(repoDir, "dir/oldFile.txt"), "oldTest", OLD_FILE_TIMESTAMP); 171 TestFileUtils.writeString(new File(repoDir, "empty.txt"), ""); 172 TestFileUtils.writeString(new File(repoDir, "some space.txt"), "space"); 173 File resumable = new File(repoDir, "resume.txt"); 174 TestFileUtils.writeString(resumable, "resumable"); 175 resumable.setLastModified(System.currentTimeMillis() - 90 * 1000); 176 httpServer = new HttpServer().setRepoDir(repoDir).start(); 177 newTransporter(httpServer.getHttpUrl()); 178 } 179 180 @AfterEach 181 protected void tearDown() throws Exception { 182 if (transporter != null) { 183 transporter.close(); 184 transporter = null; 185 } 186 if (closer != null) { 187 closer.run(); 188 closer = null; 189 } 190 if (httpServer != null) { 191 httpServer.stop(); 192 httpServer = null; 193 } 194 factory = null; 195 session = null; 196 } 197 198 @Test 199 protected void testClassify() { 200 assertEquals(Transporter.ERROR_OTHER, transporter.classify(new FileNotFoundException())); 201 assertEquals(Transporter.ERROR_OTHER, transporter.classify(new HttpTransporterException(403))); 202 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(new HttpTransporterException(404))); 203 } 204 205 @Test 206 protected void testPeek() throws Exception { 207 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 208 } 209 210 @Test 211 protected void testRetryHandler_defaultCount_positive() throws Exception { 212 httpServer.setConnectionsToClose(3); 213 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 214 } 215 216 @Test 217 protected void testRetryHandler_defaultCount_negative() throws Exception { 218 httpServer.setConnectionsToClose(4); 219 try { 220 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 221 fail("Expected error"); 222 } catch (Exception expected) { 223 } 224 } 225 226 @Test 227 protected void testRetryHandler_explicitCount_positive() throws Exception { 228 session.setConfigProperty(ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT, 10); 229 newTransporter(httpServer.getHttpUrl()); 230 httpServer.setConnectionsToClose(10); 231 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 232 } 233 234 @Test 235 protected void testRetryHandler_disabled() throws Exception { 236 session.setConfigProperty(ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT, 0); 237 newTransporter(httpServer.getHttpUrl()); 238 httpServer.setConnectionsToClose(1); 239 try { 240 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 241 } catch (Exception expected) { 242 } 243 } 244 245 @Test 246 protected void testPeek_NotFound() throws Exception { 247 try { 248 transporter.peek(new PeekTask(URI.create("repo/missing.txt"))); 249 fail("Expected error"); 250 } catch (HttpTransporterException e) { 251 assertEquals(404, e.getStatusCode()); 252 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e)); 253 } 254 } 255 256 @Test 257 protected void testPeek_Closed() throws Exception { 258 transporter.close(); 259 try { 260 transporter.peek(new PeekTask(URI.create("repo/missing.txt"))); 261 fail("Expected error"); 262 } catch (IllegalStateException e) { 263 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 264 } 265 } 266 267 @Test 268 protected void testPeek_Authenticated() throws Exception { 269 httpServer.setAuthentication("testuser", "testpass"); 270 auth = new AuthenticationBuilder() 271 .addUsername("testuser") 272 .addPassword("testpass") 273 .build(); 274 newTransporter(httpServer.getHttpUrl()); 275 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 276 } 277 278 @Test 279 protected void testPeek_Unauthenticated() throws Exception { 280 httpServer.setAuthentication("testuser", "testpass"); 281 try { 282 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 283 fail("Expected error"); 284 } catch (HttpTransporterException e) { 285 assertEquals(401, e.getStatusCode()); 286 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 287 } 288 } 289 290 @Test 291 protected void testPeek_ProxyAuthenticated() throws Exception { 292 httpServer.setProxyAuthentication("testuser", "testpass"); 293 auth = new AuthenticationBuilder() 294 .addUsername("testuser") 295 .addPassword("testpass") 296 .build(); 297 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 298 newTransporter("http://bad.localhost:1/"); 299 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 300 } 301 302 @Test 303 protected void testPeek_ProxyUnauthenticated() throws Exception { 304 httpServer.setProxyAuthentication("testuser", "testpass"); 305 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 306 newTransporter("http://bad.localhost:1/"); 307 try { 308 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 309 fail("Expected error"); 310 } catch (HttpTransporterException e) { 311 assertEquals(407, e.getStatusCode()); 312 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 313 } 314 } 315 316 @Test 317 protected void testPeek_SSL() throws Exception { 318 httpServer.addSslConnector(); 319 newTransporter(httpServer.getHttpsUrl()); 320 transporter.peek(new PeekTask(URI.create("repo/file.txt"))); 321 } 322 323 @Test 324 protected void testPeek_Redirect() throws Exception { 325 httpServer.addSslConnector(); 326 transporter.peek(new PeekTask(URI.create("redirect/file.txt"))); 327 transporter.peek(new PeekTask(URI.create("redirect/file.txt?scheme=https"))); 328 } 329 330 @Test 331 protected void testGet_ToMemory() throws Exception { 332 RecordingTransportListener listener = new RecordingTransportListener(); 333 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 334 transporter.get(task); 335 assertEquals("test", task.getDataString()); 336 assertEquals(0L, listener.getDataOffset()); 337 assertEquals(4L, listener.getDataLength()); 338 assertEquals(1, listener.getStartedCount()); 339 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 340 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 341 } 342 343 @Test 344 protected void testGet_ToFile() throws Exception { 345 File file = TestFileUtils.createTempFile("failure"); 346 RecordingTransportListener listener = new RecordingTransportListener(); 347 GetTask task = 348 new GetTask(URI.create("repo/file.txt")).setDataFile(file).setListener(listener); 349 transporter.get(task); 350 assertEquals("test", TestFileUtils.readString(file)); 351 assertEquals(0L, listener.getDataOffset()); 352 assertEquals(4L, listener.getDataLength()); 353 assertEquals(1, listener.getStartedCount()); 354 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 355 assertEquals("test", listener.getBaos().toString(StandardCharsets.UTF_8)); 356 } 357 358 @Test 359 protected void testGet_ToFileTimestamp() throws Exception { 360 File file = TestFileUtils.createTempFile("failure"); 361 RecordingTransportListener listener = new RecordingTransportListener(); 362 GetTask task = new GetTask(URI.create("repo/dir/oldFile.txt")) 363 .setDataFile(file) 364 .setListener(listener); 365 transporter.get(task); 366 assertEquals("oldTest", TestFileUtils.readString(file)); 367 assertEquals(0L, listener.getDataOffset()); 368 assertEquals(7L, listener.getDataLength()); 369 assertEquals(1, listener.getStartedCount()); 370 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 371 assertEquals("oldTest", listener.getBaos().toString(StandardCharsets.UTF_8)); 372 assertEquals(file.lastModified(), OLD_FILE_TIMESTAMP); 373 } 374 375 @Test 376 protected void testGet_EmptyResource() throws Exception { 377 File file = TestFileUtils.createTempFile("failure"); 378 RecordingTransportListener listener = new RecordingTransportListener(); 379 GetTask task = 380 new GetTask(URI.create("repo/empty.txt")).setDataFile(file).setListener(listener); 381 transporter.get(task); 382 assertEquals("", TestFileUtils.readString(file)); 383 assertEquals(0L, listener.getDataOffset()); 384 assertEquals(0L, listener.getDataLength()); 385 assertEquals(1, listener.getStartedCount()); 386 assertEquals(0, listener.getProgressedCount()); 387 assertEquals("", listener.getBaos().toString(StandardCharsets.UTF_8)); 388 } 389 390 @Test 391 protected void testGet_EncodedResourcePath() throws Exception { 392 GetTask task = new GetTask(URI.create("repo/some%20space.txt")); 393 transporter.get(task); 394 assertEquals("space", task.getDataString()); 395 } 396 397 @Test 398 protected void testGet_Authenticated() throws Exception { 399 httpServer.setAuthentication("testuser", "testpass"); 400 auth = new AuthenticationBuilder() 401 .addUsername("testuser") 402 .addPassword("testpass") 403 .build(); 404 newTransporter(httpServer.getHttpUrl()); 405 RecordingTransportListener listener = new RecordingTransportListener(); 406 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 407 transporter.get(task); 408 assertEquals("test", task.getDataString()); 409 assertEquals(0L, listener.getDataOffset()); 410 assertEquals(4L, listener.getDataLength()); 411 assertEquals(1, listener.getStartedCount()); 412 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 413 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 414 } 415 416 @Test 417 protected void testGet_Unauthenticated() throws Exception { 418 httpServer.setAuthentication("testuser", "testpass"); 419 try { 420 transporter.get(new GetTask(URI.create("repo/file.txt"))); 421 fail("Expected error"); 422 } catch (HttpTransporterException e) { 423 assertEquals(401, e.getStatusCode()); 424 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 425 } 426 } 427 428 @Test 429 protected void testGet_ProxyAuthenticated() throws Exception { 430 httpServer.setProxyAuthentication("testuser", "testpass"); 431 Authentication auth = new AuthenticationBuilder() 432 .addUsername("testuser") 433 .addPassword("testpass") 434 .build(); 435 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 436 newTransporter("http://bad.localhost:1/"); 437 RecordingTransportListener listener = new RecordingTransportListener(); 438 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 439 transporter.get(task); 440 assertEquals("test", task.getDataString()); 441 assertEquals(0L, listener.getDataOffset()); 442 assertEquals(4L, listener.getDataLength()); 443 assertEquals(1, listener.getStartedCount()); 444 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 445 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 446 } 447 448 @Test 449 protected void testGet_ProxyUnauthenticated() throws Exception { 450 httpServer.setProxyAuthentication("testuser", "testpass"); 451 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 452 newTransporter("http://bad.localhost:1/"); 453 try { 454 transporter.get(new GetTask(URI.create("repo/file.txt"))); 455 fail("Expected error"); 456 } catch (HttpTransporterException e) { 457 assertEquals(407, e.getStatusCode()); 458 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 459 } 460 } 461 462 @Test 463 protected void testGet_SSL() throws Exception { 464 httpServer.addSslConnector(); 465 newTransporter(httpServer.getHttpsUrl()); 466 RecordingTransportListener listener = new RecordingTransportListener(); 467 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 468 transporter.get(task); 469 assertEquals("test", task.getDataString()); 470 assertEquals(0L, listener.getDataOffset()); 471 assertEquals(4L, listener.getDataLength()); 472 assertEquals(1, listener.getStartedCount()); 473 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 474 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 475 } 476 477 @Test 478 protected void testGet_SSL_WithServerErrors() throws Exception { 479 httpServer.setServerErrorsBeforeWorks(1); 480 httpServer.addSslConnector(); 481 newTransporter(httpServer.getHttpsUrl()); 482 for (int i = 1; i < 3; i++) { 483 try { 484 RecordingTransportListener listener = new RecordingTransportListener(); 485 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 486 transporter.get(task); 487 assertEquals("test", task.getDataString()); 488 assertEquals(0L, listener.getDataOffset()); 489 assertEquals(4L, listener.getDataLength()); 490 assertEquals(1, listener.getStartedCount()); 491 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 492 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 493 } catch (HttpTransporterException e) { 494 assertEquals(500, e.getStatusCode()); 495 } 496 } 497 } 498 499 @Test 500 protected void testGet_HTTPS_Unknown_SecurityMode() throws Exception { 501 session.setConfigProperty(ConfigurationProperties.HTTPS_SECURITY_MODE, "unknown"); 502 httpServer.addSelfSignedSslConnector(); 503 try { 504 newTransporter(httpServer.getHttpsUrl()); 505 fail("Unsupported security mode"); 506 } catch (IllegalArgumentException a) { 507 // good 508 } 509 } 510 511 @Test 512 protected void testGet_HTTPS_Insecure_SecurityMode() throws Exception { 513 // here we use alternate server-store-selfigned key (as the key set it static initalizer is probably already 514 // used to init SSLContext/SSLSocketFactory/etc 515 session.setConfigProperty( 516 ConfigurationProperties.HTTPS_SECURITY_MODE, ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE); 517 httpServer.addSelfSignedSslConnector(); 518 newTransporter(httpServer.getHttpsUrl()); 519 RecordingTransportListener listener = new RecordingTransportListener(); 520 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 521 transporter.get(task); 522 assertEquals("test", task.getDataString()); 523 assertEquals(0L, listener.getDataOffset()); 524 assertEquals(4L, listener.getDataLength()); 525 assertEquals(1, listener.getStartedCount()); 526 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 527 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 528 } 529 530 @Test 531 protected void testGet_Redirect() throws Exception { 532 httpServer.addSslConnector(); 533 RecordingTransportListener listener = new RecordingTransportListener(); 534 GetTask task = new GetTask(URI.create("redirect/file.txt?scheme=https")).setListener(listener); 535 transporter.get(task); 536 assertEquals("test", task.getDataString()); 537 assertEquals(0L, listener.getDataOffset()); 538 assertEquals(4L, listener.getDataLength()); 539 assertEquals(1, listener.getStartedCount()); 540 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 541 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 542 } 543 544 @Test 545 protected void testGet_Resume() throws Exception { 546 File file = TestFileUtils.createTempFile("re"); 547 RecordingTransportListener listener = new RecordingTransportListener(); 548 GetTask task = new GetTask(URI.create("repo/resume.txt")) 549 .setDataFile(file, true) 550 .setListener(listener); 551 transporter.get(task); 552 assertEquals("resumable", TestFileUtils.readString(file)); 553 assertEquals(1L, listener.getStartedCount()); 554 assertEquals(2L, listener.getDataOffset()); 555 assertEquals(9, listener.getDataLength()); 556 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 557 assertEquals("sumable", listener.getBaos().toString(StandardCharsets.UTF_8)); 558 } 559 560 @Test 561 protected void testGet_ResumeLocalContentsOutdated() throws Exception { 562 File file = TestFileUtils.createTempFile("re"); 563 file.setLastModified(System.currentTimeMillis() - 5 * 60 * 1000); 564 RecordingTransportListener listener = new RecordingTransportListener(); 565 GetTask task = new GetTask(URI.create("repo/resume.txt")) 566 .setDataFile(file, true) 567 .setListener(listener); 568 transporter.get(task); 569 assertEquals("resumable", TestFileUtils.readString(file)); 570 assertEquals(1L, listener.getStartedCount()); 571 assertEquals(0L, listener.getDataOffset()); 572 assertEquals(9, listener.getDataLength()); 573 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 574 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8)); 575 } 576 577 @Test 578 protected void testGet_ResumeRangesNotSupportedByServer() throws Exception { 579 httpServer.setRangeSupport(false); 580 File file = TestFileUtils.createTempFile("re"); 581 RecordingTransportListener listener = new RecordingTransportListener(); 582 GetTask task = new GetTask(URI.create("repo/resume.txt")) 583 .setDataFile(file, true) 584 .setListener(listener); 585 transporter.get(task); 586 assertEquals("resumable", TestFileUtils.readString(file)); 587 assertEquals(1L, listener.getStartedCount()); 588 assertEquals(0L, listener.getDataOffset()); 589 assertEquals(9, listener.getDataLength()); 590 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 591 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8)); 592 } 593 594 @Test 595 protected void testGet_Checksums_Nexus() throws Exception { 596 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.NEXUS); 597 GetTask task = new GetTask(URI.create("repo/file.txt")); 598 transporter.get(task); 599 assertEquals("test", task.getDataString()); 600 assertEquals( 601 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1")); 602 } 603 604 @Test 605 protected void testGet_Checksums_XChecksum() throws Exception { 606 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.XCHECKSUM); 607 GetTask task = new GetTask(URI.create("repo/file.txt")); 608 transporter.get(task); 609 assertEquals("test", task.getDataString()); 610 assertEquals( 611 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1")); 612 } 613 614 @Test 615 protected void testGet_FileHandleLeak() throws Exception { 616 for (int i = 0; i < 100; i++) { 617 File file = TestFileUtils.createTempFile("failure"); 618 transporter.get(new GetTask(URI.create("repo/file.txt")).setDataFile(file)); 619 assertTrue(file.delete(), i + ", " + file.getAbsolutePath()); 620 } 621 } 622 623 @Test 624 protected void testGet_NotFound() throws Exception { 625 try { 626 transporter.get(new GetTask(URI.create("repo/missing.txt"))); 627 fail("Expected error"); 628 } catch (HttpTransporterException e) { 629 assertEquals(404, e.getStatusCode()); 630 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e)); 631 } 632 } 633 634 @Test 635 protected void testGet_Closed() throws Exception { 636 transporter.close(); 637 try { 638 transporter.get(new GetTask(URI.create("repo/file.txt"))); 639 fail("Expected error"); 640 } catch (IllegalStateException e) { 641 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 642 } 643 } 644 645 @Test 646 protected void testGet_StartCancelled() throws Exception { 647 RecordingTransportListener listener = new RecordingTransportListener(); 648 listener.cancelStart(); 649 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 650 try { 651 transporter.get(task); 652 fail("Expected error"); 653 } catch (TransferCancelledException e) { 654 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 655 } 656 assertEquals(0L, listener.getDataOffset()); 657 assertEquals(4L, listener.getDataLength()); 658 assertEquals(1, listener.getStartedCount()); 659 assertEquals(0, listener.getProgressedCount()); 660 } 661 662 @Test 663 protected void testGet_ProgressCancelled() throws Exception { 664 RecordingTransportListener listener = new RecordingTransportListener(); 665 listener.cancelProgress(); 666 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 667 try { 668 transporter.get(task); 669 fail("Expected error"); 670 } catch (TransferCancelledException e) { 671 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 672 } 673 assertEquals(0L, listener.getDataOffset()); 674 assertEquals(4L, listener.getDataLength()); 675 assertEquals(1, listener.getStartedCount()); 676 assertEquals(1, listener.getProgressedCount()); 677 } 678 679 @Test 680 protected void testPut_FromMemory() throws Exception { 681 RecordingTransportListener listener = new RecordingTransportListener(); 682 PutTask task = 683 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 684 transporter.put(task); 685 assertEquals(0L, listener.getDataOffset()); 686 assertEquals(6L, listener.getDataLength()); 687 assertEquals(1, listener.getStartedCount()); 688 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 689 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 690 } 691 692 @Test 693 protected void testPut_FromFile() throws Exception { 694 File file = TestFileUtils.createTempFile("upload"); 695 RecordingTransportListener listener = new RecordingTransportListener(); 696 PutTask task = 697 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataFile(file); 698 transporter.put(task); 699 assertEquals(0L, listener.getDataOffset()); 700 assertEquals(6L, listener.getDataLength()); 701 assertEquals(1, listener.getStartedCount()); 702 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 703 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 704 } 705 706 @Test 707 protected void testPut_EmptyResource() throws Exception { 708 RecordingTransportListener listener = new RecordingTransportListener(); 709 PutTask task = new PutTask(URI.create("repo/file.txt")).setListener(listener); 710 transporter.put(task); 711 assertEquals(0L, listener.getDataOffset()); 712 assertEquals(0L, listener.getDataLength()); 713 assertEquals(1, listener.getStartedCount()); 714 assertEquals(0, listener.getProgressedCount()); 715 assertEquals("", TestFileUtils.readString(new File(repoDir, "file.txt"))); 716 } 717 718 @Test 719 protected void testPut_EncodedResourcePath() throws Exception { 720 RecordingTransportListener listener = new RecordingTransportListener(); 721 PutTask task = new PutTask(URI.create("repo/some%20space.txt")) 722 .setListener(listener) 723 .setDataString("OK"); 724 transporter.put(task); 725 assertEquals(0L, listener.getDataOffset()); 726 assertEquals(2L, listener.getDataLength()); 727 assertEquals(1, listener.getStartedCount()); 728 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 729 assertEquals("OK", TestFileUtils.readString(new File(repoDir, "some space.txt"))); 730 } 731 732 @Test 733 protected void testPut_Authenticated_ExpectContinue() throws Exception { 734 httpServer.setAuthentication("testuser", "testpass"); 735 auth = new AuthenticationBuilder() 736 .addUsername("testuser") 737 .addPassword("testpass") 738 .build(); 739 newTransporter(httpServer.getHttpUrl()); 740 RecordingTransportListener listener = new RecordingTransportListener(); 741 PutTask task = 742 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 743 transporter.put(task); 744 assertEquals(0L, listener.getDataOffset()); 745 assertEquals(6L, listener.getDataLength()); 746 assertEquals(1, listener.getStartedCount()); 747 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 748 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 749 } 750 751 @Test 752 protected void testPut_Authenticated_ExpectContinueBroken() throws Exception { 753 // this makes OPTIONS recover, and have only 1 PUT (startedCount=1 as OPTIONS is not counted) 754 session.setConfigProperty(ConfigurationProperties.HTTP_SUPPORT_WEBDAV, true); 755 httpServer.setAuthentication("testuser", "testpass"); 756 httpServer.setExpectSupport(HttpServer.ExpectContinue.BROKEN); 757 auth = new AuthenticationBuilder() 758 .addUsername("testuser") 759 .addPassword("testpass") 760 .build(); 761 newTransporter(httpServer.getHttpUrl()); 762 RecordingTransportListener listener = new RecordingTransportListener(); 763 PutTask task = 764 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 765 transporter.put(task); 766 assertEquals(0L, listener.getDataOffset()); 767 assertEquals(6L, listener.getDataLength()); 768 assertEquals(1, listener.getStartedCount()); 769 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 770 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 771 } 772 773 @Test 774 protected void testPut_Authenticated_ExpectContinueRejected() throws Exception { 775 httpServer.setAuthentication("testuser", "testpass"); 776 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL); 777 auth = new AuthenticationBuilder() 778 .addUsername("testuser") 779 .addPassword("testpass") 780 .build(); 781 newTransporter(httpServer.getHttpUrl()); 782 RecordingTransportListener listener = new RecordingTransportListener(); 783 PutTask task = 784 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 785 transporter.put(task); 786 assertEquals(0L, listener.getDataOffset()); 787 assertEquals(6L, listener.getDataLength()); 788 assertEquals(1, listener.getStartedCount()); 789 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 790 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 791 } 792 793 @Test 794 protected void testPut_Authenticated_ExpectContinueDisabled() throws Exception { 795 session.setConfigProperty(ConfigurationProperties.HTTP_EXPECT_CONTINUE, false); 796 httpServer.setAuthentication("testuser", "testpass"); 797 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL); // if transport tries Expect/Continue explode 798 auth = new AuthenticationBuilder() 799 .addUsername("testuser") 800 .addPassword("testpass") 801 .build(); 802 newTransporter(httpServer.getHttpUrl()); 803 RecordingTransportListener listener = new RecordingTransportListener(); 804 PutTask task = 805 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 806 transporter.put(task); 807 assertEquals(0L, listener.getDataOffset()); 808 assertEquals(6L, listener.getDataLength()); 809 assertEquals(1, listener.getStartedCount()); // w/ expectContinue enabled would have here 2 810 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 811 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 812 } 813 814 @Test 815 protected void testPut_Authenticated_ExpectContinueRejected_ExplicitlyConfiguredHeader() throws Exception { 816 Map<String, String> headers = new HashMap<>(); 817 headers.put("Expect", "100-continue"); 818 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers); 819 httpServer.setAuthentication("testuser", "testpass"); 820 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL); 821 auth = new AuthenticationBuilder() 822 .addUsername("testuser") 823 .addPassword("testpass") 824 .build(); 825 newTransporter(httpServer.getHttpUrl()); 826 RecordingTransportListener listener = new RecordingTransportListener(); 827 PutTask task = 828 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 829 transporter.put(task); 830 assertEquals(0L, listener.getDataOffset()); 831 assertEquals(6L, listener.getDataLength()); 832 assertEquals(1, listener.getStartedCount()); 833 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 834 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 835 } 836 837 @Test 838 protected void testPut_Unauthenticated() throws Exception { 839 httpServer.setAuthentication("testuser", "testpass"); 840 RecordingTransportListener listener = new RecordingTransportListener(); 841 PutTask task = 842 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 843 try { 844 transporter.put(task); 845 fail("Expected error"); 846 } catch (HttpTransporterException e) { 847 assertEquals(401, e.getStatusCode()); 848 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 849 } 850 assertEquals(0, listener.getStartedCount()); 851 assertEquals(0, listener.getProgressedCount()); 852 } 853 854 @Test 855 protected void testPut_ProxyAuthenticated() throws Exception { 856 httpServer.setProxyAuthentication("testuser", "testpass"); 857 Authentication auth = new AuthenticationBuilder() 858 .addUsername("testuser") 859 .addPassword("testpass") 860 .build(); 861 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 862 newTransporter("http://bad.localhost:1/"); 863 RecordingTransportListener listener = new RecordingTransportListener(); 864 PutTask task = 865 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 866 transporter.put(task); 867 assertEquals(0L, listener.getDataOffset()); 868 assertEquals(6L, listener.getDataLength()); 869 assertEquals(1, listener.getStartedCount()); 870 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 871 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 872 } 873 874 @Test 875 protected void testPut_ProxyUnauthenticated() throws Exception { 876 httpServer.setProxyAuthentication("testuser", "testpass"); 877 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 878 newTransporter("http://bad.localhost:1/"); 879 RecordingTransportListener listener = new RecordingTransportListener(); 880 PutTask task = 881 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 882 try { 883 transporter.put(task); 884 fail("Expected error"); 885 } catch (HttpTransporterException e) { 886 assertEquals(407, e.getStatusCode()); 887 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 888 } 889 assertEquals(0, listener.getStartedCount()); 890 assertEquals(0, listener.getProgressedCount()); 891 } 892 893 @Test 894 protected void testPut_SSL() throws Exception { 895 httpServer.addSslConnector(); 896 httpServer.setAuthentication("testuser", "testpass"); 897 auth = new AuthenticationBuilder() 898 .addUsername("testuser") 899 .addPassword("testpass") 900 .build(); 901 newTransporter(httpServer.getHttpsUrl()); 902 RecordingTransportListener listener = new RecordingTransportListener(); 903 PutTask task = 904 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 905 transporter.put(task); 906 assertEquals(0L, listener.getDataOffset()); 907 assertEquals(6L, listener.getDataLength()); 908 assertEquals(1, listener.getStartedCount()); 909 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 910 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 911 } 912 913 @Test 914 protected void testPut_FileHandleLeak() throws Exception { 915 for (int i = 0; i < 100; i++) { 916 File src = TestFileUtils.createTempFile("upload"); 917 File dst = new File(repoDir, "file.txt"); 918 transporter.put(new PutTask(URI.create("repo/file.txt")).setDataFile(src)); 919 assertTrue(src.delete(), i + ", " + src.getAbsolutePath()); 920 assertTrue(dst.delete(), i + ", " + dst.getAbsolutePath()); 921 } 922 } 923 924 @Test 925 protected void testPut_Closed() throws Exception { 926 transporter.close(); 927 try { 928 transporter.put(new PutTask(URI.create("repo/missing.txt"))); 929 fail("Expected error"); 930 } catch (IllegalStateException e) { 931 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 932 } 933 } 934 935 @Test 936 protected void testPut_StartCancelled() throws Exception { 937 RecordingTransportListener listener = new RecordingTransportListener(); 938 listener.cancelStart(); 939 PutTask task = 940 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 941 try { 942 transporter.put(task); 943 fail("Expected error"); 944 } catch (TransferCancelledException e) { 945 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 946 } 947 assertEquals(0L, listener.getDataOffset()); 948 assertEquals(6L, listener.getDataLength()); 949 assertEquals(1, listener.getStartedCount()); 950 assertEquals(0, listener.getProgressedCount()); 951 } 952 953 @Test 954 protected void testPut_ProgressCancelled() throws Exception { 955 RecordingTransportListener listener = new RecordingTransportListener(); 956 listener.cancelProgress(); 957 PutTask task = 958 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 959 try { 960 transporter.put(task); 961 fail("Expected error"); 962 } catch (TransferCancelledException e) { 963 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 964 } 965 assertEquals(0L, listener.getDataOffset()); 966 assertEquals(6L, listener.getDataLength()); 967 assertEquals(1, listener.getStartedCount()); 968 assertEquals(1, listener.getProgressedCount()); 969 } 970 971 @Test 972 protected void testGetPut_AuthCache() throws Exception { 973 httpServer.setAuthentication("testuser", "testpass"); 974 auth = new AuthenticationBuilder() 975 .addUsername("testuser") 976 .addPassword("testpass") 977 .build(); 978 newTransporter(httpServer.getHttpUrl()); 979 GetTask get = new GetTask(URI.create("repo/file.txt")); 980 transporter.get(get); 981 RecordingTransportListener listener = new RecordingTransportListener(); 982 PutTask task = 983 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 984 transporter.put(task); 985 assertEquals(1, listener.getStartedCount()); 986 } 987 988 @Test 989 protected void testPut_PreemptiveIsDefault() throws Exception { 990 httpServer.setAuthentication("testuser", "testpass"); 991 auth = new AuthenticationBuilder() 992 .addUsername("testuser") 993 .addPassword("testpass") 994 .build(); 995 newTransporter(httpServer.getHttpUrl()); 996 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 997 transporter.put(task); 998 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 999 } 1000 1001 @Test 1002 protected void testPut_AuthCache() throws Exception { 1003 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH, false); 1004 httpServer.setAuthentication("testuser", "testpass"); 1005 auth = new AuthenticationBuilder() 1006 .addUsername("testuser") 1007 .addPassword("testpass") 1008 .build(); 1009 newTransporter(httpServer.getHttpUrl()); 1010 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1011 transporter.put(task); 1012 assertEquals(2, httpServer.getLogEntries().size()); // put (challenged) + put w/ auth 1013 httpServer.getLogEntries().clear(); 1014 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1015 transporter.put(task); 1016 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1017 } 1018 1019 @Test 1020 protected void testPut_AuthCache_Preemptive() throws Exception { 1021 httpServer.setAuthentication("testuser", "testpass"); 1022 auth = new AuthenticationBuilder() 1023 .addUsername("testuser") 1024 .addPassword("testpass") 1025 .build(); 1026 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true); 1027 newTransporter(httpServer.getHttpUrl()); 1028 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1029 transporter.put(task); 1030 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1031 httpServer.getLogEntries().clear(); 1032 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1033 transporter.put(task); 1034 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1035 } 1036 1037 @Test 1038 @Timeout(20) 1039 protected void testConcurrency() throws Exception { 1040 httpServer.setAuthentication("testuser", "testpass"); 1041 auth = new AuthenticationBuilder() 1042 .addUsername("testuser") 1043 .addPassword("testpass") 1044 .build(); 1045 newTransporter(httpServer.getHttpUrl()); 1046 final AtomicReference<Throwable> error = new AtomicReference<>(); 1047 Thread[] threads = new Thread[20]; 1048 for (int i = 0; i < threads.length; i++) { 1049 final String path = "repo/file.txt?i=" + i; 1050 threads[i] = new Thread(() -> { 1051 try { 1052 for (int j = 0; j < 100; j++) { 1053 GetTask task = new GetTask(URI.create(path)); 1054 transporter.get(task); 1055 assertEquals("test", task.getDataString()); 1056 } 1057 } catch (Throwable t) { 1058 error.compareAndSet(null, t); 1059 System.err.println(path); 1060 t.printStackTrace(); 1061 } 1062 }); 1063 threads[i].setName("Task-" + i); 1064 } 1065 for (Thread thread : threads) { 1066 thread.start(); 1067 } 1068 for (Thread thread : threads) { 1069 thread.join(); 1070 } 1071 assertNull(error.get(), String.valueOf(error.get())); 1072 } 1073 1074 @Test 1075 @Timeout(10) 1076 protected void testConnectTimeout() throws Exception { 1077 session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, 100); 1078 int port = 1; 1079 newTransporter("http://localhost:" + port); 1080 try { 1081 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1082 fail("Expected error"); 1083 } catch (Exception e) { 1084 // impl specific "timeout" exception 1085 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 1086 } 1087 } 1088 1089 @Test 1090 @Timeout(10) 1091 protected void testRequestTimeout() throws Exception { 1092 session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, 100); 1093 ServerSocket server = new ServerSocket(0); 1094 try (server) { 1095 newTransporter("http://localhost:" + server.getLocalPort()); 1096 try { 1097 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1098 fail("Expected error"); 1099 } catch (Exception e) { 1100 assertTrue(e.getClass().getSimpleName().contains("Timeout")); 1101 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 1102 } 1103 } 1104 } 1105 1106 @Test 1107 protected void testUserAgent() throws Exception { 1108 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0"); 1109 newTransporter(httpServer.getHttpUrl()); 1110 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1111 assertEquals(1, httpServer.getLogEntries().size()); 1112 for (HttpServer.LogEntry log : httpServer.getLogEntries()) { 1113 assertEquals("SomeTest/1.0", log.getHeaders().get("User-Agent")); 1114 } 1115 } 1116 1117 @Test 1118 protected void testCustomHeaders() throws Exception { 1119 Map<String, String> headers = new HashMap<>(); 1120 headers.put("User-Agent", "Custom/1.0"); 1121 headers.put("X-CustomHeader", "Custom-Value"); 1122 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0"); 1123 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers); 1124 newTransporter(httpServer.getHttpUrl()); 1125 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1126 assertEquals(1, httpServer.getLogEntries().size()); 1127 for (HttpServer.LogEntry log : httpServer.getLogEntries()) { 1128 for (Map.Entry<String, String> entry : headers.entrySet()) { 1129 assertEquals(entry.getValue(), log.getHeaders().get(entry.getKey()), entry.getKey()); 1130 } 1131 } 1132 } 1133 1134 @Test 1135 protected void testServerAuthScope_NotUsedForProxy() throws Exception { 1136 String username = "testuser", password = "testpass"; 1137 httpServer.setProxyAuthentication(username, password); 1138 auth = new AuthenticationBuilder() 1139 .addUsername(username) 1140 .addPassword(password) 1141 .build(); 1142 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 1143 newTransporter("http://" + httpServer.getHost() + ":12/"); 1144 try { 1145 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1146 fail("Server auth must not be used as proxy auth"); 1147 } catch (HttpTransporterException e) { 1148 assertEquals(407, e.getStatusCode()); 1149 } catch (IOException e) { 1150 // accepted as well: point is to fail 1151 } 1152 } 1153 1154 @Test 1155 protected void testProxyAuthScope_NotUsedForServer() throws Exception { 1156 String username = "testuser", password = "testpass"; 1157 httpServer.setAuthentication(username, password); 1158 Authentication auth = new AuthenticationBuilder() 1159 .addUsername(username) 1160 .addPassword(password) 1161 .build(); 1162 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 1163 newTransporter("http://" + httpServer.getHost() + ":12/"); 1164 try { 1165 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1166 fail("Proxy auth must not be used as server auth"); 1167 } catch (HttpTransporterException e) { 1168 assertEquals(401, e.getStatusCode()); 1169 } catch (IOException e) { 1170 // accepted as well: point is to fail 1171 } 1172 } 1173 1174 @Test 1175 protected void testAuthSchemeReuse() throws Exception { 1176 httpServer.setAuthentication("testuser", "testpass"); 1177 httpServer.setProxyAuthentication("proxyuser", "proxypass"); 1178 session.setCache(new DefaultRepositoryCache()); 1179 auth = new AuthenticationBuilder() 1180 .addUsername("testuser") 1181 .addPassword("testpass") 1182 .build(); 1183 Authentication auth = new AuthenticationBuilder() 1184 .addUsername("proxyuser") 1185 .addPassword("proxypass") 1186 .build(); 1187 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 1188 newTransporter("http://bad.localhost:1/"); 1189 GetTask task = new GetTask(URI.create("repo/file.txt")); 1190 transporter.get(task); 1191 assertEquals("test", task.getDataString()); 1192 assertEquals(3, httpServer.getLogEntries().size()); 1193 httpServer.getLogEntries().clear(); 1194 newTransporter("http://bad.localhost:1/"); 1195 task = new GetTask(URI.create("repo/file.txt")); 1196 transporter.get(task); 1197 assertEquals("test", task.getDataString()); 1198 assertEquals(1, httpServer.getLogEntries().size()); 1199 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Authorization")); 1200 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Proxy-Authorization")); 1201 } 1202 1203 @Test 1204 protected void testAuthSchemePreemptive() throws Exception { 1205 httpServer.setAuthentication("testuser", "testpass"); 1206 session.setCache(new DefaultRepositoryCache()); 1207 auth = new AuthenticationBuilder() 1208 .addUsername("testuser") 1209 .addPassword("testpass") 1210 .build(); 1211 1212 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, false); 1213 newTransporter(httpServer.getHttpUrl()); 1214 GetTask task = new GetTask(URI.create("repo/file.txt")); 1215 transporter.get(task); 1216 assertEquals("test", task.getDataString()); 1217 // there ARE challenge round-trips 1218 assertEquals(2, httpServer.getLogEntries().size()); 1219 1220 httpServer.getLogEntries().clear(); 1221 1222 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true); 1223 newTransporter(httpServer.getHttpUrl()); 1224 task = new GetTask(URI.create("repo/file.txt")); 1225 transporter.get(task); 1226 assertEquals("test", task.getDataString()); 1227 // there are NO challenge round-trips, all goes through at first 1228 assertEquals(1, httpServer.getLogEntries().size()); 1229 } 1230 1231 @Test 1232 void testInit_BadProtocol() { 1233 assertThrows(NoTransporterException.class, () -> newTransporter("bad:/void")); 1234 } 1235 1236 @Test 1237 void testInit_BadUrl() { 1238 assertThrows(NoTransporterException.class, () -> newTransporter("http://localhost:NaN")); 1239 } 1240 1241 @Test 1242 void testInit_CaseInsensitiveProtocol() throws Exception { 1243 newTransporter("http://localhost"); 1244 newTransporter("HTTP://localhost"); 1245 newTransporter("Http://localhost"); 1246 newTransporter("https://localhost"); 1247 newTransporter("HTTPS://localhost"); 1248 newTransporter("HttpS://localhost"); 1249 } 1250}