You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by Dean Gaudet <dg...@hyperreal.org> on 1997/07/24 06:24:08 UTC

cvs commit: apache/src CHANGES alloc.c buff.c buff.h http_protocol.c http_protocol.h mod_cgi.c util_script.c util_script.h

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