httpd-apreq-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r380784 [4/4] - in /httpd/apreq/branches/apr-build-system: ./ build/ include/ library/ module/ module/apache2/
Date Fri, 24 Feb 2006 18:56:38 GMT
Added: httpd/apreq/branches/apr-build-system/module/apache2/apreq_module_apache2.h
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/module/apache2/apreq_module_apache2.h?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/module/apache2/apreq_module_apache2.h (added)
+++ httpd/apreq/branches/apr-build-system/module/apache2/apreq_module_apache2.h Fri Feb 24
10:56:34 2006
@@ -0,0 +1,168 @@
+/*
+**  Copyright 2003-2006  The Apache Software Foundation
+**
+**  Licensed under the Apache License, Version 2.0 (the "License");
+**  you may not use this file except in compliance with the License.
+**  You may obtain a copy of the License at
+**
+**      http://www.apache.org/licenses/LICENSE-2.0
+**
+**  Unless required by applicable law or agreed to in writing, software
+**  distributed under the License is distributed on an "AS IS" BASIS,
+**  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+**  See the License for the specific language governing permissions and
+**  limitations under the License.
+*/
+
+#ifndef APREQ_APACHE2_H
+#define APREQ_APACHE2_H
+
+#include "apreq_module.h"
+#include <httpd.h>
+
+#ifdef  __cplusplus
+ extern "C" {
+#endif
+
+
+/**
+ * @defgroup mod_apreq2 Apache 2.X Filter Module
+ * @ingroup apreq_module
+ * @brief mod_apreq2 - DSO that ties libapreq2 to Apache HTTPD 2.X.
+ *
+ * mod_apreq2 provides the "APREQ2" input filter for using libapreq2
+ * (and allow its parsed data structures to be shared) within
+ * the Apache 2.X webserver.  Using it, libapreq2 works properly
+ * in every phase of the HTTP request, from translation handlers
+ * to output filters, and even for subrequests / internal redirects.
+ *
+ * <hr>
+ *
+ * <h2>Activating mod_apreq2 in Apache 2.X</h2>
+ *
+ * The installation process triggered by
+ * <code>% make install</code>
+ * <em>will not modify your webserver's config file</em>. Hence,
+ * be sure you activate it on startup by adding a LoadModule directive
+ * to your webserver config; e.g.
+ *
+ * @code
+ *
+ *     LoadModule apreq_module    modules/mod_apreq2.so
+ *
+ * @endcode
+ *
+ * The mod_apreq2 filter is named "apreq2", and may be used in Apache's
+ * input filter directives, e.g.
+ * @code
+ *
+ *     AddInputFilter apreq2         # or
+ *     SetInputFilter apreq2
+ *
+ * @endcode
+ *
+ * However, this is not required because libapreq2 will add the filter (only)
+ * if it's necessary.  You just need to ensure that your module invokes
+ * apreq_handle_apache2() <em>before the content handler ultimately reads
+ * from the input filter chain</em>.  It is important to realize that no
+ * matter how the input filters are initially arranged, the APREQ2 filter
+ * will attempt to reposition itself to be the last input filter to read the
+ * data.
+ *
+ * If you want to use other input filters to transform the incoming HTTP
+ * request data, is important to register those filters with Apache
+ * as having type AP_FTYPE_CONTENT_SET or AP_FTYPE_RESOURCE.  Due to the
+ * limitations of Apache's current input filter design, types higher than
+ * AP_FTYPE_CONTENT_SET may not work properly whenever the apreq filter is
+ * active.
+ *
+ * This is especially true when a content handler uses libapreq2 to parse
+ * some of the post data before doing an internal redirect.  Any input
+ * filter subsequently added to the redirected request will bypass the
+ * original apreq filter (and therefore lose access to some of the original
+ * post data), unless its type is less than the type of the apreq filter
+ * (currently AP_FTYPE_PROTOCOL-1).
+ *
+ *
+ * <H2>Server Configuration Directives</H2>
+ *
+ * <TABLE class="qref">
+ *   <CAPTION>Per-directory commands for mod_apreq2</CAPTION>
+ *   <TR>
+ *     <TH>Directive</TH>
+ *     <TH>Context</TH>
+ *     <TH>Default</TH><TH>Description</TH>
+ *   </TR>
+ *   <TR class="odd">
+ *     <TD>APREQ2_ReadLimit</TD>
+ *     <TD>directory</TD>
+ *     <TD> #APREQ_DEFAULT_READ_LIMIT </TD>
+ *     <TD> Maximum number of bytes mod_apreq2 will send off to libapreq2
+ *          for parsing. mod_apreq2 will log this event and subsequently
+ *          remove itself from the filter chain.
+ *     </TD>
+ *   </TR>
+ *   <TR>
+ *     <TD>APREQ2_BrigadeLimit</TD>
+ *     <TD>directory</TD>
+ *     <TD>#APREQ_DEFAULT_BRIGADE_LIMIT</TD>
+ *     <TD> Maximum number of bytes mod_apreq2 will let accumulate
+ *          within the heap-buckets in a brigade.  Excess data will be
+ *          spooled to an appended file bucket.
+ *     </TD>
+ *   </TR>
+ *   <TR class="odd">
+ *     <TD>APREQ2_TempDir</TD>
+ *     <TD>directory</TD>
+ *     <TD>NULL</TD>
+ *     <TD> Sets the location of the temporary directory apreq will use to spool
+ *          overflow brigade data (based on the APREQ2_BrigadeLimit setting).
+ *          If left unset, libapreq2 will select a platform-specific location
+ *          via apr_temp_dir_get().
+ *     </TD>
+ *  </TR>
+ * </TABLE>
+ *
+ * <H2>Implementation Details</H2>
+ * <PRE>
+ *   XXX apreq as a normal input filter
+ *   XXX apreq as a "virtual" content handler.
+ *   XXX apreq as a transparent "tee".
+ *   XXX apreq parser registration in post_config
+ * </PRE>
+ *
+ * @{
+ */
+/**
+ * Create an apreq handle which communicates with an Apache 2.X
+ * request_rec.
+ */
+APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r);
+
+/**
+ * The mod_apreq2 filter is named "apreq2", and may be used in Apache's
+ * input filter directives, e.g.
+ * @code
+ *
+ *     AddInputFilter apreq2         # or
+ *     SetInputFilter apreq2
+ * @endcode
+ * See above
+ */
+#define APREQ_FILTER_NAME "apreq2"
+
+/**
+ * The Apache2 Module Magic Number for use in the Apache 2.x module structures
+ * This gets bumped if changes in th4e API will break third party applications
+ * using this apache2 module
+ * @see APREQ_MODULE
+ */
+#define APREQ_APACHE2_MMN 20051231
+
+/** @} */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif

