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")) {