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