Showing the changes to java/pkg/sun/rmi/transport/proxy/HttpSendSocket.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,343 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||
| 7 | * published by the Free Software Foundation. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | package sun.rmi.transport.proxy; | ||
| 26 | |||
| 27 | import java.io.*; | ||
| 28 | import java.net.*; | ||
| 29 | |||
| 30 | import sun.rmi.runtime.Log; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * The HttpSendSocket class extends the java.net.Socket class | ||
| 34 | * by enclosing the data output stream in, then extracting the input | ||
| 35 | * stream from, an HTTP protocol transmission. | ||
| 36 | * | ||
| 37 | * NOTES: | ||
| 38 | * | ||
| 39 | * Since the length of the output request must be known before the | ||
| 40 | * HTTP header can be completed, all of the output is buffered by | ||
| 41 | * an HttpOutputStream object until either an attempt is made to | ||
| 42 | * read from this socket, or the socket is explicitly closed. | ||
| 43 | * | ||
| 44 | * On the first read attempt to read from this socket, the buffered | ||
| 45 | * output is sent to the destination as the body of an HTTP POST | ||
| 46 | * request. All reads will then acquire data from the body of | ||
| 47 | * the response. A subsequent attempt to write to this socket will | ||
| 48 | * throw an IOException. | ||
| 49 | */ | ||
| 50 | class HttpSendSocket extends Socket implements RMISocketInfo { | ||
| 51 | |||
| 52 | /** the host to connect to */ | ||
| 53 | protected String host; | ||
| 54 | |||
| 55 | /** the port to connect to */ | ||
| 56 | protected int port; | ||
| 57 | |||
| 58 | /** the URL to forward through */ | ||
| 59 | protected URL url; | ||
| 60 | |||
| 61 | /** the object managing this connection through the URL */ | ||
| 62 | protected URLConnection conn = null; | ||
| 63 | |||
| 64 | /** internal input stream for this socket */ | ||
| 65 | protected InputStream in = null; | ||
| 66 | |||
| 67 | /** internal output stream for this socket */ | ||
| 68 | protected OutputStream out = null; | ||
| 69 | |||
| 70 | /** the notifying input stream returned to users */ | ||
| 71 | protected HttpSendInputStream inNotifier; | ||
| 72 | |||
| 73 | /** the notifying output stream returned to users */ | ||
| 74 | protected HttpSendOutputStream outNotifier; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Line separator string. This is the value of the line.separator | ||
| 78 | * property at the moment that the socket was created. | ||
| 79 | */ | ||
| 80 | private String lineSeparator = | ||
| 81 | java.security.AccessController.doPrivileged( | ||
| 82 | new sun.security.action.GetPropertyAction("line.separator")); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Create a stream socket and connect it to the specified port on | ||
| 86 | * the specified host. | ||
| 87 | * @param host the host | ||
| 88 | * @param port the port | ||
| 89 | */ | ||
| 90 | public HttpSendSocket(String host, int port, URL url) throws IOException | ||
| 91 | { | ||
| 92 | super((SocketImpl)null); // no underlying SocketImpl for this object | ||
| 93 | |||
| 94 | if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { | ||
| 95 | RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, | ||
| 96 | "host = " + host + ", port = " + port + ", url = " + url); | ||
| 97 | } | ||
| 98 | |||
| 99 | this.host = host; | ||
| 100 | this.port = port; | ||
| 101 | this.url = url; | ||
| 102 | |||
| 103 | inNotifier = new HttpSendInputStream(null, this); | ||
| 104 | outNotifier = new HttpSendOutputStream(writeNotify(), this); | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Create a stream socket and connect it to the specified port on | ||
| 109 | * the specified host. | ||
| 110 | * @param host the host | ||
| 111 | * @param port the port | ||
| 112 | */ | ||
| 113 | public HttpSendSocket(String host, int port) throws IOException | ||
| 114 | { | ||
| 115 | this(host, port, new URL("http", host, port, "/")); | ||
| 116 | } | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Create a stream socket and connect it to the specified address on | ||
| 120 | * the specified port. | ||
| 121 | * @param address the address | ||
| 122 | * @param port the port | ||
| 123 | */ | ||
| 124 | public HttpSendSocket(InetAddress address, int port) throws IOException | ||
| 125 | { | ||
| 126 | this(address.getHostName(), port); | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Indicate that this socket is not reusable. | ||
| 131 | */ | ||
| 132 | public boolean isReusable() | ||
| 133 | { | ||
| 134 | return false; | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Create a new socket connection to host (or proxy), and prepare to | ||
| 139 | * send HTTP transmission. | ||
| 140 | */ | ||
| 141 | public synchronized OutputStream writeNotify() throws IOException | ||
| 142 | { | ||
| 143 | if (conn != null) { | ||
| 144 | throw new IOException("attempt to write on HttpSendSocket after " + | ||
| 145 | "request has been sent"); | ||
| 146 | } | ||
| 147 | |||
| 148 | conn = url.openConnection(); | ||
| 149 | conn.setDoOutput(true); | ||
| 150 | conn.setUseCaches(false); | ||
| 151 | conn.setRequestProperty("Content-type", "application/octet-stream"); | ||
| 152 | |||
| 153 | inNotifier.deactivate(); | ||
| 154 | in = null; | ||
| 155 | |||
| 156 | return out = conn.getOutputStream(); | ||
| 157 | } | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Send HTTP output transmission and prepare to receive response. | ||
| 161 | */ | ||
| 162 | public synchronized InputStream readNotify() throws IOException | ||
| 163 | { | ||
| 164 | RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, | ||
| 165 | "sending request and activating input stream"); | ||
| 166 | |||
| 167 | outNotifier.deactivate(); | ||
| 168 | out.close(); | ||
| 169 | out = null; | ||
| 170 | |||
| 171 | try { | ||
| 172 | in = conn.getInputStream(); | ||
| 173 | } catch (IOException e) { | ||
| 174 | RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, | ||
| 175 | "failed to get input stream, exception: ", e); | ||
| 176 | |||
| 177 | throw new IOException("HTTP request failed"); | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * If an HTTP error response is returned, sometimes an IOException | ||
| 182 | * is thrown, which is handled above, and other times it isn't, and | ||
| 183 | * the error response body will be available for reading. | ||
| 184 | * As a safety net to catch any such unexpected HTTP behavior, we | ||
| 185 | * verify that the content type of the response is what the | ||
| 186 | * HttpOutputStream generates: "application/octet-stream". | ||
| 187 | * (Servers' error responses will generally be "text/html".) | ||
| 188 | * Any error response body is printed to the log. | ||
| 189 | */ | ||
| 190 | String contentType = conn.getContentType(); | ||
| 191 | if (contentType == null || | ||
| 192 | !conn.getContentType().equals("application/octet-stream")) | ||
| 193 | { | ||
| 194 | if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.BRIEF)) { | ||
| 195 | String message; | ||
| 196 | if (contentType == null) { | ||
| 197 | message = "missing content type in response" + | ||
| 198 | lineSeparator; | ||
| 199 | } else { | ||
| 200 | message = "invalid content type in response: " + | ||
| 201 | contentType + lineSeparator; | ||
| 202 | } | ||
| 203 | |||
| 204 | message += "HttpSendSocket.readNotify: response body: "; | ||
| 205 | try { | ||
| 206 | DataInputStream din = new DataInputStream(in); | ||
| 207 | String line; | ||
| 208 | while ((line = din.readLine()) != null) | ||
| 209 | message += line + lineSeparator; | ||
| 210 | } catch (IOException e) { | ||
| 211 | } | ||
| 212 | RMIMasterSocketFactory.proxyLog.log(Log.BRIEF, message); | ||
| 213 | } | ||
| 214 | |||
| 215 | throw new IOException("HTTP request failed"); | ||
| 216 | } | ||
| 217 | |||
| 218 | return in; | ||
| 219 | } | ||
| 220 | |||
| 221 | /** | ||
| 222 | * Get the address to which the socket is connected. | ||
| 223 | */ | ||
| 224 | public InetAddress getInetAddress() | ||
| 225 | { | ||
| 226 | try { | ||
| 227 | return InetAddress.getByName(host); | ||
| 228 | } catch (UnknownHostException e) { | ||
| 229 | return null; // null if couldn't resolve destination host | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Get the local address to which the socket is bound. | ||
| 235 | */ | ||
| 236 | public InetAddress getLocalAddress() | ||
| 237 | { | ||
| 238 | try { | ||
| 239 | return InetAddress.getLocalHost(); | ||
| 240 | } catch (UnknownHostException e) { | ||
| 241 | return null; // null if couldn't determine local host | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | /** | ||
| 246 | * Get the remote port to which the socket is connected. | ||
| 247 | */ | ||
| 248 | public int getPort() | ||
| 249 | { | ||
| 250 | return port; | ||
| 251 | } | ||
| 252 | |||
| 253 | /** | ||
| 254 | * Get the local port to which the socket is connected. | ||
| 255 | */ | ||
| 256 | public int getLocalPort() | ||
| 257 | { | ||
| 258 | return -1; // request not applicable to this socket type | ||
| 259 | } | ||
| 260 | |||
| 261 | /** | ||
| 262 | * Get an InputStream for this socket. | ||
| 263 | */ | ||
| 264 | public InputStream getInputStream() throws IOException | ||
| 265 | { | ||
| 266 | return inNotifier; | ||
| 267 | } | ||
| 268 | |||
| 269 | /** | ||
| 270 | * Get an OutputStream for this socket. | ||
| 271 | */ | ||
| 272 | public OutputStream getOutputStream() throws IOException | ||
| 273 | { | ||
| 274 | return outNotifier; | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * Enable/disable TCP_NODELAY. | ||
| 279 | * This operation has no effect for an HttpSendSocket. | ||
| 280 | */ | ||
| 281 | public void setTcpNoDelay(boolean on) throws SocketException | ||
| 282 | { | ||
| 283 | } | ||
| 284 | |||
| 285 | /** | ||
| 286 | * Retrieve whether TCP_NODELAY is enabled. | ||
| 287 | */ | ||
| 288 | public boolean getTcpNoDelay() throws SocketException | ||
| 289 | { | ||
| 290 | return false; // imply option is disabled | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Enable/disable SO_LINGER with the specified linger time. | ||
| 295 | * This operation has no effect for an HttpSendSocket. | ||
| 296 | */ | ||
| 297 | public void setSoLinger(boolean on, int val) throws SocketException | ||
| 298 | { | ||
| 299 | } | ||
| 300 | |||
| 301 | /** | ||
| 302 | * Retrive setting for SO_LINGER. | ||
| 303 | */ | ||
| 304 | public int getSoLinger() throws SocketException | ||
| 305 | { | ||
| 306 | return -1; // imply option is disabled | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * Enable/disable SO_TIMEOUT with the specified timeout | ||
| 311 | * This operation has no effect for an HttpSendSocket. | ||
| 312 | */ | ||
| 313 | public synchronized void setSoTimeout(int timeout) throws SocketException | ||
| 314 | { | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * Retrive setting for SO_TIMEOUT. | ||
| 319 | */ | ||
| 320 | public synchronized int getSoTimeout() throws SocketException | ||
| 321 | { | ||
| 322 | return 0; // imply option is disabled | ||
| 323 | } | ||
| 324 | |||
| 325 | /** | ||
| 326 | * Close the socket. | ||
| 327 | */ | ||
| 328 | public synchronized void close() throws IOException | ||
| 329 | { | ||
| 330 | if (out != null) // push out transmission if not done | ||
| 331 | out.close(); | ||
| 332 | } | ||
| 333 | |||
| 334 | /** | ||
| 335 | * Return string representation of this pseudo-socket. | ||
| 336 | */ | ||
| 337 | public String toString() | ||
| 338 | { | ||
| 339 | return "HttpSendSocket[host=" + host + | ||
| 340 | ",port=" + port + | ||
| 341 | ",url=" + url + "]"; | ||
| 342 | } | ||
| 343 | } | ||