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