Propchange: httpd/apreq/branches/apr-build-system/module/apache2/apreq_module_apache2.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/module/apache2/apreq_private_apache2.h
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/module/apache2/apreq_private_apache2.h?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/module/apache2/apreq_private_apache2.h (added)
+++ httpd/apreq/branches/apr-build-system/module/apache2/apreq_private_apache2.h Fri Feb 24
10:56:34 2006
@@ -0,0 +1,56 @@
+extern module AP_MODULE_DECLARE_DATA apreq_module;
+
+struct dir_config {
+    const char         *temp_dir;
+    apr_uint64_t        read_limit;
+    apr_size_t          brigade_limit;
+};
+
+/* The "warehouse", stored in r->request_config */
+struct apache2_handle {
+    apreq_handle_t      handle;
+    request_rec        *r;
+    apr_table_t        *jar, *args;
+    apr_status_t        jar_status, args_status;
+    ap_filter_t        *f;
+};
+
+/* Tracks the apreq filter state */
+struct filter_ctx {
+    apr_bucket_brigade *bb;    /* input brigade that's passed to the parser */
+    apr_bucket_brigade *bbtmp; /* temporary copy of bb, destined for the spool */
+    apr_bucket_brigade *spool; /* copied prefetch data for downstream filters */
+    apreq_parser_t     *parser;
+    apreq_hook_t       *hook_queue;
+    apreq_hook_t       *find_param;
+    apr_table_t        *body;
+    apr_status_t        body_status;
+    apr_status_t        filter_error;
+    apr_uint64_t        bytes_read;     /* Total bytes read into this filter. */
+    apr_uint64_t        read_limit;     /* Max bytes the filter may show to parser */
+    apr_size_t          brigade_limit;
+    const char         *temp_dir;
+};
+
+apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes);
+apr_status_t apreq_filter(ap_filter_t *f,
+                          apr_bucket_brigade *bb,
+                          ap_input_mode_t mode,
+                          apr_read_type_e block,
+                          apr_off_t readbytes);
+
+void apreq_filter_make_context(ap_filter_t *f);
+void apreq_filter_init_context(ap_filter_t *f);
+
+APR_INLINE
+static void apreq_filter_relocate(ap_filter_t *f)
+{
+    request_rec *r = f->r;
+
+    if (f != r->input_filters) {
+        ap_filter_t *top = r->input_filters;
+        ap_remove_input_filter(f);
+        r->input_filters = f;
+        f->next = top;
+    }
+}

