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