summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/apreq/Makefile.in0
-rw-r--r--modules/apreq/apreq_private_apache2.h56
-rw-r--r--modules/apreq/config.m40
-rw-r--r--modules/apreq/filter.c540
-rw-r--r--modules/apreq/handle.c439
-rw-r--r--modules/apreq/mod_apreq2.h0
-rw-r--r--srclib/libapreq/Makefile.in94
-rw-r--r--srclib/libapreq/STATUS35
-rw-r--r--srclib/libapreq/apreq2-config.in218
-rw-r--r--srclib/libapreq/build.conf19
-rw-r--r--srclib/libapreq/build/apreq-conf.m472
-rw-r--r--srclib/libapreq/build/apreq-hints.m461
-rw-r--r--srclib/libapreq/build/find_apreq.m4176
-rwxr-xr-xsrclib/libapreq/build/get-version.sh39
-rwxr-xr-xsrclib/libapreq/buildconf106
-rw-r--r--srclib/libapreq/config.layout232
-rw-r--r--srclib/libapreq/configure.in173
-rw-r--r--srclib/libapreq/export_vars.sh.in13
-rw-r--r--srclib/libapreq/include/apreq.h295
-rw-r--r--srclib/libapreq/include/apreq_cookie.h216
-rw-r--r--srclib/libapreq/include/apreq_error.h97
-rw-r--r--srclib/libapreq/include/apreq_module.h457
-rw-r--r--srclib/libapreq/include/apreq_param.h209
-rw-r--r--srclib/libapreq/include/apreq_parser.h287
-rw-r--r--srclib/libapreq/include/apreq_util.h443
-rw-r--r--srclib/libapreq/include/apreq_version.h105
-rw-r--r--srclib/libapreq/library/cookie.c662
-rw-r--r--srclib/libapreq/library/error.c198
-rw-r--r--srclib/libapreq/library/module.c65
-rw-r--r--srclib/libapreq/library/module_cgi.c689
-rw-r--r--srclib/libapreq/library/module_custom.c304
-rw-r--r--srclib/libapreq/library/param.c272
-rw-r--r--srclib/libapreq/library/parser.c353
-rw-r--r--srclib/libapreq/library/parser_header.c365
-rw-r--r--srclib/libapreq/library/parser_multipart.c661
-rw-r--r--srclib/libapreq/library/parser_urlencoded.c275
-rw-r--r--srclib/libapreq/library/util.c1508
-rw-r--r--srclib/libapreq/library/version.c105
38 files changed, 9839 insertions, 0 deletions
diff --git a/modules/apreq/Makefile.in b/modules/apreq/Makefile.in
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/modules/apreq/Makefile.in
diff --git a/modules/apreq/apreq_private_apache2.h b/modules/apreq/apreq_private_apache2.h
new file mode 100644
index 0000000000..173060dc48
--- /dev/null
+++ b/modules/apreq/apreq_private_apache2.h
@@ -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;
+ }
+}
diff --git a/modules/apreq/config.m4 b/modules/apreq/config.m4
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/modules/apreq/config.m4
diff --git a/modules/apreq/filter.c b/modules/apreq/filter.c
new file mode 100644
index 0000000000..6c75a51b48
--- /dev/null
+++ b/modules/apreq/filter.c
@@ -0,0 +1,540 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+}
+
diff --git a/modules/apreq/handle.c b/modules/apreq/handle.c
new file mode 100644
index 0000000000..859710c9ea
--- /dev/null
+++ b/modules/apreq/handle.c
@@ -0,0 +1,439 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+ h->ctx = (void *)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;
+
+}
diff --git a/modules/apreq/mod_apreq2.h b/modules/apreq/mod_apreq2.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/modules/apreq/mod_apreq2.h
diff --git a/srclib/libapreq/Makefile.in b/srclib/libapreq/Makefile.in
new file mode 100644
index 0000000000..b86e9f3680
--- /dev/null
+++ b/srclib/libapreq/Makefile.in
@@ -0,0 +1,94 @@
+#
+# Top-level Makefile for APREQ
+#
+CPP = @CPP@
+
+# gets substituted into some targets
+APREQ_MAJOR_VERSION=@APREQ_MAJOR_VERSION@
+APREQ_MINOR_VERSION=@APREQ_MINOR_VERSION@
+APREQ_PATCH_VERSION=@APREQ_PATCH_VERSION@
+APREQ_DOTTED_VERSION=@APREQ_DOTTED_VERSION@
+APREQ_LIBTOOL_VERSION=@APREQ_LIBTOOL_VERSION@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+INCLUDES = @APREQ_INCLUDES@ @APREQ_PRIV_INCLUDES@ @APR_INCLUDES@
+APREQ_LDFLAGS = @APREQ_LDFLAGS@
+APREQ_LIBS = @APREQ_LIBS@
+
+TARGET_LIB = lib@APREQ_LIBNAME@.la
+INSTALL_SUBDIRS =
+EXTRA_SOURCE_DIRS =
+APRUTIL_PCFILE = apr-util-$(APRUTIL_MAJOR_VERSION).pc
+APREQ_CONFIG = apreq2-config
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+TARGETS = $(TARGET_LIB) apreq.exp
+
+# bring in rules.mk for standard functionality
+@INCLUDE_RULES@
+@INCLUDE_OUTPUTS@
+
+LINK = $(LIBTOOL) $(LTFLAGS) --mode=link $(LT_LDFLAGS) $(COMPILE) -version-info $(APREQ_LIBTOOL_VERSION) $(ALL_LDFLAGS) -o $@
+
+CLEAN_SUBDIRS = test
+
+CLEAN_TARGETS = exports.c export_vars.c apreq.exp .make.dirs apreq2-config.out
+DISTCLEAN_TARGETS = config.cache config.log config.status libtool \
+ export_vars.sh $(APREQ_CONFIG) build/rules.mk \
+ apr-util.pc build/pkg/pkginfo
+EXTRACLEAN_TARGETS = configure aclocal.m4 \
+ exports.c build-outputs.mk \
+ build/apr_common.m4 build/find_apr.m4 build/install.sh \
+ build/config.guess build/config.sub
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+includedir=@includedir@
+top_srcdir=@abs_srcdir@
+top_blddir=@abs_builddir@
+
+# Create apu-config script suitable for the install tree
+apreq2-config.out: $(APREQ_CONFIG)
+ sed 's,^\(location=\).*$$,\1installed,' < $(APREQ_CONFIG) > $@
+
+install: $(TARGET_LIB) apreq2-config.out
+ $(APR_MKDIR) $(DESTDIR)$(includedir) $(DESTDIR)$(libdir)/pkgconfig \
+ $(DESTDIR)$(libdir) $(DESTDIR)$(bindir)
+ for f in $(top_srcdir)/include/*.h $(top_blddir)/include/*.h; do \
+ $(INSTALL_DATA) $${f} $(DESTDIR)$(includedir); \
+ done
+ echo $(INSTALL_DATA) apr-util.pc $(DESTDIR)$(libdir)/pkgconfig/$(APRUTIL_PCFILE)
+ list='$(INSTALL_SUBDIRS)'; for i in $$list; do \
+ ( cd $$i ; $(MAKE) DESTDIR=$(DESTDIR) install ); \
+ done
+ $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(TARGET_LIB) $(DESTDIR)$(libdir)
+ $(INSTALL_DATA) apreq.exp $(DESTDIR)$(libdir)
+ $(INSTALL) -m 755 apreq2-config.out $(DESTDIR)$(bindir)/$(APREQ_CONFIG)
+
+$(TARGET_LIB): $(OBJECTS)
+ $(LINK) @lib_target@ $(ALL_LIBS) $(APREQ_LDFLAGS) $(APREQ_LIBS)
+
+exports.c: $(HEADERS)
+ $(APR_MKEXPORT) $(HEADERS) > $@
+
+export_vars.c: $(HEADERS)
+ $(APR_MKVAREXPORT) $(HEADERS) > $@
+
+apreq.exp: exports.c export_vars.c
+ @echo "#! lib@APREQ_LIBNAME@.so" > $@
+ @echo "* This file was AUTOGENERATED at build time." >> $@
+ @echo "* Please do not edit by hand." >> $@
+ $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | sed -e 's/^.*[)]\(.*\);$$/\1/' >> $@
+ $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.c | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' >> $@
+
+dox:
+ doxygen $(top_srcdir)/docs/doxygen.conf
+
+test: check
+check: $(TARGET_LIB)
+ cd test && $(MAKE) check
diff --git a/srclib/libapreq/STATUS b/srclib/libapreq/STATUS
new file mode 100644
index 0000000000..5f934989ee
--- /dev/null
+++ b/srclib/libapreq/STATUS
@@ -0,0 +1,35 @@
+/** @page apreq_status STATUS
+
+ 2.08 under development.
+
+Contributors looking for a mission:
+
+ - just do an egrep on "TODO" or "XXX" and see what's there
+
+
+CURRENT RELEASE NOTES:
+
+
+RELEASE SHOWSTOPPERS:
+
+
+
+CURRENT VOTES:
+
+
+TODO:
+
+ apreq2-config doesn't install correctly.
+ mod_apreq2 doesn't even build.
+
+
+OPEN ISSUES:
+
+
+BUGS:
+
+
+WISH LIST:
+
+
+*/
diff --git a/srclib/libapreq/apreq2-config.in b/srclib/libapreq/apreq2-config.in
new file mode 100644
index 0000000000..bfc8e7d22c
--- /dev/null
+++ b/srclib/libapreq/apreq2-config.in
@@ -0,0 +1,218 @@
+#!/bin/sh
+
+##
+## 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.
+##
+
+# apreq2-config- based on apu-config:
+# APR-util script designed to allow easy command line access to APR-util
+# configuration parameters.
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+bindir="@bindir@"
+libdir="@libdir@"
+includedir="@includedir@"
+
+LIBS="@APREQ_LIBS@"
+LDFLAGS="@APREQ_LDFLAGS@"
+INCLUDES="@APREQ_INCLUDES@"
+
+APREQ_LIBNAME="@APREQ_LIBNAME@"
+
+APREQ_SOURCE_DIR="@abs_srcdir@"
+APREQ_BUILD_DIR="@abs_builddir@"
+
+show_usage()
+{
+ cat << EOF
+Usage: apreq2-config [OPTION]
+
+Known values for OPTION are:
+ --prefix[=DIR] change prefix to DIR
+ --bindir print location where binaries are installed
+ --includes print include information
+ --includedir print location where headers are installed
+ --ldflags print linker flags
+ --libs print library information
+ --srcdir print apreq2 source directory
+ --link-ld print link switch(es) for linking to libapreq2
+ --link-libtool print the libtool inputs for linking to libapreq2
+ --la-file print the path to the library's .la file, if available
+ --library-version print the API version as a dotted triple
+ --libtool-version print the ABI version in a libtool-compatible format
+ --package-version print the version number of the distribution
+ --help print this help
+
+When linking with libtool, an application should do something like:
+ APREQ_LIBS="\`apreq2-config --link-libtool --libs\`"
+or when linking directly:
+ APREQ_LIBS="\`apreq2-config --link-ld --ldflags --libs\`"
+
+An application should use the results of --includes, and --ldflags in
+their build process.
+EOF
+}
+
+if test $# -eq 0; then
+ show_usage
+ exit 1
+fi
+
+thisdir="`dirname $0`"
+thisdir="`cd $thisdir && pwd`"
+if test -d $bindir; then
+ tmpbindir="`cd $bindir && pwd`"
+else
+ tmpbindir=""
+fi
+# If we have the realpath program, use it to resolve symlinks.
+# Otherwise, being in a symlinked dir may result in incorrect output.
+if test -x "`which realpath 2>/dev/null`"; then
+ thisdir="`realpath $thisdir`"
+ if test -d "$APREQ_SOURCE_DIR"; then
+ APREQ_SOURCE_DIR="`realpath $APREQ_SOURCE_DIR`"
+ fi
+ if test -n "$tmpbindir"; then
+ tmpbindir="`realpath $tmpbindir`"
+ fi
+fi
+if test "$tmpbindir" = "$thisdir"; then
+ location=installed
+elif test "$APREQ_SOURCE_DIR" = "$thisdir"; then
+ location=source
+else
+ location=build
+fi
+
+
+if test "$location" = "installed"; then
+ LA_FILE="$libdir/lib${APREQ_LIBNAME}.la"
+else
+ LA_FILE="$thisdir/lib${APREQ_LIBNAME}.la"
+fi
+
+flags=""
+
+while test $# -gt 0; do
+ # Normalize the prefix.
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case "$1" in
+ # It is possible for the user to override our prefix.
+ --prefix=*)
+ prefix=$optarg
+ ;;
+ --prefix)
+ echo $prefix
+ exit 0
+ ;;
+ --bindir)
+ echo $bindir
+ exit 0
+ ;;
+ --libs)
+ flags="$flags $LIBS"
+ ;;
+ --includedir)
+ if test "$location" = "installed"; then
+ flags="$includedir"
+ elif test "$location" = "source"; then
+ flags="$APREQ_SOURCE_DIR/include"
+ else
+ # this is for VPATH builds
+ flags="$thisdir/include $APREQ_SOURCE_DIR/include"
+ fi
+ echo $flags
+ exit 0
+ ;;
+ --includes)
+ if test "$location" = "installed"; then
+ flags="$flags -I$includedir $INCLUDES"
+ elif test "$location" = "source"; then
+ flags="$flags -I$APREQ_SOURCE_DIR/include $INCLUDES"
+ else
+ # this is for VPATH builds
+ flags="$flags -I$thisdir/include -I$APREQ_SOURCE_DIR/include $INCLUDES"
+ fi
+ ;;
+ --ldflags)
+ flags="$flags $LDFLAGS"
+ ;;
+ --srcdir)
+ echo $APREQ_SOURCE_DIR
+ exit 0
+ ;;
+ --library-version)
+ echo @APREQ_DOTTED_VERSION@
+ exit 0
+ ;;
+ --libtool-version)
+ echo @APREQ_LIBTOOL_VERSION@
+ exit 0
+ ;;
+ --package-version)
+ echo "@VERSION@"
+ exit 0
+ ;;
+ --link-ld)
+ if test "$location" = "installed"; then
+ ### avoid using -L if libdir is a "standard" location like /usr/lib
+ flags="$flags -L$libdir -l$APREQ_LIBNAME"
+ else
+ flags="$flags -L$thisdir/library/.libs -l$APREQ_LIBNAME"
+ fi
+ ;;
+ --link-libtool)
+ # If the LA_FILE exists where we think it should be, use it. If we're
+ # installed and the LA_FILE does not exist, assume to use -L/-l
+ # (the LA_FILE may not have been installed). If we're building ourselves,
+ # we'll assume that at some point the .la file be created.
+ if test -f "$LA_FILE"; then
+ flags="$flags $LA_FILE"
+ elif test "$location" = "installed"; then
+ ### avoid using -L if libdir is a "standard" location like /usr/lib
+ flags="$flags -L$libdir -l$APREQ_LIBNAME $apreq_libs"
+ else
+ flags="$flags $LA_FILE"
+ fi
+ ;;
+ --la-file)
+ if test -f "$LA_FILE"; then
+ flags="$flags $LA_FILE"
+ fi
+ ;;
+ --help)
+ show_usage
+ exit 0
+ ;;
+ *)
+ show_usage
+ exit 1
+ ;;
+ esac
+
+ # Next please.
+ shift
+done
+
+if test -n "$flags"; then
+ echo "$flags"
+fi
+
+exit 0
diff --git a/srclib/libapreq/build.conf b/srclib/libapreq/build.conf
new file mode 100644
index 0000000000..5f0603cfe8
--- /dev/null
+++ b/srclib/libapreq/build.conf
@@ -0,0 +1,19 @@
+#
+# Configuration file for APREQ. Used by APR/build/gen-build.py
+#
+
+[options]
+
+# the platform-independent .c files
+paths =
+ library/*.c
+# we have no platform-specific subdirs
+platform_dirs =
+
+# the public headers
+headers = include/*.h
+
+# gen_uri_delim.c
+
+# we have a recursive makefile for the test files (for now)
+# test/*.c
diff --git a/srclib/libapreq/build/apreq-conf.m4 b/srclib/libapreq/build/apreq-conf.m4
new file mode 100644
index 0000000000..a2ec6758a2
--- /dev/null
+++ b/srclib/libapreq/build/apreq-conf.m4
@@ -0,0 +1,72 @@
+dnl -------------------------------------------------------- -*- autoconf -*-
+dnl Copyright 2000-2005 The Apache Software Foundation or its licensors, as
+dnl applicable.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+
+dnl
+dnl custom autoconf rules for APRUTIL
+dnl
+
+dnl
+dnl APU_FIND_APR: figure out where APR is located
+dnl
+AC_DEFUN([APREQ_FIND_APR], [
+
+ dnl use the find_apr.m4 script to locate APR. sets apr_found and apr_config
+ APR_FIND_APR(,,,[1])
+ if test "$apr_found" = "no"; then
+ AC_MSG_ERROR(APR could not be located. Please use the --with-apr option.)
+ fi
+
+ APR_BUILD_DIR="`$apr_config --installbuilddir`"
+
+ dnl make APR_BUILD_DIR an absolute directory (we'll need it in the
+ dnl sub-projects in some cases)
+ APR_BUILD_DIR="`cd $APR_BUILD_DIR && pwd`"
+
+ APR_INCLUDES="`$apr_config --includes`"
+ APR_LIBS="`$apr_config --link-libtool --libs`"
+ APR_SO_EXT="`$apr_config --apr-so-ext`"
+ APR_LIB_TARGET="`$apr_config --apr-lib-target`"
+
+ AC_SUBST(APR_INCLUDES)
+ AC_SUBST(APR_LIBS)
+ AC_SUBST(APR_BUILD_DIR)
+])
+
+
+AC_DEFUN([APREQ_FIND_APU], [
+
+ dnl use the find_apr.m4 script to locate APR. sets apr_found and apu_config
+ APR_FIND_APU(,,,[1])
+ if test "$apu_found" = "no"; then
+ AC_MSG_ERROR(APR could not be located. Please use the --with-apr-util option.)
+ fi
+
+ APU_BUILD_DIR="`$apu_config --installbuilddir`"
+
+ dnl make APR_BUILD_DIR an absolute directory (we'll need it in the
+ dnl sub-projects in some cases)
+ APU_BUILD_DIR="`cd $APR_BUILD_DIR && pwd`"
+
+ APU_INCLUDES="`$apu_config --includes`"
+ APU_LIBS="`$apu_config --link-libtool --libs`"
+
+ AC_SUBST(APU_INCLUDES)
+ AC_SUBST(APU_LIBS)
+ AC_SUBST(APU_BUILD_DIR)
+])
+
+
diff --git a/srclib/libapreq/build/apreq-hints.m4 b/srclib/libapreq/build/apreq-hints.m4
new file mode 100644
index 0000000000..33a5d22d3b
--- /dev/null
+++ b/srclib/libapreq/build/apreq-hints.m4
@@ -0,0 +1,61 @@
+dnl -------------------------------------------------------- -*- autoconf -*-
+dnl Copyright 2003-2005 The Apache Software Foundation or its licensors, as
+dnl applicable.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+dnl -----------------------------------------------------------------
+dnl apu-hints.m4: apr-util's autoconf macros for platform-specific hints
+dnl
+dnl We preload various configure settings depending
+dnl on previously obtained platform knowledge.
+dnl We allow all settings to be overridden from
+dnl the command-line.
+
+dnl
+dnl APU_PRELOAD
+dnl
+dnl Preload various build parameters based on outside knowledge.
+dnl
+AC_DEFUN([APREQ_PRELOAD], [
+if test "x$apreq_preload_done" != "xyes" ; then
+ apreq_preload_done="yes"
+
+ echo "Applying apr-util hints file rules for $host"
+
+ case "$host" in
+ *-dec-osf*)
+ APR_SETIFNULL(apreq_crypt_threadsafe, [1])
+ ;;
+ *-hp-hpux11.*)
+ APR_SETIFNULL(apreq_crypt_threadsafe, [1])
+ ;;
+ *-ibm-aix4*|*-ibm-aix5.1*)
+ APR_SETIFNULL(apreq_iconv_inbuf_const, [1])
+ ;;
+ *-ibm-os390)
+ APR_SETIFNULL(apreq_crypt_threadsafe, [1])
+ ;;
+ *-solaris2*)
+ APR_SETIFNULL(apreq_iconv_inbuf_const, [1])
+ APR_SETIFNULL(apreq_crypt_threadsafe, [1])
+ ;;
+ *-sco3.2v5*)
+ APR_SETIFNULL(apreq_db_xtra_libs, [-lsocket])
+ ;;
+ esac
+
+fi
+])
+
+
diff --git a/srclib/libapreq/build/find_apreq.m4 b/srclib/libapreq/build/find_apreq.m4
new file mode 100644
index 0000000000..ed69397ece
--- /dev/null
+++ b/srclib/libapreq/build/find_apreq.m4
@@ -0,0 +1,176 @@
+dnl -------------------------------------------------------- -*- autoconf -*-
+dnl Copyright 2002-2006 The Apache Software Foundation or its licensors, as
+dnl applicable.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+dnl
+dnl find_apu.m4 : locate the APR-util (APU) include files and libraries
+dnl
+dnl This macro file can be used by applications to find and use the APU
+dnl library. It provides a standardized mechanism for using APU. It supports
+dnl embedding APU into the application source, or locating an installed
+dnl copy of APU.
+dnl
+dnl APR_FIND_APU(srcdir, builddir, implicit-install-check, acceptable-majors)
+dnl
+dnl where srcdir is the location of the bundled APU source directory, or
+dnl empty if source is not bundled.
+dnl
+dnl where builddir is the location where the bundled APU will be built,
+dnl or empty if the build will occur in the srcdir.
+dnl
+dnl where implicit-install-check set to 1 indicates if there is no
+dnl --with-apr-util option specified, we will look for installed copies.
+dnl
+dnl where acceptable-majors is a space separated list of acceptable major
+dnl version numbers. Often only a single major version will be acceptable.
+dnl If multiple versions are specified, and --with-apr-util=PREFIX or the
+dnl implicit installed search are used, then the first (leftmost) version
+dnl in the list that is found will be used. Currently defaults to [0 1].
+dnl
+dnl Sets the following variables on exit:
+dnl
+dnl apu_found : "yes", "no", "reconfig"
+dnl
+dnl apu_config : If the apu-config tool exists, this refers to it. If
+dnl apu_found is "reconfig", then the bundled directory
+dnl should be reconfigured *before* using apu_config.
+dnl
+dnl Note: this macro file assumes that apr-config has been installed; it
+dnl is normally considered a required part of an APR installation.
+dnl
+dnl Note: At this time, we cannot find *both* a source dir and a build dir.
+dnl If both are available, the build directory should be passed to
+dnl the --with-apr-util switch.
+dnl
+dnl Note: the installation layout is presumed to follow the standard
+dnl PREFIX/lib and PREFIX/include pattern. If the APU config file
+dnl is available (and can be found), then non-standard layouts are
+dnl possible, since it will be described in the config file.
+dnl
+dnl If a bundled source directory is available and needs to be (re)configured,
+dnl then apu_found is set to "reconfig". The caller should reconfigure the
+dnl (passed-in) source directory, placing the result in the build directory,
+dnl as appropriate.
+dnl
+dnl If apu_found is "yes" or "reconfig", then the caller should use the
+dnl value of apu_config to fetch any necessary build/link information.
+dnl
+
+AC_DEFUN([APR_FIND_APREQ], [
+ apreq_found="no"
+
+ if test "$target_os" = "os2-emx"; then
+ # Scripts don't pass test -x on OS/2
+ TEST_X="test -f"
+ else
+ TEST_X="test -x"
+ fi
+
+ ifelse([$4], [],
+ [
+ ifdef(AC_WARNING,([$0: missing argument 4 (acceptable-majors): Defaulting to APREQ 0.x then APREQ 1.x]))
+ acceptable_majors="0 1"
+ ], [acceptable_majors="$4"])
+
+ apreq_temp_acceptable_apreq_config=""
+ for apreq_temp_major in $acceptable_majors
+ do
+ case $apreq_temp_major in
+ 0)
+ apreq_temp_acceptable_apreq_config="$apreq_temp_acceptable_apreq_config apreq-config"
+ ;;
+ *)
+ apreq_temp_acceptable_apreq_config="$apreq_temp_acceptable_apreq_config apreq$apreq_temp_major-config"
+ ;;
+ esac
+ done
+
+ AC_MSG_CHECKING(for APREQ)
+ AC_ARG_WITH(apreq,
+ [ --with-apreq=PATH prefix for installed APREQ, path to APREQ build tree,
+ or the full path to apreq-config],
+ [
+ if test "$withval" = "no" || test "$withval" = "yes"; then
+ AC_MSG_ERROR([--with-apreq requires a directory or file to be provided])
+ fi
+
+ for apreq_temp_apreq_config_file in $apreq_temp_acceptable_apreq_config
+ do
+ for lookdir in "$withval/bin" "$withval"
+ do
+ if $TEST_X "$lookdir/$apreq_temp_apreq_config_file"; then
+ apreq_found="yes"
+ apreq_config="$lookdir/$apreq_temp_apreq_config_file"
+ break 2
+ fi
+ done
+ done
+
+ if test "$apreq_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
+ apreq_found="yes"
+ apreq_config="$withval"
+ fi
+
+ dnl if --with-apreq is used, it is a fatal error for its argument
+ dnl to be invalid
+ if test "$apreq_found" != "yes"; then
+ AC_MSG_ERROR([the --with-apreq parameter is incorrect. It must specify an install prefix, a build directory, or an apreq-config file.])
+ fi
+ ],[
+ if test -n "$3" && test "$3" = "1"; then
+ for apreq_temp_apreq_config_file in $apreq_temp_acceptable_apreq_config
+ do
+ if $apreq_temp_apreq_config_file --help > /dev/null 2>&1 ; then
+ apreq_found="yes"
+ apreq_config="$apreq_temp_apreq_config_file"
+ break
+ else
+ dnl look in some standard places (apparently not in builtin/default)
+ for lookdir in /usr /usr/local /usr/local/apr /opt/apr /usr/local/apache2 ; do
+ if $TEST_X "$lookdir/bin/$apreq_temp_apreq_config_file"; then
+ apreq_found="yes"
+ apreq_config="$lookdir/bin/$apreq_temp_apreq_config_file"
+ break 2
+ fi
+ done
+ fi
+ done
+ fi
+ dnl if we have not found anything yet and have bundled source, use that
+ if test "$apreq_found" = "no" && test -d "$1"; then
+ apreq_temp_abs_srcdir="`cd $1 && pwd`"
+ apreq_found="reconfig"
+ apreq_bundled_major="`sed -n '/#define.*APREQ_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apreq_version.h\"`"
+ case $apreq_bundled_major in
+ "")
+ AC_MSG_ERROR([failed to find major version of bundled APREQ])
+ ;;
+ 0)
+ apreq_temp_apreq_config_file="apreq-config"
+ ;;
+ *)
+ apreq_temp_apreq_config_file="apreq$apreq_bundled_major-config"
+ ;;
+ esac
+ if test -n "$2"; then
+ apreq_config="$2/$apreq_temp_apreq_config_file"
+ else
+ apreq_config="$1/$apreq_temp_apreq_config_file"
+ fi
+ fi
+ ])
+
+ AC_MSG_RESULT($apreq_found)
+])
diff --git a/srclib/libapreq/build/get-version.sh b/srclib/libapreq/build/get-version.sh
new file mode 100755
index 0000000000..d0d9d5bff8
--- /dev/null
+++ b/srclib/libapreq/build/get-version.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# extract version numbers from a header file
+#
+# USAGE: get-version.sh CMD VERSION_HEADER PREFIX
+# where CMD is one of: all, major, libtool
+# where PREFIX is the prefix to {MAJOR|MINOR|PATCH}_VERSION defines
+#
+# get-version.sh all returns a dotted version number
+# get-version.sh major returns just the major version number
+# get-version.sh minor returns just the minor version number
+# get-version.sh patch returns just the match version number
+#
+
+if test $# != 3; then
+ echo "USAGE: $0 CMD INCLUDEDIR PREFIX"
+ echo " where CMD is one of: all, major, minor, patch"
+ exit 1
+fi
+
+major_sed="/#define.*$3_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+minor_sed="/#define.*$3_MINOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+patch_sed="/#define.*$3_PATCH_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+major="`sed -n $major_sed $2`"
+minor="`sed -n $minor_sed $2`"
+patch="`sed -n $patch_sed $2`"
+
+if test "$1" = "all"; then
+ echo ${major}.${minor}.${patch}
+elif test "$1" = "major"; then
+ echo ${major}
+elif test "$1" = "minor"; then
+ echo ${minor}
+elif test "$1" = "patch"; then
+ echo ${patch}
+else
+ echo "ERROR: unknown version CMD ($1)"
+ exit 1
+fi
diff --git a/srclib/libapreq/buildconf b/srclib/libapreq/buildconf
new file mode 100755
index 0000000000..0c2f5df1ad
--- /dev/null
+++ b/srclib/libapreq/buildconf
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright 1999-2005 The Apache Software Foundation or its licensors, as
+# applicable.
+#
+# 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.
+#
+#
+
+# Default place to look for apr source. Can be overridden with
+# --with-apr=[directory]
+apr_src_dir=../apr
+apu_src_dir=../apr-util
+
+while test $# -gt 0
+do
+ # Normalize
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case "$1" in
+ --with-apr=*)
+ apr_src_dir=$optarg
+ ;;
+ --with-apr-util=*)
+ apu_src_dir=$optarg
+ ;;
+ esac
+
+ shift
+done
+
+if [ -f "$apr_src_dir/build/apr_common.m4" ]; then
+ echo ""
+ echo "Looking for apr source in $apr_src_dir"
+else
+ echo ""
+ echo "Problem finding apr source in $apr_src_dir."
+ echo "Use:"
+ echo " --with-apr=[directory]"
+ exit 1
+fi
+
+if [ -f "$apu_src_dir/build/find_apu.m4" ]; then
+ echo ""
+ echo "Looking for apr-util source in $apu_src_dir"
+else
+ echo ""
+ echo "Problem finding apr-util source in $apu_src_dir."
+ echo "Use:"
+ echo " --with-apr-util=[directory]"
+ exit 1
+fi
+
+set -e
+
+# Remove some files, then copy them from apr source tree
+rm -f build/apr_common.m4 build/find_apr.m4 build/install.sh \
+ build/config.guess build/config.sub
+cp $apr_src_dir/build/apr_common.m4 $apr_src_dir/build/find_apr.m4 \
+ $apr_src_dir/build/install.sh $apr_src_dir/build/config.guess \
+ $apr_src_dir/build/config.sub build
+
+rm -f build/find_apu.m4
+cp $apu_src_dir/build/find_apu.m4 build
+
+
+# Remove aclocal.m4 as it'll break some builds...
+rm -rf aclocal.m4 autom4te*.cache
+
+#
+# Generate the autoconf header (include/apreq_config.h) and ./configure
+#
+echo "Creating include/apreq_config.h ..."
+${AUTOHEADER:-autoheader}
+
+echo "Creating configure ..."
+### do some work to toss config.cache?
+if ${AUTOCONF:-autoconf}; then
+ :
+else
+ echo "autoconf failed"
+ exit 1
+fi
+
+#
+# Generate build-outputs.mk for the build systme
+#
+echo "Generating 'make' outputs ..."
+$apr_src_dir/build/gen-build.py make
+
+# Remove autoconf cache again
+rm -rf autom4te*.cache
+
diff --git a/srclib/libapreq/config.layout b/srclib/libapreq/config.layout
new file mode 100644
index 0000000000..80a4c8b5f3
--- /dev/null
+++ b/srclib/libapreq/config.layout
@@ -0,0 +1,232 @@
+##
+## config.layout -- Pre-defined Installation Path Layouts
+##
+## Hints:
+## - layouts can be loaded with configure's --enable-layout=ID option
+## - when no --enable-layout option is given, the default layout is `apr'
+## - a trailing plus character (`+') on paths is replaced with a
+## `/<target>' suffix where <target> is currently hardcoded to 'apr'.
+## (This may become a configurable parameter at some point.)
+##
+
+# Classical APREQ path layout designed for parallel installs.
+<Layout apreq>
+ prefix: /usr/local/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/modules
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apreq2
+ localstatedir: ${prefix}
+ libsuffix: -${APREQ_MAJOR_VERSION}
+</Layout>
+
+# Classical single-installation APR path layout.
+<Layout classic>
+ prefix: /usr/local/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/modules
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include
+ localstatedir: ${prefix}
+</Layout>
+
+# GNU standards conforming path layout.
+# See FSF's GNU project `make-stds' document for details.
+<Layout GNU>
+ prefix: /usr/local
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/etc+
+ datadir: ${prefix}/share+
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include+
+ localstatedir: ${prefix}/var+
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# Mac OS X Server (Rhapsody)
+<Layout Mac OS X Server>
+ prefix: /Local/Library/WebServer
+ exec_prefix: /usr
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: /System/Library/apr/Modules
+ mandir: ${exec_prefix}/share/man
+ sysconfdir: ${prefix}/Configuration
+ datadir: ${prefix}
+ installbuilddir: /System/Library/apr/Build
+ includedir: /System/Library/Frameworks/apr.framework/Versions/2.0/Headers
+ localstatedir: /var
+ runtimedir: ${prefix}/Logs
+</Layout>
+
+# Darwin/Mac OS Layout
+<Layout Darwin>
+ prefix: /usr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec+
+ mandir: ${prefix}/share/man
+ datadir: /Library/WebServer
+ sysconfdir: /etc+
+ installbuilddir: ${prefix}/share/httpd/build
+ includedir: ${prefix}/include+
+ localstatedir: /var
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# Red Hat Linux 7.x layout
+<Layout RedHat>
+ prefix: /usr
+ exec_prefix: ${prefix}
+ bindir: ${prefix}/bin
+ sbindir: ${prefix}/sbin
+ libdir: ${prefix}/lib
+ libexecdir: ${prefix}/lib/apr
+ mandir: ${prefix}/man
+ sysconfdir: /etc/httpd/conf
+ datadir: /var/www
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apr
+ localstatedir: /var
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# According to the /opt filesystem conventions
+<Layout opt>
+ prefix: /opt/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${prefix}/man
+ sysconfdir: /etc${prefix}
+ datadir: ${prefix}/share
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include
+ localstatedir: /var${prefix}
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# BeOS layout...
+<Layout beos>
+ prefix: /boot/home/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include
+ localstatedir: ${prefix}
+ runtimedir: ${localstatedir}/logs
+</Layout>
+
+# SuSE 6.x layout
+<Layout SuSE>
+ prefix: /usr
+ exec_prefix: ${prefix}
+ bindir: ${prefix}/bin
+ sbindir: ${prefix}/sbin
+ libdir: ${prefix}/lib
+ libexecdir: ${prefix}/lib/apr
+ mandir: ${prefix}/share/man
+ sysconfdir: /etc/httpd
+ datadir: /usr/local/httpd
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apr
+ localstatedir: /var/lib/httpd
+ runtimedir: /var/run
+</Layout>
+
+# BSD/OS layout
+<Layout BSDI>
+ prefix: /var/www
+ exec_prefix: /usr/contrib
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec/apr
+ mandir: ${exec_prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${exec_prefix}/include/apr
+ localstatedir: /var
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# Solaris 8 Layout
+<Layout Solaris>
+ prefix: /usr/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${exec_prefix}/man
+ sysconfdir: /etc/apr
+ datadir: /var/apr
+ installbuilddir: ${datadir}/build
+ includedir: ${exec_prefix}/include
+ localstatedir: ${prefix}
+ runtimedir: /var/run
+</Layout>
+
+# OpenBSD Layout
+<Layout OpenBSD>
+ prefix: /var/www
+ exec_prefix: /usr
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/lib/apr/modules
+ mandir: ${exec_prefix}/share/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${prefix}/build
+ includedir: ${exec_prefix}/lib/apr/include
+ localstatedir: ${prefix}
+ runtimedir: ${prefix}/logs
+</Layout>
+
+# Debian layout
+<Layout Debian>
+ prefix:
+ exec_prefix: ${prefix}/usr
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/lib/apr/modules
+ mandir: ${exec_prefix}/share/man
+ datadir: ${exec_prefix}/share/apr
+ includedir: ${exec_prefix}/include/apr-${APRUTIL_MAJOR_VERSION}
+ localstatedir: ${prefix}/var/run
+ runtimedir: ${prefix}/var/run
+ infodir: ${exec_prefix}/share/info
+ libsuffix: -${APRUTIL_MAJOR_VERSION}
+ installbuilddir: ${prefix}/usr/share/apache2/build
+</Layout>
diff --git a/srclib/libapreq/configure.in b/srclib/libapreq/configure.in
new file mode 100644
index 0000000000..7d31878520
--- /dev/null
+++ b/srclib/libapreq/configure.in
@@ -0,0 +1,173 @@
+dnl
+dnl Process this file with autoconf to produce a configure script
+dnl
+
+AC_PREREQ(2.50)
+AC_INIT(export_vars.sh.in)
+
+VERSION=2.08
+AC_SUBST(VERSION)
+
+AC_CONFIG_HEADER(include/apreq_config.h)
+AC_CONFIG_AUX_DIR(build)
+
+sinclude(build/apreq-conf.m4)
+sinclude(build/apreq-hints.m4)
+sinclude(build/apr_common.m4)
+sinclude(build/find_apr.m4)
+sinclude(build/find_apu.m4)
+
+dnl Generate ./config.nice for reproducing runs of configure
+dnl
+APR_CONFIG_NICE(config.nice)
+
+dnl # Some initial steps for configuration. We setup the default directory
+dnl # and which files are to be configured.
+
+dnl Absolute source/build directory
+abs_srcdir=`(cd $srcdir && pwd)`
+abs_builddir=`pwd`
+
+if test "$abs_builddir" != "$abs_srcdir"; then
+ USE_VPATH=1
+ APREQ_CONFIG_LOCATION=build
+else
+ APREQ_CONFIG_LOCATION=source
+fi
+
+AC_SUBST(APREQ_CONFIG_LOCATION)
+
+AC_CANONICAL_SYSTEM
+
+AC_PROG_INSTALL
+
+dnl
+dnl compute the top directory of the build
+dnl note: this is needed for LIBTOOL and exporting the bundled Expat
+dnl
+top_builddir="$abs_builddir"
+AC_SUBST(top_builddir)
+AC_SUBST(abs_srcdir)
+AC_SUBST(abs_builddir)
+
+dnl Initialize mkdir -p functionality.
+APR_MKDIR_P_CHECK($abs_srcdir/build/mkdir.sh)
+
+
+dnl Enable the layout handling code, then reparse the prefix-style
+dnl arguments due to autoconf being a PITA.
+APR_ENABLE_LAYOUT(apreq)
+APR_PARSE_ARGUMENTS
+
+dnl load os-specific hints for apr-util
+APREQ_PRELOAD
+
+dnl
+dnl set up the compilation flags and stuff
+dnl
+
+APREQ_INCLUDES=""
+APREQ_PRIV_INCLUDES="-I$top_builddir/include -I$top_builddir/include/private"
+if test -n "$USE_VPATH"; then
+ APREQ_PRIV_INCLUDES="$APRUTIL_PRIV_INCLUDES -I$abs_srcdir/include/private -I$abs_srcdir/include"
+fi
+
+dnl
+dnl Find the APR includes directory and (possibly) the source (base) dir.
+dnl
+APREQ_FIND_APR
+
+dnl
+dnl even though we use apr_rules.mk for building apr-util, we need
+dnl to grab CC and CPP ahead of time so that apr-util config tests
+dnl use the same compiler as APR; we need the same compiler options
+dnl and feature test macros as well
+dnl
+APR_SETIFNULL(CC, `$apr_config --cc`)
+APR_SETIFNULL(CPP, `$apr_config --cpp`)
+APR_ADDTO(CFLAGS, `$apr_config --cflags`)
+APR_ADDTO(CPPFLAGS, `$apr_config --cppflags`)
+
+AC_SUBST(CPP)
+
+APREQ_FIND_APU
+
+dnl get our version information
+get_version="$abs_srcdir/build/get-version.sh"
+version_hdr="$abs_srcdir/include/apreq_version.h"
+APREQ_MAJOR_VERSION="`$get_version major $version_hdr APREQ`"
+APREQ_MINOR_VERSION="`$get_version minor $version_hdr APREQ`"
+APREQ_PATCH_VERSION="`$get_version patch $version_hdr APREQ`"
+APREQ_DOTTED_VERSION="`$get_version all $version_hdr APREQ`"
+
+APR_MAJOR_VERSION="`$apr_config --version | cut -f1 -d.`"
+APREQ_LIBTOOL_VERSION="`expr $APREQ_MAJOR_VERSION + $APREQ_MINOR_VERSION + $APR_MAJOR_VERSION`:$APREQ_PATCH_VERSION:$APREQ_MINOR_VERSION"
+
+AC_SUBST(APREQ_DOTTED_VERSION)
+AC_SUBST(APREQ_LIBTOOL_VERSION)
+AC_SUBST(APREQ_MAJOR_VERSION)
+AC_SUBST(APREQ_MINOR_VERSION)
+AC_SUBST(APREQ_PATCH_VERSION)
+
+echo "APREQ Version: ${APREQ_DOTTED_VERSION}"
+
+
+
+so_ext=$APR_SO_EXT
+lib_target=$APR_LIB_TARGET
+AC_SUBST(so_ext)
+AC_SUBST(lib_target)
+
+APREQ_LIBNAME="apreq2"
+AC_SUBST(APREQ_LIBNAME)
+
+dnl
+dnl Prep all the flags and stuff for compilation and export to other builds
+dnl
+APR_ADDTO(APREQ_LIBS, [$APR_LIBS])
+APR_ADDTO(APREQ_LIBS, [$APU_LIBS])
+
+AC_SUBST(APREQ_EXPORT_LIBS)
+AC_SUBST(APREQ_PRIV_INCLUDES)
+AC_SUBST(APREQ_INCLUDES)
+AC_SUBST(APREQ_LDFLAGS)
+AC_SUBST(APREQ_LIBS)
+AC_SUBST(LDFLAGS)
+
+dnl copy apr's rules.mk into our build directory.
+if test ! -d ./build; then
+ $mkdir_p build
+fi
+cp $APR_BUILD_DIR/apr_rules.mk $abs_builddir/build/rules.mk
+
+dnl
+dnl BSD/OS (BSDi) needs to use a different include syntax in the Makefiles
+dnl
+case "$host_alias" in
+*bsdi* | BSD/OS)
+ # Check whether they've installed GNU make
+ if make --version > /dev/null 2>&1; then
+ INCLUDE_RULES="include $abs_builddir/build/rules.mk"
+ INCLUDE_OUTPUTS="include $abs_srcdir/build-outputs.mk"
+ else
+ INCLUDE_RULES=".include \"$abs_builddir/build/rules.mk\""
+ INCLUDE_OUTPUTS=".include \"$abs_srcdir/build-outputs.mk\""
+ fi
+ ;;
+*)
+ INCLUDE_RULES="include $abs_builddir/build/rules.mk"
+ INCLUDE_OUTPUTS="include $abs_srcdir/build-outputs.mk"
+ ;;
+esac
+AC_SUBST(INCLUDE_RULES)
+AC_SUBST(INCLUDE_OUTPUTS)
+
+for d in include include/private; do
+ test -d $top_builddir/$d || mkdir $top_builddir/$d
+done
+
+AC_CONFIG_FILES([Makefile export_vars.sh apreq2-config])
+
+AC_CONFIG_COMMANDS([default], [chmod +x apreq2-config])
+
+AC_OUTPUT
diff --git a/srclib/libapreq/export_vars.sh.in b/srclib/libapreq/export_vars.sh.in
new file mode 100644
index 0000000000..08a6296334
--- /dev/null
+++ b/srclib/libapreq/export_vars.sh.in
@@ -0,0 +1,13 @@
+#
+# export_vars.sh
+#
+# This shell script is used to export vars to the application using the
+# APRUTIL library. This script should be "sourced" to ensure the variable
+# values are set within the calling script's context. For example:
+#
+# $ . path/to/apr-util/export_vars.sh
+#
+
+APREQ_EXPORT_INCLUDES="@APREQ_INCLUDES@"
+APREQ_EXPORT_LIBS="@APREQ_EXPORT_LIBS@"
+APREQ_LDFLAGS="@APREQ_LDFLAGS@"
diff --git a/srclib/libapreq/include/apreq.h b/srclib/libapreq/include/apreq.h
new file mode 100644
index 0000000000..aa7f0ec111
--- /dev/null
+++ b/srclib/libapreq/include/apreq.h
@@ -0,0 +1,295 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_H
+#define APREQ_H
+
+#ifdef APREQ_DEBUG
+#include <assert.h>
+#endif
+
+#include "apr_tables.h"
+#include <stddef.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * @file apreq.h
+ * @brief Main header file...
+ * @ingroup libapreq2
+ *
+ * Define the generic APREQ_ macros and common data structures.
+ */
+
+#ifndef WIN32
+/**
+ * The public APREQ functions are declared with APREQ_DECLARE(), so they may
+ * use the most appropriate calling convention. Public APR functions with
+ * variable arguments must use APR_DECLARE_NONSTD().
+ *
+ * @remark Both the declaration and implementations must use the same macro.
+ */
+/** APREQ_DECLARE(rettype) apeq_func(args)
+ */
+#define APREQ_DECLARE(d) APR_DECLARE(d)
+/**
+ * The public APEQ functions using variable arguments are declared with
+ * APEQ_DECLARE_NONSTD(), as they must follow the C language calling convention.
+ * @see APEQ_DECLARE @see APEQ_DECLARE_DATA
+ * @remark Both the declaration and implementations must use the same macro.
+ * @example
+ */
+/** APEQ_DECLARE_NONSTD(rettype) apr_func(args, ...);
+ */
+#define APREQ_DECLARE_NONSTD(d) APR_DECLARE_NONSTD(d)
+/**
+ * The public APREQ variables are declared with APREQ_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ * @see APREQ_DECLARE @see APREQ_DECLARE_NONSTD
+ * @remark Note that the declaration and implementations use different forms,
+ * but both must include the macro.
+ */
+/** extern APREQ_DECLARE_DATA type apr_variable;\n
+ * APREQ_DECLARE_DATA type apr_variable = value;
+ */
+#define APREQ_DECLARE_DATA
+#elif defined (APREQ_DECLARE_STATIC)
+#define APREQ_DECLARE(type) type __stdcall
+#define APREQ_DECLARE_NONSTD(type) type
+#define APREQ_DECLARE_DATA
+#elif defined (APREQ_DECLARE_EXPORT)
+#define APREQ_DECLARE(type) __declspec(dllexport) type __stdcall
+#define APREQ_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define APREQ_DECLARE_DATA __declspec(dllexport)
+#else
+#define APREQ_DECLARE(type) __declspec(dllimport) type __stdcall
+#define APREQ_DECLARE_NONSTD(type) __declspec(dllimport) type
+#define APREQ_DECLARE_DATA __declspec(dllimport)
+#endif
+
+/**
+ * Read chucks of data in 64k blocks from the request
+ */
+
+#define APREQ_DEFAULT_READ_BLOCK_SIZE (64 * 1024)
+
+/**
+ * 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.
+ * @see ap_set_read_limit
+ */
+#define APREQ_DEFAULT_READ_LIMIT (64 * 1024 * 1024)
+/**
+ * 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
+ * @see ap_set_brigade_read_limit
+ */
+#define APREQ_DEFAULT_BRIGADE_LIMIT (256 * 1024)
+
+/**
+ * Number of elements in the initial apr_table
+ * @see apr_table_make
+ */
+#define APREQ_DEFAULT_NELTS 8
+
+
+
+/**
+ * Check to see if specified bit f is off in bitfiled name
+ */
+#define APREQ_FLAGS_OFF(f, name) ((f) &= ~(name##_MASK << name##_BIT))
+/**
+ * Check to see if specified bit f is on in bitfiled name
+ */
+#define APREQ_FLAGS_ON(f, name) ((f) |= (name##_MASK << name##_BIT))
+/**
+ * Get specified bit f in bitfiled name
+ */
+#define APREQ_FLAGS_GET(f, name) (((f) >> name##_BIT) & name##_MASK)
+/**
+ * Set specified bit f in bitfiled name to value
+ * Note the below BIT/Mask defines are used sans the
+ * _BIT, _MASK because of the this define's \#\#_MASK, \#\#_BIT usage.
+ * Each come in a pair
+ */
+#define APREQ_FLAGS_SET(f, name, value) \
+ ((f) = (((f) & ~(name##_MASK << name##_BIT)) \
+ | ((name##_MASK & (value)) << name##_BIT)))
+
+/**
+ * Charset Bit
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_CHARSET_BIT 0
+
+/**
+ * Charset Mask
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_CHARSET_MASK 255
+
+/**
+ * Tainted Bit
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_TAINTED_BIT 8
+/**
+ * Tainted Mask
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_TAINTED_MASK 1
+
+/**
+ * Cookier Version Bit
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+
+#define APREQ_COOKIE_VERSION_BIT 11
+/**
+ * Cookie Version Mask
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_COOKIE_VERSION_MASK 3
+
+/**
+ * Cookie's Secure Bit
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_COOKIE_SECURE_BIT 13
+/**
+ * Cookie's Secure Mask
+ * @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
+ * @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
+ */
+#define APREQ_COOKIE_SECURE_MASK 1
+
+/** Character encodings. */
+typedef enum {
+ APREQ_CHARSET_ASCII =0,
+ APREQ_CHARSET_LATIN1 =1, /* ISO-8859-1 */
+ APREQ_CHARSET_CP1252 =2, /* Windows-1252 */
+ APREQ_CHARSET_UTF8 =8
+} apreq_charset_t;
+
+
+/** @enum apreq_join_t Join type */
+typedef enum {
+ APREQ_JOIN_AS_IS, /**< Join the strings without modification */
+ APREQ_JOIN_ENCODE, /**< Url-encode the strings before joining them */
+ APREQ_JOIN_DECODE, /**< Url-decode the strings before joining them */
+ APREQ_JOIN_QUOTE /**< Quote the strings, backslashing existing quote marks. */
+} apreq_join_t;
+
+/** @enum apreq_match_t Match type */
+typedef enum {
+ APREQ_MATCH_FULL, /**< Full match only. */
+ APREQ_MATCH_PARTIAL /**< Partial matches are ok. */
+} apreq_match_t;
+
+/** @enum apreq_expires_t Expiration date format */
+typedef enum {
+ APREQ_EXPIRES_HTTP, /**< Use date formatting consistent with RFC 2616 */
+ APREQ_EXPIRES_NSCOOKIE /**< Use format consistent with Netscape's Cookie Spec */
+} apreq_expires_t;
+
+
+/** @brief libapreq's pre-extensible string type */
+typedef struct apreq_value_t {
+ char *name; /**< value name */
+ apr_size_t nlen; /**< length of name */
+ apr_size_t dlen; /**< length of data */
+ char data[1]; /**< value data */
+} apreq_value_t;
+
+/**
+ * Adds the specified apreq_value_t to the apr_table_t.
+ *
+ * @param v value to add
+ * @param t add v to this table
+ *
+ * @return void
+ *
+ * @ see apr_table_t @see apr_value_t
+ */
+
+static APR_INLINE
+void apreq_value_table_add(const apreq_value_t *v, apr_table_t *t) {
+ apr_table_addn(t, v->name, v->data);
+}
+
+/**
+ * @param T type
+ * @param A attribute
+ * @param P
+ *
+ * XXX
+ */
+#define apreq_attr_to_type(T,A,P) ( (T*) ((char*)(P)-offsetof(T,A)) )
+
+/**
+ * Initialize libapreq2. Applications (except apache modules using
+ * mod_apreq) should call this exactly once before they use any
+ * libapreq2 modules. If you want to modify the list of default parsers
+ * with apreq_register_parser(), please use apreq_pre_initialize()
+ * and apreq_post_initialize() instead.
+ *
+ * @param pool a base pool persisting while libapreq2 is used
+ * @remarks after you detroy the pool, you have to call this function again
+ * with a new pool if you still plan to use libapreq2
+ */
+APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool);
+
+
+/**
+ * Pre-initialize libapreq2. Applications (except apache modules using
+ * mod_apreq2) should call this exactly once before they register custom
+ * parsers with libapreq2. mod_apreq2 does this automatically during the
+ * post-config phase, so modules that need call apreq_register_parser should
+ * create a post-config hook using APR_HOOK_MIDDLE.
+ *
+ * @param pool a base pool persisting while libapreq2 is used
+ * @remarks after you detroyed the pool, you have to call this function again
+ * with a new pool if you still plan to use libapreq2
+ */
+APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool);
+
+/**
+ * Post-initialize libapreq2. Applications (except apache modules using
+ * mod_apreq2) should this exactly once before they use any
+ * libapreq2 modules for parsing.
+ *
+ * @param pool the same pool that was used in apreq_pre_initialize().
+ */
+APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* APREQ_H */
diff --git a/srclib/libapreq/include/apreq_cookie.h b/srclib/libapreq/include/apreq_cookie.h
new file mode 100644
index 0000000000..b1d5dda05a
--- /dev/null
+++ b/srclib/libapreq/include/apreq_cookie.h
@@ -0,0 +1,216 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_COOKIE_H
+#define APREQ_COOKIE_H
+
+#include "apreq.h"
+#include "apr_time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file apreq_cookie.h
+ * @brief Cookies and Jars.
+ * @ingroup libapreq2
+ *
+ * apreq_cookie.h describes a common server-side API for request (incoming)
+ * and response (outgoing) cookies. It aims towards compliance with the
+ * standard cookie specifications listed below.
+ *
+ * @see http://wp.netscape.com/newsref/std/cookie_spec.html
+ * @see http://www.ietf.org/rfc/rfc2109.txt
+ * @see http://www.ietf.org/rfc/rfc2964.txt
+ * @see http://www.ietf.org/rfc/rfc2965.txt
+ *
+ */
+
+/** @todo convert this macro to an apreq_module_t method.
+ *
+ * Maximum length of a single Set-Cookie(2) header.
+ */
+#define APREQ_COOKIE_MAX_LENGTH 4096
+
+/** @brief Cookie type, supporting both Netscape and RFC cookie specifications.
+ */
+
+typedef struct apreq_cookie_t {
+
+ char *path; /**< Restricts url path */
+ char *domain; /**< Restricts server domain */
+ char *port; /**< Restricts server port */
+ char *comment; /**< RFC cookies may send a comment */
+ char *commentURL; /**< RFC cookies may place an URL here */
+ apr_time_t max_age; /**< total duration of cookie: -1 == session */
+ unsigned flags; /**< charsets, taint marks, app-specific bits */
+ const apreq_value_t v; /**< "raw" cookie value */
+
+} apreq_cookie_t;
+
+
+/** Upgrades a jar's table values to apreq_cookie_t structs. */
+static APR_INLINE
+apreq_cookie_t *apreq_value_to_cookie(const char *val)
+{
+ union { const char *in; char *out; } deconst;
+
+ deconst.in = val;
+ return apreq_attr_to_type(apreq_cookie_t, v,
+ apreq_attr_to_type(apreq_value_t, data, deconst.out));
+}
+
+/**@return 1 if this is an RFC cookie, 0 if its a Netscape cookie. */
+static APR_INLINE
+unsigned apreq_cookie_version(const apreq_cookie_t *c) {
+ return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_VERSION);
+}
+
+/** Sets the cookie's protocol version. */
+static APR_INLINE
+void apreq_cookie_version_set(apreq_cookie_t *c, unsigned v) {
+ APREQ_FLAGS_SET(c->flags, APREQ_COOKIE_VERSION, v);
+}
+
+/** @return 1 if the secure flag is set, 0 otherwise. */
+static APR_INLINE
+unsigned apreq_cookie_is_secure(const apreq_cookie_t *c) {
+ return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_SECURE);
+}
+
+/** Sets the cookie's secure flag, meaning it only
+ * comes back over an SSL-encrypted connction.
+ */
+static APR_INLINE
+void apreq_cookie_secure_on(apreq_cookie_t *c) {
+ APREQ_FLAGS_ON(c->flags, APREQ_COOKIE_SECURE);
+}
+
+/** Turns off the cookie's secure flag. */
+static APR_INLINE
+void apreq_cookie_secure_off(apreq_cookie_t *c) {
+ APREQ_FLAGS_OFF(c->flags, APREQ_COOKIE_SECURE);
+}
+
+
+/** @return 1 if the taint flag is set, 0 otherwise. */
+static APR_INLINE
+unsigned apreq_cookie_is_tainted(const apreq_cookie_t *c) {
+ return APREQ_FLAGS_GET(c->flags, APREQ_TAINTED);
+}
+
+/** Sets the cookie's tainted flag. */
+static APR_INLINE
+void apreq_cookie_tainted_on(apreq_cookie_t *c) {
+ APREQ_FLAGS_ON(c->flags, APREQ_TAINTED);
+}
+
+/** Turns off the cookie's tainted flag. */
+static APR_INLINE
+void apreq_cookie_tainted_off(apreq_cookie_t *c) {
+ APREQ_FLAGS_OFF(c->flags, APREQ_TAINTED);
+}
+
+/**
+ * Parse a cookie header and store the cookies in an apr_table_t.
+ *
+ * @param pool pool which allocates the cookies
+ * @param jar table where parsed cookies are stored
+ * @param header the header value
+ *
+ * @return APR_SUCCESS.
+ * @return ::APREQ_ERROR_BADSEQ if an unparseable character sequence appears.
+ * @return ::APREQ_ERROR_MISMATCH if an rfc-cookie attribute appears in a
+ * netscape cookie header.
+ * @return ::APR_ENOTIMPL if an unrecognized rfc-cookie attribute appears.
+ * @return ::APREQ_ERROR_NOTOKEN if a required token was not present.
+ * @return ::APREQ_ERROR_BADCHAR if an unexpected token was present.
+ */
+APREQ_DECLARE(apr_status_t) apreq_parse_cookie_header(apr_pool_t *pool,
+ apr_table_t *jar,
+ const char *header);
+
+/**
+ * Returns a new cookie, made from the argument list.
+ *
+ * @param pool Pool which allocates the cookie.
+ * @param name The cookie's name.
+ * @param nlen Length of name.
+ * @param value The cookie's value.
+ * @param vlen Length of value.
+ *
+ * @return the new cookie
+ */
+APREQ_DECLARE(apreq_cookie_t *) apreq_cookie_make(apr_pool_t *pool,
+ const char *name,
+ const apr_size_t nlen,
+ const char *value,
+ const apr_size_t vlen);
+
+/**
+ * Returns a string that represents the cookie as it would appear
+ * in a valid "Set-Cookie*" header.
+ *
+ * @param c cookie.
+ * @param p pool which allocates the returned string.
+ *
+ * @return header string.
+ */
+APREQ_DECLARE(char*) apreq_cookie_as_string(const apreq_cookie_t *c,
+ apr_pool_t *p);
+
+
+/**
+ * Same functionality as apreq_cookie_as_string. Stores the string
+ * representation in buf, using up to len bytes in buf as storage.
+ * The return value has the same semantics as that of apr_snprintf,
+ * including the special behavior for a "len = 0" argument.
+ *
+ * @param c cookie.
+ * @param buf storage location for the result.
+ * @param len size of buf's storage area.
+ *
+ * @return size of resulting header string.
+ */
+APREQ_DECLARE(int) apreq_cookie_serialize(const apreq_cookie_t *c,
+ char *buf, apr_size_t len);
+
+/**
+ * Set the Cookie's expiration date.
+ *
+ * @param c The cookie.
+ * @param time_str If NULL, the Cookie's expiration date is unset,
+ * making it a session cookie. This means no "expires" or "max-age"
+ * attribute will appear in the cookie's serialized form. If time_str
+ * is not NULL, the expiration date will be reset to the offset (from now)
+ * represented by time_str. The time_str should be in a format that
+ * apreq_atoi64t() can understand, namely /[+-]?\\d+\\s*[YMDhms]/.
+ *
+ * @remarks Now time_str may also be a fixed date; see apr_date_parse_rfc()
+ * for admissible formats.
+ */
+APREQ_DECLARE(void) apreq_cookie_expires(apreq_cookie_t *c,
+ const char *time_str);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /*APREQ_COOKIE_H*/
+
+
diff --git a/srclib/libapreq/include/apreq_error.h b/srclib/libapreq/include/apreq_error.h
new file mode 100644
index 0000000000..b2de1fd2be
--- /dev/null
+++ b/srclib/libapreq/include/apreq_error.h
@@ -0,0 +1,97 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_ERROR_H
+#define APREQ_ERROR_H
+
+#include "apr_errno.h"
+#include "apreq.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * apreq's wrapper around apr_strerror();
+ * recognizes APREQ_ERROR_* status codes.
+ */
+APREQ_DECLARE(char *)
+apreq_strerror(apr_status_t s, char *buf, apr_size_t bufsize);
+
+/**
+ * @file apreq_error.h
+ * @brief Error status codes.
+ * @ingroup libapreq2
+ *
+ * Define the APREQ_ error codes.
+ */
+
+#ifndef APR_EBADARG
+/**
+ * Bad Arguments return value
+ * @see APR_BADARG
+ */
+#define APR_EBADARG APR_BADARG /* XXX: don't use APR_BADARG */
+#endif
+
+/** Internal apreq error. */
+#define APREQ_ERROR_GENERAL APR_OS_START_USERERR
+/** Attempted to perform unsafe action with tainted data. */
+#define APREQ_ERROR_TAINTED (APREQ_ERROR_GENERAL + 1)
+/** Parsing interrupted. */
+#define APREQ_ERROR_INTERRUPT (APREQ_ERROR_GENERAL + 2)
+
+/** Invalid input data. */
+#define APREQ_ERROR_BADDATA (APREQ_ERROR_GENERAL + 10)
+/** Invalid character. */
+#define APREQ_ERROR_BADCHAR (APREQ_ERROR_BADDATA + 1)
+/** Invalid byte sequence. */
+#define APREQ_ERROR_BADSEQ (APREQ_ERROR_BADDATA + 2)
+/** Invalid attribute. */
+#define APREQ_ERROR_BADATTR (APREQ_ERROR_BADDATA + 3)
+/** Invalid header. */
+#define APREQ_ERROR_BADHEADER (APREQ_ERROR_BADDATA + 4)
+/** Invalid utf8 encoding. */
+#define APREQ_ERROR_BADUTF8 (APREQ_ERROR_BADDATA + 5)
+
+/** Missing input data. */
+#define APREQ_ERROR_NODATA (APREQ_ERROR_GENERAL + 20)
+/** Missing required token. */
+#define APREQ_ERROR_NOTOKEN (APREQ_ERROR_NODATA + 1)
+/** Missing attribute. */
+#define APREQ_ERROR_NOATTR (APREQ_ERROR_NODATA + 2)
+/** Missing header. */
+#define APREQ_ERROR_NOHEADER (APREQ_ERROR_NODATA + 3)
+/** Missing parser. */
+#define APREQ_ERROR_NOPARSER (APREQ_ERROR_NODATA + 4)
+
+
+/** Conflicting information. */
+#define APREQ_ERROR_MISMATCH (APREQ_ERROR_GENERAL + 30)
+/** Exceeds configured maximum limit. */
+#define APREQ_ERROR_OVERLIMIT (APREQ_ERROR_MISMATCH + 1)
+/** Below configured minimum limit. */
+#define APREQ_ERROR_UNDERLIMIT (APREQ_ERROR_MISMATCH + 2)
+/** Setting already configured. */
+#define APREQ_ERROR_NOTEMPTY (APREQ_ERROR_MISMATCH + 3)
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* APREQ_ERROR_H */
diff --git a/srclib/libapreq/include/apreq_module.h b/srclib/libapreq/include/apreq_module.h
new file mode 100644
index 0000000000..1bb2345e04
--- /dev/null
+++ b/srclib/libapreq/include/apreq_module.h
@@ -0,0 +1,457 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_MODULE_H
+#define APREQ_MODULE_H
+
+#include "apreq_cookie.h"
+#include "apreq_parser.h"
+#include "apreq_error.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * @file apreq_module.h
+ * @brief Module API
+ * @ingroup libapreq2
+ */
+
+
+/**
+ * An apreq handle associated with a module. The structure
+ * may have variable size, because the module may append its own data
+ * structures after it.
+ */
+typedef struct apreq_handle_t {
+ /** the apreq module which implements this handle */
+ const struct apreq_module_t *module;
+ /** the pool which defines the lifetime of the parsed data */
+ apr_pool_t *pool;
+ /** the allocator, which persists at least as long as the pool */
+ apr_bucket_alloc_t *bucket_alloc;
+
+} apreq_handle_t;
+
+/**
+ * @brief Vtable describing the necessary environment functions.
+ */
+
+
+typedef struct apreq_module_t {
+ /** name of this apreq module */
+ const char *name;
+ /** magic number identifying the module and version */
+ apr_uint32_t magic_number;
+
+ /** get a table with all cookies */
+ apr_status_t (*jar)(apreq_handle_t *, const apr_table_t **);
+ /** get a table with all query string parameters */
+ apr_status_t (*args)(apreq_handle_t *, const apr_table_t **);
+ /** get a table with all body parameters */
+ apr_status_t (*body)(apreq_handle_t *, const apr_table_t **);
+
+ /** get a cookie by its name */
+ apreq_cookie_t *(*jar_get)(apreq_handle_t *, const char *);
+ /** get a query string parameter by its name */
+ apreq_param_t *(*args_get)(apreq_handle_t *, const char *);
+ /** get a body parameter by its name */
+ apreq_param_t *(*body_get)(apreq_handle_t *, const char *);
+
+ /** gets the parser associated with the request body */
+ apr_status_t (*parser_get)(apreq_handle_t *, const apreq_parser_t **);
+ /** manually set a parser for the request body */
+ apr_status_t (*parser_set)(apreq_handle_t *, apreq_parser_t *);
+ /** add a hook function */
+ apr_status_t (*hook_add)(apreq_handle_t *, apreq_hook_t *);
+
+ /** determine the maximum in-memory bytes a brigade may use */
+ apr_status_t (*brigade_limit_get)(apreq_handle_t *, apr_size_t *);
+ /** set the maximum in-memory bytes a brigade may use */
+ apr_status_t (*brigade_limit_set)(apreq_handle_t *, apr_size_t);
+
+ /** determine the maximum amount of data that will be fed into a parser */
+ apr_status_t (*read_limit_get)(apreq_handle_t *, apr_uint64_t *);
+ /** set the maximum amount of data that will be fed into a parser */
+ apr_status_t (*read_limit_set)(apreq_handle_t *, apr_uint64_t);
+
+ /** determine the directory used by the parser for temporary files */
+ apr_status_t (*temp_dir_get)(apreq_handle_t *, const char **);
+ /** set the directory used by the parser for temporary files */
+ apr_status_t (*temp_dir_set)(apreq_handle_t *, const char *);
+
+} apreq_module_t;
+
+
+/**
+ * Defines the module-specific status codes which
+ * are commonly considered to be non-fatal.
+ *
+ * @param s status code returned by an apreq_module_t method.
+ *
+ * @return 1 if s is fatal, 0 otherwise.
+ */
+static APR_INLINE
+unsigned apreq_module_status_is_error(apr_status_t s) {
+ switch (s) {
+ case APR_SUCCESS:
+ case APR_INCOMPLETE:
+ case APR_EINIT:
+ case APREQ_ERROR_NODATA:
+ case APREQ_ERROR_NOPARSER:
+ case APREQ_ERROR_NOHEADER:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+
+/**
+ * Expose the parsed "cookie" header associated to this handle.
+ *
+ * @param req The request handle
+ * @param t The resulting table, which will either be NULL or a
+ * valid table object on return.
+ *
+ * @return APR_SUCCESS or a module-specific error status code.
+ */
+static APR_INLINE
+apr_status_t apreq_jar(apreq_handle_t *req, const apr_table_t **t)
+{
+ return req->module->jar(req,t);
+}
+
+/**
+ * Expose the parsed "query string" associated to this handle.
+ *
+ * @param req The request handle
+ * @param t The resulting table, which will either be NULL or a
+ * valid table object on return.
+ *
+ * @return APR_SUCCESS or a module-specific error status code.
+ */
+static APR_INLINE
+apr_status_t apreq_args(apreq_handle_t *req, const apr_table_t **t)
+{
+ return req->module->args(req,t);
+}
+
+/**
+ * Expose the parsed "request body" associated to this handle.
+ *
+ * @param req The request handle
+ * @param t The resulting table, which will either be NULL or a
+ * valid table object on return.
+ *
+ * @return APR_SUCCESS or a module-specific error status code.
+ */
+static APR_INLINE
+apr_status_t apreq_body(apreq_handle_t *req, const apr_table_t **t)
+{
+ return req->module->body(req, t);
+}
+
+
+/**
+ * Fetch the first cookie with the given name.
+ *
+ * @param req The request handle
+ * @param name Case-insensitive cookie name.
+ *
+ * @return First matching cookie, or NULL if none match.
+ */
+static APR_INLINE
+apreq_cookie_t *apreq_jar_get(apreq_handle_t *req, const char *name)
+{
+ return req->module->jar_get(req, name);
+}
+
+/**
+ * Fetch the first query string param with the given name.
+ *
+ * @param req The request handle
+ * @param name Case-insensitive param name.
+ *
+ * @return First matching param, or NULL if none match.
+ */
+static APR_INLINE
+apreq_param_t *apreq_args_get(apreq_handle_t *req, const char *name)
+{
+ return req->module->args_get(req, name);
+}
+
+/**
+ * Fetch the first body param with the given name.
+ *
+ * @param req The request handle
+ * @param name Case-insensitive cookie name.
+ *
+ * @return First matching param, or NULL if none match.
+ */
+static APR_INLINE
+apreq_param_t *apreq_body_get(apreq_handle_t *req, const char *name)
+{
+ return req->module->body_get(req, name);
+}
+
+/**
+ * Fetch the active body parser.
+ *
+ * @param req The request handle
+ * @param parser Points to the active parser on return.
+ *
+ * @return APR_SUCCESS or module-specific error.
+ *
+ */
+static APR_INLINE
+apr_status_t apreq_parser_get(apreq_handle_t *req,
+ const apreq_parser_t **parser)
+{
+ return req->module->parser_get(req, parser);
+}
+
+
+/**
+ * Set the body parser for this request.
+ *
+ * @param req The request handle
+ * @param parser New parser to use.
+ *
+ * @return APR_SUCCESS or module-specific error.
+ */
+static APR_INLINE
+apr_status_t apreq_parser_set(apreq_handle_t *req,
+ apreq_parser_t *parser)
+{
+ return req->module->parser_set(req, parser);
+}
+
+/**
+ * Add a parser hook for this request.
+ *
+ * @param req The request handle
+ * @param hook Hook to add.
+ *
+ * @return APR_SUCCESS or module-specific error.
+ */
+static APR_INLINE
+apr_status_t apreq_hook_add(apreq_handle_t *req, apreq_hook_t *hook)
+{
+ return req->module->hook_add(req, hook);
+}
+
+
+/**
+ * Set the active brigade limit.
+ *
+ * @param req The handle.
+ * @param bytes New limit to use.
+ *
+ * @return APR_SUCCESS or module-specific error.
+ *
+ */
+static APR_INLINE
+apr_status_t apreq_brigade_limit_set(apreq_handle_t *req,
+ apr_size_t bytes)
+{
+ return req->module->brigade_limit_set(req, bytes);
+}
+
+/**
+ * Get the active brigade limit.
+ *
+ * @param req The handle.
+ * @param bytes Pointer to resulting (current) limit.
+ *
+ * @return APR_SUCCESS or a module-specific error,
+ * which may leave bytes undefined.
+ */
+static APR_INLINE
+apr_status_t apreq_brigade_limit_get(apreq_handle_t *req,
+ apr_size_t *bytes)
+{
+ return req->module->brigade_limit_get(req, bytes);
+}
+
+/**
+ * Set the active read limit.
+ *
+ * @param req The handle.
+ * @param bytes New limit to use.
+ *
+ * @return APR_SUCCESS or a module-specific error.
+ *
+ */
+static APR_INLINE
+apr_status_t apreq_read_limit_set(apreq_handle_t *req,
+ apr_uint64_t bytes)
+{
+ return req->module->read_limit_set(req, bytes);
+}
+
+/**
+ * Get the active read limit.
+ *
+ * @param req The request handle.
+ * @param bytes Pointer to resulting (current) limit.
+ *
+ * @return APR_SUCCESS or a module-specific error,
+ * which may leave bytes undefined.
+ */
+static APR_INLINE
+apr_status_t apreq_read_limit_get(apreq_handle_t *req,
+ apr_uint64_t *bytes)
+{
+ return req->module->read_limit_get(req, bytes);
+}
+
+/**
+ * Set the active temp directory.
+ *
+ * @param req The handle.
+ * @param path New path to use; may be NULL.
+ *
+ * @return APR_SUCCESS or a module-specific error .
+ */
+static APR_INLINE
+apr_status_t apreq_temp_dir_set(apreq_handle_t *req, const char *path)
+{
+ return req->module->temp_dir_set(req, path);
+}
+
+/**
+ * Get the active temp directory.
+ *
+ * @param req The handle.
+ * @param path Resulting path to temp dir.
+ *
+ * @return APR_SUCCESS implies path is valid, but may also be NULL.
+ * Any other return value is module-specific, and may leave
+ * path undefined.
+ */
+static APR_INLINE
+apr_status_t apreq_temp_dir_get(apreq_handle_t *req, const char **path)
+{
+ return req->module->temp_dir_get(req, path);
+}
+
+
+
+/**
+ * Convenience macro for defining a module by mapping
+ * a function prefix to an associated apreq_module_t structure.
+ *
+ * @param pre Prefix to define new environment. All attributes of
+ * the apreq_env_module_t struct are defined with this as their
+ * prefix. The generated struct is named by appending "_module" to
+ * the prefix.
+ * @param mmn Magic number (i.e. version number) of this environment.
+ */
+#define APREQ_MODULE(pre, mmn) const apreq_module_t \
+ pre##_module = { #pre, mmn, \
+ pre##_jar, pre##_args, pre##_body, \
+ pre##_jar_get, pre##_args_get, pre##_body_get, \
+ pre##_parser_get, pre##_parser_set, pre##_hook_add, \
+ pre##_brigade_limit_get, pre##_brigade_limit_set, \
+ pre##_read_limit_get, pre##_read_limit_set, \
+ pre##_temp_dir_get, pre##_temp_dir_set, \
+ }
+
+
+/**
+ * Create an apreq handle which is suitable for a CGI program. It
+ * reads input from stdin and writes output to stdout.
+ *
+ * @param pool Pool associated to this handle.
+ *
+ * @return New handle; can only be NULL if the pool allocation failed.
+ *
+ * @remarks The handle gets cached in the pool's userdata, so subsequent
+ * calls will retrieve the original cached handle.
+ */
+APREQ_DECLARE(apreq_handle_t*) apreq_handle_cgi(apr_pool_t *pool);
+
+/**
+ * Create a custom apreq handle which knows only some static
+ * values. Useful if you want to test the parser code or if you have
+ * got data from a custom source (neither Apache 2 nor CGI).
+ *
+ * @param pool allocates the parse data,
+ * @param query_string parsed into args table
+ * @param cookie value of the request "Cookie" header
+ * @param parser parses the request body
+ * @param read_limit maximum bytes to read from the body
+ * @param in brigade containing the request body
+ *
+ * @return new handle; can only be NULL if the pool allocation failed.
+ */
+APREQ_DECLARE(apreq_handle_t*) apreq_handle_custom(apr_pool_t *pool,
+ const char *query_string,
+ const char *cookie,
+ apreq_parser_t *parser,
+ apr_uint64_t read_limit,
+ apr_bucket_brigade *in);
+
+/**
+ * Find the first query string parameter or body parameter with the
+ * specified name. The match is case-insensitive.
+ *
+ * @param req request handle.
+ * @param key desired parameter name
+ *
+ * @return The first matching parameter (with args searched first) or NULL.
+ */
+APREQ_DECLARE(apreq_param_t *)apreq_param(apreq_handle_t *req, const char *key);
+
+/**
+ * Find the first cookie with the specified name.
+ * The match is case-insensitive.
+ *
+ * @param req request handle.
+ * @param name desired cookie name
+ *
+ * @return The first matching parameter (with args searched first) or NULL.
+ */
+#define apreq_cookie(req, name) apreq_jar_get(req, name)
+
+/**
+ * Returns a table containing key-value pairs for the full request
+ * (args + body).
+ *
+ * @param req request handle
+ * @param p allocates the returned table.
+ *
+ * @return table representing all available params; is never NULL.
+ */
+APREQ_DECLARE(apr_table_t *) apreq_params(apreq_handle_t *req, apr_pool_t *p);
+
+
+/**
+ * Returns a table containing all request cookies.
+ *
+ * @param req the apreq request handle
+ * @param p Allocates the returned table.
+ */
+APREQ_DECLARE(apr_table_t *)apreq_cookies(apreq_handle_t *req, apr_pool_t *p);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* APREQ_MODULE_H */
diff --git a/srclib/libapreq/include/apreq_param.h b/srclib/libapreq/include/apreq_param.h
new file mode 100644
index 0000000000..832cfc2f38
--- /dev/null
+++ b/srclib/libapreq/include/apreq_param.h
@@ -0,0 +1,209 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_PARAM_H
+#define APREQ_PARAM_H
+
+#include "apreq.h"
+#include "apr_buckets.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @file apreq_param.h
+ * @brief Request parsing and parameter API
+ * @ingroup libapreq2
+ */
+
+
+/** Common data structure for params and file uploads */
+typedef struct apreq_param_t {
+ apr_table_t *info; /**< header table associated with the param */
+ apr_bucket_brigade *upload; /**< brigade used to spool upload files */
+ unsigned flags; /**< charsets, taint marks, app-specific bits */
+ const apreq_value_t v; /**< underlying name/value info */
+} apreq_param_t;
+
+
+/** @return 1 if the taint flag is set, 0 otherwise. */
+static APR_INLINE
+unsigned apreq_param_is_tainted(const apreq_param_t *p) {
+ return APREQ_FLAGS_GET(p->flags, APREQ_TAINTED);
+}
+
+/** Sets the tainted flag. */
+static APR_INLINE
+void apreq_param_tainted_on(apreq_param_t *p) {
+ APREQ_FLAGS_ON(p->flags, APREQ_TAINTED);
+}
+
+/** Turns off the taint flag. */
+static APR_INLINE
+void apreq_param_tainted_off(apreq_param_t *p) {
+ APREQ_FLAGS_OFF(p->flags, APREQ_TAINTED);
+}
+
+/** Sets the character encoding for this parameter. */
+static APR_INLINE
+apreq_charset_t apreq_param_charset_set(apreq_param_t *p, apreq_charset_t c) {
+ apreq_charset_t old = (apreq_charset_t)
+ APREQ_FLAGS_GET(p->flags, APREQ_CHARSET);
+ APREQ_FLAGS_SET(p->flags, APREQ_CHARSET, c);
+ return old;
+}
+
+/** Gets the character encoding for this parameter. */
+static APR_INLINE
+apreq_charset_t apreq_param_charset_get(apreq_param_t *p) {
+ return (apreq_charset_t)APREQ_FLAGS_GET(p->flags, APREQ_CHARSET);
+}
+
+
+/** Upgrades args and body table values to apreq_param_t structs. */
+static APR_INLINE
+apreq_param_t *apreq_value_to_param(const char *val)
+{
+ union { const char *in; char *out; } deconst;
+
+ deconst.in = val;
+ return apreq_attr_to_type(apreq_param_t, v,
+ apreq_attr_to_type(apreq_value_t, data, deconst.out));
+}
+
+
+
+/** creates a param from name/value information */
+APREQ_DECLARE(apreq_param_t *) apreq_param_make(apr_pool_t *p,
+ const char *name,
+ const apr_size_t nlen,
+ const char *val,
+ const apr_size_t vlen);
+
+/**
+ * Url-decodes a name=value pair into a param.
+ *
+ * @param param points to the decoded parameter on success
+ * @param pool Pool from which the param is allocated.
+ * @param word Start of the name=value pair.
+ * @param nlen Length of urlencoded name.
+ * @param vlen Length of urlencoded value.
+ *
+ * @return APR_SUCCESS on success.
+ * @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
+ *
+ * @remarks Unless vlen == 0, this function assumes there is
+ * exactly one character ('=') which separates the pair.
+ *
+ */
+APREQ_DECLARE(apr_status_t) apreq_param_decode(apreq_param_t **param,
+ apr_pool_t *pool,
+ const char *word,
+ apr_size_t nlen,
+ apr_size_t vlen);
+
+/**
+ * Url-encodes the param into a name-value pair.
+ * @param pool Pool which allocates the returned string.
+ * @param param Param to encode.
+ * @return name-value pair representing the param.
+ */
+APREQ_DECLARE(char *) apreq_param_encode(apr_pool_t *pool,
+ const apreq_param_t *param);
+
+/**
+ * Parse a url-encoded string into a param table.
+ * @param pool pool used to allocate the param data.
+ * @param t table to which the params are added.
+ * @param qs Query string to url-decode.
+ * @return APR_SUCCESS if successful, error otherwise.
+ * @remark This function uses [&;] as the set of tokens
+ * to delineate words, and will treat a word w/o '='
+ * as a name-value pair with value-length = 0.
+ *
+ */
+APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool,
+ apr_table_t *t,
+ const char *qs);
+
+
+/**
+ * Returns an array of parameters (apreq_param_t *) matching the given key.
+ * The key is case-insensitive.
+ * @param p Allocates the returned array.
+ * @param t the parameter table returned by apreq_args(), apreq_body()
+ * or apreq_params()
+ * @param key Null-terminated search key, case insensitive.
+ * key==NULL fetches all parameters.
+ * @return an array of apreq_param_t* (pointers)
+ * @remark Also parses the request if necessary.
+ */
+APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p,
+ const apr_table_t *t,
+ const char *key);
+
+/**
+ * Returns a ", " -joined string containing all parameters
+ * for the requested key, an empty string if none are found.
+ * The key is case-insensitive.
+ *
+ * @param p Allocates the return string.
+ * @param t the parameter table returned by apreq_args(), apreq_body()
+ * or apreq_params()
+ * @param key Null-terminated parameter name, case insensitive.
+ * key==NULL fetches all values.
+ * @param mode Join type- see apreq_join().
+ * @return the joined string or NULL on error
+ * @remark Also parses the request if necessary.
+ */
+APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p,
+ const apr_table_t *t,
+ const char *key,
+ apreq_join_t mode);
+
+/**
+ * Returns a table of all params in req->body with non-NULL upload brigades.
+ * @param body parameter table returned by apreq_body() or apreq_params()
+ * @param pool Pool which allocates the table struct.
+ * @return Upload table.
+ * @remark Will parse the request if necessary.
+ */
+APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body,
+ apr_pool_t *pool);
+
+/**
+ * Returns the first param in req->body which has both param->v.name
+ * matching key (case insensitive) and param->upload != NULL.
+ * @param body parameter table returned by apreq_body() or apreq_params()
+ * @param name Parameter name. key == NULL returns first upload.
+ * @return Corresponding upload, NULL if none found.
+ * @remark Will parse the request as necessary.
+ */
+APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body,
+ const char *name);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* APREQ_PARAM_H */
+
+
+
diff --git a/srclib/libapreq/include/apreq_parser.h b/srclib/libapreq/include/apreq_parser.h
new file mode 100644
index 0000000000..e0f38b96f7
--- /dev/null
+++ b/srclib/libapreq/include/apreq_parser.h
@@ -0,0 +1,287 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_PARSERS_H
+#define APREQ_PARSERS_H
+/* These structs are defined below */
+
+#include "apreq_param.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file apreq_parser.h
+ * @brief Request body parser API
+ * @ingroup libapreq2
+ */
+
+/**
+ * A hook is called by the parser whenever data arrives in a file
+ * upload parameter of the request body. You may associate any number
+ * of hooks with a parser instance with apreq_parser_add_hook().
+ */
+typedef struct apreq_hook_t apreq_hook_t;
+
+/**
+ * A request body parser instance.
+ */
+typedef struct apreq_parser_t apreq_parser_t;
+
+/** Parser arguments. */
+#define APREQ_PARSER_ARGS apreq_parser_t *parser, \
+ apr_table_t *t, \
+ apr_bucket_brigade *bb
+
+/** Hook arguments */
+#define APREQ_HOOK_ARGS apreq_hook_t *hook, \
+ apreq_param_t *param, \
+ apr_bucket_brigade *bb
+
+/**
+ * The callback function implementing a request body parser.
+ */
+typedef apr_status_t (*apreq_parser_function_t)(APREQ_PARSER_ARGS);
+
+/**
+ * The callback function of a hook. See apreq_hook_t.
+ */
+typedef apr_status_t (*apreq_hook_function_t)(APREQ_HOOK_ARGS);
+
+/**
+ * Declares a API parser.
+ */
+#define APREQ_DECLARE_PARSER(f) APREQ_DECLARE_NONSTD(apr_status_t) \
+ (f) (APREQ_PARSER_ARGS)
+
+/**
+ * Declares an API hook.
+ */
+#define APREQ_DECLARE_HOOK(f) APREQ_DECLARE_NONSTD(apr_status_t) \
+ (f) (APREQ_HOOK_ARGS)
+
+/**
+ * A hook is called by the parser whenever data arrives in a file
+ * upload parameter of the request body. You may associate any number
+ * of hooks with a parser instance with apreq_parser_add_hook().
+ */
+struct apreq_hook_t {
+ apreq_hook_function_t hook; /**< the hook function */
+ apreq_hook_t *next; /**< next item in the linked list */
+ apr_pool_t *pool; /**< pool which allocated this hook */
+ void *ctx; /**< a user defined pointer passed to the hook function */
+};
+
+/**
+ * A request body parser instance.
+ */
+struct apreq_parser_t {
+ /** the function which parses chunks of body data */
+ apreq_parser_function_t parser;
+ /** the Content-Type request header */
+ const char *content_type;
+ /** a pool which outlasts the bucket_alloc. */
+ apr_pool_t *pool;
+ /** bucket allocator used to create bucket brigades */
+ apr_bucket_alloc_t *bucket_alloc;
+ /** the maximum in-memory bytes a brigade may use */
+ apr_size_t brigade_limit;
+ /** the directory for generating temporary files */
+ const char *temp_dir;
+ /** linked list of hooks */
+ apreq_hook_t *hook;
+ /** internal context pointer used by the parser function */
+ void *ctx;
+};
+
+
+/**
+ * Parse the incoming brigade into a table. Parsers normally
+ * consume all the buckets of the brigade during parsing. However
+ * parsers may leave "rejected" data in the brigade, even during a
+ * successful parse, so callers may need to clean up the brigade
+ * themselves (in particular, rejected buckets should not be
+ * passed back to the parser again).
+ * @remark bb == NULL is valid: the parser should return its
+ * public status: APR_INCOMPLETE, APR_SUCCESS, or an error code.
+ */
+static APR_INLINE
+apr_status_t apreq_parser_run(struct apreq_parser_t *psr, apr_table_t *t,
+ apr_bucket_brigade *bb)
+{
+ return psr->parser(psr, t, bb);
+}
+
+/**
+ * Run the hook with the current parameter and the incoming
+ * bucket brigade. The hook may modify the brigade if necessary.
+ * Once all hooks have completed, the contents of the brigade will
+ * be added to the parameter's bb attribute.
+ * @return APR_SUCCESS on success. All other values represent errors.
+ */
+static APR_INLINE
+apr_status_t apreq_hook_run(struct apreq_hook_t *h, apreq_param_t *param,
+ apr_bucket_brigade *bb)
+{
+ return h->hook(h, param, bb);
+}
+
+
+/**
+ * RFC 822 Header parser. It will reject all data
+ * after the first CRLF CRLF sequence (an empty line).
+ * See apreq_parser_run() for more info on rejected data.
+ */
+APREQ_DECLARE_PARSER(apreq_parse_headers);
+
+/**
+ * RFC 2396 application/x-www-form-urlencoded parser.
+ */
+APREQ_DECLARE_PARSER(apreq_parse_urlencoded);
+
+/**
+ * RFC 2388 multipart/form-data (and XForms 1.0 multipart/related)
+ * parser. It will reject any buckets representing preamble and
+ * postamble text (this is normal behavior, not an error condition).
+ * See apreq_parser_run() for more info on rejected data.
+ */
+APREQ_DECLARE_PARSER(apreq_parse_multipart);
+
+/**
+ * Generic parser. No table entries will be added to
+ * the req->body table by this parser. The parser creates
+ * a dummy apreq_param_t to pass to any configured hooks. If
+ * no hooks are configured, the dummy param's bb slot will
+ * contain a copy of the request body. It can be retrieved
+ * by casting the parser's ctx pointer to (apreq_param_t **).
+ */
+APREQ_DECLARE_PARSER(apreq_parse_generic);
+
+/**
+ * apr_xml_parser hook. It will parse until EOS appears.
+ * The parsed document isn't available until parsing has
+ * completed successfully. The hook's ctx pointer may
+ * be cast as (apr_xml_doc **) to retrieve the
+ * parsed document.
+ */
+APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser);
+
+/**
+ * Construct a parser.
+ *
+ * @param pool Pool used to allocate the parser.
+ * @param ba bucket allocator used to create bucket brigades
+ * @param content_type Content-type that this parser can deal with.
+ * @param pfn The parser function.
+ * @param brigade_limit the maximum in-memory bytes a brigade may use
+ * @param temp_dir the directory used by the parser for temporary files
+ * @param hook Hooks to associate this parser with.
+ * @param ctx Parser's internal scratch pad.
+ * @return New parser.
+ */
+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);
+
+/**
+ * Construct a hook.
+ *
+ * @param pool used to allocate the hook.
+ * @param hook The hook function.
+ * @param next List of other hooks for this hook to call on.
+ * @param ctx Hook's internal scratch pad.
+ * @return New hook.
+ */
+APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool,
+ apreq_hook_function_t hook,
+ apreq_hook_t *next,
+ void *ctx);
+
+
+/**
+ * Add a new hook to the end of the parser's hook list.
+ *
+ * @param p Parser.
+ * @param h Hook to append.
+ */
+APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p,
+ apreq_hook_t *h);
+
+
+/**
+ * Fetch the default parser function associated with the given MIME type.
+ * @param enctype The desired enctype (can also be a full "Content-Type"
+ * header).
+ * @return The parser function, or NULL if the enctype is unrecognized.
+ */
+APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype);
+
+
+/**
+ * Register a new parsing function with a MIME enctype.
+ * Registered parsers are added to apreq_parser()'s
+ * internal lookup table.
+ *
+ * @param enctype The MIME type.
+ * @param pfn The function to use during parsing. Setting
+ * parser == NULL will remove an existing parser.
+ *
+ * @return APR_SUCCESS or error.
+ */
+
+APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
+ apreq_parser_function_t pfn);
+
+
+/**
+ * Returns APREQ_ERROR_GENERAL. Effectively disables mfd parser
+ * if a file-upload field is present.
+ *
+ */
+APREQ_DECLARE_HOOK(apreq_hook_disable_uploads);
+
+/**
+ * Calls apr_brigade_cleanup on the incoming brigade
+ * after passing the brigade to any subsequent hooks.
+ */
+APREQ_DECLARE_HOOK(apreq_hook_discard_brigade);
+
+/**
+ * Special purpose utility for locating a parameter
+ * during parsing. The hook's ctx shoud be initialized
+ * to a const char *, which is a pointer to the desired
+ * param name. The hook's ctx will be reassigned to the
+ * first param found.
+ *
+ * @remarks When used, this should always be the first hook
+ * invoked, so add it manually as parser->hook instead of
+ * using apreq_parser_add_hook.
+ */
+APREQ_DECLARE_HOOK(apreq_hook_find_param);
+
+
+#ifdef __cplusplus
+}
+
+#endif
+#endif /* APREQ_PARSERS_H */
diff --git a/srclib/libapreq/include/apreq_util.h b/srclib/libapreq/include/apreq_util.h
new file mode 100644
index 0000000000..feb2d396ce
--- /dev/null
+++ b/srclib/libapreq/include/apreq_util.h
@@ -0,0 +1,443 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_UTIL_H
+#define APREQ_UTIL_H
+
+#include "apr_file_io.h"
+#include "apr_buckets.h"
+#include "apreq.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * This header contains useful functions for creating new
+ * parsers, hooks or modules. It includes
+ *
+ * - string <-> array converters
+ * - substring search functions
+ * - simple encoders & decoders for urlencoded strings
+ * - simple time, date, & file-size converters
+ * @file apreq_util.h
+ * @brief Utility functions for apreq.
+ * @ingroup libapreq2
+ */
+
+/**
+ * Join an array of values. The result is an empty string if there are
+ * no values.
+ *
+ * @param p Pool to allocate return value.
+ * @param sep String that is inserted between the joined values.
+ * @param arr Array of apreq_value_t entries.
+ * @param mode Join type- see apreq_join_t.
+ *
+ * @return Joined string, or NULL on error
+ */
+APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
+ const char *sep,
+ const apr_array_header_t *arr,
+ apreq_join_t mode);
+
+/**
+ * Returns offset of match string's location, or -1 if no match is found.
+ *
+ * @param hay Location of bytes to scan.
+ * @param hlen Number of bytes available for scanning.
+ * @param ndl Search string
+ * @param nlen Length of search string.
+ * @param type Match type.
+ *
+ * @return Offset of match string, or -1 if no match is found.
+ *
+ */
+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);
+
+/**
+ * Places a quoted copy of src into dest. Embedded quotes are escaped with a
+ * backslash ('\').
+ *
+ * @param dest Location of quoted copy. Must be large enough to hold the copy
+ * and trailing null byte.
+ * @param src Original string.
+ * @param slen Length of original string.
+ * @param dest Destination string.
+ *
+ * @return length of quoted copy in dest.
+ */
+APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
+ const apr_size_t slen);
+
+/**
+ *
+ * Same as apreq_quote() except when src begins and ends in quote marks. In
+ * that case it assumes src is quoted correctly, and just copies src to dest.
+ *
+ * @param dest Location of quoted copy. Must be large enough to hold the copy
+ * and trailing null byte.
+ * @param src Original string.
+ * @param slen Length of original string.
+ * @param dest Destination string.
+ *
+ * @return length of quoted copy in dest.
+ */
+APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
+ const apr_size_t slen);
+
+/**
+ * Url-encodes a string.
+ *
+ * @param dest Location of url-encoded result string. Caller must ensure it
+ * is large enough to hold the encoded string and trailing '\\0'.
+ * @param src Original string.
+ * @param slen Length of original string.
+ *
+ * @return length of url-encoded string in dest; does not exceed 3 * slen.
+ */
+APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
+ const apr_size_t slen);
+
+/**
+ * Convert a string from cp1252 to utf8. Caller must ensure it is large enough
+ * to hold the encoded string and trailing '\\0'.
+ *
+ * @param dest Location of utf8-encoded result string. Caller must ensure it
+ * is large enough to hold the encoded string and trailing '\\0'.
+ * @param src Original string.
+ * @param slen Length of original string.
+ *
+ * @return length of utf8-encoded string in dest; does not exceed 3 * slen.
+ */
+APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
+ const char *src, apr_size_t slen);
+
+/**
+ * Heuristically determine the charset of a string.
+ *
+ * @param src String to scan.
+ * @param slen Length of string.
+ *
+ * @return APREQ_CHARSET_ASCII if the string contains only 7-bit chars;
+ * @return APREQ_CHARSET_UTF8 if the string is a valid utf8 byte sequence;
+ * @return APREQ_CHARSET_LATIN1 if the string has no control chars;
+ * @return APREQ_CHARSET_CP1252 if the string has control chars.
+ */
+APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
+ apr_size_t slen);
+
+/**
+ * Url-decodes a string.
+ *
+ * @param dest Location of url-encoded result string. Caller must ensure dest is
+ * large enough to hold the encoded string and trailing null character.
+ * @param dlen points to resultant length of url-decoded string in dest
+ * @param src Original string.
+ * @param slen Length of original string.
+ *
+ * @return APR_SUCCESS.
+ * @return APR_INCOMPLETE if the string
+ * ends in the middle of an escape sequence.
+ * @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
+ *
+ * @remarks In the non-success case, dlen will be set to include
+ * the last succesfully decoded value. This function decodes
+ * \%uXXXX into a utf8 (wide) character, following ECMA-262
+ * (the Javascript spec) Section B.2.1.
+ */
+
+APREQ_DECLARE(apr_status_t) apreq_decode(char *dest, apr_size_t *dlen,
+ const char *src, apr_size_t slen);
+
+/**
+ * Url-decodes an iovec array.
+ *
+ * @param dest Location of url-encoded result string. Caller must ensure dest is
+ * large enough to hold the encoded string and trailing null character.
+ * @param dlen Resultant length of dest.
+ * @param v Array of iovecs that represent the source string
+ * @param nelts Number of iovecs in the array.
+ *
+ * @return APR_SUCCESS.
+ * @return APR_INCOMPLETE if the iovec
+ * ends in the middle of an escape sequence.
+ * @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
+ *
+ * @remarks In the non-APR_SUCCESS case, dlen will be set to include
+ * the last succesfully decoded value. This function decodes
+ * \%uXXXX into a utf8 (wide) character, following ECMA-262
+ * (the Javascript spec) Section B.2.1.
+ */
+
+APREQ_DECLARE(apr_status_t) apreq_decodev(char *dest, apr_size_t *dlen,
+ struct iovec *v, int nelts);
+
+/**
+ * Returns an url-encoded copy of a string.
+ *
+ * @param p Pool used to allocate the return value.
+ * @param src Original string.
+ * @param slen Length of original string.
+ *
+ * @return The url-encoded string.
+ *
+ * @remarks Use this function insead of apreq_encode if its
+ * caller might otherwise overflow dest.
+ */
+static APR_INLINE
+char *apreq_escape(apr_pool_t *p, const char *src, const apr_size_t slen)
+{
+ char *rv;
+
+ if (src == NULL)
+ return NULL;
+
+ rv = (char *)apr_palloc(p, 3 * slen + 1);
+ apreq_encode(rv, src, slen);
+ return rv;
+}
+
+/**
+ * An \e in-situ url-decoder.
+ *
+ * @param str The string to decode
+ *
+ * @return Length of decoded string, or < 0 on error.
+ */
+static APR_INLINE apr_ssize_t apreq_unescape(char *str)
+{
+ apr_size_t len;
+ apr_status_t rv = apreq_decode(str, &len, str, strlen(str));
+ if (rv == APR_SUCCESS)
+ return (apr_ssize_t)len;
+ else
+ return -1;
+}
+
+/**
+ * Converts file sizes (KMG) to bytes
+ *
+ * @param s file size matching m/^\\d+[KMG]b?$/i
+ *
+ * @return 64-bit integer representation of s.
+ *
+ * @todo What happens when s is malformed? Should this return
+ * an unsigned value instead?
+ */
+
+APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s);
+
+/**
+ * Converts time strings (YMDhms) to seconds
+ *
+ * @param s time string matching m/^\\+?\\d+[YMDhms]$/
+ *
+ * @return 64-bit integer representation of s as seconds.
+ *
+ * @todo What happens when s is malformed? Should this return
+ * an unsigned value instead?
+ */
+
+APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s);
+
+/**
+ * Writes brigade to a file.
+ *
+ * @param f File that gets the brigade.
+ * @param wlen On a successful return, wlen holds the length of
+ * the brigade, which is the amount of data written to
+ * the file.
+ * @param bb Bucket brigade.
+ *
+ * @return APR_SUCCESS.
+ * @return Error status code from either an unsuccessful apr_bucket_read(),
+ * or a failed apr_file_writev().
+ *
+ * @remarks This function leaks a bucket brigade into bb->p whenever
+ * the final bucket in bb is a spool bucket.
+ */
+
+APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
+ apr_off_t *wlen,
+ apr_bucket_brigade *bb);
+/**
+ * Makes a temporary file.
+ *
+ * @param fp Points to the temporary apr_file_t on success.
+ * @param pool Pool to associate with the temp file. When the
+ * pool is destroyed, the temp file will be closed
+ * and deleted.
+ * @param path The base directory which will contain the temp file.
+ * If param == NULL, the directory will be selected via
+ * tempnam(). See the tempnam manpage for details.
+ *
+ * @return APR_SUCCESS.
+ * @return Error status code from unsuccessful apr_filepath_merge(),
+ * or a failed apr_file_mktemp().
+ */
+
+APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
+ apr_pool_t *pool,
+ const char *path);
+
+/**
+ * Set aside all buckets in the brigade.
+ *
+ * @param bb Brigade.
+ * @param p Setaside buckets into this pool.
+ * @return APR_SUCCESS.
+ * @return Error status code from an unsuccessful apr_bucket_setaside().
+ */
+
+static APR_INLINE
+apr_status_t apreq_brigade_setaside(apr_bucket_brigade *bb, apr_pool_t *p)
+{
+ apr_bucket *e;
+ for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ apr_status_t rv = apr_bucket_setaside(e, p);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+ return APR_SUCCESS;
+}
+
+
+/**
+ * Copy a brigade.
+ *
+ * @param d (destination) Copied buckets are appended to this brigade.
+ * @param s (source) Brigade to copy from.
+ *
+ * @return APR_SUCCESS.
+ * @return Error status code from an unsuccessful apr_bucket_copy().
+ *
+ * @remarks s == d produces Undefined Behavior.
+ */
+
+static APR_INLINE
+apr_status_t apreq_brigade_copy(apr_bucket_brigade *d, apr_bucket_brigade *s) {
+ apr_bucket *e;
+ for (e = APR_BRIGADE_FIRST(s); e != APR_BRIGADE_SENTINEL(s);
+ e = APR_BUCKET_NEXT(e))
+ {
+ apr_bucket *c;
+ apr_status_t rv = apr_bucket_copy(e, &c);
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ APR_BRIGADE_INSERT_TAIL(d, c);
+ }
+ return APR_SUCCESS;
+}
+
+/**
+ * Move the front of a brigade.
+ *
+ * @param d (destination) Append buckets to this brigade.
+ * @param s (source) Brigade to take buckets from.
+ * @param e First bucket of s after the move. All buckets
+ * before e are appended to d.
+ *
+ * @remarks This moves all buckets when e == APR_BRIGADE_SENTINEL(s).
+ */
+
+static APR_INLINE
+void apreq_brigade_move(apr_bucket_brigade *d, apr_bucket_brigade *s,
+ apr_bucket *e)
+{
+ apr_bucket *f;
+
+ if (e != APR_BRIGADE_SENTINEL(s)) {
+ f = APR_RING_FIRST(&s->list);
+ if (f == e) /* zero buckets to be moved */
+ return;
+
+ /* obtain the last bucket to be moved */
+ e = APR_RING_PREV(e, link);
+
+ APR_RING_UNSPLICE(f, e, link);
+ APR_RING_SPLICE_HEAD(&d->list, f, e, apr_bucket, link);
+ }
+ else {
+ APR_BRIGADE_CONCAT(d, s);
+ }
+}
+
+
+/**
+ * Search a header string for the value of a particular named attribute.
+ *
+ * @param hdr Header string to scan.
+ * @param name Name of attribute to search for.
+ * @param nlen Length of name.
+ * @param val Location of (first) matching value.
+ * @param vlen Length of matching value.
+ *
+ * @return APR_SUCCESS.
+ * @return ::APREQ_ERROR_NOATTR if the attribute is not found.
+ * @return ::APREQ_ERROR_BADSEQ if an unpaired quote mark was detected.
+ */
+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);
+
+
+/**
+ * Concatenates the brigades, spooling large brigades into
+ * a tempfile (APREQ_SPOOL) bucket.
+ *
+ * @param pool Pool for creating a tempfile bucket.
+ * @param temp_dir Directory for tempfile creation.
+ * @param brigade_limit If out's length would exceed this value,
+ * the appended buckets get written to a tempfile.
+ * @param out Resulting brigade.
+ * @param in Brigade to append.
+ *
+ * @return APR_SUCCESS.
+ * @return Error status code resulting from either apr_brigade_length(),
+ * apreq_file_mktemp(), apreq_brigade_fwrite(), or apr_file_seek().
+ *
+ * @todo Flesh out these error codes, making them as explicit as possible.
+ */
+APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
+ const char *temp_dir,
+ apr_size_t brigade_limit,
+ apr_bucket_brigade *out,
+ apr_bucket_brigade *in);
+
+/**
+ * Determines the spool file used by the brigade. Returns NULL if the
+ * brigade is not spooled in a file (does not use an APREQ_SPOOL
+ * bucket).
+ *
+ * @param bb the bucket brigade
+ * @return the spool file, or NULL.
+ */
+APREQ_DECLARE(apr_file_t *)apreq_brigade_spoolfile(apr_bucket_brigade *bb);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* APREQ_UTIL_H */
diff --git a/srclib/libapreq/include/apreq_version.h b/srclib/libapreq/include/apreq_version.h
new file mode 100644
index 0000000000..056dda7f47
--- /dev/null
+++ b/srclib/libapreq/include/apreq_version.h
@@ -0,0 +1,105 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_VERSION_H
+#define APREQ_VERSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "apr_version.h"
+#include "apreq.h"
+
+/**
+ * @file apreq_version.h
+ * @brief Versioning API for libapreq
+ * @ingroup libapreq2
+ *
+ * There are several different mechanisms for accessing the version. There
+ * is a string form, and a set of numbers; in addition, there are constants
+ * which can be compiled into your application, and you can query the library
+ * being used for its actual version.
+ *
+ * Note that it is possible for an application to detect that it has been
+ * compiled against a different version of libapreq by use of the compile-time
+ * constants and the use of the run-time query function.
+ *
+ * libapreq version numbering follows the guidelines specified in:
+ *
+ * http://apr.apache.org/versioning.html
+ */
+
+/* The numeric compile-time version constants. These constants are the
+ * authoritative version numbers for libapreq.
+ */
+
+/** major version
+ * Major API changes that could cause compatibility problems for older
+ * programs such as structure size changes. No binary compatibility is
+ * possible across a change in the major version.
+ */
+#define APREQ_MAJOR_VERSION 2
+
+/**
+ * Minor API changes that do not cause binary compatibility problems.
+ * Should be reset to 0 when upgrading APREQ_MAJOR_VERSION
+ */
+#define APREQ_MINOR_VERSION 6
+
+/** patch level */
+#define APREQ_PATCH_VERSION 3
+
+/**
+ * This symbol is defined for internal, "development" copies of libapreq.
+ * This symbol will be \#undef'd for releases.
+ */
+#define APREQ_IS_DEV_VERSION
+
+
+/** The formatted string of libapreq's version */
+#define APREQ_VERSION_STRING \
+ APR_STRINGIFY(APREQ_MAJOR_VERSION) "." \
+ APR_STRINGIFY(APREQ_MINOR_VERSION) "." \
+ APR_STRINGIFY(APREQ_PATCH_VERSION) \
+ APREQ_IS_DEV_STRING
+
+/**
+ * Return libapreq's version information information in a numeric form.
+ *
+ * @param pvsn Pointer to a version structure for returning the version
+ * information.
+ */
+APREQ_DECLARE(void) apreq_version(apr_version_t *pvsn);
+
+/** Return libapreq's version information as a string. */
+APREQ_DECLARE(const char *) apreq_version_string(void);
+
+
+/** Internal: string form of the "is dev" flag */
+#ifdef APREQ_IS_DEV_VERSION
+#define APREQ_IS_DEV_STRING "-dev"
+#else
+#define APREQ_IS_DEV_STRING ""
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* APREQ_VERSION_H */
diff --git a/srclib/libapreq/library/cookie.c b/srclib/libapreq/library/cookie.c
new file mode 100644
index 0000000000..4ee451718a
--- /dev/null
+++ b/srclib/libapreq/library/cookie.c
@@ -0,0 +1,662 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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 "apr_strings.h"
+#include "apreq_cookie.h"
+#include "apreq_error.h"
+#include "apreq_module.h"
+#include "apreq_util.h"
+#include "at.h"
+
+static const char nscookies[] = "a=1; foo=bar; fl=left; fr=right;bad; "
+ "ns=foo=1&bar=2,frl=right-left; "
+ "flr=left-right; fll=left-left; "
+ "good_one=1;=;bad";
+
+static const char rfccookies[] = "$Version=1; first=a;$domain=quux;second=be,"
+ "$Version=1;third=cie";
+
+static apr_table_t *jar, *jar2;
+static apr_pool_t *p;
+
+static void jar_make(dAT)
+{
+ jar = apr_table_make(p, APREQ_DEFAULT_NELTS);
+ AT_not_null(jar);
+ AT_int_eq(apreq_parse_cookie_header(p, jar, nscookies), APREQ_ERROR_NOTOKEN);
+ jar2 = apr_table_make(p, APREQ_DEFAULT_NELTS);
+ AT_not_null(jar2);
+ AT_int_eq(apreq_parse_cookie_header(p, jar2, rfccookies), APR_SUCCESS);
+}
+
+static void jar_get_rfc(dAT)
+{
+ const char *val;
+ AT_not_null(val = apr_table_get(jar2, "first"));
+ AT_str_eq(val, "a");
+ AT_not_null(val = apr_table_get(jar2, "second"));
+ AT_str_eq(val, "be");
+ AT_not_null(val = apr_table_get(jar2, "third"));
+ AT_str_eq(val, "cie");
+}
+
+static void jar_get_ns(dAT)
+{
+
+ AT_str_eq(apr_table_get(jar, "a"), "1");
+
+ /* ignore wacky cookies that don't have an '=' sign */
+ AT_is_null(apr_table_get(jar, "bad"));
+
+ /* accept wacky cookies that contain multiple '=' */
+ AT_str_eq(apr_table_get(jar, "ns"), "foo=1&bar=2");
+
+ AT_str_eq(apr_table_get(jar,"foo"), "bar");
+ AT_str_eq(apr_table_get(jar,"fl"), "left");
+ AT_str_eq(apr_table_get(jar,"fr"), "right");
+ AT_str_eq(apr_table_get(jar,"frl"), "right-left");
+ AT_str_eq(apr_table_get(jar,"flr"), "left-right");
+ AT_str_eq(apr_table_get(jar,"fll"), "left-left");
+ AT_is_null(apr_table_get(jar,""));
+}
+
+
+static void netscape_cookie(dAT)
+{
+ char expires[APR_RFC822_DATE_LEN];
+ char *val;
+ apreq_cookie_t *c;
+
+ *(const char **)&val = apr_table_get(jar, "foo");
+ AT_not_null(val);
+
+ c = apreq_value_to_cookie(val);
+
+ AT_str_eq(c->v.data, "bar");
+ AT_int_eq(apreq_cookie_version(c), 0);
+ AT_str_eq(apreq_cookie_as_string(c, p), "foo=bar");
+
+ c->domain = apr_pstrdup(p, "example.com");
+ AT_str_eq(apreq_cookie_as_string(c, p), "foo=bar; domain=example.com");
+
+ c->path = apr_pstrdup(p, "/quux");
+ AT_str_eq(apreq_cookie_as_string(c, p),
+ "foo=bar; path=/quux; domain=example.com");
+
+ apreq_cookie_expires(c, "+1y");
+ apr_rfc822_date(expires, apr_time_now()
+ + apr_time_from_sec(apreq_atoi64t("+1y")));
+ expires[7] = '-';
+ expires[11] = '-';
+ val = apr_pstrcat(p, "foo=bar; path=/quux; domain=example.com; expires=",
+ expires, NULL);
+
+ AT_str_eq(apreq_cookie_as_string(c, p), val);
+}
+
+
+static void rfc_cookie(dAT)
+{
+ apreq_cookie_t *c = apreq_cookie_make(p,"rfc",3,"out",3);
+ const char *expected;
+ long expires;
+
+ AT_str_eq(c->v.data, "out");
+
+ apreq_cookie_version_set(c, 1);
+ AT_int_eq(apreq_cookie_version(c), 1);
+ AT_str_eq(apreq_cookie_as_string(c,p),"rfc=out; Version=1");
+
+ c->domain = apr_pstrdup(p, "example.com");
+
+#ifndef WIN32
+
+ AT_str_eq(apreq_cookie_as_string(c,p),
+ "rfc=out; Version=1; domain=\"example.com\"");
+ c->path = apr_pstrdup(p, "/quux");
+ AT_str_eq(apreq_cookie_as_string(c,p),
+ "rfc=out; Version=1; path=\"/quux\"; domain=\"example.com\"");
+
+ apreq_cookie_expires(c, "+3m");
+ expires = apreq_atoi64t("+3m");
+ expected = apr_psprintf(p, "rfc=out; Version=1; path=\"/quux\"; "
+ "domain=\"example.com\"; max-age=%ld",
+ expires);
+ AT_str_eq(apreq_cookie_as_string(c,p), expected);
+
+#else
+
+ expected = "rfc=out; Version=1; domain=\"example.com\"";
+ AT_str_eq(apreq_cookie_as_string(c,p), expected);
+
+ c->path = apr_pstrdup(p, "/quux");
+ expected = "rfc=out; Version=1; path=\"/quux\"; domain=\"example.com\"";
+ AT_str_eq(apreq_cookie_as_string(c,p), expected);
+
+ apreq_cookie_expires(c, "+3m");
+ expires = apreq_atoi64t("+3m");
+ expected = apr_psprintf(p, "rfc=out; Version=1; path=\"/quux\"; "
+ "domain=\"example.com\"; max-age=%ld",
+ expires);
+ AT_str_eq(apreq_cookie_as_string(c,p), expected);
+
+#endif
+
+}
+
+
+#define dT(func, plan) #func, func, plan
+
+
+int main(int argc, char *argv[])
+{
+ unsigned i, plan = 0;
+ dAT;
+ at_test_t test_list [] = {
+ { dT(jar_make, 4) },
+ { dT(jar_get_rfc, 6), "1 3 5" },
+ { dT(jar_get_ns, 10) },
+ { dT(netscape_cookie, 7) },
+ { dT(rfc_cookie, 6) },
+ };
+
+ apr_initialize();
+ atexit(apr_terminate);
+
+ apr_pool_create(&p, NULL);
+
+ AT = at_create(p, 0, at_report_stdout_make(p));
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ plan += test_list[i].plan;
+
+ AT_begin(plan);
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ AT_run(&test_list[i]);
+
+ AT_end();
+
+ return 0;
+}
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_cookie.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_date.h"
+
+
+#define RFC 1
+#define NETSCAPE 0
+
+#define ADD_COOKIE(j,c) apreq_value_table_add(&c->v, j)
+
+APREQ_DECLARE(void) apreq_cookie_expires(apreq_cookie_t *c,
+ const char *time_str)
+{
+ if (time_str == NULL) {
+ c->max_age = -1;
+ return;
+ }
+
+ if (!strcasecmp(time_str, "now"))
+ c->max_age = 0;
+ else {
+ c->max_age = apr_date_parse_rfc(time_str);
+ if (c->max_age == APR_DATE_BAD)
+ c->max_age = apr_time_from_sec(apreq_atoi64t(time_str));
+ else
+ c->max_age -= apr_time_now();
+ }
+}
+
+static apr_status_t apreq_cookie_attr(apr_pool_t *p,
+ apreq_cookie_t *c,
+ const char *attr,
+ apr_size_t alen,
+ const char *val,
+ apr_size_t vlen)
+{
+ if (alen < 2)
+ return APR_EBADARG;
+
+ if ( attr[0] == '-' || attr[0] == '$' ) {
+ ++attr;
+ --alen;
+ }
+
+ switch (apr_tolower(*attr)) {
+
+ case 'n': /* name is not an attr */
+ return APR_ENOTIMPL;
+
+ case 'v': /* version; value is not an attr */
+ if (alen == 5 && strncasecmp(attr,"value", 5) == 0)
+ return APR_ENOTIMPL;
+
+ while (!apr_isdigit(*val)) {
+ if (vlen == 0)
+ return APREQ_ERROR_BADSEQ;
+ ++val;
+ --vlen;
+ }
+ apreq_cookie_version_set(c, *val - '0');
+ return APR_SUCCESS;
+
+ case 'e': case 'm': /* expires, max-age */
+ apreq_cookie_expires(c, val);
+ return APR_SUCCESS;
+
+ case 'd':
+ c->domain = apr_pstrmemdup(p,val,vlen);
+ return APR_SUCCESS;
+
+ case 'p':
+ if (alen != 4)
+ break;
+ if (!strncasecmp("port", attr, 4)) {
+ c->port = apr_pstrmemdup(p,val,vlen);
+ return APR_SUCCESS;
+ }
+ else if (!strncasecmp("path", attr, 4)) {
+ c->path = apr_pstrmemdup(p,val,vlen);
+ return APR_SUCCESS;
+ }
+ break;
+
+ case 'c':
+ if (!strncasecmp("commentURL", attr, 10)) {
+ c->commentURL = apr_pstrmemdup(p,val,vlen);
+ return APR_SUCCESS;
+ }
+ else if (!strncasecmp("comment", attr, 7)) {
+ c->comment = apr_pstrmemdup(p,val,vlen);
+ return APR_SUCCESS;
+ }
+ break;
+
+ case 's':
+ if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen))
+ apreq_cookie_secure_on(c);
+ else
+ apreq_cookie_secure_off(c);
+ return APR_SUCCESS;
+
+ };
+
+ return APR_ENOTIMPL;
+}
+
+APREQ_DECLARE(apreq_cookie_t *) apreq_cookie_make(apr_pool_t *p,
+ const char *name,
+ const apr_size_t nlen,
+ const char *value,
+ const apr_size_t vlen)
+{
+ apreq_cookie_t *c;
+ apreq_value_t *v;
+
+ c = apr_palloc(p, nlen + vlen + 1 + sizeof *c);
+
+ if (c == NULL)
+ return NULL;
+
+ *(const apreq_value_t **)&v = &c->v;
+
+ if (vlen > 0 && value != NULL)
+ memcpy(v->data, value, vlen);
+ v->data[vlen] = 0;
+ v->dlen = vlen;
+ v->name = v->data + vlen + 1;
+ if (nlen && name != NULL)
+ memcpy(v->name, name, nlen);
+ v->name[nlen] = 0;
+ v->nlen = nlen;
+
+ c->path = NULL;
+ c->domain = NULL;
+ c->port = NULL;
+ c->comment = NULL;
+ c->commentURL = NULL;
+ c->max_age = -1; /* session cookie is the default */
+ c->flags = 0;
+
+
+ return c;
+}
+
+static APR_INLINE
+apr_status_t get_pair(apr_pool_t *p, const char **data,
+ const char **n, apr_size_t *nlen,
+ const char **v, apr_size_t *vlen, unsigned unquote)
+{
+ const char *hdr, *key, *val;
+
+ hdr = *data;
+
+ while (apr_isspace(*hdr) || *hdr == '=')
+ ++hdr;
+
+ key = strchr(hdr, '=');
+
+ if (key == NULL)
+ return APREQ_ERROR_NOTOKEN;
+
+ val = key + 1;
+
+ do --key;
+ while (key > hdr && apr_isspace(*key));
+
+ *n = key;
+
+ while (key >= hdr && !apr_isspace(*key))
+ --key;
+
+ *nlen = *n - key;
+ *n = key + 1;
+
+ while (apr_isspace(*val))
+ ++val;
+
+ if (*val == '"') {
+ unsigned saw_backslash = 0;
+ for (*v = (unquote) ? ++val : val++; *val; ++val) {
+ switch (*val) {
+ case '"':
+ *data = val + 1;
+
+ if (!unquote) {
+ *vlen = (val - *v) + 1;
+ }
+ else if (!saw_backslash) {
+ *vlen = val - *v;
+ }
+ else {
+ char *dest = apr_palloc(p, val - *v), *d = dest;
+ const char *s = *v;
+ while (s < val) {
+ if (*s == '\\')
+ ++s;
+ *d++ = *s++;
+ }
+
+ *vlen = d - dest;
+ *v = dest;
+ }
+
+ return APR_SUCCESS;
+ case '\\':
+ saw_backslash = 1;
+ if (val[1] != 0)
+ ++val;
+ default:
+ break;
+ }
+ }
+ /* bad sequence: no terminating quote found */
+ return APREQ_ERROR_BADSEQ;
+ }
+ else {
+ /* value is not wrapped in quotes */
+ for (*v = val; *val; ++val) {
+ switch (*val) {
+ case ';':
+ case ',':
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ *data = val;
+ *vlen = val - *v;
+ return APR_SUCCESS;
+ default:
+ break;
+ }
+ }
+ }
+
+ *data = val;
+ *vlen = val - *v;
+
+ return APR_SUCCESS;
+}
+
+
+
+APREQ_DECLARE(apr_status_t)apreq_parse_cookie_header(apr_pool_t *p,
+ apr_table_t *j,
+ const char *hdr)
+{
+ apreq_cookie_t *c;
+ unsigned version;
+
+ parse_cookie_header:
+
+ c = NULL;
+ version = NETSCAPE;
+
+ while (apr_isspace(*hdr))
+ ++hdr;
+
+
+ if (*hdr == '$') {
+ /* XXX cheat: assume "$..." => "$Version" => RFC Cookie header */
+ version = RFC;
+ skip_version_string:
+ switch (*hdr++) {
+ case 0:
+ return APR_SUCCESS;
+ case ',':
+ goto parse_cookie_header;
+ case ';':
+ break;
+ default:
+ goto skip_version_string;
+ }
+ }
+
+ for (;;) {
+ apr_status_t status;
+ const char *name, *value;
+ apr_size_t nlen, vlen;
+
+ while (*hdr == ';' || apr_isspace(*hdr))
+ ++hdr;
+
+ switch (*hdr) {
+
+ case 0:
+ /* this is the normal exit point */
+ if (c != NULL) {
+ ADD_COOKIE(j, c);
+ }
+ return APR_SUCCESS;
+
+ case ',':
+ ++hdr;
+ if (c != NULL) {
+ ADD_COOKIE(j, c);
+ }
+ goto parse_cookie_header;
+
+ case '$':
+ if (c == NULL) {
+ return APREQ_ERROR_BADCHAR;
+ }
+ else if (version == NETSCAPE) {
+ return APREQ_ERROR_MISMATCH;
+ }
+
+ ++hdr;
+ status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 1);
+ if (status != APR_SUCCESS)
+ return status;
+
+ status = apreq_cookie_attr(p, c, name, nlen, value, vlen);
+
+ switch (status) {
+ case APR_ENOTIMPL:
+ /* XXX: skip unrecognized attr? Not really correct,
+ but for now, just fall through */
+
+ case APR_SUCCESS:
+ break;
+ default:
+ return status;
+ }
+
+ break;
+
+ default:
+ if (c != NULL) {
+ ADD_COOKIE(j, c);
+ }
+
+ status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 0);
+
+ if (status != APR_SUCCESS)
+ return status;
+
+ c = apreq_cookie_make(p, name, nlen, value, vlen);
+ apreq_cookie_tainted_on(c);
+ if (version != NETSCAPE)
+ apreq_cookie_version_set(c, version);
+ }
+ }
+
+ /* NOT REACHED */
+ return APREQ_ERROR_GENERAL;
+}
+
+
+APREQ_DECLARE(int) apreq_cookie_serialize(const apreq_cookie_t *c,
+ char *buf, apr_size_t len)
+{
+ /* The format string must be large enough to accomodate all
+ * of the cookie attributes. The current attributes sum to
+ * ~90 characters (w/ 6-8 padding chars per attr), so anything
+ * over 100 should be fine.
+ */
+
+ unsigned version = apreq_cookie_version(c);
+ char format[128] = "%s=%s";
+ char *f = format + strlen(format);
+
+ /* XXX protocol enforcement (for debugging, anyway) ??? */
+
+ if (c->v.name == NULL)
+ return -1;
+
+#define NULL2EMPTY(attr) (attr ? attr : "")
+
+
+ if (version == NETSCAPE) {
+ char expires[APR_RFC822_DATE_LEN] = {0};
+
+#define ADD_NS_ATTR(name) do { \
+ if (c->name != NULL) \
+ strcpy(f, "; " #name "=%s"); \
+ else \
+ strcpy(f, "%0.s"); \
+ f += strlen(f); \
+} while (0)
+
+ ADD_NS_ATTR(path);
+ ADD_NS_ATTR(domain);
+
+ if (c->max_age != -1) {
+ strcpy(f, "; expires=%s");
+ apr_rfc822_date(expires, c->max_age + apr_time_now());
+ expires[7] = '-';
+ expires[11] = '-';
+ }
+ else
+ strcpy(f, "");
+
+ f += strlen(f);
+
+ if (apreq_cookie_is_secure(c))
+ strcpy(f, "; secure");
+
+ return apr_snprintf(buf, len, format, c->v.name, c->v.data,
+ NULL2EMPTY(c->path), NULL2EMPTY(c->domain), expires);
+ }
+
+ /* c->version == RFC */
+
+ strcpy(f,"; Version=%u");
+ f += strlen(f);
+
+/* ensure RFC attributes are always quoted */
+#define ADD_RFC_ATTR(name) do { \
+ if (c->name != NULL) \
+ if (*c->name == '"') \
+ strcpy(f, "; " #name "=%s"); \
+ else \
+ strcpy(f, "; " #name "=\"%s\""); \
+ else \
+ strcpy(f, "%0.s"); \
+ f += strlen (f); \
+} while (0)
+
+ ADD_RFC_ATTR(path);
+ ADD_RFC_ATTR(domain);
+ ADD_RFC_ATTR(port);
+ ADD_RFC_ATTR(comment);
+ ADD_RFC_ATTR(commentURL);
+
+ strcpy(f, c->max_age != -1 ? "; max-age=%" APR_TIME_T_FMT : "");
+
+ f += strlen(f);
+
+ if (apreq_cookie_is_secure(c))
+ strcpy(f, "; secure");
+
+ return apr_snprintf(buf, len, format, c->v.name, c->v.data, version,
+ NULL2EMPTY(c->path), NULL2EMPTY(c->domain),
+ NULL2EMPTY(c->port), NULL2EMPTY(c->comment),
+ NULL2EMPTY(c->commentURL), apr_time_sec(c->max_age));
+}
+
+
+APREQ_DECLARE(char*) apreq_cookie_as_string(const apreq_cookie_t *c,
+ apr_pool_t *p)
+{
+ int n = apreq_cookie_serialize(c, NULL, 0);
+ char *s = apr_palloc(p, n + 1);
+ apreq_cookie_serialize(c, s, n + 1);
+ return s;
+}
+
diff --git a/srclib/libapreq/library/error.c b/srclib/libapreq/library/error.c
new file mode 100644
index 0000000000..7086648b35
--- /dev/null
+++ b/srclib/libapreq/library/error.c
@@ -0,0 +1,198 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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 "apr_strings.h"
+#include "apreq_error.h"
+#include "at.h"
+
+
+static void test_strerror(dAT)
+{
+ char buf[256], *str;
+
+ str = apreq_strerror(APREQ_ERROR_GENERAL, buf, sizeof buf);
+ AT_ptr_eq(str, buf);
+ AT_str_eq(str, "Internal apreq error");
+
+ str = apreq_strerror(APREQ_ERROR_TAINTED, buf, sizeof buf);
+ AT_str_eq(str, "Attempt to perform unsafe action with tainted data");
+
+ str = apreq_strerror(APREQ_ERROR_BADSEQ, buf, sizeof buf);
+ AT_str_eq(str, "Invalid byte sequence");
+
+ str = apreq_strerror(APREQ_ERROR_NODATA, buf, sizeof buf);
+ AT_str_eq(str, "Missing input data");
+
+ str = apreq_strerror(APREQ_ERROR_GENERAL+99, buf, sizeof buf);
+ AT_str_eq(str, "Error string not yet specified by apreq");
+
+
+
+
+ /* Test some common APR status codes also */
+
+ str = apreq_strerror(APR_EINIT, buf, sizeof buf);
+ AT_str_eq(str, "There is no error, this value signifies an initialized "
+ "error code");
+
+ str = apreq_strerror(APR_INCOMPLETE, buf, sizeof buf);
+ AT_str_eq(str, "Partial results are valid but processing is incomplete");
+
+ str = apreq_strerror(APR_EOF, buf, sizeof buf);
+ AT_str_eq(str, "End of file found");
+
+ str = apreq_strerror(APR_ENOTIMPL, buf, sizeof buf);
+ AT_str_eq(str, "This function has not been implemented on this platform");
+
+ }
+
+#define dT(func, plan) #func, func, plan
+
+
+int main(int argc, char *argv[])
+{
+ unsigned i, plan = 0;
+ apr_pool_t *p;
+ dAT;
+ at_test_t test_list [] = {
+ { dT(test_strerror, 10), "1" }
+ };
+
+ apr_initialize();
+ atexit(apr_terminate);
+
+ apr_pool_create(&p, NULL);
+
+ AT = at_create(p, 0, at_report_stdout_make(p));
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ plan += test_list[i].plan;
+
+ AT_begin(plan);
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ AT_run(&test_list[i]);
+
+ AT_end();
+
+ return 0;
+}
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "apr_strings.h"
+
+/*
+ * stuffbuffer - like apr_cpystrn() but returns the address of the
+ * dest buffer instead of the address of the terminating '\0'
+ */
+static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s)
+{
+ apr_cpystrn(buf,s,bufsize);
+ return buf;
+}
+
+static const char *apreq_error_string(apr_status_t statcode)
+{
+ switch (statcode) {
+
+
+/* 0's: generic error status codes */
+
+ case APREQ_ERROR_GENERAL:
+ return "Internal apreq error";
+
+ case APREQ_ERROR_TAINTED:
+ return "Attempt to perform unsafe action with tainted data";
+
+
+/* 10's: malformed input */
+
+ case APREQ_ERROR_BADDATA:
+ return "Malformed input data";
+
+ case APREQ_ERROR_BADCHAR:
+ return "Invalid character";
+
+ case APREQ_ERROR_BADSEQ:
+ return "Invalid byte sequence";
+
+ case APREQ_ERROR_BADATTR:
+ return "Unrecognized attribute";
+
+ case APREQ_ERROR_BADHEADER:
+ return "Malformed header string";
+
+
+/* 20's: missing input */
+
+ case APREQ_ERROR_NODATA:
+ return "Missing input data";
+
+ case APREQ_ERROR_NOTOKEN:
+ return "Expected token not present";
+
+ case APREQ_ERROR_NOATTR:
+ return "Missing attribute";
+
+ case APREQ_ERROR_NOHEADER:
+ return "Missing header";
+
+ case APREQ_ERROR_NOPARSER:
+ return "Missing parser";
+
+
+/* 30's: configuration conflicts */
+
+ case APREQ_ERROR_MISMATCH:
+ return "Conflicting information";
+
+ case APREQ_ERROR_OVERLIMIT:
+ return "Exceeds configured maximum limit";
+
+ case APREQ_ERROR_NOTEMPTY:
+ return "Setting already configured";
+
+
+ default:
+ return "Error string not yet specified by apreq";
+ }
+}
+
+
+APREQ_DECLARE(char *) apreq_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ if (statcode < APR_OS_START_USERERR || statcode >= APR_OS_START_EAIERR)
+ return apr_strerror(statcode, buf, bufsize);
+ return stuffbuffer(buf, bufsize, apreq_error_string(statcode));
+}
+
diff --git a/srclib/libapreq/library/module.c b/srclib/libapreq/library/module.c
new file mode 100644
index 0000000000..9ba5a765ed
--- /dev/null
+++ b/srclib/libapreq/library/module.c
@@ -0,0 +1,65 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_module.h"
+#include "apreq_error.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_file_io.h"
+
+APREQ_DECLARE(apreq_param_t *)apreq_param(apreq_handle_t *req, const char *key)
+{
+ apreq_param_t *param = apreq_args_get(req, key);
+ if (param == NULL)
+ return apreq_body_get(req, key);
+ else
+ return param;
+}
+
+APREQ_DECLARE(apr_table_t *)apreq_params(apreq_handle_t *req, apr_pool_t *p)
+{
+ const apr_table_t *args, *body;
+ apreq_args(req, &args);
+ apreq_body(req, &body);
+
+ if (args != NULL)
+ if (body != NULL)
+ return apr_table_overlay(p, args, body);
+ else
+ return apr_table_copy(p, args);
+ else
+ if (body != NULL)
+ return apr_table_copy(p, body);
+ else
+ return NULL;
+
+}
+
+APREQ_DECLARE(apr_table_t *)apreq_cookies(apreq_handle_t *req, apr_pool_t *p)
+{
+ const apr_table_t *jar;
+ apreq_jar(req, &jar);
+
+ if (jar != NULL)
+ return apr_table_copy(p, jar);
+ else
+ return NULL;
+
+}
+
+
+/** @} */
diff --git a/srclib/libapreq/library/module_cgi.c b/srclib/libapreq/library/module_cgi.c
new file mode 100644
index 0000000000..ff1abfaaa2
--- /dev/null
+++ b/srclib/libapreq/library/module_cgi.c
@@ -0,0 +1,689 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_module.h"
+#include "apreq_error.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_env.h"
+#include "apreq_util.h"
+
+#define USER_DATA_KEY "apreq"
+
+/* Parroting APLOG_* ... */
+
+#define CGILOG_EMERG 0 /* system is unusable */
+#define CGILOG_ALERT 1 /* action must be taken immediately */
+#define CGILOG_CRIT 2 /* critical conditions */
+#define CGILOG_ERR 3 /* error conditions */
+#define CGILOG_WARNING 4 /* warning conditions */
+#define CGILOG_NOTICE 5 /* normal but significant condition */
+#define CGILOG_INFO 6 /* informational */
+#define CGILOG_DEBUG 7 /* debug-level messages */
+
+#define CGILOG_LEVELMASK 7
+#define CGILOG_MARK __FILE__, __LINE__
+
+
+
+
+struct cgi_handle {
+ struct apreq_handle_t handle;
+
+ apr_table_t *jar, *args, *body;
+ apr_status_t jar_status,
+ args_status,
+ body_status;
+
+ apreq_parser_t *parser;
+ apreq_hook_t *hook_queue;
+ apreq_hook_t *find_param;
+
+ const char *temp_dir;
+ apr_size_t brigade_limit;
+ apr_uint64_t read_limit;
+ apr_uint64_t bytes_read;
+
+ apr_bucket_brigade *in;
+ apr_bucket_brigade *tmpbb;
+
+};
+
+#define CRLF "\015\012"
+
+typedef struct {
+ const char *t_name;
+ int t_val;
+} TRANS;
+
+static const TRANS priorities[] = {
+ {"emerg", CGILOG_EMERG},
+ {"alert", CGILOG_ALERT},
+ {"crit", CGILOG_CRIT},
+ {"error", CGILOG_ERR},
+ {"warn", CGILOG_WARNING},
+ {"notice", CGILOG_NOTICE},
+ {"info", CGILOG_INFO},
+ {"debug", CGILOG_DEBUG},
+ {NULL, -1},
+};
+
+static const char *cgi_header_in(apreq_handle_t *handle,
+ const char *name)
+{
+ apr_pool_t *p = handle->pool;
+ char *key = apr_pstrcat(p, "HTTP_", name, NULL);
+ char *k, *value = NULL;
+ for (k = key; *k; ++k) {
+ if (*k == '-')
+ *k = '_';
+ else
+ *k = apr_toupper(*k);
+ }
+
+ if (!strcmp(key, "HTTP_CONTENT_TYPE")
+ || !strcmp(key, "HTTP_CONTENT_LENGTH"))
+ {
+ key += 5; /* strlen("HTTP_") */
+ }
+
+ apr_env_get(&value, key, p);
+
+ return value;
+}
+
+
+
+
+static void cgi_log_error(const char *file, int line, int level,
+ apr_status_t status, apreq_handle_t *handle,
+ const char *fmt, ...)
+{
+ apr_pool_t *p = handle->pool;
+ char buf[256];
+ char *log_level_string, *ra;
+ const char *remote_addr;
+ unsigned log_level = CGILOG_WARNING;
+ char date[APR_CTIME_LEN];
+ va_list vp;
+#ifndef WIN32
+ apr_file_t *err;
+#endif
+
+ va_start(vp, fmt);
+
+ if (apr_env_get(&log_level_string, "LOG_LEVEL", p) == APR_SUCCESS)
+ log_level = (log_level_string[0] - '0');
+
+ level &= CGILOG_LEVELMASK;
+
+ if (level < (int)log_level) {
+
+ if (apr_env_get(&ra, "REMOTE_ADDR", p) == APR_SUCCESS)
+ remote_addr = ra;
+ else
+ remote_addr = "address unavailable";
+
+ apr_ctime(date, apr_time_now());
+
+#ifndef WIN32
+
+ apr_file_open_stderr(&err, p);
+ apr_file_printf(err, "[%s] [%s] [%s] %s(%d): %s: %s\n",
+ date, priorities[level].t_name, remote_addr, file, line,
+ apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp));
+ apr_file_flush(err);
+
+#else
+ fprintf(stderr, "[%s] [%s] [%s] %s(%d): %s: %s\n",
+ date, priorities[level].t_name, remote_addr, file, line,
+ apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp));
+#endif
+ }
+
+ va_end(vp);
+
+}
+
+
+APR_INLINE
+static const char *cgi_query_string(apreq_handle_t *handle)
+{
+ char *value = NULL, qs[] = "QUERY_STRING";
+ apr_env_get(&value, qs, handle->pool);
+ return value;
+}
+
+
+static void init_body(apreq_handle_t *handle)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ const char *cl_header = cgi_header_in(handle, "Content-Length");
+ apr_bucket_alloc_t *ba = handle->bucket_alloc;
+ apr_pool_t *pool = handle->pool;
+ apr_file_t *file;
+ apr_bucket *eos, *pipe;
+
+ req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+
+ if (cl_header != NULL) {
+ char *dummy;
+ apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 0);
+
+ if (dummy == NULL || *dummy != 0) {
+ req->body_status = APREQ_ERROR_BADHEADER;
+ cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
+ "Invalid Content-Length header (%s)", cl_header);
+ return;
+ }
+ else if ((apr_uint64_t)content_length > req->read_limit) {
+ req->body_status = APREQ_ERROR_OVERLIMIT;
+ cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
+ "Content-Length header (%s) exceeds configured "
+ "max_body limit (%" APR_UINT64_T_FMT ")",
+ cl_header, req->read_limit);
+ return;
+ }
+ }
+
+ if (req->parser == NULL) {
+ const char *ct_header = cgi_header_in(handle, "Content-Type");
+
+ if (ct_header != NULL) {
+ apreq_parser_function_t pf = apreq_parser(ct_header);
+
+ if (pf != NULL) {
+ req->parser = apreq_parser_make(pool,
+ ba,
+ ct_header,
+ pf,
+ req->brigade_limit,
+ req->temp_dir,
+ req->hook_queue,
+ NULL);
+ }
+ else {
+ req->body_status = APREQ_ERROR_NOPARSER;
+ return;
+ }
+ }
+ else {
+ req->body_status = APREQ_ERROR_NOHEADER;
+ return;
+ }
+ }
+ else {
+ if (req->parser->brigade_limit > req->brigade_limit)
+ req->parser->brigade_limit = req->brigade_limit;
+ if (req->temp_dir != NULL)
+ req->parser->temp_dir = req->temp_dir;
+ if (req->hook_queue != NULL)
+ apreq_parser_add_hook(req->parser, req->hook_queue);
+ }
+
+ req->hook_queue = NULL;
+ req->in = apr_brigade_create(pool, ba);
+ req->tmpbb = apr_brigade_create(pool, ba);
+
+ apr_file_open_stdin(&file, pool); // error status?
+ pipe = apr_bucket_pipe_create(file, ba);
+ eos = apr_bucket_eos_create(ba);
+ APR_BRIGADE_INSERT_HEAD(req->in, pipe);
+ APR_BRIGADE_INSERT_TAIL(req->in, eos);
+
+ req->body_status = APR_INCOMPLETE;
+
+}
+
+static apr_status_t cgi_read(apreq_handle_t *handle,
+ apr_off_t bytes)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ apr_bucket *e;
+ apr_status_t s;
+
+ if (req->body_status == APR_EINIT)
+ init_body(handle);
+
+ if (req->body_status != APR_INCOMPLETE)
+ return req->body_status;
+
+
+ switch (s = apr_brigade_partition(req->in, bytes, &e)) {
+ apr_off_t len;
+
+ case APR_SUCCESS:
+
+ apreq_brigade_move(req->tmpbb, req->in, e);
+ req->bytes_read += bytes;
+
+ if (req->bytes_read > req->read_limit) {
+ req->body_status = APREQ_ERROR_OVERLIMIT;
+ cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status,
+ handle, "Bytes read (%" APR_UINT64_T_FMT
+ ") exceeds configured limit (%" APR_UINT64_T_FMT ")",
+ req->bytes_read, req->read_limit);
+ break;
+ }
+
+ req->body_status =
+ apreq_parser_run(req->parser, req->body, req->tmpbb);
+ apr_brigade_cleanup(req->tmpbb);
+ break;
+
+
+ case APR_INCOMPLETE:
+
+ apreq_brigade_move(req->tmpbb, req->in, e);
+ s = apr_brigade_length(req->tmpbb, 1, &len);
+
+ if (s != APR_SUCCESS) {
+ req->body_status = s;
+ break;
+ }
+ req->bytes_read += len;
+
+ if (req->bytes_read > req->read_limit) {
+ req->body_status = APREQ_ERROR_OVERLIMIT;
+ cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
+ "Bytes read (%" APR_UINT64_T_FMT
+ ") exceeds configured limit (%" APR_UINT64_T_FMT ")",
+ req->bytes_read, req->read_limit);
+
+ break;
+ }
+
+ req->body_status =
+ apreq_parser_run(req->parser, req->body, req->tmpbb);
+ apr_brigade_cleanup(req->tmpbb);
+ break;
+
+ default:
+ req->body_status = s;
+ }
+
+ return req->body_status;
+}
+
+
+
+static apr_status_t cgi_jar(apreq_handle_t *handle,
+ const apr_table_t **t)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ if (req->jar_status == APR_EINIT) {
+ const char *cookies = cgi_header_in(handle, "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 cgi_args(apreq_handle_t *handle,
+ const apr_table_t **t)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ if (req->args_status == APR_EINIT) {
+ const char *qs = cgi_query_string(handle);
+ if (qs != NULL) {
+ req->args = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS);
+ req->args_status =
+ apreq_parse_query_string(handle->pool, req->args, qs);
+ }
+ else
+ req->args_status = APREQ_ERROR_NODATA;
+ }
+
+ *t = req->args;
+ return req->args_status;
+}
+
+
+
+
+static apreq_cookie_t *cgi_jar_get(apreq_handle_t *handle,
+ const char *name)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ const apr_table_t *t;
+ const char *val;
+
+ if (req->jar_status == APR_EINIT)
+ cgi_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 *cgi_args_get(apreq_handle_t *handle,
+ const char *name)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ const apr_table_t *t;
+ const char *val;
+
+ if (req->args_status == APR_EINIT)
+ cgi_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 cgi_body(apreq_handle_t *handle,
+ const apr_table_t **t)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ switch (req->body_status) {
+
+ case APR_EINIT:
+ init_body(handle);
+ if (req->body_status != APR_INCOMPLETE)
+ break;
+
+ case APR_INCOMPLETE:
+ while (cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE)
+ == APR_INCOMPLETE)
+ ; /*loop*/
+ }
+
+ *t = req->body;
+ return req->body_status;
+}
+
+static apreq_param_t *cgi_body_get(apreq_handle_t *handle,
+ const char *name)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ const char *val;
+ apreq_hook_t *h;
+
+ switch (req->body_status) {
+
+ case APR_SUCCESS:
+
+ val = apr_table_get(req->body, name);
+ if (val != NULL)
+ return apreq_value_to_param(val);
+ return NULL;
+
+
+ case APR_EINIT:
+
+ init_body(handle);
+ if (req->body_status != APR_INCOMPLETE)
+ return NULL;
+ cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE);
+
+
+ case APR_INCOMPLETE:
+
+ val = apr_table_get(req->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 (req->find_param == NULL)
+ req->find_param = apreq_hook_make(handle->pool,
+ apreq_hook_find_param,
+ NULL, NULL);
+ h = req->find_param;
+ h->next = req->parser->hook;
+ req->parser->hook = h;
+ h->ctx = (void *)name;
+
+ do {
+ cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE);
+ if (h->ctx != name) {
+ req->parser->hook = h->next;
+ return h->ctx;
+ }
+ } while (req->body_status == APR_INCOMPLETE);
+
+ req->parser->hook = h->next;
+ return NULL;
+
+
+ default:
+
+ if (req->body == NULL)
+ return NULL;
+
+ val = apr_table_get(req->body, name);
+ if (val != NULL)
+ return apreq_value_to_param(val);
+ return NULL;
+ }
+
+ /* not reached */
+ return NULL;
+}
+
+static apr_status_t cgi_parser_get(apreq_handle_t *handle,
+ const apreq_parser_t **parser)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ *parser = req->parser;
+ return APR_SUCCESS;
+}
+
+static apr_status_t cgi_parser_set(apreq_handle_t *handle,
+ apreq_parser_t *parser)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ if (req->parser == NULL) {
+
+ if (req->hook_queue != NULL) {
+ apr_status_t s = apreq_parser_add_hook(parser, req->hook_queue);
+ if (s != APR_SUCCESS)
+ return s;
+ }
+ if (req->temp_dir != NULL) {
+ parser->temp_dir = req->temp_dir;
+ }
+ if (req->brigade_limit < parser->brigade_limit) {
+ parser->brigade_limit = req->brigade_limit;
+ }
+
+ req->hook_queue = NULL;
+ req->parser = parser;
+ return APR_SUCCESS;
+ }
+ else
+ return APREQ_ERROR_MISMATCH;
+}
+
+
+static apr_status_t cgi_hook_add(apreq_handle_t *handle,
+ apreq_hook_t *hook)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ if (req->parser != NULL) {
+ return apreq_parser_add_hook(req->parser, hook);
+ }
+ else if (req->hook_queue != NULL) {
+ apreq_hook_t *h = req->hook_queue;
+ while (h->next != NULL)
+ h = h->next;
+ h->next = hook;
+ }
+ else {
+ req->hook_queue = hook;
+ }
+ return APR_SUCCESS;
+
+}
+
+static apr_status_t cgi_brigade_limit_set(apreq_handle_t *handle,
+ apr_size_t bytes)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ apr_size_t *limit = (req->parser == NULL)
+ ? &req->brigade_limit
+ : &req->parser->brigade_limit;
+
+ if (*limit > bytes) {
+ *limit = bytes;
+ return APR_SUCCESS;
+ }
+
+ return APREQ_ERROR_MISMATCH;
+}
+
+static apr_status_t cgi_brigade_limit_get(apreq_handle_t *handle,
+ apr_size_t *bytes)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ *bytes = (req->parser == NULL)
+ ? req->brigade_limit
+ : req->parser->brigade_limit;
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t cgi_read_limit_set(apreq_handle_t *handle,
+ apr_uint64_t bytes)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+
+ if (req->read_limit > bytes && req->bytes_read < bytes) {
+ req->read_limit = bytes;
+ return APR_SUCCESS;
+ }
+
+ return APREQ_ERROR_MISMATCH;
+}
+
+
+static apr_status_t cgi_read_limit_get(apreq_handle_t *handle,
+ apr_uint64_t *bytes)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ *bytes = req->read_limit;
+ return APR_SUCCESS;
+}
+
+
+static apr_status_t cgi_temp_dir_set(apreq_handle_t *handle,
+ const char *path)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ const char **temp_dir = (req->parser == NULL)
+ ? &req->temp_dir
+ : &req->parser->temp_dir;
+
+
+ if (*temp_dir == NULL && req->bytes_read == 0) {
+ if (path != NULL)
+ *temp_dir = apr_pstrdup(handle->pool, path);
+ return APR_SUCCESS;
+ }
+
+ return APREQ_ERROR_MISMATCH;
+}
+
+
+static apr_status_t cgi_temp_dir_get(apreq_handle_t *handle,
+ const char **path)
+{
+ struct cgi_handle *req = (struct cgi_handle *)handle;
+ *path = (req->parser == NULL)
+ ? req->temp_dir
+ : req->parser->temp_dir;
+ return APR_SUCCESS;
+}
+
+
+
+#ifdef APR_POOL_DEBUG
+static apr_status_t ba_cleanup(void *data)
+{
+ apr_bucket_alloc_t *ba = data;
+ apr_bucket_alloc_destroy(ba);
+ return APR_SUCCESS;
+}
+#endif
+
+static APREQ_MODULE(cgi, 20050425);
+
+APREQ_DECLARE(apreq_handle_t *)apreq_handle_cgi(apr_pool_t *pool)
+{
+ apr_bucket_alloc_t *ba;
+ struct cgi_handle *req;
+ void *data;
+
+ apr_pool_userdata_get(&data, USER_DATA_KEY, pool);
+
+ if (data != NULL)
+ return data;
+
+ req = apr_pcalloc(pool, sizeof *req);
+ ba = apr_bucket_alloc_create(pool);
+
+ /* check pool's userdata first. */
+
+ req->handle.module = &cgi_module;
+ req->handle.pool = pool;
+ req->handle.bucket_alloc = ba;
+ req->read_limit = (apr_uint64_t) -1;
+ req->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT;
+
+ req->args_status =
+ req->jar_status =
+ req->body_status = APR_EINIT;
+
+ apr_pool_userdata_setn(&req->handle, USER_DATA_KEY, NULL, pool);
+
+#ifdef APR_POOL_DEBUG
+ apr_pool_cleanup_register(pool, ba, ba_cleanup, ba_cleanup);
+#endif
+
+ return &req->handle;
+}
diff --git a/srclib/libapreq/library/module_custom.c b/srclib/libapreq/library/module_custom.c
new file mode 100644
index 0000000000..e1e6f58bfe
--- /dev/null
+++ b/srclib/libapreq/library/module_custom.c
@@ -0,0 +1,304 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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 "apr_strings.h"
+#include "apreq_module.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+
+#define READ_BYTES (64 * 1024)
+
+struct custom_handle {
+ struct apreq_handle_t handle;
+
+ apr_table_t *jar, *args, *body;
+ apr_status_t jar_status,
+ args_status,
+ body_status;
+
+ apreq_parser_t *parser;
+
+ apr_uint64_t read_limit;
+ apr_uint64_t bytes_read;
+ apr_bucket_brigade *in;
+ apr_bucket_brigade *tmpbb;
+};
+
+
+static apr_status_t custom_parse_brigade(apreq_handle_t *handle, apr_uint64_t bytes)
+{
+ struct custom_handle *req = (struct custom_handle *)handle;
+ apr_status_t s;
+ apr_bucket *e;
+
+ if (req->body_status != APR_INCOMPLETE)
+ return req->body_status;
+
+ switch (s = apr_brigade_partition(req->in, bytes, &e)) {
+ apr_off_t len;
+
+ case APR_SUCCESS:
+ apreq_brigade_move(req->tmpbb, req->in, e);
+ req->bytes_read += bytes;
+
+ if (req->bytes_read > req->read_limit) {
+ req->body_status = APREQ_ERROR_OVERLIMIT;
+ break;
+ }
+
+ req->body_status =
+ apreq_parser_run(req->parser, req->body, req->tmpbb);
+
+ apr_brigade_cleanup(req->tmpbb);
+ break;
+
+ case APR_INCOMPLETE:
+ apreq_brigade_move(req->tmpbb, req->in, e);
+ s = apr_brigade_length(req->tmpbb, 1, &len);
+ if (s != APR_SUCCESS) {
+ req->body_status = s;
+ break;
+ }
+ req->bytes_read += len;
+
+ if (req->bytes_read > req->read_limit) {
+ req->body_status = APREQ_ERROR_OVERLIMIT;
+ break;
+ }
+ req->body_status =
+ apreq_parser_run(req->parser, req->body, req->tmpbb);
+
+ apr_brigade_cleanup(req->tmpbb);
+ break;
+
+ default:
+ req->body_status = s;
+ }
+
+ return req->body_status;
+}
+
+
+
+static apr_status_t custom_jar(apreq_handle_t *handle, const apr_table_t **t)
+{
+ struct custom_handle *req = (struct custom_handle *)handle;
+ *t = req->jar;
+ return req->jar_status;
+}
+
+static apr_status_t custom_args(apreq_handle_t *handle, const apr_table_t **t)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ *t = req->args;
+ return req->args_status;
+}
+
+static apr_status_t custom_body(apreq_handle_t *handle, const apr_table_t **t)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ while (req->body_status == APR_INCOMPLETE)
+ custom_parse_brigade(handle, READ_BYTES);
+ *t = req->body;
+ return req->body_status;
+}
+
+
+
+static apreq_cookie_t *custom_jar_get(apreq_handle_t *handle, const char *name)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ const char *val;
+
+ if (req->jar == NULL || name == NULL)
+ return NULL;
+
+ val = apr_table_get(req->jar, name);
+
+ if (val == NULL)
+ return NULL;
+
+ return apreq_value_to_cookie(val);
+}
+
+static apreq_param_t *custom_args_get(apreq_handle_t *handle, const char *name)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ const char *val;
+
+ if (req->args == NULL || name == NULL)
+ return NULL;
+
+ val = apr_table_get(req->args, name);
+
+ if (val == NULL)
+ return NULL;
+
+ return apreq_value_to_param(val);
+}
+
+static apreq_param_t *custom_body_get(apreq_handle_t *handle, const char *name)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ const char *val;
+
+ if (req->body == NULL || name == NULL)
+ return NULL;
+
+ while (1) {
+ *(const char **)&val = apr_table_get(req->body, name);
+ if (val != NULL)
+ break;
+
+ if (req->body_status == APR_INCOMPLETE)
+ custom_parse_brigade(handle, READ_BYTES);
+ else
+ return NULL;
+ }
+
+ return apreq_value_to_param(val);
+}
+
+
+
+static apr_status_t custom_parser_get(apreq_handle_t *handle,
+ const apreq_parser_t **parser)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ *parser = req->parser;
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t custom_parser_set(apreq_handle_t *handle,
+ apreq_parser_t *parser)
+{
+ (void)handle;
+ (void)parser;
+ return APR_ENOTIMPL;
+}
+
+static apr_status_t custom_hook_add(apreq_handle_t *handle,
+ apreq_hook_t *hook)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ apreq_parser_add_hook(req->parser, hook);
+ return APR_SUCCESS;
+}
+
+static apr_status_t custom_brigade_limit_get(apreq_handle_t *handle,
+ apr_size_t *bytes)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ *bytes = req->parser->brigade_limit;
+ return APR_SUCCESS;
+}
+
+static apr_status_t custom_brigade_limit_set(apreq_handle_t *handle,
+ apr_size_t bytes)
+{
+ (void)handle;
+ (void)bytes;
+ return APR_ENOTIMPL;
+}
+
+static apr_status_t custom_read_limit_get(apreq_handle_t *handle,
+ apr_uint64_t *bytes)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+ *bytes = req->read_limit;
+ return APR_SUCCESS;
+}
+
+static apr_status_t custom_read_limit_set(apreq_handle_t *handle,
+ apr_uint64_t bytes)
+{
+ (void)handle;
+ (void)bytes;
+ return APR_ENOTIMPL;
+}
+
+static apr_status_t custom_temp_dir_get(apreq_handle_t *handle,
+ const char **path)
+{
+ struct custom_handle *req = (struct custom_handle*)handle;
+
+ *path = req->parser->temp_dir;
+ return APR_SUCCESS;
+}
+
+static apr_status_t custom_temp_dir_set(apreq_handle_t *handle,
+ const char *path)
+{
+ (void)handle;
+ (void)path;
+ return APR_ENOTIMPL;
+}
+
+
+static APREQ_MODULE(custom, 20070428);
+
+APREQ_DECLARE(apreq_handle_t *)apreq_handle_custom(apr_pool_t *pool,
+ const char *query_string,
+ const char *cookie,
+ apreq_parser_t *parser,
+ apr_uint64_t read_limit,
+ apr_bucket_brigade *in)
+{
+ struct custom_handle *req;
+ req = apr_palloc(pool, sizeof(*req));
+ req->handle.module = &custom_module;
+ req->handle.pool = pool;
+ req->handle.bucket_alloc = in->bucket_alloc;
+ req->read_limit = read_limit;
+ req->bytes_read = 0;
+ req->parser = parser;
+ req->in = apr_brigade_create(pool, in->bucket_alloc);
+ req->tmpbb = apr_brigade_create(pool, in->bucket_alloc);
+ req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+ req->body_status = APR_INCOMPLETE;
+ APR_BRIGADE_CONCAT(req->in, in);
+
+ if (cookie != NULL) {
+ req->jar = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+ req->jar_status =
+ apreq_parse_cookie_header(pool, req->jar, cookie);
+ }
+ else {
+ req->jar = NULL;
+ req->jar_status = APREQ_ERROR_NODATA;
+ }
+
+
+ if (query_string != NULL) {
+ req->args = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+ req->args_status =
+ apreq_parse_query_string(pool, req->args, query_string);
+ }
+ else {
+ req->args = NULL;
+ req->args_status = APREQ_ERROR_NODATA;
+ }
+
+ if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(req->in))) {
+ apr_bucket *eos = apr_bucket_eos_create(in->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(req->in, eos);
+ }
+
+ return &req->handle;
+}
+
diff --git a/srclib/libapreq/library/param.c b/srclib/libapreq/library/param.c
new file mode 100644
index 0000000000..83e185b595
--- /dev/null
+++ b/srclib/libapreq/library/param.c
@@ -0,0 +1,272 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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_param.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+
+#define MAX_LEN (1024 * 1024)
+#define MAX_BRIGADE_LEN (1024 * 256)
+#define MAX_READ_AHEAD (1024 * 64)
+
+
+APREQ_DECLARE(apreq_param_t *) apreq_param_make(apr_pool_t *p,
+ const char *name,
+ const apr_size_t nlen,
+ const char *val,
+ const apr_size_t vlen)
+{
+ apreq_param_t *param;
+ apreq_value_t *v;
+
+ param = apr_palloc(p, nlen + vlen + 1 + sizeof *param);
+
+ if (param == NULL)
+ return NULL;
+
+ param->info = NULL;
+ param->upload = NULL;
+ param->flags = 0;
+
+ *(const apreq_value_t **)&v = &param->v;
+
+ if (vlen && val != NULL)
+ memcpy(v->data, val, vlen);
+ v->data[vlen] = 0;
+ v->dlen = vlen;
+
+ v->name = v->data + vlen + 1;
+ if (nlen && name != NULL)
+ memcpy(v->name, name, nlen);
+ v->name[nlen] = 0;
+ v->nlen = nlen;
+
+ return param;
+}
+
+APREQ_DECLARE(apr_status_t) apreq_param_decode(apreq_param_t **param,
+ apr_pool_t *pool,
+ const char *word,
+ apr_size_t nlen,
+ apr_size_t vlen)
+{
+ apr_status_t status;
+ apreq_value_t *v;
+ apreq_param_t *p;
+ apreq_charset_t charset;
+
+ if (nlen == 0) {
+ *param = NULL;
+ return APR_EBADARG;
+ }
+
+ p = apr_palloc(pool, nlen + vlen + 1 + sizeof *p);
+ p->info = NULL;
+ p->upload = NULL;
+ p->flags = 0;
+ *(const apreq_value_t **)&v = &p->v;
+
+ if (vlen > 0) {
+ status = apreq_decode(v->data, &v->dlen, word + nlen + 1, vlen);
+ if (status != APR_SUCCESS) {
+ *param = NULL;
+ return status;
+ }
+ charset = apreq_charset_divine(v->data, v->dlen);
+ }
+ else {
+ v->data[0] = 0;
+ v->dlen = 0;
+ charset = APREQ_CHARSET_ASCII;
+ }
+ v->name = v->data + vlen + 1;
+
+ status = apreq_decode(v->name, &v->nlen, word, nlen);
+ if (status != APR_SUCCESS) {
+ *param = NULL;
+ return status;
+ }
+
+ switch (apreq_charset_divine(v->name, v->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;
+ }
+
+ apreq_param_charset_set(p, charset);
+ *param = p;
+
+ return APR_SUCCESS;
+}
+
+
+APREQ_DECLARE(char *) apreq_param_encode(apr_pool_t *pool,
+ const apreq_param_t *param)
+{
+ apr_size_t dlen;
+ char *data;
+ data = apr_palloc(pool, 3 * (param->v.nlen + param->v.dlen) + 2);
+ dlen = apreq_encode(data, param->v.name, param->v.nlen);
+ data[dlen++] = '=';
+ dlen += apreq_encode(data + dlen, param->v.data, param->v.dlen);
+
+ return data;
+}
+
+APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool,
+ apr_table_t *t,
+ const char *qs)
+{
+ const char *start = qs;
+ apr_size_t nlen = 0;
+
+ for (;;++qs) {
+ switch (*qs) {
+
+ case '=':
+ if (nlen == 0) {
+ nlen = qs - start;
+ }
+ break;
+
+ case '&':
+ case ';':
+ case 0:
+ if (qs > start) {
+ apr_size_t vlen = 0;
+ apreq_param_t *param;
+ apr_status_t s;
+ if (nlen == 0)
+ nlen = qs - start;
+ else
+ vlen = qs - start - nlen - 1;
+
+ s = apreq_param_decode(&param, pool, start, nlen, vlen);
+ if (s != APR_SUCCESS)
+ return s;
+
+ apreq_param_tainted_on(param);
+ apreq_value_table_add(&param->v, t);
+ }
+
+ if (*qs == 0)
+ return APR_SUCCESS;
+
+ nlen = 0;
+ start = qs + 1;
+ }
+ }
+ /* not reached */
+ return APR_INCOMPLETE;
+}
+
+
+
+
+static int param_push(void *data, const char *key, const char *val)
+{
+ apr_array_header_t *arr = data;
+ *(apreq_param_t **)apr_array_push(arr) =
+ apreq_value_to_param(val);
+ return 1; /* keep going */
+}
+
+
+APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p,
+ const apr_table_t *t,
+ const char *key)
+{
+ apr_array_header_t *arr;
+
+ arr = apr_array_make(p, apr_table_elts(t)->nelts,
+ sizeof(apreq_param_t *));
+
+ apr_table_do(param_push, arr, t, key, NULL);
+ return arr;
+}
+
+APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p,
+ const apr_table_t *t,
+ const char *key,
+ apreq_join_t mode)
+{
+ apr_array_header_t *arr = apreq_params_as_array(p, t, key);
+ apreq_param_t **elt = (apreq_param_t **)arr->elts;
+ apreq_param_t **const end = elt + arr->nelts;
+ if (arr->nelts == 0)
+ return apr_pstrdup(p, "");
+
+ while (elt < end) {
+ *(const apreq_value_t **)elt = &(**elt).v;
+ ++elt;
+ }
+ return apreq_join(p, ", ", arr, mode);
+}
+
+
+
+static int upload_push(void *data, const char *key, const char *val)
+{
+ apr_table_t *t = data;
+ apreq_param_t *p = apreq_value_to_param(val);
+
+ if (p->upload != NULL)
+ apreq_value_table_add(&p->v, t);
+ return 1; /* keep going */
+}
+
+
+APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body,
+ apr_pool_t *pool)
+{
+ apr_table_t *t = apr_table_make(pool, APREQ_DEFAULT_NELTS);
+ apr_table_do(upload_push, t, body, NULL);
+ return t;
+}
+
+static int upload_set(void *data, const char *key, const char *val)
+{
+ const apreq_param_t **q = data;
+ apreq_param_t *p = apreq_value_to_param(val);
+
+ if (p->upload != NULL) {
+ *q = p;
+ return 0; /* upload found, stop */
+ }
+ else
+ return 1; /* keep searching */
+}
+
+
+APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body,
+ const char *name)
+{
+ apreq_param_t *param = NULL;
+ apr_table_do(upload_set, &param, body, name, NULL);
+ return param;
+}
diff --git a/srclib/libapreq/library/parser.c b/srclib/libapreq/library/parser.c
new file mode 100644
index 0000000000..1d7c46dceb
--- /dev/null
+++ b/srclib/libapreq/library/parser.c
@@ -0,0 +1,353 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+}
diff --git a/srclib/libapreq/library/parser_header.c b/srclib/libapreq/library/parser_header.c
new file mode 100644
index 0000000000..ae2e030062
--- /dev/null
+++ b/srclib/libapreq/library/parser_header.c
@@ -0,0 +1,365 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+}
diff --git a/srclib/libapreq/library/parser_multipart.c b/srclib/libapreq/library/parser_multipart.c
new file mode 100644
index 0000000000..60b5bad9de
--- /dev/null
+++ b/srclib/libapreq/library/parser_multipart.c
@@ -0,0 +1,661 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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.
+ */
+
+ /* give hints to GCC by making the brigade volatile, otherwise the
+ * loop below will end up being endless. See:
+ * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=193740
+ */
+ apr_bucket_brigade * volatile in_v = in;
+
+ do {
+ apr_bucket *f = APR_BRIGADE_FIRST(in_v);
+ APR_BUCKET_REMOVE(f);
+ APR_BRIGADE_INSERT_TAIL(out, f);
+ } while (e != APR_BRIGADE_FIRST(in_v));
+ 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;
+}
diff --git a/srclib/libapreq/library/parser_urlencoded.c b/srclib/libapreq/library/parser_urlencoded.c
new file mode 100644
index 0000000000..e90d0dd382
--- /dev/null
+++ b/srclib/libapreq/library/parser_urlencoded.c
@@ -0,0 +1,275 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+}
+
+
diff --git a/srclib/libapreq/library/util.c b/srclib/libapreq/library/util.c
new file mode 100644
index 0000000000..f982309d97
--- /dev/null
+++ b/srclib/libapreq/library/util.c
@@ -0,0 +1,1508 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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 "apr_strings.h"
+#include "apreq_error.h"
+#include "apreq_util.h"
+#include "at.h"
+
+
+static void test_atoi64f(dAT)
+{
+ AT_int_eq(apreq_atoi64f("0"), 0);
+ AT_int_eq(apreq_atoi64f("-1"), -1);
+ AT_int_eq(apreq_atoi64f("-"), 0);
+ AT_int_eq(apreq_atoi64f("5"), 5);
+ AT_int_eq(apreq_atoi64f("3.333"), 3);
+ AT_int_eq(apreq_atoi64f("33k"), 33 * 1024);
+ AT_int_eq(apreq_atoi64f(" +8M "), 8 * 1024 * 1024);
+ AT_ok(apreq_atoi64f("44GB") == (apr_int64_t)44 * 1024 * 1024 * 1024,
+ "44GB test");
+ AT_ok(apreq_atoi64f("0xaBcDefg") == (apr_int64_t)11259375 * 1024 * 1024 * 1024,
+ "hex test");
+}
+
+static void test_atoi64t(dAT)
+{
+ AT_int_eq(apreq_atoi64t("0"), 0);
+ AT_int_eq(apreq_atoi64t("-1"), -1);
+ AT_int_eq(apreq_atoi64t("-g088l3dyg00k"), 0);
+ AT_int_eq(apreq_atoi64t("5s"), 5);
+ AT_int_eq(apreq_atoi64t("3.333"), 3);
+ AT_int_eq(apreq_atoi64t("33d"), 33 * 60 * 60 * 24);
+ AT_int_eq(apreq_atoi64t(" +8M "), 8 * 60 * 60 * 24 * 30);
+ AT_int_eq(apreq_atoi64t("+9m"), 9 * 60);
+ AT_int_eq(apreq_atoi64t("6h"), 6 * 60 * 60);
+
+}
+
+static void test_index(dAT)
+{
+ const char haystack[] = "Four score and seven years ago";
+ apr_size_t hlen = sizeof haystack - 1;
+ AT_int_eq(apreq_index(haystack, hlen, "Four", 4, APREQ_MATCH_FULL),
+ 0);
+ AT_int_eq(apreq_index(haystack, hlen, "Four", 4, APREQ_MATCH_PARTIAL),
+ 0);
+ AT_int_eq(apreq_index(haystack, hlen, "Fourteen", 8, APREQ_MATCH_FULL),
+ -1);
+ AT_int_eq(apreq_index(haystack, hlen, "Fourteen", 8, APREQ_MATCH_PARTIAL),
+ -1);
+ AT_int_eq(apreq_index(haystack, hlen, "agoraphobia", 11, APREQ_MATCH_FULL),
+ -1);
+ AT_int_eq(apreq_index(haystack, hlen, "agoraphobia", 11, APREQ_MATCH_PARTIAL),
+ hlen - 3);
+}
+
+#define A_GRAVE 0xE5
+#define KATAKANA_A 0xFF71
+
+static void test_decode(dAT)
+{
+ apr_size_t elen;
+ char src1[] = "%C3%80%E3%82%a2"; /* A_GRAVE KATAKANA_A as utf8 */
+ unsigned char expect[6];
+
+ AT_int_eq(apreq_decode((char *)expect, &elen, src1, sizeof(src1) -1),
+ APR_SUCCESS);
+ AT_int_eq(elen, 5);
+ AT_int_eq(expect[0], 0xC3);
+ AT_int_eq(expect[1], 0x80);
+ AT_int_eq(expect[2], 0xE3);
+ AT_int_eq(expect[3], 0x82);
+ AT_int_eq(expect[4], 0xA2);
+}
+
+static void test_charset_divine(dAT)
+{
+ apr_size_t elen;
+ char src1[] = "%C3%80%E3%82%a2"; /* A_GRAVE KATAKANA_A as utf8 */
+ char src2[] = "pound%A3";/* latin-1 */
+ char src3[] = "euro%80";/* cp-1252 */
+ char expect[7];
+
+ AT_int_eq(apreq_decode(expect, &elen, src1, sizeof(src1) -1),
+ APR_SUCCESS);
+
+ AT_int_eq(apreq_charset_divine(expect, elen), APREQ_CHARSET_UTF8);
+
+ AT_int_eq(apreq_decode(expect, &elen, src2, sizeof(src2) -1),
+ APR_SUCCESS);
+
+ AT_int_eq(apreq_charset_divine(expect, elen), APREQ_CHARSET_LATIN1);
+ AT_int_eq(apreq_decode(expect, &elen, src3, sizeof(src3) -1),
+ APR_SUCCESS);
+
+ AT_int_eq(apreq_charset_divine(expect, elen), APREQ_CHARSET_CP1252);
+
+}
+
+
+static void test_decodev(dAT)
+{
+ char src1[] = "%2540%2";
+ char src2[] = "0%u0";
+ char src3[] = "041";
+ struct iovec iovec1[] = {
+ { src1, sizeof(src1) - 1 },
+ { src2, sizeof(src2) - 1 },
+ { src3, sizeof(src3) - 1 },
+ };
+ struct iovec iovec2[] = {
+ { src1, sizeof(src1) - 1 },
+ { src2, sizeof(src2) - 1 },
+ };
+ const char expect1[] = "%40 A";
+ const char expect2[] = "%40 ";
+ char dest[sizeof(src1) + sizeof(src2) + sizeof(src3)];
+ apr_size_t dest_len;
+ apr_status_t status;
+
+ status = apreq_decodev(dest, &dest_len, iovec1, 3);
+ AT_int_eq(status, APR_SUCCESS);
+ AT_int_eq(dest_len, sizeof(expect1) - 1);
+ AT_mem_eq(dest, expect1, sizeof(expect1) - 1);
+
+ status = apreq_decodev(dest, &dest_len, iovec2, 2);
+ AT_int_eq(status, APR_INCOMPLETE);
+ AT_int_eq(dest_len, sizeof(expect2) - 1);
+ AT_mem_eq(dest, expect2, sizeof(expect2) - 1);
+}
+
+
+static void test_encode(dAT)
+{
+
+}
+
+static void test_cp1252_to_utf8(dAT)
+{
+ char src1[] = "%C3%80%E3%82%a2"; /* A_GRAVE KATAKANA_A as utf8 */
+ char src2[5];
+ unsigned char expect[16];
+ apr_size_t slen;
+
+ AT_int_eq(apreq_decode((char *)src2, &slen, src1, sizeof(src1) -1),
+ APR_SUCCESS);
+ AT_int_eq(apreq_cp1252_to_utf8((char *)expect, src2, 5),
+ 12);
+
+ /* 0xC3 */
+ AT_int_eq(expect[0], 0xC0 | (0xC3 >> 6));
+ AT_int_eq(expect[1], 0xC3 - 0x40);
+
+ /* 0x20AC */
+ AT_int_eq(expect[2], 0xE0 | (0x20AC >> 12));
+ AT_int_eq(expect[3], 0x80 | ((0x20AC >> 6) & 0x3F));
+ AT_int_eq(expect[4], 0x80 | (0x20AC & 0x3F));
+
+ /* 0xE3 */
+ AT_int_eq(expect[5], 0xC3);
+ AT_int_eq(expect[6], 0xE3 - 0x40);
+
+ /* 0x201A */
+ AT_int_eq(expect[7], 0xE0 | (0x201A >> 12));
+ AT_int_eq(expect[8], 0x80 | ((0x201A >> 6) & 0x3F));
+ AT_int_eq(expect[9], 0x80 | (0x201A & 0x3F));
+
+
+ /* 0xA2 */
+ AT_int_eq(expect[10], 0xC0 | (0xA2 >> 6));
+ AT_int_eq(expect[11], 0xA2);
+
+}
+
+static void test_quote(dAT)
+{
+ size_t len;
+ char dst[64];
+
+ len = apreq_quote(dst, "foo", 3);
+ AT_int_eq(len, 5);
+ AT_str_eq(dst, "\"foo\"");
+
+ len = apreq_quote(dst, "\"foo", 4);
+ AT_int_eq(len, 7);
+ AT_str_eq(dst, "\"\\\"foo\"");
+
+ len = apreq_quote(dst, "foo\\bar", 7);
+ AT_int_eq(len, 10);
+ AT_str_eq(dst, "\"foo\\\\bar\"");
+
+ len = apreq_quote(dst, "foo\0bar", 7);
+ AT_int_eq(len, 10);
+ AT_str_eq(dst, "\"foo\\0bar\"");
+}
+
+static void test_quote_once(dAT)
+{
+ size_t len;
+ char dst[64];
+
+ len = apreq_quote_once(dst, "foo", 3);
+ AT_int_eq(len, 5);
+ AT_str_eq(dst, "\"foo\"");
+
+ len = apreq_quote_once(dst, "\"foo", 4);
+ AT_int_eq(len, 7);
+ AT_str_eq(dst, "\"\\\"foo\"");
+
+ len = apreq_quote_once(dst, "foo\"", 4);
+ AT_int_eq(len, 7);
+ AT_str_eq(dst, "\"foo\\\"\"");
+
+ len = apreq_quote_once(dst, "foo\0bar", 7);
+ AT_int_eq(len, 10);
+ AT_str_eq(dst, "\"foo\\0bar\"");
+
+ /* null byte must be escaped, even when there are already double
+ quotes */
+ len = apreq_quote_once(dst, "\"foo\0bar\"", 9);
+ AT_int_eq(len, 14);
+ AT_str_eq(dst, "\"\\\"foo\\0bar\\\"\"");
+
+ len = apreq_quote_once(dst, "\"foo\"", 5);
+ AT_int_eq(len, 5);
+ AT_str_eq(dst, "\"foo\"");
+
+ len = apreq_quote_once(dst, "'foo'", 5);
+ AT_int_eq(len, 7);
+ AT_str_eq(dst, "\"'foo'\"");
+
+ len = apreq_quote_once(dst, "\"fo\\o\"", 6);
+ AT_int_eq(len, 6);
+ AT_str_eq(dst, "\"fo\\o\"");
+
+ len = apreq_quote_once(dst, "\"foo\"bar\"", 9);
+ AT_int_eq(len, 14);
+ AT_str_eq(dst, "\"\\\"foo\\\"bar\\\"\"");
+}
+
+static void test_join(dAT)
+{
+
+}
+
+static void test_brigade_fwrite(dAT)
+{
+
+}
+
+static void test_file_mktemp(dAT)
+{
+
+
+}
+
+static void test_header_attribute(dAT)
+{
+ const char hdr[] = "filename=\"filename=foo\" filename=\"quux.txt\"";
+ const char *val;
+ apr_size_t vlen;
+
+ AT_int_eq(apreq_header_attribute(hdr+4, "name", 4, &val, &vlen),
+ APR_SUCCESS);
+ AT_int_eq(vlen, 12);
+ AT_mem_eq("filename=foo", val, 12);
+
+ AT_int_eq(apreq_header_attribute(hdr+4, "filename", 8, &val, &vlen),
+ APR_SUCCESS);
+ AT_int_eq(vlen, 8);
+ AT_mem_eq("quux.txt", val, 8);
+
+}
+
+static void test_brigade_concat(dAT)
+{
+
+}
+
+
+
+#define dT(func, plan) #func, func, plan
+
+
+int main(int argc, char *argv[])
+{
+ unsigned i, plan = 0;
+ apr_pool_t *p;
+ dAT;
+ at_test_t test_list [] = {
+ { dT(test_atoi64f, 9) },
+ { dT(test_atoi64t, 9) },
+ { dT(test_index, 6) },
+ { dT(test_decode, 7) },
+ { dT(test_charset_divine, 6) },
+ { dT(test_decodev, 6) },
+ { dT(test_encode, 0) },
+ { dT(test_cp1252_to_utf8, 14) },
+ { dT(test_quote, 8) },
+ { dT(test_quote_once, 18), },
+ { dT(test_join, 0) },
+ { dT(test_brigade_fwrite, 0) },
+ { dT(test_file_mktemp, 0) },
+ { dT(test_header_attribute, 6) },
+ { dT(test_brigade_concat, 0) },
+ };
+
+ apr_initialize();
+ atexit(apr_terminate);
+
+ apr_pool_create(&p, NULL);
+
+ AT = at_create(p, 0, at_report_stdout_make(p));
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ plan += test_list[i].plan;
+
+ AT_begin(plan);
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ AT_run(&test_list[i]);
+
+ AT_end();
+
+ return 0;
+}
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+}
+
+/*
+ * This is intentionally not apr_file_writev()
+ * note, this is iterative and not recursive
+ */
+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;
+
+#ifdef SOLARIS2
+# ifdef __GNUC__
+ /*
+ * iovec.iov_len is a long here
+ * which causes a comparison between
+ * signed(long) and unsigned(apr_size_t)
+ *
+ */
+ while (n < *nelts && len >= (apr_size_t)v[n].iov_len)
+# else
+ /*
+ * Sun C however defines this as size_t which is unsigned
+ *
+ */
+ while (n < *nelts && len >= v[n].iov_len)
+# endif /* !__GNUC__ */
+#else
+ /*
+ * Hopefully everything else does this
+ * (this was the default for years)
+ */
+ while (n < *nelts && len >= v[n].iov_len)
+#endif
+ 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;
+ }
+}
+
+
+
+
+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;
+ apr_int32_t flag;
+
+ 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);
+
+ /* NO APR_DELONCLOSE! see comment above */
+ flag = APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_BINARY;
+
+ rc = apr_file_mktemp(fp, tmpl, flag, 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;
+}
+
+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, *first;
+ int n = 0;
+ apr_bucket_brigade *tmp = bb;
+ *wlen = 0;
+
+ if (BUCKET_IS_SPOOL(APR_BRIGADE_LAST(bb))) {
+ tmp = apr_brigade_create(bb->p, bb->bucket_alloc);
+
+ s = apreq_brigade_copy(tmp, bb);
+ if (s != APR_SUCCESS)
+ return s;
+ }
+
+ for (e = APR_BRIGADE_FIRST(tmp); e != APR_BRIGADE_SENTINEL(tmp);
+ 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;
+
+ if (tmp != bb) {
+ while ((first = APR_BRIGADE_FIRST(tmp)) != e)
+ apr_bucket_delete(first);
+ }
+
+ *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;
+
+ if (tmp != bb) {
+ while ((first = APR_BRIGADE_FIRST(tmp)) != e)
+ apr_bucket_delete(first);
+ }
+ }
+ return APR_SUCCESS;
+}
diff --git a/srclib/libapreq/library/version.c b/srclib/libapreq/library/version.c
new file mode 100644
index 0000000000..05ebca54b3
--- /dev/null
+++ b/srclib/libapreq/library/version.c
@@ -0,0 +1,105 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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 "at.h"
+
+static void version_string(dAT)
+{
+ const char *vstring = apreq_version_string();
+ AT_not_null(vstring);
+ AT_str_eq(vstring, APREQ_VERSION_STRING);
+}
+static void version_type(dAT)
+{
+ apr_version_t v;
+ apreq_version(&v);
+ AT_int_eq(v.major, APREQ_MAJOR_VERSION);
+ AT_int_eq(v.minor, APREQ_MINOR_VERSION);
+ AT_int_eq(v.patch, APREQ_PATCH_VERSION);
+#ifdef APREQ_IS_DEV_VERSION
+ AT_int_eq(v.is_dev, 1);
+#else
+ AT_int_eq(v.is_dev, 0);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ apr_pool_t *p;
+ unsigned i, plan = 0;
+ dAT;
+ at_test_t test_list [] = {
+ {"version_string", version_string, 2, "1"},
+ {"version_type", version_type, 4}
+ };
+
+ apr_initialize();
+ atexit(apr_terminate);
+
+ apr_pool_create(&p, NULL);
+
+ AT = at_create(p, 0, at_report_stdout_make(p));
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ plan += test_list[i].plan;
+
+ AT_begin(plan);
+
+ for (i = 0; i < sizeof(test_list) / sizeof(at_test_t); ++i)
+ AT_run(&test_list[i]);
+
+ AT_end();
+
+ return 0;
+}
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You 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;
+}