| 1 31 32 package org.apache.commons.httpclient; 33 34 import java.io.BufferedOutputStream ; 35 import java.io.IOException ; 36 import java.io.InputStream ; 37 import java.io.InterruptedIOException ; 38 import java.io.OutputStream ; 39 import java.io.PushbackInputStream ; 40 import java.lang.reflect.Method ; 41 import java.net.InetAddress ; 42 import java.net.Socket ; 43 import java.net.SocketException ; 44 45 import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory; 46 import org.apache.commons.httpclient.protocol.Protocol; 47 import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; 48 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; 49 import org.apache.commons.httpclient.util.TimeoutController; 50 import org.apache.commons.logging.Log; 51 import org.apache.commons.logging.LogFactory; 52 53 85 public class HttpConnection { 86 87 89 95 public HttpConnection(String host, int port) { 96 this(null, -1, host, port, false); 97 } 98 99 112 public HttpConnection(String host, int port, boolean secure) { 113 this(null, -1, host, port, secure); 114 } 115 116 124 public HttpConnection(String host, int port, Protocol protocol) { 125 this(null, -1, host, null, port, protocol); 126 } 127 128 137 public HttpConnection(String host, String virtualHost, int port, Protocol protocol) { 138 this(null, -1, host, virtualHost, port, protocol); 139 } 140 141 150 public HttpConnection( 151 String proxyHost, 152 int proxyPort, 153 String host, 154 int port) { 155 this(proxyHost, proxyPort, host, port, false); 156 } 157 158 174 public HttpConnection( 175 String proxyHost, 176 int proxyPort, 177 String host, 178 int port, 179 boolean secure) { 180 this(proxyHost, proxyPort, host, null, port, 181 Protocol.getProtocol(secure ? "https" : "http")); 182 } 183 184 189 public HttpConnection(HostConfiguration hostConfiguration) { 190 this(hostConfiguration.getProxyHost(), 191 hostConfiguration.getProxyPort(), 192 hostConfiguration.getHost(), 193 hostConfiguration.getVirtualHost(), 194 hostConfiguration.getPort(), 195 hostConfiguration.getProtocol()); 196 this.localAddress = hostConfiguration.getLocalAddress(); 197 } 198 199 211 public HttpConnection( 212 String proxyHost, 213 int proxyPort, 214 String host, 215 String virtualHost, 216 int port, 217 Protocol protocol) { 218 219 if (host == null) { 220 throw new IllegalArgumentException ("host parameter is null"); 221 } 222 if (protocol == null) { 223 throw new IllegalArgumentException ("protocol is null"); 224 } 225 226 proxyHostName = proxyHost; 227 proxyPortNumber = proxyPort; 228 hostName = host; 229 virtualName = virtualHost; 230 portNumber = protocol.resolvePort(port); 231 protocolInUse = protocol; 232 } 233 234 236 241 public String getHost() { 242 return hostName; 243 } 244 245 251 public void setHost(String host) throws IllegalStateException { 252 if (host == null) { 253 throw new IllegalArgumentException ("host parameter is null"); 254 } 255 assertNotOpen(); 256 hostName = host; 257 } 258 259 264 public String getVirtualHost() { 265 return virtualName; 266 } 267 268 278 public void setVirtualHost(String host) throws IllegalStateException { 279 assertNotOpen(); 280 virtualName = host; 281 } 282 283 291 public int getPort() { 292 if (portNumber < 0) { 293 return isSecure() ? 443 : 80; 294 } else { 295 return portNumber; 296 } 297 } 298 299 306 public void setPort(int port) throws IllegalStateException { 307 assertNotOpen(); 308 portNumber = port; 309 } 310 311 316 public String getProxyHost() { 317 return proxyHostName; 318 } 319 320 327 public void setProxyHost(String host) throws IllegalStateException { 328 assertNotOpen(); 329 proxyHostName = host; 330 } 331 332 337 public int getProxyPort() { 338 return proxyPortNumber; 339 } 340 341 348 public void setProxyPort(int port) throws IllegalStateException { 349 assertNotOpen(); 350 proxyPortNumber = port; 351 } 352 353 359 public boolean isSecure() { 360 return protocolInUse.isSecure(); 361 } 362 363 367 public Protocol getProtocol() { 368 return protocolInUse; 369 } 370 371 383 public void setSecure(boolean secure) throws IllegalStateException { 384 assertNotOpen(); 385 protocolInUse = secure 386 ? Protocol.getProtocol("https") 387 : Protocol.getProtocol("http"); 388 } 389 390 397 public void setProtocol(Protocol protocol) { 398 assertNotOpen(); 399 400 if (protocol == null) { 401 throw new IllegalArgumentException ("protocol is null"); 402 } 403 404 protocolInUse = protocol; 405 406 } 407 408 414 public InetAddress getLocalAddress() { 415 return this.localAddress; 416 } 417 418 424 public void setLocalAddress(InetAddress localAddress) { 425 assertNotOpen(); 426 this.localAddress = localAddress; 427 } 428 429 435 public boolean isOpen() { 436 if (used && isOpen && isStaleCheckingEnabled() && isStale()) { 437 LOG.debug("Connection is stale, closing..."); 438 close(); 439 } 440 return isOpen; 441 } 442 443 450 public boolean isStaleCheckingEnabled() { 451 return staleCheckingEnabled; 452 } 453 454 467 public void setStaleCheckingEnabled(boolean staleCheckEnabled) { 468 this.staleCheckingEnabled = staleCheckEnabled; 469 } 470 471 491 protected boolean isStale() { 492 boolean isStale = true; 493 if (isOpen) { 494 isStale = false; 497 try { 498 if (inputStream.available() == 0) { 499 try { 500 socket.setSoTimeout(1); 501 int byteRead = inputStream.read(); 502 if (byteRead == -1) { 503 isStale = true; 506 } else { 507 inputStream.unread(byteRead); 508 } 509 } finally { 510 socket.setSoTimeout(soTimeout); 511 } 512 } 513 } catch (InterruptedIOException e) { 514 } catch (IOException e) { 516 LOG.debug( 518 "An error occurred while reading from the socket, is appears to be stale", 519 e 520 ); 521 isStale = true; 522 } 523 } 524 525 return isStale; 526 } 527 528 535 public boolean isProxied() { 536 return (!(null == proxyHostName || 0 >= proxyPortNumber)); 537 } 538 539 549 public void setLastResponseInputStream(InputStream inStream) { 550 lastResponseInputStream = inStream; 551 } 552 553 566 public InputStream getLastResponseInputStream() { 567 return lastResponseInputStream; 568 } 569 570 572 583 public void setSoTimeout(int timeout) 584 throws SocketException , IllegalStateException { 585 LOG.debug("HttpConnection.setSoTimeout(" + timeout + ")"); 586 soTimeout = timeout; 587 if (socket != null) { 588 socket.setSoTimeout(timeout); 589 } 590 } 591 592 601 public int getSoTimeout() throws SocketException { 602 LOG.debug("HttpConnection.getSoTimeout()"); 603 if (this.socket != null) { 604 return this.socket.getSoTimeout(); 605 } else { 606 return this.soTimeout; 607 } 608 } 609 610 616 public void setConnectionTimeout(int timeout) { 617 this.connectTimeout = timeout; 618 } 619 620 628 public void open() throws IOException { 629 LOG.trace("enter HttpConnection.open()"); 630 631 assertNotOpen(); 632 try { 633 if (null == socket) { 634 635 final String host = (null == proxyHostName) ? hostName : proxyHostName; 636 final int port = (null == proxyHostName) ? portNumber : proxyPortNumber; 637 638 usingSecureSocket = isSecure() && !isProxied(); 639 640 final ProtocolSocketFactory socketFactory = 643 (isSecure() && isProxied() 644 ? new DefaultProtocolSocketFactory() 645 : protocolInUse.getSocketFactory()); 646 647 if (connectTimeout == 0) { 648 if (localAddress != null) { 649 socket = socketFactory.createSocket(host, port, localAddress, 0); 650 } else { 651 socket = socketFactory.createSocket(host, port); 652 } 653 } else { 654 SocketTask task = new SocketTask() { 655 public void doit() throws IOException { 656 if (localAddress != null) { 657 setSocket(socketFactory.createSocket(host, port, localAddress, 0)); 658 } else { 659 setSocket(socketFactory.createSocket(host, port)); 660 } 661 } 662 }; 663 TimeoutController.execute(task, connectTimeout); 664 socket = task.getSocket(); 665 if (task.exception != null) { 666 throw task.exception; 667 } 668 } 669 670 } 671 672 679 680 socket.setTcpNoDelay(soNodelay); 681 socket.setSoTimeout(soTimeout); 682 if (sendBufferSize != -1) { 683 socket.setSendBufferSize(sendBufferSize); 684 } 685 int outbuffersize = socket.getSendBufferSize(); 686 if (outbuffersize > 2048) { 687 outbuffersize = 2048; 688 } 689 inputStream = new PushbackInputStream (socket.getInputStream()); 690 outputStream = new BufferedOutputStream ( 691 new WrappedOutputStream(socket.getOutputStream()), 692 outbuffersize 693 ); 694 isOpen = true; 695 used = false; 696 } catch (IOException e) { 697 closeSocketAndStreams(); 700 throw e; 701 } catch (TimeoutController.TimeoutException e) { 702 if (LOG.isWarnEnabled()) { 703 LOG.warn("The host " + hostName + ":" + portNumber 704 + " (or proxy " + proxyHostName + ":" + proxyPortNumber 705 + ") did not accept the connection within timeout of " 706 + connectTimeout + " milliseconds"); 707 } 708 throw new ConnectionTimeoutException(); 709 } 710 } 711 712 722 public void tunnelCreated() throws IllegalStateException , IOException { 723 LOG.trace("enter HttpConnection.tunnelCreated()"); 724 725 if (!isSecure() || !isProxied()) { 726 throw new IllegalStateException ( 727 "Connection must be secure " 728 + "and proxied to use this feature"); 729 } 730 731 if (usingSecureSocket) { 732 throw new IllegalStateException ("Already using a secure socket"); 733 } 734 735 SecureProtocolSocketFactory socketFactory = 736 (SecureProtocolSocketFactory) protocolInUse.getSocketFactory(); 737 738 socket = socketFactory.createSocket(socket, hostName, portNumber, true); 739 if (sendBufferSize != -1) { 740 socket.setSendBufferSize(sendBufferSize); 741 } 742 int outbuffersize = socket.getSendBufferSize(); 743 if (outbuffersize > 2048) { 744 outbuffersize = 2048; 745 } 746 inputStream = new PushbackInputStream (socket.getInputStream()); 747 outputStream = new BufferedOutputStream ( 748 new WrappedOutputStream(socket.getOutputStream()), 749 outbuffersize 750 ); 751 usingSecureSocket = true; 752 tunnelEstablished = true; 753 LOG.debug("Secure tunnel created"); 754 } 755 756 762 public boolean isTransparent() { 763 return !isProxied() || tunnelEstablished; 764 } 765 766 772 public void flushRequestOutputStream() throws IOException { 773 LOG.trace("enter HttpConnection.flushRequestOutputStream()"); 774 assertOpen(); 775 outputStream.flush(); 776 } 777 778 785 public OutputStream getRequestOutputStream() 786 throws IOException , IllegalStateException { 787 LOG.trace("enter HttpConnection.getRequestOutputStream()"); 788 assertOpen(); 789 OutputStream out = this.outputStream; 790 if (Wire.CONTENT_WIRE.enabled()) { 791 out = new WireLogOutputStream(out, Wire.CONTENT_WIRE); 792 } 793 return out; 794 } 795 796 806 public OutputStream getRequestOutputStream(boolean useChunking) 807 throws IOException , IllegalStateException { 808 LOG.trace("enter HttpConnection.getRequestOutputStream(boolean)"); 809 810 OutputStream out = getRequestOutputStream(); 811 if (useChunking) { 812 out = new ChunkedOutputStream(out); 813 } 814 return out; 815 } 816 817 831 public InputStream getResponseInputStream(HttpMethod method) 832 throws IOException , IllegalStateException { 833 LOG.trace("enter HttpConnection.getResponseInputStream(HttpMethod)"); 834 return getResponseInputStream(); 835 } 836 837 843 public InputStream getResponseInputStream() 844 throws IOException , IllegalStateException { 845 LOG.trace("enter HttpConnection.getResponseInputStream()"); 846 assertOpen(); 847 return inputStream; 848 } 849 850 860 public boolean isResponseAvailable() 861 throws IOException { 862 LOG.trace("enter HttpConnection.isResponseAvailable()"); 863 assertOpen(); 864 return this.inputStream.available() > 0; 865 } 866 867 877 public boolean isResponseAvailable(int timeout) 878 throws IOException { 879 LOG.trace("enter HttpConnection.isResponseAvailable(int)"); 880 assertOpen(); 881 boolean result = false; 882 if (this.inputStream.available() > 0) { 883 result = true; 884 } else { 885 try { 886 this.socket.setSoTimeout(timeout); 887 int byteRead = inputStream.read(); 888 if (byteRead != -1) { 889 inputStream.unread(byteRead); 890 LOG.debug("Input data available"); 891 result = true; 892 } else { 893 LOG.debug("Input data not available"); 894 } 895 } catch (InterruptedIOException e) { 896 if (LOG.isDebugEnabled()) { 897 LOG.debug("Input data not available after " + timeout + " ms"); 898 } 899 } finally { 900 try { 901 socket.setSoTimeout(soTimeout); 902 } catch (IOException  |