]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Enabled layered I/O. Docs are forthcoming.
authorRyan Bloom <rbb@apache.org>
Sat, 25 Mar 2000 15:00:10 +0000 (15:00 +0000)
committerRyan Bloom <rbb@apache.org>
Sat, 25 Mar 2000 15:00:10 +0000 (15:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@84837 13f79535-47bb-0310-9956-ffa450edef68

include/httpd.h
modules/filters/mod_include.c
modules/generators/mod_cgi.c
modules/http/http_core.c
modules/http/http_protocol.c
server/config.c

index a34490cf6b66803ff82feed2528cb8bce43449cc..56b1c715b7bc022ac408f712a902e10abc3b1b4c 100644 (file)
@@ -391,7 +391,10 @@ API_EXPORT(const char *) ap_get_server_built(void);
                                 *  - it's safe to die() with no more output
                                 */
 #define OK 0                   /* Module has handled this stage. */
-
+#define RERUN_HANDLERS 1        /* Module has handled this request, but
+                                 * realizes others may also want to handle
+                                 * it.
+                                 */
 
 /* ----------------------- HTTP Status Codes  ------------------------- */
 
@@ -580,6 +583,13 @@ struct request_rec {
     conn_rec *connection;
     server_rec *server;
 
+    BUFF *input;                /* Where to get the data (usually a pipe
+                                 * or a file currently). 
+                                 */
+    BUFF *output;               /* Where to send the data (usually, a pipe
+                                 * or the socket currently).
+                                 */
+
     request_rec *next;         /* If we wind up getting redirected,
                                 * pointer to the request we redirected to.
                                 */
index 2cd7cd1f49f3f46aedc77823fcd16b2ba5114d78..0f57f87678dfa4a04b4b42facdbd21bd3de5b59c 100644 (file)
@@ -2364,20 +2364,30 @@ static const char *set_xbithack(cmd_parms *cmd, void *xbp, char *arg)
     return NULL;
 }
 
-static int send_parsed_file(request_rec *r)
+struct {
+    ap_thread_t *thread;
+    request_rec *r;
+} ssi_rec;
+
+void * API_THREAD_FUNC sub_send_parsed_file(void *rec)
 {
     ap_file_t *f = NULL;
+    struct ssi_rec *dumb_rec = (struct ssi_rec *)rec;
+    ap_thread_t *subthread = dumb_rec->thread
+    request_rec *r = dumb_rec->r;
     enum xbithack *state =
     (enum xbithack *) ap_get_module_config(r->per_dir_config, &includes_module);
     int errstatus;
     request_rec *parent;
 
     if (!(ap_allow_options(r) & OPT_INCLUDES)) {
-        return DECLINED;
+        ap_thread_exit(0);
+/*        return DECLINED;*/
     }
     r->allowed |= (1 << M_GET);
     if (r->method_number != M_GET) {
-        return DECLINED;
+        ap_thread_exit(0);
+/*        return DECLINED;*/
     }
     if (r->finfo.protection == 0) {
         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
@@ -2385,7 +2395,8 @@ static int send_parsed_file(request_rec *r)
                     (r->path_info
                      ? ap_pstrcat(r->pool, r->filename, r->path_info, NULL)
                      : r->filename));
-        return HTTP_NOT_FOUND;
+        ap_thread_exit(0);
+/*        return HTTP_NOT_FOUND;*/
     }
 
     errstatus = ap_open(&f, r->filename, APR_READ, 0, r->pool);
@@ -2393,7 +2404,8 @@ static int send_parsed_file(request_rec *r)
     if (errstatus != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, errstatus, r,
                     "file permissions deny server access: %s", r->filename);
-        return HTTP_FORBIDDEN;
+        ap_thread_exit(0);
+/*        return HTTP_FORBIDDEN;*/
     }
 
     if ((*state == xbithack_full)
@@ -2406,14 +2418,16 @@ static int send_parsed_file(request_rec *r)
         ap_set_last_modified(r);
     }
     if ((errstatus = ap_meets_conditions(r)) != OK) {
-        return errstatus;
+        ap_thread_exit(0);
+/*        return errstatus;*/
     }
 
     ap_send_http_header(r);
 
     if (r->header_only) {
         ap_close(f);
-        return OK;
+        ap_thread_exit(0);
+/*        return OK;*/
     }
 
     if ((parent = ap_get_module_config(r->request_config, &includes_module))) {
@@ -2453,8 +2467,39 @@ static int send_parsed_file(request_rec *r)
        ap_set_module_config(r->request_config, &includes_module,
            NESTED_INCLUDE_MAGIC);
     }
