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