markt       2004/06/15 16:13:57

  Modified:    catalina/src/share/org/apache/catalina/servlets
                        CGIServlet.java
  Log:
  Fix CGI servlet so it correctly handles binary responses (eg images)
    - Ported from TC4
  
  Revision  Changes    Path
  1.21      +133 -23   
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java
  
  Index: CGIServlet.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- CGIServlet.java   26 May 2004 16:02:59 -0000      1.20
  +++ CGIServlet.java   15 Jun 2004 23:13:57 -0000      1.21
  @@ -26,6 +26,7 @@
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.InputStreamReader;
  +import java.io.OutputStream;
   import java.io.OutputStreamWriter;
   import java.net.URLEncoder;
   import java.util.ArrayList;
  @@ -1594,6 +1595,7 @@
                */
               Runtime rt = null;
               BufferedReader commandsStdOut = null;
  +            InputStream cgiOutput = null;
               BufferedReader commandsStdErr = null;
               BufferedOutputStream commandsStdIn = null;
               Process proc = null;
  @@ -1681,8 +1683,6 @@
                */
   
               boolean isRunning = true;
  -            commandsStdOut = new BufferedReader
  -                (new InputStreamReader(proc.getInputStream()));
               commandsStdErr = new BufferedReader
                   (new InputStreamReader(proc.getErrorStream()));
               BufferedWriter servletContainerStdout = null;
  @@ -1704,14 +1704,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 + "\")");
  @@ -1722,27 +1725,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
  @@ -1756,7 +1782,8 @@
                       }
                   }
               } //replacement for Process.waitFor()
  -            commandsStdOut.close()  ;
  +            commandsStdOut.close();
  +            cgiOutput.close();
           }
   
           private void sendToLog(BufferedReader rdr) {
  @@ -1837,5 +1864,88 @@
               return value;
           }
       }
  +
  +    /**
  +     * 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to