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; 056 057import java.io.ByteArrayInputStream; 058import java.io.File; 059import java.io.FileInputStream; 060import java.io.IOException; 061import java.io.InputStream; 062import java.io.OutputStream; 063import java.net.URLEncoder; 064import java.nio.ByteBuffer; 065import java.text.SimpleDateFormat; 066import java.util.Date; 067import java.util.Locale; 068import java.util.Properties; 069import java.util.TimeZone; 070import java.util.zip.GZIPInputStream; 071 072/** 073 * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a> 074 * @author <a href="mailto:james@atlassian.com">James William Dumay</a> 075 */ 076public abstract class AbstractHttpClientWagon 077 extends StreamWagon 078{ 079 private final class RequestEntityImplementation 080 implements RequestEntity 081 { 082 private final Resource resource; 083 084 private final Wagon wagon; 085 086 private File source; 087 088 private ByteBuffer byteBuffer; 089 090 private RequestEntityImplementation( final InputStream stream, final Resource resource, final Wagon wagon, 091 final File source ) 092 throws TransferFailedException 093 { 094 if ( source != null ) 095 { 096 this.source = source; 097 } 098 else 099 { 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 201 202 String username = null; 203 String password = null; 204 String domain = null; 205 206 if ( authenticationInfo != null ) 207 { 208 username = authenticationInfo.getUserName(); 209 210 if ( StringUtils.contains( username, "\\" ) ) 211 { 212 String[] domainAndUsername = username.split( "\\\\" ); 213 domain = domainAndUsername[0]; 214 username = domainAndUsername[1]; 215 } 216 217 password = authenticationInfo.getPassword(); 218 219 220 } 221 222 String host = getRepository().getHost(); 223 224 if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) ) 225 { 226 Credentials creds; 227 if ( domain != null ) 228 { 229 creds = new NTCredentials( username, password, host, domain ); 230 } 231 else 232 { 233 creds = new UsernamePasswordCredentials( username, password ); 234 } 235 236 int port = getRepository().getPort() > -1 ? getRepository().getPort() : AuthScope.ANY_PORT; 237 238 AuthScope scope = new AuthScope( host, port ); 239 client.getState().setCredentials( scope, creds ); 240 } 241 242 HostConfiguration hc = new HostConfiguration(); 243 244 ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() ); 245 if ( proxyInfo != null ) 246 { 247 String proxyUsername = proxyInfo.getUserName(); 248 String proxyPassword = proxyInfo.getPassword(); 249 String proxyHost = proxyInfo.getHost(); 250 int proxyPort = proxyInfo.getPort(); 251 String proxyNtlmHost = proxyInfo.getNtlmHost(); 252 String proxyNtlmDomain = proxyInfo.getNtlmDomain(); 253 if ( proxyHost != null ) 254 { 255 hc.setProxy( proxyHost, proxyPort ); 256 257 if ( proxyUsername != null && proxyPassword != null ) 258 { 259 Credentials creds; 260 if ( proxyNtlmHost != null || proxyNtlmDomain != null ) 261 { 262 creds = new NTCredentials( proxyUsername, proxyPassword, proxyNtlmHost, proxyNtlmDomain ); 263 } 264 else 265 { 266 creds = new UsernamePasswordCredentials( proxyUsername, proxyPassword ); 267 } 268 269 int port = proxyInfo.getPort() > -1 ? proxyInfo.getPort() : AuthScope.ANY_PORT; 270 271 AuthScope scope = new AuthScope( proxyHost, port ); 272 client.getState().setProxyCredentials( scope, creds ); 273 } 274 } 275 } 276 277 hc.setHost( host ); 278 279 //start a session with the webserver 280 client.setHostConfiguration( hc ); 281 } 282 283 public void closeConnection() 284 { 285 if ( connectionManager instanceof MultiThreadedHttpConnectionManager ) 286 { 287 ( (MultiThreadedHttpConnectionManager) connectionManager ).shutdown(); 288 } 289 } 290 291 public void put( File source, String resourceName ) 292 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 293 { 294 Resource resource = new Resource( resourceName ); 295 296 firePutInitiated( resource, source ); 297 298 resource.setContentLength( source.length() ); 299 300 resource.setLastModified( source.lastModified() ); 301 302 put( null, resource, source ); 303 } 304 305 public void putFromStream( final InputStream stream, String destination, long contentLength, long lastModified ) 306 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 307 { 308 Resource resource = new Resource( destination ); 309 310 firePutInitiated( resource, null ); 311 312 resource.setContentLength( contentLength ); 313 314 resource.setLastModified( lastModified ); 315 316 put( stream, resource, null ); 317 } 318 319 private void put( final InputStream stream, Resource resource, File source ) 320 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException 321 { 322 StringBuilder url = new StringBuilder( getRepository().getUrl() ); 323 String[] parts = StringUtils.split( resource.getName(), "/" ); 324 for ( String part : parts ) 325 { 326 // TODO: Fix encoding... 327 if ( !url.toString().endsWith( "/" ) ) 328 { 329 url.append( '/' ); 330 } 331 url.append( URLEncoder.encode( part ) ); 332 } 333 RequestEntityImplementation requestEntityImplementation = 334 new RequestEntityImplementation( stream, resource, this, source ); 335 put( resource, source, requestEntityImplementation, url.toString() ); 336 337 } 338 339 private void put( Resource resource, File source, RequestEntityImplementation requestEntityImplementation, 340 String url ) 341 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException 342 { 343 344 // preemptive true for put 345 client.getParams().setAuthenticationPreemptive( true ); 346 347 //Parent directories need to be created before posting 348 try 349 { 350 mkdirs( PathUtils.dirname( resource.getName() ) ); 351 } 352 catch ( IOException e ) 353 { 354 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 355 } 356 357 PutMethod putMethod = new PutMethod( url ); 358 359 firePutStarted( resource, source ); 360 361 try 362 { 363 putMethod.setRequestEntity( requestEntityImplementation ); 364 365 int statusCode; 366 try 367 { 368 statusCode = execute( putMethod ); 369 370 } 371 catch ( IOException e ) 372 { 373 fireTransferError( resource, e, TransferEvent.REQUEST_PUT ); 374 375 throw new TransferFailedException( e.getMessage(), e ); 376 } 377 378 fireTransferDebug( url + " - Status code: " + statusCode ); 379 380 // Check that we didn't run out of retries. 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 " the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user" 391 case HttpStatus.SC_MOVED_PERMANENTLY: // 301 392 case HttpStatus.SC_MOVED_TEMPORARILY: // 302 393 case HttpStatus.SC_SEE_OTHER: // 303 394 String relocatedUrl = calculateRelocatedUrl( putMethod ); 395 fireTransferDebug( "relocate to " + relocatedUrl ); 396 put( resource, source, requestEntityImplementation, relocatedUrl ); 397 return; 398 399 case SC_NULL: 400 { 401 TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url ); 402 fireTransferError( resource, e, TransferEvent.REQUEST_PUT ); 403 throw e; 404 } 405 406 case HttpStatus.SC_FORBIDDEN: 407 fireSessionConnectionRefused(); 408 throw new AuthorizationException( "Access denied to: " + url ); 409 410 case HttpStatus.SC_NOT_FOUND: 411 throw new ResourceDoesNotExistException( "File: " + url + " does not exist" ); 412 413 //add more entries here 414 default: 415 { 416 TransferFailedException e = new TransferFailedException( 417 "Failed to transfer file: " + url + ". Return code is: " + statusCode ); 418 fireTransferError( resource, e, TransferEvent.REQUEST_PUT ); 419 throw e; 420 } 421 } 422 423 firePutCompleted( resource, source ); 424 } 425 finally 426 { 427 putMethod.releaseConnection(); 428 } 429 } 430 431 protected String calculateRelocatedUrl( EntityEnclosingMethod method ) 432 { 433 Header locationHeader = method.getResponseHeader( "Location" ); 434 String locationField = locationHeader.getValue(); 435 // is it a relative Location or a full ? 436 return locationField.startsWith( "http" ) ? locationField : getURL( getRepository() ) + '/' + locationField; 437 } 438 439 protected void mkdirs( String dirname ) 440 throws IOException 441 { 442 // do nothing as default. 443 } 444 445 public boolean resourceExists( String resourceName ) 446 throws TransferFailedException, AuthorizationException 447 { 448 StringBuilder url = new StringBuilder( getRepository().getUrl() ); 449 if ( !url.toString().endsWith( "/" ) ) 450 { 451 url.append( '/' ); 452 } 453 url.append( resourceName ); 454 HeadMethod headMethod = new HeadMethod( url.toString() ); 455 456 int statusCode; 457 try 458 { 459 statusCode = execute( headMethod ); 460 } 461 catch ( IOException e ) 462 { 463 throw new TransferFailedException( e.getMessage(), e ); 464 } 465 try 466 { 467 switch ( statusCode ) 468 { 469 case HttpStatus.SC_OK: 470 return true; 471 472 case HttpStatus.SC_NOT_MODIFIED: 473 return true; 474 475 case SC_NULL: 476 throw new TransferFailedException( "Failed to transfer file: " + url ); 477 478 case HttpStatus.SC_FORBIDDEN: 479 throw new AuthorizationException( "Access denied to: " + url ); 480 481 case HttpStatus.SC_UNAUTHORIZED: 482 throw new AuthorizationException( "Not authorized." ); 483 484 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED: 485 throw new AuthorizationException( "Not authorized by proxy." ); 486 487 case HttpStatus.SC_NOT_FOUND: 488 return false; 489 490 //add more entries here 491 default: 492 throw new TransferFailedException( 493 "Failed to transfer file: " + url + ". Return code is: " + statusCode ); 494 } 495 } 496 finally 497 { 498 headMethod.releaseConnection(); 499 } 500 } 501 502 protected int execute( HttpMethod httpMethod ) 503 throws IOException 504 { 505 int statusCode; 506 507 setParameters( httpMethod ); 508 setHeaders( httpMethod ); 509 510 statusCode = client.executeMethod( httpMethod ); 511 return statusCode; 512 } 513 514 protected void setParameters( HttpMethod method ) 515 { 516 HttpMethodConfiguration config = 517 httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method ); 518 if ( config != null ) 519 { 520 HttpMethodParams params = config.asMethodParams( method.getParams() ); 521 if ( params != null ) 522 { 523 method.setParams( params ); 524 } 525 } 526 527 if ( config == null || config.getConnectionTimeout() == HttpMethodConfiguration.DEFAULT_CONNECTION_TIMEOUT ) 528 { 529 method.getParams().setSoTimeout( getTimeout() ); 530 } 531 } 532 533 protected void setHeaders( HttpMethod method ) 534 { 535 HttpMethodConfiguration config = 536 httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method ); 537 if ( config == null || config.isUseDefaultHeaders() ) 538 { 539 // TODO: merge with the other headers and have some better defaults, unify with lightweight headers 540 method.addRequestHeader( "Cache-control", "no-cache" ); 541 method.addRequestHeader( "Cache-store", "no-store" ); 542 method.addRequestHeader( "Pragma", "no-cache" ); 543 method.addRequestHeader( "Expires", "0" ); 544 method.addRequestHeader( "Accept-Encoding", "gzip" ); 545 } 546 547 if ( httpHeaders != null ) 548 { 549 for ( Object header : httpHeaders.keySet() ) 550 { 551 method.addRequestHeader( (String) header, httpHeaders.getProperty( (String) header ) ); 552 } 553 } 554 555 Header[] headers = config == null ? null : config.asRequestHeaders(); 556 if ( headers != null ) 557 { 558 for ( Header header : headers ) 559 { 560 method.addRequestHeader( header ); 561 } 562 } 563 } 564 565 /** 566 * getUrl 567 * Implementors can override this to remove unwanted parts of the url such as role-hints 568 * 569 * @param repository 570 * @return 571 */ 572 protected String getURL( Repository repository ) 573 { 574 return repository.getUrl(); 575 } 576 577 protected HttpClient getClient() 578 { 579 return client; 580 } 581 582 public void setConnectionManager( HttpConnectionManager connectionManager ) 583 { 584 this.connectionManager = connectionManager; 585 } 586 587 public Properties getHttpHeaders() 588 { 589 return httpHeaders; 590 } 591 592 public void setHttpHeaders( Properties httpHeaders ) 593 { 594 this.httpHeaders = httpHeaders; 595 } 596 597 public HttpConfiguration getHttpConfiguration() 598 { 599 return httpConfiguration; 600 } 601 602 public void setHttpConfiguration( HttpConfiguration httpConfiguration ) 603 { 604 this.httpConfiguration = httpConfiguration; 605 } 606 607 public void fillInputData( InputData inputData ) 608 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 609 { 610 Resource resource = inputData.getResource(); 611 612 StringBuilder url = new StringBuilder( getRepository().getUrl() ); 613 if ( !url.toString().endsWith( "/" ) ) 614 { 615 url.append( '/' ); 616 } 617 url.append( resource.getName() ); 618 619 getMethod = new GetMethod( url.toString() ); 620 621 long timestamp = resource.getLastModified(); 622 if ( timestamp > 0 ) 623 { 624 SimpleDateFormat fmt = new SimpleDateFormat( "EEE, dd-MMM-yy HH:mm:ss zzz", Locale.US ); 625 fmt.setTimeZone( GMT_TIME_ZONE ); 626 Header hdr = new Header( "If-Modified-Since", fmt.format( new Date( timestamp ) ) ); 627 fireTransferDebug( "sending ==> " + hdr + "(" + timestamp + ")" ); 628 getMethod.addRequestHeader( hdr ); 629 } 630 631 int statusCode; 632 try 633 { 634 statusCode = execute( getMethod ); 635 } 636 catch ( IOException e ) 637 { 638 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 639 640 throw new TransferFailedException( e.getMessage(), e ); 641 } 642 643 fireTransferDebug( url + " - Status code: " + statusCode ); 644 645 // TODO [BP]: according to httpclient docs, really should swallow the output on error. verify if that is 646 // required 647 switch ( statusCode ) 648 { 649 case HttpStatus.SC_OK: 650 break; 651 652 case HttpStatus.SC_NOT_MODIFIED: 653 // return, leaving last modified set to original value so getIfNewer should return unmodified 654 return; 655 656 case SC_NULL: 657 { 658 TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url ); 659 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 660 throw e; 661 } 662 663 case HttpStatus.SC_FORBIDDEN: 664 fireSessionConnectionRefused(); 665 throw new AuthorizationException( "Access denied to: " + url ); 666 667 case HttpStatus.SC_UNAUTHORIZED: 668 fireSessionConnectionRefused(); 669 throw new AuthorizationException( "Not authorized." ); 670 671 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED: 672 fireSessionConnectionRefused(); 673 throw new AuthorizationException( "Not authorized by proxy." ); 674 675 case HttpStatus.SC_NOT_FOUND: 676 throw new ResourceDoesNotExistException( "File: " + url + " does not exist" ); 677 678 // add more entries here 679 default: 680 { 681 cleanupGetTransfer( resource ); 682 TransferFailedException e = new TransferFailedException( 683 "Failed to transfer file: " + url + ". Return code is: " + statusCode ); 684 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 685 throw e; 686 } 687 } 688 689 InputStream is = null; 690 691 Header contentLengthHeader = getMethod.getResponseHeader( "Content-Length" ); 692 693 if ( contentLengthHeader != null ) 694 { 695 try 696 { 697 long contentLength = Integer.valueOf( contentLengthHeader.getValue() ).intValue(); 698 699 resource.setContentLength( contentLength ); 700 } 701 catch ( NumberFormatException e ) 702 { 703 fireTransferDebug( 704 "error parsing content length header '" + contentLengthHeader.getValue() + "' " + e ); 705 } 706 } 707 708 Header lastModifiedHeader = getMethod.getResponseHeader( "Last-Modified" ); 709 710 long lastModified = 0; 711 712 if ( lastModifiedHeader != null ) 713 { 714 try 715 { 716 lastModified = DateUtil.parseDate( lastModifiedHeader.getValue() ).getTime(); 717 718 resource.setLastModified( lastModified ); 719 } 720 catch ( DateParseException e ) 721 { 722 fireTransferDebug( "Unable to parse last modified header" ); 723 } 724 725 fireTransferDebug( "last-modified = " + lastModifiedHeader.getValue() + " (" + lastModified + ")" ); 726 } 727 728 Header contentEncoding = getMethod.getResponseHeader( "Content-Encoding" ); 729 boolean isGZipped = contentEncoding != null && "gzip".equalsIgnoreCase( contentEncoding.getValue() ); 730 731 try 732 { 733 is = getMethod.getResponseBodyAsStream(); 734 if ( isGZipped ) 735 { 736 is = new GZIPInputStream( is ); 737 } 738 } 739 catch ( IOException e ) 740 { 741 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 742 743 String msg = 744 "Error occurred while retrieving from remote repository:" + getRepository() + ": " + e.getMessage(); 745 746 throw new TransferFailedException( msg, e ); 747 } 748 749 inputData.setInputStream( is ); 750 } 751 752 protected void cleanupGetTransfer( Resource resource ) 753 { 754 if ( getMethod != null ) 755 { 756 getMethod.releaseConnection(); 757 } 758 } 759 760 @Override 761 public void putFromStream( InputStream stream, String destination ) 762 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 763 { 764 putFromStream( stream, destination, -1, -1 ); 765 } 766 767 @Override 768 protected void putFromStream( InputStream stream, Resource resource ) 769 throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException 770 { 771 putFromStream( stream, resource.getName(), -1, -1 ); 772 } 773 774 @Override 775 public void fillOutputData( OutputData outputData ) 776 throws TransferFailedException 777 { 778 // no needed in this implementation but throw an Exception if used 779 throw new IllegalStateException( "this wagon http client must not use fillOutputData" ); 780 } 781}