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