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