You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by sameer <sa...@c2.net> on 1997/07/04 07:46:20 UTC

[PATCH] CGI unbuffering for 1.3

	Whee, I made my cgi unbuffering work with 1.3 What this does:
createas a select() loops between the cgi and the client, so that if
the cgi pauses its output, the client sees a puase. If nph- is on,
then the only difference is that the select() loops starts as soon as
the cgi starts, instead of waiting until
scan_script_headers/send_http_hedares happens.

	I am guessing that this patch will work as-is on NT except for
my send_fb function, which is the select() loop. It's been tested so
far on freebsd.

	I coudln't figure out how to prototype spawn_child_err_buff()
in alloc.c because in alloc.h buff.h isn't included yet.

	Comments? Should I stick this in? This CGI code has been in
Stronghold since just after 1.2 went into feature freeze. SO it's
pretty stable on UNIX, in its stronghold incarnation. I may have messed
up and created some instability when I modified the stuff for 1.3,
though.

Index: alloc.c
===================================================================
RCS file: /export/home/cvs/apache/src/alloc.c,v
retrieving revision 1.35
diff -c -r1.35 alloc.c
*** alloc.c	1997/06/29 19:19:34	1.35
--- alloc.c	1997/07/04 05:37:28
***************
*** 1025,1030 ****
--- 1025,1222 ----
  #define enc_pipe(fds) pipe(fds)
  #endif /* WIN32 */
  
+ 
+ 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 pid;
+   int in_fds[2];
+   int out_fds[2];
+   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;
+       return 0;
+   }
+   
+   if (pipe_out && enc_pipe (out_fds) < 0) {
+     save_errno = errno;
+     if (pipe_in) {
+       close (in_fds[0]); close (in_fds[1]);
+     }
+     unblock_alarms();
+     errno = save_errno;
+     return 0;
+   }
+ 
+   if (pipe_err && enc_pipe (err_fds) < 0) {
+     save_errno = errno;
+     if (pipe_in) {
+       close (in_fds[0]); close (in_fds[1]);
+     }
+     if (pipe_out) {
+       close (out_fds[0]); close (out_fds[1]);
+     }
+     unblock_alarms();
+     errno = save_errno;
+     return 0;
+   }
+ 
+ #ifdef WIN32
+ 
+   {
+       HANDLE thread_handle;
+       int hStdIn, hStdOut, hStdErr;
+       int old_priority;
+       
+       (void)acquire_mutex(spawn_mutex);
+       thread_handle = GetCurrentThread(); /* doesn't need to be closed */
+       old_priority = GetThreadPriority(thread_handle);
+       SetThreadPriority(thread_handle, THREAD_PRIORITY_HIGHEST);
+       /* Now do the right thing with your pipes */
+       if(pipe_in)
+       {
+           hStdIn = dup(fileno(stdin));
+           dup2(in_fds[0], fileno(stdin));
+           close(in_fds[0]);
+       }
+       if(pipe_out)
+       {
+           hStdOut = dup(fileno(stdout));
+           dup2(out_fds[1], fileno(stdout));
+           close(out_fds[1]);
+       }
+       if(pipe_err)
+       {
+           hStdErr = dup(fileno(stderr));
+           dup2(err_fds[1], fileno(stderr));
+           close(err_fds[1]);
+       }
+ 
+       pid = (*func)(data);
+       if(!pid)
+       {
+           save_errno = errno;
+           close(in_fds[1]);
+           close(out_fds[0]);
+           close(err_fds[0]);
+       }
+ 
+       /* restore the original stdin, stdout and stderr */
+       if(pipe_in)
+           dup2(hStdIn, fileno(stdin));
+       if(pipe_out)
+           dup2(hStdOut, fileno(stdout));
+       if(pipe_err)
+           dup2(hStdErr, fileno(stderr));
+ 
+       if(pid)
+       {
+           note_subprocess(p, pid, kill_how);
+           if(pipe_in)
+           {
+               *pipe_in = bcreate(p, B_WR);
+ 	      bpushfd(*pipe_in, in_fds[1], in_fds[1]);
+           }
+           if(pipe_out)
+           {
+               *pipe_out = bcreate(p, B_RD);
+ 	      bpushfd(*pipe_out, out_fds[0], out_fds[0]);
+           }
+           if(pipe_err)
+           {
+               *pipe_err = bcreate(p, B_RD);
+ 	      bpushfd(*pipe_err, err_fds[0], err_fds[0]);
+           }
+       }
+       SetThreadPriority(thread_handle, old_priority);
+       (void)release_mutex(spawn_mutex);
+       /*
+        * go on to the end of the function, where you can
+        * unblock alarms and return the pid
+        */
+ 
+   }
+ #else
+ 
+   if ((pid = fork()) < 0) {
+     save_errno = errno;
+     if (pipe_in) {
+       close (in_fds[0]); close (in_fds[1]);
+     }
+     if (pipe_out) {
+       close (out_fds[0]); close (out_fds[1]);
+     }
+     if (pipe_err) {
+       close (err_fds[0]); close (err_fds[1]);
+     }
+     unblock_alarms();
+     errno = save_errno;
+     return 0;
+   }
+ 
+   if (!pid) {
+     /* Child process */
+     
+     if (pipe_out) {
+       close (out_fds[0]);
+       dup2 (out_fds[1], STDOUT_FILENO);
+       close (out_fds[1]);
+     }
+ 
+     if (pipe_in) {
+       close (in_fds[1]);
+       dup2 (in_fds[0], STDIN_FILENO);
+       close (in_fds[0]);
+     }
+ 
+     if (pipe_err) {
+       close (err_fds[0]);
+       dup2 (err_fds[1], STDERR_FILENO);
+       close (err_fds[1]);
+     }
+ 
+     /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
+     signal (SIGCHLD, SIG_DFL);	/* Was that it? */
+     
+     func (data);
+     exit (1);		/* Should only get here if the exec in func() failed */
+   }
+ 
+   /* Parent process */
+ 
+   note_subprocess (p, pid, kill_how);
+   
+   if (pipe_out) {
+     close (out_fds[1]);
+     *pipe_out = bcreate(p, B_RD);
+     bpushfd(*pipe_out, out_fds[0], out_fds[0]);
+   }
+ 
+   if (pipe_in) {
+     close (in_fds[0]);
+     *pipe_in = bcreate(p, B_WR);
+     bpushfd(*pipe_in, in_fds[1], in_fds[1]);
+   }
+ 
+   if (pipe_err) {
+     close (err_fds[1]);
+     *pipe_err = bcreate(p, B_RD);
+     bpushfd(*pipe_err, err_fds[0], err_fds[0]);
+   }
+ #endif /* WIN32 */
+ 
+   unblock_alarms();
+   return pid;
+ }
+ 
  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)
