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