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