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