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