Index: alloc.h
===================================================================
RCS file: /export/home/cvs/apache/src/alloc.h,v
retrieving revision 1.23
diff -c -r1.23 alloc.h
*** alloc.h	1997/06/28 20:24:27	1.23
--- alloc.h	1997/07/04 05:37:31
***************
*** 243,248 ****
--- 243,253 ----
  int spawn_child_err (pool *, int (*)(void *), void *,
  		 enum kill_conditions, FILE **pipe_in, FILE **pipe_out,
                   FILE **pipe_err);
+ #if 0
+ int spawn_child_err_buff (pool *, int (*)(void *), void *,
+            	  enum kill_conditions, BUFF **pipe_in, BUFF **pipe_out,
+                   BUFF **pipe_err);
+ #endif
  #define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL)
  
  /* magic numbers --- min free bytes to consider a free pool block useable,
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.c,v
retrieving revision 1.131
diff -c -r1.131 http_protocol.c
*** http_protocol.c	1997/07/01 06:46:02	1.131
--- http_protocol.c	1997/07/04 05:38:01
***************
*** 1516,1521 ****
--- 1516,1597 ----
  
      return (chunk_start + len_read);
  }
+ long send_fb_length(BUFF *fb, request_rec *r, long length)
+ {
+     char buf[IOBUFSIZE];
+     long total_bytes_sent;
+     register int n, w, o;
+     conn_rec *c = r->connection;
+     
+     if (length == 0) return 0;
+ 
+     total_bytes_sent = 0;
+ 
+     /* Clear out the buffer */
+     if(fb->incnt != 0)
+       {
+ 	int o;
+ 	o = bwrite(c->client, fb->inptr, fb->incnt);
+ 	fb->incnt -= o;
+ 	fb->inptr += o;
+ 	total_bytes_sent += o;
+       }
+ 
+     /* Make unbuffered */
+     fb->flags &= ~B_RD;
+ 
+     while(1)
+       {
+ 	fd_set fds;
+ 
+ 	bflush(c->client);
+ 
+ 	FD_ZERO(&fds);
+ 	FD_SET(fb->fd_in, &fds);
+ 
+ 	select(FD_SETSIZE, &fds, NULL, NULL, NULL);
+ 
+ 	while((n = bread(fb, buf, IOBUFSIZE)) < 1
+ 	      && fb->flags & B_ERROR && errno == EINTR)
+ 	  continue;
+ 	
+ 	if (n < 1) {
+             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;
+ }
+ 
+ long send_fb(BUFF *fb, request_rec *r) { return send_fb_length(fb, r, -1); }
  
  long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }
  
