You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by be...@hyperreal.org on 1998/05/16 18:34:51 UTC

cvs commit: apache-1.3/src/modules/standard mod_cgi.c mod_include.c

ben         98/05/16 09:34:51

  Modified:    src      CHANGES
               src/include alloc.h buff.h util_script.h
               src/main alloc.c buff.c http_log.c util_script.c
               src/modules/standard mod_cgi.c mod_include.c
  Log:
  Fix Win32 CGI.
  
  Revision  Changes    Path
  1.849     +5 -0      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.848
  retrieving revision 1.849
  diff -u -r1.848 -r1.849
  --- CHANGES	1998/05/15 09:01:34	1.848
  +++ CHANGES	1998/05/16 16:34:44	1.849
  @@ -1,5 +1,10 @@
   Changes with Apache 1.3b7
   
  +  *) WIN32: CGIs could cause a hang (because of a deadlock in the standard C
  +     library), so CGI handling has been changed to use Win32 native handles
  +	 instead of C file descriptors.
  +	 [Ben Laurie and Bill Stoddard <wg...@us.ibm.com>] PR#1129, 1607
  +
     *) The proxy cache would store an incorrect content-length in the cached
        file copy after a cache update. That resulted in repeated fetching
        of the original copy instead of using the cached copy.
  
  
  
  1.57      +6 -0      apache-1.3/src/include/alloc.h
  
  Index: alloc.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/alloc.h,v
  retrieving revision 1.56
  retrieving revision 1.57
  diff -u -r1.56 -r1.57
  --- alloc.h	1998/05/03 17:31:06	1.56
  +++ alloc.h	1998/05/16 16:34:46	1.57
  @@ -256,6 +256,9 @@
   
   API_EXPORT(void) ap_note_cleanups_for_file(pool *, FILE *);
   API_EXPORT(void) ap_note_cleanups_for_fd(pool *, int);
  +#ifdef WIN32
  +API_EXPORT(void) ap_note_cleanups_for_h(pool *, HANDLE);
  +#endif
   API_EXPORT(void) ap_kill_cleanups_for_fd(pool *p, int fd);
   
   API_EXPORT(void) ap_note_cleanups_for_socket(pool *, int);
  @@ -272,6 +275,9 @@
   
   API_EXPORT(int) ap_pfclose(struct pool *, FILE *);
   API_EXPORT(int) ap_pclosef(struct pool *, int fd);
  +#ifdef WIN32
  +API_EXPORT(int) ap_pcloseh(struct pool *, HANDLE hDevice);
  +#endif
   
   /* routines to deal with directories */
   API_EXPORT(DIR *) ap_popendir(pool *p, const char *name);
  
  
  
  1.40      +20 -3     apache-1.3/src/include/buff.h
  
  Index: buff.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/buff.h,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- buff.h	1998/05/03 17:31:07	1.39
  +++ buff.h	1998/05/16 16:34:46	1.40
  @@ -117,6 +117,9 @@
   /* could also put pointers to the basic I/O routines here */
       int fd;			/* the file descriptor */
       int fd_in;			/* input file descriptor, if different */
  +#ifdef WIN32
  +    HANDLE hFH;			/* Windows filehandle */
  +#endif
   
       /* transport handle, for RPC binding handle or some such */
       void *t_handle;
  @@ -142,6 +145,9 @@
   /* Stream creation and modification */
   API_EXPORT(BUFF *) ap_bcreate(pool *p, int flags);
   API_EXPORT(void) ap_bpushfd(BUFF *fb, int fd_in, int fd_out);
  +#ifdef WIN32
  +API_EXPORT(void) ap_bpushh(BUFF *fb, HANDLE hFH);
  +#endif
   API_EXPORT(int) ap_bsetopt(BUFF *fb, int optname, const void *optval);
   API_EXPORT(int) ap_bgetopt(BUFF *fb, int optname, void *optval);
   API_EXPORT(int) ap_bsetflag(BUFF *fb, int flag, int value);
  @@ -191,9 +197,20 @@
   		     ?os_toascii[(unsigned char)c]:(c), 0))
   
   #endif /*CHARSET_EBCDIC*/
  -API_EXPORT(int) ap_spawn_child_err_buff(pool *, int (*)(void *), void *,
  -		      enum kill_conditions, BUFF **pipe_in, BUFF **pipe_out,
  -				     BUFF **pipe_err);
  +typedef struct {
  +#ifdef WIN32
  +    /*
  +     *  These handles are used by ap_call_exec to call 
  +     *  create process with pipe handles.
  +     */
  +    HANDLE hPipeInputRead;
  +    HANDLE hPipeOutputWrite;
  +    HANDLE hPipeErrorWrite;
  +#endif
  +} child_info;
  +API_EXPORT(int) ap_spawn_child_err_buff(pool *, int (*)(void *, child_info *), void *,
  +					enum kill_conditions, BUFF **pipe_in, BUFF **pipe_out,
  +					BUFF **pipe_err);
   
   /* enable non-blocking operations */
   API_EXPORT(int) ap_bnonblock(BUFF *fb, int direction);
  
  
  
  1.32      +1 -1      apache-1.3/src/include/util_script.h
  
  Index: util_script.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/util_script.h,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- util_script.h	1998/05/03 17:31:11	1.31
  +++ util_script.h	1998/05/16 16:34:47	1.32
  @@ -79,7 +79,7 @@
   API_EXPORT(int) ap_scan_script_header_err_buff(request_rec *r, BUFF *f,
                                               char *buffer);
   API_EXPORT(void) ap_send_size(size_t size, request_rec *r);
  -API_EXPORT(int) ap_call_exec(request_rec *r, char *argv0, char **env,
  +API_EXPORT(int) ap_call_exec(request_rec *r, child_info *pinfo, char *argv0, char **env,
                             int shellcmd);
   
   #ifdef __cplusplus
  
  
  
  1.92      +162 -4    apache-1.3/src/main/alloc.c
  
  Index: alloc.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/alloc.c,v
  retrieving revision 1.91
  retrieving revision 1.92
  diff -u -r1.91 -r1.92
  --- alloc.c	1998/05/06 19:49:50	1.91
  +++ alloc.c	1998/05/16 16:34:47	1.92
  @@ -1533,6 +1533,36 @@
       return res;
   }
   
  +#ifdef WIN32
  +static void h_cleanup(void *fdv)
  +{
  +    CloseHandle((HANDLE) fdv);
  +}
  +
  +API_EXPORT(void) ap_note_cleanups_for_h(pool *p, HANDLE hDevice)
  +{
  +    ap_register_cleanup(p, (void *) hDevice, h_cleanup, h_cleanup);
  +}
  +
  +API_EXPORT(int) ap_pcloseh(pool *a, HANDLE hDevice)
  +{
  +    int res=0;
  +    int save_errno;
  +
  +    ap_block_alarms();
  +    
  +    if (!CloseHandle(hDevice)) {
  +        res = GetLastError();
  +    }
  +    
  +    save_errno = errno;
  +    ap_kill_cleanup(a, (void *) hDevice, h_cleanup);
  +    ap_unblock_alarms();
  +    errno = save_errno;
  +    return res;
  +}
  +#endif
  +
   /* Note that we have separate plain_ and child_ cleanups for FILE *s,
    * since fclose() would flush I/O buffers, which is extremely undesirable;
    * we just close the descriptor.
  @@ -2011,12 +2041,139 @@
       ap_unblock_alarms();
       return pid;
   }
  -
   
  -API_EXPORT(int) ap_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)
  +API_EXPORT(int) ap_spawn_child_err_buff(pool *p, int (*func) (void *, child_info *), void *data,
  +					enum kill_conditions kill_how,
  +					BUFF **pipe_in, BUFF **pipe_out, BUFF **pipe_err)
   {
  +#ifdef WIN32
  +    SECURITY_ATTRIBUTES sa = {0};  
  +    HANDLE hPipeOutputRead  = NULL;
  +    HANDLE hPipeOutputWrite = NULL;
  +    HANDLE hPipeInputRead   = NULL;
  +    HANDLE hPipeInputWrite  = NULL;
  +    HANDLE hPipeErrorRead   = NULL;
  +    HANDLE hPipeErrorWrite  = NULL;
  +    int pid = 0;
  +    child_info info;
  +
  +
  +    ap_block_alarms();
  +
  +    /*
  +     *  First thing to do is to create the pipes that we will use for stdin, stdout, and
  +     *  stderr in the child process.
  +     */      
  +    sa.nLength = sizeof(sa);
  +    sa.bInheritHandle = TRUE;
  +    sa.lpSecurityDescriptor = NULL;
  +
  +
  +    /* Create pipes for standard input/output/error redirection. */
  +    if (pipe_in && !CreatePipe(&hPipeInputRead, &hPipeInputWrite, &sa, 0))
  +	return 0;
  +
  +    if (pipe_out && !CreatePipe(&hPipeOutputRead, &hPipeOutputWrite, &sa, 0)) {
  +	if(pipe_in) {
  +	    CloseHandle(hPipeInputRead);
  +	    CloseHandle(hPipeInputWrite);
  +	}
  +	return 0;
  +    }
  +
  +    if (pipe_err && !CreatePipe(&hPipeErrorRead, &hPipeErrorWrite, &sa, 0)) {
  +	if(pipe_in) {
  +	    CloseHandle(hPipeInputRead);
  +	    CloseHandle(hPipeInputWrite);
  +	}
  +	if(pipe_out) {
  +	    CloseHandle(hPipeOutputRead);
  +	    CloseHandle(hPipeOutputWrite);
  +	}
  +	return 0;
  +    }
  +
  +    /* The script writes stdout to this pipe handle */
  +    info.hPipeOutputWrite = hPipeOutputWrite;  
  +
  +    /* The script reads stdin from this pipe handle */
  +    info.hPipeInputRead = hPipeInputRead;
  +
  +    /* The script writes stderr to this pipe handle */
  +    info.hPipeErrorWrite = hPipeErrorWrite;    
  +     
  +    /*
  +     *  Try to launch the CGI.  Under the covers, this call 
  +     *  will try to pick up the appropriate interpreter if 
  +     *  one is needed.
  +     */
  +    pid = func(data, &info);
  +    if (pid == -1) {
  +        /* Things didn't work, so cleanup */
  +        pid = 0;   /* map Win32 error code onto Unix default */
  +        CloseHandle(hPipeOutputRead);
  +        CloseHandle(hPipeInputWrite);
  +        CloseHandle(hPipeErrorRead);
  +    }
  +    else {
  +        if (pipe_out) {
  +            /*
  +             *  This pipe represents stdout for the script, 
  +             *  so we read from this pipe.
  +             */
  +	    /* Create a read buffer */
  +            *pipe_out = ap_bcreate(p, B_RD);
  +
  +	    /* Setup the cleanup routine for the handle */
  +            ap_note_cleanups_for_h(p, hPipeOutputRead);   
  +
  +	    /* Associate the handle with the new buffer */
  +            ap_bpushh(*pipe_out, hPipeOutputRead);
  +        }
  +        
  +        if (pipe_in) {
  +            /*
  +             *  This pipe represents stdin for the script, so we 
  +             *  write to this pipe.
  +             */
  +	    /* Create a write buffer */
  +            *pipe_in = ap_bcreate(p, B_WR);             
  +
  +	    /* Setup the cleanup routine for the handle */
  +            ap_note_cleanups_for_h(p, hPipeInputWrite);
  +
  +	    /* Associate the handle with the new buffer */
  +            ap_bpushh(*pipe_in, hPipeInputWrite);
  +
  +        }
  +      
  +        if (pipe_err) {
  +            /*
  +             *  This pipe represents stderr for the script, so 
  +             *  we read from this pipe.
  +             */
  +	    /* Create a read buffer */
  +            *pipe_err = ap_bcreate(p, B_RD);
  +
  +	    /* Setup the cleanup routine for the handle */
  +            ap_note_cleanups_for_h(p, hPipeErrorRead);
  +
  +	    /* Associate the handle with the new buffer */
  +            ap_bpushh(*pipe_err, hPipeErrorRead);
  +        }
  +    }  
  +
  +
  +    /*
  +     * Now that handles have been inherited, close them to be safe.
  +     * You don't want to read or write to them accidentally, and we
  +     * sure don't want to have a handle leak.
  +     */
  +    CloseHandle(hPipeOutputWrite);
  +    CloseHandle(hPipeInputRead);
  +    CloseHandle(hPipeErrorWrite);
  +
  +#else
       int fd_in, fd_out, fd_err;
       int pid, save_errno;
   
  @@ -2051,6 +2208,7 @@
   	ap_note_cleanups_for_fd(p, fd_err);
   	ap_bpushfd(*pipe_err, fd_err, fd_err);
       }
  +#endif
   
       ap_unblock_alarms();
       return pid;
  
  
  
  1.76      +34 -3     apache-1.3/src/main/buff.c
  
  Index: buff.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/buff.c,v
  retrieving revision 1.75
  retrieving revision 1.76
  diff -u -r1.75 -r1.76
  --- buff.c	1998/05/08 22:54:52	1.75
  +++ buff.c	1998/05/16 16:34:48	1.76
  @@ -235,7 +235,14 @@
   {
       int rv;
       
  -    rv = read(fb->fd_in, buf, nbyte);
  +#ifdef WIN32
  +    if (fb->hFH != INVALID_HANDLE_VALUE) {
  +        if (!ReadFile(fb->hFH,buf,nbyte,&rv,NULL))
  +            rv = -1;
  +    }
  +    else
  +#endif
  +	rv = read(fb->fd_in, buf, nbyte);
       
       return rv;
   }
  @@ -263,10 +270,17 @@
   {
       int rv;
       
  +#ifdef WIN32
  +    if (fb->hFH != INVALID_HANDLE_VALUE) {
  +        if (!WriteFile(fb->hFH,buf,nbyte,&rv,NULL))
  +          rv = -1;
  +    }
  +    else
  +#endif
   #if defined (B_SFIO)
  -    rv = sfwrite(fb->sf_out, buf, nbyte);
  +	rv = sfwrite(fb->sf_out, buf, nbyte);
   #else
  -    rv = write(fb->fd, buf, nbyte);
  +	rv = write(fb->fd, buf, nbyte);
   #endif
       
       return rv;
  @@ -340,6 +354,9 @@
   
       fb->fd = -1;
       fb->fd_in = -1;
  +#ifdef WIN32
  +    fb->hFH = INVALID_HANDLE_VALUE;
  +#endif
   
   #ifdef B_SFIO
       fb->sf_in = NULL;
  @@ -362,6 +379,16 @@
       fb->fd_in = fd_in;
   }
   
  +#ifdef WIN32
  +/*
  + * Push some Win32 handles onto the stream.
  + */
  +API_EXPORT(void) ap_bpushh(BUFF *fb, HANDLE hFH)
  +{
  +    fb->hFH = hFH;
  +}
  +#endif
  +
   API_EXPORT(int) ap_bsetopt(BUFF *fb, int optname, const void *optval)
   {
       if (optname == BO_BYTECT) {
  @@ -1373,6 +1400,10 @@
   	else {
   	    rc3 = 0;
   	}
  +    }
  +    else if (fb->hFH != INVALID_HANDLE_VALUE) {
  +	    rc2 = ap_pcloseh(fb->pool, fb->hFH);
  +	    rc3 = 0;
       }
       else {
   #endif
  
  
  
  1.57      +2 -1      apache-1.3/src/main/http_log.c
  
  Index: http_log.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/http_log.c,v
  retrieving revision 1.56
  retrieving revision 1.57
  diff -u -r1.56 -r1.57
  --- http_log.c	1998/05/04 16:28:47	1.56
  +++ http_log.c	1998/05/16 16:34:48	1.57
  @@ -651,7 +651,7 @@
   {
       piped_log *pl;
       FILE *dummy;
  -    
  +
       if (!spawn_child (p, piped_log_child, (void *)program,
   		kill_after_timeout, &dummy, NULL)) {
   	perror ("spawn_child");
  @@ -661,6 +661,7 @@
       pl = ap_palloc (p, sizeof (*pl));
       pl->p = p;
       pl->write_f = dummy;
  +
       return pl;
   }
   
  
  
  
  1.110     +110 -1    apache-1.3/src/main/util_script.c
  
  Index: util_script.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/util_script.c,v
  retrieving revision 1.109
  retrieving revision 1.110
  diff -u -r1.109 -r1.110
  --- util_script.c	1998/05/10 02:20:12	1.109
  +++ util_script.c	1998/05/16 16:34:48	1.110
  @@ -586,7 +586,7 @@
   #endif
   
   
  -API_EXPORT(int) ap_call_exec(request_rec *r, char *argv0, char **env, int shellcmd)
  +API_EXPORT(int) ap_call_exec(request_rec *r, child_info *pinfo, char *argv0, char **env, int shellcmd)
   {
       int pid = 0;
   #if defined(RLIMIT_CPU)  || defined(RLIMIT_NPROC) || \
  @@ -715,7 +715,13 @@
   	char *dot;
   	char *exename;
   	int is_exe = 0;
  +	STARTUPINFO si;
  +	PROCESS_INFORMATION pi;
  +	char *pCommand;
   
  +	memset(&si, 0, sizeof(si));
  +	memset(&pi, 0, sizeof(pi));
  +
   	interpreter[0] = 0;
   
   	exename = strrchr(r->filename, '/');
  @@ -770,6 +776,108 @@
   	    }
   	}
   
  +	/*
  +	 * Make child process use hPipeOutputWrite as standard out,
  +	 * and make sure it does not show on screen.
  +	 */
  +	si.cb = sizeof(si);
  +	si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  +	si.wShowWindow = SW_HIDE;
  +	si.hStdInput   = pinfo->hPipeInputRead;
  +	si.hStdOutput  = pinfo->hPipeOutputWrite;
  +	si.hStdError   = pinfo->hPipeErrorWrite;
  +	
  +	pid = -1;      
  +	if ((!r->args) || (!r->args[0]) || strchr(r->args, '=')) { 
  +	    if (is_exe || is_binary) {
  +	        /*
  +	         * When the CGI is a straight binary executable, 
  +		 * we can run it as is
  +	         */
  +	        pCommand = r->filename;
  +	    }
  +	    else if (is_script) {
  +                /* When an interpreter is needed, we need to create 
  +                 * a command line that has the interpreter name
  +                 * followed by the CGI script name.  
  +		 */
  +	        pCommand = ap_pstrcat(r->pool, interpreter + 2, " ", 
  +				      r->filename, NULL);
  +	    }
  +	    else {
  +	        /* If not an executable or script, just execute it
  +                 * from a command prompt.  
  +                 */
  +	        pCommand = ap_pstrcat(r->pool, "CMD.EXE", " /C ", 
  +				      r->filename, NULL);
  +	    }
  +	}
  +	else {
  +
  +            /* If we are in this leg, there are some other arguments
  +             * that we must include in the execution of the CGI.
  +             * Because CreateProcess is the way it is, we have to
  +             * create a command line like format for the execution
  +             * of the CGI.  This means we need to create on long
  +             * string with the executable and arguments.
  +             *
  +             * The arguments string comes in the request structure,
  +             * and each argument is separated by a '+'.  We'll replace
  +             * these pluses with spaces.
  +	     */
  +	    char *arguments=NULL;
  +	    int iStringSize = 0;
  +	    int x;
  +	    
  +	    /*
  +	     *  Duplicate the request structure string so we don't change it.
  +	     */                                   
  +	    arguments = ap_pstrdup(r->pool, r->args);
  +       
  +	    /*
  +	     *  Change the '+' to ' '
  +	     */
  +	    for (x=0; arguments[x]; x++) {
  +	        if ('+' == arguments[x]) {
  +		  arguments[x] = ' ';
  +		}
  +	    }
  +       
  +	    /*
  +	     * We need to unescape any characters that are 
  +             * in the arguments list.
  +	     */
  +	    ap_unescape_url(arguments);
  +	    arguments = ap_escape_shell_cmd(r->pool, arguments);
  +           
  +	    /*
  +	     * The argument list should now be good to use, 
  +	     * so now build the command line.
  +	     */
  +	    if (is_exe || is_binary) {
  +	        pCommand = ap_pstrcat(r->pool, r->filename, " ", 
  +				      arguments, NULL);
  +	    }
  +	    else if (is_script) {
  +	        pCommand = ap_pstrcat(r->pool, interpreter + 2, " ", 
  +				      r->filename, " ", arguments, NULL);
  +	    }
  +	    else {
  +	        pCommand = ap_pstrcat(r->pool, "CMD.EXE", " /C ", 
  +				      r->filename, " ", arguments, NULL);
  +	    }
  +	}
  +	
  +	if (CreateProcess(NULL, pCommand, NULL, NULL, TRUE, 0, env, NULL, &si, &pi)) {
  +	  pid = pi.dwProcessId;
  +	  /*
  +	   * We must close the handles to the new process and its main thread
  +	   * to prevent handle and memory leaks.
  +	   */ 
  +	  CloseHandle(pi.hProcess);
  +	  CloseHandle(pi.hThread);
  +	}
  +#if 0
   	if ((!r->args) || (!r->args[0]) || strchr(r->args, '=')) {
   	    if (is_exe || is_binary) {
   		pid = spawnle(_P_NOWAIT, r->filename, r->filename, NULL, env);
  @@ -800,6 +908,7 @@
   					      r->filename), env);
   	    }
   	}
  +#endif
   	return (pid);
       }
   #else
  
  
  
  1.78      +5 -5      apache-1.3/src/modules/standard/mod_cgi.c
  
  Index: mod_cgi.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_cgi.c,v
  retrieving revision 1.77
  retrieving revision 1.78
  diff -u -r1.77 -r1.78
  --- mod_cgi.c	1998/05/09 02:28:22	1.77
  +++ mod_cgi.c	1998/05/16 16:34:50	1.78
  @@ -281,7 +281,7 @@
       char *argv0;
   };
   
  -static int cgi_child(void *child_stuff)
  +static int cgi_child(void *child_stuff, child_info *pinfo)
   {
       struct cgi_child_stuff *cld = (struct cgi_child_stuff *) child_stuff;
       request_rec *r = cld->r;
  @@ -327,7 +327,7 @@
   
       ap_cleanup_for_exec();
   
  -    child_pid = ap_call_exec(r, argv0, env, 0);
  +    child_pid = ap_call_exec(r, pinfo, argv0, env, 0);
   #ifdef WIN32
       return (child_pid);
   #else
  @@ -429,9 +429,9 @@
        * SSI request -djg
        */
       if (!ap_spawn_child_err_buff(r->main ? r->main->pool : r->pool, cgi_child,
  -			            (void *) &cld,
  -			       kill_after_timeout,
  -			       &script_out, &script_in, &script_err)) {
  +			         (void *) &cld,
  +			         kill_after_timeout,
  +			         &script_out, &script_in, &script_err)) {
   	ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
   		    "couldn't spawn child process: %s", r->filename);
   	return SERVER_ERROR;
  
  
  
  1.86      +7 -1      apache-1.3/src/modules/standard/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_include.c,v
  retrieving revision 1.85
  retrieving revision 1.86
  diff -u -r1.85 -r1.86
  --- mod_include.c	1998/05/09 02:28:22	1.85
  +++ mod_include.c	1998/05/16 16:34:50	1.86
  @@ -729,6 +729,7 @@
       }
   }
   
  +#ifndef WIN32
   typedef struct {
       request_rec *r;
       char *s;
  @@ -825,7 +826,7 @@
                                    */
       return 0;
   }
  -
  +#endif
   
   static int handle_exec(FILE *in, request_rec *r, const char *error)
   {
  @@ -839,6 +840,10 @@
               return 1;
           }
           if (!strcmp(tag, "cmd")) {
  +#ifdef WIN32
  +            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
  +                        "cmd in SSI temporarily disabled");
  +#else
               parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 1);
               if (include_cmd(parsed_string, r) == -1) {
                   ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
  @@ -850,6 +855,7 @@
               /* just in case some stooge changed directories */
   #ifndef WIN32
               ap_chdir_file(r->filename);
  +#endif
   #endif
           }
           else if (!strcmp(tag, "cgi")) {