Return-Path: Delivered-To: apmail-httpd-apreq-dev-archive@httpd.apache.org Received: (qmail 45142 invoked by uid 500); 11 Mar 2001 03:15:27 -0000 Mailing-List: contact apreq-dev-help@httpd.apache.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Post: List-Help: List-Unsubscribe: List-Subscribe: Delivered-To: mailing list apreq-dev@httpd.apache.org Received: (qmail 45128 invoked from network); 11 Mar 2001 03:15:23 -0000 Sender: joe@sunstarsys.com To: apreq-dev@httpd.apache.org Subject: [RFC] Patch (Was: Apache::Request patch request (fwd)) References: From: Joe Schaefer Date: 10 Mar 2001 22:16:45 -0500 In-Reply-To: Joe Schaefer's message of "08 Mar 2001 16:37:00 -0500" Message-ID: Lines: 373 User-Agent: Gnus/5.0802 (Gnus v5.8.2) Emacs/20.5 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N Status: O X-Status: X-Keywords: X-UID: 10 Joe Schaefer writes: > Jody Biggs writes: > > sub param { > > #... > > if (defined $value) { > > $tab->unset($name); > > $tab->add($name, $value); > > } > > #... > > } > > The fix you suggest seems OK, in case the mod_perl folks can't/won't > change Apache::Table. Maybe we should include a similar work-around in > libapreq-0.32? Here's a patch that does the following: 1) rewrites Apache::Request::param as an xsub, incorporating Jody's above fix. I'm not sure I did it right, since I'm still not comfortable with my understanding of XS. It seems to work under light testing though. My reason for XS'ing param() was mainly to eliminate any need for $r->parms. 2) reworks ApacheRequest_tmpfile to provide access to the temp file's name: (a) adds (char *) upload->tmpnam to the ApacheUpload struct (b) provides perl access to it via Apache::Upload::tmpnam (c) adds new perl method Apache::Upload::link, used like this $r->upload->link($linkname) or die sprintf "link(%s, %s) failed", $r->upload->tmpnam, $linkname; This makes a hard link to the temp file via link(2); unfortunately I don't think it is portable to non-*nix platforms. The implementation is in the patch to Request.xs. Suggestions on a more portable method would be most appreciated. This patch doesn't include David's recent patch enabling upload hooks yet (btw: David- how do you install per-upload object hooks with your patch?) 3) includes the apache_cookie.c patch that I should have committed already :( Threat: I'll commit these in a few days unless someone objects. I mean it this time :) Thanks again. -- Joe Schaefer =================================================================== % cvs diff -R . cvs server: Diffing . cvs server: Diffing Cookie cvs server: Diffing Request Index: Request/Request.pm =================================================================== RCS file: /home/cvs/httpd-apreq/Request/Request.pm,v retrieving revision 1.12 diff -u -r1.12 Request.pm --- Request/Request.pm 2000/12/23 03:19:14 1.12 +++ Request/Request.pm 2001/03/11 01:46:05 @@ -12,19 +12,19 @@ } #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 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; Index: Request/Request.xs =================================================================== RCS file: /home/cvs/httpd-apreq/Request/Request.xs,v retrieving revision 1.11 diff -u -r1.11 Request.xs --- Request/Request.xs 2001/02/11 23:37:46 1.11 +++ Request/Request.xs 2001/03/11 01:46:06 @@ -76,6 +76,7 @@ #define ApacheUpload_name(upload) upload->name #define ApacheUpload_filename(upload) upload->filename #define ApacheUpload_next(upload) upload->next +#define ApacheUpload_tmpnam(upload) upload->tmpnam #ifndef PerlLIO_dup #define PerlLIO_dup(fd) dup((fd)) @@ -246,6 +247,65 @@ ST(0) = mod_perl_tie_table(req->parms); void +ApacheRequest_param(req, key=NULL, sv=Nullsv) + Apache::Request req + const char *key + SV *sv + + PPCODE: + ApacheRequest_parse(req); + if (key) { + 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),na); + ap_table_add(req->parms, key, val); + } + } + else if (SvPOK(sv)) { + ap_table_set(req->parms, key, (const char *)SvPV(sv, na)); + } + if(GIMME == G_SCALAR) { + const char *val = ap_table_get(req->parms, key); + if (val) XPUSHs(sv_2mortal(newSVpv((char*)val,0))); + else XSRETURN_UNDEF; + } + else { + 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)) continue; + XPUSHs(sv_2mortal(newSVpv(elts[i].val,0))); + } + } + } + else { + if(GIMME == G_SCALAR) { + XPUSHs(sv_2mortal(mod_perl_tie_table(req->parms))); + } + else { + 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 ) continue; + XPUSHs(sv_2mortal(newSVpv(elts[i].key,0))); + } + } + } + +void ApacheRequest_upload(req, name=NULL) Apache::Request req char *name @@ -323,6 +383,10 @@ ApacheUpload_filename(upload) Apache::Upload upload +char * +ApacheUpload_tmpnam(upload) + Apache::Upload upload + Apache::Upload ApacheUpload_next(upload) Apache::Upload upload @@ -330,6 +394,17 @@ const char * ApacheUpload_type(upload) Apache::Upload upload + +char * +ApacheUpload_link(upload, name) + Apache::Upload upload + char *name + + CODE: + RETVAL = (link(upload->tmpnam, name)) ? NULL : name; + + OUTPUT: + RETVAL void ApacheUpload_info(upload, key=NULL) cvs server: Diffing c Index: c/apache_cookie.c =================================================================== RCS file: /home/cvs/httpd-apreq/c/apache_cookie.c,v retrieving revision 1.8 diff -u -r1.8 apache_cookie.c --- c/apache_cookie.c 2001/01/05 00:05:23 1.8 +++ c/apache_cookie.c 2001/03/11 01:46:06 @@ -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; ivalues->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); } Index: c/apache_request.c =================================================================== RCS file: /home/cvs/httpd-apreq/c/apache_request.c,v retrieving revision 1.8 diff -u -r1.8 apache_request.c --- c/apache_request.c 2000/12/17 00:36:38 1.8 +++ c/apache_request.c 2001/03/11 01:46:07 @@ -315,20 +315,37 @@ return OK; } -FILE *ApacheRequest_tmpfile(ApacheRequest *req) +static void remove_tmpfile (void *data) { + char *name = (char *)data; + remove(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 name[L_tmpnam]; + int fd, tries = 100; + + while (--tries > 0) { + if (tmpnam(name) == NULL) continue; + fd = ap_popenf(r->pool, name, O_CREAT|O_EXCL|O_RDWR, 0600); + if ( fd >= 0 ) + break; /* success */ } - else { - ap_note_cleanups_for_file(r->pool, fp); + + if (tries == 0 || (fp = ap_pfdopen(r->pool, fd, "r+")) == NULL ) { + ap_log_rerror(REQ_ERROR, + "[libapreq] could not open temp file '%s'", name); + return NULL; } + upload->fp = fp; + upload->tmpnam = ap_pstrdup(r->pool, name); + ap_register_cleanup(r->pool, (void *)upload->tmpnam, + remove_tmpfile, ap_null_cleanup); return fp; + } int ApacheRequest_parse_multipart(ApacheRequest *req) @@ -418,7 +435,7 @@ req->upload = upload; } - if (!(upload->fp = ApacheRequest_tmpfile(req))) { + if (!(upload->fp = ApacheRequest_tmpfile(req, upload))) { return HTTP_INTERNAL_SERVER_ERROR; } Index: c/apache_request.h =================================================================== RCS file: /home/cvs/httpd-apreq/c/apache_request.h,v retrieving revision 1.4 diff -u -r1.4 apache_request.h --- c/apache_request.h 2001/01/03 03:58:56 1.4 +++ c/apache_request.h 2001/03/11 01:46:07 @@ -26,6 +26,7 @@ ApacheUpload *next; char *filename; char *name; + char *tmpnam; table *info; FILE *fp; long size; @@ -72,7 +73,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); cvs server: Diffing eg cvs server: Diffing eg/c cvs server: Diffing eg/c/testapreq cvs server: Diffing eg/perl cvs server: Diffing lib cvs server: Diffing lib/Apache %