343 lines · 10.3 KB · Java
RawDownload
/* * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package sun.rmi.transport.proxy; import java.io.*;import java.net.*; import sun.rmi.runtime.Log; /** * The HttpSendSocket class extends the java.net.Socket class * by enclosing the data output stream in, then extracting the input * stream from, an HTTP protocol transmission. * * NOTES: * * Since the length of the output request must be known before the * HTTP header can be completed, all of the output is buffered by * an HttpOutputStream object until either an attempt is made to * read from this socket, or the socket is explicitly closed. * * On the first read attempt to read from this socket, the buffered * output is sent to the destination as the body of an HTTP POST * request.  All reads will then acquire data from the body of * the response.  A subsequent attempt to write to this socket will * throw an IOException. */class HttpSendSocket extends Socket implements RMISocketInfo {     /** the host to connect to */    protected String host;     /** the port to connect to */    protected int port;     /** the URL to forward through */    protected URL url;     /** the object managing this connection through the URL */    protected URLConnection conn = null;     /** internal input stream for this socket */    protected InputStream in = null;     /** internal output stream for this socket */    protected OutputStream out = null;     /** the notifying input stream returned to users */    protected HttpSendInputStream inNotifier;     /** the notifying output stream returned to users */    protected HttpSendOutputStream outNotifier;     /**     * Line separator string.  This is the value of the line.separator     * property at the moment that the socket was created.     */    private String lineSeparator =        java.security.AccessController.doPrivileged(            new sun.security.action.GetPropertyAction("line.separator"));     /**     * Create a stream socket and connect it to the specified port on     * the specified host.     * @param host the host     * @param port the port     */    public HttpSendSocket(String host, int port, URL url) throws IOException    {        super((SocketImpl)null);        // no underlying SocketImpl for this object         if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {            RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,                "host = " + host + ", port = " + port + ", url = " + url);        }         this.host = host;        this.port = port;        this.url = url;         inNotifier = new HttpSendInputStream(null, this);        outNotifier = new HttpSendOutputStream(writeNotify(), this);    }     /**     * Create a stream socket and connect it to the specified port on     * the specified host.     * @param host the host     * @param port the port     */    public HttpSendSocket(String host, int port) throws IOException    {        this(host, port, new URL("http", host, port, "/"));    }     /**     * Create a stream socket and connect it to the specified address on     * the specified port.     * @param address the address     * @param port the port     */    public HttpSendSocket(InetAddress address, int port) throws IOException    {        this(address.getHostName(), port);    }     /**     * Indicate that this socket is not reusable.     */    public boolean isReusable()    {        return false;    }     /**     * Create a new socket connection to host (or proxy), and prepare to     * send HTTP transmission.     */    public synchronized OutputStream writeNotify() throws IOException    {        if (conn != null) {            throw new IOException("attempt to write on HttpSendSocket after " +                                  "request has been sent");        }         conn = url.openConnection();        conn.setDoOutput(true);        conn.setUseCaches(false);        conn.setRequestProperty("Content-type", "application/octet-stream");         inNotifier.deactivate();        in = null;         return out = conn.getOutputStream();    }     /**     * Send HTTP output transmission and prepare to receive response.     */    public synchronized InputStream readNotify() throws IOException    {        RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,            "sending request and activating input stream");         outNotifier.deactivate();        out.close();        out = null;         try {            in = conn.getInputStream();        } catch (IOException e) {            RMIMasterSocketFactory.proxyLog.log(Log.BRIEF,                "failed to get input stream, exception: ", e);             throw new IOException("HTTP request failed");        }         /*         * If an HTTP error response is returned, sometimes an IOException         * is thrown, which is handled above, and other times it isn't, and         * the error response body will be available for reading.         * As a safety net to catch any such unexpected HTTP behavior, we         * verify that the content type of the response is what the         * HttpOutputStream generates: "application/octet-stream".         * (Servers' error responses will generally be "text/html".)         * Any error response body is printed to the log.         */        String contentType = conn.getContentType();        if (contentType == null ||            !conn.getContentType().equals("application/octet-stream"))        {            if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) {                String message;                if (contentType == null) {                    message = "missing content type in response" +                        lineSeparator;                } else {                    message = "invalid content type in response: " +                        contentType + lineSeparator;                }                 message += "HttpSendSocket.readNotify: response body: ";                try {                    DataInputStream din = new DataInputStream(in);                    String line;                    while ((line = din.readLine()) != null)                        message += line + lineSeparator;                } catch (IOException e) {                }                RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, message);            }             throw new IOException("HTTP request failed");        }         return in;    }     /**     * Get the address to which the socket is connected.     */    public InetAddress getInetAddress()    {        try {            return InetAddress.getByName(host);        } catch (UnknownHostException e) {            return null;        // null if couldn't resolve destination host        }    }     /**     * Get the local address to which the socket is bound.     */    public InetAddress getLocalAddress()    {        try {            return InetAddress.getLocalHost();        } catch (UnknownHostException e) {            return null;        // null if couldn't determine local host        }    }     /**     * Get the remote port to which the socket is connected.     */    public int getPort()    {        return port;    }     /**     * Get the local port to which the socket is connected.     */    public int getLocalPort()    {        return -1;      // request not applicable to this socket type    }     /**     * Get an InputStream for this socket.     */    public InputStream getInputStream() throws IOException    {        return inNotifier;    }     /**     * Get an OutputStream for this socket.     */    public OutputStream getOutputStream() throws IOException    {        return outNotifier;    }     /**     * Enable/disable TCP_NODELAY.     * This operation has no effect for an HttpSendSocket.     */    public void setTcpNoDelay(boolean on) throws SocketException    {    }     /**     * Retrieve whether TCP_NODELAY is enabled.     */    public boolean getTcpNoDelay() throws SocketException    {        return false;   // imply option is disabled    }     /**     * Enable/disable SO_LINGER with the specified linger time.     * This operation has no effect for an HttpSendSocket.     */    public void setSoLinger(boolean on, int val) throws SocketException    {    }     /**     * Retrive setting for SO_LINGER.     */    public int getSoLinger() throws SocketException    {        return -1;      // imply option is disabled    }     /**     * Enable/disable SO_TIMEOUT with the specified timeout     * This operation has no effect for an HttpSendSocket.     */    public synchronized void setSoTimeout(int timeout) throws SocketException    {    }     /**     * Retrive setting for SO_TIMEOUT.     */    public synchronized int getSoTimeout() throws SocketException    {        return 0;       // imply option is disabled    }     /**     * Close the socket.     */    public synchronized void close() throws IOException    {        if (out != null) // push out transmission if not done            out.close();    }     /**     * Return string representation of this pseudo-socket.     */    public String toString()    {        return "HttpSendSocket[host=" + host +               ",port=" + port +               ",url=" + url + "]";    }}