You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apreq-cvs@httpd.apache.org by jo...@apache.org on 2006/02/24 19:56:38 UTC

svn commit: r380784 [3/4] - in /httpd/apreq/branches/apr-build-system: ./ build/ include/ library/ module/ module/apache2/

Added: httpd/apreq/branches/apr-build-system/library/parser.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/parser.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/library/parser.c (added)
+++ httpd/apreq/branches/apr-build-system/library/parser.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,352 @@
+/*
+**  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 "apreq_error.h"
+#include "apreq_parser.h"
+#include "apreq_util.h"
+#include "apr_strings.h"
+#include "apr_xml.h"
+#include "apr_hash.h"
+
+#define PARSER_STATUS_CHECK(PREFIX)   do {         \
+    if (ctx->status == PREFIX##_ERROR)             \
+        return APREQ_ERROR_GENERAL;                \
+    else if (ctx->status == PREFIX##_COMPLETE)     \
+        return APR_SUCCESS;                        \
+    else if (bb == NULL)                           \
+        return APR_INCOMPLETE;                     \
+} while (0);
+
+APREQ_DECLARE(apreq_parser_t *) apreq_parser_make(apr_pool_t *pool,
+                                                  apr_bucket_alloc_t *ba,
+                                                  const char *content_type,
+                                                  apreq_parser_function_t pfn,
+                                                  apr_size_t brigade_limit,
+                                                  const char *temp_dir,
+                                                  apreq_hook_t *hook,
+                                                  void *ctx)
+{
+    apreq_parser_t *p = apr_palloc(pool, sizeof *p);
+    p->content_type = content_type;
+    p->parser = pfn;
+    p->hook = hook;
+    p->pool = pool;
+    p->bucket_alloc = ba;
+    p->brigade_limit = brigade_limit;
+    p->temp_dir = temp_dir;
+    p->ctx = ctx;
+    return p;
+}
+
+APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool,
+                                              apreq_hook_function_t hook,
+                                              apreq_hook_t *next,
+                                              void *ctx)
+{
+    apreq_hook_t *h = apr_palloc(pool, sizeof *h);
+    h->hook = hook;
+    h->next = next;
+    h->pool = pool;
+    h->ctx = ctx;
+    return h;
+}
+
+
+/*XXX this may need to check the parser's state before modifying the hook list */
+APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p,
+                                                  apreq_hook_t *h)
+{
+    apreq_hook_t *last = h;
+
+    while (last->next)
+        last = last->next;
+
+    last->next = p->hook;
+    p->hook = h;
+
+    return APR_SUCCESS;
+}
+
+static int default_parsers_lock = 0;
+static apr_hash_t *default_parsers = NULL;
+static apr_pool_t *default_parser_pool = NULL;
+
+static apr_status_t apreq_parsers_cleanup(void *data)
+{
+    default_parsers_lock = 0;
+    default_parsers = NULL;
+    default_parser_pool = NULL;
+
+    return APR_SUCCESS;
+}
+
+APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool)
+{
+    apr_status_t status;
+
+    if (default_parser_pool != NULL)
+        return APR_SUCCESS;
+
+    if (default_parsers_lock)
+        return APREQ_ERROR_GENERAL;
+
+    status = apr_pool_create(&default_parser_pool, pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    apr_pool_cleanup_register(default_parser_pool, NULL,
+                              apreq_parsers_cleanup,
+                              apr_pool_cleanup_null);
+
+    default_parsers = apr_hash_make(default_parser_pool);
+
+    apreq_register_parser("application/x-www-form-urlencoded",
+                          apreq_parse_urlencoded);
+    apreq_register_parser("multipart/form-data", apreq_parse_multipart);
+    apreq_register_parser("multipart/related", apreq_parse_multipart);
+
+    return APR_SUCCESS;
+}
+
+APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool)
+{
+    (void)pool;
+
+    if (default_parser_pool == NULL)
+        return APREQ_ERROR_GENERAL;
+
+    default_parsers_lock = 1;
+    return APR_SUCCESS;
+}
+
+APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool)
+{
+    apr_status_t s = apreq_pre_initialize(pool);
+
+    if (s != APR_SUCCESS)
+        return s;
+
+    return apreq_post_initialize(pool);
+}
+
+
+APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
+                                                  apreq_parser_function_t pfn)
+{
+    apreq_parser_function_t *f = NULL;
+
+    if (default_parsers == NULL)
+        return APR_EINIT;
+
+    if (enctype == NULL)
+        return APR_EINVAL;
+
+    if (default_parsers_lock)
+        return APREQ_ERROR_GENERAL;
+
+    if (pfn != NULL) {
+        f = apr_palloc(default_parser_pool, sizeof *f);
+        *f = pfn;
+    }
+    apr_hash_set(default_parsers, apr_pstrdup(default_parser_pool, enctype),
+                 APR_HASH_KEY_STRING, f);
+
+    return APR_SUCCESS;
+}
+
+APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype)
+{
+    apreq_parser_function_t *f;
+    apr_size_t tlen = 0;
+
+    if (enctype == NULL || default_parsers_lock == 0)
+        return NULL;
+
+    while(enctype[tlen] && enctype[tlen] != ';')
+        ++tlen;
+
+    f = apr_hash_get(default_parsers, enctype, tlen);
+
+    if (f != NULL)
+        return *f;
+    else
+        return NULL;
+}
+
+APREQ_DECLARE_HOOK(apreq_hook_disable_uploads)
+{
+    return (bb == NULL) ? APR_SUCCESS : APREQ_ERROR_GENERAL;
+}
+
+APREQ_DECLARE_HOOK(apreq_hook_discard_brigade)
+{
+    apr_status_t s = APR_SUCCESS;
+    if (hook->next)
+        s = apreq_hook_run(hook->next, param, bb);
+    if (bb != NULL)
+        apr_brigade_cleanup(bb);
+    return s;
+}
+
+
+/* generic parser */
+
+struct gen_ctx {
+    apreq_param_t               *param;
+    enum {
+        GEN_INCOMPLETE,
+        GEN_COMPLETE,
+        GEN_ERROR
+    }                            status;
+};
+
+APREQ_DECLARE_PARSER(apreq_parse_generic)
+{
+    struct gen_ctx *ctx = parser->ctx;
+    apr_pool_t *pool = parser->pool;
+    apr_status_t s = APR_SUCCESS;
+    apr_bucket *e = APR_BRIGADE_LAST(bb);
+    unsigned saw_eos = 0;
+
+    if (ctx == NULL) {
+        parser->ctx = ctx = apr_palloc(pool, sizeof *ctx);
+        ctx->status = GEN_INCOMPLETE;
+        ctx->param = apreq_param_make(pool,
+                                      "_dummy_", strlen("_dummy_"), "", 0);
+        ctx->param->upload = apr_brigade_create(pool, parser->bucket_alloc);
+        ctx->param->info = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+    }
+
+
+    PARSER_STATUS_CHECK(GEN);
+
+    while (e != APR_BRIGADE_SENTINEL(bb)) {
+        if (APR_BUCKET_IS_EOS(e)) {
+            saw_eos = 1;
+            break;
+        }
+        e = APR_BUCKET_PREV(e);
+    }
+
+    if (parser->hook != NULL) {
+        s = apreq_hook_run(parser->hook, ctx->param, bb);
+        if (s != APR_SUCCESS) {
+            ctx->status = GEN_ERROR;
+            return s;
+        }
+    }
+
+    apreq_brigade_setaside(bb, pool);
+    s = apreq_brigade_concat(pool, parser->temp_dir, parser->brigade_limit,
+                             ctx->param->upload, bb);
+
+    if (s != APR_SUCCESS) {
+        ctx->status = GEN_ERROR;
+        return s;
+    }
+
+    if (saw_eos) {
+        ctx->status = GEN_COMPLETE;
+        return APR_SUCCESS;
+    }
+    else
+        return APR_INCOMPLETE;
+}
+
+
+struct xml_ctx {
+    apr_xml_doc                 *doc;
+    apr_xml_parser              *xml_parser;
+    enum {
+        XML_INCOMPLETE,
+        XML_COMPLETE,
+        XML_ERROR
+    }                            status;
+};
+
+
+APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser)
+{
+    apr_pool_t *pool = hook->pool;
+    struct xml_ctx *ctx = hook->ctx;
+    apr_status_t s = APR_SUCCESS;
+    apr_bucket *e;
+
+    if (ctx == NULL) {
+        hook->ctx = ctx = apr_palloc(pool, sizeof *ctx);
+        ctx->doc = NULL;
+        ctx->xml_parser = apr_xml_parser_create(pool);
+        ctx->status = XML_INCOMPLETE;
+    }
+
+    PARSER_STATUS_CHECK(XML);
+
+    for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
+         e = APR_BUCKET_NEXT(e))
+    {
+        const char *data;
+        apr_size_t dlen;
+
+        if (APR_BUCKET_IS_EOS(e)) {
+            s = apr_xml_parser_done(ctx->xml_parser, &ctx->doc);
+            if (s == APR_SUCCESS) {
+                ctx->status = XML_COMPLETE;
+                if (hook->next)
+                    s = apreq_hook_run(hook->next, param, bb);
+            }
+            else {
+                ctx->status = XML_ERROR;
+            }
+           return s;
+        }
+        else if (APR_BUCKET_IS_METADATA(e)) {
+            continue;
+        }
+
+        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+
+        if (s != APR_SUCCESS) {
+            ctx->status = XML_ERROR;
+            return s;
+        }
+
+        s = apr_xml_parser_feed(ctx->xml_parser, data, dlen);
+
+        if (s != APR_SUCCESS) {
+            ctx->status = XML_ERROR;
+            return s;
+        }
+
+    }
+
+    if (hook->next)
+        return apreq_hook_run(hook->next, param, bb);
+
+    return APR_SUCCESS;
+}
+
+APREQ_DECLARE_HOOK(apreq_hook_find_param)
+{
+    const char *key = hook->ctx;
+    int is_final = (bb == NULL) || APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb));
+    apr_status_t s = (hook->next == NULL)
+        ? APR_SUCCESS : apreq_hook_run(hook->next, param, bb);
+
+    if (is_final && strcasecmp(key, param->v.name) == 0)
+        hook->ctx = param;
+
+    return s;
+}

