Class HttpClientConnection


  • public class HttpClientConnection
    extends java.lang.Object
    The class HttpClientConnection provides a simple HTTP/1.1 compliant connection from a client to an HTTP server. This class does not provide a full-blown HTTP connection, but it is rather optimized for what ONC/RPC clients need in order to tunnel ONC remote procedure calls through ordinary HTTP connections, thus penetrating firewalls.

    A HttpClientConnection is not that clever as you would first expect. Rather you have to do some things for yourself, like reconnecting dropped connections, and so on. While this sometimes result in more labour on the caller's shoulders, this keeps resource wasting at a minimum, and gives you full control over redirections and other mess -- you do want full control, right?.

    For this reason, for instance, an HttpClientConnection does not buffer the whole request before sending it to the server but rather relies on the caller to supply the right content-length information. This avoids unnecessary double buffering but instead creates the bas64 encoded content on-the-fly.

    Of course, this client connection object does not touch the content, it just suplies the pipe to swallow the data.

    Version:
    $Revision: 1.1.1.1 $ $Date: 2003/08/13 12:03:45 $ $State: Exp $ $Locker: $
    Author:
    Harald Albrecht
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private byte[] asciiBuffer
      Buffer receiving ASCII characters from Unicode strings when sending (header) strings to the HTTP server.
      private java.lang.String cachedProxyHost
      Address of proxy host to contact instead of real HTTP server.
      private int cachedProxyPort
      Port number of proxy HTTP server.
      private boolean chunkedTransfer
      Indicates whether the HTTP server send its reply using the chunked transfer encoding.
      private java.lang.String contentType
      Type of content sent by HTTP server.
      static byte[] CRLF  
      private boolean finalChunkSeen
      Indicates whether the end-of-chunks chunk has been read (whow, another one for the Purlitzer price).
      private char[] headerLine
      Dynamically growing buffer used during header parsing.
      private java.lang.String hostname
      Host name of HTTP server to contact in the form of www.acplt.org.
      private static int HTTP_DEAD  
      static int HTTP_DEFAULTPORT
      Default port where HTTP servers listen for incomming requests.
      private static int HTTP_IDLE  
      private static int HTTP_RECEIVING  
      private static int HTTP_SENDING  
      private java.io.InputStream in  
      private boolean keepAlive  
      private int mode
      Indicates sending/receiving mode of the HTTP connection.
      private java.io.OutputStream out
      Buffered output stream used for sending the HTTP headers.
      private int port
      Port number where to contact the HTTP server.
      private int remainingChunkLength
      Contains the amount of data still to be read for the current chunk.
      private int remainingContentLength
      Indicates the amount of content data which still has to be sent or received.
      private int responseCode
      Contains the HTTP response code from the last request sent to the HTTP server.
      private java.net.Socket socket
      TCP/IP socket for communication with the HTTP server.
      private int timeout
      Timeout (in milliseconds) for communication with an HTTP server.
      private boolean useProxy
      Indicates whether a proxy HTTP server needs to be contacted in order to reach the real HTTP server.
      private java.lang.String userAgentId  
    • Constructor Summary

      Constructors 
      Constructor Description
      HttpClientConnection​(java.lang.String hostname)
      Constructs a new HttpClientConnection.
      HttpClientConnection​(java.lang.String hostname, int port)
      Constructs a new HttpClientConnection.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      int beginDecoding()
      Begin receiving the content sent by the HTTP server.
      void beginPostRequest​(java.lang.String path, java.lang.String mimeType, int contentLength)
      Starts a new HTTP "POST" request and sends all necessary HTTP header fields.
      void close()
      Closes the connection to the HTTP server and frees up some resources.
      private void connect()
      Connects to the HTTP server.
      void endDecoding()
      This method silently discards any unread content, if the caller has yet not read all content.
      void endPostRequest()
      Ends the HTTP "POST" request.
      java.lang.String getContentType()
      Returns the content type (MIME type, charset, etc.).
      boolean getKeepAlive()  
      private java.lang.String getProxyHost()
      Retrieves the host name where the HTTP proxy server resided from the system properties.
      private int getProxyPort()
      Retrieves the port number where the HTTP proxy server resides from the system properties.
      int getRemainingContentLength()
      Returns amount of content still available (to be read).
      int getResponseCode()  
      int getTimeout()
      Retrieve the current timeout set for remote procedure calls.
      protected void handleOption​(java.lang.String option, java.lang.String value)
      Handle options sent by the HTTP server.
      int readContentBytes​(byte[] buffer, int offset, int length)
      Read content sent by the HTTP server.
      private boolean readHeaderLine​(java.lang.String[] keyvalue)
      Read in a header line coming over the HTTP connection from the server.
      private int readHeaders()
      Read the HTTP headers sent by the servers and also parse them at the same time.
      private java.lang.String readLine()
      Read exactly one line, termined by CRLF or either CR or LF, and return it.
      void setTimeout​(int milliseconds)
      Set the timout for sending or receiving information to/from the HTTP server.
      private void write​(java.lang.String s)
      Writes an ASCII string to the HTTP server (this is buffered first).
      void writeContentBytes​(byte[] bytes, int offset, int length)
      Send (part) of the content to the HTTP server.
      private void writeln​(java.lang.String s)
      Writes an ASCII string and appends a line termination in the form of CR followed by LF.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • HTTP_DEFAULTPORT

        public static final int HTTP_DEFAULTPORT
        Default port where HTTP servers listen for incomming requests. This is just a convenience definition to make the code more readable.
        See Also:
        Constant Field Values
      • hostname

        private java.lang.String hostname
        Host name of HTTP server to contact in the form of www.acplt.org.
      • port

        private int port
        Port number where to contact the HTTP server. This defaults to the standard port where HTTP servers are expected: port 80.
      • socket

        private java.net.Socket socket
        TCP/IP socket for communication with the HTTP server.
      • timeout

        private int timeout
        Timeout (in milliseconds) for communication with an HTTP server.
      • keepAlive

        private boolean keepAlive
      • chunkedTransfer

        private boolean chunkedTransfer
        Indicates whether the HTTP server send its reply using the chunked transfer encoding.
      • remainingChunkLength

        private int remainingChunkLength
        Contains the amount of data still to be read for the current chunk.
      • finalChunkSeen

        private boolean finalChunkSeen
        Indicates whether the end-of-chunks chunk has been read (whow, another one for the Purlitzer price).
      • contentType

        private java.lang.String contentType
        Type of content sent by HTTP server.
      • out

        private java.io.OutputStream out
        Buffered output stream used for sending the HTTP headers. This stream is not used to send content in an HTTP request.
      • in

        private java.io.InputStream in
      • responseCode

        private int responseCode
        Contains the HTTP response code from the last request sent to the HTTP server.
      • asciiBuffer

        private byte[] asciiBuffer
        Buffer receiving ASCII characters from Unicode strings when sending (header) strings to the HTTP server.
      • headerLine

        private char[] headerLine
        Dynamically growing buffer used during header parsing.
      • userAgentId

        private java.lang.String userAgentId
      • mode

        private int mode
        Indicates sending/receiving mode of the HTTP connection.
      • remainingContentLength

        private int remainingContentLength
        Indicates the amount of content data which still has to be sent or received.
      • CRLF

        public static final byte[] CRLF
      • useProxy

        private boolean useProxy
        Indicates whether a proxy HTTP server needs to be contacted in order to reach the real HTTP server.
      • cachedProxyHost

        private java.lang.String cachedProxyHost
        Address of proxy host to contact instead of real HTTP server.
      • cachedProxyPort

        private int cachedProxyPort
        Port number of proxy HTTP server.
    • Constructor Detail

      • HttpClientConnection

        public HttpClientConnection​(java.lang.String hostname)
        Constructs a new HttpClientConnection. The port used on the HTTP server side is the default HTTP port, 80.
        Parameters:
        hostname - name (DNS name or IP dotted address) of host running a HTTP server to which we want to connect to.
      • HttpClientConnection

        public HttpClientConnection​(java.lang.String hostname,
                                    int port)
        Constructs a new HttpClientConnection.
        Parameters:
        hostname - name (DNS name or IP dotted address) of host running a HTTP server to which we should connect to.
        port - Port number where the HTTP server can be contacted.
    • Method Detail

      • close

        public void close()
        Closes the connection to the HTTP server and frees up some resources. After calling close it is still possible to open a new connection to the HTTP server once again.
      • beginPostRequest

        public void beginPostRequest​(java.lang.String path,
                                     java.lang.String mimeType,
                                     int contentLength)
                              throws java.io.IOException
        Starts a new HTTP "POST" request and sends all necessary HTTP header fields. Next, the caller can send lots of content using the writeContentBytes(byte[], int, int) method. Finally, to finish the request he has to call the endPostRequest() method.
        Parameters:
        path - Path to server object which handles the POST request. For instance, this can be a CGI script (although it better should not be one, except in the case of FAST CGI).
        mimeType - MIME-classified type of content to be sent.
        contentLength - Length of content to be sent. If negative, the length is not known in advance. In this case, keeping the connection alive is not possible, so callers should avoid this situation, if possible.
        Throws:
        java.io.IOException - if an I/O exception occurs when sending the HTTP headers. In this case the connection is closed automatically and the caller must not send any content. However, the caller is free to give the request another try by calling beginEncoding again, thus opening a new HTTP connection.
      • writeContentBytes

        public void writeContentBytes​(byte[] bytes,
                                      int offset,
                                      int length)
                               throws java.io.IOException
        Send (part) of the content to the HTTP server. Note that the output is done unbuffered, so callers should write their content in large chunks to avoid the calling overhead for sending data.
        Parameters:
        bytes - The data.
        offset - Start offset in the data.
        length - Number of bytes to write.
        Throws:
        java.lang.RuntimeException - if too much content was sent.
        java.io.IOException - if an I/O error occurs.
        java.lang.NullPointerException - if bytes is null.
        java.lang.IndexOutOfBoundsException - if offset is negative, or length is negative, or offset + length is greater than the length of the array bytes.
      • endPostRequest

        public void endPostRequest()
                            throws java.io.IOException
        Ends the HTTP "POST" request. The next logical step for a caller is then to call ... #FIXME
        Throws:
        java.io.IOException
      • handleOption

        protected void handleOption​(java.lang.String option,
                                    java.lang.String value)
        Handle options sent by the HTTP server.

        Currently the following options are handled by this class:

        • Content-Length -- length of content following the header section
        • Content-Type -- type of content sent
        • Proxy-Connection -- handle keep-alive request
        • Connection -- handle keep-alive request
        • Transfer-Encoding -- transfer encoding choosen by HTTP server
        Parameters:
        option - Name of option sent by HTTP server.
        value - Value of option.
      • readHeaders

        private int readHeaders()
                         throws java.io.IOException
        Read the HTTP headers sent by the servers and also parse them at the same time.
        Returns:
        HTTP status code.
        Throws:
        java.io.IOException
      • readHeaderLine

        private boolean readHeaderLine​(java.lang.String[] keyvalue)
                                throws java.io.IOException
        Read in a header line coming over the HTTP connection from the server.
        Parameters:
        keyvalue - An array with room for either exactly one or two strings, receiving the header option and optionally its value. If only room for a single return string is supplied, then readHeaderLine will only read in the header line (like the first HTTP header) without separating the options's value from its name. If a header option has no option, then null is returned as the value string.
        Returns:
        false if the end of the headers has been reached.
        Throws:
        java.io.IOException
      • readLine

        private java.lang.String readLine()
                                   throws java.io.IOException
        Read exactly one line, termined by CRLF or either CR or LF, and return it.
        Returns:
        Line without the terminating CR, LF or CRLF.
        Throws:
        java.io.IOException
      • beginDecoding

        public int beginDecoding()
                          throws java.io.IOException
        Begin receiving the content sent by the HTTP server. This method blocks until at least the HTTP header section has been received or until the connection times out.
        Returns:
        HTTP server response code (status code).
        Throws:
        java.io.IOException
      • getContentType

        public java.lang.String getContentType()
        Returns the content type (MIME type, charset, etc.).
        Returns:
        content type
      • readContentBytes

        public int readContentBytes​(byte[] buffer,
                                    int offset,
                                    int length)
                             throws java.io.IOException
        Read content sent by the HTTP server. This method also handles the HTTP/1.1 chunked transfer encoding if the HTTP server insisted on using it. If only chunked transfer encoding has been introduced with the first official 0.9 protocol version of HTTP, it would have made sending ONC/RPC requests much easier, because we would not need to buffer the while request before sending it just to know its exact length. Unfortunately, chunking has only been introduced lately so we can not expect servers and especially proxies to handle it. Sigh.
        Parameters:
        buffer - Buffer to receive the content sent by the HTTP server.
        offset - Start offset in the buffer.
        length - Number of bytes to receive.
        Throws:
        java.net.ProtocolException - if not enough content was available (the caller attempted to read more data than available) or if we received junk information violating the HTTP protocol specification.
        java.io.IOException - if an I/O error occurs.
        java.lang.NullPointerException - if bytes is null.
        java.lang.IndexOutOfBoundsException - if offset is negative, or length is negative, or offset + length is greater than the length of the array bytes.
      • getRemainingContentLength

        public int getRemainingContentLength()
        Returns amount of content still available (to be read). This always shows the remaining amount and is updated whenever content is read using readContentBytes(byte[], int, int).
        Returns:
        Amount of content available.
      • endDecoding

        public void endDecoding()
                         throws java.io.IOException

        This method silently discards any unread content, if the caller has yet not read all content.

        Throws:
        java.io.IOException
      • setTimeout

        public void setTimeout​(int milliseconds)
        Set the timout for sending or receiving information to/from the HTTP server.
        Parameters:
        milliseconds - Timeout in milliseconds.
      • getTimeout

        public int getTimeout()
        Retrieve the current timeout set for remote procedure calls. A timeout of zero indicates batching calls (no reply message is expected).
        Returns:
        Current timeout.
      • getResponseCode

        public int getResponseCode()
      • getKeepAlive

        public boolean getKeepAlive()
      • connect

        private void connect()
                      throws java.io.IOException
        Connects to the HTTP server. In case an HTTP proxy has been configured, this connects to the proxy instead.

        If the connection is in keep-alive mode and already open, then the connection is reused.

        Throws:
        java.lang.SecurityException - if a security manager exists and its checkConnect method does not allow the connect operation.
        java.io.IOException
      • write

        private void write​(java.lang.String s)
                    throws java.io.IOException
        Writes an ASCII string to the HTTP server (this is buffered first).
        Parameters:
        s - String to write.
        Throws:
        java.io.IOException
      • writeln

        private void writeln​(java.lang.String s)
                      throws java.io.IOException
        Writes an ASCII string and appends a line termination in the form of CR followed by LF.
        Parameters:
        s - String to write.
        Throws:
        java.io.IOException
      • getProxyHost

        private java.lang.String getProxyHost()
        Retrieves the host name where the HTTP proxy server resided from the system properties.
        Returns:
        Name of proxy host or null if no proxy has been configured.
      • getProxyPort

        private int getProxyPort()
        Retrieves the port number where the HTTP proxy server resides from the system properties. If no port number has been configured for the HTTP proxy, then the default http port number of 80 is returned.
        Returns:
        Port number of HTTP proxy server.