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 = new GetTask(URI.create("repo/file.txt")) 348 .setDataPath(file.toPath()) 349 .setListener(listener); 350 transporter.get(task); 351 assertEquals("test", TestFileUtils.readString(file)); 352 assertEquals(0L, listener.getDataOffset()); 353 assertEquals(4L, listener.getDataLength()); 354 assertEquals(1, listener.getStartedCount()); 355 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 356 assertEquals("test", listener.getBaos().toString(StandardCharsets.UTF_8)); 357 } 358 359 @Test 360 protected void testGet_ToFileTimestamp() throws Exception { 361 File file = TestFileUtils.createTempFile("failure"); 362 RecordingTransportListener listener = new RecordingTransportListener(); 363 GetTask task = new GetTask(URI.create("repo/dir/oldFile.txt")) 364 .setDataPath(file.toPath()) 365 .setListener(listener); 366 transporter.get(task); 367 assertEquals("oldTest", TestFileUtils.readString(file)); 368 assertEquals(0L, listener.getDataOffset()); 369 assertEquals(7L, listener.getDataLength()); 370 assertEquals(1, listener.getStartedCount()); 371 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 372 assertEquals("oldTest", listener.getBaos().toString(StandardCharsets.UTF_8)); 373 assertEquals(file.lastModified(), OLD_FILE_TIMESTAMP); 374 } 375 376 @Test 377 protected void testGet_EmptyResource() throws Exception { 378 File file = TestFileUtils.createTempFile("failure"); 379 RecordingTransportListener listener = new RecordingTransportListener(); 380 GetTask task = new GetTask(URI.create("repo/empty.txt")) 381 .setDataPath(file.toPath()) 382 .setListener(listener); 383 transporter.get(task); 384 assertEquals("", TestFileUtils.readString(file)); 385 assertEquals(0L, listener.getDataOffset()); 386 assertEquals(0L, listener.getDataLength()); 387 assertEquals(1, listener.getStartedCount()); 388 assertEquals(0, listener.getProgressedCount()); 389 assertEquals("", listener.getBaos().toString(StandardCharsets.UTF_8)); 390 } 391 392 @Test 393 protected void testGet_EncodedResourcePath() throws Exception { 394 GetTask task = new GetTask(URI.create("repo/some%20space.txt")); 395 transporter.get(task); 396 assertEquals("space", task.getDataString()); 397 } 398 399 @Test 400 protected void testGet_Authenticated() throws Exception { 401 httpServer.setAuthentication("testuser", "testpass"); 402 auth = new AuthenticationBuilder() 403 .addUsername("testuser") 404 .addPassword("testpass") 405 .build(); 406 newTransporter(httpServer.getHttpUrl()); 407 RecordingTransportListener listener = new RecordingTransportListener(); 408 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 409 transporter.get(task); 410 assertEquals("test", task.getDataString()); 411 assertEquals(0L, listener.getDataOffset()); 412 assertEquals(4L, listener.getDataLength()); 413 assertEquals(1, listener.getStartedCount()); 414 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 415 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 416 } 417 418 @Test 419 protected void testGet_Unauthenticated() throws Exception { 420 httpServer.setAuthentication("testuser", "testpass"); 421 try { 422 transporter.get(new GetTask(URI.create("repo/file.txt"))); 423 fail("Expected error"); 424 } catch (HttpTransporterException e) { 425 assertEquals(401, e.getStatusCode()); 426 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 427 } 428 } 429 430 @Test 431 protected void testGet_ProxyAuthenticated() throws Exception { 432 httpServer.setProxyAuthentication("testuser", "testpass"); 433 Authentication auth = new AuthenticationBuilder() 434 .addUsername("testuser") 435 .addPassword("testpass") 436 .build(); 437 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 438 newTransporter("http://bad.localhost:1/"); 439 RecordingTransportListener listener = new RecordingTransportListener(); 440 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 441 transporter.get(task); 442 assertEquals("test", task.getDataString()); 443 assertEquals(0L, listener.getDataOffset()); 444 assertEquals(4L, listener.getDataLength()); 445 assertEquals(1, listener.getStartedCount()); 446 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 447 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 448 } 449 450 @Test 451 protected void testGet_ProxyUnauthenticated() throws Exception { 452 httpServer.setProxyAuthentication("testuser", "testpass"); 453 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 454 newTransporter("http://bad.localhost:1/"); 455 try { 456 transporter.get(new GetTask(URI.create("repo/file.txt"))); 457 fail("Expected error"); 458 } catch (HttpTransporterException e) { 459 assertEquals(407, e.getStatusCode()); 460 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 461 } 462 } 463 464 @Test 465 protected void testGet_SSL() throws Exception { 466 httpServer.addSslConnector(); 467 newTransporter(httpServer.getHttpsUrl()); 468 RecordingTransportListener listener = new RecordingTransportListener(); 469 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 470 transporter.get(task); 471 assertEquals("test", task.getDataString()); 472 assertEquals(0L, listener.getDataOffset()); 473 assertEquals(4L, listener.getDataLength()); 474 assertEquals(1, listener.getStartedCount()); 475 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 476 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 477 } 478 479 @Test 480 protected void testGet_SSL_WithServerErrors() throws Exception { 481 httpServer.setServerErrorsBeforeWorks(1); 482 httpServer.addSslConnector(); 483 newTransporter(httpServer.getHttpsUrl()); 484 for (int i = 1; i < 3; i++) { 485 try { 486 RecordingTransportListener listener = new RecordingTransportListener(); 487 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 488 transporter.get(task); 489 assertEquals("test", task.getDataString()); 490 assertEquals(0L, listener.getDataOffset()); 491 assertEquals(4L, listener.getDataLength()); 492 assertEquals(1, listener.getStartedCount()); 493 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 494 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 495 } catch (HttpTransporterException e) { 496 assertEquals(500, e.getStatusCode()); 497 } 498 } 499 } 500 501 @Test 502 protected void testGet_HTTPS_Unknown_SecurityMode() throws Exception { 503 session.setConfigProperty(ConfigurationProperties.HTTPS_SECURITY_MODE, "unknown"); 504 httpServer.addSelfSignedSslConnector(); 505 try { 506 newTransporter(httpServer.getHttpsUrl()); 507 fail("Unsupported security mode"); 508 } catch (IllegalArgumentException a) { 509 // good 510 } 511 } 512 513 @Test 514 protected void testGet_HTTPS_Insecure_SecurityMode() throws Exception { 515 // here we use alternate server-store-selfigned key (as the key set it static initalizer is probably already 516 // used to init SSLContext/SSLSocketFactory/etc 517 session.setConfigProperty( 518 ConfigurationProperties.HTTPS_SECURITY_MODE, ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE); 519 httpServer.addSelfSignedSslConnector(); 520 newTransporter(httpServer.getHttpsUrl()); 521 RecordingTransportListener listener = new RecordingTransportListener(); 522 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 523 transporter.get(task); 524 assertEquals("test", task.getDataString()); 525 assertEquals(0L, listener.getDataOffset()); 526 assertEquals(4L, listener.getDataLength()); 527 assertEquals(1, listener.getStartedCount()); 528 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 529 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 530 } 531 532 @Test 533 protected void testGet_Redirect() throws Exception { 534 httpServer.addSslConnector(); 535 RecordingTransportListener listener = new RecordingTransportListener(); 536 GetTask task = new GetTask(URI.create("redirect/file.txt?scheme=https")).setListener(listener); 537 transporter.get(task); 538 assertEquals("test", task.getDataString()); 539 assertEquals(0L, listener.getDataOffset()); 540 assertEquals(4L, listener.getDataLength()); 541 assertEquals(1, listener.getStartedCount()); 542 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 543 assertEquals(task.getDataString(), listener.getBaos().toString(StandardCharsets.UTF_8)); 544 } 545 546 @Test 547 protected void testGet_Resume() throws Exception { 548 File file = TestFileUtils.createTempFile("re"); 549 RecordingTransportListener listener = new RecordingTransportListener(); 550 GetTask task = new GetTask(URI.create("repo/resume.txt")) 551 .setDataPath(file.toPath(), true) 552 .setListener(listener); 553 transporter.get(task); 554 assertEquals("resumable", TestFileUtils.readString(file)); 555 assertEquals(1L, listener.getStartedCount()); 556 assertEquals(2L, listener.getDataOffset()); 557 assertEquals(9, listener.getDataLength()); 558 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 559 assertEquals("sumable", listener.getBaos().toString(StandardCharsets.UTF_8)); 560 } 561 562 @Test 563 protected void testGet_ResumeLocalContentsOutdated() throws Exception { 564 File file = TestFileUtils.createTempFile("re"); 565 file.setLastModified(System.currentTimeMillis() - 5 * 60 * 1000); 566 RecordingTransportListener listener = new RecordingTransportListener(); 567 GetTask task = new GetTask(URI.create("repo/resume.txt")) 568 .setDataPath(file.toPath(), true) 569 .setListener(listener); 570 transporter.get(task); 571 assertEquals("resumable", TestFileUtils.readString(file)); 572 assertEquals(1L, listener.getStartedCount()); 573 assertEquals(0L, listener.getDataOffset()); 574 assertEquals(9, listener.getDataLength()); 575 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 576 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8)); 577 } 578 579 @Test 580 protected void testGet_ResumeRangesNotSupportedByServer() throws Exception { 581 httpServer.setRangeSupport(false); 582 File file = TestFileUtils.createTempFile("re"); 583 RecordingTransportListener listener = new RecordingTransportListener(); 584 GetTask task = new GetTask(URI.create("repo/resume.txt")) 585 .setDataPath(file.toPath(), true) 586 .setListener(listener); 587 transporter.get(task); 588 assertEquals("resumable", TestFileUtils.readString(file)); 589 assertEquals(1L, listener.getStartedCount()); 590 assertEquals(0L, listener.getDataOffset()); 591 assertEquals(9, listener.getDataLength()); 592 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 593 assertEquals("resumable", listener.getBaos().toString(StandardCharsets.UTF_8)); 594 } 595 596 @Test 597 protected void testGet_Checksums_Nexus() throws Exception { 598 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.NEXUS); 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_Checksums_XChecksum() throws Exception { 608 httpServer.setChecksumHeader(HttpServer.ChecksumHeader.XCHECKSUM); 609 GetTask task = new GetTask(URI.create("repo/file.txt")); 610 transporter.get(task); 611 assertEquals("test", task.getDataString()); 612 assertEquals( 613 "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get("SHA-1")); 614 } 615 616 @Test 617 protected void testGet_FileHandleLeak() throws Exception { 618 for (int i = 0; i < 100; i++) { 619 File file = TestFileUtils.createTempFile("failure"); 620 transporter.get(new GetTask(URI.create("repo/file.txt")).setDataPath(file.toPath())); 621 assertTrue(file.delete(), i + ", " + file.getAbsolutePath()); 622 } 623 } 624 625 @Test 626 protected void testGet_NotFound() throws Exception { 627 try { 628 transporter.get(new GetTask(URI.create("repo/missing.txt"))); 629 fail("Expected error"); 630 } catch (HttpTransporterException e) { 631 assertEquals(404, e.getStatusCode()); 632 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e)); 633 } 634 } 635 636 @Test 637 protected void testGet_Closed() throws Exception { 638 transporter.close(); 639 try { 640 transporter.get(new GetTask(URI.create("repo/file.txt"))); 641 fail("Expected error"); 642 } catch (IllegalStateException e) { 643 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 644 } 645 } 646 647 @Test 648 protected void testGet_StartCancelled() throws Exception { 649 RecordingTransportListener listener = new RecordingTransportListener(); 650 listener.cancelStart(); 651 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 652 try { 653 transporter.get(task); 654 fail("Expected error"); 655 } catch (TransferCancelledException e) { 656 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 657 } 658 assertEquals(0L, listener.getDataOffset()); 659 assertEquals(4L, listener.getDataLength()); 660 assertEquals(1, listener.getStartedCount()); 661 assertEquals(0, listener.getProgressedCount()); 662 } 663 664 @Test 665 protected void testGet_ProgressCancelled() throws Exception { 666 RecordingTransportListener listener = new RecordingTransportListener(); 667 listener.cancelProgress(); 668 GetTask task = new GetTask(URI.create("repo/file.txt")).setListener(listener); 669 try { 670 transporter.get(task); 671 fail("Expected error"); 672 } catch (TransferCancelledException e) { 673 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 674 } 675 assertEquals(0L, listener.getDataOffset()); 676 assertEquals(4L, listener.getDataLength()); 677 assertEquals(1, listener.getStartedCount()); 678 assertEquals(1, listener.getProgressedCount()); 679 } 680 681 @Test 682 protected void testPut_FromMemory() throws Exception { 683 RecordingTransportListener listener = new RecordingTransportListener(); 684 PutTask task = 685 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 686 transporter.put(task); 687 assertEquals(0L, listener.getDataOffset()); 688 assertEquals(6L, listener.getDataLength()); 689 assertEquals(1, listener.getStartedCount()); 690 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 691 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 692 } 693 694 @Test 695 protected void testPut_FromFile() throws Exception { 696 File file = TestFileUtils.createTempFile("upload"); 697 RecordingTransportListener listener = new RecordingTransportListener(); 698 PutTask task = 699 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataPath(file.toPath()); 700 transporter.put(task); 701 assertEquals(0L, listener.getDataOffset()); 702 assertEquals(6L, listener.getDataLength()); 703 assertEquals(1, listener.getStartedCount()); 704 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 705 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 706 } 707 708 @Test 709 protected void testPut_EmptyResource() throws Exception { 710 RecordingTransportListener listener = new RecordingTransportListener(); 711 PutTask task = new PutTask(URI.create("repo/file.txt")).setListener(listener); 712 transporter.put(task); 713 assertEquals(0L, listener.getDataOffset()); 714 assertEquals(0L, listener.getDataLength()); 715 assertEquals(1, listener.getStartedCount()); 716 assertEquals(0, listener.getProgressedCount()); 717 assertEquals("", TestFileUtils.readString(new File(repoDir, "file.txt"))); 718 } 719 720 @Test 721 protected void testPut_EncodedResourcePath() throws Exception { 722 RecordingTransportListener listener = new RecordingTransportListener(); 723 PutTask task = new PutTask(URI.create("repo/some%20space.txt")) 724 .setListener(listener) 725 .setDataString("OK"); 726 transporter.put(task); 727 assertEquals(0L, listener.getDataOffset()); 728 assertEquals(2L, listener.getDataLength()); 729 assertEquals(1, listener.getStartedCount()); 730 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 731 assertEquals("OK", TestFileUtils.readString(new File(repoDir, "some space.txt"))); 732 } 733 734 @Test 735 protected void testPut_Authenticated_ExpectContinue() throws Exception { 736 httpServer.setAuthentication("testuser", "testpass"); 737 auth = new AuthenticationBuilder() 738 .addUsername("testuser") 739 .addPassword("testpass") 740 .build(); 741 newTransporter(httpServer.getHttpUrl()); 742 RecordingTransportListener listener = new RecordingTransportListener(); 743 PutTask task = 744 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 745 transporter.put(task); 746 assertEquals(0L, listener.getDataOffset()); 747 assertEquals(6L, listener.getDataLength()); 748 assertEquals(1, listener.getStartedCount()); 749 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 750 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 751 } 752 753 @Test 754 protected void testPut_Authenticated_ExpectContinueBroken() throws Exception { 755 // this makes OPTIONS recover, and have only 1 PUT (startedCount=1 as OPTIONS is not counted) 756 session.setConfigProperty(ConfigurationProperties.HTTP_SUPPORT_WEBDAV, true); 757 httpServer.setAuthentication("testuser", "testpass"); 758 httpServer.setExpectSupport(HttpServer.ExpectContinue.BROKEN); 759 auth = new AuthenticationBuilder() 760 .addUsername("testuser") 761 .addPassword("testpass") 762 .build(); 763 newTransporter(httpServer.getHttpUrl()); 764 RecordingTransportListener listener = new RecordingTransportListener(); 765 PutTask task = 766 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 767 transporter.put(task); 768 assertEquals(0L, listener.getDataOffset()); 769 assertEquals(6L, listener.getDataLength()); 770 assertEquals(1, listener.getStartedCount()); 771 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 772 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 773 } 774 775 @Test 776 protected void testPut_Authenticated_ExpectContinueRejected() throws Exception { 777 httpServer.setAuthentication("testuser", "testpass"); 778 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL); 779 auth = new AuthenticationBuilder() 780 .addUsername("testuser") 781 .addPassword("testpass") 782 .build(); 783 newTransporter(httpServer.getHttpUrl()); 784 RecordingTransportListener listener = new RecordingTransportListener(); 785 PutTask task = 786 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 787 transporter.put(task); 788 assertEquals(0L, listener.getDataOffset()); 789 assertEquals(6L, listener.getDataLength()); 790 assertEquals(1, listener.getStartedCount()); 791 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 792 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 793 } 794 795 @Test 796 protected void testPut_Authenticated_ExpectContinueDisabled() throws Exception { 797 session.setConfigProperty(ConfigurationProperties.HTTP_EXPECT_CONTINUE, false); 798 httpServer.setAuthentication("testuser", "testpass"); 799 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL); // if transport tries Expect/Continue explode 800 auth = new AuthenticationBuilder() 801 .addUsername("testuser") 802 .addPassword("testpass") 803 .build(); 804 newTransporter(httpServer.getHttpUrl()); 805 RecordingTransportListener listener = new RecordingTransportListener(); 806 PutTask task = 807 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 808 transporter.put(task); 809 assertEquals(0L, listener.getDataOffset()); 810 assertEquals(6L, listener.getDataLength()); 811 assertEquals(1, listener.getStartedCount()); // w/ expectContinue enabled would have here 2 812 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 813 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 814 } 815 816 @Test 817 protected void testPut_Authenticated_ExpectContinueRejected_ExplicitlyConfiguredHeader() throws Exception { 818 Map<String, String> headers = new HashMap<>(); 819 headers.put("Expect", "100-continue"); 820 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers); 821 httpServer.setAuthentication("testuser", "testpass"); 822 httpServer.setExpectSupport(HttpServer.ExpectContinue.FAIL); 823 auth = new AuthenticationBuilder() 824 .addUsername("testuser") 825 .addPassword("testpass") 826 .build(); 827 newTransporter(httpServer.getHttpUrl()); 828 RecordingTransportListener listener = new RecordingTransportListener(); 829 PutTask task = 830 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 831 transporter.put(task); 832 assertEquals(0L, listener.getDataOffset()); 833 assertEquals(6L, listener.getDataLength()); 834 assertEquals(1, listener.getStartedCount()); 835 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 836 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 837 } 838 839 @Test 840 protected void testPut_Unauthenticated() throws Exception { 841 httpServer.setAuthentication("testuser", "testpass"); 842 RecordingTransportListener listener = new RecordingTransportListener(); 843 PutTask task = 844 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 845 try { 846 transporter.put(task); 847 fail("Expected error"); 848 } catch (HttpTransporterException e) { 849 assertEquals(401, e.getStatusCode()); 850 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 851 } 852 assertEquals(0, listener.getStartedCount()); 853 assertEquals(0, listener.getProgressedCount()); 854 } 855 856 @Test 857 protected void testPut_ProxyAuthenticated() throws Exception { 858 httpServer.setProxyAuthentication("testuser", "testpass"); 859 Authentication auth = new AuthenticationBuilder() 860 .addUsername("testuser") 861 .addPassword("testpass") 862 .build(); 863 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 864 newTransporter("http://bad.localhost:1/"); 865 RecordingTransportListener listener = new RecordingTransportListener(); 866 PutTask task = 867 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 868 transporter.put(task); 869 assertEquals(0L, listener.getDataOffset()); 870 assertEquals(6L, listener.getDataLength()); 871 assertEquals(1, listener.getStartedCount()); 872 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 873 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 874 } 875 876 @Test 877 protected void testPut_ProxyUnauthenticated() throws Exception { 878 httpServer.setProxyAuthentication("testuser", "testpass"); 879 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 880 newTransporter("http://bad.localhost:1/"); 881 RecordingTransportListener listener = new RecordingTransportListener(); 882 PutTask task = 883 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 884 try { 885 transporter.put(task); 886 fail("Expected error"); 887 } catch (HttpTransporterException e) { 888 assertEquals(407, e.getStatusCode()); 889 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 890 } 891 assertEquals(0, listener.getStartedCount()); 892 assertEquals(0, listener.getProgressedCount()); 893 } 894 895 @Test 896 protected void testPut_SSL() throws Exception { 897 httpServer.addSslConnector(); 898 httpServer.setAuthentication("testuser", "testpass"); 899 auth = new AuthenticationBuilder() 900 .addUsername("testuser") 901 .addPassword("testpass") 902 .build(); 903 newTransporter(httpServer.getHttpsUrl()); 904 RecordingTransportListener listener = new RecordingTransportListener(); 905 PutTask task = 906 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 907 transporter.put(task); 908 assertEquals(0L, listener.getDataOffset()); 909 assertEquals(6L, listener.getDataLength()); 910 assertEquals(1, listener.getStartedCount()); 911 assertTrue(listener.getProgressedCount() > 0, "Count: " + listener.getProgressedCount()); 912 assertEquals("upload", TestFileUtils.readString(new File(repoDir, "file.txt"))); 913 } 914 915 @Test 916 protected void testPut_FileHandleLeak() throws Exception { 917 for (int i = 0; i < 100; i++) { 918 File src = TestFileUtils.createTempFile("upload"); 919 File dst = new File(repoDir, "file.txt"); 920 transporter.put(new PutTask(URI.create("repo/file.txt")).setDataPath(src.toPath())); 921 assertTrue(src.delete(), i + ", " + src.getAbsolutePath()); 922 assertTrue(dst.delete(), i + ", " + dst.getAbsolutePath()); 923 } 924 } 925 926 @Test 927 protected void testPut_Closed() throws Exception { 928 transporter.close(); 929 try { 930 transporter.put(new PutTask(URI.create("repo/missing.txt"))); 931 fail("Expected error"); 932 } catch (IllegalStateException e) { 933 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 934 } 935 } 936 937 @Test 938 protected void testPut_StartCancelled() throws Exception { 939 RecordingTransportListener listener = new RecordingTransportListener(); 940 listener.cancelStart(); 941 PutTask task = 942 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 943 try { 944 transporter.put(task); 945 fail("Expected error"); 946 } catch (TransferCancelledException e) { 947 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 948 } 949 assertEquals(0L, listener.getDataOffset()); 950 assertEquals(6L, listener.getDataLength()); 951 assertEquals(1, listener.getStartedCount()); 952 assertEquals(0, listener.getProgressedCount()); 953 } 954 955 @Test 956 protected void testPut_ProgressCancelled() throws Exception { 957 RecordingTransportListener listener = new RecordingTransportListener(); 958 listener.cancelProgress(); 959 PutTask task = 960 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 961 try { 962 transporter.put(task); 963 fail("Expected error"); 964 } catch (TransferCancelledException e) { 965 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 966 } 967 assertEquals(0L, listener.getDataOffset()); 968 assertEquals(6L, listener.getDataLength()); 969 assertEquals(1, listener.getStartedCount()); 970 assertEquals(1, listener.getProgressedCount()); 971 } 972 973 @Test 974 protected void testGetPut_AuthCache() throws Exception { 975 httpServer.setAuthentication("testuser", "testpass"); 976 auth = new AuthenticationBuilder() 977 .addUsername("testuser") 978 .addPassword("testpass") 979 .build(); 980 newTransporter(httpServer.getHttpUrl()); 981 GetTask get = new GetTask(URI.create("repo/file.txt")); 982 transporter.get(get); 983 RecordingTransportListener listener = new RecordingTransportListener(); 984 PutTask task = 985 new PutTask(URI.create("repo/file.txt")).setListener(listener).setDataString("upload"); 986 transporter.put(task); 987 assertEquals(1, listener.getStartedCount()); 988 } 989 990 @Test 991 protected void testPut_PreemptiveIsDefault() throws Exception { 992 httpServer.setAuthentication("testuser", "testpass"); 993 auth = new AuthenticationBuilder() 994 .addUsername("testuser") 995 .addPassword("testpass") 996 .build(); 997 newTransporter(httpServer.getHttpUrl()); 998 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 999 transporter.put(task); 1000 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1001 } 1002 1003 @Test 1004 protected void testPut_AuthCache() throws Exception { 1005 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH, false); 1006 httpServer.setAuthentication("testuser", "testpass"); 1007 auth = new AuthenticationBuilder() 1008 .addUsername("testuser") 1009 .addPassword("testpass") 1010 .build(); 1011 newTransporter(httpServer.getHttpUrl()); 1012 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1013 transporter.put(task); 1014 assertEquals(2, httpServer.getLogEntries().size()); // put (challenged) + put w/ auth 1015 httpServer.getLogEntries().clear(); 1016 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1017 transporter.put(task); 1018 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1019 } 1020 1021 @Test 1022 protected void testPut_AuthCache_Preemptive() throws Exception { 1023 httpServer.setAuthentication("testuser", "testpass"); 1024 auth = new AuthenticationBuilder() 1025 .addUsername("testuser") 1026 .addPassword("testpass") 1027 .build(); 1028 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true); 1029 newTransporter(httpServer.getHttpUrl()); 1030 PutTask task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1031 transporter.put(task); 1032 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1033 httpServer.getLogEntries().clear(); 1034 task = new PutTask(URI.create("repo/file.txt")).setDataString("upload"); 1035 transporter.put(task); 1036 assertEquals(1, httpServer.getLogEntries().size()); // put w/ auth 1037 } 1038 1039 @Test 1040 @Timeout(20) 1041 protected void testConcurrency() throws Exception { 1042 httpServer.setAuthentication("testuser", "testpass"); 1043 auth = new AuthenticationBuilder() 1044 .addUsername("testuser") 1045 .addPassword("testpass") 1046 .build(); 1047 newTransporter(httpServer.getHttpUrl()); 1048 final AtomicReference<Throwable> error = new AtomicReference<>(); 1049 Thread[] threads = new Thread[20]; 1050 for (int i = 0; i < threads.length; i++) { 1051 final String path = "repo/file.txt?i=" + i; 1052 threads[i] = new Thread(() -> { 1053 try { 1054 for (int j = 0; j < 100; j++) { 1055 GetTask task = new GetTask(URI.create(path)); 1056 transporter.get(task); 1057 assertEquals("test", task.getDataString()); 1058 } 1059 } catch (Throwable t) { 1060 error.compareAndSet(null, t); 1061 System.err.println(path); 1062 t.printStackTrace(); 1063 } 1064 }); 1065 threads[i].setName("Task-" + i); 1066 } 1067 for (Thread thread : threads) { 1068 thread.start(); 1069 } 1070 for (Thread thread : threads) { 1071 thread.join(); 1072 } 1073 assertNull(error.get(), String.valueOf(error.get())); 1074 } 1075 1076 @Test 1077 @Timeout(10) 1078 protected void testConnectTimeout() throws Exception { 1079 session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, 100); 1080 int port = 1; 1081 newTransporter("http://localhost:" + port); 1082 try { 1083 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1084 fail("Expected error"); 1085 } catch (Exception e) { 1086 // impl specific "timeout" exception 1087 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 1088 } 1089 } 1090 1091 @Test 1092 @Timeout(10) 1093 protected void testRequestTimeout() throws Exception { 1094 session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, 100); 1095 ServerSocket server = new ServerSocket(0); 1096 try (server) { 1097 newTransporter("http://localhost:" + server.getLocalPort()); 1098 try { 1099 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1100 fail("Expected error"); 1101 } catch (Exception e) { 1102 assertTrue(e.getClass().getSimpleName().contains("Timeout")); 1103 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e)); 1104 } 1105 } 1106 } 1107 1108 @Test 1109 protected void testUserAgent() throws Exception { 1110 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0"); 1111 newTransporter(httpServer.getHttpUrl()); 1112 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1113 assertEquals(1, httpServer.getLogEntries().size()); 1114 for (HttpServer.LogEntry log : httpServer.getLogEntries()) { 1115 assertEquals("SomeTest/1.0", log.getHeaders().get("User-Agent")); 1116 } 1117 } 1118 1119 @Test 1120 protected void testCustomHeaders() throws Exception { 1121 Map<String, String> headers = new HashMap<>(); 1122 headers.put("User-Agent", "Custom/1.0"); 1123 headers.put("X-CustomHeader", "Custom-Value"); 1124 session.setConfigProperty(ConfigurationProperties.USER_AGENT, "SomeTest/1.0"); 1125 session.setConfigProperty(ConfigurationProperties.HTTP_HEADERS + ".test", headers); 1126 newTransporter(httpServer.getHttpUrl()); 1127 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1128 assertEquals(1, httpServer.getLogEntries().size()); 1129 for (HttpServer.LogEntry log : httpServer.getLogEntries()) { 1130 for (Map.Entry<String, String> entry : headers.entrySet()) { 1131 assertEquals(entry.getValue(), log.getHeaders().get(entry.getKey()), entry.getKey()); 1132 } 1133 } 1134 } 1135 1136 @Test 1137 protected void testServerAuthScope_NotUsedForProxy() throws Exception { 1138 String username = "testuser", password = "testpass"; 1139 httpServer.setProxyAuthentication(username, password); 1140 auth = new AuthenticationBuilder() 1141 .addUsername(username) 1142 .addPassword(password) 1143 .build(); 1144 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort()); 1145 newTransporter("http://" + httpServer.getHost() + ":12/"); 1146 try { 1147 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1148 fail("Server auth must not be used as proxy auth"); 1149 } catch (HttpTransporterException e) { 1150 assertEquals(407, e.getStatusCode()); 1151 } catch (IOException e) { 1152 // accepted as well: point is to fail 1153 } 1154 } 1155 1156 @Test 1157 protected void testProxyAuthScope_NotUsedForServer() throws Exception { 1158 String username = "testuser", password = "testpass"; 1159 httpServer.setAuthentication(username, password); 1160 Authentication auth = new AuthenticationBuilder() 1161 .addUsername(username) 1162 .addPassword(password) 1163 .build(); 1164 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 1165 newTransporter("http://" + httpServer.getHost() + ":12/"); 1166 try { 1167 transporter.get(new GetTask(URI.create("repo/file.txt"))); 1168 fail("Proxy auth must not be used as server auth"); 1169 } catch (HttpTransporterException e) { 1170 assertEquals(401, e.getStatusCode()); 1171 } catch (IOException e) { 1172 // accepted as well: point is to fail 1173 } 1174 } 1175 1176 @Test 1177 protected void testAuthSchemeReuse() throws Exception { 1178 httpServer.setAuthentication("testuser", "testpass"); 1179 httpServer.setProxyAuthentication("proxyuser", "proxypass"); 1180 session.setCache(new DefaultRepositoryCache()); 1181 auth = new AuthenticationBuilder() 1182 .addUsername("testuser") 1183 .addPassword("testpass") 1184 .build(); 1185 Authentication auth = new AuthenticationBuilder() 1186 .addUsername("proxyuser") 1187 .addPassword("proxypass") 1188 .build(); 1189 proxy = new Proxy(Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth); 1190 newTransporter("http://bad.localhost:1/"); 1191 GetTask task = new GetTask(URI.create("repo/file.txt")); 1192 transporter.get(task); 1193 assertEquals("test", task.getDataString()); 1194 assertEquals(3, httpServer.getLogEntries().size()); 1195 httpServer.getLogEntries().clear(); 1196 newTransporter("http://bad.localhost:1/"); 1197 task = new GetTask(URI.create("repo/file.txt")); 1198 transporter.get(task); 1199 assertEquals("test", task.getDataString()); 1200 assertEquals(1, httpServer.getLogEntries().size()); 1201 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Authorization")); 1202 assertNotNull(httpServer.getLogEntries().get(0).getHeaders().get("Proxy-Authorization")); 1203 } 1204 1205 @Test 1206 protected void testAuthSchemePreemptive() throws Exception { 1207 httpServer.setAuthentication("testuser", "testpass"); 1208 session.setCache(new DefaultRepositoryCache()); 1209 auth = new AuthenticationBuilder() 1210 .addUsername("testuser") 1211 .addPassword("testpass") 1212 .build(); 1213 1214 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, false); 1215 newTransporter(httpServer.getHttpUrl()); 1216 GetTask task = new GetTask(URI.create("repo/file.txt")); 1217 transporter.get(task); 1218 assertEquals("test", task.getDataString()); 1219 // there ARE challenge round-trips 1220 assertEquals(2, httpServer.getLogEntries().size()); 1221 1222 httpServer.getLogEntries().clear(); 1223 1224 session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_AUTH, true); 1225 newTransporter(httpServer.getHttpUrl()); 1226 task = new GetTask(URI.create("repo/file.txt")); 1227 transporter.get(task); 1228 assertEquals("test", task.getDataString()); 1229 // there are NO challenge round-trips, all goes through at first 1230 assertEquals(1, httpServer.getLogEntries().size()); 1231 } 1232 1233 @Test 1234 void testInit_BadProtocol() { 1235 assertThrows(NoTransporterException.class, () -> newTransporter("bad:/void")); 1236 } 1237 1238 @Test 1239 void testInit_BadUrl() { 1240 assertThrows(NoTransporterException.class, () -> newTransporter("http://localhost:NaN")); 1241 } 1242 1243 @Test 1244 void testInit_CaseInsensitiveProtocol() throws Exception { 1245 newTransporter("http://localhost"); 1246 newTransporter("HTTP://localhost"); 1247 newTransporter("Http://localhost"); 1248 newTransporter("https://localhost"); 1249 newTransporter("HTTPS://localhost"); 1250 newTransporter("HttpS://localhost"); 1251 } 1252}