]> granicus.if.org Git - apache/commitdiff
Changed mod_cgi to not do single-byte reads to consume the
authorBrian Pane <brianp@apache.org>
Sat, 23 Mar 2002 23:19:41 +0000 (23:19 +0000)
committerBrian Pane <brianp@apache.org>
Sat, 23 Mar 2002 23:19:41 +0000 (23:19 +0000)
script headers

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@94151 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
include/util_script.h
modules/generators/mod_cgi.c
server/util_script.c

diff --git a/CHANGES b/CHANGES
index f045f9db9fd231443fc3c283dff5e52c2729ea6a..7251ef8aeeb3ba54710bca076545280a3ec5cfe7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,7 @@
 Changes with Apache 2.0.34-dev
 
+  *) Remove the single-byte socket reads for CGI headers [Brian Pane]
+
   *) When a proxied site was being served, Apache was replacing
      the original site Server header with it's own, which is not
      allowed by RFC2616. Fixed. [Graham Leggett]
diff --git a/STATUS b/STATUS
index 9f9bcd4285e800f681a840b8793eebadd3c5896e..57aa5129706704fbf082423b45b8beda6a7470ce 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -1,5 +1,5 @@
 APACHE 2.0 STATUS:                                              -*-text-*-
-Last modified at [$Date: 2002/03/22 19:35:47 $]
+Last modified at [$Date: 2002/03/23 23:19:41 $]
 
 Release:
 
@@ -188,6 +188,8 @@ RELEASE NON-SHOWSTOPPERS BUT WOULD BE REAL NICE TO WRAP THESE UP:
       to read from.
       Proposed solution in:
         Message-ID: <3C36ADAF.60601@cnet.com>
+      Update 3/23/2002: solution implemented for mod_cgi, mod_cgid remains
+        to be fixed
 
     * Try to get libtool inter-library dependency code working on AIX.
         Message-ID: <cm3n10lx555.fsf@rdu163-40-092.nc.rr.com>
index b1620c9b3bd90d12712d81444d569b1c746eeb41..8229f20cc12482a64b784d842f915b55ab4b3ca4 100644 (file)
@@ -59,6 +59,8 @@
 #ifndef APACHE_UTIL_SCRIPT_H
 #define APACHE_UTIL_SCRIPT_H
 
+#include "apr_buckets.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -124,6 +126,21 @@ AP_DECLARE(void) ap_add_common_vars(request_rec *r);
  */ 
 AP_DECLARE(int) ap_scan_script_header_err(request_rec *r, apr_file_t *f, char *buffer);
 
+/**
+ * Read headers output from a script, ensuring that the output is valid.  If
+ * the output is valid, then the headers are added to the headers out of the
+ * current request
+ * @param r The current request
+ * @param bb The brigade from which to read
+ * @param buffer Empty when calling the function.  On output, if there was an
+ *               error, the string that cause the error is stored here. 
+ * @return HTTP_OK on success, HTTP_INTERNAL_SERVER_ERROR otherwise
+ * @deffunc int ap_scan_script_header_err_brigade(request_rec *r, apr_bucket_brigade *bb, char *buffer)
+ */ 
+AP_DECLARE(int) ap_scan_script_header_err_brigade(request_rec *r,
+                                                  apr_bucket_brigade *bb,
+                                                  char *buffer);
+
 /**
  * Read headers strings from a script, ensuring that the output is valid.  If
  * the output is valid, then the headers are added to the headers out of the
index fb48e486cc2a6a7543c9fcc380ed25d319ec6e11..7336f0461f3b9b69c8d540573b01f767c7931abd 100644 (file)
@@ -261,7 +261,7 @@ static void log_script_err(request_rec *r, apr_file_t *script_err)
 }
 
 static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
-                 char *dbuf, const char *sbuf, apr_file_t *script_in
+                 char *dbuf, const char *sbuf, apr_bucket_brigade *bb
                   apr_file_t *script_err)
 {
     const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);
@@ -280,9 +280,11 @@ static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
          (apr_file_open(&f, conf->logname,
                   APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {
        /* Soak up script output */
+#if LATER
        while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
                             script_in) == APR_SUCCESS)
            continue;
+#endif /* LATER */
 
         log_script_err(r, script_err);
        return ret;
@@ -319,6 +321,7 @@ static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
     if (sbuf && *sbuf)
        apr_file_printf(f, "%s\n", sbuf);
 
+#if LATER
     if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_in) == APR_SUCCESS) {
        apr_file_puts("%stdout\n", f);
        apr_file_puts(argsbuffer, f);
@@ -327,6 +330,7 @@ static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
            apr_file_puts(argsbuffer, f);
        apr_file_puts("\n", f);
     }
+#endif /* LATER */
 
     if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == APR_SUCCESS) {
        apr_file_puts("%stderr\n", f);
@@ -337,7 +341,7 @@ static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
        apr_file_puts("\n", f);
     }
 
-    apr_file_close(script_in);
+    apr_brigade_destroy(bb);
     apr_file_close(script_err);
 
     apr_file_close(f);
@@ -464,29 +468,12 @@ static apr_status_t run_cgi_child(apr_file_t **script_out,
     
         if (rc != APR_SUCCESS) {
             /* Bad things happened. Everyone should have cleaned up. */
-#if APR_HAS_PROC_INVOKED
-            if (procnew->invoked) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
-                              "mod_cgi: failed to invoke process: %s", 
-                              procnew->invoked);
-            }
-            else
-#endif
             ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
