You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apreq-cvs@httpd.apache.org by jo...@apache.org on 2003/06/22 17:34:43 UTC
cvs commit: httpd-apreq-2/src apreq_params.c apreq_params.h apreq_parsers.c apreq_parsers.h
joes 2003/06/22 08:34:43
Modified: . STATUS
src apreq_params.c apreq_params.h apreq_parsers.c
apreq_parsers.h
Log:
Add config framework to apreq parsers. Add file bucket logic for spooling uploads into brigades.
Revision Changes Path
1.12 +2 -13 httpd-apreq-2/STATUS
Index: STATUS
===================================================================
RCS file: /home/cvs/httpd-apreq-2/STATUS,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- STATUS 15 Jun 2003 05:29:03 -0000 1.11
+++ STATUS 22 Jun 2003 15:34:43 -0000 1.12
@@ -18,18 +18,7 @@
* Missing API components:
1. Key safety features ("disable uploads", "max body", "temp dir",
- etc.) are unimplemented.
-
- 2. File uploads are `buffered' into a bucket brigade.
- The buckets are currently heap-allocated, which
- causes the entire file to be spooled into RAM.
- This behavior is unsafe, since large uploads can
- DOS the server by exhausting RAM.
-
- [joes] How about writing an upload hook?
-
-
- 3. The req->upload API is unimplemented.
+ etc.) are not fully unimplemented.
CURRENT VOTES:
1.19 +46 -3 httpd-apreq-2/src/apreq_params.c
Index: apreq_params.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_params.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- apreq_params.c 8 Jun 2003 18:37:56 -0000 1.18
+++ apreq_params.c 22 Jun 2003 15:34:43 -0000 1.19
@@ -74,7 +74,6 @@
apreq_param_t *param = apr_palloc(p, nlen + vlen + 1 + sizeof *param);
apreq_value_t *v = ¶m->v;
param->charset = APREQ_CHARSET;
- param->language = NULL;
param->info = NULL;
param->bb = NULL;
@@ -163,7 +162,6 @@
}
-
APREQ_DECLARE(apr_table_t *) apreq_params(apr_pool_t *pool,
const apreq_request_t *req)
{
@@ -185,7 +183,6 @@
param = apr_palloc(pool, nlen + vlen + 1 + sizeof *param);
param->charset = ASCII; /* XXX: UTF_8 */
- param->language = NULL;
param->info = NULL;
param->bb = NULL;
@@ -293,4 +290,50 @@
req->body = apr_table_make(apreq_env_pool(req->env),APREQ_NELTS);
return apreq_run_parser(req->parser, req->cfg, req->body, bb);
+}
+
+
+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(apreq_strtoval(val));
+ if (p->bb)
+ apr_table_addn(t, key, val);
+ return 0;
+}
+
+
+APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool,
+ const apreq_request_t *req)
+{
+ apr_table_t *t;
+ if (req->body == NULL)
+ return NULL;
+
+ t = apr_table_make(pool, APREQ_NELTS);
+ /* XXX needs appropriate copy/merge callbacks */
+ apr_table_do(upload_push, t, req->body, NULL);
+ return t;
+}
+
+static int upload_get(void *data, const char *key, const char *val)
+{
+ const apreq_param_t *p = apreq_value_to_param(apreq_strtoval(val));
+ const apreq_param_t **q = data;
+ if (p->bb) {
+ *q = p;
+ return 1; /* upload found, stop */
+ }
+ else
+ return 0; /* keep searching */
+}
+
+APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apreq_request_t *req,
+ const char *key)
+{
+ const apreq_param_t *param = NULL;
+ if (req->body == NULL)
+ return NULL;
+ apr_table_do(upload_get, ¶m, req->body, key, NULL);
+ return param;
}
1.17 +8 -3 httpd-apreq-2/src/apreq_params.h
Index: apreq_params.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_params.h,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- apreq_params.h 15 Jun 2003 10:33:01 -0000 1.16
+++ apreq_params.h 22 Jun 2003 15:34:43 -0000 1.17
@@ -81,11 +81,8 @@
typedef struct apreq_param_t {
enum { ASCII, UTF_8, UTF_16, ISO_LATIN_1 } charset;
- char *language;
apr_table_t *info;
-
apr_bucket_brigade *bb;
-
apreq_value_t v;
} apreq_param_t;
@@ -180,6 +177,14 @@
APREQ_DECLARE(apr_status_t)apreq_parse_request(apreq_request_t *req,
apr_bucket_brigade *bb);
+
+APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool,
+ const apreq_request_t *req);
+
+APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apreq_request_t *req,
+ const char *key);
+
+
/** @} */
#ifdef __cplusplus
1.25 +184 -17 httpd-apreq-2/src/apreq_parsers.c
Index: apreq_parsers.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- apreq_parsers.c 20 May 2003 20:10:59 -0000 1.24
+++ apreq_parsers.c 22 Jun 2003 15:34:43 -0000 1.25
@@ -158,7 +158,6 @@
param->bb = NULL;
param->info = NULL;
param->charset = UTF_8;
- param->language = NULL;
v->name = v->data + vlen + 1;
@@ -682,6 +681,172 @@
return APR_INCOMPLETE;
}
+APR_INLINE
+static apr_status_t mfd_fwritev(apr_file_t *f, struct iovec *v,
+ int *nelts, apr_size_t *bytes_written)
+{
+ apr_size_t len, bytes_avail = 0;
+ int n = *nelts;
+ apr_status_t s = apr_file_writev(f, v, n, &len);
+
+ *bytes_written = len;
+
+ if (s != APR_SUCCESS)
+ return s;
+
+ while (--n >= 0)
+ bytes_avail += v[n].iov_len;
+
+
+ if (bytes_avail > len) {
+ /* incomplete write: must shift v */
+ n = 0;
+ while (v[n].iov_len <= len) {
+ len -= v[n].iov_len;
+ ++n;
+ }
+ v[n].iov_len -= len;
+ v[n].iov_base = (char *)(v[n].iov_base) + len;
+
+ if (n > 0) {
+ struct iovec *dest = v;
+ do {
+ *dest++ = v[n++];
+ } while (n < *nelts);
+ *nelts = dest - v;
+ }
+ else {
+ s = mfd_fwritev(f, v, nelts, &len);
+ *bytes_written += len;
+ }
+ }
+
+ return s;
+}
+
+
+APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
+ apr_pool_t *pool,
+ const apreq_cfg_t *cfg)
+{
+ apr_status_t rc = APR_SUCCESS;
+ char *path = NULL;
+
+ if (cfg && cfg->temp_dir) {
+ rc = apr_filepath_merge(&path, cfg->temp_dir, "apreqXXXXXX",
+ APR_FILEPATH_NOTRELATIVE, pool);
+ if (rc != APR_SUCCESS)
+ return rc;
+ }
+ else {
+ int tries = 100;
+ char *tmp;
+
+ /* XXX: this should hopefully be replace with currently
+ * non-existing apr_tmp_dir_get() */
+ while (--tries > 0) {
+ if ( (tmp = tempnam(NULL, "apreq")) == NULL ) {
+ continue;
+ }
+ path = apr_pstrcat(pool, tmp, "XXXXXX", NULL);
+ free(tmp);
+ break;
+ }
+ if (path == NULL)
+ return APR_EGENERAL;
+ }
+
+ return apr_file_mktemp(fp, path,
+ APR_CREATE | APR_READ | APR_WRITE
+ | APR_EXCL | APR_DELONCLOSE | APR_BINARY, pool);
+}
+
+#define MAX_FILE_BUCKET_LENGTH ( 1 << ( 6 * sizeof(apr_size_t) ) )
+
+APR_INLINE
+static apr_status_t mfd_bb_concat(apr_pool_t *pool, const apreq_cfg_t *cfg,
+ apr_bucket_brigade *out,
+ apr_bucket_brigade *in)
+{
+ apr_bucket *last = APR_BRIGADE_LAST(out);
+ apr_status_t s;
+ struct iovec v[APREQ_NELTS];
+ apr_bucket_file *f;
+ apr_bucket *e;
+ int n = 0;
+
+ if (! APR_BUCKET_IS_FILE(last)) {
+ apr_bucket_brigade *bb;
+ apr_file_t *file;
+ apr_off_t len;
+
+ s = apr_brigade_length(out, 1, &len);
+ if (s != APR_SUCCESS)
+ return s;
+ if (cfg && len < cfg->max_brigade_len) {
+ APR_BRIGADE_CONCAT(out, in);
+ return APR_SUCCESS;
+ }
+
+ s = apreq_file_mktemp(&file, pool, cfg);
+ if (s != APR_SUCCESS)
+ return s;
+
+ bb = apr_brigade_create(pool, out->bucket_alloc);
+ e = apr_bucket_file_create(file, len, 0, pool, out->bucket_alloc);
+ APR_BRIGADE_INSERT_HEAD(bb, e);
+ s = mfd_bb_concat(pool, cfg, bb, out);
+ if (s != APR_SUCCESS)
+ return s;
+ APR_BRIGADE_CONCAT(out, bb);
+ last = APR_BRIGADE_LAST(out);
+ }
+
+ f = last->data;
+
+ if (last->length > MAX_FILE_BUCKET_LENGTH) {
+ apr_bucket_copy(last, &e);
+ APR_BRIGADE_INSERT_TAIL(out, e);
+ e->length = 0;
+ e->start = last->length;
+ last = e;
+ }
+
+ e = APR_BRIGADE_FIRST(in);
+
+ while (!APR_BRIGADE_EMPTY(in)) {
+ apr_size_t len;
+
+ if (e == APR_BRIGADE_SENTINEL(in) || n == APREQ_NELTS) {
+ int nvec = n;
+ s = mfd_fwritev(f->fd, v, &nvec, &len);
+ if (s != APR_SUCCESS)
+ return s;
+
+ /* nvec now holds the actual number written */
+ n -= nvec;
+
+ while (nvec-- > 0) {
+ apr_bucket *first = APR_BRIGADE_FIRST(in);
+ apr_bucket_delete(first);
+ }
+
+ last->length += len;
+ }
+ else {
+ s = apr_bucket_read(e, (const char **)&(v[n].iov_base),
+ &len, APR_NONBLOCK_READ);
+ if (s != APR_SUCCESS)
+ return s;
+
+ v[n++].iov_len = len;
+ e = APR_BUCKET_NEXT(e);
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
static apr_status_t nextval(const char **line, const char *name,
const char **val, apr_size_t *vlen)
@@ -886,7 +1051,7 @@
param->info = ctx->info;
param->bb = apr_brigade_create(pool,
apr_bucket_alloc_create(pool));
-
+ param->v.status = APR_INCOMPLETE;
apr_table_addn(t, param->v.name, param->v.data);
ctx->status = MFD_UPLOAD;
}
@@ -922,7 +1087,6 @@
len = off;
param = apr_palloc(pool, len + sizeof *param);
param->charset = APREQ_CHARSET;
- param->language = NULL;
param->bb = NULL;
param->info = ctx->info;
@@ -957,31 +1121,34 @@
arr = apr_table_elts(t);
e = (apr_table_entry_t *)arr->elts;
param = apreq_value_to_param(apreq_strtoval(e[arr->nelts-1].val));
-/* param = apreq_value_to_param(*(apreq_value_t **)
- (arr->elts + (arr->elt_size * (arr->nelts-1))));
-*/
+
switch (s) {
case APR_INCOMPLETE:
- if (parser->hook)
- return apreq_run_hook(parser->hook, pool, cfg,
- param->bb, ctx->bb);
- else {
- APR_BRIGADE_CONCAT(param->bb, ctx->bb);
- return s;
+ if (parser->hook) {
+ s = apreq_run_hook(parser->hook, pool, cfg, ctx->bb);
+ if (s != APR_INCOMPLETE && s != APR_SUCCESS)
+ return s;
}
+ return mfd_bb_concat(pool, cfg, param->bb, ctx->bb);
case APR_SUCCESS:
eos = apr_bucket_eos_create(ctx->bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ctx->bb, eos);
if (parser->hook) {
- do s = apreq_run_hook(parser->hook, pool, cfg,
- param->bb, ctx->bb);
- while (s == APR_INCOMPLETE);
+ s = apreq_run_hook(parser->hook, pool, cfg, ctx->bb);
+ if (s != APR_SUCCESS)
+ return s;
}
- else
- APR_BRIGADE_CONCAT(param->bb, ctx->bb);
+
+ apr_bucket_delete(eos);
+ param->v.status = mfd_bb_concat(pool, cfg,
+ param->bb, ctx->bb);
+
+ if (param->v.status != APR_SUCCESS)
+ return s;
+
ctx->status = MFD_NEXTLINE;
goto mfd_parse_brigade;
1.14 +7 -3 httpd-apreq-2/src/apreq_parsers.h
Index: apreq_parsers.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- apreq_parsers.h 15 Jun 2003 10:33:01 -0000 1.13
+++ apreq_parsers.h 22 Jun 2003 15:34:43 -0000 1.14
@@ -25,6 +25,7 @@
/** Request config */
typedef struct apreq_cfg_t {
char *temp_dir;
+ apr_size_t max_brigade_len;
apr_off_t max_len;
int read_bytes;
int disable_uploads;
@@ -39,12 +40,11 @@
#define APREQ_DECLARE_HOOK(f) apr_status_t (f)(apreq_hook_t *hook, \
apr_pool_t *pool, \
const apreq_cfg_t *cfg, \
- apr_bucket_brigade *out, \
- apr_bucket_brigade *in)
+ apr_bucket_brigade *bb)
#define APREQ_CTX_MAXSIZE 128
#define apreq_run_parser(psr,cfg,t,bb) psr->parser(psr,cfg,t,bb)
-#define apreq_run_hook(h,pool,cfg,out,in) h->hook(h,pool,cfg,out,in)
+#define apreq_run_hook(h,pool,cfg,bb) h->hook(h,pool,cfg,bb)
typedef struct apreq_hook_t apreq_hook_t;
typedef struct apreq_parser_t apreq_parser_t;
@@ -82,6 +82,10 @@
apreq_hook_t *h);
APREQ_DECLARE(apreq_parser_t *)apreq_parser(void *env, apreq_hook_t *hook);
+
+APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
+ apr_pool_t *pool,
+ const apreq_cfg_t *cfg);
/** @} */
#ifdef __cplusplus