Propchange: httpd/apreq/branches/apr-build-system/library/parser.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/library/parser_header.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/parser_header.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/library/parser_header.c (added)
+++ httpd/apreq/branches/apr-build-system/library/parser_header.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,364 @@
+/*
+**  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 "apreq_parser.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+
+#define PARSER_STATUS_CHECK(PREFIX)   do {         \
+    if (ctx->status == PREFIX##_ERROR)             \
+        return APREQ_ERROR_GENERAL;                \
+    else if (ctx->status == PREFIX##_COMPLETE)     \
+        return APR_SUCCESS;                        \
+    else if (bb == NULL)                           \
+        return APR_INCOMPLETE;                     \
+} while (0);
+
+
+struct hdr_ctx {
+    apr_bucket_brigade *bb;
+    apr_size_t          nlen;
+    apr_size_t          glen;
+    apr_size_t          vlen;
+    enum {
+        HDR_NAME,
+        HDR_GAP,
+        HDR_VALUE,
+        HDR_NEWLINE,
+        HDR_CONTINUE,
+        HDR_COMPLETE,
+        HDR_ERROR
+    }                   status;
+};
+
+/********************* header parsing utils ********************/
+
+
+static apr_status_t split_header_line(apreq_param_t **p,
+                                      apr_pool_t *pool,
+                                      apr_bucket_brigade *bb,
+                                      apr_size_t nlen,
+                                      apr_size_t glen,
+                                      apr_size_t vlen)
+{
+    apreq_param_t *param;
+    apreq_value_t *v;
+    apr_bucket *e, *f;
+    apr_status_t s;
+    struct iovec vec[APREQ_DEFAULT_NELTS], *iov, *end;
+    apr_array_header_t arr;
+    char *dest;
+    const char *data;
+    apr_size_t dlen;
+
+    if (nlen == 0)
+        return APR_EBADARG;
+
+    param = apreq_param_make(pool, NULL, nlen, NULL, vlen - 1); /*drop (CR)LF */
+    *(const apreq_value_t **)&v = &param->v;
+
+    arr.pool     = pool;
+    arr.elt_size = sizeof(struct iovec);
+    arr.nelts    = 0;
+    arr.nalloc   = APREQ_DEFAULT_NELTS;
+    arr.elts     = (char *)vec;
+
+    e = APR_BRIGADE_FIRST(bb);
+
+    /* store name in a temporary iovec array */
+
+    while (nlen > 0) {
+        apr_size_t len;
+        end = apr_array_push(&arr);
+        s = apr_bucket_read(e, (const char **)&end->iov_base,
+                            &len, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        assert(nlen >= len);
+        end->iov_len = len;
+        nlen -= len;
+
+        e = APR_BUCKET_NEXT(e);
+    }
+
+    /* skip gap */
+
+    while (glen > 0) {
+        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        assert(glen >= dlen);
+        glen -= dlen;
+        e = APR_BUCKET_NEXT(e);
+    }
+
+    /* copy value */
+    assert(vlen > 0);
+    dest = v->data;
+    while (vlen > 0) {
+
+        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        memcpy(dest, data, dlen);
+        dest += dlen;
+        assert(vlen >= dlen);
+        vlen -= dlen;
+        e = APR_BUCKET_NEXT(e);
+    }
+
+    assert(dest[-1] == '\n');
+
+    if (dest[-2] == '\r')
+        --dest;
+
+    dest[-1] = 0;
+    v->dlen = (dest - v->data) - 1;
+
+    /* write name */
+    v->name = dest;
+    iov = (struct iovec *)arr.elts;
+
+    while (iov <= end) {
+        memcpy(dest, iov->iov_base, iov->iov_len);
+        dest += iov->iov_len;
+        ++iov;
+    }
+    *dest = 0;
+    nlen = dest - v->name;
+
+    while ((f = APR_BRIGADE_FIRST(bb)) != e)
+        apr_bucket_delete(f);
+
+    apreq_param_tainted_on(param);
+    *p = param;
+    return APR_SUCCESS;
+
+}
+
+
+APREQ_DECLARE_PARSER(apreq_parse_headers)
+{
+    apr_pool_t *pool = parser->pool;
+    apr_bucket *e;
+    struct hdr_ctx *ctx;
+
+    if (parser->ctx == NULL) {
+        ctx = apr_pcalloc(pool, sizeof *ctx);
+        ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
+        parser->ctx = ctx;
+        ctx->status = HDR_NAME;
+    }
+    else
+        ctx = parser->ctx;
+
+    PARSER_STATUS_CHECK(HDR);
+    e = APR_BRIGADE_LAST(ctx->bb);
+    APR_BRIGADE_CONCAT(ctx->bb, bb);
+
+ parse_hdr_brigade:
+
+
+    /* parse the brigade for CRLF_CRLF-terminated header block,
+     * each time starting from the front of the brigade.
+     */
+
+    for (e = APR_BUCKET_NEXT(e);
+         e != APR_BRIGADE_SENTINEL(ctx->bb);
+         e = APR_BUCKET_NEXT(e))
+    {
+        apr_size_t off = 0, dlen;
+        const char *data;
+        apr_status_t s;
+        apreq_param_t *param = NULL; /* silences gcc-4.0 warning */
+
+        if (APR_BUCKET_IS_EOS(e)) {
+            ctx->status = HDR_COMPLETE;
+            APR_BRIGADE_CONCAT(bb, ctx->bb);
+            return APR_SUCCESS;
+        }
+        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+
+        if ( s != APR_SUCCESS ) {
+            ctx->status = HDR_ERROR;
+            return s;
+        }
+        if (dlen == 0)
+            continue;
+
+    parse_hdr_bucket:
+
+        /*              gap           nlen = 13
+         *              vvv           glen =  3
+         * Sample-Header:  grape      vlen =  5
+         * ^^^^^^^^^^^^^   ^^^^^
+         *     name        value
+         */
+
+        switch (ctx->status) {
+
+        case HDR_NAME:
+
+            while (off < dlen) {
+                switch (data[off++]) {
+
+                case '\n':
+                    if (off < dlen)
+                        apr_bucket_split(e, off);
+                    e = APR_BUCKET_NEXT(e);
+
+                    do {
+                        apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
+                        apr_bucket_delete(f);
+                    } while (e != APR_BRIGADE_FIRST(ctx->bb));
+                    APR_BRIGADE_CONCAT(bb, ctx->bb);
+                    ctx->status = HDR_COMPLETE;
+                    return APR_SUCCESS;
+
+                case ':':
+                    if (off > 1) {
+                        apr_bucket_split(e, off - 1);
+                        dlen -= off - 1;
+                        data += off - 1;
+                        off = 1;
+                        e = APR_BUCKET_NEXT(e);
+                    }
+                    ++ctx->glen;
+                    ctx->status = HDR_GAP;
+                    goto parse_hdr_bucket;
+
+                default:
+                    ++ctx->nlen;
+                }
+
+            }
+
+            break;
+
+
+        case HDR_GAP:
+
+            while (off < dlen) {
+                switch (data[off++]) {
+                case ' ':
+                case '\t':
+                    ++ctx->glen;
+                    break;
+
+                case '\n':
+                    ctx->status = HDR_NEWLINE;
+                    goto parse_hdr_bucket;
+
+                default:
+                    ctx->status = HDR_VALUE;
+                    if (off > 1) {
+                        apr_bucket_split(e, off - 1);
+                        dlen -= off - 1;
+                        data += off - 1;
+                        off = 1;
+                        e = APR_BUCKET_NEXT(e);
+                    }
+                    ++ctx->vlen;
+                    goto parse_hdr_bucket;
+                }
+            }
+            break;
+
+
+        case HDR_VALUE:
+
+            while (off < dlen) {
+                ++ctx->vlen;
+                if (data[off++] == '\n') {
+                    ctx->status = HDR_NEWLINE;
+                    goto parse_hdr_bucket;
+                }
+            }
+            break;
+
+
+        case HDR_NEWLINE:
+
+            if (off == dlen)
+                break;
+            else {
+                switch (data[off]) {
+
+                case ' ':
+                case '\t':
+                    ctx->status = HDR_CONTINUE;
+                    ++off;
+                    ++ctx->vlen;
+                    break;
+
+                default:
+                    /* can parse brigade now */
+                    if (off > 0)
+                        apr_bucket_split(e, off);
+                    s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
+                    if (parser->hook != NULL && s == APR_SUCCESS)
+                        s = apreq_hook_run(parser->hook, param, NULL);
+
+                    if (s != APR_SUCCESS) {
+                        ctx->status = HDR_ERROR;
+                        return s;
+                    }
+
+                    apreq_value_table_add(&param->v, t);
+                    e = APR_BRIGADE_SENTINEL(ctx->bb);
+                    ctx->status = HDR_NAME;
+                    ctx->nlen = 0;
+                    ctx->vlen = 0;
+                    ctx->glen = 0;
+
+                    goto parse_hdr_brigade;
+                }
+
+                /* cases ' ', '\t' fall through to HDR_CONTINUE */
+            }
+
+
+        case HDR_CONTINUE:
+
+            while (off < dlen) {
+                switch (data[off++]) {
+                case ' ':
+                case '\t':
+                    ++ctx->vlen;
+                    break;
+
+                case '\n':
+                    ctx->status = HDR_NEWLINE;
+                    goto parse_hdr_bucket;
+
+                default:
+                    ctx->status = HDR_VALUE;
+                    ++ctx->vlen;
+                    goto parse_hdr_bucket;
+                }
+            }
+            break;
+
+        default:
+            ; /* not reached */
+        }
+    }
+    apreq_brigade_setaside(ctx->bb,pool);
+    return APR_INCOMPLETE;
+}

Propchange: httpd/apreq/branches/apr-build-system/library/parser_header.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/library/parser_multipart.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/parser_multipart.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/library/parser_multipart.c (added)
+++ httpd/apreq/branches/apr-build-system/library/parser_multipart.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,653 @@
+/*
+**  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 "apreq_parser.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+#include "apr_strings.h"
+#include "apr_strmatch.h"
+
+#ifndef CRLF
+#define CRLF    "\015\012"
+#endif
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define PARSER_STATUS_CHECK(PREFIX)   do {         \
+    if (ctx->status == PREFIX##_ERROR)             \
+        return APREQ_ERROR_GENERAL;                \
+    else if (ctx->status == PREFIX##_COMPLETE)     \
+        return APR_SUCCESS;                        \
+    else if (bb == NULL)                           \
+        return APR_INCOMPLETE;                     \
+} while (0);
+
+/* maximum recursion level in the mfd parser */
+#define MAX_LEVEL 8
+
+struct mfd_ctx {
+    apr_table_t                 *info;
+    apr_bucket_brigade          *in;
+    apr_bucket_brigade          *bb;
+    apreq_parser_t              *hdr_parser;
+    apreq_parser_t              *next_parser;
+    const apr_strmatch_pattern  *pattern;
+    char                        *bdry;
+    enum {
+        MFD_INIT,
+        MFD_NEXTLINE,
+        MFD_HEADER,
+        MFD_POST_HEADER,
+        MFD_PARAM,
+        MFD_UPLOAD,
+        MFD_MIXED,
+        MFD_COMPLETE,
+        MFD_ERROR
+    }                            status;
+    apr_bucket                  *eos;
+    const char                  *param_name;
+    apreq_param_t               *upload;
+    unsigned                    level;
+};
+
+
+/********************* multipart/form-data *********************/
+
+APR_INLINE
+static apr_status_t brigade_start_string(apr_bucket_brigade *bb,
+                                         const char *start_string)
+{
+    apr_bucket *e;
+    apr_size_t slen = strlen(start_string);
+
+    for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
+         e = APR_BUCKET_NEXT(e))
+    {
+        const char *buf;
+        apr_status_t s, bytes_to_check;
+        apr_size_t blen;
+
+        if (slen == 0)
+            return APR_SUCCESS;
+
+        if (APR_BUCKET_IS_EOS(e))
+            return APR_EOF;
+
+        s = apr_bucket_read(e, &buf, &blen, APR_BLOCK_READ);
+
+        if (s != APR_SUCCESS)
+            return s;
+
+        if (blen == 0)
+            continue;
+
+        bytes_to_check = MIN(slen,blen);
+
+        if (strncmp(buf,start_string,bytes_to_check) != 0)
+            return APREQ_ERROR_GENERAL;
+
+        slen -= bytes_to_check;
+        start_string += bytes_to_check;
+    }
+
+    /* slen > 0, so brigade isn't large enough yet */
+    return APR_INCOMPLETE;
+}
+
+
+static apr_status_t split_on_bdry(apr_bucket_brigade *out,
+                                  apr_bucket_brigade *in,
+                                  const apr_strmatch_pattern *pattern,
+                                  const char *bdry)
+{
+    apr_bucket *e = APR_BRIGADE_FIRST(in);
+    apr_size_t blen = strlen(bdry), off = 0;
+
+    while ( e != APR_BRIGADE_SENTINEL(in) ) {
+        apr_ssize_t idx;
+        apr_size_t len;
+        const char *buf;
+        apr_status_t s;
+
+        if (APR_BUCKET_IS_EOS(e))
+            return APR_EOF;
+
+        s = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        if (len == 0) {
+            apr_bucket *f = e;
+            e = APR_BUCKET_NEXT(e);
+            apr_bucket_delete(f);
+            continue;
+        }
+
+    look_for_boundary_up_front:
+        if (strncmp(bdry + off, buf, MIN(len, blen - off)) == 0) {
+            if ( len >= blen - off ) {
+                /* complete match */
+                if (len > blen - off)
+                    apr_bucket_split(e, blen - off);
+                e = APR_BUCKET_NEXT(e);
+
+                do {
+                    apr_bucket *f = APR_BRIGADE_FIRST(in);
+                    apr_bucket_delete(f);
+                } while (APR_BRIGADE_FIRST(in) != e);
+
+                return APR_SUCCESS;
+            }
+            /* partial match */
+            off += len;
+            e = APR_BUCKET_NEXT(e);
+            continue;
+        }
+        else if (off > 0) {
+            /* prior (partial) strncmp failed,
+             * so we can move previous buckets across
+             * and retest buf against the full bdry.
+             */
+            do {
+                apr_bucket *f = APR_BRIGADE_FIRST(in);
+                APR_BUCKET_REMOVE(f);
+                APR_BRIGADE_INSERT_TAIL(out, f);
+            } while (e != APR_BRIGADE_FIRST(in));
+            off = 0;
+            goto look_for_boundary_up_front;
+        }
+
+        if (pattern != NULL && len >= blen) {
+            const char *match = apr_strmatch(pattern, buf, len);
+            if (match != NULL)
+                idx = match - buf;
+            else {
+                idx = apreq_index(buf + len-blen, blen, bdry, blen,
+                                  APREQ_MATCH_PARTIAL);
+                if (idx >= 0)
+                    idx += len-blen;
+            }
+        }
+        else
+            idx = apreq_index(buf, len, bdry, blen, APREQ_MATCH_PARTIAL);
+
+        /* Theoretically idx should never be 0 here, because we
+         * already tested the front of the brigade for a potential match.
+         * However, it doesn't hurt to allow for the possibility,
+         * since this will just start the whole loop over again.
+         */
+        if (idx >= 0)
+            apr_bucket_split(e, idx);
+
+        APR_BUCKET_REMOVE(e);
+        APR_BRIGADE_INSERT_TAIL(out, e);
+        e = APR_BRIGADE_FIRST(in);
+    }
+
+    return APR_INCOMPLETE;
+}
+
+
+static
+struct mfd_ctx * create_multipart_context(const char *content_type,
+                                          apr_pool_t *pool,
+                                          apr_bucket_alloc_t *ba,
+                                          apr_size_t brigade_limit,
+                                          const char *temp_dir,
+                                          unsigned level)
+
+{
+    apr_status_t s;
+    apr_size_t blen;
+    struct mfd_ctx *ctx = apr_palloc(pool, sizeof *ctx);
+    char *ct = apr_pstrdup(pool, content_type);
+
+    ct = strchr(ct, ';');
+    if (ct == NULL)
+        return NULL; /* missing semicolon */
+
+    *ct++ = 0;
+    s = apreq_header_attribute(ct, "boundary", 8,
+                               (const char **)&ctx->bdry, &blen);
+
+    if (s != APR_SUCCESS)
+        return NULL; /* missing boundary */
+
+    ctx->bdry[blen] = 0;
+
+    *--ctx->bdry = '-';
+    *--ctx->bdry = '-';
+    *--ctx->bdry = '\n';
+    *--ctx->bdry = '\r';
+
+    ctx->status = MFD_INIT;
+    ctx->pattern = apr_strmatch_precompile(pool, ctx->bdry, 1);
+    ctx->hdr_parser = apreq_parser_make(pool, ba, "",
+                                        apreq_parse_headers,
+                                        brigade_limit,
+                                        temp_dir, NULL, NULL);
+    ctx->info = NULL;
+    ctx->bb = apr_brigade_create(pool, ba);
+    ctx->in = apr_brigade_create(pool, ba);
+    ctx->eos = apr_bucket_eos_create(ba);
+    ctx->next_parser = NULL;
+    ctx->param_name = NULL;
+    ctx->upload = NULL;
+    ctx->level = level;
+
+    return ctx;
+}
+
+APREQ_DECLARE_PARSER(apreq_parse_multipart)
+{
+    apr_pool_t *pool = parser->pool;
+    apr_bucket_alloc_t *ba = parser->bucket_alloc;
+    struct mfd_ctx *ctx = parser->ctx;
+    apr_status_t s;
+
+    if (ctx == NULL) {
+        ctx = create_multipart_context(parser->content_type,
+                                       pool, ba,
+                                       parser->brigade_limit,
+                                       parser->temp_dir, 1);
+        if (ctx == NULL)
+            return APREQ_ERROR_GENERAL;
+
+
+        parser->ctx = ctx;
+    }
+
+    PARSER_STATUS_CHECK(MFD);
+    APR_BRIGADE_CONCAT(ctx->in, bb);
+
+ mfd_parse_brigade:
+
+    switch (ctx->status) {
+
+    case MFD_INIT:
+        {
+            s = split_on_bdry(ctx->bb, ctx->in, NULL, ctx->bdry + 2);
+            if (s != APR_SUCCESS) {
+                apreq_brigade_setaside(ctx->in, pool);
+                apreq_brigade_setaside(ctx->bb, pool);
+                return s;
+            }
+            ctx->status = MFD_NEXTLINE;
+            /* Be polite and return any preamble text to the caller. */
+            APR_BRIGADE_CONCAT(bb, ctx->bb);
+        }
+
+        /* fall through */
+
+    case MFD_NEXTLINE:
+        {
+            s = split_on_bdry(ctx->bb, ctx->in, NULL, CRLF);
+            if (s == APR_EOF) {
+                ctx->status = MFD_COMPLETE;
+                return APR_SUCCESS;
+            }
+            if (s != APR_SUCCESS) {
+                apreq_brigade_setaside(ctx->in, pool);
+                apreq_brigade_setaside(ctx->bb, pool);
+                return s;
+            }
+            if (!APR_BRIGADE_EMPTY(ctx->bb)) {
+                char *line;
+                apr_size_t len;
+                apr_brigade_pflatten(ctx->bb, &line, &len, pool);
+
+                if (len >= 2 && strncmp(line, "--", 2) == 0) {
+                    APR_BRIGADE_CONCAT(bb, ctx->in);
+                    ctx->status = MFD_COMPLETE;
+                    return APR_SUCCESS;
+                }
+                apr_brigade_cleanup(ctx->bb);
+            }
+
+            ctx->status = MFD_HEADER;
+            ctx->info = NULL;
+        }
+        /* fall through */
+
+    case MFD_HEADER:
+        {
+            if (ctx->info == NULL) {
+                ctx->info = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+                /* flush out header parser internal structs for reuse */
+                ctx->hdr_parser->ctx = NULL;
+            }
+            s = apreq_parser_run(ctx->hdr_parser, ctx->info, ctx->in);
+            switch (s) {
+            case APR_SUCCESS:
+                ctx->status = MFD_POST_HEADER;
+                break;
+            case APR_INCOMPLETE:
+                apreq_brigade_setaside(ctx->in, pool);
+                return APR_INCOMPLETE;
+            default:
+                ctx->status = MFD_ERROR;
+                return s;
+            }
+        }
+        /* fall through */
+
+    case MFD_POST_HEADER:
+        {
+            /*  Must handle special case of missing CRLF (mainly
+             *  coming from empty file uploads). See RFC2065 S5.1.1:
+             *
+             *    body-part = MIME-part-header [CRLF *OCTET]
+             *
+             *  So the CRLF we already matched in MFD_HEADER may have been
+             *  part of the boundary string! Both Konqueror (v??) and
+             *  Mozilla-0.97 are known to emit such blocks.
+             *
+             *  Here we first check for this condition with
+             *  brigade_start_string, and prefix the brigade with
+             *  an additional CRLF bucket if necessary.
+             */
+
+            const char *cd, *ct, *name, *filename;
+            apr_size_t nlen, flen;
+            apr_bucket *e;
+
+            switch (brigade_start_string(ctx->in, ctx->bdry + 2)) {
+
+            case APR_INCOMPLETE:
+                apreq_brigade_setaside(ctx->in, pool);
+                return APR_INCOMPLETE;
+
+            case APR_SUCCESS:
+                /* part has no body- return CRLF to front */
+                e = apr_bucket_immortal_create(CRLF, 2,
+                                                ctx->bb->bucket_alloc);
+                APR_BRIGADE_INSERT_HEAD(ctx->in, e);
+                break;
+
+            default:
+                ; /* has body, ok */
+            }
+
+            cd = apr_table_get(ctx->info, "Content-Disposition");
+
+            /*  First check to see if must descend into a new multipart
+             *  block.  If we do, create a new parser and pass control
+             *  to it.
+             */
+
+            ct = apr_table_get(ctx->info, "Content-Type");
+
+            if (ct != NULL && strncmp(ct, "multipart/", 10) == 0) {
+                struct mfd_ctx *next_ctx;
+
+                if (ctx->level >= MAX_LEVEL) {
+                    ctx->status = MFD_ERROR;
+                    goto mfd_parse_brigade;
+                }
+
+                next_ctx = create_multipart_context(ct, pool, ba,
+                                                    parser->brigade_limit,
+                                                    parser->temp_dir,
+                                                    ctx->level + 1);
+
+                next_ctx->param_name = "";
+
+                if (cd != NULL) {
+                    s = apreq_header_attribute(cd, "name", 4,
+                                               &name, &nlen);
+                    if (s == APR_SUCCESS) {
+                        next_ctx->param_name
+                            = apr_pstrmemdup(pool, name, nlen);
+                    }
+                    else {
+                        const char *cid = apr_table_get(ctx->info,
+                                                        "Content-ID");
+                        if (cid != NULL)
+                            next_ctx->param_name = apr_pstrdup(pool, cid);
+                    }
+
+                }
+
+                ctx->next_parser = apreq_parser_make(pool, ba, ct,
+                                                     apreq_parse_multipart,
+                                                     parser->brigade_limit,
+                                                     parser->temp_dir,
+                                                     parser->hook,
+                                                     next_ctx);
+                ctx->status = MFD_MIXED;
+                goto mfd_parse_brigade;
+
+            }
+
+            /* Look for a normal form-data part. */
+
+            if (cd != NULL && strncmp(cd, "form-data", 9) == 0) {
+                s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
+                if (s != APR_SUCCESS) {
+                    ctx->status = MFD_ERROR;
+                    goto mfd_parse_brigade;
+                }
+
+                s = apreq_header_attribute(cd, "filename",
+                                           8, &filename, &flen);
+                if (s == APR_SUCCESS) {
+                    apreq_param_t *param;
+
+                    param = apreq_param_make(pool, name, nlen,
+                                             filename, flen);
+                    apreq_param_tainted_on(param);
+                    param->info = ctx->info;
+                    param->upload
+                        = apr_brigade_create(pool, ctx->bb->bucket_alloc);
+                    ctx->upload = param;
+                    ctx->status = MFD_UPLOAD;
+                    goto mfd_parse_brigade;
+                }
+                else {
+                    ctx->param_name = apr_pstrmemdup(pool, name, nlen);
+                    ctx->status = MFD_PARAM;
+                    /* fall thru */
+                }
+            }
+
+            /* else check for a file part in a multipart section */
+            else if (cd != NULL && strncmp(cd, "file", 4) == 0) {
+                apreq_param_t *param;
+
+                s = apreq_header_attribute(cd, "filename",
+                                           8, &filename, &flen);
+                if (s != APR_SUCCESS || ctx->param_name == NULL) {
+                    ctx->status = MFD_ERROR;
+                    goto mfd_parse_brigade;
+                }
+                name = ctx->param_name;
+                nlen = strlen(name);
+                param = apreq_param_make(pool, name, nlen,
+                                         filename, flen);
+                apreq_param_tainted_on(param);
+                param->info = ctx->info;
+                param->upload = apr_brigade_create(pool,
+                                                   ctx->bb->bucket_alloc);
+                ctx->upload = param;
+                ctx->status = MFD_UPLOAD;
+                goto mfd_parse_brigade;
+            }
+
+            /* otherwise look for Content-ID in multipart/mixed case */
+            else {
+                const char *cid = apr_table_get(ctx->info, "Content-ID");
+                apreq_param_t *param;
+
+                if (cid != NULL) {
+                    name = cid;
+                    nlen = strlen(name);
+                }
+                else {
+                    name = "";
+                    nlen = 0;
+                }
+
+                filename = "";
+                flen = 0;
+                param = apreq_param_make(pool, name, nlen,
+                                         filename, flen);
+                apreq_param_tainted_on(param);
+                param->info = ctx->info;
+                param->upload = apr_brigade_create(pool,
+                                               ctx->bb->bucket_alloc);
+                ctx->upload = param;
+                ctx->status = MFD_UPLOAD;
+                goto mfd_parse_brigade;
+            }
+        }
+        /* fall through */
+
+    case MFD_PARAM:
+        {
+            apreq_param_t *param;
+            apreq_value_t *v;
+            apr_size_t len;
+            apr_off_t off;
+
+            s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
+
+            switch (s) {
+
+            case APR_INCOMPLETE:
+                apreq_brigade_setaside(ctx->in, pool);
+                apreq_brigade_setaside(ctx->bb, pool);
+                return s;
+
+            case APR_SUCCESS:
+                s = apr_brigade_length(ctx->bb, 1, &off);
+                if (s != APR_SUCCESS) {
+                    ctx->status = MFD_ERROR;
+                    return s;
+                }
+                len = off;
+                param = apreq_param_make(pool, ctx->param_name,
+                                         strlen(ctx->param_name),
+                                         NULL, len);
+                apreq_param_tainted_on(param);
+                param->info = ctx->info;
+
+                *(const apreq_value_t **)&v = &param->v;
+                apr_brigade_flatten(ctx->bb, v->data, &len);
+                v->data[len] = 0;
+
+                if (parser->hook != NULL) {
+                    s = apreq_hook_run(parser->hook, param, NULL);
+                    if (s != APR_SUCCESS) {
+                        ctx->status = MFD_ERROR;
+                        return s;
+                    }
+                }
+
+                apreq_param_charset_set(param,
+                                        apreq_charset_divine(v->data, len));
+                apreq_value_table_add(v, t);
+                ctx->status = MFD_NEXTLINE;
+                ctx->param_name = NULL;
+                apr_brigade_cleanup(ctx->bb);
+                goto mfd_parse_brigade;
+
+            default:
+                ctx->status = MFD_ERROR;
+                return s;
+            }
+
+
+        }
+        break;  /* not reached */
+
+    case MFD_UPLOAD:
+        {
+            apreq_param_t *param = ctx->upload;
+
+            s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
+            switch (s) {
+
+            case APR_INCOMPLETE:
+                if (parser->hook != NULL) {
+                    s = apreq_hook_run(parser->hook, param, ctx->bb);
+                    if (s != APR_SUCCESS) {
+                        ctx->status = MFD_ERROR;
+                        return s;
+                    }
+                }
+                apreq_brigade_setaside(ctx->bb, pool);
+                apreq_brigade_setaside(ctx->in, pool);
+                s = apreq_brigade_concat(pool, parser->temp_dir,
+                                         parser->brigade_limit,
+                                         param->upload, ctx->bb);
+                return (s == APR_SUCCESS) ? APR_INCOMPLETE : s;
+
+            case APR_SUCCESS:
+                if (parser->hook != NULL) {
+                    APR_BRIGADE_INSERT_TAIL(ctx->bb, ctx->eos);
+                    s = apreq_hook_run(parser->hook, param, ctx->bb);
+                    APR_BUCKET_REMOVE(ctx->eos);
+                    if (s != APR_SUCCESS) {
+                        ctx->status = MFD_ERROR;
+                        return s;
+                    }
+                }
+                apreq_value_table_add(&param->v, t);
+                apreq_brigade_setaside(ctx->bb, pool);
+                s = apreq_brigade_concat(pool, parser->temp_dir,
+                                         parser->brigade_limit,
+                                         param->upload, ctx->bb);
+
+                if (s != APR_SUCCESS)
+                    return s;
+
+                ctx->status = MFD_NEXTLINE;
+                goto mfd_parse_brigade;
+
+            default:
+                ctx->status = MFD_ERROR;
+                return s;
+            }
+
+        }
+        break;  /* not reached */
+
+
+    case MFD_MIXED:
+        {
+            s = apreq_parser_run(ctx->next_parser, t, ctx->in);
+            switch (s) {
+            case APR_SUCCESS:
+                ctx->status = MFD_INIT;
+                ctx->param_name = NULL;
+                goto mfd_parse_brigade;
+            case APR_INCOMPLETE:
+                APR_BRIGADE_CONCAT(bb, ctx->in);
+                return APR_INCOMPLETE;
+            default:
+                ctx->status = MFD_ERROR;
+                return s;
+            }
+
+        }
+        break; /* not reached */
+
+    default:
+        return APREQ_ERROR_GENERAL;
+    }
+
+    return APR_INCOMPLETE;
+}

