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