Propchange: httpd/apreq/branches/apr-build-system/module/apache2/apreq_private_apache2.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/module/apache2/filter.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/module/apache2/filter.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/module/apache2/filter.c (added)
+++ httpd/apreq/branches/apr-build-system/module/apache2/filter.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,539 @@
+/*
+**  Copyright 2003-2006  The Apache Software Foundation
+**
+**  Licensed under the Apache License, Version 2.0 (the "License");
+**  you may not use this file except in compliance with the License.
+**  You may obtain a copy of the License at
+**
+**      http://www.apache.org/licenses/LICENSE-2.0
+**
+**  Unless required by applicable law or agreed to in writing, software
+**  distributed under the License is distributed on an "AS IS" BASIS,
+**  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+**  See the License for the specific language governing permissions and
+**  limitations under the License.
+*/
+
+#include "assert.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "util_filter.h"
+#include "apr_tables.h"
+#include "apr_buckets.h"
+#include "http_request.h"
+#include "apr_strings.h"
+
+#include "apreq_module_apache2.h"
+#include "apreq_private_apache2.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+#include "apreq_version.h"
+
+static void *apreq_create_dir_config(apr_pool_t *p, char *d)
+{
+    /* d == OR_ALL */
+    struct dir_config *dc = apr_palloc(p, sizeof *dc);
+    dc->temp_dir      = NULL;
+    dc->read_limit    = APREQ_DEFAULT_READ_LIMIT;
+    dc->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT;
+    return dc;
+}
+
+static void *apreq_merge_dir_config(apr_pool_t *p, void *a_, void *b_)
+{
+    struct dir_config *a = a_, *b = b_, *c = apr_palloc(p, sizeof *c);
+
+    c->temp_dir      = (b->temp_dir != NULL)            /* overrides ok */
+                      ? b->temp_dir : a->temp_dir;
+
+    c->brigade_limit = (b->brigade_limit == (apr_size_t)-1) /* overrides ok */
+                      ? a->brigade_limit : b->brigade_limit;
+
+    c->read_limit    = (b->read_limit < a->read_limit)  /* why min? */
+                      ? b->read_limit : a->read_limit;
+
+    return c;
+}
+
+static const char *apreq_set_temp_dir(cmd_parms *cmd, void *data,
+                                      const char *arg)
+{
+    struct dir_config *conf = data;
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+
+    if (err != NULL)
+        return err;
+
+    conf->temp_dir = arg;
+    return NULL;
+}
+
+static const char *apreq_set_read_limit(cmd_parms *cmd, void *data,
+                                        const char *arg)
+{
+    struct dir_config *conf = data;
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+
+    if (err != NULL)
+        return err;
+
+    conf->read_limit = apreq_atoi64f(arg);
+    return NULL;
+}
+
+static const char *apreq_set_brigade_limit(cmd_parms *cmd, void *data,
+                                           const char *arg)
+{
+    struct dir_config *conf = data;
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+
+    if (err != NULL)
+        return err;
+
+    conf->brigade_limit = apreq_atoi64f(arg);
+    return NULL;
+}
+
+
+static const command_rec apreq_cmds[] =
+{
+    AP_INIT_TAKE1("APREQ2_TempDir", apreq_set_temp_dir, NULL, OR_ALL,
+                  "Default location of temporary directory"),
+    AP_INIT_TAKE1("APREQ2_ReadLimit", apreq_set_read_limit, NULL, OR_ALL,
+                  "Maximum amount of data that will be fed into a parser."),
+    AP_INIT_TAKE1("APREQ2_BrigadeLimit", apreq_set_brigade_limit, NULL, OR_ALL,
+                  "Maximum in-memory bytes a brigade may use."),
+    { NULL }
+};
+
+
+void apreq_filter_init_context(ap_filter_t *f)
+{
+    request_rec *r = f->r;
+    struct filter_ctx *ctx = f->ctx;
+    apr_bucket_alloc_t *ba = r->connection->bucket_alloc;
+    const char *cl_header;
+
+    if (r->method_number == M_GET) {
+        /* Don't parse GET (this protects against subrequest body parsing). */
+        ctx->body_status = APREQ_ERROR_NODATA;
+        return;
+    }
+
+    cl_header = apr_table_get(r->headers_in, "Content-Length");
+
+    if (cl_header != NULL) {
+        char *dummy;
+        apr_uint64_t content_length = apr_strtoi64(cl_header,&dummy,0);
+
+        if (dummy == NULL || *dummy != 0) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
+                          "Invalid Content-Length header (%s)", cl_header);
+            ctx->body_status = APREQ_ERROR_BADHEADER;
+            return;
+        }
+        else if (content_length > ctx->read_limit) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
+                          "Content-Length header (%s) exceeds configured "
+                          "max_body limit (%" APR_UINT64_T_FMT ")",
+                          cl_header, ctx->read_limit);
+            ctx->body_status = APREQ_ERROR_OVERLIMIT;
+            return;
+        }
+    }
+
+    if (ctx->parser == NULL) {
+        const char *ct_header = apr_table_get(r->headers_in, "Content-Type");
+
+        if (ct_header != NULL) {
+            apreq_parser_function_t pf = apreq_parser(ct_header);
+
+            if (pf != NULL) {
+                ctx->parser = apreq_parser_make(r->pool, ba, ct_header, pf,
+                                                ctx->brigade_limit,
+                                                ctx->temp_dir,
+                                                ctx->hook_queue,
+                                                NULL);
+            }
+            else {
+                ctx->body_status = APREQ_ERROR_NOPARSER;
+                return;
+            }
+        }
+        else {
+            ctx->body_status = APREQ_ERROR_NOHEADER;
+            return;
+        }
+    }
+    else {
+        if (ctx->parser->brigade_limit > ctx->brigade_limit)
+            ctx->parser->brigade_limit = ctx->brigade_limit;
+        if (ctx->temp_dir != NULL)
+            ctx->parser->temp_dir = ctx->temp_dir;
+        if (ctx->hook_queue != NULL)
+            apreq_parser_add_hook(ctx->parser, ctx->hook_queue);
+    }
+
+    ctx->hook_queue = NULL;
+    ctx->bb    = apr_brigade_create(r->pool, ba);
+    ctx->bbtmp = apr_brigade_create(r->pool, ba);
+    ctx->spool = apr_brigade_create(r->pool, ba);
+    ctx->body  = apr_table_make(r->pool, APREQ_DEFAULT_NELTS);
+    ctx->body_status = APR_INCOMPLETE;
+}
+
+
+/*
+ * Situations to contend with:
+ *
+ * 1) Often the filter will be added by the content handler itself,
+ *    so the apreq_filter_init hook will not be run.
+ * 2) If an auth handler uses apreq, the apreq_filter will ensure
+ *    it's part of the protocol filters.  apreq_filter_init does NOT need
+ *    to notify the protocol filter that it must not continue parsing,
+ *    the apreq filter can perform this check itself.  apreq_filter_init
+ *    just needs to ensure cfg->f does not point at it.
+ * 3) If req->proto_input_filters and req->input_filters are apreq
+ *    filters, and req->input_filters->next == req->proto_input_filters,
+ *    it is safe for apreq_filter to "steal" the proto filter's context
+ *    and subsequently drop it from the chain.
+ */
+
+
+/* Examines the input_filter chain and moves the apreq filter(s) around
+ * before the filter chain is stacked by ap_get_brigade.
+ */
+
+
+static apr_status_t apreq_filter_init(ap_filter_t *f)
+{
+    request_rec *r = f->r;
+    struct filter_ctx *ctx = f->ctx;
+    struct apache2_handle *handle =
+        (struct apache2_handle *)apreq_handle_apache2(r);
+
+    /* Don't parse GET (this protects against subrequest body parsing). */
+    if (f->r->method_number == M_GET)
+        return APR_SUCCESS;
+
+    if (ctx == NULL || ctx->body_status == APR_EINIT) {
+        if (f == r->input_filters) {
+            handle->f = f;
+        }
+        else if (r->input_filters->frec->filter_func.in_func == apreq_filter) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                          "removing intermediate apreq filter");
+            if (handle->f == f)
+                handle->f = r->input_filters;
+            ap_remove_input_filter(f);
+        }
+        else {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                          "relocating intermediate apreq filter");
+            apreq_filter_relocate(f);
+            handle->f = f;
+        }
+        return APR_SUCCESS;
+    }
+
+    /* else this is a protocol filter which may still be active.
+     * if it is, we must deregister it now.
+     */
+    if (handle->f == f) {
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                     "disabling stale protocol filter");
+        if (ctx->body_status == APR_INCOMPLETE)
+            ctx->body_status = APREQ_ERROR_INTERRUPT;
+        handle->f = NULL;
+    }
+    return APR_SUCCESS;
+}
+
+
+
+apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes)
+{
+    struct filter_ctx *ctx = f->ctx;
+    request_rec *r = f->r;
+    apr_status_t rv;
+    apr_off_t len;
+
+    if (ctx->body_status == APR_EINIT)
+        apreq_filter_init_context(f);
+
+    if (ctx->body_status != APR_INCOMPLETE || readbytes == 0)
+        return ctx->body_status;
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                  "prefetching %" APR_OFF_T_FMT " bytes", readbytes);
+
+    rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES,
+                       APR_BLOCK_READ, readbytes);
+
+    if (rv != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                      "ap_get_brigade failed during prefetch");
+        ctx->filter_error = rv;
+        return ctx->body_status = APREQ_ERROR_GENERAL;
+    }
+
+    apreq_brigade_setaside(ctx->bb, r->pool);
+    apreq_brigade_copy(ctx->bbtmp, ctx->bb);
+
+    rv = apreq_brigade_concat(r->pool, ctx->temp_dir, ctx->brigade_limit,
+                              ctx->spool, ctx->bbtmp);
+    if (rv != APR_SUCCESS && rv != APR_EOF) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                      "apreq_brigade_concat failed; TempDir problem?");
+        ctx->filter_error = APR_EGENERAL;
+        return ctx->body_status = rv;
+    }
+
+    /* Adding "f" to the protocol filter chain ensures the
+     * spooled data is preserved across internal redirects.
+     */
+
+    if (f != r->proto_input_filters) {
+        ap_filter_t *in;
+        for (in = r->input_filters; in != r->proto_input_filters;
+             in = in->next)
+        {
+            if (f == in) {
+                r->proto_input_filters = f;
+                break;
+            }
+        }
+    }
+
+    apr_brigade_length(ctx->bb, 1, &len);
+    ctx->bytes_read += len;
+
+    if (ctx->bytes_read > ctx->read_limit) {
+        ctx->body_status = APREQ_ERROR_OVERLIMIT;
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r,
+                      "Bytes read (%" APR_UINT64_T_FMT
+                      ") exceeds configured read limit (%" APR_UINT64_T_FMT ")",
+                      ctx->bytes_read, ctx->read_limit);
+        return ctx->body_status;
+    }
+
+    ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
+    apr_brigade_cleanup(ctx->bb);
+
+    return ctx->body_status;
+}
+
+
+
+apr_status_t apreq_filter(ap_filter_t *f,
+                          apr_bucket_brigade *bb,
+                          ap_input_mode_t mode,
+                          apr_read_type_e block,
+                          apr_off_t readbytes)
+{
+    request_rec *r = f->r;
+    struct filter_ctx *ctx;
+    apr_status_t rv;
+    apr_off_t len;
+
+    switch (mode) {
+    case AP_MODE_READBYTES:
+        /* only the modes above are supported */
+        break;
+
+    case AP_MODE_EXHAUSTIVE: /* not worth supporting at this level */
+    case AP_MODE_GETLINE: /* chunked trailers are b0rked in ap_http_filter */
+        return ap_get_brigade(f->next, bb, mode, block, readbytes);
+
+    default:
+        return APR_ENOTIMPL;
+    }
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    if (ctx->body_status == APR_EINIT)
+        apreq_filter_init_context(f);
+
+    if (ctx->spool && !APR_BRIGADE_EMPTY(ctx->spool)) {
+        apr_bucket *e;
+        rv = apr_brigade_partition(ctx->spool, readbytes, &e);
+        if (rv != APR_SUCCESS && rv != APR_INCOMPLETE)
+            return rv;
+
+        if (APR_BUCKET_IS_EOS(e))
+            e = APR_BUCKET_NEXT(e);
+
+        apreq_brigade_move(bb, ctx->spool, e);
+        return APR_SUCCESS;
+    }
+    else if (ctx->body_status != APR_INCOMPLETE) {
+        if (ctx->filter_error)
+            return ctx->filter_error;
+
+        rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
+        ap_remove_input_filter(f);
+        return rv;
+    }
+
+
+    rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
+    if (rv != APR_SUCCESS)
+        return rv;
+
+    apreq_brigade_copy(ctx->bb, bb);
+    apr_brigade_length(bb, 1, &len);
+    ctx->bytes_read += len;
+
+    if (ctx->bytes_read > ctx->read_limit) {
+        ctx->body_status = APREQ_ERROR_OVERLIMIT;
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r,
+                      "Bytes read (%" APR_UINT64_T_FMT
+                      ") exceeds configured max_body limit (%"
+                      APR_UINT64_T_FMT ")",
+                      ctx->bytes_read, ctx->read_limit);
+    }
+    else {
+        ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
+        apr_brigade_cleanup(ctx->bb);
+    }
+    return APR_SUCCESS;
+}
+
+
+static int apreq_pre_init(apr_pool_t *p, apr_pool_t *plog,
+                          apr_pool_t *ptemp, server_rec *base_server)
+{
+    apr_status_t status;
+
+    status = apreq_pre_initialize(p);
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, base_server,
+                     "Failed to pre-initialize libapreq2");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    return OK;
+}
+
+static int apreq_post_init(apr_pool_t *p, apr_pool_t *plog,
+                           apr_pool_t *ptemp, server_rec *base_server)
+{
+    apr_status_t status;
+
+    ap_add_version_component(p, apr_psprintf(p,
+                                             "mod_apreq2-%d/%s",
+                                             APREQ_APACHE2_MMN,
+                                             apreq_version_string()));
+
+    status = apreq_post_initialize(p);
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, base_server,
+                     "Failed to post-initialize libapreq2");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    return OK;
+}
+
+static void register_hooks (apr_pool_t *p)
+{
+    /* APR_HOOK_FIRST because we want other modules to be able to
+     * register parsers in their post_config hook via APR_HOOK_MIDDLE.
+     */
+    ap_hook_post_config(apreq_pre_init, NULL, NULL, APR_HOOK_FIRST);
+
+    /* APR_HOOK_LAST because we need to lock the default_parsers hash
+     * (to prevent further modifications) before the server forks.
+     */
+    ap_hook_post_config(apreq_post_init, NULL, NULL, APR_HOOK_LAST);
+
+    ap_register_input_filter(APREQ_FILTER_NAME, apreq_filter, apreq_filter_init,
+                             AP_FTYPE_PROTOCOL-1);
+}
+
+
+
+/** @} */
+
+
+module AP_MODULE_DECLARE_DATA apreq_module = {
+#line __LINE__ "mod_apreq2.c"
+	STANDARD20_MODULE_STUFF,
+	apreq_create_dir_config,
+	apreq_merge_dir_config,
+	NULL,
+	NULL,
+	apreq_cmds,
+	register_hooks,
+};
+
+
+void apreq_filter_make_context(ap_filter_t *f)
+{
+    request_rec *r;
+    struct filter_ctx *ctx;
+    struct dir_config *d;
+
+    r = f->r;
+    d = ap_get_module_config(r->per_dir_config, &apreq_module);
+
+    if (f == r->input_filters
+        && r->proto_input_filters == f->next
+        && f->next->frec->filter_func.in_func == apreq_filter
+        && f->r->method_number != M_GET)
+    {
+
+        ctx = f->next->ctx;
+
+        switch (ctx->body_status) {
+
+        case APREQ_ERROR_INTERRUPT:
+            ctx->body_status = APR_INCOMPLETE;
+            /* fall thru */
+
+        case APR_SUCCESS:
+
+            if (d != NULL) {
+                ctx->temp_dir      = d->temp_dir;
+                ctx->read_limit    = d->read_limit;
+                ctx->brigade_limit = d->brigade_limit;
+
+                if (ctx->parser != NULL) {
+                    ctx->parser->temp_dir = d->temp_dir;
+                    ctx->parser->brigade_limit = d->brigade_limit;
+                }
+
+            }
+
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                          "stealing filter context");
+            f->ctx = ctx;
+            r->proto_input_filters = f;
+            ap_remove_input_filter(f->next);
+
+            return;
+
+        default:
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, ctx->body_status, r,
+                          "cannot steal context: bad filter status");
+        }
+    }
+
+    ctx = apr_pcalloc(r->pool, sizeof *ctx);
+    ctx->body_status = APR_EINIT;
+
+    if (d == NULL) {
+        ctx->read_limit    = (apr_uint64_t)-1;
+        ctx->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT;
+    } else {
+        ctx->temp_dir      = d->temp_dir;
+        ctx->read_limit    = d->read_limit;
+        ctx->brigade_limit = d->brigade_limit;
+    }
+
+    f->ctx = ctx;
+}
+

