8155182: fix to JDK-8066750 broke jdk9 builds
Summary: Restore RMI Http Proxy support for now
Reviewed-by: darcy, lancea, smarks
--- a/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java Tue Apr 26 17:35:10 2016 -0400
+++ b/jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java Tue Apr 26 21:25:18 2016 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, 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
@@ -35,8 +35,21 @@
* request that the RMI runtime use its socket factory instance
* instead of the default implementation.
*
- * <p>The default socket factory implementation creates a direct
- * socket connection to the remote host.
+ * <p>The default socket factory implementation performs a
+ * three-tiered approach to creating client sockets. First, a direct
+ * socket connection to the remote VM is attempted. If that fails
+ * (due to a firewall), the runtime uses HTTP with the explicit port
+ * number of the server. If the firewall does not allow this type of
+ * communication, then HTTP to a cgi-bin script on the server is used
+ * to POST the RMI call. The HTTP tunneling mechanisms are disabled by
+ * default. This behavior is controlled by the {@code java.rmi.server.disableHttp}
+ * property, whose default value is {@code true}. Setting this property's
+ * value to {@code false} will enable the HTTP tunneling mechanisms.
+ *
+ * <p><strong>Deprecated: HTTP Tunneling.</strong> <em>The HTTP tunneling mechanisms
+ * described above, specifically HTTP with an explicit port and HTTP to a
+ * cgi-bin script, are deprecated. These HTTP tunneling mechanisms are
+ * subject to removal in a future release of the platform.</em>
*
* <p>The default socket factory implementation creates server sockets that
* are bound to the wildcard address, which accepts requests from all network
@@ -168,7 +181,7 @@
public synchronized static RMISocketFactory getDefaultSocketFactory() {
if (defaultSocketFactory == null) {
defaultSocketFactory =
- new sun.rmi.transport.tcp.TCPDirectSocketFactory();
+ new sun.rmi.transport.proxy.RMIMasterSocketFactory();
}
return defaultSocketFactory;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1996, 2013, 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 java.util.Hashtable;
+
+/**
+ * CGIClientException is thrown when an error is detected
+ * in a client's request.
+ */
+class CGIClientException extends Exception {
+ private static final long serialVersionUID = 8147981687059865216L;
+
+ public CGIClientException(String s) {
+ super(s);
+ }
+
+ public CGIClientException(String s, Throwable cause) {
+ super(s, cause);
+ }
+}
+
+/**
+ * CGIServerException is thrown when an error occurs here on the server.
+ */
+class CGIServerException extends Exception {
+
+ private static final long serialVersionUID = 6928425456704527017L;
+
+ public CGIServerException(String s) {
+ super(s);
+ }
+
+ public CGIServerException(String s, Throwable cause) {
+ super(s, cause);
+ }
+}
+
+/**
+ * CGICommandHandler is the interface to an object that handles a
+ * particular supported command.
+ */
+interface CGICommandHandler {
+
+ /**
+ * Return the string form of the command
+ * to be recognized in the query string.
+ */
+ public String getName();
+
+ /**
+ * Execute the command with the given string as parameter.
+ */
+ public void execute(String param) throws CGIClientException, CGIServerException;
+}
+
+/**
+ * The CGIHandler class contains methods for executing as a CGI program.
+ * The main function interprets the query string as a command of the form
+ * "{@code <command>=<parameters>}".
+ *
+ * This class depends on the CGI 1.0 environment variables being set as
+ * properties of the same name in this Java VM.
+ *
+ * All data and methods of this class are static because they are specific
+ * to this particular CGI process.
+ */
+public final class CGIHandler {
+
+ /* get CGI parameters that we need */
+ static int ContentLength;
+ static String QueryString;
+ static String RequestMethod;
+ static String ServerName;
+ static int ServerPort;
+
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ ContentLength =
+ Integer.getInteger("CONTENT_LENGTH", 0).intValue();
+ QueryString = System.getProperty("QUERY_STRING", "");
+ RequestMethod = System.getProperty("REQUEST_METHOD", "");
+ ServerName = System.getProperty("SERVER_NAME", "");
+ ServerPort = Integer.getInteger("SERVER_PORT", 0).intValue();
+ return null;
+ }
+ });
+ }
+
+ /* list of handlers for supported commands */
+ private static CGICommandHandler commands[] = {
+ new CGIForwardCommand(),
+ new CGIGethostnameCommand(),
+ new CGIPingCommand(),
+ new CGITryHostnameCommand()
+ };
+
+ /* construct table mapping command strings to handlers */
+ private static Hashtable<String, CGICommandHandler> commandLookup;
+ static {
+ commandLookup = new Hashtable<>();
+ for (int i = 0; i < commands.length; ++ i)
+ commandLookup.put(commands[i].getName(), commands[i]);
+ }
+
+ /* prevent instantiation of this class */
+ private CGIHandler() {}
+
+ /**
+ * Execute command given in query string on URL. The string before
+ * the first '=' is interpreted as the command name, and the string
+ * after the first '=' is the parameters to the command.
+ */
+ public static void main(String args[])
+ {
+ try {
+ String command, param;
+ int delim = QueryString.indexOf('=');
+ if (delim == -1) {
+ command = QueryString;
+ param = "";
+ }
+ else {
+ command = QueryString.substring(0, delim);
+ param = QueryString.substring(delim + 1);
+ }
+ CGICommandHandler handler =
+ commandLookup.get(command);
+ if (handler != null)
+ try {
+ handler.execute(param);
+ } catch (CGIClientException e) {
+ e.printStackTrace();
+ returnClientError(e.getMessage());
+ } catch (CGIServerException e) {
+ e.printStackTrace();
+ returnServerError(e.getMessage());
+ }
+ else
+ returnClientError("invalid command.");
+ } catch (Exception e) {
+ e.printStackTrace();
+ returnServerError("internal error: " + e.getMessage());
+ }
+ System.exit(0);
+ }
+
+ /**
+ * Return an HTML error message indicating there was error in
+ * the client's request.
+ */
+ private static void returnClientError(String message)
+ {
+ System.out.println("Status: 400 Bad Request: " + message);
+ System.out.println("Content-type: text/html");
+ System.out.println("");
+ System.out.println("<HTML>" +
+ "<HEAD><TITLE>Java RMI Client Error" +
+ "</TITLE></HEAD>" +
+ "<BODY>");
+ System.out.println("<H1>Java RMI Client Error</H1>");
+ System.out.println("");
+ System.out.println(message);
+ System.out.println("</BODY></HTML>");
+ System.exit(1);
+ }
+
+ /**
+ * Return an HTML error message indicating an error occurred
+ * here on the server.
+ */
+ private static void returnServerError(String message)
+ {
+ System.out.println("Status: 500 Server Error: " + message);
+ System.out.println("Content-type: text/html");
+ System.out.println("");
+ System.out.println("<HTML>" +
+ "<HEAD><TITLE>Java RMI Server Error" +
+ "</TITLE></HEAD>" +
+ "<BODY>");
+ System.out.println("<H1>Java RMI Server Error</H1>");
+ System.out.println("");
+ System.out.println(message);
+ System.out.println("</BODY></HTML>");
+ System.exit(1);
+ }
+}
+
+/**
+ * "forward" command: Forward request body to local port on the server,
+ * and send response back to client.
+ */
+final class CGIForwardCommand implements CGICommandHandler {
+
+ public String getName() {
+ return "forward";
+ }
+
+ @SuppressWarnings("deprecation")
+ private String getLine (DataInputStream socketIn) throws IOException {
+ return socketIn.readLine();
+ }
+
+ public void execute(String param) throws CGIClientException, CGIServerException
+ {
+ if (!CGIHandler.RequestMethod.equals("POST"))
+ throw new CGIClientException("can only forward POST requests");
+
+ int port;
+ try {
+ port = Integer.parseInt(param);
+ } catch (NumberFormatException e) {
+ throw new CGIClientException("invalid port number.", e);
+ }
+ if (port <= 0 || port > 0xFFFF)
+ throw new CGIClientException("invalid port: " + port);
+ if (port < 1024)
+ throw new CGIClientException("permission denied for port: " +
+ port);
+
+ byte buffer[];
+ Socket socket;
+ try {
+ socket = new Socket(InetAddress.getLocalHost(), port);
+ } catch (IOException e) {
+ throw new CGIServerException("could not connect to local port", e);
+ }
+
+ /*
+ * read client's request body
+ */
+ DataInputStream clientIn = new DataInputStream(System.in);
+ buffer = new byte[CGIHandler.ContentLength];
+ try {
+ clientIn.readFully(buffer);
+ } catch (EOFException e) {
+ throw new CGIClientException("unexpected EOF reading request body", e);
+ } catch (IOException e) {
+ throw new CGIClientException("error reading request body", e);
+ }
+
+ /*
+ * send to local server in HTTP
+ */
+ try {
+ DataOutputStream socketOut =
+ new DataOutputStream(socket.getOutputStream());
+ socketOut.writeBytes("POST / HTTP/1.0\r\n");
+ socketOut.writeBytes("Content-length: " +
+ CGIHandler.ContentLength + "\r\n\r\n");
+ socketOut.write(buffer);
+ socketOut.flush();
+ } catch (IOException e) {
+ throw new CGIServerException("error writing to server", e);
+ }
+
+ /*
+ * read response
+ */
+ DataInputStream socketIn;
+ try {
+ socketIn = new DataInputStream(socket.getInputStream());
+ } catch (IOException e) {
+ throw new CGIServerException("error reading from server", e);
+ }
+ String key = "Content-length:".toLowerCase();
+ boolean contentLengthFound = false;
+ String line;
+ int responseContentLength = -1;
+ do {
+ try {
+ line = getLine(socketIn);
+ } catch (IOException e) {
+ throw new CGIServerException("error reading from server", e);
+ }
+ if (line == null)
+ throw new CGIServerException(
+ "unexpected EOF reading server response");
+
+ if (line.toLowerCase().startsWith(key)) {
+ if (contentLengthFound) {
+ throw new CGIServerException(
+ "Multiple Content-length entries found.");
+ } else {
+ responseContentLength =
+ Integer.parseInt(line.substring(key.length()).trim());
+ contentLengthFound = true;
+ }
+ }
+ } while ((line.length() != 0) &&
+ (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
+
+ if (!contentLengthFound || responseContentLength < 0)
+ throw new CGIServerException(
+ "missing or invalid content length in server response");
+ buffer = new byte[responseContentLength];
+ try {
+ socketIn.readFully(buffer);
+ } catch (EOFException e) {
+ throw new CGIServerException(
+ "unexpected EOF reading server response", e);
+ } catch (IOException e) {
+ throw new CGIServerException("error reading from server", e);
+ }
+
+ /*
+ * send response back to client
+ */
+ System.out.println("Status: 200 OK");
+ System.out.println("Content-type: application/octet-stream");
+ System.out.println("");
+ try {
+ System.out.write(buffer);
+ } catch (IOException e) {
+ throw new CGIServerException("error writing response", e);
+ }
+ System.out.flush();
+ }
+}
+
+/**
+ * "gethostname" command: Return the host name of the server as the
+ * response body
+ */
+final class CGIGethostnameCommand implements CGICommandHandler {
+
+ public String getName() {
+ return "gethostname";
+ }
+
+ public void execute(String param)
+ {
+ System.out.println("Status: 200 OK");
+ System.out.println("Content-type: application/octet-stream");
+ System.out.println("Content-length: " +
+ CGIHandler.ServerName.length());
+ System.out.println("");
+ System.out.print(CGIHandler.ServerName);
+ System.out.flush();
+ }
+}
+
+/**
+ * "ping" command: Return an OK status to indicate that connection
+ * was successful.
+ */
+final class CGIPingCommand implements CGICommandHandler {
+
+ public String getName() {
+ return "ping";
+ }
+
+ public void execute(String param)
+ {
+ System.out.println("Status: 200 OK");
+ System.out.println("Content-type: application/octet-stream");
+ System.out.println("Content-length: 0");
+ System.out.println("");
+ }
+}
+
+/**
+ * "tryhostname" command: Return a human readable message describing
+ * what host name is available to local Java VMs.
+ */
+final class CGITryHostnameCommand implements CGICommandHandler {
+
+ public String getName() {
+ return "tryhostname";
+ }
+
+ public void execute(String param)
+ {
+ System.out.println("Status: 200 OK");
+ System.out.println("Content-type: text/html");
+ System.out.println("");
+ System.out.println("<HTML>" +
+ "<HEAD><TITLE>Java RMI Server Hostname Info" +
+ "</TITLE></HEAD>" +
+ "<BODY>");
+ System.out.println("<H1>Java RMI Server Hostname Info</H1>");
+ System.out.println("<H2>Local host name available to Java VM:</H2>");
+ System.out.print("<P>InetAddress.getLocalHost().getHostName()");
+ try {
+ String localHostName = InetAddress.getLocalHost().getHostName();
+
+ System.out.println(" = " + localHostName);
+ } catch (UnknownHostException e) {
+ System.out.println(" threw java.net.UnknownHostException");
+ }
+
+ System.out.println("<H2>Server host information obtained through CGI interface from HTTP server:</H2>");
+ System.out.println("<P>SERVER_NAME = " + CGIHandler.ServerName);
+ System.out.println("<P>SERVER_PORT = " + CGIHandler.ServerPort);
+ System.out.println("</BODY></HTML>");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1996, 2005, 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.BufferedInputStream;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import sun.rmi.runtime.Log;
+
+/**
+ * The HttpAwareServerSocket class extends the java.net.ServerSocket
+ * class. It behaves like a ServerSocket, except that if
+ * the first four bytes of an accepted socket are the letters "POST",
+ * then it returns an HttpReceiveSocket instead of a java.net.Socket.
+ * This means that the accept method blocks until four bytes have been
+ * read from the new socket's input stream.
+ */
+class HttpAwareServerSocket extends ServerSocket {
+
+ /**
+ * Create a server socket on a specified port.
+ * @param port the port
+ * @exception IOException IO error when opening the socket.
+ */
+ public HttpAwareServerSocket(int port) throws IOException
+ {
+ super(port);
+ }
+
+ /**
+ * Create a server socket, bind it to the specified local port
+ * and listen to it. You can connect to an annonymous port by
+ * specifying the port number to be 0. <i>backlog</i> specifies
+ * how many connection requests the system will queue up while waiting
+ * for the ServerSocket to execute accept().
+ * @param port the specified port
+ * @param backlog the number of queued connect requests pending accept
+ */
+ public HttpAwareServerSocket(int port, int backlog) throws IOException
+ {
+ super(port, backlog);
+ }
+
+ /**
+ * Accept a connection. This method will block until the connection
+ * is made and four bytes can be read from the input stream.
+ * If the first four bytes are "POST", then an HttpReceiveSocket is
+ * returned, which will handle the HTTP protocol wrapping.
+ * Otherwise, a WrappedSocket is returned. The input stream will be
+ * reset to the beginning of the transmission.
+ * In either case, a BufferedInputStream will already be on top of
+ * the underlying socket's input stream.
+ * @exception IOException IO error when waiting for the connection.
+ */
+ public Socket accept() throws IOException
+ {
+ Socket socket = super.accept();
+ BufferedInputStream in =
+ new BufferedInputStream(socket.getInputStream());
+
+ RMIMasterSocketFactory.proxyLog.log(Log.BRIEF,
+ "socket accepted (checking for POST)");
+
+ in.mark(4);
+ boolean isHttp = (in.read() == 'P') &&
+ (in.read() == 'O') &&
+ (in.read() == 'S') &&
+ (in.read() == 'T');
+ in.reset();
+
+ if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) {
+ RMIMasterSocketFactory.proxyLog.log(Log.BRIEF,
+ (isHttp ? "POST found, HTTP socket returned" :
+ "POST not found, direct socket returned"));
+ }
+
+ if (isHttp)
+ return new HttpReceiveSocket(socket, in, null);
+ else
+ return new WrappedSocket(socket, in, null);
+ }
+
+ /**
+ * Return the implementation address and implementation port of
+ * the HttpAwareServerSocket as a String.
+ */
+ public String toString()
+ {
+ return "HttpAware" + super.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1996, 2014, 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 sun.rmi.runtime.Log;
+
+/**
+ * The HttpInputStream class assists the HttpSendSocket and HttpReceiveSocket
+ * classes by filtering out the header for the message as well as any
+ * data after its proper content length.
+ */
+class HttpInputStream extends FilterInputStream {
+
+ /** bytes remaining to be read from proper content of message */
+ protected int bytesLeft;
+
+ /** bytes remaining to be read at time of last mark */
+ protected int bytesLeftAtMark;
+
+ /**
+ * Create new filter on a given input stream.
+ * @param in the InputStream to filter from
+ */
+ @SuppressWarnings("deprecation")
+ public HttpInputStream(InputStream in) throws IOException
+ {
+ super(in);
+
+ if (in.markSupported())
+ in.mark(0); // prevent resetting back to old marks
+
+ // pull out header, looking for content length
+
+ DataInputStream dis = new DataInputStream(in);
+ String key = "Content-length:".toLowerCase();
+ boolean contentLengthFound = false;
+ String line;
+ do {
+ line = dis.readLine();
+
+ if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
+ RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
+ "received header line: \"" + line + "\"");
+ }
+
+ if (line == null)
+ throw new EOFException();
+
+ if (line.toLowerCase().startsWith(key)) {
+ if (contentLengthFound) {
+ throw new IOException(
+ "Multiple Content-length entries found.");
+ } else {
+ bytesLeft =
+ Integer.parseInt(line.substring(key.length()).trim());
+ contentLengthFound = true;
+ }
+ }
+
+ // The idea here is to go past the first blank line.
+ // Some DataInputStream.readLine() documentation specifies that
+ // it does include the line-terminating character(s) in the
+ // returned string, but it actually doesn't, so we'll cover
+ // all cases here...
+ } while ((line.length() != 0) &&
+ (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
+
+ if (!contentLengthFound || bytesLeft < 0) {
+ // This really shouldn't happen, but if it does, shoud we fail??
+ // For now, just give up and let a whole lot of bytes through...
+ bytesLeft = Integer.MAX_VALUE;
+ }
+ bytesLeftAtMark = bytesLeft;
+
+ if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
+ RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
+ "content length: " + bytesLeft);
+ }
+ }
+
+ /**
+ * Returns the number of bytes that can be read with blocking.
+ * Make sure that this does not exceed the number of bytes remaining
+ * in the proper content of the message.
+ */
+ public int available() throws IOException
+ {
+ int bytesAvailable = in.available();
+ if (bytesAvailable > bytesLeft)
+ bytesAvailable = bytesLeft;
+
+ return bytesAvailable;
+ }
+
+ /**
+ * Read a byte of data from the stream. Make sure that one is available
+ * from the proper content of the message, else -1 is returned to
+ * indicate to the user that the end of the stream has been reached.
+ */
+ public int read() throws IOException
+ {
+ if (bytesLeft > 0) {
+ int data = in.read();
+ if (data != -1)
+ -- bytesLeft;
+
+ if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
+ RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
+ "received byte: '" +
+ ((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) +
+ "' " + data);
+ }
+
+ return data;
+ }
+ else {
+ RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
+ "read past content length");
+
+ return -1;
+ }
+ }
+
+ public int read(byte b[], int off, int len) throws IOException
+ {
+ if (bytesLeft == 0 && len > 0) {
+ RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
+ "read past content length");
+
+ return -1;
+ }
+ if (len > bytesLeft)
+ len = bytesLeft;
+ int bytesRead = in.read(b, off, len);
+ bytesLeft -= bytesRead;
+
+ if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
+ RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
+ "read " + bytesRead + " bytes, " + bytesLeft + " remaining");
+ }
+
+ return bytesRead;
+ }
+
+ /**
+ * Mark the current position in the stream (for future calls to reset).
+ * Remember where we are within the proper content of the message, so
+ * that a reset method call can recreate our state properly.
+ * @param readlimit how many bytes can be read before mark becomes invalid
+ */
+ public void mark(int readlimit)
+ {
+ in.mark(readlimit);
+ if (in.markSupported())
+ bytesLeftAtMark = bytesLeft;
+ }
+
+ /**
+ * Repositions the stream to the last marked position. Make sure to
+ * adjust our position within the proper content accordingly.
+ */
+ public void reset() throws IOException
+ {
+ in.reset();
+ bytesLeft = bytesLeftAtMark;
+ }
+
+ /**
+ * Skips bytes of the stream. Make sure to adjust our
+ * position within the proper content accordingly.
+ * @param n number of bytes to be skipped
+ */
+ public long skip(long n) throws IOException
+ {
+ if (n > bytesLeft)
+ n = bytesLeft;
+ long bytesSkipped = in.skip(n);
+ bytesLeft -= bytesSkipped;
+ return bytesSkipped;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1996, 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.*;
+
+/**
+ * The HttpOutputStream class assists the HttpSendSocket and HttpReceiveSocket
+ * classes by providing an output stream that buffers its entire input until
+ * closed, and then it sends the complete transmission prefixed by the end of
+ * an HTTP header that specifies the content length.
+ */
+class HttpOutputStream extends ByteArrayOutputStream {
+
+ /** the output stream to send response to */
+ protected OutputStream out;
+
+ /** true if HTTP response has been sent */
+ boolean responseSent = false;
+
+ /**
+ * Begin buffering new HTTP response to be sent to a given stream.
+ * @param out the OutputStream to send response to
+ */
+ public HttpOutputStream(OutputStream out) {
+ super();
+ this.out = out;
+ }
+
+ /**
+ * On close, send HTTP-packaged response.
+ */
+ public synchronized void close() throws IOException {
+ if (!responseSent) {
+ /*
+ * If response would have zero content length, then make it
+ * have some arbitrary data so that certain clients will not
+ * fail because the "document contains no data".
+ */
+ if (size() == 0)
+ write(emptyData);
+
+ DataOutputStream dos = new DataOutputStream(out);
+ dos.writeBytes("Content-type: application/octet-stream\r\n");
+ dos.writeBytes("Content-length: " + size() + "\r\n");
+ dos.writeBytes("\r\n");
+ writeTo(dos);
+ dos.flush();
+ // Do not close the underlying stream here, because that would
+ // close the underlying socket and prevent reading a response.
+ reset(); // reset byte array
+ responseSent = true;
+ }
+ }
+
+ /** data to send if the response would otherwise be empty */
+ private static byte[] emptyData = { 0 };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1996, 2000, 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.Socket;
+import java.net.InetAddress;
+
+/**
+ * The HttpReceiveSocket class extends the WrappedSocket class
+ * by removing the HTTP protocol packaging from the input stream and
+ * formatting the output stream as an HTTP response.
+ *
+ * NOTES:
+ *
+ * The output stream must be explicitly closed for the output to be
+ * sent, since the HttpResponseOutputStream needs to buffer the entire
+ * transmission to be able to fill in the content-length field of
+ * the HTTP header. Closing this socket will do this.
+ *
+ * The constructor blocks until the HTTP protocol header
+ * is received. This could be fixed, but I don't think it should be a
+ * problem because this object would not be created unless the
+ * HttpAwareServerSocket has detected the beginning of the header
+ * anyway, so the rest should be there.
+ *
+ * This socket can only be used to process one POST and reply to it.
+ * Another message would be received on a newly accepted socket anyway.
+ */
+public class HttpReceiveSocket extends WrappedSocket implements RMISocketInfo {
+
+ /** true if the HTTP header has pushed through the output stream yet */
+ private boolean headerSent = false;
+
+ /**
+ * Layer on top of a pre-existing Socket object, and use specified
+ * input and output streams.
+ * @param socket the pre-existing socket to use
+ * @param in the InputStream to use for this socket (can be null)
+ * @param out the OutputStream to use for this socket (can be null)
+ */
+ public HttpReceiveSocket(Socket socket, InputStream in, OutputStream out)
+ throws IOException
+ {
+ super(socket, in, out);
+
+ this.in = new HttpInputStream(in != null ? in :
+ socket.getInputStream());
+ this.out = (out != null ? out :
+ socket.getOutputStream());
+ }
+
+ /**
+ * Indicate that this socket is not reusable.
+ */
+ public boolean isReusable()
+ {
+ return false;
+ }
+
+ /**
+ * Get the address to which this socket is connected. "null" is always
+ * returned (to indicate an unknown address) because the originating
+ * host's IP address cannot be reliably determined: both because the
+ * request probably went through a proxy server, and because if it was
+ * delivered by a local forwarder (CGI script or servlet), we do NOT
+ * want it to appear as if the call is coming from the local host (in
+ * case the remote object makes access control decisions based on the
+ * "client host" of a remote call; see bugid 4399040).
+ */
+ public InetAddress getInetAddress() {
+ return null;
+ }
+
+ /**
+ * Get an OutputStream for this socket.
+ */
+ public OutputStream getOutputStream() throws IOException
+ {
+ if (!headerSent) { // could this be done in constructor??
+ DataOutputStream dos = new DataOutputStream(out);
+ dos.writeBytes("HTTP/1.0 200 OK\r\n");
+ dos.flush();
+ headerSent = true;
+ out = new HttpOutputStream(out);
+ }
+ return out;
+ }
+
+ /**
+ * Close the socket.
+ */
+ public synchronized void close() throws IOException
+ {
+ getOutputStream().close(); // make sure response is sent
+ socket.close();
+ }
+
+ /**
+ * Return string representation of the socket.
+ */
+ public String toString()
+ {
+ return "HttpReceive" + socket.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1996, 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.*;
+
+/**
+ * The HttpSendInputStream class is used by the HttpSendSocket class as
+ * a layer on the top of the InputStream it returns so that it can be
+ * notified of attempts to read from it. This allows the HttpSendSocket
+ * to know when it should push across its output message.
+ */
+class HttpSendInputStream extends FilterInputStream {
+
+ /** the HttpSendSocket object that is providing this stream */
+ HttpSendSocket owner;
+
+ /**
+ * Create new filter on a given input stream.
+ * @param in the InputStream to filter from
+ * @param owner the HttpSendSocket that is providing this stream
+ */
+ public HttpSendInputStream(InputStream in, HttpSendSocket owner)
+ throws IOException
+ {
+ super(in);
+
+ this.owner = owner;
+ }
+
+ /**
+ * Mark this stream as inactive for its owner socket, so the next time
+ * a read is attempted, the owner will be notified and a new underlying
+ * input stream obtained.
+ */
+ public void deactivate()
+ {
+ in = null;
+ }
+
+ /**
+ * Read a byte of data from the stream.
+ */
+ public int read() throws IOException
+ {
+ if (in == null)
+ in = owner.readNotify();
+ return in.read();
+ }
+
+ /**
+ * Read into an array of bytes.
+ * @param b the buffer into which the data is to be read
+ * @param off the start offset of the data
+ * @param len the maximum number of bytes to read
+ */
+ public int read(byte b[], int off, int len) throws IOException
+ {
+ if (len == 0)
+ return 0;
+ if (in == null)
+ in = owner.readNotify();
+ return in.read(b, off, len);
+ }
+
+ /**
+ * Skip bytes of input.
+ * @param n the number of bytes to be skipped
+ */
+ public long skip(long n) throws IOException
+ {
+ if (n == 0)
+ return 0;
+ if (in == null)
+ in = owner.readNotify();
+ return in.skip(n);
+ }
+
+ /**
+ * Return the number of bytes that can be read without blocking.
+ */
+ public int available() throws IOException
+ {
+ if (in == null)
+ in = owner.readNotify();
+ return in.available();
+ }
+
+ /**
+ * Close the stream.
+ */
+ public void close() throws IOException
+ {
+ owner.close();
+ }
+
+ /**
+ * Mark the current position in the stream.
+ * @param readlimit how many bytes can be read before mark becomes invalid
+ */
+ public synchronized void mark(int readlimit)
+ {
+ if (in == null) {
+ try {
+ in = owner.readNotify();
+ }
+ catch (IOException e) {
+ return;
+ }
+ }
+ in.mark(readlimit);
+ }
+
+ /**
+ * Reposition the stream to the last marked position.
+ */
+ public synchronized void reset() throws IOException
+ {
+ if (in == null)
+ in = owner.readNotify();
+ in.reset();
+ }
+
+ /**
+ * Return true if this stream type supports mark/reset.
+ */
+ public boolean markSupported()
+ {
+ if (in == null) {
+ try {
+ in = owner.readNotify();
+ }
+ catch (IOException e) {
+ return false;
+ }
+ }
+ return in.markSupported();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 1996, 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.*;
+
+/**
+ * The HttpSendOutputStream class is used by the HttpSendSocket class as
+ * a layer on the top of the OutputStream it returns so that it can be
+ * notified of attempts to write to it. This allows the HttpSendSocket
+ * to know when it should construct a new message.
+ */
+class HttpSendOutputStream extends FilterOutputStream {
+
+ /** the HttpSendSocket object that is providing this stream */
+ HttpSendSocket owner;
+
+ /**
+ * Create new filter on a given output stream.
+ * @param out the OutputStream to filter from
+ * @param owner the HttpSendSocket that is providing this stream
+ */
+ public HttpSendOutputStream(OutputStream out, HttpSendSocket owner)
+ throws IOException
+ {
+ super(out);
+
+ this.owner = owner;
+ }
+
+ /**
+ * Mark this stream as inactive for its owner socket, so the next time
+ * a write is attempted, the owner will be notified and a new underlying
+ * output stream obtained.
+ */
+ public void deactivate()
+ {
+ out = null;
+ }
+
+ /**
+ * Write a byte of data to the stream.
+ */
+ public void write(int b) throws IOException
+ {
+ if (out == null)
+ out = owner.writeNotify();
+ out.write(b);
+ }
+
+ /**
+ * Write a subarray of bytes.
+ * @param b the buffer from which the data is to be written
+ * @param off the start offset of the data
+ * @param len the number of bytes to be written
+ */
+ public void write(byte b[], int off, int len) throws IOException
+ {
+ if (len == 0)
+ return;
+ if (out == null)
+ out = owner.writeNotify();
+ out.write(b, off, len);
+ }
+
+ /**
+ * Flush the stream.
+ */
+ public void flush() throws IOException
+ {
+ if (out != null)
+ out.flush();
+ }
+
+ /**
+ * Close the stream.
+ */
+ public void close() throws IOException
+ {
+ flush();
+ owner.close();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 1996, 2012, 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 java.security.PrivilegedAction;
+
+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(
+ (PrivilegedAction<String>) () -> System.getProperty("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 {
+ BufferedReader din = new BufferedReader(new InputStreamReader(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 + "]";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1996, 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.IOException;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.rmi.server.RMISocketFactory;
+
+/**
+ * RMIDirectSocketFactory creates a direct socket connection to the
+ * specified port on the specified host.
+ */
+public class RMIDirectSocketFactory extends RMISocketFactory {
+
+ public Socket createSocket(String host, int port) throws IOException
+ {
+ return new Socket(host, port);
+ }
+
+ public ServerSocket createServerSocket(int port) throws IOException
+ {
+ return new ServerSocket(port);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1998, 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.IOException;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.rmi.server.RMISocketFactory;
+
+/**
+ * RMIHttpToCGISocketFactory creates a socket connection to the
+ * specified host that is comminicated within an HTTP request,
+ * forwarded through the default firewall proxy, to the target host's
+ * normal HTTP server, to a CGI program which forwards the request to
+ * the actual specified port on the socket.
+ */
+public class RMIHttpToCGISocketFactory extends RMISocketFactory {
+
+ public Socket createSocket(String host, int port)
+ throws IOException
+ {
+ return new HttpSendSocket(host, port,
+ new URL("http", host,
+ "/cgi-bin/java-rmi.cgi" +
+ "?forward=" + port));
+ }
+
+ public ServerSocket createServerSocket(int port) throws IOException
+ {
+ return new HttpAwareServerSocket(port);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1998, 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.IOException;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.rmi.server.RMISocketFactory;
+
+/**
+ * RMIHttpToPortSocketFactory creates a socket connection to the
+ * specified host that is communicated within an HTTP request,
+ * forwarded through the default firewall proxy, directly to the
+ * specified port.
+ */
+public class RMIHttpToPortSocketFactory extends RMISocketFactory {
+
+ public Socket createSocket(String host, int port)
+ throws IOException
+ {
+ return new HttpSendSocket(host, port,
+ new URL("http", host, port, "/"));
+ }
+
+ public ServerSocket createServerSocket(int port)
+ throws IOException
+ {
+ return new HttpAwareServerSocket(port);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 1996, 2013, 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 java.security.*;
+import java.util.*;
+import java.rmi.server.LogStream;
+import java.rmi.server.RMISocketFactory;
+import sun.rmi.runtime.Log;
+import sun.rmi.runtime.NewThreadAction;
+
+/**
+ * RMIMasterSocketFactory attempts to create a socket connection to the
+ * specified host using successively less efficient mechanisms
+ * until one succeeds. If the host is successfully connected to,
+ * the factory for the successful mechanism is stored in an internal
+ * hash table keyed by the host name, so that future attempts to
+ * connect to the same host will automatically use the same
+ * mechanism.
+ */
+@SuppressWarnings("deprecation")
+public class RMIMasterSocketFactory extends RMISocketFactory {
+
+ /** "proxy" package log level */
+ static int logLevel = LogStream.parseLevel(getLogLevel());
+
+ private static String getLogLevel() {
+ return java.security.AccessController.doPrivileged(
+ (PrivilegedAction<String>) () -> System.getProperty("sun.rmi.transport.proxy.logLevel"));
+ }
+
+ /* proxy package log */
+ static final Log proxyLog =
+ Log.getLog("sun.rmi.transport.tcp.proxy",
+ "transport", RMIMasterSocketFactory.logLevel);
+
+ /** timeout for attemping direct socket connections */
+ private static long connectTimeout = getConnectTimeout();
+
+ private static long getConnectTimeout() {
+ return java.security.AccessController.doPrivileged((PrivilegedAction<Long>) () ->
+ Long.getLong("sun.rmi.transport.proxy.connectTimeout", 15000)); // default: 15 seconds
+ }
+
+ /** whether to fallback to HTTP on general connect failures */
+ private static final boolean eagerHttpFallback =
+ java.security.AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
+ Boolean.getBoolean("sun.rmi.transport.proxy.eagerHttpFallback"));
+
+ /** table of hosts successfully connected to and the factory used */
+ private Hashtable<String, RMISocketFactory> successTable =
+ new Hashtable<>();
+
+ /** maximum number of hosts to remember successful connection to */
+ private static final int MaxRememberedHosts = 64;
+
+ /** list of the hosts in successTable in initial connection order */
+ private Vector<String> hostList = new Vector<>(MaxRememberedHosts);
+
+ /** default factory for initial use for direct socket connection */
+ protected RMISocketFactory initialFactory = new RMIDirectSocketFactory();
+
+ /** ordered list of factories to try as alternate connection
+ * mechanisms if a direct socket connections fails */
+ protected Vector<RMISocketFactory> altFactoryList;
+
+ /**
+ * Create a RMIMasterSocketFactory object. Establish order of
+ * connection mechanisms to attempt on createSocket, if a direct
+ * socket connection fails.
+ */
+ public RMIMasterSocketFactory() {
+ altFactoryList = new Vector<>(2);
+ boolean setFactories = false;
+
+ try {
+ String proxyHost;
+ proxyHost = java.security.AccessController.doPrivileged(
+ (PrivilegedAction<String>) () -> System.getProperty("http.proxyHost"));
+
+ if (proxyHost == null)
+ proxyHost = java.security.AccessController.doPrivileged(
+ (PrivilegedAction<String>) () -> System.getProperty("proxyHost"));
+
+ boolean disable = java.security.AccessController.doPrivileged(
+ (PrivilegedAction<String>) () -> System.getProperty("java.rmi.server.disableHttp", "true"))
+ .equalsIgnoreCase("true");
+
+ if (!disable && proxyHost != null && proxyHost.length() > 0) {
+ setFactories = true;
+ }
+ } catch (Exception e) {
+ // unable to obtain the properties, so use the default behavior.
+ }
+
+ if (setFactories) {
+ altFactoryList.addElement(new RMIHttpToPortSocketFactory());
+ altFactoryList.addElement(new RMIHttpToCGISocketFactory());
+ }
+ }
+
+ /**
+ * Create a new client socket. If we remember connecting to this host
+ * successfully before, then use the same factory again. Otherwise,
+ * try using a direct socket connection and then the alternate factories
+ * in the order specified in altFactoryList.
+ */
+ public Socket createSocket(String host, int port)
+ throws IOException
+ {
+ if (proxyLog.isLoggable(Log.BRIEF)) {
+ proxyLog.log(Log.BRIEF, "host: " + host + ", port: " + port);
+ }
+
+ /*
+ * If we don't have any alternate factories to consult, short circuit
+ * the fallback procedure and delegate to the initial factory.
+ */
+ if (altFactoryList.size() == 0) {
+ return initialFactory.createSocket(host, port);
+ }
+
+ RMISocketFactory factory;
+
+ /*
+ * If we remember successfully connecting to this host before,
+ * use the same factory.
+ */
+ factory = successTable.get(host);
+ if (factory != null) {
+ if (proxyLog.isLoggable(Log.BRIEF)) {
+ proxyLog.log(Log.BRIEF,
+ "previously successful factory found: " + factory);
+ }
+ return factory.createSocket(host, port);
+ }
+
+ /*
+ * Next, try a direct socket connection. Open socket in another
+ * thread and only wait for specified timeout, in case the socket
+ * would otherwise spend minutes trying an unreachable host.
+ */
+ Socket initialSocket = null;
+ Socket fallbackSocket = null;
+ final AsyncConnector connector =
+ new AsyncConnector(initialFactory, host, port,
+ AccessController.getContext());
+ // connection must be attempted with
+ // this thread's access control context
+ IOException initialFailure = null;
+
+ try {
+ synchronized (connector) {
+
+ Thread t = java.security.AccessController.doPrivileged(
+ new NewThreadAction(connector, "AsyncConnector", true));
+ t.start();
+
+ try {
+ long now = System.currentTimeMillis();
+ long deadline = now + connectTimeout;
+ do {
+ connector.wait(deadline - now);
+ initialSocket = checkConnector(connector);
+ if (initialSocket != null)
+ break;
+ now = System.currentTimeMillis();
+ } while (now < deadline);
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException(
+ "interrupted while waiting for connector");
+ }
+ }
+
+ // assume no route to host (for now) if no connection yet
+ if (initialSocket == null)
+ throw new NoRouteToHostException(
+ "connect timed out: " + host);
+
+ proxyLog.log(Log.BRIEF, "direct socket connection successful");
+
+ return initialSocket;
+
+ } catch (UnknownHostException | NoRouteToHostException e) {
+ initialFailure = e;
+ } catch (SocketException e) {
+ if (eagerHttpFallback) {
+ initialFailure = e;
+ } else {
+ throw e;
+ }
+ } finally {
+ if (initialFailure != null) {
+
+ if (proxyLog.isLoggable(Log.BRIEF)) {
+ proxyLog.log(Log.BRIEF,
+ "direct socket connection failed: ", initialFailure);
+ }
+
+ // Finally, try any alternate connection mechanisms.
+ for (int i = 0; i < altFactoryList.size(); ++ i) {
+ factory = altFactoryList.elementAt(i);
+ if (proxyLog.isLoggable(Log.BRIEF)) {
+ proxyLog.log(Log.BRIEF,
+ "trying with factory: " + factory);
+ }
+ try (Socket testSocket =
+ factory.createSocket(host, port)) {
+ // For HTTP connections, the output (POST request) must
+ // be sent before we verify a successful connection.
+ // So, sacrifice a socket for the sake of testing...
+ // The following sequence should verify a successful
+ // HTTP connection if no IOException is thrown.
+ InputStream in = testSocket.getInputStream();
+ int b = in.read(); // probably -1 for EOF...
+ } catch (IOException ex) {
+ if (proxyLog.isLoggable(Log.BRIEF)) {
+ proxyLog.log(Log.BRIEF, "factory failed: ", ex);
+ }
+
+ continue;
+ }
+ proxyLog.log(Log.BRIEF, "factory succeeded");
+
+ // factory succeeded, open new socket for caller's use
+ try {
+ fallbackSocket = factory.createSocket(host, port);
+ } catch (IOException ex) { // if it fails 2nd time,
+ } // just give up
+ break;
+ }
+ }
+ }
+
+ synchronized (successTable) {
+ try {
+ // check once again to see if direct connection succeeded
+ synchronized (connector) {
+ initialSocket = checkConnector(connector);
+ }
+ if (initialSocket != null) {
+ // if we had made another one as well, clean it up...
+ if (fallbackSocket != null)
+ fallbackSocket.close();
+ return initialSocket;
+ }
+ // if connector ever does get socket, it won't be used
+ connector.notUsed();
+ } catch (UnknownHostException | NoRouteToHostException e) {
+ initialFailure = e;
+ } catch (SocketException e) {
+ if (eagerHttpFallback) {
+ initialFailure = e;
+ } else {
+ throw e;
+ }
+ }
+ // if we had found an alternate mechanism, go and use it
+ if (fallbackSocket != null) {
+ // remember this successful host/factory pair
+ rememberFactory(host, factory);
+ return fallbackSocket;
+ }
+ throw initialFailure;
+ }
+ }
+
+ /**
+ * Remember a successful factory for connecting to host.
+ * Currently, excess hosts are removed from the remembered list
+ * using a Least Recently Created strategy.
+ */
+ void rememberFactory(String host, RMISocketFactory factory) {
+ synchronized (successTable) {
+ while (hostList.size() >= MaxRememberedHosts) {
+ successTable.remove(hostList.elementAt(0));
+ hostList.removeElementAt(0);
+ }
+ hostList.addElement(host);
+ successTable.put(host, factory);
+ }
+ }
+
+ /**
+ * Check if an AsyncConnector succeeded. If not, return socket
+ * given to fall back to.
+ */
+ Socket checkConnector(AsyncConnector connector)
+ throws IOException
+ {
+ Exception e = connector.getException();
+ if (e != null) {
+ e.fillInStackTrace();
+ /*
+ * The AsyncConnector implementation guaranteed that the exception
+ * will be either an IOException or a RuntimeException, and we can
+ * only throw one of those, so convince that compiler that it must
+ * be one of those.
+ */
+ if (e instanceof IOException) {
+ throw (IOException) e;
+ } else if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ } else {
+ throw new Error("internal error: " +
+ "unexpected checked exception: " + e.toString());
+ }
+ }
+ return connector.getSocket();
+ }
+
+ /**
+ * Create a new server socket.
+ */
+ public ServerSocket createServerSocket(int port) throws IOException {
+ //return new HttpAwareServerSocket(port);
+ return initialFactory.createServerSocket(port);
+ }
+
+
+ /**
+ * AsyncConnector is used by RMIMasterSocketFactory to attempt socket
+ * connections on a separate thread. This allows RMIMasterSocketFactory
+ * to control how long it will wait for the connection to succeed.
+ */
+ private class AsyncConnector implements Runnable {
+
+ /** what factory to use to attempt connection */
+ private RMISocketFactory factory;
+
+ /** the host to connect to */
+ private String host;
+
+ /** the port to connect to */
+ private int port;
+
+ /** access control context to attempt connection within */
+ private AccessControlContext acc;
+
+ /** exception that occurred during connection, if any */
+ private Exception exception = null;
+
+ /** the connected socket, if successful */
+ private Socket socket = null;
+
+ /** socket should be closed after created, if ever */
+ private boolean cleanUp = false;
+
+ /**
+ * Create a new asynchronous connector object.
+ */
+ AsyncConnector(RMISocketFactory factory, String host, int port,
+ AccessControlContext acc)
+ {
+ this.factory = factory;
+ this.host = host;
+ this.port = port;
+ this.acc = acc;
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkConnect(host, port);
+ }
+ }
+
+ /**
+ * Attempt socket connection in separate thread. If successful,
+ * notify master waiting,
+ */
+ public void run() {
+ try {
+ /*
+ * Using the privileges of the thread that wants to make the
+ * connection is tempting, but it will fail with applets with
+ * the current applet security manager because the applet
+ * network connection policy is not captured in the permission
+ * framework of the access control context we have.
+ *
+ * java.security.AccessController.beginPrivileged(acc);
+ */
+ try {
+ Socket temp = factory.createSocket(host, port);
+ synchronized (this) {
+ socket = temp;
+ notify();
+ }
+ rememberFactory(host, factory);
+ synchronized (this) {
+ if (cleanUp)
+ try {
+ socket.close();
+ } catch (IOException e) {
+ }
+ }
+ } catch (Exception e) {
+ /*
+ * Note that the only exceptions which could actually have
+ * occurred here are IOException or RuntimeException.
+ */
+ synchronized (this) {
+ exception = e;
+ notify();
+ }
+ }
+ } finally {
+ /*
+ * See above comments for matching beginPrivileged() call that
+ * is also commented out.
+ *
+ * java.security.AccessController.endPrivileged();
+ */
+ }
+ }
+
+ /**
+ * Get exception that occurred during connection attempt, if any.
+ * In the current implementation, this is guaranteed to be either
+ * an IOException or a RuntimeException.
+ */
+ private synchronized Exception getException() {
+ return exception;
+ }
+
+ /**
+ * Get successful socket, if any.
+ */
+ private synchronized Socket getSocket() {
+ return socket;
+ }
+
+ /**
+ * Note that this connector's socket, if ever successfully created,
+ * will not be used, so it should be cleaned up quickly
+ */
+ synchronized void notUsed() {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ }
+ }
+ cleanUp = true;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1996, 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;
+
+/**
+ * RMISocketInfo is an interface that extensions of the java.net.Socket
+ * class may use to provide more information on its capabilities.
+ */
+public interface RMISocketInfo {
+
+ /**
+ * Return true if this socket can be used for more than one
+ * RMI call. If a socket does not implement this interface, then
+ * it is assumed to be reusable.
+ */
+ public boolean isReusable();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 1996, 2013, 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.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The WrappedSocket class provides a general wrapper for providing an
+ * extended implementation of java.net.Socket that can be attached to
+ * a pre-existing Socket object. WrappedSocket itself provides a
+ * constructor for specifying alternate input or output streams to be
+ * returned than those of the underlying Socket.
+ */
+class WrappedSocket extends Socket {
+
+ /** the underlying concrete socket */
+ protected Socket socket;
+
+ /** the input stream to return for socket */
+ protected InputStream in = null;
+
+ /** the output stream to return for socket */
+ protected OutputStream out = null;
+
+ /**
+ * Layer on top of a pre-existing Socket object, and use specified
+ * input and output streams. This allows the creator of the
+ * underlying socket to peek at the beginning of the input with a
+ * BufferedInputStream and determine which kind of socket
+ * to create, without consuming the input.
+ * @param socket the pre-existing socket to use
+ * @param in the InputStream to return to users (can be null)
+ * @param out the OutputStream to return to users (can be null)
+ */
+ public WrappedSocket(Socket socket, InputStream in, OutputStream out)
+ throws IOException
+ {
+ super((java.net.SocketImpl)null); // no underlying SocketImpl for this object
+ this.socket = socket;
+ this.in = in;
+ this.out = out;
+ }
+
+ /**
+ * Get the address to which the socket is connected.
+ */
+ public InetAddress getInetAddress()
+ {
+ return socket.getInetAddress();
+ }
+
+ /**
+ * Get the local address to which the socket is bound.
+ */
+ public InetAddress getLocalAddress() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<InetAddress>() {
+ @Override
+ public InetAddress run() {
+ return socket.getLocalAddress();
+
+ }
+ });
+ }
+
+ /**
+ * Get the remote port to which the socket is connected.
+ */
+ public int getPort()
+ {
+ return socket.getPort();
+ }
+
+ /**
+ * Get the local port to which the socket is connected.
+ */
+ public int getLocalPort()
+ {
+ return socket.getLocalPort();
+ }
+
+ /**
+ * Get an InputStream for this socket.
+ */
+ public InputStream getInputStream() throws IOException
+ {
+ if (in == null)
+ in = socket.getInputStream();
+ return in;
+ }
+
+ /**
+ * Get an OutputStream for this socket.
+ */
+ public OutputStream getOutputStream() throws IOException
+ {
+ if (out == null)
+ out = socket.getOutputStream();
+ return out;
+ }
+
+ /**
+ * Enable/disable TCP_NODELAY.
+ */
+ public void setTcpNoDelay(boolean on) throws SocketException
+ {
+ socket.setTcpNoDelay(on);
+ }
+
+ /**
+ * Retrieve whether TCP_NODELAY is enabled.
+ */
+ public boolean getTcpNoDelay() throws SocketException
+ {
+ return socket.getTcpNoDelay();
+ }
+
+ /**
+ * Enable/disable SO_LINGER with the specified linger time.
+ */
+ public void setSoLinger(boolean on, int val) throws SocketException
+ {
+ socket.setSoLinger(on, val);
+ }
+
+ /**
+ * Retrive setting for SO_LINGER.
+ */
+ public int getSoLinger() throws SocketException
+ {
+ return socket.getSoLinger();
+ }
+
+ /**
+ * Enable/disable SO_TIMEOUT with the specified timeout
+ */
+ public synchronized void setSoTimeout(int timeout) throws SocketException
+ {
+ socket.setSoTimeout(timeout);
+ }
+
+ /**
+ * Retrive setting for SO_TIMEOUT.
+ */
+ public synchronized int getSoTimeout() throws SocketException
+ {
+ return socket.getSoTimeout();
+ }
+
+ /**
+ * Close the socket.
+ */
+ public synchronized void close() throws IOException
+ {
+ socket.close();
+ }
+
+ /**
+ * Return string representation of the socket.
+ */
+ public String toString()
+ {
+ return "Wrapped" + socket.toString();
+ }
+}
--- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java Tue Apr 26 17:35:10 2016 -0400
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java Tue Apr 26 21:25:18 2016 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2001, 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
@@ -26,10 +26,14 @@
package sun.rmi.transport.tcp;
import java.io.*;
+import java.net.InetAddress;
import java.net.Socket;
+import java.net.SocketException;
import java.rmi.*;
+import java.rmi.server.RMISocketFactory;
import sun.rmi.runtime.Log;
import sun.rmi.transport.*;
+import sun.rmi.transport.proxy.*;
public class TCPConnection implements Connection {
@@ -116,7 +120,10 @@
*/
public boolean isReusable()
{
- return true;
+ if ((socket != null) && (socket instanceof RMISocketInfo))
+ return ((RMISocketInfo) socket).isReusable();
+ else
+ return true;
}
/**
--- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java Tue Apr 26 17:35:10 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 1996, 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.tcp;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.net.ServerSocket;
-import java.rmi.server.RMISocketFactory;
-
-/**
- * RMIDirectSocketFactory creates a direct socket connection to the
- * specified port on the specified host.
- */
-public class TCPDirectSocketFactory extends RMISocketFactory {
-
- public Socket createSocket(String host, int port) throws IOException
- {
- return new Socket(host, port);
- }
-
- public ServerSocket createServerSocket(int port) throws IOException
- {
- return new ServerSocket(port);
- }
-}
--- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java Tue Apr 26 17:35:10 2016 -0400
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java Tue Apr 26 21:25:18 2016 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, 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
@@ -75,6 +75,7 @@
import sun.rmi.transport.Target;
import sun.rmi.transport.Transport;
import sun.rmi.transport.TransportConstants;
+import sun.rmi.transport.proxy.HttpReceiveSocket;
/**
* TCPTransport is the socket-based implementation of the RMI Transport
@@ -710,10 +711,35 @@
? sockIn
: new BufferedInputStream(sockIn);
- // Read magic
+ // Read magic (or HTTP wrapper)
+ bufIn.mark(4);
DataInputStream in = new DataInputStream(bufIn);
int magic = in.readInt();
+ if (magic == POST) {
+ tcpLog.log(Log.BRIEF, "decoding HTTP-wrapped call");
+
+ // It's really a HTTP-wrapped request. Repackage
+ // the socket in a HttpReceiveSocket, reinitialize
+ // sockIn and in, and reread magic.
+ bufIn.reset(); // unread "POST"
+
+ try {
+ socket = new HttpReceiveSocket(socket, bufIn, null);
+ remoteHost = "0.0.0.0";
+ sockIn = socket.getInputStream();
+ bufIn = new BufferedInputStream(sockIn);
+ in = new DataInputStream(bufIn);
+ magic = in.readInt();
+
+ } catch (IOException e) {
+ throw new RemoteException("Error HTTP-unwrapping call",
+ e);
+ }
+ }
+ // bufIn's mark will invalidate itself when it overflows
+ // so it doesn't have to be turned off
+
// read and verify transport header
short version = in.readShort();
if (magic != TransportConstants.Magic ||
--- a/jdk/test/ProblemList.txt Tue Apr 26 17:35:10 2016 -0400
+++ b/jdk/test/ProblemList.txt Tue Apr 26 21:25:18 2016 -0400
@@ -191,6 +191,8 @@
java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 7191877 generic-all
+sun/rmi/transport/proxy/EagerHttpFallback.java 7195095 generic-all
+
java/rmi/activation/Activatable/extLoadedImpl/ext.sh 8062724 generic-all
sun/rmi/rmic/newrmic/equivalence/run.sh 8145980 generic-all
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1999, 2012, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ *
+ * @summary HttpSocket functionality test
+ * @author Dana Burns
+ *
+ * @library ../../testlibrary
+ * @modules java.rmi/sun.rmi.registry
+ * java.rmi/sun.rmi.server
+ * java.rmi/sun.rmi.transport
+ * java.rmi/sun.rmi.transport.proxy
+ * java.rmi/sun.rmi.transport.tcp
+ * @build TestLibrary HttpSocketTest HttpSocketTest_Stub
+ * @run main/othervm/policy=security.policy HttpSocketTest
+ */
+
+/*
+ * This test assures remote methods can be carried out over RMI.
+ * After setting the RMI runtime socket factory to the http proxy version,
+ * a registry is created, a remote object (an instance of this class) is
+ * registered with it, and then it is exercised.
+ */
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.Naming;
+import java.rmi.RMISecurityManager;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMISocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import sun.rmi.transport.proxy.RMIHttpToPortSocketFactory;
+
+interface MyRemoteInterface extends Remote {
+ void setRemoteObject( Remote r ) throws RemoteException;
+ Remote getRemoteObject() throws RemoteException;
+}
+
+public class HttpSocketTest extends UnicastRemoteObject
+ implements MyRemoteInterface
+{
+ private static final String NAME = "HttpSocketTest";
+
+ public HttpSocketTest() throws RemoteException{}
+
+ private Remote ro;
+
+ public static void main(String[] args)
+ throws Exception
+ {
+
+ Registry registry = null;
+
+ TestLibrary.suggestSecurityManager(null);
+
+ // Set the socket factory.
+ System.err.println("installing socket factory");
+ RMISocketFactory.setSocketFactory(new RMIHttpToPortSocketFactory());
+ int registryPort = -1;
+
+ try {
+ System.err.println("Starting registry");
+ registry = TestLibrary.createRegistryOnUnusedPort();
+ registryPort = TestLibrary.getRegistryPort(registry);
+ } catch (Exception e) {
+ TestLibrary.bomb(e);
+ }
+
+ try {
+ registry.rebind( NAME, new HttpSocketTest() );
+ MyRemoteInterface httpTest =
+ (MyRemoteInterface)Naming.lookup("//:" + registryPort + "/" + NAME);
+ httpTest.setRemoteObject( new HttpSocketTest() );
+ Remote r = httpTest.getRemoteObject();
+
+ } catch (Exception e) {
+ TestLibrary.bomb(e);
+ }
+
+
+ }
+
+ public void setRemoteObject( Remote ro ) throws RemoteException {
+ this.ro = ro;
+ }
+
+ public Remote getRemoteObject() throws RemoteException {
+ return( this.ro );
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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.
+ */
+
+// Stub class generated by rmic, do not edit.
+// Contents subject to change without notice.
+
+public final class HttpSocketTest_Stub
+ extends java.rmi.server.RemoteStub
+ implements MyRemoteInterface, java.rmi.Remote
+{
+ private static final java.rmi.server.Operation[] operations = {
+ new java.rmi.server.Operation("java.rmi.Remote getRemoteObject()"),
+ new java.rmi.server.Operation("void setRemoteObject(java.rmi.Remote)")
+ };
+
+ private static final long interfaceHash = 3775375480010579665L;
+
+ private static final long serialVersionUID = 2;
+
+ private static boolean useNewInvoke;
+ private static java.lang.reflect.Method $method_getRemoteObject_0;
+ private static java.lang.reflect.Method $method_setRemoteObject_1;
+
+ static {
+ try {
+ java.rmi.server.RemoteRef.class.getMethod("invoke",
+ new java.lang.Class[] {
+ java.rmi.Remote.class,
+ java.lang.reflect.Method.class,
+ java.lang.Object[].class,
+ long.class
+ });
+ useNewInvoke = true;
+ $method_getRemoteObject_0 = MyRemoteInterface.class.getMethod("getRemoteObject", new java.lang.Class[] {});
+ $method_setRemoteObject_1 = MyRemoteInterface.class.getMethod("setRemoteObject", new java.lang.Class[] {java.rmi.Remote.class});
+ } catch (java.lang.NoSuchMethodException e) {
+ useNewInvoke = false;
+ }
+ }
+
+ // constructors
+ public HttpSocketTest_Stub() {
+ super();
+ }
+ public HttpSocketTest_Stub(java.rmi.server.RemoteRef ref) {
+ super(ref);
+ }
+
+ // methods from remote interfaces
+
+ // implementation of getRemoteObject()
+ public java.rmi.Remote getRemoteObject()
+ throws java.rmi.RemoteException
+ {
+ try {
+ if (useNewInvoke) {
+ Object $result = ref.invoke(this, $method_getRemoteObject_0, null, -2578437860804964265L);
+ return ((java.rmi.Remote) $result);
+ } else {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+ ref.invoke(call);
+ java.rmi.Remote $result;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $result = (java.rmi.Remote) in.readObject();
+ } catch (java.io.IOException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } catch (java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } finally {
+ ref.done(call);
+ }
+ return $result;
+ }
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of setRemoteObject(Remote)
+ public void setRemoteObject(java.rmi.Remote $param_Remote_1)
+ throws java.rmi.RemoteException
+ {
+ try {
+ if (useNewInvoke) {
+ ref.invoke(this, $method_setRemoteObject_1, new java.lang.Object[] {$param_Remote_1}, -7518632118115022871L);
+ } else {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_Remote_1);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ ref.done(call);
+ }
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/transport/httpSocket/security.policy Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,10 @@
+
+grant {
+ permission java.net.SocketPermission "*:1024-", "accept,connect,listen";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.proxy";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp";
+ permission java.lang.RuntimePermission "setFactory";
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 8023862
+ * @summary Verify that the default value of the java.rmi.server.disableHttp
+ * has been changed from false to true.
+ * @modules java.rmi/sun.rmi.transport.proxy
+ * @compile -XDignore.symbol.file DisableHttpDefaultValue.java
+ *
+ * @run main/othervm DisableHttpDefaultValue true
+ * @run main/othervm -Djava.rmi.server.disableHttp DisableHttpDefaultValue false
+ * @run main/othervm -Djava.rmi.server.disableHttp=false DisableHttpDefaultValue false
+ * @run main/othervm -Djava.rmi.server.disableHttp=xyzzy DisableHttpDefaultValue false
+ * @run main/othervm -Djava.rmi.server.disableHttp=true DisableHttpDefaultValue true
+ */
+
+import sun.rmi.transport.proxy.RMIMasterSocketFactory;
+
+public class DisableHttpDefaultValue {
+ /**
+ * Subclass RMIMasterSocketFactory to get access to
+ * protected field altFactoryList. This list has a
+ * zero size if proxying is disabled.
+ */
+ static class SocketFactory extends RMIMasterSocketFactory {
+ boolean proxyDisabled() {
+ return altFactoryList.size() == 0;
+ }
+ }
+
+ /**
+ * Takes a single arg, which is the expected boolean value of
+ * java.rmi.server.disableHttp.
+ */
+ public static void main(String[] args) throws Exception {
+ // Force there to be a proxy host, so that we are able to
+ // tell whether proxying is enabled or disabled.
+ System.setProperty("http.proxyHost", "proxy.example.com");
+
+ String propval = System.getProperty("java.rmi.server.disableHttp");
+ String propdisp = (propval == null) ? "null" : ("\"" + propval + "\"");
+ boolean expected = Boolean.parseBoolean(args[0]);
+ boolean actual = new SocketFactory().proxyDisabled();
+ System.out.printf("### prop=%s exp=%s act=%s%n", propdisp, expected, actual);
+ if (expected != actual)
+ throw new AssertionError();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002, 2012, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 4290727
+ * @summary Verify that ConnectException will trigger HTTP fallback if
+ * sun.rmi.transport.proxy.eagerHttpFallback system property is set.
+ *
+ * @library ../../../../java/rmi/testlibrary
+ * @modules java.rmi/sun.rmi.registry
+ * java.rmi/sun.rmi.server
+ * java.rmi/sun.rmi.transport
+ * java.rmi/sun.rmi.transport.tcp
+ * @build TestLibrary
+ * @run main/othervm EagerHttpFallback
+ */
+
+import java.rmi.*;
+import java.rmi.registry.*;
+
+public class EagerHttpFallback {
+
+ static final int INITIAL_PORT = TestLibrary.getUnusedRandomPort();
+ static final int FALLBACK_PORT = TestLibrary.getUnusedRandomPort();
+
+ public static void main(String[] args) throws Exception {
+ System.setProperty("http.proxyHost", "127.0.0.1");
+ System.setProperty("http.proxyPort", Integer.toString(FALLBACK_PORT));
+ System.setProperty("sun.rmi.transport.proxy.eagerHttpFallback",
+ "true");
+ LocateRegistry.createRegistry(FALLBACK_PORT);
+
+ /*
+ * The call below should trigger a ConnectException in the
+ * RMIMasterSocketFactory when it attempts a direct connection to
+ * INITIAL_PORT, which no one is listening on. Since
+ * eagerHttpFallback is set, this ConnectException should trigger HTTP
+ * fallback, which will send a call through the HTTP proxy, which is
+ * configured to be localhost with a port behind which a registry is
+ * listening--so if fallback works properly, the list() call should
+ * succeed.
+ */
+ try {
+ LocateRegistry.getRegistry(INITIAL_PORT).list();
+ } catch (Exception e) {
+ System.err.println(
+ "call on registry stub with port " + INITIAL_PORT +
+ "did not successfully perform HTTP fallback to " +
+ FALLBACK_PORT);
+ throw e;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1999, 2012, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 4203167
+ *
+ * @summary RMI blocks in HttpAwareServerSocket.accept() if you telnet to it
+ * @author Adrian Colley
+ *
+ * @library ../../../../../java/rmi/testlibrary
+ * @modules java.rmi/sun.rmi.transport.proxy
+ * @build TestIface TestImpl TestImpl_Stub
+ * @run main/othervm/policy=security.policy/timeout=60 BlockAcceptTest
+ */
+
+/* This test attempts to stymie the RMI accept loop. The accept loop in
+ * RMI endlessly accepts a connection, spawns a thread for it, and repeats.
+ * The accept() call can be replaced by a user-supplied library which
+ * might foolishly block indefinitely in its accept() method, which would
+ * prevent RMI from accepting other connections on that socket.
+ *
+ * Unfortunately, HttpAwareServerSocket (default server socket) is/was such
+ * a foolish thing. It reads 4 bytes to see if they're "POST" before
+ * returning. The bug fix is to move the HTTP stuff into the mainloop,
+ * which has the side effect of enabling it for non-default socketfactories.
+ *
+ * This test:
+ * 1. Creates an object and exports it.
+ * 2. Connects to the listening RMI port and sends nothing, to hold it up.
+ * 3. Makes a regular call, using HTTP tunnelling.
+ * 4. Fails to deadlock, thereby passing the test.
+ *
+ * Some runtime dependencies I'm trying to eliminate:
+ * 1. We don't know the port number until after exporting the object, but
+ * have to set it in http.proxyPort somehow. Hopefully http.proxyPort
+ * isn't read too soon or this test will fail with a ConnectException.
+ */
+
+import java.rmi.*;
+import java.rmi.server.RMISocketFactory;
+import java.io.*;
+import java.net.*;
+
+import sun.rmi.transport.proxy.RMIMasterSocketFactory;
+import sun.rmi.transport.proxy.RMIHttpToPortSocketFactory;
+
+public class BlockAcceptTest
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ // Make trouble for ourselves
+ if (System.getSecurityManager() == null)
+ System.setSecurityManager(new RMISecurityManager());
+
+ // HTTP direct to the server port
+ System.setProperty("http.proxyHost", "127.0.0.1");
+
+ // Set the socket factory.
+ System.err.println("(installing HTTP-out socket factory)");
+ HttpOutFactory fac = new HttpOutFactory();
+ RMISocketFactory.setSocketFactory(fac);
+
+ // Create remote object
+ TestImpl impl = new TestImpl();
+
+ // Export and get which port.
+ System.err.println("(exporting remote object)");
+ TestIface stub = impl.export();
+ try {
+ int port = fac.whichPort();
+
+ // Sanity
+ if (port == 0)
+ throw new Error("TEST FAILED: export didn't reserve a port(?)");
+
+ // Set the HTTP port, at last.
+ System.setProperty("http.proxyPort", port+"");
+
+ // Now, connect to that port
+ //Thread.sleep(2000);
+ System.err.println("(connecting to listening port on 127.0.0.1:" +
+ port + ")");
+ Socket DoS = new Socket("127.0.0.1", port);
+ // we hold the connection open until done with the test.
+
+ // The test itself: make a remote call and see if it's blocked or
+ // if it works
+ //Thread.sleep(2000);
+ System.err.println("(making RMI-through-HTTP call)");
+ System.err.println("(typical test failure deadlocks here)");
+ String result = stub.testCall("dummy load");
+
+ System.err.println(" => " + result);
+ if (!("OK".equals(result)))
+ throw new Error("TEST FAILED: result not OK");
+ System.err.println("Test passed.");
+
+ // Clean up, including writing a byte to that connection just in
+ // case an optimizer thought of optimizing it out of existence
+ try {
+ DoS.getOutputStream().write(0);
+ DoS.getOutputStream().close();
+ } catch (Throwable apathy) {
+ }
+
+ } finally {
+ try {
+ impl.unexport();
+ } catch (Throwable unmatter) {
+ }
+ }
+
+ // Should exit here
+ }
+
+ private static class HttpOutFactory
+ extends RMISocketFactory
+ {
+ private int servport = 0;
+
+ public Socket createSocket(String h, int p)
+ throws IOException
+ {
+ return ((new RMIHttpToPortSocketFactory()).createSocket(h, p));
+ }
+
+ /** Create a server socket and remember which port it's on.
+ * Aborts if createServerSocket(0) is called twice, because then
+ * it doesn't know whether to remember the first or second port.
+ */
+ public ServerSocket createServerSocket(int p)
+ throws IOException
+ {
+ ServerSocket ss;
+ ss = (new RMIMasterSocketFactory()).createServerSocket(p);
+ if (p == 0) {
+ if (servport != 0) {
+ System.err.println("TEST FAILED: " +
+ "Duplicate createServerSocket(0)");
+ throw new Error("Test aborted (createServerSocket)");
+ }
+ servport = ss.getLocalPort();
+ }
+ return (ss);
+ }
+
+ /** Return which port was reserved by createServerSocket(0).
+ * If the return value was 0, createServerSocket(0) wasn't called.
+ */
+ public int whichPort() {
+ return (servport);
+ }
+ } // end class HttpOutFactory
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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.
+ */
+
+import java.rmi.*;
+
+public interface TestIface
+ extends Remote
+{
+ public String testCall(String ign)
+ throws RemoteException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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.
+ */
+
+import java.rmi.*;
+import java.rmi.server.*;
+
+public class TestImpl
+ extends Object
+ implements TestIface
+{
+ public TestImpl() {
+ }
+
+ public TestIface export()
+ throws RemoteException
+ {
+ return (TestIface)UnicastRemoteObject.exportObject(this);
+ }
+
+ public void unexport()
+ throws NoSuchObjectException
+ {
+ UnicastRemoteObject.unexportObject(this, true);
+ }
+
+ public String testCall(String ign) {
+ return ("OK");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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.
+ */
+
+// Stub class generated by rmic, do not edit.
+// Contents subject to change without notice.
+
+public final class TestImpl_Stub
+ extends java.rmi.server.RemoteStub
+ implements TestIface
+{
+ private static final long serialVersionUID = 2;
+
+ private static java.lang.reflect.Method $method_testCall_0;
+
+ static {
+ try {
+ $method_testCall_0 = TestIface.class.getMethod("testCall", new java.lang.Class[] {java.lang.String.class});
+ } catch (java.lang.NoSuchMethodException e) {
+ throw new java.lang.NoSuchMethodError(
+ "stub class initialization failed");
+ }
+ }
+
+ // constructors
+ public TestImpl_Stub(java.rmi.server.RemoteRef ref) {
+ super(ref);
+ }
+
+ // methods from remote interfaces
+
+ // implementation of testCall(String)
+ public java.lang.String testCall(java.lang.String $param_String_1)
+ throws java.rmi.RemoteException
+ {
+ try {
+ Object $result = ref.invoke(this, $method_testCall_0, new java.lang.Object[] {$param_String_1}, -4495720265115653109L);
+ return ((java.lang.String) $result);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy Tue Apr 26 21:25:18 2016 -0400
@@ -0,0 +1,10 @@
+grant {
+ // Take this out once we can specify -Djava.security.debug on
+ // the run line and figure out what else is needed
+ permission java.security.AllPermission;
+
+ permission java.net.SocketPermission "*:1024-65535", "connect,listen";
+ permission java.util.PropertyPermission "http.proxyHost", "write";
+ permission java.util.PropertyPermission "http.proxyPort", "write";
+ permission java.lang.RuntimePermission "setFactory";
+};