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

[PATCH] nph killer, cgi buffering

This patch:

- provides BUFF * interfaces to the various things cgi needs, in a way
  that avoids mucho code duplication

- adds bnonblock() to set a BUFF to non-blocking mode, and bfileno() to
  get an fd for calling select() on.

- provides send_fb/send_fb_length which do non-blocking reads, and
  whenever a read would block they bflush the client before blocking.

- eliminates the special case "nph-" for CGIs.  (nph doesn't work with
  HTTP/1.1 or SSL)

- works on simple .cgis, needs testing via mod_include, needs more eyes
  to look at it.  Needs testing on NT (needs porting??).

Dean

Index: alloc.c
===================================================================
RCS file: /export/home/cvs/apache/src/alloc.c,v
retrieving revision 1.40
diff -u -r1.40 alloc.c
--- alloc.c	1997/07/15 21:39:50	1.40
+++ alloc.c	1997/07/20 00:56:14
@@ -1064,9 +1064,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];
@@ -1074,13 +1081,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;
   }
   
@@ -1089,7 +1090,6 @@
     if (pipe_in) {
       close (in_fds[0]); close (in_fds[1]);
     }
-    unblock_alarms();
     errno = save_errno;
     return 0;
   }
@@ -1102,7 +1102,6 @@
     if (pipe_out) {
       close (out_fds[0]); close (out_fds[1]);
     }
-    unblock_alarms();
     errno = save_errno;
     return 0;
   }
@@ -1158,23 +1157,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);
@@ -1198,7 +1188,6 @@
     if (pipe_err) {
       close (err_fds[0]); close (err_fds[1]);
     }
-    unblock_alarms();
     errno = save_errno;
     return 0;
   }
@@ -1237,43 +1226,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)
Index: buff.c
===================================================================
RCS file: /export/home/cvs/apache/src/buff.c,v
retrieving revision 1.37
diff -u -r1.37 buff.c
--- buff.c	1997/07/15 21:39:50	1.37
+++ buff.c	1997/07/20 00:56:16
@@ -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;
     }
Index: buff.h
===================================================================
RCS file: /export/home/cvs/apache/src/buff.h,v
retrieving revision 1.21
diff -u -r1.21 buff.h
--- buff.h	1997/07/19 22:34:05	1.21
+++ buff.h	1997/07/20 00:56:17
@@ -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);
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.c,v
retrieving revision 1.143
diff -u -r1.143 http_protocol.c
--- http_protocol.c	1997/07/19 20:27:52	1.143
+++ http_protocol.c	1997/07/20 00:56:22
@@ -1626,6 +1626,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;
Index: http_protocol.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.h,v
retrieving revision 1.24
diff -u -r1.24 http_protocol.h
--- http_protocol.h	1997/07/19 20:27:52	1.24
+++ http_protocol.h	1997/07/20 00:56:23
@@ -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.
Index: mod_cgi.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_cgi.c,v
retrieving revision 1.49
diff -u -r1.49 mod_cgi.c
--- mod_cgi.c	1997/07/17 22:27:34	1.49
+++ mod_cgi.c	1997/07/20 00:56:24
@@ -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))
 	continue;
-      while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err))
+      while (bgets(argsbuffer, HUGE_STRING_LEN, script_err))
 	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);
     }
 
@@ -233,27 +233,27 @@
       fprintf(f, "%s\n", sbuf);
 
     *argsbuffer = '\0';
-    fgets(argsbuffer, HUGE_STRING_LEN-1, script_in);
+    bgets(argsbuffer, HUGE_STRING_LEN, script_in);
     if (*argsbuffer) {
       fputs("%stdout\n", f);
       fputs(argsbuffer, f);
-      while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in))
+      while (bgets(argsbuffer, HUGE_STRING_LEN, script_in))
 	fputs(argsbuffer, f);
       fputs("\n", f);
     }
 
     *argsbuffer = '\0';
-    fgets(argsbuffer, HUGE_STRING_LEN-1, script_err);
+    bgets(argsbuffer, HUGE_STRING_LEN, script_err);
     if (*argsbuffer) {
       fputs("%stderr\n", f);
       fputs(argsbuffer, f);
-      while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err))
+      while (bgets(argsbuffer, HUGE_STRING_LEN, script_err))
 	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 +277,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 +311,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 +347,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;
@@ -421,15 +416,10 @@
 	   * 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 +461,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 +470,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 +492,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))
 	        continue;
-	    while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err)
-	           > 0)
+	    while (bgets(argsbuffer, HUGE_STRING_LEN, script_err))
 	        continue;
 	    kill_timeout (r);
 
@@ -535,24 +523,20 @@
 	
 	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);
 
-	/* 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))
+	      continue;
 	kill_timeout(r);
-	pfclose (r->main ? r->main->pool : r->pool, script_err);
+	     
+	bclose(script_in);
+	bclose(script_out);
     }
 
-    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
     }    
Index: util_script.c
===================================================================
RCS file: /export/home/cvs/apache/src/util_script.c,v
retrieving revision 1.66
diff -u -r1.66 util_script.c
--- util_script.c	1997/07/15 21:39:59	1.66
+++ util_script.c	1997/07/20 00:56:26
@@ -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];
Index: util_script.h
===================================================================
RCS file: /export/home/cvs/apache/src/util_script.h,v
retrieving revision 1.21
diff -u -r1.21 util_script.h
--- util_script.h	1997/07/15 21:40:00	1.21
+++ util_script.h	1997/07/20 00:56:27
@@ -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);
 



Re: [PATCH] nph killer, cgi buffering

Posted by Dean Gaudet <dg...@arctic.org>.
On Sat, 19 Jul 1997, Dean Gaudet wrote:

> This patch:

- doesn't fix the "user hit stop, but the cgi keeps running" bug (unless the
  cgi is always generating output)  ... the fix for this is more
  complicated, and as Roy suggests, we should leave it for sfio.

Dean