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