Commit | Line | Data |
e88ae2ce |
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">\r |
2 | <HTML>\r |
3 | <HEAD>\r |
4 | <TITLE>\r |
5 | Integrating FastCGI with Java\r |
6 | </TITLE>\r |
7 | <STYLE TYPE="text/css">\r |
8 | body {\r |
9 | background-color: #FFFFFF;\r |
10 | color: #000000;\r |
11 | }\r |
12 | :link { color: #cc0000 }\r |
13 | :visited { color: #555555 }\r |
14 | :active { color: #000011 }\r |
15 | dt.c4 {font-style: italic}\r |
16 | h5.c3 {text-align: center}\r |
17 | p.c2 {text-align: center}\r |
18 | div.c1 {text-align: center}\r |
19 | </STYLE>\r |
20 | </HEAD>\r |
21 | <BODY>\r |
22 | <DIV CLASS="c1">\r |
23 | <A HREF="http://fastcgi.com"><IMG BORDER="0" SRC="../images/fcgi-hd.gif" ALT="[[FastCGI]]"></A>\r |
24 | </DIV>\r |
25 | <BR CLEAR="all">\r |
26 | <DIV CLASS="c1">\r |
27 | <H3>\r |
28 | Integrating FastCGI with Java\r |
29 | </H3>\r |
30 | </DIV>\r |
31 | <!--Copyright (c) 1996 Open Market, Inc. -->\r |
32 | <!--See the file "LICENSE.TERMS" for information on usage and redistribution-->\r |
33 | <!--of this file, and for a DISCLAIMER OF ALL WARRANTIES. -->\r |
34 | <!-- $Id: fcgi-java.htm,v 1.3 2001/11/27 01:03:47 robs Exp $ -->\r |
35 | <P CLASS="c2">\r |
36 | Steve Harris<BR>\r |
37 | Open Market, Inc.<BR>\r |
38 | <EM>7 May 1996</EM>\r |
39 | </P>\r |
40 | <H5 CLASS="c3">\r |
41 | Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.<BR>\r |
42 | Tel: 617-621-9500 Fax: 617-621-1703 URL: <A HREF=\r |
43 | "http://www.openmarket.com/">http://www.openmarket.com/</A><BR>\r |
44 | </H5>\r |
45 | <HR>\r |
46 | <H3>\r |
47 | <A NAME="S1">1. Introduction</A>\r |
48 | </H3>\r |
49 | <P>\r |
50 | Java is an object-oriented programming language developed by Sun Microsystems. The Java Depvelopers Kit (JDK),\r |
51 | which contains the basic Java class packages, is available from Sun in both source and binary forms at\r |
52 | Sun's <A HREF="http://java.sun.com/java.sun.com/JDK-1.0/index.html">JavaSoft</A> site. This document\r |
53 | assumes that you have some familiarity with the basics of compiling and running Java programs.\r |
54 | </P>\r |
55 | <P>\r |
56 | There are two kinds of applications built using Java.\r |
57 | </P>\r |
58 | <UL>\r |
59 | <LI>\r |
60 | <I>Java Applets</I> are graphical components which are run off HTML pages via the <TT><APPLET></TT>\r |
61 | HTML extention tag.<BR>\r |
62 | <BR>\r |
63 | </LI>\r |
64 | <LI>\r |
65 | <I>Java Applications (Apps)</I> are stand-alone programs that are run by invoking the Java interpreter\r |
66 | directly. Like C programs, they have a <TT>main()</TT> method which the interpreter uses as an entry point.\r |
67 | </LI>\r |
68 | </UL>\r |
69 | <P>\r |
70 | The initial emphasis on using Java for client side applets should not obscure the fact that Java is a full\r |
71 | strength programming language which can be used to develop server side stand alone applications, including CGI\r |
72 | and now FastCGI applications.\r |
73 | </P>\r |
74 | <P>\r |
75 | The remainder of this document explains how to write and run FastCGI Java applications. It also illustrates\r |
76 | the conversion of a sample Java CGI program to a FastCGI program.\r |
77 | </P>\r |
78 | <H3>\r |
79 | <A NAME="S2">2. Writing FastCGI applications in Java</A>\r |
80 | </H3>\r |
81 | <P>\r |
82 | Writing a FastCGI application in Java is as simple as writing one in C.\r |
83 | </P>\r |
84 | <OL>\r |
85 | <LI>\r |
86 | Import the <TT>FCGIInterface</TT> class.\r |
87 | </LI>\r |
88 | <LI>\r |
89 | Perform one-time initialization at the top of the <TT>main()</TT> method.\r |
90 | </LI>\r |
91 | <LI>\r |
92 | Create a new <TT>FCGIInterface</TT> object and send it an <TT>FCGIaccept()</TT> message in a loop.\r |
93 | </LI>\r |
94 | <LI>\r |
95 | Put the per-request application code inside that loop.\r |
96 | </LI>\r |
97 | </OL>\r |
98 | <P>\r |
99 | On return from <TT>FCGIaccept()</TT> you can access the request's environment variables using\r |
100 | <TT>System.getProperty</TT> and perform request-related I/O through the standard variables <TT>System.in</TT>,\r |
101 | <TT>System.out</TT>, and <TT>System.err</TT>.\r |
102 | </P>\r |
103 | <P>\r |
104 | To illustrate these points, the kit includes <TT>examples/TinyCGI</TT>, a CGI Java application, and\r |
105 | <TT>examples/TinyFCGI</TT>, the FastCGI version of TinyCGI. These programs perform the same functions as the C\r |
106 | programs <TT>examples/tiny-cgi.c</TT> and <TT>examples/tiny-fcgi.c</TT> that are used as examples in the <A\r |
107 | HREF="fcgi-devel-kit.htm#S3.1.1">FastCGI Developer's Kit document</A>.\r |
108 | </P>\r |
109 | <H4>\r |
110 | A. TinyCGI\r |
111 | </H4>\r |
112 | <PRE>\r |
113 | \r |
114 | class TinyCGI { \r |
115 | public static void main (String args[]) { \r |
116 | int count = 0;\r |
117 | ++count;\r |
118 | System.out.println("Content-type: text/html\n\n");\r |
119 | System.out.println("<html>");\r |
120 | System.out.println(\r |
121 | "<head><TITLE>CGI Hello</TITLE></head>");\r |
122 | System.out.println("<body>");\r |
123 | System.out.println("<H3>CGI-Hello</H3>");\r |
124 | System.out.println("request number " + count + \r |
125 | " running on host " \r |
126 | + System.getProperty<"SERVER_NAME"));\r |
127 | System.out.println("</body>");\r |
128 | System.out.println("</html>"); \r |
129 | }\r |
130 | }\r |
131 | \r |
132 | </PRE>\r |
133 | <H4>\r |
134 | B. TinyFCGI\r |
135 | </H4>\r |
136 | <PRE>\r |
137 | \r |
138 | import FCGIInterface;\r |
139 | \r |
140 | class TinyFCGI { \r |
141 | public static void main (String args[]) { \r |
142 | int count = 0;\r |
143 | while(new FCGIInterface().FCGIaccept()>= 0) {\r |
144 | count ++;\r |
145 | System.out.println("Content-type: text/html\n\n");\r |
146 | System.out.println("<html>");\r |
147 | System.out.println(\r |
148 | "<head><TITLE>FastCGI-Hello Java stdio</TITLE></head>");\r |
149 | System.out.println("<body>");\r |
150 | System.out.println("<H3>FastCGI-HelloJava stdio</H3>");\r |
151 | System.out.println("request number " + count + \r |
152 | " running on host " \r |
153 | + System.getProperty<"SERVER_NAME"));\r |
154 | System.out.println("</body>");\r |
155 | System.out.println("</html>"); \r |
156 | }\r |
157 | }\r |
158 | }\r |
159 | \r |
160 | </PRE>\r |
161 | <H4>\r |
162 | C. Running these Examples\r |
163 | </H4>\r |
164 | <P>\r |
165 | We assume that you have downloaded the JDK and the FastCGI Developer's Kit, and that you have a Web server\r |
166 | running that can access the <TT>fcgi-devel-kit/examples</TT> directory. In all cases where we specify paths,\r |
167 | we are using relative paths within <TT>fcgi-devel-kit</TT> or the JDK which will need to be enlarged to a full\r |
168 | path by the user.\r |
169 | </P>\r |
170 | <H5>\r |
171 | Configuring\r |
172 | </H5>\r |
173 | <OL>\r |
174 | <LI>\r |
175 | Add your JDK's <TT>java/bin</TT> directory to your Unix <TT>PATH</TT> if it isn't there\r |
176 | already.<BR>\r |
177 | <BR>\r |
178 | </LI>\r |
179 | <LI>\r |
180 | Add the directories <TT>fcgi-devel-kit/examples</TT> and <TT>fcgi-devel-kit/java/classes</TT> to your Java\r |
181 | <TT>CLASSPATH</TT>.<BR>\r |
182 | <BR>\r |
183 | </LI>\r |
184 | <LI>\r |
185 | In your Open Market Secure WebServer configuration file, <TT>httpd.config</TT>, add the following two\r |
186 | lines:<BR>\r |
187 | <BR>\r |
188 | <TT>ExternalAppClass TinyFCGI -host</TT> <I>hostName:portNum</I><BR>\r |
189 | <TT>Responder TinyFCGI fcgi-devel-kit/examples/TinyFCGI</TT><BR>\r |
190 | <BR>\r |
191 | \r |
192 | <UL>\r |
193 | <LI>\r |
194 | <I>hostName</I> is the name of your host machine.<BR>\r |
195 | </LI>\r |
196 | <LI>\r |
197 | <I>portNum</I> is the port that you've selected for communication between the Web server and the\r |
198 | Java application.<BR>\r |
199 | </LI>\r |
200 | </UL>\r |
201 | <BR>\r |
202 | On other servers you can use <TT>cgi-fcgi</TT> to get a similar effect.\r |
203 | </LI>\r |
204 | <LI>\r |
205 | Create a soft link <TT>examples/javexe</TT> to the <TT>java/bin</TT> directory in your JDK. This link is\r |
206 | required only to run the CGI scripts <TT>examples/TinyCGI.cgi</TT> and <TT>examples/TinyFCGI.cgi</TT>,\r |
207 | which use it to invoke the Java interpreter <TT>java/bin/java</TT>. It is not used by FastCGI applications.\r |
208 | </LI>\r |
209 | <LI>\r |
210 | You might have to modify <TT>examples/TinyFCGI.cgi</TT> to use a Unix shell for which your CLASSPATH is\r |
211 | defined.\r |
212 | </LI>\r |
213 | </OL>\r |
214 | <H5>\r |
215 | Running\r |
216 | </H5>\r |
217 | <UL>\r |
218 | <LI>\r |
219 | To run TinyFCGI as FastCGI, you invoke the Java interpreter with the -D option, giving it the\r |
220 | <TT>FCGI_PORT</TT> environment variable and the same <I>portNum</I> that was used in the Web server\r |
221 | configuration. The command is:<BR>\r |
222 | <BR>\r |
223 | <TT>java -DFCGI_PORT=portNum TinyFCGI</TT><BR>\r |
224 | <BR>\r |
225 | Then point your browser at <TT>fcgi-devel-kit/examples/TinyFCGI</TT>. Notice that each time you reload,\r |
226 | the count increments.<BR>\r |
227 | <BR>\r |
228 | </LI>\r |
229 | <LI>\r |
230 | To run TinyCGI, point your browser at <TT>fcgi-devel-kit/examples/TinyCGI.cgi</TT> on your host machine.\r |
231 | Notice that the count does not increment.<BR>\r |
232 | <BR>\r |
233 | </LI>\r |
234 | <LI>\r |
235 | Finally, you can run TinyFCGI as a straight CGI program by pointing your browser at\r |
236 | <TT>fcgi-devel-kit/examplesi/TinyFCGI.cgi.</TT> The results are exactly the same as when you ran TinyCGI.\r |
237 | Invoking a FastCGI program without an <TT>FCGI_PORT</TT> parameter tells the FastCGI interface to leave the\r |
238 | normal CGI environment in place.\r |
239 | </LI>\r |
240 | </UL>\r |
241 | <P>\r |
242 | Due to gaps in the Java interpreter's support for listening sockets, Java FastCGI applications are\r |
243 | currently limited to being started as external applications. They can't be started and managed by the Web\r |
244 | server because they are incapable of using a listening socket that the Web server creates.\r |
245 | </P>\r |
246 | <H3>\r |
247 | <A NAME="S3">3. Standard I/O and Application Libraries</A>\r |
248 | </H3>\r |
249 | <P>\r |
250 | As we have seen above, FastCGI for Java offers a redefinition of standard I/O corresponding to the the\r |
251 | <I>fcgi_stdio</I> functionality. It also offers a set of directly callable I/O methods corresponding to the\r |
252 | <I>fcgiapp</I> C library. To understand where these methods occur we need to look briefly at the FastCGI\r |
253 | redefinition of standard I/O.\r |
254 | </P>\r |
255 | <P>\r |
256 | Java defines standard I/O in the <I>java.System</I> class as follows:\r |
257 | </P>\r |
258 | <P>\r |
259 | public static InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in), 128);<BR>\r |
260 | public static PrintStream out = new PrintStream(new BufferedOutputStream(new\r |
261 | FileOutputStream(FileDescriptor.out), 128), true);<BR>\r |
262 | public static PrintStream err = new PrintStream(new BufferedOutputStream(new\r |
263 | FileOutputStream(FileDescriptor.err), 128), true);\r |
264 | </P>\r |
265 | <P>\r |
266 | The File Descriptors <I>in</I>, <I>out</I>, <I>err</I> are constants set to 0, 1 and 2 respectively.\r |
267 | </P>\r |
268 | <P>\r |
269 | The FastCGI interface redefines <I>java.System in, out</I>, and <I>err</I> by replacing the File streams with\r |
270 | Socket streams and inserting streams which know how to manage the FastCGI protocol between the Socket streams\r |
271 | and the Buffered streams in the above definitions.\r |
272 | </P>\r |
273 | <P>\r |
274 | For those cases where the FCGI application needs to bypass the standard I/O streams, it can directly access\r |
275 | the methods of the FCGI input and output streams which roughly correspond to the functions in the C\r |
276 | <I>fcgiapp</I> library. These streams can be accessed via the <I>request</I> class variable in FCGIInterface.\r |
277 | Each Request object has instance variables that refer to an FCGIInputStream, and to two FCGIOutputStreams\r |
278 | associated with that request.\r |
279 | </P>\r |
280 | <H3>\r |
281 | <A NAME="S4">4. Environment Variables</A>\r |
282 | </H3>\r |
283 | <P>\r |
284 | Java does not use the C <I>environ</I> list. Nor is there a <I>getenv</I> command that reads system\r |
285 | environment variables. This is intentional for reasons of portability and security. Java has an internal\r |
286 | dictionary of properties which belongs to the System class. These System properties are <I>name/value</I>\r |
287 | associations that constitute the Java environment. When a Java application starts up, it reads in a file with\r |
288 | default properties. As we have seen, additional System properties may be inserted by using the -D <I>Java</I>\r |
289 | command argument.\r |
290 | </P>\r |
291 | <P>\r |
292 | For CGI, where the Java application is invoked from a .cgi script that, in turn, invokes the Java interpreter,\r |
293 | this script could read the environment and pass the variables to the Java application either by writing a file\r |
294 | or by creating -D options on the fly. Both of these methods are somewhat awkward.\r |
295 | </P>\r |
296 | <P>\r |
297 | For FastCGI Java applications, the environment variables are obtained from the FastCGI web server via\r |
298 | <TT>FCGI_PARAMS</TT> records that are sent to the application at the start of each request. The FastCGI\r |
299 | interface stores the original startup properties, combines these with the properties obtained from the server,\r |
300 | and puts the new set of properties in the System properties dictionary. The only parameter that has to be\r |
301 | specifically added at startup time is the FCGI_PORT parameter for the Socket creation. In the future, we\r |
302 | expect that even this parameter won't be needed, since its use is due to an acknowledged rigidity in the\r |
303 | JDK's implementation of sockets.\r |
304 | </P>\r |
305 | <P>\r |
306 | </P>\r |
307 | <H3>\r |
308 | <A NAME="S4">5. Further examples: EchoFCGI and Echo2FCGI</A>\r |
309 | </H3>\r |
310 | <P>\r |
311 | The next two examples illustrate the points made in the last two sections. EchoFCGI and Echo2FCGI both echo\r |
312 | user input and display the application's environment variables. EchoFCGI reads the user input from\r |
313 | System.in, while Echo2FCGI reads the user input directly from the intermediate FastCGI input stream.\r |
314 | </P>\r |
315 | <H4>\r |
316 | A. EchoFCGI\r |
317 | </H4>\r |
318 | <PRE>\r |
319 | import FCGIInterface;\r |
320 | import FCGIGlobalDefs;\r |
321 | import java.io.*;\r |
322 | \r |
323 | class EchoFCGI {\r |
324 | \r |
325 | public static void main (String args[]) {\r |
326 | int status = 0;\r |
327 | while(new FCGIInterface().FCGIaccept()>= 0) {\r |
328 | System.out.println("Content-type: text/html\n\n");\r |
329 | System.out.println("<html>");\r |
330 | System.out.println(\r |
331 | "<head%gt;<TITLE>FastCGI echo\r |
332 | </TITLE></head>");\r |
333 | System.out.println("<body>"); \r |
334 | System.out.println(\r |
335 | "<H2>FastCGI echo</H2>");\r |
336 | System.out.println("<H3>STDIN</H3>");\r |
337 | for ( int c = 0; c != -1; ) {\r |
338 | try {\r |
339 | c = System.in.read();\r |
340 | } catch(IOException e) {\r |
341 | System.out.println(\r |
342 | "<br><b>SYSTEM EXCEPTION");\r |
343 | Runtime rt = Runtime.getRuntime();\r |
344 | rt.exit(status);\r |
345 | }\r |
346 | if (c != -1) { \r |
347 | System.out.print((char)c);\r |
348 | }\r |
349 | }\r |
350 | System.out.println(\r |
351 | "<H3>Environment Variables:</H3>");\r |
352 | \r |
353 | System.getProperties().list(System.out);\r |
354 | System.out.println("</body>");\r |
355 | System.out.println("</html>");\r |
356 | }\r |
357 | }\r |
358 | }\r |
359 | </PRE>\r |
360 | <H4>\r |
361 | B. Echo2FCGI\r |
362 | </H4>\r |
363 | <PRE>\r |
364 | import FCGIInterface;\r |
365 | import FCGIGlobalDefs;\r |
366 | import FCGIInputStream;\r |
367 | import FCGIOutputStream;\r |
368 | import FCGIMessage;\r |
369 | import FCGIRequest;\r |
370 | import java.io.*;\r |
371 | \r |
372 | class Echo2FCGI {\r |
373 | \r |
374 | public static void main (String args[]) {\r |
375 | int status = 0;\r |
376 | FCGIInterface intf = new FCGIInterface();\r |
377 | while(intf.FCGIaccept()>= 0) {\r |
378 | System.out.println("Content-type: text/html\n\n");\r |
379 | System.out.println("<html>");\r |
380 | System.out.println(\r |
381 | "<head><TITLE>FastCGI echo\r |
382 | </TITLE></head>");\r |
383 | System.out.println("<body>"); \r |
384 | System.out.println("<H2>FastCGI echo</H2>");\r |
385 | System.out.println("<H3>STDIN:</H3">);\r |
386 | for ( int c = 0; c != -1; ) {\r |
387 | try {\r |
388 | c = intf.request.inStream.read();\r |
389 | } catch(IOException e) {\r |
390 | System.out.println(\r |
391 | "<br><b>SYSTEM EXCEPTION");\r |
392 | Runtime rt = Runtime.getRuntime();\r |
393 | rt.exit(status);\r |
394 | }\r |
395 | if (c != -1) { \r |
396 | System.out.print((char)c);\r |
397 | }\r |
398 | }\r |
399 | System.out.println(\r |
400 | "<H3>Environment Variables:</H3>");\r |
401 | \r |
402 | System.getProperties().list(System.out);\r |
403 | System.out.println(<"/body>");\r |
404 | System.out.println("</html>");\r |
405 | }\r |
406 | }\r |
407 | }\r |
408 | </PRE>\r |
409 | <H4>\r |
410 | C. Running these Examples\r |
411 | </H4>\r |
412 | <H5>\r |
413 | Configuring\r |
414 | </H5>\r |
415 | <P>\r |
416 | As with TinyFCGI, you need to configure the web server to recognize these two FastCGI applications. Your\r |
417 | configuration now looks like this:\r |
418 | </P>\r |
419 | <P>\r |
420 | </P>\r |
421 | <PRE>\r |
422 | ExternalAppClass java1 -host hostname:portNum\r |
423 | Responder java1 fcgi-devel-kit/examples/TinyFCGI\r |
424 | ExternalAppClass java2 -host hostname:portNumA\r |
425 | Responder java2 fcgi-devel-kit/examples/EchoFCGI\r |
426 | ExternalAppClass java3 -host hostname:porNumB\r |
427 | Responder java3 fcgi-devel-kit/examples/Echo2FCGI\r |
428 | </PRE>\r |
429 | <P>\r |
430 | Note that the application classes and port numbers are different for each application.\r |
431 | </P>\r |
432 | <H5>\r |
433 | Running\r |
434 | </H5>\r |
435 | <P>\r |
436 | As with TinyFCGI, you need to run these programs with the -D option using FCGI_PORT and the appropriate port\r |
437 | number. To get some data for standard input we have created two html pages with forms that use a POST method.\r |
438 | These are echo.html and echo2.html. You must edit these .html files to expand the path to\r |
439 | <I>fcgi-devel-kit/examples</I> to a full path. Once the appropriate Java program is running, point your\r |
440 | browser at the corresponding HTML page, enter some data and select the <I>go_find</I> button.\r |
441 | </P>\r |
442 | <H3>\r |
443 | <A NAME="S6">6. FastCGI Java Classes</A>\r |
444 | </H3>\r |
445 | <P>\r |
446 | The Java FastCGI classes are included in both source and byte code format in <I>fcgi-devel-kit/java/src</I>\r |
447 | and :<I>fcgi-devel-kit/java/classes</I> respectively. The following is a brief description of these classes:\r |
448 | </P>\r |
449 | <P>\r |
450 | </P>\r |
451 | <DL>\r |
452 | <DT CLASS="c4">\r |
453 | FCGIInterface\r |
454 | </DT>\r |
455 | <DD>\r |
456 | This class contains the FCGIaccept method called by the FastCGI user application. This method sets up the\r |
457 | appropriate FastCGI environment for communication with the web server and manages FastCGI requests.<BR>\r |
458 | </DD>\r |
459 | <DT CLASS="c4">\r |
460 | FCGIInputStream\r |
461 | </DT>\r |
462 | <DD>\r |
463 | This input stream manages FastCGI internal buffers to ensure that the user gets all of the FastCGI messages\r |
464 | associated with a request. It uses FCGIMessage objects to interpret these incoming messages.<BR>\r |
465 | </DD>\r |
466 | <DT CLASS="c4">\r |
467 | FCGIOutputStream\r |
468 | </DT>\r |
469 | <DD>\r |
470 | This output stream manages FastCGI internal buffers to send user data back to the web server and to notify\r |
471 | the server of various FCGI protocol conditions. It uses FCGIMessage objects to format outgoing FastCGI\r |
472 | messages.<BR>\r |
473 | </DD>\r |
474 | <DT CLASS="c4">\r |
475 | FCGIMessage\r |
476 | </DT>\r |
477 | <DD>\r |
478 | This is the only class that understands the actual structure of the FastCGI messages. It interprets\r |
479 | incoming FastCGI records and constructs outgoing ones..<BR>\r |
480 | </DD>\r |
481 | <DT CLASS="c4">\r |
482 | FCGIRequest\r |
483 | </DT>\r |
484 | <DD>\r |
485 | This class currently contains data fields used by FastCGI to manage user requests. In a multi-threaded\r |
486 | version of FastCGI, the role of this class will be expanded.<BR>\r |
487 | </DD>\r |
488 | <DT CLASS="c4">\r |
489 | FCGIGlobalDefs\r |
490 | </DT>\r |
491 | <DD>\r |
492 | This class contains definitions of FastCGI constants.\r |
493 | </DD>\r |
494 | </DL>\r |
495 | <HR>\r |
496 | <ADDRESS>\r |
497 | <A HREF="mailto:harris@openmarket.com">Steve Harris // harris@openmarket.com</A>\r |
498 | </ADDRESS>\r |
499 | </BODY>\r |
500 | </HTML>\r |
501 | \r |