joes 2004/06/27 11:07:35
Modified: glue/perl/xsbuilder/Apache/Request Request_pm Request_pod
glue/perl/xsbuilder/Apache/Upload Apache__Upload.h
glue/perl/xsbuilder/maps apreq_functions.map
src apreq_params.h apreq_parsers.c
t parsers.c
Log:
Implement apreq_hook_disable_uploads, and start work (still unimplemented) on
perl glue implementation of DISABLE_UPLOADS, HOOK_DATA and UPLOAD_HOOK.
Revision Changes Path
1.13 +0 -2
httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Request_pm
Index: Request_pm
===================================================================
RCS file:
/home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Request_pm,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- Request_pm 26 Jun 2004 20:30:40 -0000 1.12
+++ Request_pm 27 Jun 2004 18:07:35 -0000 1.13
@@ -1,6 +1,4 @@
use APR::Table;
-use APR::Bucket;
-use APR::Brigade;
package Apache::Request::Table;
push our(@ISA), "APR::Table";
1.14 +33 -16
httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Request_pod
Index: Request_pod
===================================================================
RCS file:
/home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Request_pod,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- Request_pod 26 Jun 2004 20:30:40 -0000 1.13
+++ Request_pod 27 Jun 2004 18:07:35 -0000 1.14
@@ -24,20 +24,20 @@
object as (second) argument. Newer versions of CGI.pm also accept
this syntax within modperl.
-=item * The query parameters are stored as Apache::Table objects,
+=item * The query parameters are stored in APR::Table derived objects,
and are therefore parsed using case-insensitive keys.
-=item * The query string is always parsed, even for POST requests.
+=item * The query string is always parsed first, even for POST requests.
=back
=head2 new
-creates a new I<Apache::Request> object with an environment object $r:
+creates a new C<Apache::Request> object with an environment object $r:
my $req = Apache::Request->new($r);
-With mod_perl2, the environment object must be an I<Apache::RequestRec>
+With mod_perl2, the environment object must be an C<Apache::RequestRec>
object. All methods from the environment class are inherited.
The following attributes are optional:
@@ -58,16 +58,19 @@
that supports link(2), the TEMP_DIR should be located on the same
file system as the final destination file:
+ use Apache::Upload;
my $req = Apache::Request->new($r, TEMP_DIR => "/home/httpd/tmp");
my $upload = $req->upload('file');
$upload->link("/home/user/myfile") || warn "link failed: $!";
-=item HOOK_DATA [TODO]
+For more details on C<link>, see the L<Apache:Upload> manpage.
+
+=item HOOK_DATA (requires L<Apache::Upload>)
Extra configuration info passed to an upload hook.
-See the description for the next item, I<UPLOAD_HOOK>.
+See the description for the next item, C<UPLOAD_HOOK>.
-=item UPLOAD_HOOK (requires Apache::Upload) [TODO]
+=item UPLOAD_HOOK (requires L<Apache::Upload>)
Sets up a callback to run whenever file upload data is read. This
can be used to provide an upload progress meter during file uploads.
@@ -75,7 +78,7 @@
$upload->fh after the hook exits.
my $transparent_hook = sub {
- my ($upload, $bb, $hook_data, $next_hook) = @_;
+ my ($upload, $data, $hook_data) = @_;
warn "$hook_data: got $len bytes for " . $upload->name;
};
@@ -86,7 +89,7 @@
=back
-=head2 instance [DEPRECATED]
+=head2 C<instance> [DEPRECATED]
The default (and only) behavior of I<Apache::Request> is to intelligently
cache B<POST> data for the duration of the request. Thus there is no longer
@@ -97,21 +100,35 @@
However an C<instance()> method is aliased to C<new()> in this release
to ease the pain of porting from 1.X to 2.X.
-=head2 param
+=head2 C<param>
-Get or set (TODO) the request parameters (using case-insensitive keys) by
-mimicing the OO interface of C<CGI::param>. WIth a single
+Get the request parameters (using case-insensitive keys) by
+mimicing the OO interface of C<CGI::param>.
# similar to CGI.pm
- my $value = $req->param('foo');
- my @values = $req->param('foo');
- my @params = $req->param;
+ my $foo_value = $req->param('foo');
+ my @foo_values = $req->param('foo');
+ my @param_names = $req->param;
# the following differ slightly from CGI.pm
- # returns ref to APR::Table object representing all (args + body) params
+ # returns ref to Apache::Request::Table object representing
+ # all (args + body) params
my $table = $req->param;
+
+In list context, or when invoked with a single argument,
+C<param> always induces libapreq2 to read and parse all
+remaining data in the request body. However, C<scalar $req->param("foo")>
+is lazy: libapreq2 will only read=parse more data if
+
+ 1) no "foo" param appears in the query string arguments, AND
+ 2) no "foo" param appears in the previously parsed POST data.
+
+In this circumstance libapreq2 will read and parse additional
+blocks of the incoming request body until it has found the
+the "foo" param.
+
=head2 parms, params [DEPRECATED]
1.5 +114 -0
httpd-apreq-2/glue/perl/xsbuilder/Apache/Upload/Apache__Upload.h
Index: Apache__Upload.h
===================================================================
RCS file:
/home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Upload/Apache__Upload.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Apache__Upload.h 26 Jun 2004 21:35:11 -0000 1.4
+++ Apache__Upload.h 27 Jun 2004 18:07:35 -0000 1.5
@@ -310,3 +310,117 @@
ST(0) = f2g(aTHX_ file, bb->p, APR_PERLIO_HOOK_READ);
XSRETURN(1);
}
+
+struct hook_ctx {
+ SV *hook_data;
+ SV *hook;
+ SV *upload;
+ SV *bucket_data;
+ PerlInterpreter *perl;
+};
+
+#ifdef IMPLEMENT_UPLOAD_HOOKS
+
+#define DEREF(slot) if (ctx->slot) SvREFCNT_dec(ctx->slot)
+
+static void upload_hook_cleanup(void *ctx_)
+{
+ struct hook_ctx *ctx = ctx_;
+
+#ifdef USE_ITHREADS
+ dTHXa(ctx->perl);
+#endif
+
+ DEREF(hook_data);
+ DEREF(hook);
+ DEREF(upload);
+ DEREF(bucket_data);
+}
+
+
+APR_INLINE
+static void eval_upload_hook(pTHX_ SV *hook, SV* upload,
+ SV *bucket_data, SV* hook_data)
+{
+ dSP;
+
+ PUSHMARK(SP);
+ EXTEND(SP, 3);
+ ENTER;
+ SAVETMPS;
+
+ PUSHs(upload);
+ PUSHs(bucket_data);
+ PUSHs(hook_data);
+
+ PUTBACK;
+ perl_call_sv(hook, G_EVAL|G_DISCARD);
+ FREETMPS;
+ LEAVE;
+}
+
+
+static
+APREQ_DECLARE_HOOK(apreq_xs_hook_wrapper)
+{
+ struct hook_ctx *ctx = hook->ctx; /* set ctx during config */
+ apr_bucket *e;
+ apr_status_t s = APR_SUCCESS;
+
+#ifdef USE_ITHREADS
+ dTHXa(ctx->perl);
+#endif
+
+ if (hook->next) {
+ s = APREQ_RUN_HOOK(hook->next, env, param, bb);
+ if (s != APR_SUCCESS)
+ return s;
+ }
+
+ for (e = APR_BRIGADE_FIRST(bb); e!= APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ apr_off_t len;
+ const char *data;
+
+ if (APR_BUCKET_IS_EOS(e)) {
+ /*last call */
+ eval_upload_hook(aTHX_ ctx->hook, ctx->upload,
+ &PL_sv_undef, ctx->hook_data);
+
+ if (SvTRUE(ERRSV)) {
+ /*XXX: handle error */
+ s = APR_EGENERAL;
+ }
+
+ break;
+ }
+
+ s = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
+ if (s != APR_SUCCESS)
+ break;
+
+ SvPVX(ctx->bucket_data) = (char *)data;
+ SvCUR(ctx->bucket_data) = (STRLEN)len;
+
+ eval_upload_hook(aTHX_ ctx->hook, ctx->upload, ctx->bucket_data,
+ ctx->hook_data);
+
+ if (SvTRUE(ERRSV)) {
+ /*XXX: handle error */
+ s = APR_EGENERAL;
+ break;
+ }
+
+ }
+
+ return s;
+}
+
+static XS(apreq_xs_upload_hook)
+{
+ /*this needs to initialize hook_ctx (bucket_data must be CONSTANT with
LEN=-1)*/
+
+}
+
+#endif
1.21 +0 -2
httpd-apreq-2/glue/perl/xsbuilder/maps/apreq_functions.map
Index: apreq_functions.map
===================================================================
RCS file:
/home/cvs/httpd-apreq-2/glue/perl/xsbuilder/maps/apreq_functions.map,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- apreq_functions.map 26 Jun 2004 21:35:11 -0000 1.20
+++ apreq_functions.map 27 Jun 2004 18:07:35 -0000 1.21
@@ -2,8 +2,6 @@
MODULE=Apache::Request PACKAGE=Apache::Request PREFIX=apreq_
apreq_request | apreq_xs_request | const char *:class, void *:env, const
char *:qs=NULL
-! apreq_parse_request
-! apreq_params
apreq_param | apreq_xs_request_get |
MODULE=Apache::Request PACKAGE=Apache::Request
1.33 +6 -0 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.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- apreq_params.h 23 Jun 2004 02:22:28 -0000 1.32
+++ apreq_params.h 27 Jun 2004 18:07:35 -0000 1.33
@@ -380,6 +380,12 @@
APREQ_DECLARE(apreq_parser_t *)apreq_parser(void *env,
apreq_hook_t *hook);
+/**
+ * Returns APR_EGENERAL. Effectively disables mfd parser
+ * if a file-upload field is present.
+ *
+ */
+APREQ_DECLARE_HOOK(apreq_hook_disable_uploads);
#ifdef __cplusplus
}
#endif
1.51 +25 -11 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.50
retrieving revision 1.51
diff -u -r1.50 -r1.51
--- apreq_parsers.c 26 Jun 2004 01:36:24 -0000 1.50
+++ apreq_parsers.c 27 Jun 2004 18:07:35 -0000 1.51
@@ -976,13 +976,19 @@
ctx->status = MFD_PARAM;
}
else {
+ apr_array_header_t *arr;
+ apr_table_entry_t e = {NULL};
apreq_param_t *param = apreq_make_param(pool, name, nlen,
filename, flen);
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);
+ arr = (apr_array_header_t *)apr_table_elts(t);
+ e.key = (char *)param->v.name;
+ e.val = param->v.data;
+ *(apr_table_entry_t *)(apr_array_push(arr)) = e;
+ arr->nelts--;
ctx->status = MFD_UPLOAD;
goto mfd_parse_brigade;
}
@@ -1045,21 +1051,23 @@
case MFD_UPLOAD:
{
apreq_param_t *param;
- const apr_array_header_t *arr;
+ apr_array_header_t *arr;
apr_table_entry_t *e;
s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
- arr = apr_table_elts(t);
+ arr = (apr_array_header_t *)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_strtoval(e[arr->nelts].val));
switch (s) {
case APR_INCOMPLETE:
if (parser->hook) {
s = APREQ_RUN_HOOK(parser->hook, env, param, ctx->bb);
- if (s != APR_INCOMPLETE && s != APR_SUCCESS)
+ if (s != APR_INCOMPLETE && s != APR_SUCCESS) {
+ ctx->status = MFD_ERROR;
return s;
+ }
}
APREQ_BRIGADE_SETASIDE(ctx->bb, pool);
APREQ_BRIGADE_SETASIDE(ctx->in, pool);
@@ -1072,16 +1080,17 @@
APR_BRIGADE_INSERT_TAIL(ctx->bb, eos);
s = APREQ_RUN_HOOK(parser->hook, env, param, ctx->bb);
apr_bucket_delete(eos);
- if (s != APR_SUCCESS)
+ if (s != APR_SUCCESS) {
+ ctx->status = MFD_ERROR;
return s;
+ }
}
-
+ apr_table_addn(t, param->v.name, param->v.data);
APREQ_BRIGADE_SETASIDE(ctx->bb, pool);
- param->v.status = apreq_brigade_concat(env,
- param->bb, ctx->bb);
+ s = apreq_brigade_concat(env, param->bb, ctx->bb);
- if (param->v.status != APR_SUCCESS)
- return param->v.status;
+ if (s != APR_SUCCESS)
+ return s;
ctx->status = MFD_NEXTLINE;
goto mfd_parse_brigade;
@@ -1099,4 +1108,9 @@
}
return APR_INCOMPLETE;
+}
+
+APREQ_DECLARE_HOOK(apreq_hook_disable_uploads)
+{
+ return APR_EGENERAL;
}
1.16 +39 -1 httpd-apreq-2/t/parsers.c
Index: parsers.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/t/parsers.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- parsers.c 26 Jun 2004 01:36:24 -0000 1.15
+++ parsers.c 27 Jun 2004 18:07:35 -0000 1.16
@@ -83,7 +83,7 @@
CuAssertPtrNotNull(tc, req);
CuAssertStrEquals(tc, req->env, apreq_env_content_type(req->env));
- /* strlen(form_data) == 317 */
+ /* strlen(form_data) == 319 */
for (j = 0; j <= strlen(form_data); ++j) {
apr_bucket *e = apr_bucket_immortal_create(form_data,
strlen(form_data),
@@ -126,6 +126,43 @@
CuAssertStrEquals(tc, "text/plain", val);
}
}
+static void parse_disable_uploads(CuTest *tc)
+{
+ const char *val;
+ apr_table_t *t;
+ apr_status_t rv;
+ apreq_request_t *req = apreq_request(APREQ_MFD_ENCTYPE
+ "; charset=\"iso-8859-1\"; boundary=\"AaB03x\""
,"");
+ apr_bucket_brigade *bb = apr_brigade_create(p,
+ apr_bucket_alloc_create(p));
+ apr_bucket *e = apr_bucket_immortal_create(form_data,
+ strlen(form_data),
+ bb->bucket_alloc);
+
+ CuAssertPtrNotNull(tc, req);
+ CuAssertStrEquals(tc, req->env, apreq_env_content_type(req->env));
+
+ APR_BRIGADE_INSERT_HEAD(bb, e);
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(bb->bucket_alloc));
+
+ req->body = NULL;
+ req->parser = apreq_parser(req->env, apreq_make_hook(p,
+ apreq_hook_disable_uploads, NULL, NULL));
+
+ rv = apreq_parse_request(req,bb);
+ CuAssertIntEquals(tc, APR_EGENERAL, rv);
+ CuAssertPtrNotNull(tc, req->body);
+ CuAssertIntEquals(tc, 1, apr_table_elts(req->body)->nelts);
+
+ val = apr_table_get(req->body,"field1");
+ CuAssertStrEquals(tc, "Joe owes =80100.", val);
+ t = apreq_value_to_param(apreq_strtoval(val))->info;
+ val = apr_table_get(t, "content-transfer-encoding");
+ CuAssertStrEquals(tc,"quoted-printable", val);
+
+ val = apr_table_get(req->body, "pics");
+ CuAssertPtrEquals(tc, NULL, val);
+}
CuSuite *testparser(void)
@@ -133,6 +170,7 @@
CuSuite *suite = CuSuiteNew("Parsers");
SUITE_ADD_TEST(suite, parse_urlencoded);
SUITE_ADD_TEST(suite, parse_multipart);
+ SUITE_ADD_TEST(suite, parse_disable_uploads);
return suite;
}