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 2001/03/15 04:04:13 UTC

cvs commit: httpd-apreq/c apache_cookie.c apache_request.c apache_request.h

joes        01/03/14 19:04:13

  Modified:    .        Changes libapreq.pod
               Request  Request.pm Request.xs
               c        apache_cookie.c apache_request.c apache_request.h
  Log:
  fix $r->param( key => [ 0..9 ] ), convert to XS. [Joe Schaefer <jo...@sunstarsys.com>]
  Thanks to Jody Biggs <jo...@codegrok.com> for the spot and suggested fix.
  
  req->upload_hook, req->hook_data added. [David Welton <da...@prosa.it>]
  
  upload->tempname, req->temp_dir; $upload->link(), $upload->tempname()
  added. [Joe Schaefer <jo...@sunstarsys.com>]
  
  handle cookies containing "&", "=" in data. [Joe Schaefer <jo...@sunstarsys.com>]
  
  Revision  Changes    Path
  1.31      +10 -0     httpd-apreq/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/Changes,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- Changes	2001/01/29 18:16:38	1.30
  +++ Changes	2001/03/15 03:04:10	1.31
  @@ -4,6 +4,16 @@
   
   =item 0.32 - ?
   
  +fix $r->param( key => [ 0..9 ] ), convert to XS. [Joe Schaefer <jo...@sunstarsys.com>]
  +Thanks to Jody Biggs <jo...@codegrok.com> for the spot and suggested fix.
  +
  +req->upload_hook, req->hook_data added. [David Welton <da...@prosa.it>]
  +
  +upload->tempname, req->temp_dir; $upload->link(), $upload->tempname()
  +added. [Joe Schaefer <jo...@sunstarsys.com>]
  +
  +handle cookies containing "&", "=" in data. [Joe Schaefer <jo...@sunstarsys.com>]
  +
   $r->parms can be set to another Apache::Table instance [dougm]
   
   fix compile errors when PerlIO is used
  
  
  
  1.4       +31 -1     httpd-apreq/libapreq.pod
  
  Index: libapreq.pod
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/libapreq.pod,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- libapreq.pod	2000/12/23 02:56:53	1.3
  +++ libapreq.pod	2001/03/15 03:04:11	1.4
  @@ -49,6 +49,30 @@
        return status;
    }
   
  +
  +=item req->temp_dir
  +
  +Sets the directory where upload files are spooled.
  +
  +  char dir[] = "/usr/tmp";
  +  req->temp_dir = dir;
  +
  +=item req->hook_data
  +
  +=item req->upload_hook
  +
  +Redirects upload data to be processed by the hook.
  +
  +  req->hook_data = (void *) some_struct_pointer;
  +  req->upload_hook = (int(*)(void*,char*,int,const ApacheUpload*)) some_function;
  +
  +In this case 
  +
  +  some_function(req->hookdata,buffer,bufsize,upload);
  +
  +will be called repeatedly during the file upload instead of writing the 
  +data to a temp file.
  +
   =back
   
   =head2 ApacheRequest *ApacheRequest_new (request_rec *r)
  @@ -111,7 +135,7 @@
   
   =item upload->filename
   
  -The name of the upload file:
  +The name of the upload file as reported by the client:
   
    char *filename = upload->filename;
   
  @@ -120,6 +144,12 @@
   A file pointer to the uploaded file:
   
    FILE *fp = upload->fp;
  +
  +=item upload->tempname
  +
  +The name of the temporary upload file on the server:
  +
  +char *tempname = upload->tempname;
   
   =item upload->size
   
  
  
  
  1.13      +26 -13    httpd-apreq/Request/Request.pm
  
  Index: Request.pm
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/Request/Request.pm,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- Request.pm	2000/12/23 03:19:14	1.12
  +++ Request.pm	2001/03/15 03:04:11	1.13
  @@ -12,19 +12,6 @@
   }
   
   #just prototype methods here, moving to xs later
  -sub param {
  -    my $self = shift;
  -    my($name, $value) = @_;
  -    my $tab = $self->parms;
  -    unless ($name) {
  -	my %seen;
  -	return wantarray ? grep { !$seen{$_}++ } keys %$tab : $tab;
  -    }
  -    if (defined $value) {
  -	$tab->set($name, $value);
  -    }
  -    return wantarray ? ($tab->get($name)) : scalar $tab->get($name);
  -}
   
   sub instance {
       my $class = shift;
  @@ -100,6 +87,16 @@
        return $status;
    }
   
  +=item TEMP_DIR
  +
  +Sets the directory where upload files are spooled.  On a *nix-like
  +that supports link(2), the TEMP_DIR should be placed on the same
  +file system as the final destination file:
  +
  + my $apr = Apache::Request->new($r, TEMP_DIR => "/home/httpd/tmp");
  + my $upload = $apr->upload('file');
  + $upload->link("/home/user/myfile") || warn "link failed: $!";
  +
   =back
   
   =head2 instance
  @@ -240,6 +237,22 @@
       for my $upload ($apr->upload) {
   	...
       }
  +
  +=head2 tempname
  +
  +Provides the name of the spool file.
  +
  +=head2 link
  +
  +To avoid recopying the spool file on a Unix-like system,
  +I<link> will create a hard link to it:
  +
  +  my $upload = $apr->upload('file');
  +  $upload->link("/path/to/newfile") or
  +      die sprintf "link from '%s' failed: $!", $upload->tempname;
  +
  +Typically the new name must lie on the same file system as the
  +spool file. Check your system's link(2) manpage for details.
   
   =back
   
  
  
  
  1.12      +107 -0    httpd-apreq/Request/Request.xs
  
  Index: Request.xs
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/Request/Request.xs,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- Request.xs	2001/02/11 23:37:46	1.11
  +++ Request.xs	2001/03/15 03:04:11	1.12
  @@ -76,6 +76,7 @@
   #define ApacheUpload_name(upload)     upload->name
   #define ApacheUpload_filename(upload) upload->filename
   #define ApacheUpload_next(upload)     upload->next
  +#define ApacheUpload_tempname(upload)   upload->tempname
   
   #ifndef PerlLIO_dup
   #define PerlLIO_dup(fd)   dup((fd)) 
  @@ -211,6 +212,11 @@
   		RETVAL->post_max = (int)SvIV(ST(i+1));
   		break;
   	    }
  +	case 't':
  +	    if (strcasecmp(key, "temp_dir") == 0) {
  +		RETVAL->temp_dir = (char *)SvPV(ST(i+1), PL_na);
  +		break;
  +	    }
   	default:
   	    croak("[libapreq] unknown attribute: `%s'", key);
   	}
  @@ -246,6 +252,92 @@
       ST(0) = mod_perl_tie_table(req->parms);
   
   void
  +ApacheRequest_param(req, key=NULL, sv=Nullsv)
  +    Apache::Request req	
  +    char *key
  +    SV *sv
  +
  +    PPCODE:
  +    if ( !req->parsed ) ApacheRequest_parse(req);
  +
  +    if (key) {
  +
  +	if (sv != Nullsv) {
  +
  +	    if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
  +	    	I32 i;
  +	    	AV *av = (AV*)SvRV(sv);
  +	    	const char *val;
  +
  +            	ap_table_unset(req->parms, key);
  +	    	for (i=0; i<=AvFILL(av); i++) {
  +		    val = (const char *)SvPV(*av_fetch(av, i, FALSE),PL_na);
  +	            ap_table_add(req->parms, key, val);
  +	    	}
  +	    }
  +            else ap_table_set(req->parms, key, (const char *)SvPV(sv, PL_na));
  +	}
  +
  +	switch (GIMME_V) {
  +
  +        case G_SCALAR:			/* return (first) parameter value */
  +	    {
  +	    	const char *val = ap_table_get(req->parms, key);
  +	    	if (val) XPUSHs(sv_2mortal(newSVpv((char*)val,0)));
  +	    	else XSRETURN_UNDEF;
  +	    }
  +	    break;
  +
  +	case G_ARRAY:			/* return list of parameter values */
  +	    {
  +  	        I32 i;
  +	        array_header *arr  = ap_table_elts(req->parms);
  +	        table_entry *elts = (table_entry *)arr->elts;
  +	        for (i = 0; i < arr->nelts; ++i) {
  +	            if (elts[i].key && !strcasecmp(elts[i].key, key))
  +	            	XPUSHs(sv_2mortal(newSVpv(elts[i].val,0)));
  +	        }
  +	    }
  +	    break;
  +
  +	default:
  +            XSRETURN_UNDEF;
  +	} 
  +    } 
  +    else {		
  +
  +	switch (GIMME_V) {
  +
  +	case G_SCALAR:	    		/* like $apr->parms */
  +	    ST(0) = mod_perl_tie_table(req->parms);
  +	    XSRETURN(1); 
  +	    break;
  +
  +	case G_ARRAY:			/* return list of unique keys */
  +            {
  +            	I32 i;
  +	    	array_header *arr  = ap_table_elts(req->parms);
  +	    	table_entry *elts = (table_entry *)arr->elts;
  +	    	for (i = 0; i < arr->nelts; ++i) {
  +		    I32 j;
  +	           if (!elts[i].key) continue;
  +		    /* simple but inefficient uniqueness check */
  +		    for (j = 0; j < i; ++j) { 
  +		        if (!strcasecmp(elts[i].key, elts[j].key))
  +			    break;
  +		    }
  +	            if ( i == j )
  +	                XPUSHs(sv_2mortal(newSVpv(elts[i].key,0)));
  +	        }
  +            }
  +	    break;
  +
  +	default:
  +	    XSRETURN_UNDEF;
  + 	}
  +    }
  +
  +void
   ApacheRequest_upload(req, name=NULL)
       Apache::Request req
       char *name
  @@ -323,6 +415,10 @@
   ApacheUpload_filename(upload)
       Apache::Upload upload
   
  +char *
  +ApacheUpload_tempname(upload)
  +    Apache::Upload upload
  +
   Apache::Upload
   ApacheUpload_next(upload)
       Apache::Upload upload 
  @@ -330,6 +426,17 @@
   const char *
   ApacheUpload_type(upload)
       Apache::Upload upload 
  +
  +char *
  +ApacheUpload_link(upload, name)
  +    Apache::Upload upload
  +    char *name
  +
  +	CODE:
  +	RETVAL = (link(upload->tempname, name)) ? NULL : name;
  +	
  +	OUTPUT:
  +	RETVAL	
   
   void
   ApacheUpload_info(upload, key=NULL)
  
  
  
  1.9       +36 -4     httpd-apreq/c/apache_cookie.c
  
  Index: apache_cookie.c
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/c/apache_cookie.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- apache_cookie.c	2001/01/05 00:05:23	1.8
  +++ apache_cookie.c	2001/03/15 03:04:12	1.9
  @@ -192,8 +192,40 @@
           cookie_push_arr(arr, ap_pstrcat(p, name, "=", val, NULL)); \
       }
   
  -#define escape_url(val) \
  -ap_os_escape_path(p, val?val:"", 1)
  +static char * escape_url(pool *p, char *val) 
  +{
  +  char *result = ap_os_escape_path(p, val?val:"", 1);
  +  char *end = result + strlen(result);
  +  char *seek;
  +
  +  for ( seek = end-1; seek >= result; --seek) {
  +    char *ptr, *replacement;
  +
  +    switch (*seek) {
  +
  +    case '&':
  +	replacement = "%26";
  +	break;
  +    case '=':
  +	replacement = "%3d";
  +	break;
  +    /* additional cases here */
  +
  +    default:
  +	continue; /* next for() */
  +    }
  +
  +
  +    for (ptr = end; ptr > seek; --ptr) {
  +      ptr[2] = ptr[0];
  +    }
  +
  +    strncpy(seek, replacement, 3);
  +    end += 2;
  +  }
  +
  +  return(result);
  +}
   
   char *ApacheCookie_as_string(ApacheCookie *c)
   {
  @@ -214,10 +246,10 @@
   	cookie_push_arr(values, "secure");
       }
   
  -    cookie = ap_pstrcat(p, escape_url(c->name), "=", NULL);
  +    cookie = ap_pstrcat(p, escape_url(p, c->name), "=", NULL);
       for (i=0; i<c->values->nelts; i++) {
   	cookie = ap_pstrcat(p, cookie, 
  -			    escape_url(((char**)c->values->elts)[i]), 
  +			    escape_url(p, ((char**)c->values->elts)[i]), 
   			    (i < (c->values->nelts-1) ? "&" : NULL),
   			    NULL);
       }
  
  
  
  1.9       +43 -13    httpd-apreq/c/apache_request.c
  
  Index: apache_request.c
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/c/apache_request.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- apache_request.c	2000/12/17 00:36:38	1.8
  +++ apache_request.c	2001/03/15 03:04:12	1.9
  @@ -203,6 +203,9 @@
       req->upload = NULL;
       req->post_max = -1;
       req->disable_uploads = 0;
  +    req->upload_hook = NULL;
  +    req->hook_data = NULL;
  +    req->temp_dir = NULL;
       req->parsed = 0;
       req->r = r;
   
  @@ -315,20 +318,41 @@
       return OK;
   }
   
  -FILE *ApacheRequest_tmpfile(ApacheRequest *req)
  +static void remove_tmpfile(void *data) {
  +    remove((char *) data);
  +}
  +
  +FILE *ApacheRequest_tmpfile(ApacheRequest *req, ApacheUpload *upload)
   {
       request_rec *r = req->r;
       FILE *fp;
  -
  -    if (!(fp = tmpfile())) {
  -	ap_log_rerror(REQ_ERROR,
  -		      "[libapreq] could not create tmpfile()"); 
  +    char prefix[] = "apreq";
  +    char *name;
  +    int fd, tries = 100;
  +    
  +    while (--tries > 0) {
  +	if ( (name = tempnam(req->temp_dir, prefix)) == NULL ) continue;
  +	fd = ap_popenf(r->pool, name, O_CREAT|O_EXCL|O_RDWR, 0600);
  +	if ( fd >= 0 )
  +	    break; /* success */
  +	else
  +	    free(name);
       }
  -    else {
  -	ap_note_cleanups_for_file(r->pool, fp);
  +    
  +    if ( tries == 0  || (fp = ap_pfdopen(r->pool, fd, "w+") ) == NULL ) {
  +	ap_log_rerror(REQ_ERROR,
  +		      "[libapreq] could not open temp file '%s'", name); 	
  +	if ( fd >= 0 ) { remove(name); }
  +	return NULL;
       }
   
  +    upload->fp = fp;
  +    upload->tempname = ap_pstrdup(r->pool, name);
  +    ap_register_cleanup(r->pool, (void *)upload->tempname, 
  +			remove_tmpfile, ap_null_cleanup);
  +
       return fp;
  +
   }
   
   int ApacheRequest_parse_multipart(ApacheRequest *req)
  @@ -376,7 +400,7 @@
   	table *header = multipart_buffer_headers(mbuff);	
   	const char *cd, *param=NULL, *filename=NULL;
   	char buff[FILLUNIT];
  -	int blen;
  +	int blen, wlen;
   
   	if (!header) {
   	    return OK;
  @@ -418,7 +442,7 @@
   		req->upload = upload;
   	    }
   
  -	    if (!(upload->fp = ApacheRequest_tmpfile(req))) {
  +	    if (! req->upload_hook && ! ApacheRequest_tmpfile(req, upload) ) {
   		return HTTP_INTERNAL_SERVER_ERROR;
   	    }
   
  @@ -427,12 +451,18 @@
   	    upload->name = ap_pstrdup(req->r->pool, param);
   
   	    while ((blen = multipart_buffer_read(mbuff, buff, sizeof(buff)))) {
  -		/* write the file */
  -	        /* XXX: do better error-checking on the fwrite? */
  -		upload->size += fwrite(buff, 1, blen, upload->fp); 	
  +		if (req->upload_hook != NULL) {
  +		    wlen = req->upload_hook(req->hook_data, buff, blen, upload);
  +		} else {
  +		    wlen = fwrite(buff, 1, blen, upload->fp);
  +		}
  +		if (wlen != blen) {
  +		    return HTTP_INTERNAL_SERVER_ERROR;
  +		}
  +		upload->size += wlen;
   	    }
   
  -	    if (upload->size > 0) {
  +	    if (upload->size > 0 && (req->upload_hook == NULL)) {
   		fseek(upload->fp, 0, 0);
   	    }
   	    else {
  
  
  
  1.5       +5 -1      httpd-apreq/c/apache_request.h
  
  Index: apache_request.h
  ===================================================================
  RCS file: /home/cvs/httpd-apreq/c/apache_request.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- apache_request.h	2001/01/03 03:58:56	1.4
  +++ apache_request.h	2001/03/15 03:04:13	1.5
  @@ -19,6 +19,9 @@
       int parsed;
       int post_max;
       int disable_uploads;
  +    int (*upload_hook)(void *ptr, char *buf, int len, const ApacheUpload *upload);
  +    void *hook_data;
  +    char* temp_dir;
       request_rec *r;
   } ApacheRequest;
   
  @@ -26,6 +29,7 @@
       ApacheUpload *next;
       char *filename;
       char *name;
  +    char *tempname;
       table *info;
       FILE *fp;
       long size;
  @@ -72,7 +76,7 @@
   #define ApacheRequest_parse(req) \
       (req->status = req->parsed ? req->status : ApacheRequest___parse(req)) 
   
  -FILE *ApacheRequest_tmpfile(ApacheRequest *req);
  +FILE *ApacheRequest_tmpfile(ApacheRequest *req, ApacheUpload *upload);
   ApacheUpload *ApacheUpload_new(ApacheRequest *req);
   ApacheUpload *ApacheUpload_find(ApacheUpload *upload, char *name);