Index: http_protocol.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.h,v
retrieving revision 1.19
diff -c -r1.19 http_protocol.h
*** http_protocol.h	1997/04/07 10:58:38	1.19
--- http_protocol.h	1997/07/04 05:38:06
***************
*** 110,115 ****
--- 110,118 ----
  
  long send_fd(FILE *f, request_rec *r);
  long send_fd_length(FILE *f, request_rec *r, long length);
+ 
+ long send_fb(BUFF *f, request_rec *r);
+ 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.42
diff -c -r1.42 mod_cgi.c
*** mod_cgi.c	1997/06/29 17:39:50	1.42
--- mod_cgi.c	1997/07/04 05:38:40
***************
*** 183,189 ****
  }
  
  static int log_script(request_rec *r, cgi_server_conf *conf, int ret,
! 	       char *dbuf, char *sbuf, FILE *script_in, FILE *script_err)
  {
      table *hdrs_arr = r->headers_in;
      table_entry *hdrs = (table_entry *)hdrs_arr->elts;
--- 183,189 ----
  }
  
  static int log_script(request_rec *r, cgi_server_conf *conf, int ret,
! 		    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,205 ****
  	((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname),
  		     "a")) == NULL)) {
        /* Soak up script output */
!       while (fgets(argsbuffer, MAX_STRING_LEN-1, script_in) != NULL)
  	continue;
!       while (fgets(argsbuffer, MAX_STRING_LEN-1, script_err) != NULL)
  	continue;
        return ret;
      }
--- 197,205 ----
  	((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname),
  		     "a")) == NULL)) {
        /* Soak up script output */
!       while (bgets(argsbuffer, MAX_STRING_LEN-1, script_in))
  	continue;
!       while (bgets(argsbuffer, MAX_STRING_LEN-1, script_err))
  	continue;
        return ret;
      }
***************
*** 207,213 ****
      /* "%% [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 */
      fprintf(f, "%%%% %d %s\n", ret, r->filename);
  
      fputs("%request\n", f);
--- 207,213 ----
      /* "%% [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" */
      fprintf(f, "%%%% %d %s\n", ret, r->filename);
  
      fputs("%request\n", f);
***************
*** 216,222 ****
        fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
      }
      if ((r->method_number == M_POST || r->method_number == M_PUT)
! 	&& dbuf && *dbuf) {
        fprintf(f, "\n%s\n", dbuf);
      }
  
--- 216,222 ----
        fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
      }
      if ((r->method_number == M_POST || r->method_number == M_PUT)
! 	&& *dbuf) {
        fprintf(f, "\n%s\n", dbuf);
      }
  
***************
*** 233,259 ****
        fprintf(f, "%s\n", sbuf);
  
      *argsbuffer = '\0';
!     fgets(argsbuffer, HUGE_STRING_LEN-1, script_in);
      if (*argsbuffer) {
        fputs("%stdout\n", f);
        fputs(argsbuffer, f);
!       while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL)
  	fputs(argsbuffer, f);
        fputs("\n", f);
      }
  
      *argsbuffer = '\0';
!     fgets(argsbuffer, HUGE_STRING_LEN-1, script_err);
      if (*argsbuffer) {
        fputs("%stderr\n", f);
        fputs(argsbuffer, f);
!       while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL)
  	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);
  
      pfclose(r->pool, f);
      return ret;
--- 233,259 ----
        fprintf(f, "%s\n", sbuf);
  
      *argsbuffer = '\0';
!     bgets(argsbuffer, HUGE_STRING_LEN-1, script_in);
      if (*argsbuffer) {
        fputs("%stdout\n", f);
        fputs(argsbuffer, f);
!       while (bgets(argsbuffer, HUGE_STRING_LEN-1, script_in))
  	fputs(argsbuffer, f);
        fputs("\n", f);
      }
  
      *argsbuffer = '\0';
!     bgets(argsbuffer, HUGE_STRING_LEN-1, script_err);
      if (*argsbuffer) {
        fputs("%stderr\n", f);
        fputs(argsbuffer, f);
!       while (bgets(argsbuffer, HUGE_STRING_LEN-1, script_err))
  	fputs(argsbuffer, f);
        fputs("\n", f);
      }
  
!     bclose(script_in);
!     bclose(script_err);
  
      pfclose(r->pool, f);
      return ret;
