joes 2004/07/07 16:53:01
Modified: . CHANGES STATUS
glue/perl/t/apreq request.t
glue/perl/t/response/TestApReq request.pm
glue/perl/xsbuilder/Apache/Request Apache__Request.h
src apreq_env.c apreq_params.h apreq_parsers.c
Log:
Implement HOOK_DATA and UPLOAD_HOOK
Revision Changes Path
1.54 +3 -0 httpd-apreq-2/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/httpd-apreq-2/CHANGES,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -r1.53 -r1.54
--- CHANGES 6 Jul 2004 18:26:48 -0000 1.53
+++ CHANGES 7 Jul 2004 23:53:01 -0000 1.54
@@ -6,6 +6,9 @@
- Perl API [joes]
+ Implement HOOK_DATA and UPLOAD_HOOK.
+
+- Perl API [joes]
Add safe XS wrappers for $table->add, $table->set, $table->STORE,
and $table_class->new.
1.63 +1 -3 httpd-apreq-2/STATUS
Index: STATUS
===================================================================
RCS file: /home/cvs/httpd-apreq-2/STATUS,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -r1.62 -r1.63
--- STATUS 7 Jul 2004 13:31:59 -0000 1.62
+++ STATUS 7 Jul 2004 23:53:01 -0000 1.63
@@ -81,8 +81,6 @@
- Install the html dox during "make install". Should we do this
for the doxy manpages also?
- - Implement HOOK_DATA and UPLOAD_HOOK.
-
- Rework glue/perl build system to use apreq2-config instead of
relying on paths like "../../src".
1.16 +6 -1 httpd-apreq-2/glue/perl/t/apreq/request.t
Index: request.t
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/t/apreq/request.t,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- request.t 5 Jul 2004 14:18:26 -0000 1.15
+++ request.t 7 Jul 2004 23:53:01 -0000 1.16
@@ -6,7 +6,7 @@
use Apache::TestUtil;
use Apache::TestRequest qw(GET_BODY UPLOAD_BODY);
-plan tests => 17, have_lwp;
+plan tests => 18, have_lwp;
my $location = "/TestApReq__request";
#print GET_BODY $location;
@@ -37,6 +37,11 @@
my $value = 'DataUpload' x 100;
my $result = UPLOAD_BODY("$location?test=type", content => $value);
ok t_cmp("text/plain", $result, "type");
+}
+{
+ my $value = 'DataUpload' x 100;
+ my $result = UPLOAD_BODY("$location?test=hook", content => $value);
+ ok t_cmp($value, $result, "type");
}
{
my $value = 'DataUpload' x 100;
1.24 +17 -0 httpd-apreq-2/glue/perl/t/response/TestApReq/request.pm
Index: request.pm
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/t/response/TestApReq/request.pm,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- request.pm 7 Jul 2004 06:41:16 -0000 1.23
+++ request.pm 7 Jul 2004 23:53:01 -0000 1.24
@@ -13,6 +13,17 @@
use Apache::ServerUtil;
use File::Spec;
+my $data;
+
+sub hook {
+ my ($upload, $buffer, $len, $hook_data) = @_;
+ warn "$upload saw EOS" and return unless defined $buffer;
+
+ die "BAD UPLOAD ARGS" unless length $buffer == $len;
+ warn "$upload saw $buffer";
+ $data .= $buffer;
+}
+
sub handler {
my $r = shift;
my $temp_dir = $r->server->server_root_relative('logs');
@@ -110,6 +121,12 @@
$req->upload("HTTPUPLOAD")->slurp(my $data);
$req->print($data);
}
+ }
+ elsif ($test eq 'hook') {
+ $data = "";
+ $req->config(UPLOAD_HOOK => \&hook);
+ $req->parse;
+ $r->print($data);
}
elsif ($test eq 'type') {
my $upload = $req->upload("HTTPUPLOAD");
1.42 +184 -12
httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Apache__Request.h
Index: Apache__Request.h
===================================================================
RCS file:
/home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Apache__Request.h,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- Apache__Request.h 7 Jul 2004 06:41:17 -0000 1.41
+++ Apache__Request.h 7 Jul 2004 23:53:01 -0000 1.42
@@ -143,53 +143,225 @@
APREQ_XS_DEFINE_TABLE_METHOD_N(param,set);
APREQ_XS_DEFINE_TABLE_METHOD_N(param,add);
+
+struct hook_ctx {
+ SV *hook_data;
+ SV *hook;
+ SV *bucket_data;
+ SV *parent;
+ PerlInterpreter *perl;
+};
+
+
+#define DEREF(slot) if (ctx->slot) SvREFCNT_dec(ctx->slot)
+
+static apr_status_t upload_hook_cleanup(void *ctx_)
+{
+ struct hook_ctx *ctx = ctx_;
+
+#ifdef USE_ITHREADS
+ dTHXa(ctx->perl);
+#endif
+
+ DEREF(hook_data);
+ DEREF(hook);
+ DEREF(bucket_data);
+ DEREF(parent);
+ return APR_SUCCESS;
+}
+
+APR_INLINE
+static apr_status_t eval_upload_hook(pTHX_ apreq_param_t *upload,
+ void *env, struct hook_ctx *ctx)
+{
+ dSP;
+ SV *sv = ctx->bucket_data;
+ STRLEN len = SvPOK(sv) ? SvCUR(sv) : 0;
+
+ PUSHMARK(SP);
+ EXTEND(SP, 4);
+ ENTER;
+ SAVETMPS;
+
+ PUSHs(sv_2mortal(apreq_xs_2sv(upload, "Apache::Upload", ctx->parent)));
+ PUSHs(sv);
+ PUSHs(sv_2mortal(newSViv(len)));
+ if (ctx->hook_data)
+ PUSHs(ctx->hook_data);
+
+ PUTBACK;
+ perl_call_sv(ctx->hook, G_EVAL|G_DISCARD);
+ FREETMPS;
+ LEAVE;
+
+ if (SvTRUE(ERRSV)) {
+ Perl_warn(aTHX_ "Upload hook failed: %s", SvPV_nolen(ERRSV));
+ return APR_EGENERAL;
+ }
+ return APR_SUCCESS;
+}
+
+
+static apr_status_t apreq_xs_upload_hook(APREQ_HOOK_ARGS)
+{
+ struct hook_ctx *ctx = hook->ctx; /* ctx set during $req->config */
+ apr_bucket *e;
+ apr_status_t s = APR_SUCCESS;
+#ifdef USE_ITHREADS
+ dTHXa(ctx->perl);
+#endif
+
+ for (e = APR_BRIGADE_FIRST(bb); e!= APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ apr_off_t len;
+ const char *data;
+ apreq_log(APREQ_DEBUG 0, env, "looping through buckets");
+
+ if (APR_BUCKET_IS_EOS(e)) { /*last call on this upload */
+ SV *sv = ctx->bucket_data;
+ ctx->bucket_data = &PL_sv_undef;
+ s = eval_upload_hook(aTHX_ param, env, ctx);
+ ctx->bucket_data = sv;
+ if (s != APR_SUCCESS)
+ return s;
+ apreq_log(APREQ_DEBUG 0, env, "upload hook saw eos bucket");
+
+ break;
+ }
+
+ s = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
+ if (s != APR_SUCCESS)
+ return s;
+
+ sv_setpvn(ctx->bucket_data, data, (STRLEN)len);
+
+ s = eval_upload_hook(aTHX_ param, env, ctx);
+
+ apreq_log(APREQ_DEBUG 0, env, "ran upload hook");
+
+ if (s != APR_SUCCESS)
+ return s;
+
+ }
+
+ if (hook->next)
+ s = APREQ_RUN_HOOK(hook->next, env, param, bb);
+
+ return s;
+}
+
+
+
static XS(apreq_xs_request_config)
{
dXSARGS;
+ apr_pool_t *pool;
apreq_request_t *req;
+ apreq_hook_t *upload_hook = NULL;
+ SV *sv;
+ SV *hook_data = NULL;
int j;
+
if (items % 2 != 1 || !SvROK(ST(0)))
Perl_croak(aTHX_ "usage: $req->config(%settings)");
- req = apreq_xs_sv2(request,ST(0));
+ sv = apreq_xs_find_obj(aTHX_ ST(0), "request");
+ req = (apreq_request_t *)SvIVX(sv);
+ pool = apreq_env_pool(req->env);
for (j = 1; j + 1 < items; j += 2) {
- STRLEN alen, vlen;
- const char *attr = SvPVbyte(ST(j),alen),
- *val = SvPVbyte(ST(j+1),vlen);
+ STRLEN alen;
+ const char *attr = SvPVbyte(ST(j),alen);
if (strcasecmp(attr,"POST_MAX")== 0
|| strcasecmp(attr, "MAX_BODY") == 0)
{
+ const char *val = SvPV_nolen(ST(j+1));
apreq_env_max_body(req->env,
(apr_off_t)apreq_atoi64f(val));
}
else if (strcasecmp(attr, "TEMP_DIR") == 0) {
+ const char *val = SvPV_nolen(ST(j+1));
apreq_env_temp_dir(req->env, val);
}
else if (strcasecmp(attr, "MAX_BRIGADE") == 0) {
+ const char *val = SvPV_nolen(ST(j+1));
apreq_env_max_brigade(req->env, (apr_ssize_t)apreq_atoi64f(val));
}
else if (strcasecmp(attr, "DISABLE_UPLOADS") == 0) {
- if (req->parser == NULL)
+ if (req->parser == NULL) {
req->parser = apreq_parser(req->env, NULL);
- if (req->parser != NULL)
- apreq_add_hook(req->parser,
- apreq_make_hook(apreq_env_pool(req->env),
- apreq_hook_disable_uploads,
- NULL, NULL));
+ if (req->parser == NULL) {
+ Perl_warn(aTHX_ "Apache::Request::config: "
+ "cannot disable/enable uploads (parser not
found)");
+ continue;
+ }
+ }
+ if (SvTRUE(ST(j+1))) {
+ /* add disable_uploads hook */
+ if (req->parser == NULL)
+ req->parser = apreq_parser(req->env, NULL);
+ if (req->parser != NULL)
+ apreq_add_hook(req->parser,
+ apreq_make_hook(pool,
+
apreq_hook_disable_uploads,
+ NULL, NULL));
+ }
+ else {
+ /* remove all disable_uploads hooks */
+ apreq_hook_t *first = req->parser->hook;
+
+ while (first != NULL && first->hook ==
apreq_hook_disable_uploads)
+ first = first->next;
+
+ req->parser->hook = first;
+
+ if (first != NULL) {
+ apreq_hook_t *cur;
+
+ for (cur = first->next; cur != NULL; cur = cur->next) {
+ if (cur->hook == apreq_hook_disable_uploads)
+ first->next = cur->next;
+ else
+ first = cur;
+ }
+ }
+ }
}
else if (strcasecmp(attr, "UPLOAD_HOOK") == 0) {
- ;
+ struct hook_ctx *ctx = apr_palloc(apreq_env_pool(req->env),
sizeof *ctx);
+ if (upload_hook)
+ Perl_croak(aTHX_ "Apache::Request::config: "
+ "cannot set UPLOAD_HOOK more than once");
+
+ ctx->hook_data = NULL;
+ ctx->hook = newSVsv(ST(j+1));
+ ctx->bucket_data = newSV(8000);
+ ctx->parent = SvREFCNT_inc(sv);
+#ifdef USE_ITHREADS
+ ctx->perl = aTHX;
+#endif
+ upload_hook = apreq_make_hook(pool, apreq_xs_upload_hook, NULL,
ctx);
+ apreq_add_hook(req->parser, upload_hook);
+ apr_pool_cleanup_register(pool, ctx, upload_hook_cleanup, NULL);
}
+
else if (strcasecmp(attr, "HOOK_DATA") == 0) {
- ;
+ if (hook_data)
+ Perl_croak(aTHX_ "Apache::Request::config: "
+ "cannot set HOOK_DATA more than once");
+ hook_data = ST(j+1);
}
else {
Perl_warn(aTHX_ "Apache::Request::config: "
"Unrecognized attribute %s, skipped", attr);
}
}
+
+ if (upload_hook && hook_data)
+ ((struct hook_ctx *)upload_hook->ctx)->hook_data =
newSVsv(hook_data);
+
XSRETURN(0);
}
1.11 +0 -2 httpd-apreq-2/src/apreq_env.c
Index: apreq_env.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_env.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- apreq_env.c 7 Jul 2004 16:12:15 -0000 1.10
+++ apreq_env.c 7 Jul 2004 23:53:01 -0000 1.11
@@ -16,8 +16,6 @@
#include "apreq.h"
#include "apreq_env.h"
-#include "apreq_params.h"
-#include "apreq_cookie.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "apr_env.h"
1.36 +13 -13 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.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- apreq_params.h 7 Jul 2004 13:49:53 -0000 1.35
+++ apreq_params.h 7 Jul 2004 23:53:01 -0000 1.36
@@ -217,26 +217,26 @@
#include "apreq.h"
/** Parser arguments. */
-#define APREQ_PARSER_ARGS (apreq_parser_t *parser, \
+#define APREQ_PARSER_ARGS apreq_parser_t *parser, \
void *env, \
apr_table_t *t, \
- apr_bucket_brigade *bb)
+ apr_bucket_brigade *bb
/** Hook arguments */
-#define APREQ_HOOK_ARGS (apreq_hook_t *hook, \
+#define APREQ_HOOK_ARGS apreq_hook_t *hook, \
void *env, \
- const apreq_param_t *param, \
- apr_bucket_brigade *bb)
+ apreq_param_t *param, \
+ apr_bucket_brigade *bb
/**
* Declares a API parser.
*/
#ifndef WIN32
#define APREQ_DECLARE_PARSER(f) APREQ_DECLARE(apr_status_t) \
- (f) APREQ_PARSER_ARGS
+ (f) (APREQ_PARSER_ARGS)
#else
#define APREQ_DECLARE_PARSER(f) APREQ_DECLARE_NONSTD(apr_status_t) \
- (f) APREQ_PARSER_ARGS
+ (f) (APREQ_PARSER_ARGS)
#endif
/**
@@ -244,10 +244,10 @@
*/
#ifndef WIN32
#define APREQ_DECLARE_HOOK(f) APREQ_DECLARE(apr_status_t) \
- (f) APREQ_HOOK_ARGS
+ (f) (APREQ_HOOK_ARGS)
#else
#define APREQ_DECLARE_HOOK(f) APREQ_DECLARE_NONSTD(apr_status_t) \
- (f) APREQ_HOOK_ARGS
+ (f) (APREQ_HOOK_ARGS)
#endif
/**
@@ -255,7 +255,7 @@
*
*/
struct apreq_hook_t {
- apr_status_t (*hook) APREQ_HOOK_ARGS;
+ apr_status_t (*hook) (APREQ_HOOK_ARGS);
apreq_hook_t *next;
void *ctx;
};
@@ -265,7 +265,7 @@
*
*/
struct apreq_parser_t {
- apr_status_t (*parser) APREQ_PARSER_ARGS;
+ apr_status_t (*parser) (APREQ_PARSER_ARGS);
const char *enctype;
apreq_hook_t *hook;
void *ctx;
@@ -339,7 +339,7 @@
APREQ_DECLARE(apreq_parser_t *)
apreq_make_parser(apr_pool_t *pool,
const char *enctype,
- apr_status_t (*parser) APREQ_PARSER_ARGS,
+ apr_status_t (*parser) (APREQ_PARSER_ARGS),
apreq_hook_t *hook,
void *ctx);
@@ -354,7 +354,7 @@
*/
APREQ_DECLARE(apreq_hook_t *)
apreq_make_hook(apr_pool_t *pool,
- apr_status_t (*hook) APREQ_HOOK_ARGS,
+ apr_status_t (*hook) (APREQ_HOOK_ARGS),
apreq_hook_t *next,
void *ctx);
1.55 +7 -7 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.54
retrieving revision 1.55
diff -u -r1.54 -r1.55
--- apreq_parsers.c 1 Jul 2004 18:18:26 -0000 1.54
+++ apreq_parsers.c 7 Jul 2004 23:53:01 -0000 1.55
@@ -44,7 +44,7 @@
APREQ_DECLARE(apreq_parser_t *)
apreq_make_parser(apr_pool_t *pool,
const char *enctype,
- apr_status_t (*parser) APREQ_PARSER_ARGS,
+ apr_status_t (*parser) (APREQ_PARSER_ARGS),
apreq_hook_t *hook,
void *ctx)
{
@@ -58,7 +58,7 @@
APREQ_DECLARE(apreq_hook_t *)
apreq_make_hook(apr_pool_t *pool,
- apr_status_t (*hook) APREQ_HOOK_ARGS,
+ apr_status_t (*hook) (APREQ_HOOK_ARGS),
apreq_hook_t *next,
void *ctx)
{
@@ -146,7 +146,7 @@
decoded_len = apreq_decode((char *)v->name + off, data, dlen);
if (decoded_len < 0) {
- return APR_BADARG;
+ return APR_EGENERAL;
}
off += decoded_len;
@@ -179,7 +179,7 @@
decoded_len = apreq_decode(v->data + off, data, dlen);
if (decoded_len < 0) {
- return APR_BADCH;
+ return APR_EGENERAL;
}
off += decoded_len;
@@ -611,7 +611,7 @@
bytes_to_check = MIN(slen,blen);
if (strncmp(buf,start_string,bytes_to_check) != 0)
- return APR_BADCH;
+ return APR_EGENERAL;
slen -= bytes_to_check;
start_string += bytes_to_check;
@@ -961,14 +961,14 @@
if (cd == NULL) {
ctx->status = MFD_ERROR;
- return APR_BADARG;
+ return APR_EGENERAL;
}
s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
- return APR_BADARG;
+ return APR_EGENERAL;
}
s = apreq_header_attribute(cd, "filename", 8, &filename, &flen);