+    ap_thread_exit(0);
+/*    return OK;*/
+}
 
-    return OK;
+int send_parsed_file(request_rec *r)
+{
+    struct ssi_rec dumb_rec;
+    ap_thread_t *subthread = NULL;
+    ap_file_t *pipein = NULL;
+    ap_file_t *pipeout = NULL;
+    ap_iol *iolin;
+    ap_iol *iolout;
+    BUFF *bpipeint = NULL;
+    BUFF *bpipeout = NULL;
+
+    ap_create_pipe(&pipein, &pipeout, r->pool);
+
+    iolin = ap_create_file_iol(pipein);
+    ap_bpush_iol(bpipein, iolin);
+
+    iolout = ap_create_file_iol(pipeout);
+    ap_bpush_iol(bpipeout, iolout);
+    r->output = bpipeout;
+
+    ap_setup_input(r);
+
+    dumb_rec->thread = subthread;
+    dumb_rec->r = r;
+    ap_create_thread(&subthread, NULL, sub_send_parsed_file, dumb_rec, r->pool);
+    r->input = bpipein;
+        
+
+    return RERUN_HANDLERS;
 }
 
 static int send_shtml_file(request_rec *r)
index e07d42d1b40e98cf2e7c6c0378b286354db0eac3..374aa8f80ed468c3bce396158b91e357d3404f8a 100644 (file)
@@ -621,7 +621,9 @@ static int cgi_handler(request_rec *r)
            ap_table_unset(r->headers_in, "Content-Length");
 
            ap_internal_redirect_handler(location, r);
-           return OK;
+/*            r->content_type = NULL;*/
+            r->handler = NULL;
+           return RERUN_HANDLERS;
        }
        else if (location && r->status == 200) {
            /* XX Note that if a script wants to produce its own Redirect
@@ -630,12 +632,12 @@ static int cgi_handler(request_rec *r)
            return REDIRECT;
        }
 
-       ap_send_http_header(r);
+/*     ap_send_http_header(r);*/
        if (!r->header_only) {
-           ap_send_fb(script_in, r);
+            r->input = script_in;
        }
-       ap_bclose(script_in);
-
+/*     ap_bclose(script_in);
+*/
        while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) {
            continue;
        }
@@ -643,10 +645,12 @@ static int cgi_handler(request_rec *r)
     }
 
     if (script_in && nph) {
-       ap_send_fb(script_in, r);
+        r->input = script_in;
     }
 
-    return OK;                 /* NOT r->status, even if it has changed. */
+/*    r->content_type = NULL;*/
+    r->handler = NULL;
+    return RERUN_HANDLERS;     /* NOT r->status, even if it has changed. */
 }
 
 static const handler_rec cgi_handlers[] =
index b68372e9396ea1eabd194704be6712c69a78185c..d9369a0a659bd06d9e93b3f00aa8c0453a0cec44 100644 (file)
@@ -2530,12 +2530,15 @@ static int default_handler(request_rec *r)
     if (r->method_number != M_GET) {
         return METHOD_NOT_ALLOWED;
     }
-       
+/*     
     if ((status = ap_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->pool)) != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
                     "file permissions deny server access: %s", r->filename);
         return FORBIDDEN;
-    }
+    }*/
+
+    ap_setup_input(r);
+
     ap_update_mtime(r, r->finfo.mtime);
     ap_set_last_modified(r);
     ap_set_etag(r);
@@ -2583,7 +2586,7 @@ static int default_handler(request_rec *r)
        
        if (!r->header_only) {
            if (!rangestatus) {
-               ap_send_fd(fd, r);
+               ap_send_fb(r->input, r);
            }
            else {
                long     length;
@@ -2634,7 +2637,6 @@ static int default_handler(request_rec *r)
     }
 #endif
 
-    ap_close(fd);
     return OK;
 }
 
