Commit | Line | Data |
61962ef7 |
1 | /* |
2 | * @(#)FCGIInterface.java |
3 | * |
4 | * |
5 | * FastCGi compatibility package Interface |
6 | * |
7 | * |
8 | * Copyright (c) 1996 Open Market, Inc. |
9 | * |
af1b4cad |
10 | * See the file "LICENSE" for information on usage and redistribution |
61962ef7 |
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 |
15 | package com.fastcgi; |
61962ef7 |
16 | |
17 | import java.net.*; |
18 | import java.io.*; |
19 | import 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 |
26 | public 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 | } |