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);