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 import java.util.Hashtable; 30 31 /** 32 * CGIClientException is thrown when an error is detected 33 * in a client's request. 34 */ 35 class CGIClientException extends Exception { 36 private static final long serialVersionUID = 8147981687059865216L; 37 38 public CGIClientException(String s) { 39 super(s); 40 } 41 } 42 43 /** 44 * CGIServerException is thrown when an error occurs here on the server. 45 */ 46 class CGIServerException extends Exception { 47 48 private static final long serialVersionUID = 6928425456704527017L; 49 50 public CGIServerException(String s) { 51 super(s); 52 } 53 } 54 55 /** 56 * CGICommandHandler is the interface to an object that handles a 57 * particular supported command. 58 */ 59 interface CGICommandHandler { 60 61 /** 62 * Return the string form of the command 63 * to be recognized in the query string. 64 */ 65 public String getName(); 66 67 /** 68 * Execute the command with the given string as parameter. 69 */ 70 public void execute(String param) throws CGIClientException, CGIServerException; 71 } 72 73 /** 74 * The CGIHandler class contains methods for executing as a CGI program. 75 * The main function interprets the query string as a command of the form 76 * "<command>=<parameters>". 77 * 78 * This class depends on the CGI 1.0 environment variables being set as 79 * properties of the same name in this Java VM. 80 * 81 * All data and methods of this class are static because they are specific 82 * to this particular CGI process. 83 */ 84 public final class CGIHandler { 85 86 /* get CGI parameters that we need */ 87 static int ContentLength; 88 static String QueryString; 89 static String RequestMethod; 90 static String ServerName; 91 static int ServerPort; 92 93 static { 94 java.security.AccessController.doPrivileged( 95 new java.security.PrivilegedAction<Void>() { 96 public Void run() { 97 ContentLength = 98 Integer.getInteger("CONTENT_LENGTH", 0).intValue(); 99 QueryString = System.getProperty("QUERY_STRING", ""); 100 RequestMethod = System.getProperty("REQUEST_METHOD", ""); 101 ServerName = System.getProperty("SERVER_NAME", ""); 102 ServerPort = Integer.getInteger("SERVER_PORT", 0).intValue(); 103 return null; 104 } 105 }); 106 } 107 108 /* list of handlers for supported commands */ 109 private static CGICommandHandler commands[] = { 110 new CGIForwardCommand(), 111 new CGIGethostnameCommand(), 112 new CGIPingCommand(), 113 new CGITryHostnameCommand() 114 }; 115 116 /* construct table mapping command strings to handlers */ 117 private static Hashtable<String, CGICommandHandler> commandLookup; 118 static { 119 commandLookup = new Hashtable<>(); 120 for (int i = 0; i < commands.length; ++ i) 121 commandLookup.put(commands[i].getName(), commands[i]); 122 } 123 124 /* prevent instantiation of this class */ 125 private CGIHandler() {} 126 127 /** 128 * Execute command given in query string on URL. The string before 129 * the first '=' is interpreted as the command name, and the string 130 * after the first '=' is the parameters to the command. 131 */ 132 public static void main(String args[]) 133 { 134 try { 135 String command, param; 136 int delim = QueryString.indexOf("="); 137 if (delim == -1) { 138 command = QueryString; 139 param = ""; 140 } 141 else { 142 command = QueryString.substring(0, delim); 143 param = QueryString.substring(delim + 1); 144 } 145 CGICommandHandler handler = 146 commandLookup.get(command); 147 if (handler != null) 148 try { 149 handler.execute(param); 150 } catch (CGIClientException e) { 151 returnClientError(e.getMessage()); 152 } catch (CGIServerException e) { 153 returnServerError(e.getMessage()); 154 } 155 else 156 returnClientError("invalid command: " + command); 157 } catch (Exception e) { 158 returnServerError("internal error: " + e.getMessage()); 159 } 160 System.exit(0); 161 } 162 163 /** 164 * Return an HTML error message indicating there was error in 165 * the client's request. 166 */ 167 private static void returnClientError(String message) 168 { 169 System.out.println("Status: 400 Bad Request: " + message); 170 System.out.println("Content-type: text/html"); 171 System.out.println(""); 172 System.out.println("<HTML>" + 173 "<HEAD><TITLE>Java RMI Client Error" + 174 "</TITLE></HEAD>" + 175 "<BODY>"); 176 System.out.println("<H1>Java RMI Client Error</H1>"); 177 System.out.println(""); 178 System.out.println(message); 179 System.out.println("</BODY></HTML>"); 180 System.exit(1); 181 } 182 183 /** 184 * Return an HTML error message indicating an error occurred 185 * here on the server. 186 */ 187 private static void returnServerError(String message) 188 { 189 System.out.println("Status: 500 Server Error: " + message); 190 System.out.println("Content-type: text/html"); 191 System.out.println(""); 192 System.out.println("<HTML>" + 193 "<HEAD><TITLE>Java RMI Server Error" + 194 "</TITLE></HEAD>" + 195 "<BODY>"); 196 System.out.println("<H1>Java RMI Server Error</H1>"); 197 System.out.println(""); 198 System.out.println(message); 199 System.out.println("</BODY></HTML>"); 200 System.exit(1); 201 } 202 } 203 204 /** 205 * "forward" command: Forward request body to local port on the server, 206 * and send response back to client. 207 */ 208 final class CGIForwardCommand implements CGICommandHandler { 209 210 public String getName() { 211 return "forward"; 212 } 213 214 @SuppressWarnings("deprecation") 215 private String getLine (DataInputStream socketIn) throws IOException { 216 return socketIn.readLine(); 217 } 218 219 public void execute(String param) throws CGIClientException, CGIServerException 220 { 221 if (!CGIHandler.RequestMethod.equals("POST")) 222 throw new CGIClientException("can only forward POST requests"); 223 224 int port; 225 try { 226 port = Integer.parseInt(param); 227 } catch (NumberFormatException e) { 228 throw new CGIClientException("invalid port number: " + param); 229 } 230 if (port <= 0 || port > 0xFFFF) 231 throw new CGIClientException("invalid port: " + port); 232 if (port < 1024) 233 throw new CGIClientException("permission denied for port: " + 234 port); 235 236 byte buffer[]; 237 Socket socket; 238 try { 239 socket = new Socket(InetAddress.getLocalHost(), port); 240 } catch (IOException e) { 241 throw new CGIServerException("could not connect to local port"); 242 } 243 244 /* 245 * read client's request body 246 */ 247 DataInputStream clientIn = new DataInputStream(System.in); 248 buffer = new byte[CGIHandler.ContentLength]; 249 try { 250 clientIn.readFully(buffer); 251 } catch (EOFException e) { 252 throw new CGIClientException("unexpected EOF reading request body"); 253 } catch (IOException e) { 254 throw new CGIClientException("error reading request body"); 255 } 256 257 /* 258 * send to local server in HTTP 259 */ 260 try { 261 DataOutputStream socketOut = 262 new DataOutputStream(socket.getOutputStream()); 263 socketOut.writeBytes("POST / HTTP/1.0\r\n"); 264 socketOut.writeBytes("Content-length: " + 265 CGIHandler.ContentLength + "\r\n\r\n"); 266 socketOut.write(buffer); 267 socketOut.flush(); 268 } catch (IOException e) { 269 throw new CGIServerException("error writing to server"); 270 } 271 272 /* 273 * read response 274 */ 275 DataInputStream socketIn; 276 try { 277 socketIn = new DataInputStream(socket.getInputStream()); 278 } catch (IOException e) { 279 throw new CGIServerException("error reading from server"); 280 } 281 String key = "Content-length:".toLowerCase(); 282 boolean contentLengthFound = false; 283 String line; 284 int responseContentLength = -1; 285 do { 286 try { 287 line = getLine(socketIn); 288 } catch (IOException e) { 289 throw new CGIServerException("error reading from server"); 290 } 291 if (line == null) 292 throw new CGIServerException( 293 "unexpected EOF reading server response"); 294 295 if (line.toLowerCase().startsWith(key)) { 296 if (contentLengthFound){ 297 // what would we want to do in this case?? 298 } 299 responseContentLength = 300 Integer.parseInt(line.substring(key.length()).trim()); 301 contentLengthFound = true; 302 } 303 } while ((line.length() != 0) && 304 (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); 305 306 if (!contentLengthFound || responseContentLength < 0) 307 throw new CGIServerException( 308 "missing or invalid content length in server response"); 309 buffer = new byte[responseContentLength]; 310 try { 311 socketIn.readFully(buffer); 312 } catch (EOFException e) { 313 throw new CGIServerException( 314 "unexpected EOF reading server response"); 315 } catch (IOException e) { 316 throw new CGIServerException("error reading from server"); 317 } 318 319 /* 320 * send response back to client 321 */ 322 System.out.println("Status: 200 OK"); 323 System.out.println("Content-type: application/octet-stream"); 324 System.out.println(""); 325 try { 326 System.out.write(buffer); 327 } catch (IOException e) { 328 throw new CGIServerException("error writing response"); 329 } 330 System.out.flush(); 331 } 332 } 333 334 /** 335 * "gethostname" command: Return the host name of the server as the 336 * response body 337 */ 338 final class CGIGethostnameCommand implements CGICommandHandler { 339 340 public String getName() { 341 return "gethostname"; 342 } 343 344 public void execute(String param) 345 { 346 System.out.println("Status: 200 OK"); 347 System.out.println("Content-type: application/octet-stream"); 348 System.out.println("Content-length: " + 349 CGIHandler.ServerName.length()); 350 System.out.println(""); 351 System.out.print(CGIHandler.ServerName); 352 System.out.flush(); 353 } 354 } 355 356 /** 357 * "ping" command: Return an OK status to indicate that connection 358 * was successful. 359 */ 360 final class CGIPingCommand implements CGICommandHandler { 361 362 public String getName() { 363 return "ping"; 364 } 365 366 public void execute(String param) 367 { 368 System.out.println("Status: 200 OK"); 369 System.out.println("Content-type: application/octet-stream"); 370 System.out.println("Content-length: 0"); 371 System.out.println(""); 372 } 373 } 374 375 /** 376 * "tryhostname" command: Return a human readable message describing 377 * what host name is available to local Java VMs. 378 */ 379 final class CGITryHostnameCommand implements CGICommandHandler { 380 381 public String getName() { 382 return "tryhostname"; 383 } 384 385 public void execute(String param) 386 { 387 System.out.println("Status: 200 OK"); 388 System.out.println("Content-type: text/html"); 389 System.out.println(""); 390 System.out.println("<HTML>" + 391 "<HEAD><TITLE>Java RMI Server Hostname Info" + 392 "</TITLE></HEAD>" + 393 "<BODY>"); 394 System.out.println("<H1>Java RMI Server Hostname Info</H1>"); 395 System.out.println("<H2>Local host name available to Java VM:</H2>"); 396 System.out.print("<P>InetAddress.getLocalHost().getHostName()"); 397 try { 398 String localHostName = InetAddress.getLocalHost().getHostName(); 399 400 System.out.println(" = " + localHostName); 401 } catch (UnknownHostException e) { 402 System.out.println(" threw java.net.UnknownHostException"); 403 } 404 405 System.out.println("<H2>Server host information obtained through CGI interface from HTTP server:</H2>"); 406 System.out.println("<P>SERVER_NAME = " + CGIHandler.ServerName); 407 System.out.println("<P>SERVER_PORT = " + CGIHandler.ServerPort); 408 System.out.println("</BODY></HTML>"); 409 } 410 }