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