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