***************
*** 277,283 ****
      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    
--- 277,282 ----
***************
*** 312,321 ****
      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.
       */
--- 311,316 ----
***************
*** 352,358 ****
  {
      int retval, nph, dbpos = 0;
      char *argv0, *dbuf = NULL;
!     FILE *script_out, *script_in, *script_err;
      char argsbuffer[HUGE_STRING_LEN];
      int is_included = !strcmp (r->protocol, "INCLUDED");
      void *sconf = r->server->module_config;
--- 347,353 ----
  {
      int retval, nph, dbpos = 0;
      char *argv0, *dbuf = NULL;
!     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,435 ****
  	   * 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
          log_reason ("couldn't spawn child process", r->filename, r);
          return SERVER_ERROR;
      }
--- 416,425 ----
  	   * waiting for free_proc_chain to cleanup in the middle of an
  	   * SSI request -djg
  	   */
! 	  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,477 ****
  		dbpos += dbsize;
  	    }
  	    reset_timeout(r);
! 	    if (fwrite(argsbuffer, sizeof(char), len_read, script_out)
  	            < (size_t)len_read) {
  	        /* silly script stopped reading, soak up remaining message */
  	        while (get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0)
--- 461,467 ----
  		dbpos += dbsize;
  	    }
  	    reset_timeout(r);
! 	    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,499 ****
  	    }
  	}
  
! 	fflush (script_out);
  	signal (SIGPIPE, handler);
  	
  	kill_timeout (r);
      }
      
!     pfclose (r->main ? r->main->pool : r->pool, 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)))
  	    return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err);
  	
  	location = table_get (r->headers_out, "Location");
--- 470,489 ----
  	    }
  	}
  
! 	bflush (script_out);
  	signal (SIGPIPE, handler);
  	
  	kill_timeout (r);
      }
      
!     bclose(script_out);
      
      /* Handle script return... */
      if (script_in && !nph) {
          char *location, sbuf[MAX_STRING_LEN];
  	int ret;
        
!         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,512 ****
  	  
  	    /* Soak up all the script output */
  	    hard_timeout ("read from script", r);
! 	    while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_in)
! 	           > 0)
  	        continue;
! 	    while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err)
! 	           > 0)
  	        continue;
  	    kill_timeout (r);
  
--- 492,500 ----
  	  
  	    /* Soak up all the script output */
  	    hard_timeout ("read from script", r);
! 	    while (bgets(argsbuffer, HUGE_STRING_LEN-1, script_in))
  	        continue;
! 	    while (bgets(argsbuffer, HUGE_STRING_LEN-1, script_err))
  	        continue;
  	    kill_timeout (r);
  
***************
*** 535,558 ****
  	
  	send_http_header(r);
  	if (!r->header_only)
! 	    send_fd(script_in, r);
! 	pfclose (r->main ? r->main->pool : r->pool, 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;
  	kill_timeout(r);
! 	pfclose (r->main ? r->main->pool : r->pool, 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
  	waitpid(child_pid, (int*)0, 0);
  #endif
      }    
--- 523,542 ----
  	
  	send_http_header(r);
  	if (!r->header_only)
! 	    send_fb(script_in, r);
  
  	soft_timeout("soaking script stderr", r);
! 	while(bgets(argsbuffer, HUGE_STRING_LEN-1, script_err))
! 	      continue;
  	kill_timeout(r);
! 	     
! 	bclose(script_in);
! 	bclose(script_out);
      }
  
!     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.62
diff -c -r1.62 util_script.c
*** util_script.c	1997/06/29 19:19:37	1.62
--- util_script.c	1997/07/04 05:38:56
***************
*** 312,317 ****
--- 312,406 ----
      }
  }
  