Propchange: httpd/apreq/branches/apr-build-system/module/apache2/filter.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/module/apache2/handle.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/module/apache2/handle.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/module/apache2/handle.c (added)
+++ httpd/apreq/branches/apr-build-system/module/apache2/handle.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,438 @@
+/*
+**  Copyright 2003-2006  The Apache Software Foundation
+**
+**  Licensed under the Apache License, Version 2.0 (the "License");
+**  you may not use this file except in compliance with the License.
+**  You may obtain a copy of the License at
+**
+**      http://www.apache.org/licenses/LICENSE-2.0
+**
+**  Unless required by applicable law or agreed to in writing, software
+**  distributed under the License is distributed on an "AS IS" BASIS,
+**  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+**  See the License for the specific language governing permissions and
+**  limitations under the License.
+*/
+
+#include "assert.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "util_filter.h"
+#include "apr_tables.h"
+#include "apr_buckets.h"
+#include "http_request.h"
+#include "apr_strings.h"
+
+#include "apreq_module_apache2.h"
+#include "apreq_private_apache2.h"
+#include "apreq_error.h"
+
+
+APR_INLINE
+static ap_filter_t *get_apreq_filter(apreq_handle_t *handle)
+{
+    struct apache2_handle *req = (struct apache2_handle *)handle;
+
+    if (req->f == NULL) {
+        req->f = ap_add_input_filter(APREQ_FILTER_NAME, NULL,
+                                     req->r,
+                                     req->r->connection);
+        /* ap_add_input_filter does not guarantee cfg->f == r->input_filters,
+         * so we reposition the new filter there as necessary.
+         */
+        apreq_filter_relocate(req->f);
+    }
+
+    return req->f;
+}
+
+
+static apr_status_t apache2_jar(apreq_handle_t *handle, const apr_table_t **t)
+{
+    struct apache2_handle *req = (struct apache2_handle*)handle;
+    request_rec *r = req->r;
+
+    if (req->jar_status == APR_EINIT) {
+        const char *cookies = apr_table_get(r->headers_in, "Cookie");
+        if (cookies != NULL) {
+            req->jar = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS);
+            req->jar_status =
+                apreq_parse_cookie_header(handle->pool, req->jar, cookies);
+        }
+        else
+            req->jar_status = APREQ_ERROR_NODATA;
+    }
+
+    *t = req->jar;
+    return req->jar_status;
+}
+
+static apr_status_t apache2_args(apreq_handle_t *handle, const apr_table_t **t)
+{
+    struct apache2_handle *req = (struct apache2_handle*)handle;
+    request_rec *r = req->r;
+
+    if (req->args_status == APR_EINIT) {
+        if (r->args != NULL) {
+            req->args = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS);
+            req->args_status =
+                apreq_parse_query_string(handle->pool, req->args, r->args);
+        }
+        else
+            req->args_status = APREQ_ERROR_NODATA;
+    }
+
+    *t = req->args;
+    return req->args_status;
+}
+
+
+
+
+static apreq_cookie_t *apache2_jar_get(apreq_handle_t *handle, const char *name)
+{
+    struct apache2_handle *req = (struct apache2_handle *)handle;
+    const apr_table_t *t;
+    const char *val;
+
+    if (req->jar_status == APR_EINIT)
+        apache2_jar(handle, &t);
+    else
+        t = req->jar;
+
+    if (t == NULL)
+        return NULL;
+
+    val = apr_table_get(t, name);
+    if (val == NULL)
+        return NULL;
+
+    return apreq_value_to_cookie(val);
+}
+
+static apreq_param_t *apache2_args_get(apreq_handle_t *handle, const char *name)
+{
+    struct apache2_handle *req = (struct apache2_handle *)handle;
+    const apr_table_t *t;
+    const char *val;
+
+    if (req->args_status == APR_EINIT)
+        apache2_args(handle, &t);
+    else
+        t = req->args;
+
+    if (t == NULL)
+        return NULL;
+
+    val = apr_table_get(t, name);
+    if (val == NULL)
+        return NULL;
+
+    return apreq_value_to_param(val);
+}
+
+
+static apr_status_t apache2_body(apreq_handle_t *handle, const apr_table_t **t)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    switch (ctx->body_status) {
+
+    case APR_EINIT:
+        apreq_filter_init_context(f);
+        if (ctx->body_status != APR_INCOMPLETE)
+            break;
+
+    case APR_INCOMPLETE:
+        while (apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE) == APR_INCOMPLETE)
+            ;   /*loop*/
+    }
+
+    *t = ctx->body;
+    return ctx->body_status;
+}
+
+static apreq_param_t *apache2_body_get(apreq_handle_t *handle, const char *name)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+    const char *val;
+    apreq_hook_t *h;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    switch (ctx->body_status) {
+
+    case APR_SUCCESS:
+
+        val = apr_table_get(ctx->body, name);
+        if (val != NULL)
+            return apreq_value_to_param(val);
+        return NULL;
+
+
+    case APR_EINIT:
+
+        apreq_filter_init_context(f);
+        if (ctx->body_status != APR_INCOMPLETE)
+            return NULL;
+        apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
+
+
+    case APR_INCOMPLETE:
+
+        val = apr_table_get(ctx->body, name);
+        if (val != NULL)
+            return apreq_value_to_param(val);
+
+        /* Not seen yet, so we need to scan for
+           param while prefetching the body */
+
+        if (ctx->find_param == NULL)
+            ctx->find_param = apreq_hook_make(handle->pool,
+                                              apreq_hook_find_param,
+                                              NULL, NULL);
+        h = ctx->find_param;
+        h->next = ctx->parser->hook;
+        ctx->parser->hook = h;
+        *(const char **)&h->ctx = name;
+
+        do {
+            apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
+            if (h->ctx != name) {
+                ctx->parser->hook = h->next;
+                return h->ctx;
+            }
+        } while (ctx->body_status == APR_INCOMPLETE);
+
+        ctx->parser->hook = h->next;
+        return NULL;
+
+
+    default:
+
+        if (ctx->body == NULL)
+            return NULL;
+
+        val = apr_table_get(ctx->body, name);
+        if (val != NULL)
+            return apreq_value_to_param(val);
+        return NULL;
+
+    }
+
+    /* not reached */
+    return NULL;
+}
+
+static
+apr_status_t apache2_parser_get(apreq_handle_t *handle,
+                                  const apreq_parser_t **parser)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx = f->ctx;
+
+    if (ctx == NULL) {
+        *parser = NULL;
+        return APR_EINIT;
+    }
+    *parser = ctx->parser;
+    return APR_SUCCESS;
+}
+
+static
+apr_status_t apache2_parser_set(apreq_handle_t *handle,
+                                apreq_parser_t *parser)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    if (ctx->parser == NULL) {
+        ctx->parser = parser;
+        return APR_SUCCESS;
+    }
+    else
+        return APREQ_ERROR_NOTEMPTY;
+}
+
+
+
+static
+apr_status_t apache2_hook_add(apreq_handle_t *handle,
+                              apreq_hook_t *hook)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    if (ctx->parser != NULL) {
+        return apreq_parser_add_hook(ctx->parser, hook);
+    }
+    else if (ctx->hook_queue != NULL) {
+        apreq_hook_t *h = ctx->hook_queue;
+        while (h->next != NULL)
+            h = h->next;
+        h->next = hook;
+    }
+    else {
+        ctx->hook_queue = hook;
+    }
+    return APR_SUCCESS;
+
+}
+
+static
+apr_status_t apache2_brigade_limit_set(apreq_handle_t *handle,
+                                       apr_size_t bytes)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    if (ctx->body_status == APR_EINIT || ctx->brigade_limit > bytes) {
+        ctx->brigade_limit = bytes;
+        return APR_SUCCESS;
+    }
+
+    return APREQ_ERROR_MISMATCH;
+}
+
+static
+apr_status_t apache2_brigade_limit_get(apreq_handle_t *handle,
+                                       apr_size_t *bytes)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+    *bytes = ctx->brigade_limit;
+    return APR_SUCCESS;
+}
+
+static
+apr_status_t apache2_read_limit_set(apreq_handle_t *handle,
+                                    apr_uint64_t bytes)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+
+    if (ctx->read_limit > bytes && ctx->bytes_read < bytes) {
+        ctx->read_limit = bytes;
+        return APR_SUCCESS;
+    }
+
+    return APREQ_ERROR_MISMATCH;
+}
+
+static
+apr_status_t apache2_read_limit_get(apreq_handle_t *handle,
+                                    apr_uint64_t *bytes)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+    *bytes = ctx->read_limit;
+    return APR_SUCCESS;
+}
+
+static
+apr_status_t apache2_temp_dir_set(apreq_handle_t *handle,
+                                  const char *path)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+    // init vs incomplete state?
+    if (ctx->temp_dir == NULL && ctx->bytes_read == 0) {
+        if (path != NULL)
+            ctx->temp_dir = apr_pstrdup(handle->pool, path);
+        return APR_SUCCESS;
+    }
+
+    return APREQ_ERROR_NOTEMPTY;
+}
+
+static
+apr_status_t apache2_temp_dir_get(apreq_handle_t *handle,
+                                  const char **path)
+{
+    ap_filter_t *f = get_apreq_filter(handle);
+    struct filter_ctx *ctx;
+
+    if (f->ctx == NULL)
+        apreq_filter_make_context(f);
+
+    ctx = f->ctx;
+    *path = ctx->parser ? ctx->parser->temp_dir : ctx->temp_dir;
+    return APR_SUCCESS;
+}
+
+static APREQ_MODULE(apache2, APREQ_APACHE2_MMN);
+
+APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r)
+{
+    struct apache2_handle *req =
+        ap_get_module_config(r->request_config, &apreq_module);
+
+    if (req != NULL) {
+        get_apreq_filter(&req->handle);
+        return &req->handle;
+    }
+
+    req = apr_palloc(r->pool, sizeof *req);
+    ap_set_module_config(r->request_config, &apreq_module, req);
+
+    req->handle.module = &apache2_module;
+    req->handle.pool = r->pool;
+    req->handle.bucket_alloc = r->connection->bucket_alloc;
+    req->r = r;
+
+    req->args_status = req->jar_status = APR_EINIT;
+    req->args = req->jar = NULL;
+
+    req->f = NULL;
+
+    get_apreq_filter(&req->handle);
+    return &req->handle;
+
+}

Propchange: httpd/apreq/branches/apr-build-system/module/apache2/handle.c
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message