-                          "mod_cgi: couldn't create child process: %s",
-                          r->filename);
+                        "couldn't create child process: %d: %s", rc, r->filename);
         }
         else {
             apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
 
-#if APR_HAS_PROC_INVOKED
-            if (procnew->invoked) {
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, rc, r,
-                              "mod_cgi invoked process: %s", 
-                              procnew->invoked);
-            }
-#endif
-
             *script_in = procnew->out;
             if (!*script_in)
                 return APR_EBADF;
@@ -559,6 +546,19 @@ static apr_status_t default_build_command(const char **cmd, const char ***argv,
     return APR_SUCCESS;
 }
 
+static void discard_script_output(apr_bucket_brigade *bb)
+{
+    apr_bucket *e;
+    const char *buf;
+    apr_size_t len;
+    apr_status_t rv;
+    APR_BRIGADE_FOREACH(e, bb) {
+        rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
+        if (!APR_STATUS_IS_SUCCESS(rv)) {
+            break;
+        }
+    }
+}
 
 static int cgi_handler(request_rec *r)
 {
@@ -705,20 +705,23 @@ static int cgi_handler(request_rec *r)
        const char *location;
        char sbuf[MAX_STRING_LEN];
        int ret;
+        conn_rec *c = r->connection;
 
-       if ((ret = ap_scan_script_header_err(r, script_in, sbuf))) {
-           return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err);
+        bb = apr_brigade_create(r->pool);
+        b = apr_bucket_pipe_create(script_in);
+        APR_BRIGADE_INSERT_TAIL(bb, b);
+        b = apr_bucket_eos_create();
+        APR_BRIGADE_INSERT_TAIL(bb, b);
+
+       if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) {
+           return log_script(r, conf, ret, dbuf, sbuf, bb, script_err);
        }
 
        location = apr_table_get(r->headers_out, "Location");
 
        if (location && location[0] == '/' && r->status == 200) {
-
-           /* Soak up all the script output */
-           while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
-                                script_in) == APR_SUCCESS) {
-               continue;
-           }
+            discard_script_output(bb);
+            apr_brigade_destroy(bb);
             log_script_err(r, script_err);
            /* This redirect needs to be a GET no matter what the original
             * method was.
@@ -739,15 +742,12 @@ static int cgi_handler(request_rec *r)
            /* XX Note that if a script wants to produce its own Redirect
             * body, it now has to explicitly *say* "Status: 302"
             */
+            discard_script_output(bb);
+            apr_brigade_destroy(bb);
            return HTTP_MOVED_TEMPORARILY;
        }
 
        if (!r->header_only) {
-            bb = apr_brigade_create(r->pool);
-           b = apr_bucket_pipe_create(script_in);
-           APR_BRIGADE_INSERT_TAIL(bb, b);
-            b = apr_bucket_eos_create();
-           APR_BRIGADE_INSERT_TAIL(bb, b);
            ap_pass_brigade(r->output_filters, bb);
        }
 
@@ -756,6 +756,7 @@ static int cgi_handler(request_rec *r)
     }
 
     if (script_in && nph) {
+        conn_rec *c = r->connection;
         struct ap_filter_t *cur;
         
         /* get rid of all filters up through protocol...  since we
index 351b08b5a2b9e490ee2f5fa2f40838954e7506d6..7a790d577ddb6beed72ff1f05bad2e8919926ef9 100644 (file)
@@ -618,6 +618,58 @@ AP_DECLARE(int) ap_scan_script_header_err(request_rec *r, apr_file_t *f,
     return ap_scan_script_header_err_core(r, buffer, getsfunc_FILE, f);
 }
 
+static int getsfunc_BRIGADE(char *buf, int len, void *arg)
+{
+    apr_bucket_brigade *bb = (apr_bucket_brigade *)arg;
+    const char *dst_end = buf + len - 1; /* leave room for terminating null */
+    char *dst = buf;
+    apr_bucket *e = APR_BRIGADE_FIRST(bb);
+    apr_status_t rv;
+    int done = 0;
+
+    while ((dst < dst_end) && !done && !APR_BUCKET_IS_EOS(e)) {
+        const char *bucket_data;
+        apr_size_t bucket_data_len;
+        const char *src;
+        const char *src_end;
+        apr_bucket * next;
+
+        rv = apr_bucket_read(e, &bucket_data, &bucket_data_len,
+                             APR_BLOCK_READ);
+        if (!APR_STATUS_IS_SUCCESS(rv)) {
+            return 0;
+        }
+        src = bucket_data;
+        src_end = bucket_data + bucket_data_len;
+        while ((src < src_end) && (dst < dst_end) && !done) {
+            if (*src == '\n') {
+                done = 1;
+            }
+            else {
+                *dst++ = *src;
+            }
+            src++;
+        }
+
+        if (src < src_end) {
+            apr_bucket_split(e, src - bucket_data);
+        }
+        next = APR_BUCKET_NEXT(e);
+        APR_BUCKET_REMOVE(e);
+        apr_bucket_destroy(e);
+        e = next;
+    }
+    *dst = 0;
+    return 1;
+}
+
+AP_DECLARE(int) ap_scan_script_header_err_brigade(request_rec *r,
+                                                  apr_bucket_brigade *bb,
+                                                  char *buffer)
+{
+    return ap_scan_script_header_err_core(r, buffer, getsfunc_BRIGADE, bb);
+}
+
 struct vastrs {
     va_list args;
     int arg;