Fix a spelling mistake in the docs.
[catagits/fcgi2.git] / java / FCGIInterface.java
CommitLineData
61962ef7 1/*
2 * @(#)FCGIInterface.java
3 *
4 *
5 * FastCGi compatibility package Interface
6 *
7 *
8 * Copyright (c) 1996 Open Market, Inc.
9 *
10 * See the file "LICENSE.TERMS" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 *
58760be7 13 * $Id: FCGIInterface.java,v 1.4 2000/03/27 15:37:25 robs Exp $
61962ef7 14 */
07c41236 15package com.fastcgi;
61962ef7 16
17import java.net.*;
18import java.io.*;
19import java.util.Properties;
61962ef7 20
21/*
22 * This is the FastCGI interface that the application calls to communicate with the
23 * FastCGI web server. This version is single threaded, and handles one request at
24 * a time, which is why we can have a static variable for it.
25 */
05f58140 26public class FCGIInterface
27{
58760be7 28 private static final String RCSID = "$Id: FCGIInterface.java,v 1.4 2000/03/27 15:37:25 robs Exp $";
61962ef7 29
30 /*
31 * Class variables
32 */
33 public static FCGIRequest request = null;
34 public static boolean acceptCalled = false;
35 public static boolean isFCGI = true;
36 public static Properties startupProps;
37 public static ServerSocket srvSocket;
38
39 /*
40 * Accepts a new request from the HTTP server and creates
41 * a conventional execution environment for the request.
42 * If the application was invoked as a FastCGI server,
43 * the first call to FCGIaccept indicates that the application
44 * has completed its initialization and is ready to accept
45 * a request. Subsequent calls to FCGI_accept indicate that
46 * the application has completed its processing of the
47 * current request and is ready to accept a new request.
48 * If the application was invoked as a CGI program, the first
49 * call to FCGIaccept is essentially a no-op and the second
50 * call returns EOF (-1) as does an error. Application should exit.
51 *
52 * If the application was invoked as a FastCGI server,
53 * and this is not the first call to this procedure,
54 * FCGIaccept first flushes any buffered output to the HTTP server.
55 *
56 * On every call, FCGIaccept accepts the new request and
57 * reads the FCGI_PARAMS stream into System.props. It also creates
58 * streams that understand FastCGI protocol and take input from
59 * the HTTP server send output and error output to the HTTP server,
60 * and assigns these new streams to System.in, System.out and
61 * System.err respectively.
62 *
63 * For now, we will just return an int to the caller, which is why
64 * this method catches, but doen't throw Exceptions.
65 *
66 */
67 public int FCGIaccept() {
68 int acceptResult = 0;
69
70 /*
71 * If first call, mark it and if fcgi save original system properties,
72 * If not first call, and we are cgi, we should be gone.
73 */
74 if (!acceptCalled){
75 isFCGI = System.getProperties().containsKey("FCGI_PORT");
76 acceptCalled = true;
77 if (isFCGI) {
78 /*
79 * save original system properties (nonrequest)
80 * and get a server socket
81 */
61962ef7 82 startupProps = new Properties(System.getProperties());
83 String str =
84 new String(System.getProperty("FCGI_PORT"));
85 if (str.length() <= 0) {
86 return -1;
87 }
88 int portNum = Integer.parseInt(str);
89
90 try {
91 srvSocket = new ServerSocket(portNum);
92 } catch (IOException e) {
58760be7 93 if (request != null)
94 {
95 request.socket = null;
96 }
61962ef7 97 srvSocket = null;
98 request = null;
99 return -1;
100 }
101 }
102 }
103 else {
104 if (!isFCGI){
105 return -1;
106 }
107 }
108 /*
109 * If we are cgi, just leave everything as is, otherwise set up env
110 */
111 if (isFCGI){
112 try {
113 acceptResult = FCGIAccept();
114 } catch (IOException e) {
115 return -1;
116 }
117 if (acceptResult < 0){
118 return -1;
119 }
120
121 /*
122 * redirect stdin, stdout and stderr to fcgi socket
123 */
124 System.setIn(new BufferedInputStream(request.inStream, 8192));
125 System.setOut(new PrintStream(new BufferedOutputStream(
126 request.outStream, 8192)));
127 System.setErr(new PrintStream(new BufferedOutputStream(
128 request.errStream, 512)));
129 System.setProperties(request.params);
130 }
131 return 0;
132 }
133
134 /*
135 * Accepts a new request from the HTTP server.
136 * Finishes the request accepted by the previous call
137 * to FCGI_Accept. Sets up the FCGI environment and reads
138 * saved and per request environmental varaibles into
139 * the request object. (This is redundant on System.props
140 * as long as we can handle only one request object.)
141 */
142 int FCGIAccept() throws IOException{
143
144 boolean isNewConnection;
145 boolean errCloseEx = false;
146 boolean outCloseEx = false;
147
148 if (request != null) {
149 /*
150 * Complete the previous request
151 */
152 System.err.close();
153 System.out.close();
154 boolean prevRequestfailed = (errCloseEx || outCloseEx ||
155 request.inStream.getFCGIError() != 0 ||
156 request.inStream.getException() != null);
157 if (prevRequestfailed || !request.keepConnection ) {
158 request.socket.close();
159 request.socket = null;
160 }
161 if (prevRequestfailed) {
162 request = null;
163 return -1;
164 }
165 }
166 else {
167 /*
168 * Get a Request and initialize some variables
169 */
170 request = new FCGIRequest();
171 request.socket = null;
172 request.inStream = null;
173 }
174 isNewConnection = false;
175
176 /*
177 * if connection isnt open accept a new connection (blocking)
178 */
179 for(;;) {
180 if (request.socket == null){
181 try {
182 request.socket = srvSocket.accept();
183 } catch (IOException e) {
184 request.socket = null;
185 request = null;
186 return -1;
187 }
188 isNewConnection = true;
189 }
190
191 /* Try reading from new connection. If the read fails and
192 * it was an old connection the web server probably closed it;
193 * try making a new connection before giving up
194 */
195 request.isBeginProcessed = false;
196 request.inStream =
197 new FCGIInputStream((FileInputStream)request.
198 socket.getInputStream(),
199 8192, 0, request);
200 request.inStream.fill();
201 if (request.isBeginProcessed) {
202 break;
203 }
204 request.socket.close();
205
206 request.socket = null;
207 if (isNewConnection) {
208 return -1;
209 }
210 }
211 /*
212 * Set up the objects for the new request
213 */
214 request.params = new Properties(startupProps);
215 switch(request.role) {
216 case FCGIGlobalDefs.def_FCGIResponder:
217 request.params.put("ROLE","RESPONDER");
218 break;
219 case FCGIGlobalDefs.def_FCGIAuthorizer:
220 request.params.put("ROLE", "AUTHORIZER");
221 break;
222 case FCGIGlobalDefs.def_FCGIFilter:
223 request.params.put("ROLE", "FILTER");
224 break;
225 default:
226 return -1;
227 }
228 request.inStream.setReaderType(FCGIGlobalDefs.def_FCGIParams);
229 /*
230 * read the rest of request parameters
231 */
232 if (new FCGIMessage(request.inStream).readParams(request.params) < 0) {
233 return -1;
234 }
235 request.inStream.setReaderType(FCGIGlobalDefs.def_FCGIStdin);
236 request.outStream
237 = new FCGIOutputStream((FileOutputStream)request.socket.
238 getOutputStream(), 8192,
239 FCGIGlobalDefs.def_FCGIStdout,request);
240 request.errStream
241 = new FCGIOutputStream((FileOutputStream)request.socket.
242 getOutputStream(), 512,
243 FCGIGlobalDefs.def_FCGIStderr,request);
244 request.numWriters = 2;
245 return 0;
246 }
247}