1
+ package javaxt .http .servlet ;
2
+ import java .io .IOException ;
3
+ import java .io .InputStream ;
4
+ import java .io .OutputStream ;
5
+ import java .util .StringTokenizer ;
6
+
7
+ //******************************************************************************
8
+ //** CGI Servlet
9
+ //******************************************************************************
10
+ /**
11
+ * Http Servlet used to run CGI programs. Based on CgiServlet.java, v1.8
12
+ * developed by Jef Poskanzer (acme.com).
13
+ *
14
+ ******************************************************************************/
15
+
16
+ public class CgiServlet extends HttpServlet {
17
+
18
+ private java .io .File executable ;
19
+
20
+ //**************************************************************************
21
+ //** Constructor
22
+ //**************************************************************************
23
+
24
+ public CgiServlet (java .io .File executable ){
25
+ this .executable = executable ;
26
+ }
27
+
28
+
29
+ //**************************************************************************
30
+ //** getServletInfo
31
+ //**************************************************************************
32
+ /** Returns a string containing information about the author, version, and
33
+ * copyright of the servlet.
34
+ */
35
+ public String getServletInfo () {
36
+ return "JavaXT CGI Servlet" ;
37
+ }
38
+
39
+
40
+ //**************************************************************************
41
+ //** getParameters
42
+ //**************************************************************************
43
+ /** Returns a list of parameters that are used to instantiate the CGI
44
+ * application.
45
+ */
46
+ protected java .util .ArrayList <String > getParameters (HttpServletRequest request ){
47
+ java .util .ArrayList <String > env = new java .util .ArrayList <String >();
48
+ //env.add("PATH=" + "/usr/local/bin:/usr/ucb:/bin:/usr/bin");
49
+ env .add ("GATEWAY_INTERFACE=" + "CGI/1.1" );
50
+ env .add ("SERVER_SOFTWARE=" + getServletContext ().getServerInfo ());
51
+ env .add ("SERVER_PROTOCOL=" + request .getProtocol ());
52
+ env .add ("SERVER_NAME=" + request .getServerName ());
53
+ env .add ("SERVER_PORT=" + request .getServerPort ());
54
+ env .add ("REMOTE_ADDR=" + request .getRemoteAddr ());
55
+ env .add ("REMOTE_HOST=" + request .getRemoteHost ());
56
+ env .add ("REQUEST_METHOD=" + request .getMethod ());
57
+ env .add ("SCRIPT_NAME=" + request .getServletPath ());
58
+
59
+ int contentLength = request .getContentLength ();
60
+ if (contentLength !=-1 ) env .add ("CONTENT_LENGTH=" + contentLength );
61
+
62
+ String contentType = request .getContentType ();
63
+ if (contentType !=null ) env .add ("CONTENT_TYPE=" + contentType );
64
+
65
+ String pathInfo = request .getPathInfo ();
66
+ if (pathInfo !=null ) env .add ("PATH_INFO=" + pathInfo );
67
+
68
+ String pathTranslated = request .getPathTranslated ();
69
+ if (pathTranslated !=null ) env .add ("PATH_TRANSLATED=" + pathTranslated );
70
+
71
+ String queryString = request .getQueryString ();
72
+ if (queryString !=null ) env .add ("QUERY_STRING=" + queryString );
73
+
74
+ String remoteUser = request .getRemoteUser ();
75
+ if (remoteUser !=null ) env .add ("REMOTE_USER=" + remoteUser );
76
+
77
+ String authType = request .getAuthType ();
78
+ if (authType !=null ) env .add ("AUTH_TYPE=" + authType );
79
+
80
+ java .util .Enumeration <String > hnEnum = request .getHeaderNames ();
81
+ while (hnEnum .hasMoreElements ()) {
82
+ String name = hnEnum .nextElement ();
83
+ String value = request .getHeader (name );
84
+ if (value == null ) value = "" ;
85
+ env .add ("HTTP_" + name .toUpperCase ().replace ('-' , '_' ) + "=" + value );
86
+ }
87
+ return env ;
88
+ }
89
+
90
+
91
+ //**************************************************************************
92
+ //** processRequest
93
+ //**************************************************************************
94
+ /** Services a single request from the client.
95
+ * @param request the servlet request
96
+ * @param response the servlet response
97
+ * @exception ServletException when an exception has occurred
98
+ */
99
+ public void processRequest (HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException {
100
+ String method = request .getMethod ().toUpperCase ();
101
+ if (!(method .equals ("GET" ) || method .equals ("POST" ))) {
102
+ response .sendError (HttpServletResponse .SC_NOT_IMPLEMENTED );
103
+ return ;
104
+ }
105
+
106
+
107
+ //Generate a list of parameters used to instantiate the CGI application
108
+ java .util .ArrayList <String > env = getParameters (request );
109
+ String [] parameters = new String [env .size ()+1 ];
110
+ parameters [0 ] = executable .toString ();
111
+ for (int i =0 ; i <parameters .length ; i ++){
112
+ if (i >0 ) parameters [i ] = env .get (i -1 );
113
+ }
114
+
115
+
116
+ try {
117
+
118
+ //Run executable via Command Line
119
+ Runtime runtime = Runtime .getRuntime ();
120
+ Process process = runtime .exec (parameters , null , executable .getParentFile ());
121
+
122
+
123
+ //If this is a POST, pass the body of the request to the process
124
+ if (method .equals ("POST" )) {
125
+ OutputStream outputStream = process .getOutputStream ();
126
+ InputStream inputStream = request .getInputStream ();
127
+ byte [] b = new byte [1024 ];
128
+ int x =0 ;
129
+ while ( (x = inputStream .read (b )) != -1 ) {
130
+ outputStream .write (b ,0 ,x );
131
+ }
132
+ inputStream .close ();
133
+ outputStream .close ();
134
+ }
135
+
136
+
137
+ //Parse output streams
138
+ StreamReader s1 = new StreamReader (process .getInputStream (), response );
139
+ ErrorStreamReader s2 = new ErrorStreamReader (process .getErrorStream ());
140
+ s1 .start ();
141
+ s2 .start ();
142
+ process .waitFor ();
143
+ s1 .join ();
144
+ s2 .join ();
145
+
146
+
147
+ //Explicitly clean up every the process by calling close on each stream
148
+ try {process .getInputStream ().close ();} catch (Exception ex ){}
149
+ try {process .getErrorStream ().close ();} catch (Exception ex ){}
150
+ try {process .getOutputStream ().close ();} catch (Exception ex ){}
151
+
152
+ //Explicitly destroy the process even if the process is already terminated
153
+ try {process .destroy ();} catch (Exception ex ){}
154
+
155
+ process = null ;
156
+
157
+ }
158
+ catch (IOException e ){
159
+ throw e ;
160
+ }
161
+ catch (InterruptedException e ){
162
+ //throw e;
163
+ return ;
164
+ }
165
+ }
166
+
167
+
168
+ //**************************************************************************
169
+ //** StreamReader Class
170
+ //**************************************************************************
171
+ /** Thread used to process the standard output stream. */
172
+
173
+ private class StreamReader implements Runnable {
174
+
175
+ private InputStream is ;
176
+ private HttpServletResponse response ;
177
+ private Thread thread ;
178
+ private byte [] b = new byte [1 ];
179
+
180
+ public StreamReader (InputStream is , HttpServletResponse response ){
181
+ this .is = is ;
182
+ this .response = response ;
183
+ }
184
+
185
+ public void start () {
186
+ thread = new Thread (this );
187
+ thread .start ();
188
+ }
189
+
190
+ public void run () {
191
+
192
+ try {
193
+ //Parse the list few lines returned from the executable. These
194
+ //may contain HTTP response headers
195
+ boolean firstLine = true ;
196
+ while (true ) {
197
+ String line = readLine ();
198
+ if (line ==null ) break ;
199
+ line = line .trim ();
200
+ if (line .equals ("" )) break ;
201
+
202
+ int colon = line .indexOf (":" );
203
+ if (colon == -1 ) {
204
+ // No colon. If it's the first line, parse it for status.
205
+ if (firstLine ) {
206
+ StringTokenizer tok = new StringTokenizer (line , " " );
207
+ try {
208
+ switch (tok .countTokens ()) {
209
+ case 2 :
210
+ tok .nextToken ();
211
+ response .setStatus (Integer .parseInt (tok .nextToken ()));
212
+ break ;
213
+ case 3 :
214
+ tok .nextToken ();
215
+ response .setStatus (Integer .parseInt (tok .nextToken ()), tok .nextToken ());
216
+ break ;
217
+ }
218
+ } catch (NumberFormatException ignore ) {
219
+ }
220
+ } else {
221
+ // No colon and it's not the first line? Ignore.
222
+ }
223
+ } else {
224
+ // There's a colon. Check for certain special headers.
225
+ String name = line .substring (0 , colon );
226
+ String value = line .substring (colon + 1 ).trim ();
227
+ if (name .equalsIgnoreCase ("Status" )) {
228
+ StringTokenizer tok = new StringTokenizer (value , " " );
229
+ try {
230
+ switch (tok .countTokens ()) {
231
+ case 1 :
232
+ response .setStatus (Integer .parseInt (tok .nextToken ()));
233
+ break ;
234
+ case 2 :
235
+ response .setStatus (Integer .parseInt (tok .nextToken ()), tok .nextToken ());
236
+ break ;
237
+ }
238
+ } catch (NumberFormatException ignore ) {
239
+ }
240
+ } else if (name .equalsIgnoreCase ("Content-type" )) {
241
+ response .setContentType (value );
242
+ } else if (name .equalsIgnoreCase ("Content-length" )) {
243
+ try {
244
+ response .setContentLength (Integer .parseInt (value ));
245
+ } catch (NumberFormatException ignore ) {
246
+ }
247
+ } else if (name .equalsIgnoreCase ("Location" )) {
248
+ response .setStatus (HttpServletResponse .SC_MOVED_TEMPORARILY );
249
+ response .setHeader (name , value );
250
+ } else if (name .equalsIgnoreCase ("Set-Cookie" )) {
251
+ int x = value .indexOf ("=" );
252
+ if (x > 0 ) {
253
+ String n = value .substring (0 , x );
254
+ String v = value .substring (x + 1 ).trim ();
255
+ response .addCookie (new Cookie (n , v ));
256
+ }
257
+ } else {
258
+ // Not a special header. Just set it.
259
+ response .setHeader (name , value );
260
+ }
261
+ }
262
+ }
263
+
264
+
265
+ //Set transfer encoding
266
+ response .setHeader ("Transfer-Encoding" , "Chunked" );
267
+
268
+
269
+ //Tranfer remaining bytes from the standard output stream to
270
+ //the servlet output stream
271
+ OutputStream outputStream = response .getOutputStream ();
272
+ byte [] b = new byte [1024 ];
273
+ int x =0 ;
274
+ while ( (x = is .read (b )) != -1 ) {
275
+ outputStream .write (b ,0 ,x );
276
+ }
277
+
278
+ //Close the input and output streams
279
+ outputStream .close ();
280
+ is .close ();
281
+
282
+ }
283
+ catch (IOException e ) {
284
+ // response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
285
+ // There's some weird bug in Java, when reading from a Process
286
+ // you get a spurious IOException. We have to ignore it.
287
+ }
288
+ catch (Exception e ) {
289
+ e .printStackTrace ();
290
+ return ;
291
+ }
292
+ }
293
+
294
+ private String readLine () throws IOException {
295
+ StringBuffer str = new StringBuffer ();
296
+ while (true ){
297
+ if (is .read (b )==-1 ) break ;
298
+ byte c = b [0 ];
299
+ if (c =='\n' ) break ;
300
+ str .append ((char ) c );
301
+ }
302
+ return str .toString ();
303
+ }
304
+
305
+ public void join () throws InterruptedException {
306
+ thread .join ();
307
+ }
308
+
309
+ } //End StreamReader Class
310
+
311
+
312
+ //**************************************************************************
313
+ //** ErrorStreamReader Class
314
+ //**************************************************************************
315
+ /** Thread used to read the standard output streams. */
316
+
317
+ private class ErrorStreamReader implements Runnable {
318
+
319
+ private InputStream is ;
320
+ private Thread thread ;
321
+ private byte [] b = new byte [1 ];
322
+
323
+ public ErrorStreamReader (InputStream is ){
324
+ this .is = is ;
325
+ }
326
+
327
+ public void start () {
328
+ thread = new Thread (this );
329
+ thread .start ();
330
+ }
331
+
332
+ public void run () {
333
+ try {
334
+ while (true ) {
335
+ if (is .read (b )==-1 ) break ;
336
+ }
337
+ is .close ();
338
+ }
339
+ catch (Exception e ) {
340
+ //System.out.println ("Problem reading stream... :" + ex);
341
+ e .printStackTrace ();
342
+ return ;
343
+ }
344
+ }
345
+
346
+ public void join () throws InterruptedException {
347
+ thread .join ();
348
+ }
349
+
350
+ } //End ErrorStreamReader Class
351
+ }
0 commit comments