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