dgaudet 97/07/23 21:24:07
Modified: src CHANGES alloc.c buff.c buff.h http_protocol.c http_protocol.h mod_cgi.c util_script.c util_script.h Log: cgi unbuffering. Includes various BUFF * routines for script/cgi that suplement the FILE * routines. BUFF's now nicely handle switching from buffered reading to unbuffered reading. Submitted by: Dean Gaudet, Sameer Parekh, Roy Fielding Reviewed by: Brian Behlendorf Revision Changes Path 1.361 +20 -0 apache/src/CHANGES Index: CHANGES =================================================================== RCS file: /export/home/cvs/apache/src/CHANGES,v retrieving revision 1.360 retrieving revision 1.361 diff -u -r1.360 -r1.361 --- CHANGES 1997/07/23 00:06:05 1.360 +++ CHANGES 1997/07/24 04:23:55 1.361 @@ -1,3 +1,23 @@ +Changes with Apache 1.3a2 + + *) "nph-" CGIs were not compatible with HTTP/1.1 or SSL support because + they were passed a socket that connected directly to the client. + As such they would have to implement the transport level details + such as encryption or chunking in order to work properly. + This isn't part of the CGI spec so CGIs generally don't do this. + The most common use of nph- CGIs is when the programmer wants an + unbuffered connection to the client; regular CGIs have always been + fully buffered. Apache now provides an unbuffered connection to + all CGIs. Given that most CGIs are written in a language that by + default does buffering (i.e. perl) this shouldn't have a detrimental + effect on performance. The programmer can still use nph- CGIs, + and they're still responsible for sending valid HTTP/1.1 responses. + [Dean Gaudet, Sameer Parekh, Roy Fielding] + + *) If a BUFF is switched from buffered to unbuffered reading the first + bread() will return whatever remained in the buffer prior to the + switch. [Dean Gaudet] + Changes with Apache 1.3a1 *) Added another Configure helper script: TestLib. It determines 1.43 +104 -52 apache/src/alloc.c Index: alloc.c =================================================================== RCS file: /export/home/cvs/apache/src/alloc.c,v retrieving revision 1.42 retrieving revision 1.43 diff -u -r1.42 -r1.43 --- alloc.c 1997/07/24 04:14:24 1.42 +++ alloc.c 1997/07/24 04:23:56 1.43 @@ -1067,9 +1067,16 @@ #define enc_pipe(fds) pipe(fds) #endif /* WIN32 */ -API_EXPORT(int) spawn_child_err (pool *p, int (*func)(void *), void *data, +/* for fdopen, to get binary mode */ +#if defined (__EMX__) || defined (WIN32) +#define BINMODE "b" +#else +#define BINMODE +#endif + +static int spawn_child_err_core (pool *p, int (*func)(void *), void *data, enum kill_conditions kill_how, - FILE **pipe_in, FILE **pipe_out, FILE **pipe_err) + int *pipe_in, int *pipe_out, int *pipe_err) { int pid; int in_fds[2]; @@ -1077,13 +1084,7 @@ int err_fds[2]; int save_errno; - block_alarms(); - - if (pipe_in && enc_pipe (in_fds) < 0) - { - save_errno = errno; - unblock_alarms(); - errno = save_errno; + if (pipe_in && enc_pipe (in_fds) < 0) { return 0; } @@ -1092,7 +1093,6 @@ if (pipe_in) { close (in_fds[0]); close (in_fds[1]); } - unblock_alarms(); errno = save_errno; return 0; } @@ -1105,7 +1105,6 @@ if (pipe_out) { close (out_fds[0]); close (out_fds[1]); } - unblock_alarms(); errno = save_errno; return 0; } @@ -1161,23 +1160,14 @@ if(pid) { note_subprocess(p, pid, kill_how); - if(pipe_in) - { - *pipe_in = fdopen(in_fds[1], "wb"); - if(*pipe_in) - note_cleanups_for_file(p, *pipe_in); + if(pipe_in) { + *pipe_in = in_fds[1]; } - if(pipe_out) - { - *pipe_out = fdopen(out_fds[0], "rb"); - if(*pipe_out) - note_cleanups_for_file(p, *pipe_out); + if(pipe_out) { + *pipe_out = out_fds[0]; } - if(pipe_err) - { - *pipe_err = fdopen(err_fds[0], "rb"); - if(*pipe_err) - note_cleanups_for_file(p, *pipe_err); + if(pipe_err) { + *pipe_err = err_fds[0]; } } SetThreadPriority(thread_handle, old_priority); @@ -1201,7 +1191,6 @@ if (pipe_err) { close (err_fds[0]); close (err_fds[1]); } - unblock_alarms(); errno = save_errno; return 0; } @@ -1240,43 +1229,106 @@ if (pipe_out) { close (out_fds[1]); -#ifdef __EMX__ - /* Need binary mode set for OS/2. */ - *pipe_out = fdopen (out_fds[0], "rb"); -#else - *pipe_out = fdopen (out_fds[0], "r"); -#endif - - if (*pipe_out) note_cleanups_for_file (p, *pipe_out); + *pipe_out = out_fds[0]; } if (pipe_in) { close (in_fds[0]); -#ifdef __EMX__ - /* Need binary mode set for OS/2 */ - *pipe_in = fdopen (in_fds[1], "wb"); -#else - *pipe_in = fdopen (in_fds[1], "w"); -#endif - - if (*pipe_in) note_cleanups_for_file (p, *pipe_in); + *pipe_in = in_fds[1]; } if (pipe_err) { close (err_fds[1]); -#ifdef __EMX__ - /* Need binary mode set for OS/2. */ - *pipe_err = fdopen (err_fds[0], "rb"); -#else - *pipe_err = fdopen (err_fds[0], "r"); -#endif - - if (*pipe_err) note_cleanups_for_file (p, *pipe_err); + *pipe_err = err_fds[0]; } #endif /* WIN32 */ - unblock_alarms(); return pid; +} + + +API_EXPORT(int) spawn_child_err (pool *p, int (*func)(void *), void *data, + enum kill_conditions kill_how, + FILE **pipe_in, FILE **pipe_out, FILE **pipe_err) +{ + int fd_in, fd_out, fd_err; + int pid, save_errno; + + block_alarms(); + + pid = spawn_child_err_core (p, func, data, kill_how, + pipe_in ? &fd_in : NULL, + pipe_out ? &fd_out : NULL, + pipe_err ? &fd_err : NULL ); + + if (pid == 0) { + save_errno = errno; + unblock_alarms(); + errno = save_errno; + return 0; + } + + if (pipe_out) { + *pipe_out = fdopen (fd_out, "r" BINMODE); + if (*pipe_out) note_cleanups_for_file (p, *pipe_out); + else close (fd_out); + } + + if (pipe_in) { + *pipe_in = fdopen (fd_in, "w" BINMODE); + if (*pipe_in) note_cleanups_for_file (p, *pipe_in); + else close (fd_in); + } + + if (pipe_err) { + *pipe_err = fdopen (fd_err, "r" BINMODE); + if (*pipe_err) note_cleanups_for_file (p, *pipe_err); + else close (fd_err); + } + + unblock_alarms(); + return pid; +} + + +API_EXPORT(int) spawn_child_err_buff (pool *p, int (*func)(void *), void *data, + enum kill_conditions kill_how, + BUFF **pipe_in, BUFF **pipe_out, BUFF **pipe_err) +{ + int fd_in, fd_out, fd_err; + int pid, save_errno; + + block_alarms(); + + pid = spawn_child_err_core (p, func, data, kill_how, + pipe_in ? &fd_in : NULL, + pipe_out ? &fd_out : NULL, + pipe_err ? &fd_err : NULL ); + + if (pid == 0) { + save_errno = errno; + unblock_alarms(); + errno = save_errno; + return 0; + } + + if (pipe_out) { + *pipe_out = bcreate(p, B_RD); + bpushfd(*pipe_out, fd_out, fd_out); + } + + if (pipe_in) { + *pipe_in = bcreate(p, B_WR); + bpushfd(*pipe_in, fd_in, fd_in); + } + + if (pipe_err) { + *pipe_err = bcreate(p, B_RD); + bpushfd(*pipe_err, fd_err, fd_err); + } + + unblock_alarms(); + return pid; } static void free_proc_chain (struct process_chain *procs) 1.38 +33 -5 apache/src/buff.c Index: buff.c =================================================================== RCS file: /export/home/cvs/apache/src/buff.c,v retrieving revision 1.37 retrieving revision 1.38 diff -u -r1.37 -r1.38 --- buff.c 1997/07/15 21:39:50 1.37 +++ buff.c 1997/07/24 04:23:57 1.38 @@ -415,18 +415,38 @@ { if (value) { fb->flags |= flag; - if( flag & B_CHUNK ) { + if (flag & B_CHUNK) { start_chunk(fb); } } else { fb->flags &= ~flag; - if( flag & B_CHUNK ) { + if (flag & B_CHUNK) { end_chunk(fb); } } return value; } + +API_EXPORT(int) bnonblock(BUFF *fb, int direction) +{ + int fd; + + fd = ( direction == B_RD ) ? fb->fd_in : fb->fd; +#if defined(O_NONBLOCK) + return fcntl (fd, F_SETFL, O_NONBLOCK); +#elif defined(F_NDELAY) + return fcntl (fd, F_SETFL, F_NDELAY); +#else + return 0; +#endif +} + +API_EXPORT(int) bfileno(BUFF *fb, int direction) +{ + return (direction == B_RD) ? fb->fd_in : fb->fd; +} + /* * This is called instead of read() everywhere in here. It implements * the B_SAFEREAD functionality -- which is to force a flush() if a read() @@ -521,10 +541,18 @@ if (fb->flags & B_RDERR) return -1; if (nbyte == 0) return 0; - if (!(fb->flags & B_RD)) - { -/* Unbuffered reading */ + if (!(fb->flags & B_RD)) { + /* Unbuffered reading. First check if there was something in the + * buffer from before we went unbuffered. */ + if (fb->incnt) { + i = (fb->incnt > nbyte) ? nbyte : fb->incnt; + memcpy (buf, fb->inptr, i); + fb->incnt -= i; + fb->inptr += i; + return i; + } i = saferead( fb, buf, nbyte ); + if (i == 0) fb->flags |= B_EOF; if (i == -1 && errno != EAGAIN) doerror(fb, B_RD); return i; } 1.22 +9 -0 apache/src/buff.h Index: buff.h =================================================================== RCS file: /export/home/cvs/apache/src/buff.h,v retrieving revision 1.21 retrieving revision 1.22 diff -u -r1.21 -r1.22 --- buff.h 1997/07/19 22:34:05 1.21 +++ buff.h 1997/07/24 04:23:57 1.22 @@ -158,3 +158,12 @@ #define bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \ (fb)->outcnt == (fb)->bufsiz) ? bflsbuf(c, (fb)) : \ ((fb)->outbase[(fb)->outcnt++] = (c), 0)) + +API_EXPORT(int) spawn_child_err_buff (pool *, int (*)(void *), void *, + enum kill_conditions, BUFF **pipe_in, BUFF **pipe_out, + BUFF **pipe_err); + +/* enable non-blocking operations */ +API_EXPORT(int) bnonblock(BUFF *fb, int direction); +/* and get an fd to select() on */ +API_EXPORT(int) bfileno(BUFF *fb, int direction); 1.145 +79 -0 apache/src/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /export/home/cvs/apache/src/http_protocol.c,v retrieving revision 1.144 retrieving revision 1.145 diff -u -r1.144 -r1.145 --- http_protocol.c 1997/07/20 18:52:40 1.144 +++ http_protocol.c 1997/07/24 04:23:58 1.145 @@ -1629,6 +1629,85 @@ return total_bytes_sent; } +/* + * Send the body of a response to the client. + */ +API_EXPORT(long) send_fb(BUFF *fb, request_rec *r) { + return send_fb_length(fb, r, -1); +} + +API_EXPORT(long) send_fb_length(BUFF *fb, request_rec *r, long length) +{ + char buf[IOBUFSIZE]; + long total_bytes_sent = 0; + register int n, w, o, len, fd; + fd_set fds; + + if (length == 0) return 0; + + /* Make fb unbuffered and non-blocking */ + bsetflag (fb, B_RD, 0); + bnonblock (fb, B_RD); + fd = bfileno (fb, B_RD); + + soft_timeout("send body", r); + + while (!r->connection->aborted) { + if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) + len = length - total_bytes_sent; + else len = IOBUFSIZE; + + do { + n = bread (fb, buf, len); + if (n >= 0) break; + if (n < 0 && errno != EAGAIN) break; + /* we need to block, so flush the output first */ + bflush (r->connection->client); + FD_ZERO (&fds); + FD_SET (fd, &fds); + /* we don't care what select says, we might as well loop back + * around and try another read + */ + ap_select (fd+1, &fds, NULL, NULL, NULL); + } while (!r->connection->aborted); + + if (n < 1 || r->connection->aborted) { + break; + } + + o=0; + total_bytes_sent += n; + + while (n && !r->connection->aborted) { + w = bwrite(r->connection->client, &buf[o], n); + if (w > 0) { + reset_timeout(r); /* reset timeout after successful write */ + n-=w; + o+=w; + } + else if (w < 0) { + if (r->connection->aborted) + break; + else if (errno == EAGAIN) + continue; + else { + log_unixerr("send body lost connection to", + get_remote_host(r->connection, + r->per_dir_config, REMOTE_NAME), + NULL, r->server); + bsetflag(r->connection->client, B_EOUT, 1); + r->connection->aborted = 1; + break; + } + } + } + } + + kill_timeout(r); + SET_BYTES_SENT(r); + return total_bytes_sent; +} + API_EXPORT(int) rputc (int c, request_rec *r) { if (r->connection->aborted) return EOF; 1.25 +3 -0 apache/src/http_protocol.h Index: http_protocol.h =================================================================== RCS file: /export/home/cvs/apache/src/http_protocol.h,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- http_protocol.h 1997/07/19 20:27:52 1.24 +++ http_protocol.h 1997/07/24 04:23:59 1.25 @@ -110,6 +110,9 @@ API_EXPORT(long) send_fd(FILE *f, request_rec *r); API_EXPORT(long) send_fd_length(FILE *f, request_rec *r, long length); + +API_EXPORT(long) send_fb(BUFF *f, request_rec *r); +API_EXPORT(long) send_fb_length(BUFF *f, request_rec *r, long length); /* Hmmm... could macrofy these for now, and maybe forever, though the * definitions of the macros would get a whole lot hairier. 1.50 +35 -56 apache/src/mod_cgi.c Index: mod_cgi.c =================================================================== RCS file: /export/home/cvs/apache/src/mod_cgi.c,v retrieving revision 1.49 retrieving revision 1.50 diff -u -r1.49 -r1.50 --- mod_cgi.c 1997/07/17 22:27:34 1.49 +++ mod_cgi.c 1997/07/24 04:23:59 1.50 @@ -183,7 +183,7 @@ } static int log_script(request_rec *r, cgi_server_conf *conf, int ret, - char *dbuf, char *sbuf, FILE *script_in, FILE *script_err) + char *dbuf, char *sbuf, BUFF *script_in, BUFF *script_err) { table *hdrs_arr = r->headers_in; table_entry *hdrs = (table_entry *)hdrs_arr->elts; @@ -197,9 +197,9 @@ ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), "a")) == NULL)) { /* Soak up script output */ - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in)) + while (bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) continue; - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err)) + while (bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) continue; return ret; } @@ -207,7 +207,7 @@ /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/etc/httpd/cgi-bin */ + /* "%% 500 /usr/local/etc/httpd/cgi-bin" */ fprintf(f, "%%%% %d %s\n", ret, r->filename); fputs("%request\n", f); @@ -216,7 +216,7 @@ fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); } if ((r->method_number == M_POST || r->method_number == M_PUT) - && dbuf && *dbuf) { + && *dbuf) { fprintf(f, "\n%s\n", dbuf); } @@ -232,28 +232,24 @@ if (sbuf && *sbuf) fprintf(f, "%s\n", sbuf); - *argsbuffer = '\0'; - fgets(argsbuffer, HUGE_STRING_LEN-1, script_in); - if (*argsbuffer) { + if (bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) { fputs("%stdout\n", f); fputs(argsbuffer, f); - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in)) + while (bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) fputs(argsbuffer, f); fputs("\n", f); } - *argsbuffer = '\0'; - fgets(argsbuffer, HUGE_STRING_LEN-1, script_err); - if (*argsbuffer) { + if (bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { fputs("%stderr\n", f); fputs(argsbuffer, f); - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err)) + while (bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) fputs(argsbuffer, f); fputs("\n", f); } - pfclose(r->main ? r->main->pool : r->pool, script_in); - pfclose(r->main ? r->main->pool : r->pool, script_err); + bclose(script_in); + bclose(script_err); pfclose(r->pool, f); return ret; @@ -277,7 +273,6 @@ struct cgi_child_stuff *cld = (struct cgi_child_stuff *)child_stuff; request_rec *r = cld->r; char *argv0 = cld->argv0; - int nph = cld->nph; int child_pid; #ifdef DEBUG_CGI @@ -312,10 +307,6 @@ if (!cld->debug) error_log2stderr (r->server); -#if !defined(__EMX__) && !defined(WIN32) - if (nph) client_to_stdout (r->connection); -#endif - /* Transumute outselves into the script. * NB only ISINDEX scripts get decoded arguments. */ @@ -352,7 +343,7 @@ { int retval, nph, dbpos = 0; char *argv0, *dbuf = NULL; - FILE *script_out, *script_in, *script_err; + BUFF *script_out, *script_in, *script_err; char argsbuffer[HUGE_STRING_LEN]; int is_included = !strcmp (r->protocol, "INCLUDED"); void *sconf = r->server->module_config; @@ -415,21 +406,16 @@ cld.argv0 = argv0; cld.r = r; cld.nph = nph; cld.debug = conf->logname ? 1 : 0; + /* + * we spawn out of r->main if it's there so that we can avoid + * waiting for free_proc_chain to cleanup in the middle of an + * SSI request -djg + */ if (!(child_pid = - /* - * we spawn out of r->main if it's there so that we can avoid - * waiting for free_proc_chain to cleanup in the middle of an - * SSI request -djg - */ - spawn_child_err (r->main ? r->main->pool : r->pool, cgi_child, - (void *)&cld, - nph ? just_wait : kill_after_timeout, -#if defined(__EMX__) || defined(WIN32) - &script_out, &script_in, &script_err))) { -#else - &script_out, nph ? NULL : &script_in, - &script_err))) { -#endif + spawn_child_err_buff (r->main ? r->main->pool : r->pool, cgi_child, + (void *)&cld, + kill_after_timeout, + &script_out, &script_in, &script_err))) { log_reason ("couldn't spawn child process", r->filename, r); return SERVER_ERROR; } @@ -471,7 +457,7 @@ dbpos += dbsize; } reset_timeout(r); - if (fwrite(argsbuffer, sizeof(char), len_read, script_out) + if (bwrite(script_out, argsbuffer, len_read) < (size_t)len_read) { /* silly script stopped reading, soak up remaining message */ while (get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) @@ -480,20 +466,20 @@ } } - fflush (script_out); + bflush (script_out); signal (SIGPIPE, handler); kill_timeout (r); } - pfclose (r->main ? r->main->pool : r->pool, script_out); + bclose(script_out); /* Handle script return... */ if (script_in && !nph) { char *location, sbuf[MAX_STRING_LEN]; int ret; - if ((ret = scan_script_header_err(r, script_in, sbuf))) + if ((ret = scan_script_header_err_buff(r, script_in, sbuf))) return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); location = table_get (r->headers_out, "Location"); @@ -502,11 +488,9 @@ /* Soak up all the script output */ hard_timeout ("read from script", r); - while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_in) - > 0) + while (bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) continue; - while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) - > 0) + while (bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) continue; kill_timeout (r); @@ -535,24 +519,19 @@ send_http_header(r); if (!r->header_only) - send_fd(script_in, r); - pfclose (r->main ? r->main->pool : r->pool, script_in); + send_fb(script_in, r); + bclose(script_in); - /* Soak up stderr */ soft_timeout("soaking script stderr", r); - while (!r->connection->aborted && - (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) > 0)) - continue; + while(bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) + continue; kill_timeout(r); - pfclose (r->main ? r->main->pool : r->pool, script_err); + bclose(script_err); } - if (nph) { -#if defined(__EMX__) || defined(WIN32) - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) { - bputs(argsbuffer, r->connection->client); - } -#else + if (script_in && nph) { + send_fb(script_in, r); +#if !defined(__EMX__) && !defined(WIN32) waitpid(child_pid, (int*)0, 0); #endif } 1.67 +27 -3 apache/src/util_script.c Index: util_script.c =================================================================== RCS file: /export/home/cvs/apache/src/util_script.c,v retrieving revision 1.66 retrieving revision 1.67 diff -u -r1.66 -r1.67 --- util_script.c 1997/07/15 21:39:59 1.66 +++ util_script.c 1997/07/24 04:24:00 1.67 @@ -312,7 +312,9 @@ } } -API_EXPORT(int) scan_script_header_err(request_rec *r, FILE *f, char *buffer) + +static int scan_script_header_err_core (request_rec *r, char *buffer, + int (*getsfunc)(char *, int, void *), void *getsfunc_data) { char x[MAX_STRING_LEN]; char *w, *l; @@ -325,7 +327,7 @@ while(1) { - if (fgets(w, MAX_STRING_LEN-1, f) == NULL) { + if ((*getsfunc)(w, MAX_STRING_LEN-1, getsfunc_data) == 0) { kill_timeout (r); log_reason ("Premature end of script headers", r->filename, r); return SERVER_ERROR; @@ -354,7 +356,7 @@ if (!buffer) /* Soak up all the script output --- may save an outright kill */ - while (fgets(w, MAX_STRING_LEN-1, f) != NULL) + while ((*getsfunc)(w, MAX_STRING_LEN-1, getsfunc_data)) continue; kill_timeout (r); @@ -401,6 +403,28 @@ } } } + +static int getsfunc_FILE (char *buf, int len, void *f) +{ + return fgets (buf, len, (FILE *)f) != NULL; +} + +API_EXPORT(int) scan_script_header_err(request_rec *r, FILE *f, char *buffer) +{ + return scan_script_header_err_core (r, buffer, getsfunc_FILE, f); +} + +static int getsfunc_BUFF (char *w, int len, void *fb) +{ + return bgets (w, len, (BUFF *)fb) > 0; +} + +API_EXPORT(int) scan_script_header_err_buff(request_rec *r, BUFF *fb, + char *buffer) +{ + return scan_script_header_err_core (r, buffer, getsfunc_BUFF, fb); +} + API_EXPORT(void) send_size(size_t size, request_rec *r) { char ss[20]; 1.22 +1 -0 apache/src/util_script.h Index: util_script.h =================================================================== RCS file: /export/home/cvs/apache/src/util_script.h,v retrieving revision 1.21 retrieving revision 1.22 diff -u -r1.21 -r1.22 --- util_script.h 1997/07/15 21:40:00 1.21 +++ util_script.h 1997/07/24 04:24:00 1.22 @@ -64,6 +64,7 @@ API_EXPORT(void) add_common_vars(request_rec *r); #define scan_script_header(a1,a2) scan_script_header_err(a1,a2,NULL) API_EXPORT(int) scan_script_header_err(request_rec *r, FILE *f, char *buffer); +API_EXPORT(int) scan_script_header_err_buff(request_rec *r, BUFF *f, char *buffer); API_EXPORT(void) send_size(size_t size, request_rec *r); API_EXPORT(int) call_exec (request_rec *r, char *argv0, char **env, int shellcmd);