00001 package com.quadcap.http.servlets.cgi;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.ByteArrayOutputStream;
00042
import java.io.File;
00043
import java.io.FileOutputStream;
00044
import java.io.InputStream;
00045
import java.io.IOException;
00046
import java.io.OutputStream;
00047
00048
import java.util.Hashtable;
00049
import java.util.Enumeration;
00050
import java.util.Vector;
00051
00052
import java.net.URLEncoder;
00053
00054
import javax.servlet.ServletException;
00055
00056
import javax.servlet.http.HttpServletRequest;
00057
import javax.servlet.http.HttpServletResponse;
00058
00059
import com.quadcap.http.util.HeaderParser;
00060
00061
import com.quadcap.io.LogInputStream;
00062
00063
import com.quadcap.util.text.Scanner;
00064
00065
import com.quadcap.util.Debug;
00066
00067
00068
00069
00070
00071
00072 public class CgiScript {
00073 CgiServlet servlet;
00074 File
script;
00075 String
interp;
00076
00077 static final String
FORM_ENCODED =
"application/x-www-form-urlencoded";
00078
00079 public CgiScript(
CgiServlet servlet, String interp, File script) {
00080
this.servlet = servlet;
00081
this.interp = interp;
00082
this.script = script;
00083 }
00084
00085 final String
ns(String s) {
00086
return s == null ?
"" : s;
00087 }
00088
00089 public synchronized void service(HttpServletRequest req,
00090 HttpServletResponse res)
00091
throws IOException, ServletException
00092 {
00093
boolean form =
false;
00094 byte[] formData = null;
00095
if (req.getMethod().equalsIgnoreCase(
"POST") &&
00096 req.getContentType().equalsIgnoreCase(
FORM_ENCODED)) {
00097 form =
true;
00098 ByteArrayOutputStream bos =
new ByteArrayOutputStream();
00099 Enumeration ed = req.getParameterNames();
00100
boolean first =
true;
00101
while (ed.hasMoreElements()) {
00102 String name = ed.nextElement().toString();
00103 String [] vals = req.getParameterValues(name);
00104
for (
int i = 0; i < vals.length; i++) {
00105
if (!first) bos.write(
'&');
00106 first =
false;
00107 bos.write(URLEncoder.encode(name).getBytes());
00108 bos.write(
'=');
00109 bos.write(URLEncoder.encode(vals[i]).getBytes());
00110 }
00111 }
00112 formData = bos.toByteArray();
00113 }
else {
00114 formData =
new byte[0];
00115 }
00116
00117
if (
Trace.bit(2)) {
00118
Debug.println(
"formData = " +
new String(formData));
00119 }
00120
00121
00122
00123 Vector env =
new Vector();
00124
if (form) {
00125 env.addElement(
"CONTENT_LENGTH=" + formData.length);
00126 }
else {
00127 env.addElement(
"CONTENT_LENGTH=" + req.getContentLength());
00128 }
00129 env.addElement(
"CONTENT_TYPE=" + req.getContentType());
00130 env.addElement(
"DOCUMENT_ROOT=" +
00131
servlet.getServletConfig().getServletContext().getRealPath(
"."));
00132 env.addElement(
"GATEWAY_INTERFACE=1.1");
00133 env.addElement(
"HTTP_ACCEPT=" + req.getHeader(
"Http-Accept"));
00134 env.addElement(
"HTTP_USER_AGENT=" + req.getHeader(
"User-Agent"));
00135 env.addElement(
"PATH_INFO=" + ns(req.getPathInfo()));
00136 env.addElement(
"QUERY_STRING=" + req.getQueryString());
00137 env.addElement(
"REQUEST_METHOD=" + req.getMethod());
00138 env.addElement(
"SCRIPT_NAME=" + req.getServletPath());
00139 env.addElement(
"SERVER_NAME=" + req.getServerName());
00140 env.addElement(
"SERVER_PORT=" + req.getServerPort());
00141 env.addElement(
"SERVER_PROTOCOL=" + req.getProtocol());
00142
00143 String[] envp =
new String[env.size()];
00144
for (
int i = 0; i < env.size(); i++) {
00145 envp[i] = env.elementAt(i).toString();
00146
00147
if (
Trace.bit(2)) {
00148
Debug.println(
" " + envp[i]);
00149 }
00150
00151 }
00152
00153 String[] cmdp =
new String[2];
00154
00155 cmdp[0] =
interp;
00156 cmdp[1] =
script.getAbsolutePath();
00157
00158 res.setContentType(
"text/html");
00159
00160
00161
if (
Trace.bit(0)) {
00162
Debug.println(
"Invoking: " + cmdp[0] +
" " + cmdp[1]);
00163 }
00164
00165 Process cgi = Runtime.getRuntime().exec(cmdp, envp);
00166 InputStream pi = cgi.getInputStream();
00167
00168
00169
00170
00171
00172 OutputStream po = cgi.getOutputStream();
00173 InputStream pe = cgi.getErrorStream();
00174
00175 OutputStream so = res.getOutputStream();
00176 ByteArrayOutputStream se =
new ByteArrayOutputStream();
00177
00178 Thread t1 =
makeInputThread(formData, po);
00179 Thread t2 =
makeOutputThread(pi, so, res);
00180 Thread t3 =
makeCopyThread(pe, se);
00181
00182 t1.start();
00183 t2.start();
00184 t3.start();
00185
int ret = 0;
00186
00187
try { ret = cgi.waitFor(); }
catch (Exception e) {}
00188
try { t1.join(); }
catch (Exception e) {}
00189
try { t2.join(); }
catch (Exception e) {}
00190
try { t3.join(); }
catch (Exception e) {}
00191
00192
00193
if (
Trace.bit(1)) {
00194
Debug.println(
"stderr: " + se.toString());
00195 }
00196
00197
00198
00199
if (ret != 0) {
00200
throw new ServletException(
"Script failed: " + se.toString());
00201 }
00202 }
00203
00204
00205
00206
00207
00208 public static Thread
makeInputThread(
final byte[] formData,
00209
final OutputStream out) {
00210 Thread t =
new Thread() {
00211
public void run() {
00212
int c;
00213
try {
00214 out.write(formData);
00215 out.close();
00216 }
catch (IOException e) {
00217
Debug.print(e);
00218 }
00219 }
00220 };
00221
return t;
00222 }
00223
00224 public static Thread
makeOutputThread(
final InputStream in,
00225
final OutputStream out,
00226
final HttpServletResponse res) {
00227 Thread t =
new Thread() {
00228 Hashtable headers =
new Hashtable();
00229
Scanner scanner =
new Scanner(in);
00230
boolean terminate =
false;
00231
public void run() {
00232
int c;
00233
try {
00234
try {
00235
HeaderParser.parseHeaders(scanner, headers);
00236 }
catch (Throwable e) {
00237
Debug.print(e);
00238
00239
Debug.println(
"scanner = " + scanner.
getLog());
00240
00241 }
00242 Enumeration e = headers.keys();
00243
while (e.hasMoreElements()) {
00244 String hdr = (String)e.nextElement();
00245 String val = (String)headers.get(hdr);
00246
if (hdr.equals(
"status")) {
00247
int code = Integer.parseInt(val.substring(0,3));
00248 String reason = val.substring(4);
00249
if (code == 303) {
00250 res.sendRedirect(reason);
00251
return;
00252 }
else {
00253 res.setStatus(code, reason);
00254 }
00255 }
else if (hdr.equals(
"content-type")) {
00256 res.setContentType(val);
00257 }
else if (hdr.equals(
"location")) {
00258 res.sendRedirect(val);
00259 }
else {
00260 res.setHeader(hdr, val);
00261 }
00262 }
00263
00264
while (!terminate && (c = in.read()) >= 0) {
00265 out.write(c);
00266 }
00267 }
catch (IOException e) {
00268
Debug.print(e);
00269 }
00270 }
00271
public void terminate() {
00272
this.terminate =
true;
00273 }
00274 };
00275
return t;
00276 }
00277
00278
00279
00280
00281
00282 public static Thread
makeCopyThread(
final InputStream in,
00283
final OutputStream out) {
00284 Thread t =
new Thread() {
00285
boolean terminate =
false;
00286
public void run() {
00287
int c;
00288
try {
00289
while (!terminate && (c = in.read()) >= 0) out.write(c);
00290 }
catch (IOException e) {
00291
Debug.print(e);
00292 }
00293 }
00294
public void terminate() {
00295
this.terminate =
true;
00296 }
00297 };
00298
return t;
00299 }
00300
00301 }
00302