View Javadoc
1   package org.apache.maven.wagon.providers.webdav;
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.commons.httpclient.Credentials;
23  import org.apache.commons.httpclient.Header;
24  import org.apache.commons.httpclient.HostConfiguration;
25  import org.apache.commons.httpclient.HttpClient;
26  import org.apache.commons.httpclient.HttpConnectionManager;
27  import org.apache.commons.httpclient.HttpMethod;
28  import org.apache.commons.httpclient.HttpStatus;
29  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
30  import org.apache.commons.httpclient.NTCredentials;
31  import org.apache.commons.httpclient.UsernamePasswordCredentials;
32  import org.apache.commons.httpclient.auth.AuthScope;
33  import org.apache.commons.httpclient.cookie.CookiePolicy;
34  import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
35  import org.apache.commons.httpclient.methods.GetMethod;
36  import org.apache.commons.httpclient.methods.HeadMethod;
37  import org.apache.commons.httpclient.methods.PutMethod;
38  import org.apache.commons.httpclient.methods.RequestEntity;
39  import org.apache.commons.httpclient.params.HttpMethodParams;
40  import org.apache.commons.httpclient.util.DateParseException;
41  import org.apache.commons.httpclient.util.DateUtil;
42  import org.apache.commons.io.IOUtils;
43  import org.apache.maven.wagon.InputData;
44  import org.apache.maven.wagon.OutputData;
45  import org.apache.maven.wagon.PathUtils;
46  import org.apache.maven.wagon.ResourceDoesNotExistException;
47  import org.apache.maven.wagon.StreamWagon;
48  import org.apache.maven.wagon.TransferFailedException;
49  import org.apache.maven.wagon.Wagon;
50  import org.apache.maven.wagon.authorization.AuthorizationException;
51  import org.apache.maven.wagon.events.TransferEvent;
52  import org.apache.maven.wagon.proxy.ProxyInfo;
53  import org.apache.maven.wagon.repository.Repository;
54  import org.apache.maven.wagon.resource.Resource;
55  import org.apache.maven.wagon.shared.http.EncodingUtil;
56  import org.codehaus.plexus.util.IOUtil;
57  
58  import java.io.ByteArrayInputStream;
59  import java.io.File;
60  import java.io.FileInputStream;
61  import java.io.IOException;
62  import java.io.InputStream;
63  import java.io.OutputStream;
64  import java.nio.ByteBuffer;
65  import java.text.SimpleDateFormat;
66  import java.util.Date;
67  import java.util.Locale;
68  import java.util.Properties;
69  import java.util.TimeZone;
70  import java.util.zip.GZIPInputStream;
71  
72  /**
73   * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
74   * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
75   */
76  public abstract class AbstractHttpClientWagon
77      extends StreamWagon
78  {
79      private final class RequestEntityImplementation
80          implements RequestEntity
81      {
82          private final Resource resource;
83  
84          private final Wagon wagon;
85  
86          private File source;
87  
88          private ByteBuffer byteBuffer;
89  
90          private RequestEntityImplementation( final InputStream stream, final Resource resource, final Wagon wagon,
91                                               final File source )
92              throws TransferFailedException
93          {
94              if ( source != null )
95              {
96                  this.source = source;
97              }
98              else
99              {
100                 try
101                 {
102                     byte[] bytes = IOUtils.toByteArray( stream );
103                     this.byteBuffer = ByteBuffer.allocate( bytes.length );
104                     this.byteBuffer.put( bytes );
105                     stream.close();
106                 }
107                 catch ( IOException e )
108                 {
109                     throw new TransferFailedException( e.getMessage(), e );
110                 }
111                 finally
112                 {
113                     IOUtils.closeQuietly( stream );
114                 }
115             }
116 
117             this.resource = resource;
118             this.wagon = wagon;
119         }
120 
121         public long getContentLength()
122         {
123             return resource.getContentLength();
124         }
125 
126         public String getContentType()
127         {
128             return null;
129         }
130 
131         public boolean isRepeatable()
132         {
133             return true;
134         }
135 
136         public void writeRequest( OutputStream output )
137             throws IOException
138         {
139             byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
140 
141             TransferEvent transferEvent =
142                 new TransferEvent( wagon, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_PUT );
143             transferEvent.setTimestamp( System.currentTimeMillis() );
144 
145             InputStream fin = null;
146             try
147             {
148                 fin = this.source != null
149                     ? new FileInputStream( source )
150                     : new ByteArrayInputStream( this.byteBuffer.array() );
151                 int remaining = Integer.MAX_VALUE;
152                 while ( remaining > 0 )
153                 {
154                     int n = fin.read( buffer, 0, Math.min( buffer.length, remaining ) );
155 
156                     if ( n == -1 )
157                     {
158                         break;
159                     }
160 
161                     fireTransferProgress( transferEvent, buffer, n );
162 
163                     output.write( buffer, 0, n );
164 
165                     remaining -= n;
166                 }
167 
168                 fin.close();
169                 fin = null;
170             }
171             finally
172             {
173                 IOUtils.closeQuietly( fin );
174             }
175 
176             output.flush();
177         }
178     }
179 
180     protected static final int SC_NULL = -1;
181 
182     protected static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone( "GMT" );
183 
184     private HttpClient client;
185 
186     protected HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
187 
188     /**
189      * @deprecated Use httpConfiguration instead.
190      */
191     private Properties httpHeaders;
192 
193     /**
194      * @since 1.0-beta-6
195      */
196     private HttpConfiguration httpConfiguration;
197 
198     private HttpMethod getMethod;
199 
200     public void openConnectionInternal()
201     {
202         repository.setUrl( getURL( repository ) );
203         client = new HttpClient( connectionManager );
204 
205         // WAGON-273: default the cookie-policy to browser compatible
206         client.getParams().setCookiePolicy( CookiePolicy.BROWSER_COMPATIBILITY );
207 
208         String username = null;
209         String password = null;
210         String domain = null;
211 
212         if ( authenticationInfo != null )
213         {
214             username = authenticationInfo.getUserName();
215 
216             if ( username != null && username.contains( "\\" ) )
217             {
218                 String[] domainAndUsername = username.split( "\\\\" );
219                 domain = domainAndUsername[0];
220                 username = domainAndUsername[1];
221             }
222 
223             password = authenticationInfo.getPassword();
224 
225 
226         }
227 
228         String host = getRepository().getHost();
229 
230         if ( !( username == null || username.length() == 0 )
231             && !( password == null || password.length() == 0 ) )
232         {
233             Credentials creds;
234             if ( domain != null )
235             {
236                 creds = new NTCredentials( username, password, host, domain );
237             }
238             else
239             {
240                 creds = new UsernamePasswordCredentials( username, password );
241             }
242 
243             int port = getRepository().getPort() > -1 ? getRepository().getPort() : AuthScope.ANY_PORT;
244 
245             AuthScope scope = new AuthScope( host, port );
246             client.getState().setCredentials( scope, creds );
247         }
248 
249         HostConfiguration hc = new HostConfiguration();
250 
251         ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() );
252         if ( proxyInfo != null )
253         {
254             String proxyUsername = proxyInfo.getUserName();
255             String proxyPassword = proxyInfo.getPassword();
256             String proxyHost = proxyInfo.getHost();
257             int proxyPort = proxyInfo.getPort();
258             String proxyNtlmHost = proxyInfo.getNtlmHost();
259             String proxyNtlmDomain = proxyInfo.getNtlmDomain();
260             if ( proxyHost != null )
261             {
262                 hc.setProxy( proxyHost, proxyPort );
263 
264                 if ( proxyUsername != null && proxyPassword != null )
265                 {
266                     Credentials creds;
267                     if ( proxyNtlmHost != null || proxyNtlmDomain != null )
268                     {
269                         creds = new NTCredentials( proxyUsername, proxyPassword, proxyNtlmHost, proxyNtlmDomain );
270                     }
271                     else
272                     {
273                         creds = new UsernamePasswordCredentials( proxyUsername, proxyPassword );
274                     }
275 
276                     int port = proxyInfo.getPort() > -1 ? proxyInfo.getPort() : AuthScope.ANY_PORT;
277 
278                     AuthScope scope = new AuthScope( proxyHost, port );
279                     client.getState().setProxyCredentials( scope, creds );
280                 }
281             }
282         }
283 
284         hc.setHost( host );
285 
286         //start a session with the webserver
287         client.setHostConfiguration( hc );
288     }
289 
290     public void closeConnection()
291     {
292         if ( connectionManager instanceof MultiThreadedHttpConnectionManager )
293         {
294             ( (MultiThreadedHttpConnectionManager) connectionManager ).shutdown();
295         }
296     }
297 
298     public void put( File source, String resourceName )
299         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
300     {
301         Resource resource = new Resource( resourceName );
302 
303         firePutInitiated( resource, source );
304 
305         resource.setContentLength( source.length() );
306 
307         resource.setLastModified( source.lastModified() );
308 
309         put( null, resource, source );
310     }
311 
312     public void putFromStream( final InputStream stream, String destination, long contentLength, long lastModified )
313         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
314     {
315         Resource resource = new Resource( destination );
316 
317         firePutInitiated( resource, null );
318 
319         resource.setContentLength( contentLength );
320 
321         resource.setLastModified( lastModified );
322 
323         put( stream, resource, null );
324     }
325 
326     private void put( final InputStream stream, Resource resource, File source )
327         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
328     {
329         RequestEntityImplementation requestEntityImplementation =
330             new RequestEntityImplementation( stream, resource, this, source );
331 
332         put( resource, source, requestEntityImplementation, buildUrl( resource ) );
333 
334     }
335 
336     /**
337      * Builds a complete URL string from the repository URL and the relative path of the resource passed.
338      *
339      * @param resource the resource to extract the relative path from.
340      * @return the complete URL
341      */
342     private String buildUrl( Resource resource )
343     {
344         return EncodingUtil.encodeURLToString( getRepository().getUrl(), resource.getName() );
345     }
346 
347     private void put( Resource resource, File source, RequestEntityImplementation requestEntityImplementation,
348                       String url )
349         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
350     {
351         // preemptive true for put
352         client.getParams().setAuthenticationPreemptive( true );
353 
354         //Parent directories need to be created before posting
355         try
356         {
357             mkdirs( PathUtils.dirname( resource.getName() ) );
358         }
359         catch ( IOException e )
360         {
361             fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
362         }
363 
364         PutMethod putMethod = new PutMethod( url );
365 
366         firePutStarted( resource, source );
367 
368         try
369         {
370             putMethod.setRequestEntity( requestEntityImplementation );
371 
372             int statusCode;
373             try
374             {
375                 statusCode = execute( putMethod );
376 
377             }
378             catch ( IOException e )
379             {
380                 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
381 
382                 throw new TransferFailedException( e.getMessage(), e );
383             }
384 
385             fireTransferDebug( url + " - Status code: " + statusCode );
386 
387             // Check that we didn't run out of retries.
388             // CHECKSTYLE_OFF: AvoidNestedBlocks
389             switch ( statusCode )
390             {
391                 // Success Codes
392                 case HttpStatus.SC_OK: // 200
393                 case HttpStatus.SC_CREATED: // 201
394                 case HttpStatus.SC_ACCEPTED: // 202
395                 case HttpStatus.SC_NO_CONTENT:  // 204
396                     break;
397 
398                 // handle all redirect even if http specs says
399                 // " the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user"
400                 case HttpStatus.SC_MOVED_PERMANENTLY: // 301
401                 case HttpStatus.SC_MOVED_TEMPORARILY: // 302
402                 case HttpStatus.SC_SEE_OTHER: // 303
403                     String relocatedUrl = calculateRelocatedUrl( putMethod );
404                     fireTransferDebug( "relocate to " + relocatedUrl );
405                     put( resource, source, requestEntityImplementation, relocatedUrl );
406                     return;
407 
408                 case SC_NULL:
409                 {
410                     TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url );
411                     fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
412                     throw e;
413                 }
414 
415                 case HttpStatus.SC_FORBIDDEN:
416                     fireSessionConnectionRefused();
417                     throw new AuthorizationException( "Access denied to: " + url );
418 
419                 case HttpStatus.SC_NOT_FOUND:
420                     throw new ResourceDoesNotExistException( "File: " + url + " does not exist" );
421 
422                     //add more entries here
423                 default:
424                 {
425                     TransferFailedException e = new TransferFailedException(
426                         "Failed to transfer file: " + url + ". Return code is: " + statusCode );
427                     fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
428                     throw e;
429                 }
430             }
431             // CHECKSTYLE_ON: AvoidNestedBlocks
432 
433             firePutCompleted( resource, source );
434         }
435         finally
436         {
437             putMethod.releaseConnection();
438         }
439     }
440 
441     protected String calculateRelocatedUrl( EntityEnclosingMethod method )
442     {
443         Header locationHeader = method.getResponseHeader( "Location" );
444         String locationField = locationHeader.getValue();
445         // is it a relative Location or a full ?
446         return locationField.startsWith( "http" ) ? locationField : getURL( getRepository() ) + '/' + locationField;
447     }
448 
449     protected void mkdirs( String dirname )
450         throws IOException
451     {
452         // do nothing as default.
453     }
454 
455     public boolean resourceExists( String resourceName )
456         throws TransferFailedException, AuthorizationException
457     {
458         StringBuilder url = new StringBuilder( getRepository().getUrl() );
459         if ( !url.toString().endsWith( "/" ) )
460         {
461             url.append( '/' );
462         }
463         url.append( resourceName );
464         HeadMethod headMethod = new HeadMethod( url.toString() );
465 
466         int statusCode;
467         try
468         {
469             statusCode = execute( headMethod );
470         }
471         catch ( IOException e )
472         {
473             throw new TransferFailedException( e.getMessage(), e );
474         }
475         try
476         {
477             switch ( statusCode )
478             {
479                 case HttpStatus.SC_OK:
480                     return true;
481 
482                 case HttpStatus.SC_NOT_MODIFIED:
483                     return true;
484 
485                 case SC_NULL:
486                     throw new TransferFailedException( "Failed to transfer file: " + url );
487 
488                 case HttpStatus.SC_FORBIDDEN:
489                     throw new AuthorizationException( "Access denied to: " + url );
490 
491                 case HttpStatus.SC_UNAUTHORIZED:
492                     throw new AuthorizationException( "Not authorized." );
493 
494                 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
495                     throw new AuthorizationException( "Not authorized by proxy." );
496 
497                 case HttpStatus.SC_NOT_FOUND:
498                     return false;
499 
500                 //add more entries here
501                 default:
502                     throw new TransferFailedException(
503                         "Failed to transfer file: " + url + ". Return code is: " + statusCode );
504             }
505         }
506         finally
507         {
508             headMethod.releaseConnection();
509         }
510     }
511 
512     protected int execute( HttpMethod httpMethod )
513         throws IOException
514     {
515         int statusCode;
516 
517         setParameters( httpMethod );
518         setHeaders( httpMethod );
519 
520         statusCode = client.executeMethod( httpMethod );
521         return statusCode;
522     }
523 
524     protected void setParameters( HttpMethod method )
525     {
526         HttpMethodConfiguration config =
527             httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
528         if ( config != null )
529         {
530             HttpMethodParams params = config.asMethodParams( method.getParams() );
531             if ( params != null )
532             {
533                 method.setParams( params );
534             }
535         }
536 
537         if ( config == null || config.getConnectionTimeout() == HttpMethodConfiguration.DEFAULT_CONNECTION_TIMEOUT )
538         {
539             method.getParams().setSoTimeout( getTimeout() );
540         }
541     }
542 
543     protected void setHeaders( HttpMethod method )
544     {
545         HttpMethodConfiguration config =
546             httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
547         if ( config == null || config.isUseDefaultHeaders() )
548         {
549             // TODO: merge with the other headers and have some better defaults, unify with lightweight headers
550             method.addRequestHeader( "Cache-control", "no-cache" );
551             method.addRequestHeader( "Cache-store", "no-store" );
552             method.addRequestHeader( "Pragma", "no-cache" );
553             method.addRequestHeader( "Expires", "0" );
554             method.addRequestHeader( "Accept-Encoding", "gzip" );
555             method.addRequestHeader( "User-Agent", DEFAULT_USER_AGENT );
556         }
557 
558         if ( httpHeaders != null )
559         {
560             for ( Object header : httpHeaders.keySet() )
561             {
562                 if ( "User-Agent".equals( header ) )
563                 {
564                     method.setRequestHeader( (String) header, httpHeaders.getProperty( (String) header ) );
565                 }
566                 else
567                 {
568                     method.addRequestHeader( (String) header, httpHeaders.getProperty( (String) header ) );
569                 }
570             }
571         }
572 
573         Header[] headers = config == null ? null : config.asRequestHeaders();
574         if ( headers != null )
575         {
576             for ( Header header : headers )
577             {
578                 method.addRequestHeader( header );
579             }
580         }
581     }
582 
583     private static final String DEFAULT_USER_AGENT = getDefaultUserAgent();
584 
585     private static String getDefaultUserAgent()
586     {
587         Properties props = new Properties();
588 
589         InputStream is = AbstractHttpClientWagon.class.getResourceAsStream(
590             "/META-INF/maven/org.apache.maven.wagon/wagon-webdav-jackrabbit/pom.properties" );
591         if ( is != null )
592         {
593             try
594             {
595                 props.load( is );
596                 is.close();
597                 is = null;
598             }
599             catch ( IOException ignore )
600             {
601                 // ignore
602             }
603             finally
604             {
605                 IOUtil.close( is );
606             }
607         }
608 
609         String ver = props.getProperty( "version", "unknown-version" );
610         return "Apache-Maven-Wagon/" + ver + " (Java " + System.getProperty( "java.version" ) + "; ";
611     }
612 
613     /**
614      * getUrl
615      * Implementors can override this to remove unwanted parts of the url such as role-hints
616      *
617      * @param repository
618      * @return
619      */
620     protected String getURL( Repository repository )
621     {
622         return repository.getUrl();
623     }
624 
625     protected HttpClient getClient()
626     {
627         return client;
628     }
629 
630     public void setConnectionManager( HttpConnectionManager connectionManager )
631     {
632         this.connectionManager = connectionManager;
633     }
634 
635     public Properties getHttpHeaders()
636     {
637         return httpHeaders;
638     }
639 
640     public void setHttpHeaders( Properties httpHeaders )
641     {
642         this.httpHeaders = httpHeaders;
643     }
644 
645     public HttpConfiguration getHttpConfiguration()
646     {
647         return httpConfiguration;
648     }
649 
650     public void setHttpConfiguration( HttpConfiguration httpConfiguration )
651     {
652         this.httpConfiguration = httpConfiguration;
653     }
654 
655     public void fillInputData( InputData inputData )
656         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
657     {
658         Resource resource = inputData.getResource();
659 
660         StringBuilder url = new StringBuilder( getRepository().getUrl() );
661         if ( !url.toString().endsWith( "/" ) )
662         {
663             url.append( '/' );
664         }
665         url.append( resource.getName() );
666 
667         getMethod = new GetMethod( url.toString() );
668 
669         long timestamp = resource.getLastModified();
670         if ( timestamp > 0 )
671         {
672             SimpleDateFormat fmt = new SimpleDateFormat( "EEE, dd-MMM-yy HH:mm:ss zzz", Locale.US );
673             fmt.setTimeZone( GMT_TIME_ZONE );
674             Header hdr = new Header( "If-Modified-Since", fmt.format( new Date( timestamp ) ) );
675             fireTransferDebug( "sending ==> " + hdr + "(" + timestamp + ")" );
676             getMethod.addRequestHeader( hdr );
677         }
678 
679         int statusCode;
680         try
681         {
682             statusCode = execute( getMethod );
683         }
684         catch ( IOException e )
685         {
686             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
687 
688             throw new TransferFailedException( e.getMessage(), e );
689         }
690 
691         fireTransferDebug( url + " - Status code: " + statusCode );
692 
693         // TODO [BP]: according to httpclient docs, really should swallow the output on error. verify if that is
694         // required
695         // CHECKSTYLE_OFF: AvoidNestedBlocks
696         switch ( statusCode )
697         {
698             case HttpStatus.SC_OK:
699                 break;
700 
701             case HttpStatus.SC_NOT_MODIFIED:
702                 // return, leaving last modified set to original value so getIfNewer should return unmodified
703                 return;
704 
705             case SC_NULL:
706             {
707                 TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url );
708                 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
709                 throw e;
710             }
711 
712             case HttpStatus.SC_FORBIDDEN:
713                 fireSessionConnectionRefused();
714                 throw new AuthorizationException( "Access denied to: " + url );
715 
716             case HttpStatus.SC_UNAUTHORIZED:
717                 fireSessionConnectionRefused();
718                 throw new AuthorizationException( "Not authorized." );
719 
720             case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
721                 fireSessionConnectionRefused();
722                 throw new AuthorizationException( "Not authorized by proxy." );
723 
724             case HttpStatus.SC_NOT_FOUND:
725                 throw new ResourceDoesNotExistException( "File: " + url + " does not exist" );
726 
727                 // add more entries here
728             default:
729             {
730                 cleanupGetTransfer( resource );
731                 TransferFailedException e = new TransferFailedException(
732                     "Failed to transfer file: " + url + ". Return code is: " + statusCode );
733                 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
734                 throw e;
735             }
736         }
737         // CHECKSTYLE_ON: AvoidNestedBlocks
738 
739         InputStream is = null;
740 
741         Header contentLengthHeader = getMethod.getResponseHeader( "Content-Length" );
742 
743         if ( contentLengthHeader != null )
744         {
745             try
746             {
747                 long contentLength = Integer.valueOf( contentLengthHeader.getValue() ).intValue();
748 
749                 resource.setContentLength( contentLength );
750             }
751             catch ( NumberFormatException e )
752             {
753                 fireTransferDebug(
754                     "error parsing content length header '" + contentLengthHeader.getValue() + "' " + e );
755             }
756         }
757 
758         Header lastModifiedHeader = getMethod.getResponseHeader( "Last-Modified" );
759 
760         long lastModified = 0;
761 
762         if ( lastModifiedHeader != null )
763         {
764             try
765             {
766                 lastModified = DateUtil.parseDate( lastModifiedHeader.getValue() ).getTime();
767 
768                 resource.setLastModified( lastModified );
769             }
770             catch ( DateParseException e )
771             {
772                 fireTransferDebug( "Unable to parse last modified header" );
773             }
774 
775             fireTransferDebug( "last-modified = " + lastModifiedHeader.getValue() + " (" + lastModified + ")" );
776         }
777 
778         Header contentEncoding = getMethod.getResponseHeader( "Content-Encoding" );
779         boolean isGZipped = contentEncoding != null && "gzip".equalsIgnoreCase( contentEncoding.getValue() );
780 
781         try
782         {
783             is = getMethod.getResponseBodyAsStream();
784             if ( isGZipped )
785             {
786                 is = new GZIPInputStream( is );
787             }
788         }
789         catch ( IOException e )
790         {
791             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
792 
793             String msg =
794                 "Error occurred while retrieving from remote repository:" + getRepository() + ": " + e.getMessage();
795 
796             throw new TransferFailedException( msg, e );
797         }
798 
799         inputData.setInputStream( is );
800     }
801 
802     protected void cleanupGetTransfer( Resource resource )
803     {
804         if ( getMethod != null )
805         {
806             getMethod.releaseConnection();
807         }
808     }
809 
810     @Override
811     public void putFromStream( InputStream stream, String destination )
812         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
813     {
814         putFromStream( stream, destination, -1, -1 );
815     }
816 
817     @Override
818     protected void putFromStream( InputStream stream, Resource resource )
819         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
820     {
821         putFromStream( stream, resource.getName(), -1, -1 );
822     }
823 
824     @Override
825     public void fillOutputData( OutputData outputData )
826         throws TransferFailedException
827     {
828         // no needed in this implementation but throw an Exception if used
829         throw new IllegalStateException( "this wagon http client must not use fillOutputData" );
830     }
831 }