You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2004/06/16 01:13:04 UTC
cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets CGIServlet.java
markt 2004/06/15 16:13:04
Modified: catalina/src/share/org/apache/catalina/servlets
CGIServlet.java
Log:
Fix CGI servlet so it correctly handles binary responses (eg images)
Revision Changes Path
1.23 +135 -25 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java
Index: CGIServlet.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- CGIServlet.java 22 Apr 2004 20:46:56 -0000 1.22
+++ CGIServlet.java 15 Jun 2004 23:13:04 -0000 1.23
@@ -69,6 +69,7 @@
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedOutputStream;
import java.io.IOException;
@@ -1645,6 +1646,7 @@
*/
Runtime rt = null;
BufferedReader commandsStdOut = null;
+ InputStream cgiOutput = null;
BufferedReader commandsStdErr = null;
BufferedOutputStream commandsStdIn = null;
Process proc = null;
@@ -1732,8 +1734,6 @@
*/
boolean isRunning = true;
- commandsStdOut = new BufferedReader
- (new InputStreamReader(proc.getInputStream()));
commandsStdErr = new BufferedReader
(new InputStreamReader(proc.getErrorStream()));
BufferedWriter servletContainerStdout = null;
@@ -1755,14 +1755,17 @@
} ;
}.start() ;
-
+ InputStream cgiHeaderStream =
+ new HTTPHeaderInputStream(proc.getInputStream());
+ BufferedReader cgiHeaderReader =
+ new BufferedReader(new InputStreamReader(cgiHeaderStream));
+ boolean isBinaryContent = false;
+
while (isRunning) {
-
try {
-
//set headers
String line = null;
- while (((line = commandsStdOut.readLine()) != null)
+ while (((line = cgiHeaderReader.readLine()) != null)
&& !("".equals(line))) {
if (debug >= 2) {
log("runCGI: addHeader(\"" + line + "\")");
@@ -1773,27 +1776,50 @@
* response.setStatus(getStatusCode(line));
*/
} else if (line.indexOf(":") >= 0) {
- response.addHeader
- (line.substring(0, line.indexOf(":")).trim(),
- line.substring(line.indexOf(":") + 1).trim());
+ String header =
+ line.substring(0, line.indexOf(":")).trim();
+ String value =
+ line.substring(line.indexOf(":") + 1).trim();
+ response.addHeader(header , value);
+ if ((header.toLowerCase().equals("content-type"))
+ && (!value.toLowerCase().startsWith("text"))) {
+ isBinaryContent = true;
+ }
} else {
log("runCGI: bad header line \"" + line + "\"");
}
}
//write output
- char[] cBuf = new char[1024];
- while ((bufRead = commandsStdOut.read(cBuf)) != -1) {
- if (servletContainerStdout != null) {
+ if (isBinaryContent) {
+ byte[] bBuf = new byte[2048];
+ OutputStream out = response.getOutputStream();
+ cgiOutput = proc.getInputStream();
+ while ((bufRead = cgiOutput.read(bBuf)) != -1) {
if (debug >= 4) {
- log("runCGI: write(\"" + new String(cBuf, 0, bufRead) + "\")");
+ log("runCGI: output " + bufRead +
+ " bytes of binary data");
}
- servletContainerStdout.write(cBuf, 0, bufRead);
+ out.write(bBuf, 0, bufRead);
}
- }
+ } else {
+ commandsStdOut = new BufferedReader
+ (new InputStreamReader(proc.getInputStream()));
- if (servletContainerStdout != null) {
- servletContainerStdout.flush();
+ char[] cBuf = new char[1024];
+ while ((bufRead = commandsStdOut.read(cBuf)) != -1) {
+ if (servletContainerStdout != null) {
+ if (debug >= 4) {
+ log("runCGI: write(\"" +
+ new String(cBuf, 0, bufRead) + "\")");
+ }
+ servletContainerStdout.write(cBuf, 0, bufRead);
+ }
+ }
+
+ if (servletContainerStdout != null) {
+ servletContainerStdout.flush();
+ }
}
proc.exitValue(); // Throws exception if alive
@@ -1807,7 +1833,8 @@
}
}
} //replacement for Process.waitFor()
- commandsStdOut.close() ;
+ commandsStdOut.close();
+ cgiOutput.close();
}
private void sendToLog(BufferedReader rdr) {
@@ -1889,4 +1916,87 @@
}
}
+ /**
+ * This is an input stream specifically for reading HTTP headers. It reads
+ * upto and including the two blank lines terminating the headers. It
+ * allows the content to be read using bytes or characters as appropriate.
+ */
+ protected class HTTPHeaderInputStream extends InputStream {
+ private static final int STATE_CHARACTER = 0;
+ private static final int STATE_FIRST_CR = 1;
+ private static final int STATE_FIRST_LF = 2;
+ private static final int STATE_SECOND_CR = 3;
+ private static final int STATE_HEADER_END = 4;
+
+ private InputStream input;
+ private int state;
+
+ HTTPHeaderInputStream(InputStream theInput) {
+ input = theInput;
+ state = STATE_CHARACTER;
+ }
+
+ /**
+ * @see java.io.InputStream#read()
+ */
+ public int read() throws IOException {
+ if (state == STATE_HEADER_END) {
+ return -1;
+ }
+
+ int i = input.read();
+
+ // Update the state
+ // State machine looks like this
+ //
+ // -------->--------
+ // | (CR) |
+ // | |
+ // CR1--->--- |
+ // | | |
+ // ^(CR) |(LF) |
+ // | | |
+ // CHAR--->--LF1--->--EOH
+ // (LF) | (LF) |
+ // |(CR) ^(LF)
+ // | |
+ // (CR2)-->---
+
+ if (i == 10) {
+ // LF
+ switch(state) {
+ case STATE_CHARACTER:
+ state = STATE_FIRST_LF;
+ break;
+ case STATE_FIRST_CR:
+ state = STATE_FIRST_LF;
+ break;
+ case STATE_FIRST_LF:
+ case STATE_SECOND_CR:
+ state = STATE_HEADER_END;
+ break;
+ }
+
+ } else if (i == 13) {
+ // CR
+ switch(state) {
+ case STATE_CHARACTER:
+ state = STATE_FIRST_CR;
+ break;
+ case STATE_FIRST_CR:
+ state = STATE_HEADER_END;
+ break;
+ case STATE_FIRST_LF:
+ state = STATE_SECOND_CR;
+ break;
+ }
+
+ } else {
+ state = STATE_CHARACTER;
+ }
+
+ return i;
+ }
+ } // class HTTPHeaderInputStream
+
} //class CGIServlet
---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org