1 package org.apache.maven.wagon.shared.http4;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.ByteArrayInputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.net.URLEncoder;
29 import java.nio.ByteBuffer;
30 import java.security.cert.X509Certificate;
31 import java.text.SimpleDateFormat;
32 import java.util.Date;
33 import java.util.Locale;
34 import java.util.Map;
35 import java.util.Properties;
36 import java.util.TimeZone;
37 import java.util.zip.GZIPInputStream;
38
39 import javax.net.ssl.HttpsURLConnection;
40 import javax.net.ssl.SSLException;
41 import javax.net.ssl.SSLSession;
42 import javax.net.ssl.SSLSocket;
43
44 import org.apache.http.Header;
45 import org.apache.http.HttpEntity;
46 import org.apache.http.HttpException;
47 import org.apache.http.HttpHost;
48 import org.apache.http.HttpResponse;
49 import org.apache.http.HttpStatus;
50 import org.apache.http.auth.AuthScope;
51 import org.apache.http.auth.Credentials;
52 import org.apache.http.auth.NTCredentials;
53 import org.apache.http.auth.UsernamePasswordCredentials;
54 import org.apache.http.client.AuthCache;
55 import org.apache.http.client.methods.HttpGet;
56 import org.apache.http.client.methods.HttpHead;
57 import org.apache.http.client.methods.HttpPut;
58 import org.apache.http.client.methods.HttpUriRequest;
59 import org.apache.http.client.params.ClientPNames;
60 import org.apache.http.client.params.CookiePolicy;
61 import org.apache.http.client.protocol.ClientContext;
62 import org.apache.http.conn.ClientConnectionManager;
63 import org.apache.http.conn.params.ConnRoutePNames;
64 import org.apache.http.conn.scheme.PlainSocketFactory;
65 import org.apache.http.conn.scheme.Scheme;
66 import org.apache.http.conn.scheme.SchemeRegistry;
67 import org.apache.http.conn.ssl.SSLSocketFactory;
68 import org.apache.http.conn.ssl.X509HostnameVerifier;
69 import org.apache.http.entity.AbstractHttpEntity;
70 import org.apache.http.impl.auth.BasicScheme;
71 import org.apache.http.impl.client.BasicAuthCache;
72 import org.apache.http.impl.client.DefaultHttpClient;
73 import org.apache.http.impl.conn.BasicClientConnectionManager;
74 import org.apache.http.impl.conn.PoolingClientConnectionManager;
75 import org.apache.http.impl.cookie.DateParseException;
76 import org.apache.http.impl.cookie.DateUtils;
77 import org.apache.http.message.BasicHeader;
78 import org.apache.http.params.CoreConnectionPNames;
79 import org.apache.http.params.CoreProtocolPNames;
80 import org.apache.http.params.HttpParams;
81 import org.apache.http.protocol.BasicHttpContext;
82 import org.apache.maven.wagon.InputData;
83 import org.apache.maven.wagon.OutputData;
84 import org.apache.maven.wagon.PathUtils;
85 import org.apache.maven.wagon.ResourceDoesNotExistException;
86 import org.apache.maven.wagon.StreamWagon;
87 import org.apache.maven.wagon.TransferFailedException;
88 import org.apache.maven.wagon.Wagon;
89 import org.apache.maven.wagon.authorization.AuthorizationException;
90 import org.apache.maven.wagon.events.TransferEvent;
91 import org.apache.maven.wagon.proxy.ProxyInfo;
92 import org.apache.maven.wagon.repository.Repository;
93 import org.apache.maven.wagon.resource.Resource;
94 import org.codehaus.plexus.util.IOUtil;
95 import org.codehaus.plexus.util.StringUtils;
96
97
98
99
100
101 public abstract class AbstractHttpClientWagon
102 extends StreamWagon
103 {
104
105 private BasicHttpContext localContext;
106
107 private final class RequestEntityImplementation
108 extends AbstractHttpEntity
109 {
110
111 private final static int BUFFER_SIZE = 2048;
112
113 private final Resource resource;
114
115 private final Wagon wagon;
116
117 private ByteBuffer byteBuffer;
118
119 private File source;
120
121 private long length = -1;
122
123 private RequestEntityImplementation( final InputStream stream, final Resource resource, final Wagon wagon,
124 final File source )
125 throws TransferFailedException
126 {
127 if ( source != null )
128 {
129 this.source = source;
130 }
131 else
132 {
133 try
134 {
135 byte[] bytes = IOUtil.toByteArray( stream );
136 byteBuffer = ByteBuffer.allocate( bytes.length );
137 byteBuffer.put( bytes );
138 }
139 catch ( IOException e )
140 {
141 throw new TransferFailedException( e.getMessage(), e );
142 }
143 }
144 this.resource = resource;
145 this.length = resource == null ? -1 : resource.getContentLength();
146
147 this.wagon = wagon;
148 }
149
150 public long getContentLength()
151 {
152 return length;
153 }
154
155 public InputStream getContent()
156 throws IOException, IllegalStateException
157 {
158 if ( this.source != null )
159 {
160 return new FileInputStream( this.source );
161 }
162 return new ByteArrayInputStream( this.byteBuffer.array() );
163 }
164
165 public boolean isRepeatable()
166 {
167 return true;
168 }
169
170 public void writeTo( final OutputStream outstream )
171 throws IOException
172 {
173 if ( outstream == null )
174 {
175 throw new IllegalArgumentException( "Output stream may not be null" );
176 }
177 TransferEvent transferEvent =
178 new TransferEvent( wagon, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_PUT );
179 transferEvent.setTimestamp( System.currentTimeMillis() );
180 InputStream instream = ( this.source != null )
181 ? new FileInputStream( this.source )
182 : new ByteArrayInputStream( this.byteBuffer.array() );
183 try
184 {
185 byte[] buffer = new byte[BUFFER_SIZE];
186 int l;
187 if ( this.length < 0 )
188 {
189
190 while ( ( l = instream.read( buffer ) ) != -1 )
191 {
192 fireTransferProgress( transferEvent, buffer, -1 );
193 outstream.write( buffer, 0, l );
194 }
195 }
196 else
197 {
198
199 long remaining = this.length;
200 while ( remaining > 0 )
201 {
202 l = instream.read( buffer, 0, (int) Math.min( BUFFER_SIZE, remaining ) );
203 if ( l == -1 )
204 {
205 break;
206 }
207 fireTransferProgress( transferEvent, buffer, (int) Math.min( BUFFER_SIZE, remaining ) );
208 outstream.write( buffer, 0, l );
209 remaining -= l;
210 }
211 }
212 }
213 finally
214 {
215 instream.close();
216 }
217 }
218
219 public boolean isStreaming()
220 {
221 return true;
222 }
223 }
224
225 protected static final int SC_NULL = -1;
226
227 protected static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone( "GMT" );
228
229 private DefaultHttpClient client;
230
231
232
233
234 protected static ClientConnectionManager connectionManagerPooled;
235
236
237
238
239 protected ClientConnectionManager clientConnectionManager =
240 new BasicClientConnectionManager( createSchemeRegistry() );
241
242
243
244
245
246
247
248 protected static boolean useClientManagerPooled =
249 Boolean.valueOf( System.getProperty( "maven.wagon.http.pool", "true" ) );
250
251
252
253
254
255
256
257 protected static boolean sslInsecure = Boolean.valueOf( System.getProperty( "maven.wagon.http.ssl.insecure", "false" ) );
258
259
260
261
262
263
264
265 protected static boolean IGNORE_SSL_VALIDITY_DATES =
266 Boolean.valueOf( System.getProperty( "maven.wagon.http.ssl.ignore.validity.dates", "false" ) );
267
268
269
270
271
272
273
274
275 protected static boolean sslAllowAll =
276 Boolean.valueOf( System.getProperty( "maven.wagon.http.ssl.allowall", "false" ) );
277
278 private static SchemeRegistry createSchemeRegistry()
279 {
280 SchemeRegistry schemeRegistry = new SchemeRegistry();
281 schemeRegistry.register( new Scheme( "http", 80, PlainSocketFactory.getSocketFactory() ) );
282 SSLSocketFactory sslSocketFactory;
283 if ( sslInsecure )
284 {
285 try
286 {
287 sslSocketFactory = new SSLSocketFactory(
288 RelaxedX509TrustManager.createRelaxedSSLContext(),
289 sslAllowAll ? new RelaxedHostNameVerifier() : SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER );
290 }
291 catch ( IOException e )
292 {
293 throw new RuntimeException( "failed to init SSLSocket Factory " + e.getMessage(), e );
294 }
295 }
296 else
297 {
298 sslSocketFactory = new SSLSocketFactory(
299 HttpsURLConnection.getDefaultSSLSocketFactory(),
300 SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER );
301 }
302
303 Scheme httpsScheme = new Scheme( "https", 443, new ConfigurableSSLSocketFactoryDecorator( sslSocketFactory ) );
304 schemeRegistry.register( httpsScheme );
305
306 return schemeRegistry;
307 }
308
309 static
310 {
311 if ( !useClientManagerPooled )
312 {
313 System.out.println( "http connection pool disabled in wagon http" );
314 }
315 else
316 {
317 PoolingClientConnectionManager poolingClientConnectionManager =
318 new PoolingClientConnectionManager( createSchemeRegistry() );
319 int maxPerRoute =
320 Integer.parseInt( System.getProperty( "maven.wagon.httpconnectionManager.maxPerRoute", "20" ) );
321 poolingClientConnectionManager.setDefaultMaxPerRoute( maxPerRoute );
322 int maxTotal = Integer.parseInt( System.getProperty( "maven.wagon.httpconnectionManager.maxTotal", "40" ) );
323 poolingClientConnectionManager.setDefaultMaxPerRoute( maxPerRoute );
324 poolingClientConnectionManager.setMaxTotal( maxTotal );
325
326 connectionManagerPooled = poolingClientConnectionManager;
327 }
328 }
329
330
331
332
333
334
335 private static class RelaxedHostNameVerifier
336 implements X509HostnameVerifier
337 {
338 public void verify( String s, SSLSocket sslSocket )
339 throws IOException
340 {
341
342 }
343
344 public void verify( String s, X509Certificate x509Certificate )
345 throws SSLException
346 {
347
348 }
349
350 public void verify( String s, String[] strings, String[] strings1 )
351 throws SSLException
352 {
353
354 }
355
356 public boolean verify( String s, SSLSession sslSession )
357 {
358 return true;
359 }
360 }
361
362 public ClientConnectionManager getConnectionManager()
363 {
364 if ( !useClientManagerPooled )
365 {
366 return clientConnectionManager;
367 }
368 return connectionManagerPooled;
369 }
370
371 public static void setConnectionManagerPooled( ClientConnectionManager clientConnectionManager )
372 {
373 connectionManagerPooled = clientConnectionManager;
374 }
375
376 public static void setUseClientManagerPooled( boolean pooledClientManager )
377 {
378 useClientManagerPooled = pooledClientManager;
379 }
380
381
382
383
384
385 private Properties httpHeaders;
386
387
388
389
390 private HttpConfiguration httpConfiguration;
391
392 private HttpGet getMethod;
393
394 public void openConnectionInternal()
395 {
396 repository.setUrl( getURL( repository ) );
397 client = new DefaultHttpClient( getConnectionManager() );
398
399
400 client.getParams().setParameter( ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY );
401
402 if ( authenticationInfo != null )
403 {
404
405 String username = authenticationInfo.getUserName();
406 String password = authenticationInfo.getPassword();
407
408 if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) )
409 {
410 Credentials creds = new UsernamePasswordCredentials( username, password );
411
412 String host = getRepository().getHost();
413 int port = getRepository().getPort() > -1 ? getRepository().getPort() : AuthScope.ANY_PORT;
414
415 client.getCredentialsProvider().setCredentials( new AuthScope( host, port ), creds );
416
417
418
419
420
421
422
423
424
425
426
427 }
428 }
429
430 ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() );
431 if ( proxyInfo != null )
432 {
433 String proxyUsername = proxyInfo.getUserName();
434 String proxyPassword = proxyInfo.getPassword();
435 String proxyHost = proxyInfo.getHost();
436 int proxyPort = proxyInfo.getPort();
437 String proxyNtlmHost = proxyInfo.getNtlmHost();
438 String proxyNtlmDomain = proxyInfo.getNtlmDomain();
439 if ( proxyHost != null )
440 {
441 HttpHost proxy = new HttpHost( proxyHost, proxyPort );
442
443 if ( proxyUsername != null && proxyPassword != null )
444 {
445 Credentials creds;
446 if ( proxyNtlmHost != null || proxyNtlmDomain != null )
447 {
448 creds = new NTCredentials( proxyUsername, proxyPassword, proxyNtlmHost, proxyNtlmDomain );
449 }
450 else
451 {
452 creds = new UsernamePasswordCredentials( proxyUsername, proxyPassword );
453 }
454
455 int port = proxyInfo.getPort() > -1 ? proxyInfo.getPort() : AuthScope.ANY_PORT;
456
457 AuthScope authScope = new AuthScope( proxyHost, port );
458 client.getCredentialsProvider().setCredentials( authScope, creds );
459 }
460
461 client.getParams().setParameter( ConnRoutePNames.DEFAULT_PROXY, proxy );
462 }
463 }
464 }
465
466 public void closeConnection()
467 {
468 if ( !useClientManagerPooled )
469 {
470 getConnectionManager().shutdown();
471 }
472 }
473
474 public void put( File source, String resourceName )
475 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
476 {
477 Resource resource = new Resource( resourceName );
478
479 firePutInitiated( resource, source );
480
481 resource.setContentLength( source.length() );
482
483 resource.setLastModified( source.lastModified() );
484
485 put( null, resource, source );
486 }
487
488 public void putFromStream( final InputStream stream, String destination, long contentLength, long lastModified )
489 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
490 {
491 Resource resource = new Resource( destination );
492
493 firePutInitiated( resource, null );
494
495 resource.setContentLength( contentLength );
496
497 resource.setLastModified( lastModified );
498
499 put( stream, resource, null );
500 }
501
502 private void put( final InputStream stream, Resource resource, File source )
503 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
504 {
505 put( resource, source, new RequestEntityImplementation( stream, resource, this, source ) );
506 }
507
508 private void put( Resource resource, File source, HttpEntity httpEntity )
509 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
510 {
511
512 StringBuilder url = new StringBuilder( getURL( getRepository() ) );
513 String[] parts = StringUtils.split( resource.getName(), "/" );
514 for ( String part : parts )
515 {
516
517
518 if ( !url.toString().endsWith( "/" ) )
519 {
520 url.append( '/' );
521 }
522 url.append( URLEncoder.encode( part ) );
523 }
524 put( resource, source, httpEntity, url.toString() );
525 }
526
527 private void put( Resource resource, File source, HttpEntity httpEntity, String url )
528 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
529 {
530
531
532 try
533 {
534 mkdirs( PathUtils.dirname( resource.getName() ) );
535 }
536 catch ( HttpException he )
537 {
538 fireTransferError( resource, he, TransferEvent.REQUEST_GET );
539 }
540 catch ( IOException e )
541 {
542 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
543 }
544
545 if ( authenticationInfo != null )
546 {
547 String username = authenticationInfo.getUserName();
548 String password = authenticationInfo.getPassword();
549
550 if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) )
551 {
552 AuthCache authCache = new BasicAuthCache();
553 BasicScheme basicAuth = new BasicScheme();
554 HttpHost targetHost =
555 new HttpHost( repository.getHost(), repository.getPort(), repository.getProtocol() );
556 authCache.put( targetHost, basicAuth );
557
558 localContext = new BasicHttpContext();
559 localContext.setAttribute( ClientContext.AUTH_CACHE, authCache );
560 }
561 }
562
563 HttpPut putMethod = new HttpPut( url );
564
565 firePutStarted( resource, source );
566
567 try
568 {
569 putMethod.setEntity( httpEntity );
570
571 HttpResponse response;
572 try
573 {
574 response = execute( putMethod );
575 }
576 catch ( IOException e )
577 {
578 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
579
580 throw new TransferFailedException( e.getMessage(), e );
581 }
582 catch ( HttpException e )
583 {
584 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
585
586 throw new TransferFailedException( e.getMessage(), e );
587 }
588
589 int statusCode = response.getStatusLine().getStatusCode();
590 String reasonPhrase = ", ReasonPhrase: " + response.getStatusLine().getReasonPhrase() + ".";
591 fireTransferDebug( url + " - Status code: " + statusCode + reasonPhrase );
592
593
594 switch ( statusCode )
595 {
596
597 case HttpStatus.SC_OK:
598 case HttpStatus.SC_CREATED:
599 case HttpStatus.SC_ACCEPTED:
600 case HttpStatus.SC_NO_CONTENT:
601 break;
602
603 case HttpStatus.SC_MOVED_PERMANENTLY:
604 case HttpStatus.SC_MOVED_TEMPORARILY:
605 case HttpStatus.SC_SEE_OTHER:
606 put( resource, source, httpEntity, calculateRelocatedUrl( response ) );
607 return;
608 case SC_NULL:
609 {
610 TransferFailedException e =
611 new TransferFailedException( "Failed to transfer file: " + url + reasonPhrase );
612 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
613 throw e;
614 }
615
616 case HttpStatus.SC_FORBIDDEN:
617 fireSessionConnectionRefused();
618 throw new AuthorizationException( "Access denied to: " + url + reasonPhrase );
619
620 case HttpStatus.SC_NOT_FOUND:
621 throw new ResourceDoesNotExistException( "File: " + url + " does not exist" + reasonPhrase );
622
623
624 default:
625 {
626 TransferFailedException e = new TransferFailedException(
627 "Failed to transfer file: " + url + ". Return code is: " + statusCode + reasonPhrase );
628 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
629 throw e;
630 }
631 }
632
633 firePutCompleted( resource, source );
634 }
635 finally
636 {
637 putMethod.abort();
638 }
639 }
640
641 protected String calculateRelocatedUrl( HttpResponse response )
642 {
643 Header locationHeader = response.getFirstHeader( "Location" );
644 String locationField = locationHeader.getValue();
645
646 return locationField.startsWith( "http" ) ? locationField : getURL( getRepository() ) + '/' + locationField;
647 }
648
649 protected void mkdirs( String dirname )
650 throws HttpException, IOException
651 {
652
653 }
654
655 public boolean resourceExists( String resourceName )
656 throws TransferFailedException, AuthorizationException
657 {
658 String repositoryUrl = getRepository().getUrl();
659 String url = repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + resourceName;
660 HttpHead headMethod = new HttpHead( url );
661 HttpResponse response = null;
662 int statusCode;
663 try
664 {
665 response = execute( headMethod );
666 }
667 catch ( IOException e )
668 {
669 throw new TransferFailedException( e.getMessage(), e );
670 }
671 catch ( HttpException e )
672 {
673 throw new TransferFailedException( e.getMessage(), e );
674 }
675
676 try
677 {
678 statusCode = response.getStatusLine().getStatusCode();
679 String reasonPhrase = ", ReasonPhrase: " + response.getStatusLine().getReasonPhrase() + ".";
680 switch ( statusCode )
681 {
682 case HttpStatus.SC_OK:
683 return true;
684
685 case HttpStatus.SC_NOT_MODIFIED:
686 return true;
687
688 case SC_NULL:
689 throw new TransferFailedException( "Failed to transfer file: " + url + reasonPhrase );
690
691 case HttpStatus.SC_FORBIDDEN:
692 throw new AuthorizationException( "Access denied to: " + url + reasonPhrase );
693
694 case HttpStatus.SC_UNAUTHORIZED:
695 throw new AuthorizationException( "Not authorized " + reasonPhrase );
696
697 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
698 throw new AuthorizationException( "Not authorized by proxy " + reasonPhrase );
699
700 case HttpStatus.SC_NOT_FOUND:
701 return false;
702
703
704 default:
705 throw new TransferFailedException(
706 "Failed to transfer file: " + url + ". Return code is: " + statusCode + reasonPhrase );
707 }
708 }
709 finally
710 {
711 headMethod.abort();
712 }
713 }
714
715 protected HttpResponse execute( HttpUriRequest httpMethod )
716 throws HttpException, IOException
717 {
718 setParameters( httpMethod );
719 setHeaders( httpMethod );
720 client.getParams().setParameter( CoreProtocolPNames.USER_AGENT, getUserAgent( httpMethod ) );
721
722 ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() );
723
724 if ( proxyInfo != null )
725 {
726 if ( proxyInfo.getUserName() != null && proxyInfo.getPassword() != null )
727 {
728 Credentials creds;
729 if ( proxyInfo.getNtlmHost() != null || proxyInfo.getNtlmDomain() != null )
730 {
731 creds =
732 new NTCredentials( proxyInfo.getUserName(), proxyInfo.getPassword(), proxyInfo.getNtlmHost(),
733 proxyInfo.getNtlmDomain() );
734 }
735 else
736 {
737 creds = new UsernamePasswordCredentials( proxyInfo.getUserName(), proxyInfo.getPassword() );
738 }
739
740 Header bs = new BasicScheme().authenticate( creds, httpMethod );
741 httpMethod.addHeader( "Proxy-Authorization", bs.getValue() );
742 }
743
744 }
745
746 return client.execute( httpMethod, localContext );
747 }
748
749 protected void setParameters( HttpUriRequest method )
750 {
751 HttpMethodConfiguration config =
752 httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
753 if ( config != null )
754 {
755 HttpParams params = config.asMethodParams( method.getParams() );
756
757 if ( config.isUsePreemptive() && authenticationInfo != null )
758 {
759 String username = authenticationInfo.getUserName();
760 String password = authenticationInfo.getPassword();
761
762 if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) )
763 {
764
765 AuthCache authCache = new BasicAuthCache();
766 BasicScheme basicAuth = new BasicScheme();
767 HttpHost targetHost =
768 new HttpHost( repository.getHost(), repository.getPort(), repository.getProtocol() );
769 authCache.put( targetHost, basicAuth );
770
771 localContext = new BasicHttpContext();
772 localContext.setAttribute( ClientContext.AUTH_CACHE, authCache );
773 }
774
775 }
776
777 if ( params != null )
778 {
779 method.setParams( params );
780 }
781 }
782
783 if ( config == null )
784 {
785 int readTimeout = getReadTimeout();
786 method.getParams().setParameter( CoreConnectionPNames.SO_TIMEOUT, readTimeout );
787 }
788 }
789
790 protected void setHeaders( HttpUriRequest method )
791 {
792 HttpMethodConfiguration config =
793 httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
794 if ( config == null || config.isUseDefaultHeaders() )
795 {
796
797 method.addHeader( "Cache-control", "no-cache" );
798 method.addHeader( "Cache-store", "no-store" );
799 method.addHeader( "Pragma", "no-cache" );
800 method.addHeader( "Expires", "0" );
801 method.addHeader( "Accept-Encoding", "gzip" );
802 }
803
804 if ( httpHeaders != null )
805 {
806 for ( Map.Entry<Object, Object> entry : httpHeaders.entrySet() )
807 {
808 method.addHeader( (String) entry.getKey(), (String) entry.getValue() );
809 }
810 }
811
812 Header[] headers = config == null ? null : config.asRequestHeaders();
813 if ( headers != null )
814 {
815 for ( int i = 0; i < headers.length; i++ )
816 {
817 method.addHeader( headers[i] );
818 }
819 }
820 }
821
822 protected String getUserAgent( HttpUriRequest method )
823 {
824 if ( httpHeaders != null )
825 {
826 String value = (String) httpHeaders.get( "User-Agent" );
827 if ( value != null )
828 {
829 return value;
830 }
831 }
832 HttpMethodConfiguration config =
833 httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
834
835 if ( config != null )
836 {
837 return (String) config.getHeaders().get( "User-Agent" );
838 }
839 return null;
840 }
841
842
843
844
845
846
847
848
849 protected String getURL( Repository repository )
850 {
851 return repository.getUrl();
852 }
853
854 public HttpConfiguration getHttpConfiguration()
855 {
856 return httpConfiguration;
857 }
858
859 public void setHttpConfiguration( HttpConfiguration httpConfiguration )
860 {
861 this.httpConfiguration = httpConfiguration;
862 }
863
864 public void fillInputData( InputData inputData )
865 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
866 {
867 Resource resource = inputData.getResource();
868
869 String repositoryUrl = getRepository().getUrl();
870 String url = repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + resource.getName();
871 getMethod = new HttpGet( url );
872 long timestamp = resource.getLastModified();
873 if ( timestamp > 0 )
874 {
875 SimpleDateFormat fmt = new SimpleDateFormat( "EEE, dd-MMM-yy HH:mm:ss zzz", Locale.US );
876 fmt.setTimeZone( GMT_TIME_ZONE );
877 Header hdr = new BasicHeader( "If-Modified-Since", fmt.format( new Date( timestamp ) ) );
878 fireTransferDebug( "sending ==> " + hdr + "(" + timestamp + ")" );
879 getMethod.addHeader( hdr );
880 }
881
882 HttpResponse response;
883 int statusCode;
884 try
885 {
886 response = execute( getMethod );
887 }
888 catch ( IOException e )
889 {
890 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
891
892 throw new TransferFailedException( e.getMessage(), e );
893 }
894 catch ( HttpException e )
895 {
896 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
897
898 throw new TransferFailedException( e.getMessage(), e );
899 }
900
901 statusCode = response.getStatusLine().getStatusCode();
902
903 String reasonPhrase = ", ReasonPhrase:" + response.getStatusLine().getReasonPhrase() + ".";
904
905 fireTransferDebug( url + " - Status code: " + statusCode + reasonPhrase );
906
907
908
909 switch ( statusCode )
910 {
911 case HttpStatus.SC_OK:
912 break;
913
914 case HttpStatus.SC_NOT_MODIFIED:
915
916 return;
917
918 case SC_NULL:
919 {
920 TransferFailedException e =
921 new TransferFailedException( "Failed to transfer file: " + url + " " + reasonPhrase );
922 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
923 throw e;
924 }
925
926 case HttpStatus.SC_FORBIDDEN:
927 fireSessionConnectionRefused();
928 throw new AuthorizationException( "Access denied to: " + url + " " + reasonPhrase );
929
930 case HttpStatus.SC_UNAUTHORIZED:
931 fireSessionConnectionRefused();
932 throw new AuthorizationException( "Not authorized " + reasonPhrase );
933
934 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
935 fireSessionConnectionRefused();
936 throw new AuthorizationException( "Not authorized by proxy " + reasonPhrase );
937
938 case HttpStatus.SC_NOT_FOUND:
939 throw new ResourceDoesNotExistException( "File: " + url + " " + reasonPhrase );
940
941
942 default:
943 {
944 cleanupGetTransfer( resource );
945 TransferFailedException e = new TransferFailedException(
946 "Failed to transfer file: " + url + ". Return code is: " + statusCode + " " + reasonPhrase );
947 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
948 throw e;
949 }
950 }
951
952 InputStream is;
953
954 Header contentLengthHeader = response.getFirstHeader( "Content-Length" );
955
956 if ( contentLengthHeader != null )
957 {
958 try
959 {
960 long contentLength = Long.parseLong( contentLengthHeader.getValue() );
961
962 resource.setContentLength( contentLength );
963 }
964 catch ( NumberFormatException e )
965 {
966 fireTransferDebug(
967 "error parsing content length header '" + contentLengthHeader.getValue() + "' " + e );
968 }
969 }
970
971 Header lastModifiedHeader = response.getFirstHeader( "Last-Modified" );
972
973 long lastModified = 0;
974
975 if ( lastModifiedHeader != null )
976 {
977 try
978 {
979 lastModified = DateUtils.parseDate( lastModifiedHeader.getValue() ).getTime();
980
981 resource.setLastModified( lastModified );
982 }
983 catch ( DateParseException e )
984 {
985 fireTransferDebug( "Unable to parse last modified header" );
986 }
987
988 fireTransferDebug( "last-modified = " + lastModifiedHeader.getValue() + " (" + lastModified + ")" );
989 }
990
991 Header contentEncoding = response.getFirstHeader( "Content-Encoding" );
992 boolean isGZipped = contentEncoding == null ? false : "gzip".equalsIgnoreCase( contentEncoding.getValue() );
993
994 try
995 {
996 is = response.getEntity().getContent();
997
998 if ( isGZipped )
999 {
1000 is = new GZIPInputStream( is );
1001 }
1002 }
1003 catch ( IOException e )
1004 {
1005 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
1006
1007 String msg =
1008 "Error occurred while retrieving from remote repository " + getRepository() + ": " + e.getMessage();
1009
1010 throw new TransferFailedException( msg, e );
1011 }
1012
1013 inputData.setInputStream( is );
1014 }
1015
1016 protected void cleanupGetTransfer( Resource resource )
1017 {
1018 if ( getMethod != null )
1019 {
1020 getMethod.abort();
1021 }
1022 }
1023
1024
1025 @Override
1026 public void putFromStream( InputStream stream, String destination )
1027 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
1028 {
1029 putFromStream( stream, destination, -1, -1 );
1030 }
1031
1032 @Override
1033 protected void putFromStream( InputStream stream, Resource resource )
1034 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
1035 {
1036 putFromStream( stream, resource.getName(), -1, -1 );
1037 }
1038
1039 public Properties getHttpHeaders()
1040 {
1041 return httpHeaders;
1042 }
1043
1044 public void setHttpHeaders( Properties httpHeaders )
1045 {
1046 this.httpHeaders = httpHeaders;
1047 }
1048
1049 @Override
1050 public void fillOutputData( OutputData outputData )
1051 throws TransferFailedException
1052 {
1053
1054 throw new IllegalStateException( "this wagon http client must not use fillOutputData" );
1055 }
1056 }