|
OK - I'm not the world's biggest expert in XS (OK,
OK - I actually just learned it in my attempt to delve into the depths of
libapreq to solve my little UPLOAD_HOOK mystery), but I noticed that although
some of the C code that needs access to Perl stuff (SV's, etc), are written in
Request.xs rather than in apache_request.c I assume this is just to give
them access to Perl. On of the things defined in the XS file includes
the upload_hook function. However, I noticed that while the normal C
implementation is the and it definately uses perlguts, it doesn't seem to have a
second definition in the Apache::Request part of the file (eg, under MODULE =
Apache::Request).
I played around with it and discovered that
(possibly as a result), the upload_hook NEVER gets called - which causes serious
errors when it's implemented.
What ends up happening is that
apace_multiread_buffer slurps in the filename and the first 5119 bytes (5*1024)
of the file, and passes it to Perl. Since the upload_hook in Request.xs
does NOT get called, perl does not write to the file, and does not return wlen,
thus causing C to abort the read operation, leaving junk in the STDIN - which
eventually gets read and interpreted as a bad request.
The reason this took me so damn long to discover is
because I was thrown off by the fact that I got $upload->filename and
$upload->length in the calling perl script, but of course, these are defined
BEFORE anything gets read.
So I did a bit of error-logging to prove my theory
that upload_hook doesn't get called. I changed the read_file loop in
apache_request to:
while ((blen =
multipart_buffer_read(mbuff, buff, sizeof(buff))))
{
ap_log_rerror(REQ_ERROR,"libapreq: about to read buffer..."); if (req->upload_hook != NULL) { ap_log_rerror(REQ_ERROR,"libapreq: Going to XS to call hook..."); wlen = req->upload_hook(req->hook_data, buff, blen, upload); ap_log_rerror(REQ_ERROR,"libapreq: Returned from XS..."); //wlen = fwrite(buff, 1, blen, upload->fp); /*write to file from C - maybe perl isn't writing? No, doesn't sxeem to be the only problem*/ } else { ap_log_rerror(REQ_ERROR,"libapreq: Going to write data..."); wlen = fwrite(buff, 1, blen, upload->fp); } Then, in the XS file, I added some verbosity to
upload_hook:
static int upload_hook(void *ptr, char *buf, int
len, ApacheUpload *upload)
{ UploadHook *hook = (UploadHook *)ptr; if (!(upload->fp &&
ApacheRequest_tmpfile(upload->req, upload)))
{
return -1; // error } {
SV *sv; dSP;
PUSHMARK(SP);
EXTEND(SP, 4); ENTER; SAVETMPS; sv =
sv_newmortal();
sv_setref_pv(sv, "Apache::Upload", (void*)upload); PUSHs(sv); sv =
sv_2mortal(newSVpvn(buf,len));
SvTAINT(sv); PUSHs(sv); sv =
sv_2mortal(newSViv(len));
SvTAINT(sv); PUSHs(sv);
PUSHs(hook->data);
PUTBACK;
perl_call_sv(hook->sub, G_EVAL|G_DISCARD); //call_sv(newSVpv("&Apache::Test::UploadMeter::apreq_hook",0),G_EVAL|G_DISCARD); FREETMPS; LEAVE; }
ap_log_rerror(APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, upload->req->r
,"libapreq: UPLOAD_HOOK CALLED AND EXITED");
if (SvTRUE(ERRSV))
{
return -1; } return
PerlIO_write(PerlIO_importFILE(upload->fp,0), buf,
len);
// return; } Then I uploaded two files - one with UPLOAD_HOOK
enabled, one without. Here's the log extract from them:
Without UPLOAD_HOOK:
[Sun Oct 21 02:31:41 2001] [info] mod_unique_id:
using ip addr 192.168.1.11
[Sun Oct 21 02:31:41 2001] [info] created shared memory segment #2326530 [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] get_line: '-----------------------------7d13c62731096c' [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] find_boundary: '-----------------------------7d13c62731096c' ?= '-----------------------------7d13c62731096c' [snip] [Sun Oct 21 02:31:47 2001] [error] [client
192.168.1.1] multipart_buffer_headers: 'Content-Type' = 'text/plain'
[Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] get_line: '' [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] multipart_buffer_read: 5119 bytes [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] libapreq: about to read buffer... [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] libapreq: Going to write data... [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] multipart_buffer_read: 5119 bytes [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] libapreq: about to read buffer... [Sun Oct 21 02:31:47 2001] [error] [client 192.168.1.1] libapreq: Going to write data... [snip] [Sun Oct 21 02:31:47 2001] [error] [client
192.168.1.1] get_line: '(null)'
[Sun Oct 21 02:31:47 2001] [error] Done: 0 With UPLOAD_HOOK:
[Sun Oct 21 02:32:48 2001] [info] mod_unique_id:
using ip addr 192.168.1.11
[Sun Oct 21 02:32:48 2001] [info] created shared memory segment #2457602 [Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] get_line: '-----------------------------7d1522f31096c' [Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] find_boundary: '-----------------------------7d1522f31096c' ?= '-----------------------------7d1522f31096c' [snip] [Sun Oct 21 02:32:52 2001] [error] [client
192.168.1.1] multipart_buffer_headers: 'Content-Type' = 'text/plain'
[Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] get_line: '' [Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] multipart_buffer_read: 5119 bytes [Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] libapreq: about to read buffer... [Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] libapreq: Going to XS to call hook... [Sun Oct 21 02:32:52 2001] [error] [client 192.168.1.1] libapreq: Returned from XS... [Sun Oct 21 02:32:52 2001] [error] Done: 500 As you can see, the XS function didn't spit
anything out to the error_log. If I knew how to debug this with a source
debugger, I'd double check there to be 100% certain, but I think this is enough
proof that something's wrong. Also note that this was done with a
non-forked Apache (eg, httpd -X). In a normal Apache environment, the remaining
data would be read and (mis)interpreted by another child process, causing
another error in the error log [one of malformed URL, invalid header, invalid
request, etc].
I'd like to try to help fix it, but first I'd need
to understand why:
1) upload_hook is implemented in Request.xs,
rather then in apache_request (and thus linking libapreq .c files against
perl)
2) upload_hook is not defined in Request.xs under
the Apache::Request package namespace
Issac
Internet is a wonderful mechanism for making a fool
of
yourself in front of a very large audience. --Anonymous Moving the mouse won't get you into
trouble... Clicking it might.
--Anonymous PGP Key 0xE0FA561B - Fingerprint:
7E18 C018 D623 A57B 7F37 D902 8C84 7675 E0FA 561B |
- Re: libapreq Request.XS Issac Goldstand
- Re: libapreq Request.XS Doug MacEachern