index e345e57eb180bc8db0de95591bdaede125aedc0f..b46004ee364fa7a901b87d4b93ce5e957fcc51a8 100644 (file)
@@ -959,6 +959,30 @@ static void get_mime_headers(request_rec *r)
     ap_overlap_tables(r->headers_in, tmp_headers, AP_OVERLAP_TABLES_MERGE);
 }
 
+ap_status_t ap_setup_input(request_rec *r)
+{
+    BUFF *temp = NULL;
+    ap_iol *iol;
+    ap_file_t *fd = NULL;
+    ap_status_t status;
+
+    if (!r->input) {
+        if ((status = ap_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->pool)) != APR_SUCCESS) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
+                         "file permissions deny server access: %s", r->filename);
+            return status;
+        }
+
+        iol = ap_create_file_iol(fd);
+        if (!iol)
+            return APR_EBADF;
+        temp = ap_bcreate(r->pool, B_RD);
+        ap_bpush_iol(temp, iol);   
+        r->input = temp;
+    }
+    return APR_SUCCESS;
+}
+
 request_rec *ap_read_request(conn_rec *conn)
 {
     request_rec *r;
@@ -1860,10 +1884,13 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
     long chunk_start = 0;
     unsigned long max_body;
     ap_status_t rv;
+    BUFF *used_buff;
+
+    used_buff = r->input ? r->input : r->connection->client;
 
     if (!r->read_chunked) {     /* Content-length read */
         len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
-        rv = ap_bread(r->connection->client, buffer, len_to_read, &len_read);
+        rv = ap_bread(used_buff, buffer, len_to_read, &len_read);
         if (len_read == 0) {    /* error or eof */
             if (rv != APR_SUCCESS) {
                 r->connection->keepalive = -1;
@@ -1902,7 +1929,7 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
 
     if (r->remaining == 0) {    /* Start of new chunk */
 
-        chunk_start = getline(buffer, bufsiz, r->connection->client, 0);
+        chunk_start = getline(buffer, bufsiz, used_buff, 0);
         if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
             || !ap_isxdigit(*buffer)) {
             r->connection->keepalive = -1;
@@ -1943,7 +1970,7 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
         len_read = chunk_start;
 
         while ((bufsiz > 1) && ((len_read =
-                  getline(buffer, bufsiz, r->connection->client, 1)) > 0)) {
+                  getline(buffer, bufsiz, used_buff, 1)) > 0)) {
 
             if (len_read != (bufsiz - 1)) {
                 buffer[len_read++] = CR;        /* Restore footer line end  */
@@ -1977,7 +2004,7 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
 
     len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
 
-    (void) ap_bread(r->connection->client, buffer, len_to_read, &len_read);
+    (void) ap_bread(used_buff, buffer, len_to_read, &len_read);
     if (len_read == 0) {        /* error or eof */
         r->connection->keepalive = -1;
         return -1;
@@ -1986,8 +2013,8 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
     r->remaining -= len_read;
 
     if (r->remaining == 0) {    /* End of chunk, get trailing CRLF */
-        if ((c = ap_bgetc(r->connection->client)) == CR) {
-            c = ap_bgetc(r->connection->client);
+        if ((c = ap_bgetc(used_buff)) == CR) {
+            c = ap_bgetc(used_buff);
         }
         if (c != LF) {
             r->connection->keepalive = -1;
@@ -2050,16 +2077,17 @@ API_EXPORT(int) ap_discard_request_body(request_rec *r)
  */
 API_EXPORT(long) ap_send_fd(ap_file_t *fd, request_rec *r)
 {
+    BUFF *used_buff = r->output ? r->output : r->connection->client;
     long len = r->finfo.size;
 #ifdef HAVE_SENDFILE
     if (!r->chunked) {
        ap_status_t rv;
-        ap_bsetopt(r->connection->client, BO_TIMEOUT,
+        ap_bsetopt(used_buff, BO_TIMEOUT,
                    r->connection->keptalive
                    ? &r->server->keep_alive_timeout
                    : &r->server->timeout);
-        ap_bflush(r->connection->client);
-        rv = iol_sendfile(r->connection->client->iol, 
+        ap_bflush(used_buff);
+        rv = iol_sendfile(used_buff->iol, 
                           fd,     /* The file to send */
                           NULL,   /* header and trailer iovecs */
                           0,      /* Offset in file to begin sending from */
@@ -2070,7 +2098,7 @@ API_EXPORT(long) ap_send_fd(ap_file_t *fd, request_rec *r)
                           "ap_send_fd: iol_sendfile failed.");
         }
         if (r->connection->keptalive) {
-            ap_bsetopt(r->connection->client, BO_TIMEOUT, 
+            ap_bsetopt(used_buff, BO_TIMEOUT, 
                        &r->server->timeout);
         }
     }
@@ -2091,6 +2119,7 @@ API_EXPORT(long) ap_send_fd_length(ap_file_t *fd, request_rec *r, long length)
     ap_ssize_t w;
     ap_ssize_t n;
     ap_status_t rv;
+    BUFF *used_buff = r->output ? r->output : r->connection->client;
 
     if (length == 0)
         return 0;
@@ -2113,7 +2142,7 @@ API_EXPORT(long) ap_send_fd_length(ap_file_t *fd, request_rec *r, long length)
         o = 0;
 
         while (n && !ap_is_aborted(r->connection)) {
-            rv = ap_bwrite(r->connection->client, &buf[o], n, &w);
+            rv = ap_bwrite(used_buff, &buf[o], n, &w);
             if (w > 0) {
                 total_bytes_sent += w;
                 n -= w;
@@ -2123,7 +2152,7 @@ API_EXPORT(long) ap_send_fd_length(ap_file_t *fd, request_rec *r, long length)
                 if (!ap_is_aborted(r->connection)) {
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
                      "client stopped connection before send body completed");
-                    ap_bsetflag(r->connection->client, B_EOUT, 1);
+                    ap_bsetflag(used_buff, B_EOUT, 1);
                     r->connection->aborted = 1;
                 }
                 break;
@@ -2152,6 +2181,7 @@ API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
     ap_ssize_t w;
     ap_ssize_t n;
     ap_status_t rv;
+    BUFF *used_buff = r->output ? r->output : r->connection->client;
 
     if (length == 0) {
         return 0;
@@ -2193,7 +2223,7 @@ API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
         
         o = 0;
         while (n && !ap_is_aborted(r->connection)) {
-            rv = ap_bwrite(r->connection->client, &buf[o], n, &w);
+            rv = ap_bwrite(used_buff, &buf[o], n, &w);
             if (w > 0) {
                 total_bytes_sent += w;
                 n -= w;
@@ -2203,7 +2233,7 @@ API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
                 if (!ap_is_aborted(r->connection)) {
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
                         "client stopped connection before rflush completed");
-                    ap_bsetflag(r->connection->client, B_EOUT, 1);
+                    ap_bsetflag(used_buff, B_EOUT, 1);
                     r->connection->aborted = 1;
                 }
                 break;
@@ -2238,6 +2268,7 @@ API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
     ap_ssize_t w;
     ap_status_t rv;
     char *addr;
+    BUFF *used_buff = r->output ? r->output : r->connection->client;
     
     if (length == 0)
         return 0;
@@ -2254,7 +2285,7 @@ API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
 
         while (n && !r->connection->aborted) {
             ap_mmap_offset((void**)&addr, mm, offset);
-            rv = ap_bwrite(r->connection->client, addr, n, &w);
+            rv = ap_bwrite(used_buff, addr, n, &w);
             if (w > 0) {
                 total_bytes_sent += w;
                 n -= w;
@@ -2268,7 +2299,7 @@ API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
                 else {
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
                      "client stopped connection before send mmap completed");
-                    ap_bsetflag(r->connection->client, B_EOUT, 1);
+                    ap_bsetflag(used_buff, B_EOUT, 1);
                     r->connection->aborted = 1;
                     break;
                 }
@@ -2283,15 +2314,16 @@ API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
 
 API_EXPORT(int) ap_rputc(int c, request_rec *r)
 {
+    BUFF *used_buff = r->output ? r->output : r->connection->client;
     if (r->connection->aborted)
         return EOF;
 
-    if (ap_bputc(c, r->connection->client) < 0) {
+    if (ap_bputc(c, used_buff) < 0) {
         if (!r->connection->aborted) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO,
-                ap_berror(r->connection->client), r,
+                ap_berror(used_buff), r,
                 "client stopped connection before rputc completed");
-            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            ap_bsetflag(used_buff, B_EOUT, 1);
             r->connection->aborted = 1;
         }
         return EOF;
@@ -2303,17 +2335,18 @@ API_EXPORT(int) ap_rputc(int c, request_rec *r)
 API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
 {
     int rcode;
+    BUFF *used_buff = r->output ? r->output : r->connection->client; 
 
     if (r->connection->aborted)
         return EOF;
     
-    rcode = ap_bputs(str, r->connection->client);
+    rcode = ap_bputs(str, used_buff);
     if (rcode < 0) {
         if (!r->connection->aborted) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO,
-                ap_berror(r->connection->client), r,
+                ap_berror(used_buff), r,
                 "client stopped connection before rputs completed");
-            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            ap_bsetflag(used_buff, B_EOUT, 1);
             r->connection->aborted = 1;
         }
         return EOF;
@@ -2326,16 +2359,17 @@ API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
 {
     ap_ssize_t n;
     ap_status_t rv;
+    BUFF *used_buff = r->output ? r->output : r->connection->client; 
 
     if (r->connection->aborted)
         return EOF;
 
-    rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
+    rv = ap_bwrite(used_buff, buf, nbyte, &n);
     if (n < 0) {
         if (!r->connection->aborted) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
                 "client stopped connection before rwrite completed");
-            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            ap_bsetflag(used_buff, B_EOUT, 1);
             r->connection->aborted = 1;
         }
         return EOF;
@@ -2347,18 +2381,19 @@ API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
 API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list ap)
 {
     int n;
+    BUFF *used_buff = r->output ? r->output : r->connection->client; 
 
     if (r->connection->aborted)
         return -1;
 
-    n = ap_vbprintf(r->connection->client, fmt, ap);
+    n = ap_vbprintf(used_buff, fmt, ap);
 
     if (n < 0) {
         if (!r->connection->aborted) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO,
-                ap_berror(r->connection->client), r,
+                ap_berror(used_buff), r,
                 "client stopped connection before vrprintf completed");
-            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            ap_bsetflag(used_buff, B_EOUT, 1);
             r->connection->aborted = 1;
         }
         return -1;
@@ -2371,20 +2406,21 @@ API_EXPORT(int) ap_rprintf(request_rec *r, const char *fmt,...)
 {
     va_list vlist;
     int n;
+    BUFF *used_buff = r->output ? r->output : r->connection->client; 
 
     if (r->connection->aborted)
         return -1;
 
     va_start(vlist, fmt);
-    n = ap_vbprintf(r->connection->client, fmt, vlist);
+    n = ap_vbprintf(used_buff, fmt, vlist);
     va_end(vlist);
 
     if (n < 0) {
         if (!r->connection->aborted) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO,
-                ap_berror(r->connection->client), r,
+                ap_berror(used_buff), r,
                 "client stopped connection before rprintf completed");
-            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            ap_bsetflag(used_buff, B_EOUT, 1);
             r->connection->aborted = 1;
         }
         return -1;
@@ -2399,7 +2435,7 @@ API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
     ap_ssize_t i;
     int j, k;
     const char *x;
-    BUFF *fb = r->connection->client;
+    BUFF *used_buff = r->output ? r->output : r->connection->client; 
     ap_status_t rv;
 
     if (r->connection->aborted)
@@ -2411,13 +2447,13 @@ API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
         if (x == NULL)
             break;
         j = strlen(x);
-        rv = ap_bwrite(fb, x, j, &i);
+        rv = ap_bwrite(used_buff, x, j, &i);
         if (i != j) {
             va_end(args);
             if (!r->connection->aborted) {
                 ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
                     "client stopped connection before rvputs completed");
-                ap_bsetflag(r->connection->client, B_EOUT, 1);
+                ap_bsetflag(used_buff, B_EOUT, 1);
                 r->connection->aborted = 1;
             }
             return EOF;
@@ -2433,12 +2469,13 @@ API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
 API_EXPORT(int) ap_rflush(request_rec *r)
 {
     ap_status_t rv;
+    BUFF *used_buff = r->output ? r->output : r->connection->client; 
 
-    if ((rv = ap_bflush(r->connection->client)) != APR_SUCCESS) {
+    if ((rv = ap_bflush(used_buff)) != APR_SUCCESS) {
         if (!ap_is_aborted(r->connection)) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
                 "client stopped connection before rflush completed");
-            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            ap_bsetflag(used_buff, B_EOUT, 1);
             r->connection->aborted = 1;
         }
         return EOF;
index ad25e54859331937ee4cc720fe4bb7ad35d869d4..d802504e1e4fec5b398a913a3577a8190beed6c2 100644 (file)
@@ -308,53 +308,60 @@ int ap_invoke_handler(request_rec *r)
     const char *handler;
     char *p;
     size_t handler_len;
-    int result = HTTP_INTERNAL_SERVER_ERROR;
+    int result;
 
-    if (r->handler) {
-       handler = r->handler;
-       handler_len = strlen(handler);
-    }
-    else {
-       handler = r->content_type ? r->content_type : ap_default_type(r);
-       if ((p = strchr(handler, ';')) != NULL) { /* MIME type arguments */
-           while (p > handler && p[-1] == ' ')
-               --p;            /* strip trailing spaces */
-           handler_len = p - handler;
-       }
-       else {
+    do {
+        result = DECLINED;
+        if (r->handler) {
+           handler = r->handler;
            handler_len = strlen(handler);
-       }
-    }
-
-    /* Pass one --- direct matches */
+        }
+        else {
+           handler = r->content_type ? r->content_type : ap_default_type(r);
+           if ((p = strchr(handler, ';')) != NULL) { /* MIME type arguments */
+               while (p > handler && p[-1] == ' ')
+                   --p;                /* strip trailing spaces */
+               handler_len = p - handler;
+           }
+           else {
+               handler_len = strlen(handler);
+           }
+        }
 
-    for (handp = handlers; handp->hr.content_type; ++handp) {
-       if (handler_len == handp->len
-           && !strncmp(handler, handp->hr.content_type, handler_len)) {
-            result = (*handp->hr.handler) (r);
+        /* Pass one --- direct matches */
+        for (handp = handlers; handp->hr.content_type; ++handp) {
+           if (handler_len == handp->len
+               && !strncmp(handler, handp->hr.content_type, handler_len)) {
+                result = (*handp->hr.handler) (r);
 
-            if (result != DECLINED)
-                return result;
+                if (result != DECLINED)
+                    break;
+            }
         }
-    }
 
-    /* Pass two --- wildcard matches */
+        /* Pass two --- wildcard matches */
 
-    for (handp = wildhandlers; handp->hr.content_type; ++handp) {
-       if (handler_len >= handp->len
-           && !strncmp(handler, handp->hr.content_type, handp->len)) {
-             result = (*handp->hr.handler) (r);
+        if (result == DECLINED) {
+            for (handp = wildhandlers; handp->hr.content_type; ++handp) {
+               if (handler_len >= handp->len
+                   && !strncmp(handler, handp->hr.content_type, handp->len)) {
+                    result = (*handp->hr.handler) (r);
 
-             if (result != DECLINED)
-                 return result;
-         }
-    }
+                    if (result != DECLINED)
+                        break;
+                 }
+            }
+        }
+    } while (result == RERUN_HANDLERS);
 
     if (result == HTTP_INTERNAL_SERVER_ERROR && r->handler && r->filename) {
         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r,
             "handler \"%s\" not found for: %s", r->handler, r->filename);
+        return HTTP_INTERNAL_SERVER_ERROR;
     }
-    return HTTP_INTERNAL_SERVER_ERROR;
+    return result;
 }
 
 int g_bDebugHooks;