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
 
 
 
 

Reply via email to