8155182: fix to JDK-8066750 broke jdk9 builds
authorrriggs
Tue, 26 Apr 2016 21:25:18 -0400
changeset 37667 6d042f115c35
parent 37666 71d351269690
child 37668 34a002e5168a
8155182: fix to JDK-8066750 broke jdk9 builds Summary: Restore RMI Http Proxy support for now Reviewed-by: darcy, lancea, smarks
jdk/src/java.rmi/share/classes/java/rmi/server/RMISocketFactory.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/CGIHandler.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpAwareServerSocket.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpOutputStream.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpReceiveSocket.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendInputStream.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendOutputStream.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpSendSocket.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIDirectSocketFactory.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToCGISocketFactory.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIHttpToPortSocketFactory.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMISocketInfo.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/WrappedSocket.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java
jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java
jdk/test/ProblemList.txt
jdk/test/java/rmi/transport/httpSocket/HttpSocketTest.java
jdk/test/java/rmi/transport/httpSocket/HttpSocketTest_Stub.java
jdk/test/java/rmi/transport/httpSocket/security.policy
jdk/test/sun/rmi/transport/proxy/DisableHttpDefaultValue.java
jdk/test/sun/rmi/transport/proxy/EagerHttpFallback.java
jdk/test/sun/rmi/transport/tcp/blockAccept/BlockAcceptTest.java
jdk/test/sun/rmi/transport/tcp/blockAccept/TestIface.java
jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl.java
jdk/test/sun/rmi/transport/tcp/blockAccept/TestImpl_Stub.java
jdk/test/sun/rmi/transport/tcp/blockAccept/security.policy
--- 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";
+};