Propchange: httpd/apreq/branches/apr-build-system/library/parser_multipart.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/library/parser_urlencoded.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/parser_urlencoded.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/library/parser_urlencoded.c (added)
+++ httpd/apreq/branches/apr-build-system/library/parser_urlencoded.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,274 @@
+/*
+**  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 "apreq_parser.h"
+#include "apreq_util.h"
+#include "apreq_error.h"
+
+
+#define PARSER_STATUS_CHECK(PREFIX)   do {         \
+    if (ctx->status == PREFIX##_ERROR)             \
+        return APREQ_ERROR_GENERAL;                \
+    else if (ctx->status == PREFIX##_COMPLETE)     \
+        return APR_SUCCESS;                        \
+    else if (bb == NULL)                           \
+        return APR_INCOMPLETE;                     \
+} while (0);
+
+
+
+struct url_ctx {
+    apr_bucket_brigade *bb;
+    apr_size_t          nlen;
+    apr_size_t          vlen;
+    enum {
+        URL_NAME,
+        URL_VALUE,
+        URL_COMPLETE,
+        URL_ERROR
+    }                   status;
+};
+
+
+/******************** application/x-www-form-urlencoded ********************/
+
+static apr_status_t split_urlword(apreq_param_t **p, apr_pool_t *pool,
+                                  apr_bucket_brigade *bb,
+                                  apr_size_t nlen,
+                                  apr_size_t vlen)
+{
+    apreq_param_t *param;
+    apreq_value_t *v;
+    apr_bucket *e, *f;
+    apr_status_t s;
+    struct iovec vec[APREQ_DEFAULT_NELTS];
+    apr_array_header_t arr;
+    apr_size_t mark;
+    apreq_charset_t charset;
+
+    if (nlen == 0)
+        return APR_EBADARG;
+
+    param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
+    *(const apreq_value_t **)&v = &param->v;
+
+    arr.pool     = pool;
+    arr.elt_size = sizeof(struct iovec);
+    arr.nelts    = 0;
+    arr.nalloc   = APREQ_DEFAULT_NELTS;
+    arr.elts     = (char *)vec;
+
+    ++nlen, ++vlen;
+    e = APR_BRIGADE_FIRST(bb);
+
+    while (!APR_BUCKET_IS_EOS(e)) {
+        struct iovec *iov = apr_array_push(&arr);
+        apr_size_t len;
+        s = apr_bucket_read(e, (const char **)&iov->iov_base,
+                            &len, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        iov->iov_len = len;
+        nlen -= len;
+
+        e = APR_BUCKET_NEXT(e);
+
+        if (nlen == 0) {
+            iov->iov_len--;
+            break;
+        }
+    }
+
+    mark = arr.nelts;
+
+    while (!APR_BUCKET_IS_EOS(e)) {
+        struct iovec *iov = apr_array_push(&arr);
+        apr_size_t len;
+        s = apr_bucket_read(e, (const char **)&iov->iov_base,
+                            &len, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        iov->iov_len = len;
+        vlen -= len;
+
+        e = APR_BUCKET_NEXT(e);
+
+        if (vlen == 0) {
+            iov->iov_len--;
+            break;
+        }
+
+    }
+
+    s = apreq_decodev(v->data, &vlen,
+                      (struct iovec *)arr.elts + mark, arr.nelts - mark);
+    if (s != APR_SUCCESS)
+        return s;
+
+    charset = apreq_charset_divine(v->data, vlen);
+
+    v->name = v->data + vlen + 1;
+    v->dlen = vlen;
+
+    s = apreq_decodev(v->name, &nlen, (struct iovec *)arr.elts, mark);
+    if (s != APR_SUCCESS)
+        return s;
+
+    switch (apreq_charset_divine(v->name, nlen)) {
+    case APREQ_CHARSET_UTF8:
+        if (charset == APREQ_CHARSET_ASCII)
+            charset = APREQ_CHARSET_UTF8;
+    case APREQ_CHARSET_ASCII:
+        break;
+
+    case APREQ_CHARSET_LATIN1:
+        if (charset != APREQ_CHARSET_CP1252)
+            charset = APREQ_CHARSET_LATIN1;
+        break;
+    case APREQ_CHARSET_CP1252:
+        charset = APREQ_CHARSET_CP1252;
+    }
+
+    v->nlen = nlen;
+
+    while ((f = APR_BRIGADE_FIRST(bb)) != e)
+        apr_bucket_delete(f);
+
+    apreq_param_tainted_on(param);
+    apreq_param_charset_set(param, charset);
+    *p = param;
+    return APR_SUCCESS;
+}
+
+APREQ_DECLARE_PARSER(apreq_parse_urlencoded)
+{
+    apr_pool_t *pool = parser->pool;
+    apr_bucket *e;
+    struct url_ctx *ctx;
+
+    if (parser->ctx == NULL) {
+        ctx = apr_pcalloc(pool, sizeof *ctx);
+        ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
+        parser->ctx = ctx;
+        ctx->status = URL_NAME;
+    }
+    else
+        ctx = parser->ctx;
+
+    PARSER_STATUS_CHECK(URL);
+    e = APR_BRIGADE_LAST(ctx->bb);
+    APR_BRIGADE_CONCAT(ctx->bb, bb);
+
+ parse_url_brigade:
+
+    for (e  = APR_BUCKET_NEXT(e);
+         e != APR_BRIGADE_SENTINEL(ctx->bb);
+         e  = APR_BUCKET_NEXT(e))
+    {
+        apreq_param_t *param;
+        apr_size_t off = 0, dlen;
+        const char *data;
+        apr_status_t s;
+
+        if (APR_BUCKET_IS_EOS(e)) {
+            if (ctx->status == URL_NAME) {
+                s = APR_SUCCESS;
+            }
+            else {
+                s = split_urlword(&param, pool, ctx->bb, ctx->nlen, ctx->vlen);
+                if (parser->hook != NULL && s == APR_SUCCESS)
+                    s = apreq_hook_run(parser->hook, param, NULL);
+
+                if (s == APR_SUCCESS) {
+                    apreq_value_table_add(&param->v, t);
+                    ctx->status = URL_COMPLETE;
+                }
+                else {
+                    ctx->status = URL_ERROR;
+                }
+            }
+
+            APR_BRIGADE_CONCAT(bb, ctx->bb);
+            return s;
+        }
+
+        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+        if ( s != APR_SUCCESS ) {
+            ctx->status = URL_ERROR;
+            return s;
+        }
+
+    parse_url_bucket:
+
+        switch (ctx->status) {
+
+        case URL_NAME:
+            while (off < dlen) {
+                switch (data[off++]) {
+                case '=':
+                    apr_bucket_split(e, off);
+                    dlen -= off;
+                    data += off;
+                    off = 0;
+                    e = APR_BUCKET_NEXT(e);
+                    ctx->status = URL_VALUE;
+                    goto parse_url_bucket;
+                default:
+                    ++ctx->nlen;
+                }
+            }
+            break;
+
+        case URL_VALUE:
+            while (off < dlen) {
+
+                switch (data[off++]) {
+                case '&':
+                case ';':
+                    apr_bucket_split(e, off);
+                    s = split_urlword(&param, pool, ctx->bb,
+                                      ctx->nlen, ctx->vlen);
+                    if (parser->hook != NULL && s == APR_SUCCESS)
+                        s = apreq_hook_run(parser->hook, param, NULL);
+
+                    if (s != APR_SUCCESS) {
+                        ctx->status = URL_ERROR;
+                        return s;
+                    }
+
+                    apreq_value_table_add(&param->v, t);
+                    ctx->status = URL_NAME;
+                    ctx->nlen = 0;
+                    ctx->vlen = 0;
+                    e = APR_BRIGADE_SENTINEL(ctx->bb);
+                    goto parse_url_brigade;
+
+                default:
+                    ++ctx->vlen;
+                }
+            }
+            break;
+        default:
+            ; /* not reached */
+        }
+    }
+    apreq_brigade_setaside(ctx->bb, pool);
+    return APR_INCOMPLETE;
+}
+
+

Propchange: httpd/apreq/branches/apr-build-system/library/parser_urlencoded.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/library/util.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/util.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/library/util.c (added)
+++ httpd/apreq/branches/apr-build-system/library/util.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,1118 @@
+/*
+**  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 "apreq_util.h"
+#include "apreq_error.h"
+#include "apr_time.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include <assert.h>
+
+#undef MAX
+#undef MIN
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
+
+/* used for specifying file sizes */
+
+APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s)
+{
+    apr_int64_t n = 0;
+    char *p;
+    if (s == NULL)
+        return 0;
+
+    n = apr_strtoi64(s, &p, 0);
+
+    if (p == NULL)
+        return n;
+    while (apr_isspace(*p))
+        ++p;
+
+    switch (*p) {
+      case 'G': /* fall thru */
+      case 'g': return n * 1024*1024*1024;
+      case 'M': /* fall thru */
+      case 'm': return n * 1024*1024;
+      case 'K': /* fall thru */
+      case 'k': return n * 1024;
+    }
+
+    return n;
+}
+
+
+/* converts date offsets (e.g. "+3M") to seconds */
+
+APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s)
+{
+    apr_int64_t n = 0;
+    char *p;
+    if (s == NULL)
+        return 0;
+    n = apr_strtoi64(s, &p, 0); /* XXX: what about overflow? */
+
+    if (p == NULL)
+        return n;
+    while (apr_isspace(*p))
+        ++p;
+
+    switch (*p) {
+      case 'Y': /* fall thru */
+      case 'y': return n * 60*60*24*365;
+      case 'M': return n * 60*60*24*30;
+      case 'D': /* fall thru */
+      case 'd': return n * 60*60*24;
+      case 'H': /* fall thru */
+      case 'h': return n * 60*60;
+      case 'm': return n * 60;
+      case 's': /* fall thru */
+      default:
+          return n;
+    }
+    /* should never get here */
+    return -1;
+}
+
+
+APREQ_DECLARE(apr_ssize_t ) apreq_index(const char* hay, apr_size_t hlen,
+                                        const char* ndl, apr_size_t nlen,
+                                        const apreq_match_t type)
+{
+    apr_size_t len = hlen;
+    const char *end = hay + hlen;
+    const char *begin = hay;
+
+    while ( (hay = memchr(hay, ndl[0], len)) ) {
+	len = end - hay;
+
+	/* done if matches up to capacity of buffer */
+	if ( memcmp(hay, ndl, MIN(nlen, len)) == 0 ) {
+            if (type == APREQ_MATCH_FULL && len < nlen)
+                hay = NULL;     /* insufficient room for match */
+	    break;
+        }
+        --len;
+        ++hay;
+    }
+
+    return hay ? hay - begin : -1;
+}
+
+
+static const char c2x_table[] = "0123456789ABCDEF";
+static APR_INLINE unsigned char hex2_to_char(const char *what)
+{
+    register unsigned char digit;
+
+#if !APR_CHARSET_EBCDIC
+    digit  = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
+    digit *= 16;
+    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
+#else /*APR_CHARSET_EBCDIC*/
+    char xstr[5];
+    xstr[0]='0';
+    xstr[1]='x';
+    xstr[2]=what[0];
+    xstr[3]=what[1];
+    xstr[4]='\0';
+    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16));
+#endif /*APR_CHARSET_EBCDIC*/
+    return (digit);
+}
+
+
+/* Unicode notes: "bmp" refers to the 16-bit
+ * Unicode Basic Multilingual Plane. Here we're
+ * restricting our unicode internals to 16-bit
+ * codepoints, to keep the code as simple as possible.
+ * This should be sufficient for apreq itself, since
+ * we really only need to validate RFC3986-encoded utf8.
+ */
+
+/* Converts Windows cp1252 to Unicode. */
+
+static APR_INLINE
+apr_uint16_t cp1252_to_bmp(unsigned char c)
+{
+    /* We only need to deal with iso-8859-1 control chars
+     * in the 0x80 - 0x9F range.
+     */
+    if ((c & 0xE0) != 0x80)
+        return c;
+
+    switch (c) {
+    case 0x80: return 0x20AC;
+    case 0x82: return 0x201A;
+    case 0x83: return 0x192;
+    case 0x84: return 0x201E;
+    case 0x85: return 0x2026;
+    case 0x86: return 0x2020;
+    case 0x87: return 0x2021;
+    case 0x88: return 0x2C6;
+    case 0x89: return 0x2030;
+    case 0x8A: return 0x160;
+    case 0x8B: return 0x2039;
+    case 0x8C: return 0x152;
+    case 0x8E: return 0x17D;
+    case 0x91: return 0x2018;
+    case 0x92: return 0x2019;
+    case 0x93: return 0x201C;
+    case 0x94: return 0x201D;
+    case 0x95: return 0x2022;
+    case 0x96: return 0x2013;
+    case 0x97: return 0x2014;
+    case 0x98: return 0x2DC;
+    case 0x99: return 0x2122;
+    case 0x9A: return 0x161;
+    case 0x9B: return 0x203A;
+    case 0x9C: return 0x153;
+    case 0x9E: return 0x17E;
+    case 0x9F: return 0x178;
+    }
+    return c;
+}
+
+/* converts cp1252 to utf8 */
+APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
+                                               const char *src, apr_size_t slen)
+{
+    const unsigned char *s = (unsigned const char *)src;
+    const unsigned char *end = s + slen;
+    unsigned char *d = (unsigned char *)dest;
+    apr_uint16_t c;
+
+    while (s < end) {
+        c = cp1252_to_bmp(*s++);
+
+        if (c < 0x80) {
+            *d++ = c;
+        }
+        else if (c < 0x800) {
+            *d++ = 0xC0 | (c >> 6);
+            *d++ = 0x80 | (c & 0x3F);
+        }
+        else {
+            *d++ = 0xE0 | (c >> 12);
+            *d++ = 0x80 | ((c >> 6) & 0x3F);
+            *d++ = 0x80 | (c & 0x3F);
+        }
+    }
+    *d = 0;
+    return d - (unsigned char *)dest;
+}
+
+
+/**
+ * Valid utf8 bit patterns: (true utf8 must satisfy a minimality condition)
+ *
+ * 0aaaaaaa
+ * 110bbbba 10aaaaaa                        minimality mask: 0x1E
+ * 1110cccc 10cbbbba 10aaaaaa                                0x0F || 0x20
+ * 11110ddd 10ddcccc 10cbbbba 10aaaaaa                       0x07 || 0x30
+ * 111110ee 10eeeddd 10ddcccc 10cbbbba 10aaaaaa              0x03 || 0x38
+ * 1111110f 10ffffee 10eeeddd 10ddcccc 10cbbbba 10aaaaaa     0x01 || 0x3C
+ *
+ * Charset divination heuristics:
+ * 1) presume ascii; if not, then
+ * 2) presume utf8; if not, then
+ * 3) presume latin1; unless there are control chars, in which case
+ * 4) punt to cp1252.
+ *
+ * Note: in downgrading from 2 to 3, we need to be careful
+ * about earlier control characters presumed to be valid utf8.
+ */
+
+APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
+                                                    apr_size_t slen)
+
+{
+    apreq_charset_t rv = APREQ_CHARSET_ASCII;
+    register unsigned char trail = 0, saw_cntrl = 0, mask = 0;
+    register const unsigned char *s = (const unsigned char *)src;
+    const unsigned char *end = s + slen;
+
+    for (; s < end; ++s) {
+        if (trail) {
+            if ((*s & 0xC0) == 0x80 && (mask == 0 || (mask & *s))) {
+                mask = 0;
+                --trail;
+
+                if ((*s & 0xE0) == 0x80) {
+                    saw_cntrl = 1;
+                }
+            }
+            else {
+                trail = 0;
+                if (saw_cntrl)
+                    return APREQ_CHARSET_CP1252;
+                rv = APREQ_CHARSET_LATIN1;
+            }
+        }
+        else if (*s < 0x80) {
+            /* do nothing */
+        }
+        else if (*s < 0xA0) {
+            return APREQ_CHARSET_CP1252;
+        }
+        else if (*s < 0xC0) {
+            if (saw_cntrl)
+                return APREQ_CHARSET_CP1252;
+            rv = APREQ_CHARSET_LATIN1;
+        }
+        else if (rv == APREQ_CHARSET_LATIN1) {
+            /* do nothing */
+        }
+
+        /* utf8 cases */
+
+        else if (*s < 0xE0) {
+            if (*s & 0x1E) {
+                rv = APREQ_CHARSET_UTF8;
+                trail = 1;
+                mask = 0;
+            }
+            else if (saw_cntrl)
+                return APREQ_CHARSET_CP1252;
+            else
+                rv = APREQ_CHARSET_LATIN1;
+        }
+        else if (*s < 0xF0) {
+            mask = (*s & 0x0F) ? 0 : 0x20;
+            rv = APREQ_CHARSET_UTF8;
+            trail = 2;
+        }
+        else if (*s < 0xF8) {
+            mask = (*s & 0x07) ? 0 : 0x30;
+            rv = APREQ_CHARSET_UTF8;
+            trail = 3;
+        }
+        else if (*s < 0xFC) {
+            mask = (*s & 0x03) ? 0 : 0x38;
+            rv = APREQ_CHARSET_UTF8;
+            trail = 4;
+        }
+        else if (*s < 0xFE) {
+            mask = (*s & 0x01) ? 0 : 0x3C;
+            rv = APREQ_CHARSET_UTF8;
+            trail = 5;
+        }
+        else {
+            rv = APREQ_CHARSET_UTF8;
+        }
+    }
+
+    return trail ? saw_cntrl ?
+        APREQ_CHARSET_CP1252 : APREQ_CHARSET_LATIN1 : rv;
+}
+
+
+static APR_INLINE apr_uint16_t hex4_to_bmp(const char *what) {
+    register apr_uint16_t digit = 0;
+
+#if !APR_CHARSET_EBCDIC
+    digit  = (what[0] >= 'A' ? ((what[0] & 0xDF)-'A') + 10 : (what[0]-'0'));
+    digit *= 16;
+    digit += (what[1] >= 'A' ? ((what[1] & 0xDF)-'A') + 10 : (what[1]-'0'));
+    digit *= 16;
+    digit += (what[2] >= 'A' ? ((what[2] & 0xDF)-'A') + 10 : (what[2]-'0'));
+    digit *= 16;
+    digit += (what[3] >= 'A' ? ((what[3] & 0xDF)-'A') + 10 : (what[3]-'0'));
+
+#else /*APR_CHARSET_EBCDIC*/
+    char xstr[7];
+    xstr[0]='0';
+    xstr[1]='x';
+    xstr[2]=what[0];
+    xstr[3]=what[1];
+    xstr[4]=what[2];
+    xstr[5]=what[3];
+    xstr[6]='\0';
+    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFFFF & strtol(xstr, NULL, 16));
+#endif /*APR_CHARSET_EBCDIC*/
+    return (digit);
+}
+
+
+static apr_status_t url_decode(char *dest, apr_size_t *dlen,
+                               const char *src, apr_size_t *slen)
+{
+    register const char *s = src;
+    unsigned char *start = (unsigned char *)dest;
+    register unsigned char *d = (unsigned char *)dest;
+    const char *end = src + *slen;
+
+    for (; s < end; ++d, ++s) {
+        switch (*s) {
+
+        case '+':
+            *d = ' ';
+            break;
+
+        case '%':
+	    if (s + 2 < end && apr_isxdigit(s[1]) && apr_isxdigit(s[2]))
+            {
+                *d = hex2_to_char(s + 1);
+                s += 2;
+	    }
+            else if (s + 5 < end && (s[1] == 'u' || s[1] == 'U') &&
+                     apr_isxdigit(s[2]) && apr_isxdigit(s[3]) &&
+                     apr_isxdigit(s[4]) && apr_isxdigit(s[5]))
+            {
+                apr_uint16_t c = hex4_to_bmp(s+2);
+
+                if (c < 0x80) {
+                    *d = c;
+                }
+                else if (c < 0x800) {
+                    *d++ = 0xC0 | (c >> 6);
+                    *d   = 0x80 | (c & 0x3F);
+                }
+                else {
+                    *d++ = 0xE0 | (c >> 12);
+                    *d++ = 0x80 | ((c >> 6) & 0x3F);
+                    *d   = 0x80 | (c & 0x3F);
+                }
+                s += 5;
+            }
+	    else {
+                *dlen = d - start;
+                *slen = s - src;
+                if (s + 5 < end
+                    || (s + 2 < end && !apr_isxdigit(s[2]))
+                    || (s + 1 < end && !apr_isxdigit(s[1])
+                        && s[1] != 'u' && s[1] != 'U'))
+                {
+                    *d = 0;
+                    return APREQ_ERROR_BADSEQ;
+                }
+
+                memmove(d, s, end - s);
+                d[end - s] = 0;
+                return APR_INCOMPLETE;
+	    }
+            break;
+
+        default:
+            if (*s > 0) {
+                *d = *s;
+            }
+            else {
+                *d = 0;
+                *dlen = d - start;
+                *slen = s - src;
+                return APREQ_ERROR_BADCHAR;
+            }
+        }
+    }
+
+    *d = 0;
+    *dlen = d - start;
+    *slen = s - src;
+    return APR_SUCCESS;
+}
+
+
+APREQ_DECLARE(apr_status_t) apreq_decode(char *d, apr_size_t *dlen,
+                                         const char *s, apr_size_t slen)
+{
+    apr_size_t len = 0;
+    const char *end = s + slen;
+
+    if (s == (const char *)d) {     /* optimize for src = dest case */
+        for ( ; d < end; ++d) {
+            if (*d == '%' || *d == '+')
+                break;
+            else if (*d == 0) {
+                *dlen = (const char *)d - s;
+                return APREQ_ERROR_BADCHAR;
+            }
+        }
+        len = (const char *)d - s;
+        s = (const char *)d;
+        slen -= len;
+    }
+
+    return url_decode(d, dlen, s, &slen);
+}
+
+APREQ_DECLARE(apr_status_t) apreq_decodev(char *d, apr_size_t *dlen,
+                                          struct iovec *v, int nelts)
+{
+    apr_status_t status = APR_SUCCESS;
+    int n = 0;
+
+    *dlen = 0;
+
+    while (n < nelts) {
+        apr_size_t slen, len;
+
+        slen = v[n].iov_len;
+        switch (status = url_decode(d, &len, v[n].iov_base, &slen)) {
+
+        case APR_SUCCESS:
+            d += len;
+            *dlen += len;
+            ++n;
+            continue;
+
+        case APR_INCOMPLETE:
+            d += len;
+            *dlen += len;
+            slen = v[n].iov_len - slen;
+
+            if (++n == nelts) {
+                return status;
+            }
+            memcpy(d + slen, v[n].iov_base, v[n].iov_len);
+            v[n].iov_len += slen;
+            v[n].iov_base = d;
+            continue;
+
+        default:
+            *dlen += len;
+            return status;
+        }
+    }
+
+    return status;
+}
+
+
+APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
+                                       const apr_size_t slen)
+{
+    char *d = dest;
+    const unsigned char *s = (const unsigned char *)src;
+    unsigned char c;
+
+    for ( ; s < (const unsigned char *)src + slen; ++s) {
+        c = *s;
+        if ( c < 0x80 && (apr_isalnum(c)
+                          || c == '-' || c == '.'
+                          || c == '_' || c == '~') )
+            *d++ = c;
+
+        else if ( c == ' ' )
+            *d++ = '+';
+
+        else {
+#if APR_CHARSET_EBCDIC
+            c = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)c);
+#endif
+            *d++ = '%';
+            *d++ = c2x_table[c >> 4];
+            *d++ = c2x_table[c & 0xf];
+        }
+    }
+    *d = 0;
+
+    return d - dest;
+}
+
+static int is_quoted(const char *p, const apr_size_t len) {
+    if (len > 1 && p[0] == '"' && p[len-1] == '"') {
+        apr_size_t i;
+        int backslash = 0;
+
+        for (i = 1; i < len - 1; i++) {
+            if (p[i] == '\\')
+                backslash = !backslash;
+            else if (p[i] == 0 || (p[i] == '"' && !backslash))
+                return 0;
+            else
+                backslash = 0;
+        }
+
+        return !backslash;
+    }
+
+    return 0;
+}
+
+APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
+                                           const apr_size_t slen)
+{
+    if (is_quoted(src, slen)) {
+        /* looks like src is already quoted */
+        memcpy(dest, src, slen);
+        dest[slen] = 0;
+        return slen;
+    }
+    else
+        return apreq_quote(dest, src, slen);
+}
+
+APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
+                                      const apr_size_t slen)
+{
+    char *d = dest;
+    const char *s = src;
+    const char *const last = src + slen - 1;
+
+    if (slen == 0) {
+        *d = 0;
+        return 0;
+    }
+
+    *d++ = '"';
+
+    while (s <= last) {
+        switch (*s) {
+        case 0:
+            *d++ = '\\';
+            *d++ = '0';
+            s++;
+            break;
+
+        case '\\':
+        case '"':
+            *d++ = '\\';
+
+        default:
+            *d++ = *s++;
+        }
+    }
+
+    *d++ = '"';
+    *d = 0;
+
+    return d - dest;
+}
+
+APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
+                                 const char *sep,
+                                 const apr_array_header_t *arr,
+                                 apreq_join_t mode)
+{
+    apr_size_t len, slen;
+    char *rv;
+    const apreq_value_t **a = (const apreq_value_t **)arr->elts;
+    char *d;
+    const int n = arr->nelts;
+    int j;
+
+    slen = sep ? strlen(sep) : 0;
+
+    if (n == 0)
+        return apr_pstrdup(p, "");
+
+    for (j=0, len=0; j < n; ++j)
+        len += a[j]->dlen + slen + 1;
+
+    /* Allocated the required space */
+
+    switch (mode) {
+    case APREQ_JOIN_ENCODE:
+        len += 2 * len;
+        break;
+    case APREQ_JOIN_QUOTE:
+        len = 2 * (len + n);
+        break;
+    case APREQ_JOIN_AS_IS:
+    case APREQ_JOIN_DECODE:
+        /* nothing special required, just here to keep noisy compilers happy */
+        break;
+    }
+
+    rv = apr_palloc(p, len);
+
+    /* Pass two --- copy the argument strings into the result space */
+
+    d = rv;
+
+    switch (mode) {
+
+    case APREQ_JOIN_ENCODE:
+        d += apreq_encode(d, a[0]->data, a[0]->dlen);
+
+        for (j = 1; j < n; ++j) {
+                memcpy(d, sep, slen);
+                d += slen;
+                d += apreq_encode(d, a[j]->data, a[j]->dlen);
+        }
+        break;
+
+    case APREQ_JOIN_DECODE:
+        if (apreq_decode(d, &len, a[0]->data, a[0]->dlen))
+            return NULL;
+        else
+            d += len;
+
+        for (j = 1; j < n; ++j) {
+            memcpy(d, sep, slen);
+            d += slen;
+
+            if (apreq_decode(d, &len, a[j]->data, a[j]->dlen))
+                return NULL;
+            else
+                d += len;
+        }
+        break;
+
+
+    case APREQ_JOIN_QUOTE:
+        d += apreq_quote_once(d, a[0]->data, a[0]->dlen);
+
+        for (j = 1; j < n; ++j) {
+            memcpy(d, sep, slen);
+            d += slen;
+            d += apreq_quote_once(d, a[j]->data, a[j]->dlen);
+        }
+        break;
+
+
+    case APREQ_JOIN_AS_IS:
+        memcpy(d,a[0]->data, a[0]->dlen);
+        d += a[0]->dlen;
+
+        for (j = 1; j < n ; ++j) {
+            memcpy(d, sep, slen);
+            d += slen;
+            memcpy(d, a[j]->data, a[j]->dlen);
+            d += a[j]->dlen;
+        }
+        break;
+    }
+
+    *d = 0;
+    return rv;
+}
+
+APR_INLINE
+static apr_status_t apreq_fwritev(apr_file_t *f, struct iovec *v,
+                                  int *nelts, apr_size_t *bytes_written)
+{
+    apr_size_t len;
+    int n;
+    apr_status_t s;
+
+    *bytes_written = 0;
+
+    while (1) {
+        /* try to write */
+        s = apr_file_writev(f, v, *nelts, &len);
+
+        *bytes_written += len;
+
+        if (s != APR_SUCCESS)
+            return s;
+
+        /* see how far we've come */
+        n = 0;
+        while (n < *nelts && len >= v[n].iov_len)
+            len -= v[n++].iov_len;
+
+        if (n == *nelts) {
+            /* nothing left to write, report success */
+            *nelts = 0;
+            return APR_SUCCESS;
+        }
+
+        /* incomplete write: must shift v */
+        v[n].iov_len -= len;
+        v[n].iov_base = (char *)(v[n].iov_base) + len;
+
+        if (n > 0) {
+            /* we're satisfied for now if we can remove one iovec from
+               the "v" array */
+            (*nelts) -= n;
+            memmove(v, v + n, sizeof(*v) * *nelts);
+
+            return APR_SUCCESS;
+        }
+
+        /* we're still in the first iovec - check for endless loop,
+           and then try again */
+        if (len == 0)
+            return APREQ_ERROR_GENERAL;
+    }
+}
+
+
+APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
+                                                 apr_off_t *wlen,
+                                                 apr_bucket_brigade *bb)
+{
+    struct iovec v[APREQ_DEFAULT_NELTS];
+    apr_status_t s;
+    apr_bucket *e;
+    int n = 0;
+    *wlen = 0;
+
+    for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
+         e = APR_BUCKET_NEXT(e))
+    {
+        apr_size_t len;
+        if (n == APREQ_DEFAULT_NELTS) {
+            s = apreq_fwritev(f, v, &n, &len);
+            if (s != APR_SUCCESS)
+                return s;
+            *wlen += len;
+        }
+        s = apr_bucket_read(e, (const char **)&(v[n].iov_base),
+                            &len, APR_BLOCK_READ);
+        if (s != APR_SUCCESS)
+            return s;
+
+        v[n++].iov_len = len;
+    }
+
+    while (n > 0) {
+        apr_size_t len;
+        s = apreq_fwritev(f, v, &n, &len);
+        if (s != APR_SUCCESS)
+            return s;
+        *wlen += len;
+    }
+    return APR_SUCCESS;
+}
+
+
+struct cleanup_data {
+    const char *fname;
+    apr_pool_t *pool;
+};
+
+static apr_status_t apreq_file_cleanup(void *d)
+{
+    struct cleanup_data *data = d;
+    return apr_file_remove(data->fname, data->pool);
+}
+
+/*
+ * The reason we need the above cleanup is because on Windows, APR_DELONCLOSE
+ * forces applications to open the file with FILE_SHARED_DELETE
+ * set, which is, unfortunately, a property that is preserved
+ * across NTFS "hard" links.  This breaks apps that link() the temp
+ * file to a permanent location, and subsequently expect to open it
+ * before the original tempfile is closed+deleted. In fact, even
+ * Apache::Upload does this, so it is a common enough event that the
+ * apreq_file_cleanup workaround is necessary.
+ */
+
+APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
+                                              apr_pool_t *pool,
+                                              const char *path)
+{
+    apr_status_t rc;
+    char *tmpl;
+    struct cleanup_data *data;
+
+    if (path == NULL) {
+        rc = apr_temp_dir_get(&path, pool);
+        if (rc != APR_SUCCESS)
+            return rc;
+    }
+    rc = apr_filepath_merge(&tmpl, path, "apreqXXXXXX",
+                            APR_FILEPATH_NOTRELATIVE, pool);
+
+    if (rc != APR_SUCCESS)
+        return rc;
+
+    data = apr_palloc(pool, sizeof *data);
+    /* cleanups are LIFO, so this one will run just after
+       the cleanup set by mktemp */
+    apr_pool_cleanup_register(pool, data,
+                              apreq_file_cleanup, apreq_file_cleanup);
+
+    rc = apr_file_mktemp(fp, tmpl, /* NO APR_DELONCLOSE! see comment above */
+                           APR_CREATE | APR_READ | APR_WRITE
+                           | APR_EXCL | APR_BINARY, pool);
+
+    if (rc == APR_SUCCESS) {
+        apr_file_name_get(&data->fname, *fp);
+        data->pool = pool;
+    }
+    else {
+        apr_pool_cleanup_kill(pool, data, apreq_file_cleanup);
+    }
+
+    return rc;
+}
+
+
+/*
+ * is_2616_token() is the verbatim definition from section 2.2
+ * in the rfc itself.  We try to optimize it around the
+ * expectation that the argument is not a token, which
+ * should be the typical usage.
+ */
+
+static APR_INLINE
+unsigned is_2616_token(const char c) {
+    switch (c) {
+    case ' ': case ';': case ',': case '"': case '\t':
+        /* The chars we are expecting are listed above;
+           the chars below are just for completeness. */
+    case '?': case '=': case '@': case ':': case '\\': case '/':
+    case '(': case ')':
+    case '<': case '>':
+    case '{': case '}':
+    case '[': case ']':
+        return 0;
+    default:
+        if (apr_iscntrl(c))
+            return 0;
+    }
+    return 1;
+}
+
+APREQ_DECLARE(apr_status_t)
+    apreq_header_attribute(const char *hdr,
+                           const char *name, const apr_size_t nlen,
+                           const char **val, apr_size_t *vlen)
+{
+    const char *key, *v;
+
+    /* Must ensure first char isn't '=', so we can safely backstep. */
+    while (*hdr == '=')
+        ++hdr;
+
+    while ((key = strchr(hdr, '=')) != NULL) {
+
+        v = key + 1;
+        --key;
+
+        while (apr_isspace(*key) && key > hdr + nlen)
+            --key;
+
+        key -= nlen - 1;
+
+        while (apr_isspace(*v))
+            ++v;
+
+        if (*v == '"') {
+            ++v;
+            *val = v;
+
+        look_for_end_quote:
+            switch (*v) {
+            case '"':
+                break;
+            case 0:
+                return APREQ_ERROR_BADSEQ;
+            case '\\':
+                if (v[1] != 0)
+                    ++v;
+            default:
+                ++v;
+                goto look_for_end_quote;
+            }
+        }
+        else {
+            *val = v;
+
+        look_for_terminator:
+            switch (*v) {
+            case 0:
+            case ' ':
+            case ';':
+            case ',':
+            case '\t':
+            case '\r':
+            case '\n':
+                break;
+            default:
+                ++v;
+                goto look_for_terminator;
+            }
+        }
+
+        if (key >= hdr && strncasecmp(key, name, nlen) == 0) {
+            *vlen = v - *val;
+            if (key == hdr || ! is_2616_token(key[-1]))
+                return APR_SUCCESS;
+        }
+        hdr = v;
+    }
+
+    return APREQ_ERROR_NOATTR;
+}
+
+
+
+#define BUCKET_IS_SPOOL(e) ((e)->type == &spool_bucket_type)
+#define FILE_BUCKET_LIMIT      ((apr_size_t)-1 - 1)
+
+static
+void spool_bucket_destroy(void *data)
+{
+    apr_bucket_type_file.destroy(data);
+}
+
+static
+apr_status_t spool_bucket_read(apr_bucket *e, const char **str,
+                                   apr_size_t *len, apr_read_type_e block)
+{
+    return apr_bucket_type_file.read(e, str, len, block);
+}
+
+static
+apr_status_t spool_bucket_setaside(apr_bucket *data, apr_pool_t *reqpool)
+{
+    return apr_bucket_type_file.setaside(data, reqpool);
+}
+
+static
+apr_status_t spool_bucket_split(apr_bucket *a, apr_size_t point)
+{
+    apr_status_t rv = apr_bucket_shared_split(a, point);
+    a->type = &apr_bucket_type_file;
+    return rv;
+}
+
+static
+apr_status_t spool_bucket_copy(apr_bucket *e, apr_bucket **c)
+{
+    apr_status_t rv = apr_bucket_shared_copy(e, c);
+    (*c)->type = &apr_bucket_type_file;
+    return rv;
+}
+
+static const apr_bucket_type_t spool_bucket_type = {
+    "APREQ_SPOOL", 5, APR_BUCKET_DATA,
+    spool_bucket_destroy,
+    spool_bucket_read,
+    spool_bucket_setaside,
+    spool_bucket_split,
+    spool_bucket_copy,
+};
+
+APREQ_DECLARE(apr_file_t *)apreq_brigade_spoolfile(apr_bucket_brigade *bb)
+{
+    apr_bucket *last;
+
+    last = APR_BRIGADE_LAST(bb);
+    if (BUCKET_IS_SPOOL(last))
+        return ((apr_bucket_file *)last->data)->fd;
+
+    return NULL;
+}
+
+APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
+                                                 const char *temp_dir,
+                                                 apr_size_t heap_limit,
+                                                 apr_bucket_brigade *out,
+                                                 apr_bucket_brigade *in)
+{
+    apr_status_t s;
+    apr_bucket_file *f;
+    apr_off_t wlen;
+    apr_file_t *file;
+    apr_off_t in_len, out_len;
+    apr_bucket *last_in, *last_out;
+
+    last_out = APR_BRIGADE_LAST(out);
+
+    if (APR_BUCKET_IS_EOS(last_out))
+        return APR_EOF;
+
+    s = apr_brigade_length(out, 0, &out_len);
+    if (s != APR_SUCCESS)
+        return s;
+
+    /* This cast, when out_len = -1, is intentional */
+    if ((apr_uint64_t)out_len < heap_limit) {
+
+        s = apr_brigade_length(in, 0, &in_len);
+        if (s != APR_SUCCESS)
+            return s;
+
+        /* This cast, when in_len = -1, is intentional */
+        if ((apr_uint64_t)in_len < heap_limit - (apr_uint64_t)out_len) {
+            APR_BRIGADE_CONCAT(out, in);
+            return APR_SUCCESS;
+        }
+    }
+
+    if (!BUCKET_IS_SPOOL(last_out)) {
+
+        s = apreq_file_mktemp(&file, pool, temp_dir);
+        if (s != APR_SUCCESS)
+            return s;
+
+        s = apreq_brigade_fwrite(file, &wlen, out);
+
+        if (s != APR_SUCCESS)
+            return s;
+
+        last_out = apr_bucket_file_create(file, wlen, 0,
+                                          out->p, out->bucket_alloc);
+        last_out->type = &spool_bucket_type;
+        APR_BRIGADE_INSERT_TAIL(out, last_out);
+        f = last_out->data;
+    }
+    else {
+        f = last_out->data;
+        /* Need to seek here, just in case our spool bucket
+         * was read from between apreq_brigade_concat calls.
+         */
+        wlen = last_out->start + last_out->length;
+        s = apr_file_seek(f->fd, APR_SET, &wlen);
+        if (s != APR_SUCCESS)
+            return s;
+    }
+
+    if (in == out)
+        return APR_SUCCESS;
+
+    last_in = APR_BRIGADE_LAST(in);
+
+    if (APR_BUCKET_IS_EOS(last_in))
+        APR_BUCKET_REMOVE(last_in);
+
+    s = apreq_brigade_fwrite(f->fd, &wlen, in);
+
+    if (s == APR_SUCCESS) {
+
+        /* We have to deal with the possibility that the new
+         * data may be too large to be represented by a single
+         * temp_file bucket.
+         */
+
+        while ((apr_uint64_t)wlen > FILE_BUCKET_LIMIT - last_out->length) {
+            apr_bucket *e;
+
+            apr_bucket_copy(last_out, &e);
+            e->length = 0;
+            e->start = last_out->start + FILE_BUCKET_LIMIT;
+            wlen -= FILE_BUCKET_LIMIT - last_out->length;
+            last_out->length = FILE_BUCKET_LIMIT;
+
+            /* Copying makes the bucket types exactly the
+             * opposite of what we need here.
+             */
+            last_out->type = &apr_bucket_type_file;
+            e->type = &spool_bucket_type;
+
+            APR_BRIGADE_INSERT_TAIL(out, e);
+            last_out = e;
+        }
+
+        last_out->length += wlen;
+
+        if (APR_BUCKET_IS_EOS(last_in))
+            APR_BRIGADE_INSERT_TAIL(out, last_in);
+
+    }
+    else if (APR_BUCKET_IS_EOS(last_in))
+        APR_BRIGADE_INSERT_TAIL(in, last_in);
+
+    apr_brigade_cleanup(in);
+    return s;
+}
+

Propchange: httpd/apreq/branches/apr-build-system/library/util.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/apreq/branches/apr-build-system/library/version.c
URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/version.c?rev=380784&view=auto
==============================================================================
--- httpd/apreq/branches/apr-build-system/library/version.c (added)
+++ httpd/apreq/branches/apr-build-system/library/version.c Fri Feb 24 10:56:34 2006
@@ -0,0 +1,35 @@
+/*
+**  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 "apreq_version.h"
+#include "apr_general.h" /* for APR_STRINGIFY */
+
+APREQ_DECLARE(void) apreq_version(apr_version_t *pvsn)
+{
+    pvsn->major = APREQ_MAJOR_VERSION;
+    pvsn->minor = APREQ_MINOR_VERSION;
+    pvsn->patch = APREQ_PATCH_VERSION;
+#ifdef APREQ_IS_DEV_VERSION
+    pvsn->is_dev = 1;
+#else
+    pvsn->is_dev = 0;
+#endif
+}
+
+APREQ_DECLARE(const char *) apreq_version_string(void)
+{
+    return APREQ_VERSION_STRING;
+}

Propchange: httpd/apreq/branches/apr-build-system/library/version.c
------------------------------------------------------------------------------
    svn:eol-style = native