@@ -0,0 +1,299 @@
+/********************************************************************
+ Copyright (c) 2004-6, WebThing Ltd
+ Author: Nick Kew <nick@webthing.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*********************************************************************/
+
+#include <httpd.h>
+#include <http_config.h>
+#include <http_request.h>
+#include <util_filter.h>
+#include <apr_strings.h>
+#include <http_log.h>
+#include <http_protocol.h>
+
+#include "mod_form.h"
+
+module AP_MODULE_DECLARE_DATA form_module ;
+static const char* form_std_delim = "&" ;
+
+
+typedef struct {
+ size_t maxsize ;
+ int post ;
+ int get ;
+ const char* delim ;
+} form_conf ;
+typedef struct {
+ apr_table_t* vars ;
+ size_t len ;
+ int eos ;
+ char delim;
+} form_ctx ;
+
+static apr_table_t* form_data(request_rec* r) {
+ form_ctx* ctx = ap_get_module_config(r->request_config, &form_module) ;
+ return ctx ? ctx->vars : NULL ;
+}
+static const char* form_value(request_rec* r, const char* arg) {
+ form_ctx* ctx = ap_get_module_config(r->request_config, &form_module) ;
+ if ( ! ctx || ! ctx->vars )
+ return NULL ;
+ return apr_table_get(ctx->vars, arg) ;
+}
+
+static void form_decode(request_rec* r, char* args, const char* delim) {
+ form_ctx* ctx = ap_get_module_config(r->request_config, &form_module ) ;
+ char* pair ;
+ char* last = NULL ;
+ char* eq ;
+ if ( ! ctx ) {
+ ctx = apr_pcalloc(r->pool, sizeof(form_ctx)) ;
+ ctx->delim = delim[0];
+ ap_set_module_config(r->request_config, &form_module, ctx) ;
+ }
+ if ( ! ctx->vars ) {
+ ctx->vars = apr_table_make(r->pool, 10) ;
+ }
+ for ( pair = apr_strtok(args, delim, &last) ; pair ;
+ pair = apr_strtok(NULL, delim, &last) ) {
+ for (eq = pair ; *eq ; ++eq)
+ if ( *eq == '+' )
+ *eq = ' ' ;
+ ap_unescape_url(pair) ;
+ eq = strchr(pair, '=') ;
+ if ( eq ) {
+ *eq++ = 0 ;
+ apr_table_merge(ctx->vars, pair, eq) ;
+ } else {
+ apr_table_merge(ctx->vars, pair, "") ;
+ }
+ }
+}
+#define BUFSZ 8192
+static apr_status_t form_filter(ap_filter_t *f, apr_bucket_brigade *bbout,
+ ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) {
+ form_ctx* ctx ;
+ char* leftover = NULL ;
+ char* eq ;
+ char* delim ;
+ char* pair ;
+ apr_bucket* b ;
+ apr_bucket* nextb ;
+ apr_bucket_brigade* bb ;
+ int rv ;
+ int rstat ;
+ const char* buf ;
+ size_t llen ;
+ size_t bytes ;
+ size_t readbytes = BUFSZ ;
+
+ if ( ! f->ctx ) {
+ f->ctx = ap_get_module_config(f->r->request_config, &form_module ) ;
+ }
+ ctx = f->ctx ;
+
+ if ( ctx->eos ) {
+ APR_BRIGADE_INSERT_TAIL(bbout, apr_bucket_eos_create(bbout->bucket_alloc));
+ }
+
+ if ( ! ctx->vars ) {
+ ctx->vars = apr_table_make(f->r->pool, 10) ;
+ }
+
+ bb = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc) ;
+ do {
+ rv = ap_get_brigade(f->next, bb, AP_MODE_READBYTES,
+ APR_BLOCK_READ, readbytes) ;
+ if ( (rv != APR_SUCCESS ) && ( rv != APR_EAGAIN) ) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "Reading form data");
+ return rv ;
+ }
+ for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = nextb) {
+ nextb = APR_BUCKET_NEXT(b) ;
+ APR_BUCKET_REMOVE(b) ;
+ APR_BRIGADE_INSERT_TAIL(bbout, b) ;
+ if ( APR_BUCKET_IS_EOS(b) ) {
+ ctx->eos = 1 ;
+ /* we still have data in leftover - now it's a complete arg=val */
+ if ( leftover ) {
+ pair = leftover ;
+ for (eq = pair ; *eq ; ++eq)
+ if ( *eq == '+' )
+ *eq = ' ' ;
+ ap_unescape_url(pair) ;
+ eq = strchr(pair, '=' ) ;
+ if ( eq ) {
+ *eq++ = 0 ;
+ apr_table_mergen(ctx->vars, pair, eq) ;
+ } else {
+ apr_table_mergen(ctx->vars, pair, "") ;
+ }
+ }
+
+ } else {
+ if ( ! APR_BUCKET_IS_METADATA(b) ) {
+ do {
+ bytes = readbytes;
+ rstat = apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) ;
+ if ( rstat == APR_SUCCESS ) {
+ ctx->len -= bytes ;
+ while ( bytes > 0 ) {
+ delim = memchr(buf, ctx->delim, bytes) ;
+ if ( delim || (ctx->len == 0) ) {
+ if ( leftover ) {
+ llen = strlen(leftover) ;
+ pair = apr_palloc(f->r->pool, llen + delim - buf + 1) ;
+ memcpy(pair, leftover, llen) ;
+ memcpy(pair+llen, buf, delim-buf) ;
+ pair[llen+delim-buf] = 0 ;
+ leftover = NULL ;
+ } else if ( delim == 0 ) {
+ pair = apr_pmemdup(f->r->pool, buf, bytes + 1) ;
+ pair[bytes] = 0 ;
+ } else {
+ pair = apr_pmemdup(f->r->pool, buf, delim - buf + 1) ;
+ pair[delim-buf] = 0 ;
+ }
+ for (eq = pair ; *eq ; ++eq)
+ if ( *eq == '+' )
+ *eq = ' ' ;
+ ap_unescape_url(pair) ;
+ eq = strchr(pair, '=' ) ;
+ if ( eq ) {
+ *eq++ = 0 ;
+ apr_table_mergen(ctx->vars, pair, eq) ;
+ } else {
+ apr_table_mergen(ctx->vars, pair, "") ;
+ }
+ } else {
+ leftover = apr_pstrndup(f->r->pool, buf, bytes) ;
+ }
+ if ( delim++ ) {
+ bytes -= (delim - buf ) ;
+ buf = delim ;
+ } else {
+ bytes = 0 ; /* rest of buf is now in leftover - ignore */
+ }
+ }
+ }
+ } while ( rstat == APR_EAGAIN ) ;
+ if ( rstat != APR_SUCCESS ) {
+ return rstat ;
+ }
+ }
+ }
|