+ int scan_script_header_err_buff(request_rec *r, BUFF *fb, char *buffer)
+ {
+     char x[MAX_STRING_LEN];
+     char *w, *l;
+     int p;
+ 
+     if (buffer) *buffer = '\0';
+     w = buffer ? buffer : x;
+ 
+     hard_timeout ("read script header", r);
+     
+     while(1) {
+ 
+ 	if (bgets(w, MAX_STRING_LEN-1, fb) <= 0) {
+ 	    log_reason ("Premature end of script headers", r->filename, r);
+ 	    return SERVER_ERROR;
+         }
+ 
+ 	/* Delete terminal (CR?)LF */
+ 	
+ 	p = strlen(w);
+ 	if (p > 0 && w[p-1] == '\n')
+ 	{
+ 	    if (p > 1 && w[p-2] == '\015') w[p-2] = '\0';
+ 	    else w[p-1] = '\0';
+ 	}
+ 
+         if(w[0] == '\0') {
+ 	    kill_timeout (r);
+ 	    return OK;
+ 	}
+                                    
+ 	/* if we see a bogus header don't ignore it. Shout and scream */
+ 	
+         if(!(l = strchr(w,':'))) {
+ 	    char malformed[(sizeof MALFORMED_MESSAGE)+1+MALFORMED_HEADER_LENGTH_TO_SHOW];
+             strcpy(malformed, MALFORMED_MESSAGE);
+             strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW);
+ 
+ 	    if (!buffer)
+ 	      /* Soak up all the script output --- may save an outright kill */
+ 	      while (bgets(w, MAX_STRING_LEN-1, fb) <= 0)
+ 		continue;
+ 	    
+ 	    kill_timeout (r);
+ 	    log_reason (malformed, r->filename, r);
+ 	    return SERVER_ERROR;
+         }
+ 
+         *l++ = '\0';
+ 	while (*l && isspace (*l)) ++l;
+ 	
+         if(!strcasecmp(w,"Content-type")) {
+ 
+ 	    /* Nuke trailing whitespace */
+ 	    
+ 	    char *endp = l + strlen(l) - 1;
+ 	    while (endp > l && isspace(*endp)) *endp-- = '\0';
+ 	    
+ 	    r->content_type = pstrdup (r->pool, l);
+ 	}
+         else if(!strcasecmp(w,"Status")) {
+             sscanf(l, "%d", &r->status);
+             r->status_line = pstrdup(r->pool, l);
+         }
+         else if(!strcasecmp(w,"Location")) {
+ 	    table_set (r->headers_out, w, l);
+         }   
+         else if(!strcasecmp(w,"Content-Length")) {
+ 	    table_set (r->headers_out, w, l);
+         }   
+         else if(!strcasecmp(w,"Transfer-Encoding")) {
+ 	    table_set (r->headers_out, w, l);
+         }   
+ 
+ /* The HTTP specification says that it is legal to merge duplicate
+  * headers into one.  Some browsers that support Cookies don't like
+  * merged headers and prefer that each Set-Cookie header is sent
+  * separately.  Lets humour those browsers.
+  */
+ 	else if(!strcasecmp(w, "Set-Cookie")) {
+ 	    table_add(r->err_headers_out, w, l);
+ 	}
+         else {
+ 	    table_merge (r->err_headers_out, w, l);
+         }
+     }
+ }
+ 
  int scan_script_header_err(request_rec *r, FILE *f, char *buffer)
  {
      char x[MAX_STRING_LEN];
Index: util_script.h
===================================================================
RCS file: /export/home/cvs/apache/src/util_script.h,v
retrieving revision 1.17
diff -c -r1.17 util_script.h
*** util_script.h	1997/06/15 19:22:35	1.17
--- util_script.h	1997/07/04 05:38:59
***************
*** 64,69 ****
--- 64,70 ----
  void add_common_vars(request_rec *r);
  #define scan_script_header(a1,a2) scan_script_header_err(a1,a2,NULL)
  int scan_script_header_err(request_rec *r, FILE *f, char *buffer);
+ int scan_script_header_err_buff(request_rec *r, BUFF *f, char *buffer);
  void send_size(size_t size, request_rec *r);
  int call_exec (request_rec *r, char *argv0, char **env, int shellcmd);
  


-- 
Sameer Parekh					Voice:   510-986-8770
President					FAX:     510-986-8777
C2Net
http://www.c2.net/				sameer@c2.net

Re: [PATCH] CGI unbuffering for 1.3

Posted by Brian Behlendorf <br...@organic.com>.
At 10:46 PM 7/3/97 -0700, you wrote:
>	Whee, I made my cgi unbuffering work with 1.3 What this does:
>createas a select() loops between the cgi and the client, so that if
>the cgi pauses its output, the client sees a puase. If nph- is on,
>then the only difference is that the select() loops starts as soon as
>the cgi starts, instead of waiting until
>scan_script_headers/send_http_hedares happens.

+1, it's running on Hyperreal and all appears well, tested with regular
CGI, CGI designed to output every 2 seconds, and with nph-cgi.

I just noticed - if a script is running, and it's chown'd due to suexec to
a UID other than the main server, then the server can't kill it when the
client quits the connection before the script is done.  Interesting problem
- should the server fire up suexec with sh kill?  :)

	Brian


--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--
"Why not?" - TL                brian@organic.com - hyperreal.org - apache.org