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