Blame src/LYCgi.c

Packit f574b8
/*
Packit f574b8
 * $LynxId: LYCgi.c,v 1.72 2018/03/18 18:56:05 tom Exp $
Packit f574b8
 *                   Lynx CGI support                              LYCgi.c
Packit f574b8
 *                   ================
Packit f574b8
 *
Packit f574b8
 * Authors
Packit f574b8
 *          GL      George Lindholm <George.Lindholm@ubc.ca>
Packit f574b8
 *
Packit f574b8
 * History
Packit f574b8
 *      15 Jun 95   Created as way to provide a lynx based service with
Packit f574b8
 *                  dynamic pages without the need for a http daemon.  GL
Packit f574b8
 *      27 Jun 95   Added <index> (command line) support.  Various cleanup
Packit f574b8
 *                  and bug fixes. GL
Packit f574b8
 *	04 Sep 97   Added support for PATH_INFO scripts.  JKT
Packit f574b8
 *
Packit f574b8
 * Bugs
Packit f574b8
 *      If the called scripts aborts before sending the mime headers then
Packit f574b8
 *      lynx hangs.
Packit f574b8
 *
Packit f574b8
 *      Should do something about SIGPIPE, (but then it should never happen)
Packit f574b8
 *
Packit f574b8
 *      No support for redirection.  Or mime-types.
Packit f574b8
 *
Packit f574b8
 *      Should try and parse for a HTTP 1.1 header in case we are "calling" a
Packit f574b8
 *      nph- script.
Packit f574b8
 */
Packit f574b8
Packit f574b8
#include <HTUtils.h>
Packit f574b8
#include <HTTP.h>
Packit f574b8
#include <HTParse.h>
Packit f574b8
#include <HTTCP.h>
Packit f574b8
#include <HTFormat.h>
Packit f574b8
#include <HTFile.h>
Packit f574b8
#include <HTAlert.h>
Packit f574b8
#include <HTMIME.h>
Packit f574b8
#include <HTAABrow.h>
Packit f574b8
Packit f574b8
#include <LYGlobalDefs.h>
Packit f574b8
#include <LYUtils.h>
Packit f574b8
#include <HTML.h>
Packit f574b8
#include <HTInit.h>
Packit f574b8
#include <LYGetFile.h>
Packit f574b8
#include <LYBookmark.h>
Packit f574b8
#include <GridText.h>
Packit f574b8
#include <LYCgi.h>
Packit f574b8
#include <LYStrings.h>
Packit f574b8
#include <LYLocal.h>
Packit f574b8
Packit f574b8
#include <LYLeaks.h>
Packit f574b8
#include <www_wait.h>
Packit f574b8
Packit f574b8
static char **env = NULL;	/* Environment variables */
Packit f574b8
static unsigned envc_size = 0;	/* Slots in environment array */
Packit f574b8
static unsigned envc = 0;	/* Slots used so far */
Packit f574b8
static HTList *alloced = NULL;
Packit f574b8
Packit f574b8
#if defined(LYNXCGI_LINKS) && !defined(__MINGW32__)
Packit f574b8
static char *user_agent = NULL;
Packit f574b8
static char *server_software = NULL;
Packit f574b8
static char *accept_language = NULL;
Packit f574b8
static char *post_len = NULL;
Packit f574b8
#endif /* LYNXCGI_LINKS */
Packit f574b8
Packit f574b8
static void add_environment_value(const char *env_value);
Packit f574b8
Packit f574b8
#define PERROR(msg) CTRACE((tfp, "LYNXCGI: %s: %s\n", msg, LYStrerror(errno)))
Packit f574b8
Packit f574b8
#define PUTS(buf)    (*target->isa->put_block)(target, buf, strlen(buf))
Packit f574b8
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
static void free_alloced_lynxcgi(void)
Packit f574b8
{
Packit f574b8
    void *ptr;
Packit f574b8
Packit f574b8
    while ((ptr = HTList_removeLastObject(alloced)) != NULL) {
Packit f574b8
	FREE(ptr);
Packit f574b8
    }
Packit f574b8
    FREE(alloced);
Packit f574b8
#ifdef LYNXCGI_LINKS
Packit f574b8
    FREE(user_agent);
Packit f574b8
    FREE(server_software);
Packit f574b8
#endif
Packit f574b8
}
Packit f574b8
#endif /* LY_FIND_LEAKS */
Packit f574b8
Packit f574b8
static void remember_alloced(void *ptr)
Packit f574b8
{
Packit f574b8
    if (!alloced) {
Packit f574b8
	alloced = HTList_new();
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
	atexit(free_alloced_lynxcgi);
Packit f574b8
#endif
Packit f574b8
    }
Packit f574b8
    HTList_addObject(alloced, ptr);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Simple routine for expanding the environment array and adding a value to
Packit f574b8
 * it
Packit f574b8
 */
Packit f574b8
static void add_environment_value(const char *env_value)
Packit f574b8
{
Packit f574b8
    if (envc == envc_size) {	/* Need some more slots */
Packit f574b8
	envc_size += 10;
Packit f574b8
	if (env) {
Packit f574b8
	    env = (char **) realloc(env,
Packit f574b8
				    sizeof(env[0]) * (envc_size + 2));
Packit f574b8
	    /* + terminator and base 0 */
Packit f574b8
	} else {
Packit f574b8
	    env = (char **) malloc(sizeof(env[0]) * (envc_size + 2));
Packit f574b8
	    /* + terminator and base 0 */
Packit f574b8
	    remember_alloced(env);
Packit f574b8
	}
Packit f574b8
	if (env == NULL) {
Packit f574b8
	    outofmem(__FILE__, "LYCgi");
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    env[envc++] = DeConst(env_value);
Packit f574b8
    env[envc] = NULL;		/* Make sure it is always properly terminated */
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Add the value of an existing environment variable to those passed on to the
Packit f574b8
 * lynxcgi script.
Packit f574b8
 */
Packit f574b8
void add_lynxcgi_environment(const char *variable_name)
Packit f574b8
{
Packit f574b8
    char *env_value;
Packit f574b8
Packit f574b8
    env_value = LYGetEnv(variable_name);
Packit f574b8
    if (env_value != NULL) {
Packit f574b8
	char *add_value = NULL;
Packit f574b8
Packit f574b8
	HTSprintf0(&add_value, "%s=%s", variable_name, env_value);
Packit f574b8
	add_environment_value(add_value);
Packit f574b8
	remember_alloced(add_value);
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
#ifdef __MINGW32__
Packit f574b8
static int LYLoadCGI(const char *arg,
Packit f574b8
		     HTParentAnchor *anAnchor,
Packit f574b8
		     HTFormat format_out,
Packit f574b8
		     HTStream *sink)
Packit f574b8
{
Packit f574b8
    (void) arg;
Packit f574b8
    (void) anAnchor;
Packit f574b8
    (void) format_out;
Packit f574b8
    (void) sink;
Packit f574b8
    return -1;
Packit f574b8
}
Packit f574b8
#else
Packit f574b8
#ifdef LYNXCGI_LINKS
Packit f574b8
/*
Packit f574b8
 * Wrapper for exec_ok(), confirming with user if the link text is not visible
Packit f574b8
 * in the status line.
Packit f574b8
 */
Packit f574b8
static BOOL can_exec_cgi(const char *linktext, const char *linkargs)
Packit f574b8
{
Packit f574b8
    const char *format = gettext("Do you want to execute \"%s\"?");
Packit f574b8
    char *message = NULL;
Packit f574b8
    char *command = NULL;
Packit f574b8
    char *p;
Packit f574b8
    BOOL result = TRUE;
Packit f574b8
Packit f574b8
    if (!exec_ok(HTLoadedDocumentURL(), linktext, CGI_PATH)) {
Packit f574b8
	/* exec_ok gives out msg. */
Packit f574b8
	result = FALSE;
Packit f574b8
    } else {
Packit f574b8
	StrAllocCopy(command, linktext);
Packit f574b8
	if (non_empty(linkargs)) {
Packit f574b8
	    HTSprintf(&command, " %s", linkargs);
Packit f574b8
	}
Packit f574b8
	HTUnEscape(command);
Packit f574b8
	for (p = command; *p; ++p)
Packit f574b8
	    if (*p == '+')
Packit f574b8
		*p = ' ';
Packit f574b8
	HTSprintf0(&message, format, command);
Packit f574b8
	result = HTConfirm(message);
Packit f574b8
	FREE(message);
Packit f574b8
	FREE(command);
Packit f574b8
    }
Packit f574b8
    return result;
Packit f574b8
}
Packit f574b8
#endif /* LYNXCGI_LINKS */
Packit f574b8
Packit f574b8
static int LYLoadCGI(const char *arg,
Packit f574b8
		     HTParentAnchor *anAnchor,
Packit f574b8
		     HTFormat format_out,
Packit f574b8
		     HTStream *sink)
Packit f574b8
{
Packit f574b8
    int status = 0;
Packit f574b8
Packit f574b8
#ifdef LYNXCGI_LINKS
Packit f574b8
#ifndef VMS
Packit f574b8
    char *cp;
Packit f574b8
    struct stat stat_buf;
Packit f574b8
    char *pgm = NULL;		/* executable */
Packit f574b8
    char *pgm_args = NULL;	/* and its argument(s) */
Packit f574b8
    int statrv;
Packit f574b8
    char *orig_pgm = NULL;	/* Path up to ? as given, URL-escaped */
Packit f574b8
    char *document_root = NULL;	/* Corrected value of DOCUMENT_ROOT  */
Packit f574b8
    char *path_info = NULL;	/* PATH_INFO extracted from pgm      */
Packit f574b8
    char *pgm_buff = NULL;	/* PATH_INFO extraction buffer       */
Packit f574b8
    char *path_translated;	/* From document_root/path_info      */
Packit f574b8
Packit f574b8
    if (isEmpty(arg) || strlen(arg) <= 8) {
Packit f574b8
	HTAlert(BAD_REQUEST);
Packit f574b8
	status = -2;
Packit f574b8
	return (status);
Packit f574b8
Packit f574b8
    } else {
Packit f574b8
	if (StrNCmp(arg, "lynxcgi://localhost", 19) == 0) {
Packit f574b8
	    StrAllocCopy(pgm, arg + 19);
Packit f574b8
	} else {
Packit f574b8
	    StrAllocCopy(pgm, arg + 8);
Packit f574b8
	}
Packit f574b8
	if ((cp = StrChr(pgm, '?')) != NULL) {	/* Need to terminate executable */
Packit f574b8
	    *cp++ = '\0';
Packit f574b8
	    pgm_args = cp;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    StrAllocCopy(orig_pgm, pgm);
Packit f574b8
    if (trimPoundSelector(pgm) != NULL) {
Packit f574b8
	/*
Packit f574b8
	 * Strip a #fragment from path.  In this case any pgm_args found above
Packit f574b8
	 * will also be bogus, since the '?' came after the '#' and is part of
Packit f574b8
	 * the fragment.  Note that we don't handle the case where a '#'
Packit f574b8
	 * appears after a '?' properly according to URL rules.  - kw
Packit f574b8
	 */
Packit f574b8
	pgm_args = NULL;
Packit f574b8
    }
Packit f574b8
    HTUnEscape(pgm);
Packit f574b8
Packit f574b8
    /* BEGIN WebSter Mods */
Packit f574b8
    /* If pgm is not stat-able, see if PATH_INFO data is at the end of pgm */
Packit f574b8
    if ((statrv = stat(pgm, &stat_buf)) < 0) {
Packit f574b8
	StrAllocCopy(pgm_buff, pgm);
Packit f574b8
	while (statrv < 0 || (statrv = stat(pgm_buff, &stat_buf)) < 0) {
Packit f574b8
	    if ((cp = strrchr(pgm_buff, '/')) != NULL) {
Packit f574b8
		*cp = '\0';
Packit f574b8
		statrv = 1;	/* force new stat()  - kw */
Packit f574b8
	    } else {
Packit f574b8
		PERROR("strrchr(pgm_buff, '/') returned NULL");
Packit f574b8
		break;
Packit f574b8
	    }
Packit f574b8
	}
Packit f574b8
Packit f574b8
	if (statrv < 0) {
Packit f574b8
	    /* Did not find PATH_INFO data */
Packit f574b8
	    PERROR("stat() of pgm_buff failed");
Packit f574b8
	} else {
Packit f574b8
	    /* Found PATH_INFO data.  Strip it off of pgm and into path_info. */
Packit f574b8
	    StrAllocCopy(path_info, pgm + strlen(pgm_buff));
Packit f574b8
	    /* The following is safe since pgm_buff was derived from pgm
Packit f574b8
	       by stripping stuff off its end and by HTUnEscaping, so we
Packit f574b8
	       know we have enough memory allocated for pgm.  Note that
Packit f574b8
	       pgm_args may still point into that memory, so we cannot
Packit f574b8
	       reallocate pgm here. - kw */
Packit f574b8
	    strcpy(pgm, pgm_buff);
Packit f574b8
	    CTRACE((tfp,
Packit f574b8
		    "LYNXCGI: stat() of %s succeeded, path_info=\"%s\".\n",
Packit f574b8
		    pgm_buff, path_info));
Packit f574b8
	}
Packit f574b8
	FREE(pgm_buff);
Packit f574b8
    }
Packit f574b8
    /* END WebSter Mods */
Packit f574b8
Packit f574b8
    if (statrv != 0) {
Packit f574b8
	/*
Packit f574b8
	 * Neither the path as given nor any components examined by backing up
Packit f574b8
	 * were stat()able.  - kw
Packit f574b8
	 */
Packit f574b8
	HTAlert(gettext("Unable to access cgi script"));
Packit f574b8
	PERROR("stat() failed");
Packit f574b8
	status = -4;
Packit f574b8
Packit f574b8
    } else
Packit f574b8
#ifdef _WINDOWS			/* 1998/01/14 (Wed) 09:16:04 */
Packit f574b8
#define isExecutable(mode) (mode & (S_IXUSR))
Packit f574b8
#else
Packit f574b8
#define isExecutable(mode) (mode & (S_IXUSR|S_IXGRP|S_IXOTH))
Packit f574b8
#endif
Packit f574b8
    if (!(S_ISREG(stat_buf.st_mode) && isExecutable(stat_buf.st_mode))) {
Packit f574b8
	/*
Packit f574b8
	 * Not a runnable file, See if we can load it using "file:" code.
Packit f574b8
	 */
Packit f574b8
	char *new_arg = NULL;
Packit f574b8
Packit f574b8
	/*
Packit f574b8
	 * But try "file:" only if the file we are looking at is the path as
Packit f574b8
	 * given (no path_info was extracted), otherwise it will be to
Packit f574b8
	 * confusing to know just what file is loaded.  - kw
Packit f574b8
	 */
Packit f574b8
	if (path_info) {
Packit f574b8
	    CTRACE((tfp,
Packit f574b8
		    "%s is not a file and %s not an executable, giving up.\n",
Packit f574b8
		    orig_pgm, pgm));
Packit f574b8
	    FREE(path_info);
Packit f574b8
	    FREE(pgm);
Packit f574b8
	    FREE(orig_pgm);
Packit f574b8
	    status = -4;
Packit f574b8
	    return (status);
Packit f574b8
	}
Packit f574b8
Packit f574b8
	LYLocalFileToURL(&new_arg, orig_pgm);
Packit f574b8
Packit f574b8
	CTRACE((tfp, "%s is not an executable file, passing the buck.\n", arg));
Packit f574b8
	status = HTLoadFile(new_arg, anAnchor, format_out, sink);
Packit f574b8
	FREE(new_arg);
Packit f574b8
Packit f574b8
    } else if (path_info &&
Packit f574b8
	       anAnchor != HTMainAnchor &&
Packit f574b8
	       !(reloading && anAnchor->document) &&
Packit f574b8
	       strcmp(arg, HTLoadedDocumentURL()) &&
Packit f574b8
	       HText_AreDifferent(anAnchor, arg) &&
Packit f574b8
	       HTUnEscape(orig_pgm) &&
Packit f574b8
	       !can_exec_cgi(orig_pgm, "")) {
Packit f574b8
	/*
Packit f574b8
	 * If we have extra path info and are not just reloading the current,
Packit f574b8
	 * check the full file path (after unescaping) now to catch forbidden
Packit f574b8
	 * segments.  - kw
Packit f574b8
	 */
Packit f574b8
	status = HT_NOT_LOADED;
Packit f574b8
Packit f574b8
    } else if (no_lynxcgi) {
Packit f574b8
	HTUserMsg(CGI_DISABLED);
Packit f574b8
	status = HT_NOT_LOADED;
Packit f574b8
Packit f574b8
    } else if (no_bookmark_exec &&
Packit f574b8
	       anAnchor != HTMainAnchor &&
Packit f574b8
	       !(reloading && anAnchor->document) &&
Packit f574b8
	       strcmp(arg, HTLoadedDocumentURL()) &&
Packit f574b8
	       HText_AreDifferent(anAnchor, arg) &&
Packit f574b8
	       HTLoadedDocumentBookmark()) {
Packit f574b8
	/*
Packit f574b8
	 * If we are reloading a lynxcgi document that had already been loaded,
Packit f574b8
	 * the various checks above should allow it even if no_bookmark_exec is
Packit f574b8
	 * TRUE an we are not now coming from a bookmark page.  - kw
Packit f574b8
	 */
Packit f574b8
	HTUserMsg(BOOKMARK_EXEC_DISABLED);
Packit f574b8
	status = HT_NOT_LOADED;
Packit f574b8
Packit f574b8
    } else if (anAnchor != HTMainAnchor &&
Packit f574b8
	       !(reloading && anAnchor->document) &&
Packit f574b8
	       strcmp(arg, HTLoadedDocumentURL()) &&
Packit f574b8
	       HText_AreDifferent(anAnchor, arg) &&
Packit f574b8
	       !can_exec_cgi(pgm, pgm_args)) {
Packit f574b8
	/*
Packit f574b8
	 * If we are reloading a lynxcgi document that had already been loaded,
Packit f574b8
	 * the various checks above should allow it even if exec_ok() would
Packit f574b8
	 * reject it because we are not now coming from a document with a URL
Packit f574b8
	 * allowed by TRUSTED_LYNXCGI rules.  - kw
Packit f574b8
	 */
Packit f574b8
	status = HT_NOT_LOADED;
Packit f574b8
Packit f574b8
    } else {
Packit f574b8
	HTFormat format_in;
Packit f574b8
	HTStream *target = NULL;	/* Unconverted data */
Packit f574b8
	int fd1[2], fd2[2];
Packit f574b8
	char buf[MAX_LINE];
Packit f574b8
	int pid;
Packit f574b8
Packit f574b8
#ifdef HAVE_TYPE_UNIONWAIT
Packit f574b8
	union wait wstatus;
Packit f574b8
Packit f574b8
#else
Packit f574b8
	int wstatus;
Packit f574b8
#endif
Packit f574b8
Packit f574b8
	fd1[0] = -1;
Packit f574b8
	fd1[1] = -1;
Packit f574b8
	fd2[0] = -1;
Packit f574b8
	fd2[1] = -1;
Packit f574b8
Packit f574b8
	if (anAnchor->isHEAD || keep_mime_headers) {
Packit f574b8
Packit f574b8
	    /* Show output as plain text */
Packit f574b8
	    format_in = WWW_PLAINTEXT;
Packit f574b8
	} else {
Packit f574b8
Packit f574b8
	    /* Decode full HTTP response */
Packit f574b8
	    format_in = HTAtom_for("www/mime");
Packit f574b8
	}
Packit f574b8
Packit f574b8
	target = HTStreamStack(format_in,
Packit f574b8
			       format_out,
Packit f574b8
			       sink, anAnchor);
Packit f574b8
Packit f574b8
	if (target == NULL) {
Packit f574b8
	    char *tmp = 0;
Packit f574b8
Packit f574b8
	    HTSprintf0(&tmp, CANNOT_CONVERT_I_TO_O,
Packit f574b8
		       HTAtom_name(format_in),
Packit f574b8
		       HTAtom_name(format_out));
Packit f574b8
	    HTAlert(tmp);
Packit f574b8
	    FREE(tmp);
Packit f574b8
	    status = HT_NOT_LOADED;
Packit f574b8
Packit f574b8
	} else if (anAnchor->post_data && pipe(fd1) < 0) {
Packit f574b8
	    HTAlert(CONNECT_SET_FAILED);
Packit f574b8
	    PERROR("pipe() failed");
Packit f574b8
	    status = -3;
Packit f574b8
Packit f574b8
	} else if (pipe(fd2) < 0) {
Packit f574b8
	    HTAlert(CONNECT_SET_FAILED);
Packit f574b8
	    PERROR("pipe() failed");
Packit f574b8
	    close(fd1[0]);
Packit f574b8
	    close(fd1[1]);
Packit f574b8
	    status = -3;
Packit f574b8
Packit f574b8
	} else {
Packit f574b8
	    static BOOL first_time = TRUE;	/* One time setup flag */
Packit f574b8
Packit f574b8
	    if (first_time) {	/* Set up static environment variables */
Packit f574b8
		first_time = FALSE;	/* Only once */
Packit f574b8
Packit f574b8
		add_environment_value("REMOTE_HOST=localhost");
Packit f574b8
		add_environment_value("REMOTE_ADDR=127.0.0.1");
Packit f574b8
Packit f574b8
		HTSprintf0(&user_agent, "HTTP_USER_AGENT=%s/%s libwww/%s",
Packit f574b8
			   LYNX_NAME, LYNX_VERSION, HTLibraryVersion);
Packit f574b8
		add_environment_value(user_agent);
Packit f574b8
Packit f574b8
		HTSprintf0(&server_software, "SERVER_SOFTWARE=%s/%s",
Packit f574b8
			   LYNX_NAME, LYNX_VERSION);
Packit f574b8
		add_environment_value(server_software);
Packit f574b8
	    }
Packit f574b8
	    fflush(stdout);
Packit f574b8
	    fflush(stderr);
Packit f574b8
	    CTRACE_FLUSH(tfp);
Packit f574b8
Packit f574b8
	    if ((pid = fork()) > 0) {	/* The good, */
Packit f574b8
		ssize_t chars;
Packit f574b8
		off_t total_chars;
Packit f574b8
Packit f574b8
		close(fd2[1]);
Packit f574b8
Packit f574b8
		if (anAnchor->post_data) {
Packit f574b8
		    ssize_t written;
Packit f574b8
		    int remaining, total_written = 0;
Packit f574b8
Packit f574b8
		    close(fd1[0]);
Packit f574b8
Packit f574b8
		    /* We have form data to push across the pipe */
Packit f574b8
		    if (TRACE) {
Packit f574b8
			CTRACE((tfp,
Packit f574b8
				"LYNXCGI: Doing post, content-type '%s'\n",
Packit f574b8
				anAnchor->post_content_type));
Packit f574b8
			CTRACE((tfp, "LYNXCGI: Writing:\n"));
Packit f574b8
			trace_bstring(anAnchor->post_data);
Packit f574b8
			CTRACE((tfp, "----------------------------------\n"));
Packit f574b8
		    }
Packit f574b8
		    remaining = BStrLen(anAnchor->post_data);
Packit f574b8
		    while ((written = write(fd1[1],
Packit f574b8
					    BStrData(anAnchor->post_data) + total_written,
Packit f574b8
					    (size_t) remaining)) != 0) {
Packit f574b8
			if (written < 0) {
Packit f574b8
#ifdef EINTR
Packit f574b8
			    if (errno == EINTR)
Packit f574b8
				continue;
Packit f574b8
#endif /* EINTR */
Packit f574b8
#ifdef ERESTARTSYS
Packit f574b8
			    if (errno == ERESTARTSYS)
Packit f574b8
				continue;
Packit f574b8
#endif /* ERESTARTSYS */
Packit f574b8
			    PERROR("write() of POST data failed");
Packit f574b8
			    break;
Packit f574b8
			}
Packit f574b8
			CTRACE((tfp, "LYNXCGI: Wrote %d bytes of POST data.\n",
Packit f574b8
				(int) written));
Packit f574b8
			total_written += (int) written;
Packit f574b8
			remaining -= (int) written;
Packit f574b8
			if (remaining == 0)
Packit f574b8
			    break;
Packit f574b8
		    }
Packit f574b8
		    if (remaining != 0) {
Packit f574b8
			CTRACE((tfp, "LYNXCGI: %d bytes remain unwritten!\n",
Packit f574b8
				remaining));
Packit f574b8
		    }
Packit f574b8
		    close(fd1[1]);
Packit f574b8
		}
Packit f574b8
Packit f574b8
		HTReadProgress(total_chars = 0, (off_t) 0);
Packit f574b8
		while ((chars = read(fd2[0], buf, sizeof(buf))) != 0) {
Packit f574b8
		    if (chars < 0) {
Packit f574b8
#ifdef EINTR
Packit f574b8
			if (errno == EINTR)
Packit f574b8
			    continue;
Packit f574b8
#endif /* EINTR */
Packit f574b8
#ifdef ERESTARTSYS
Packit f574b8
			if (errno == ERESTARTSYS)
Packit f574b8
			    continue;
Packit f574b8
#endif /* ERESTARTSYS */
Packit f574b8
			PERROR("read() of CGI output failed");
Packit f574b8
			break;
Packit f574b8
		    }
Packit f574b8
		    total_chars += (int) chars;
Packit f574b8
		    HTReadProgress(total_chars, (off_t) 0);
Packit f574b8
		    CTRACE((tfp, "LYNXCGI: Rx: %.*s\n", (int) chars, buf));
Packit f574b8
		    (*target->isa->put_block) (target, buf, (int) chars);
Packit f574b8
		}
Packit f574b8
Packit f574b8
		if (chars < 0 && total_chars == 0) {
Packit f574b8
		    status = HT_NOT_LOADED;
Packit f574b8
		    (*target->isa->_abort) (target, NULL);
Packit f574b8
		    target = NULL;
Packit f574b8
		} else if (chars != 0) {
Packit f574b8
		    status = HT_PARTIAL_CONTENT;
Packit f574b8
		} else {
Packit f574b8
		    status = HT_LOADED;
Packit f574b8
		}
Packit f574b8
Packit f574b8
#ifndef HAVE_WAITPID
Packit f574b8
		while (wait(&wstatus) != pid) ;		/* do nothing */
Packit f574b8
#else
Packit f574b8
		while (-1 == waitpid(pid, &wstatus, 0)) {	/* wait for child */
Packit f574b8
#ifdef EINTR
Packit f574b8
		    if (errno == EINTR)
Packit f574b8
			continue;
Packit f574b8
#endif /* EINTR */
Packit f574b8
#ifdef ERESTARTSYS
Packit f574b8
		    if (errno == ERESTARTSYS)
Packit f574b8
			continue;
Packit f574b8
#endif /* ERESTARTSYS */
Packit f574b8
		    break;
Packit f574b8
		}
Packit f574b8
#endif /* !HAVE_WAITPID */
Packit f574b8
		close(fd2[0]);
Packit f574b8
Packit f574b8
	    } else if (pid == 0) {	/* The Bad, */
Packit f574b8
		char **argv = NULL;
Packit f574b8
		int argv_cnt = 3;	/* name, one arg and terminator */
Packit f574b8
		char **cur_argv = NULL;
Packit f574b8
		int exec_errno;
Packit f574b8
Packit f574b8
		/* Set up output pipe */
Packit f574b8
		close(fd2[0]);
Packit f574b8
		dup2(fd2[1], fileno(stdout));	/* Should check success code */
Packit f574b8
		dup2(fd2[1], fileno(stderr));
Packit f574b8
		close(fd2[1]);
Packit f574b8
Packit f574b8
		if (non_empty(language)) {
Packit f574b8
		    HTSprintf0(&accept_language, "HTTP_ACCEPT_LANGUAGE=%s", language);
Packit f574b8
		    add_environment_value(accept_language);
Packit f574b8
		}
Packit f574b8
Packit f574b8
		if (non_empty(pref_charset)) {
Packit f574b8
		    cp = NULL;
Packit f574b8
		    StrAllocCopy(cp, "HTTP_ACCEPT_CHARSET=");
Packit f574b8
		    StrAllocCat(cp, pref_charset);
Packit f574b8
		    add_environment_value(cp);
Packit f574b8
		}
Packit f574b8
Packit f574b8
		if (anAnchor->post_data &&
Packit f574b8
		    anAnchor->post_content_type) {
Packit f574b8
		    cp = NULL;
Packit f574b8
		    StrAllocCopy(cp, "CONTENT_TYPE=");
Packit f574b8
		    StrAllocCat(cp, anAnchor->post_content_type);
Packit f574b8
		    add_environment_value(cp);
Packit f574b8
		}
Packit f574b8
Packit f574b8
		if (anAnchor->post_data) {	/* post script, read stdin */
Packit f574b8
		    close(fd1[1]);
Packit f574b8
		    dup2(fd1[0], fileno(stdin));
Packit f574b8
		    close(fd1[0]);
Packit f574b8
Packit f574b8
		    /* Build environment variables */
Packit f574b8
Packit f574b8
		    add_environment_value("REQUEST_METHOD=POST");
Packit f574b8
Packit f574b8
		    HTSprintf0(&post_len, "CONTENT_LENGTH=%d",
Packit f574b8
			       BStrLen(anAnchor->post_data));
Packit f574b8
		    add_environment_value(post_len);
Packit f574b8
		} else {
Packit f574b8
		    close(fileno(stdin));
Packit f574b8
Packit f574b8
		    if (anAnchor->isHEAD) {
Packit f574b8
			add_environment_value("REQUEST_METHOD=HEAD");
Packit f574b8
		    }
Packit f574b8
		}
Packit f574b8
Packit f574b8
		/*
Packit f574b8
		 * Set up argument line, mainly for <index> scripts
Packit f574b8
		 */
Packit f574b8
		if (pgm_args != NULL) {
Packit f574b8
		    for (cp = pgm_args; *cp != '\0'; cp++) {
Packit f574b8
			if (*cp == '+') {
Packit f574b8
			    argv_cnt++;
Packit f574b8
			}
Packit f574b8
		    }
Packit f574b8
		}
Packit f574b8
Packit f574b8
		argv = (char **) malloc((unsigned) argv_cnt * sizeof(char *));
Packit f574b8
Packit f574b8
		if (argv == NULL) {
Packit f574b8
		    outofmem(__FILE__, "LYCgi");
Packit f574b8
		}
Packit f574b8
Packit f574b8
		cur_argv = argv + 1;	/* For argv[0] */
Packit f574b8
		if (pgm_args != NULL) {
Packit f574b8
		    char *cr;
Packit f574b8
Packit f574b8
		    /* Data for a get/search form */
Packit f574b8
		    if (is_www_index) {
Packit f574b8
			add_environment_value("REQUEST_METHOD=SEARCH");
Packit f574b8
		    } else if (!anAnchor->isHEAD && !anAnchor->post_data) {
Packit f574b8
			add_environment_value("REQUEST_METHOD=GET");
Packit f574b8
		    }
Packit f574b8
Packit f574b8
		    cp = NULL;
Packit f574b8
		    StrAllocCopy(cp, "QUERY_STRING=");
Packit f574b8
		    StrAllocCat(cp, pgm_args);
Packit f574b8
		    add_environment_value(cp);
Packit f574b8
Packit f574b8
		    /*
Packit f574b8
		     * Split up arguments into argv array
Packit f574b8
		     */
Packit f574b8
		    cp = pgm_args;
Packit f574b8
		    cr = cp;
Packit f574b8
		    while (1) {
Packit f574b8
			if (*cp == '\0') {
Packit f574b8
			    *(cur_argv++) = HTUnEscape(cr);
Packit f574b8
			    break;
Packit f574b8
Packit f574b8
			} else if (*cp == '+') {
Packit f574b8
			    *cp++ = '\0';
Packit f574b8
			    *(cur_argv++) = HTUnEscape(cr);
Packit f574b8
			    cr = cp;
Packit f574b8
			}
Packit f574b8
			cp++;
Packit f574b8
		    }
Packit f574b8
		} else if (!anAnchor->isHEAD && !anAnchor->post_data) {
Packit f574b8
		    add_environment_value("REQUEST_METHOD=GET");
Packit f574b8
		}
Packit f574b8
		*cur_argv = NULL;	/* Terminate argv */
Packit f574b8
		argv[0] = pgm;
Packit f574b8
Packit f574b8
		/* Begin WebSter Mods  -jkt */
Packit f574b8
		if (non_empty(LYCgiDocumentRoot)) {
Packit f574b8
		    /* Add DOCUMENT_ROOT to env */
Packit f574b8
		    cp = NULL;
Packit f574b8
		    StrAllocCopy(cp, "DOCUMENT_ROOT=");
Packit f574b8
		    StrAllocCat(cp, LYCgiDocumentRoot);
Packit f574b8
		    add_environment_value(cp);
Packit f574b8
		}
Packit f574b8
		if (path_info != NULL) {
Packit f574b8
		    /* Add PATH_INFO to env */
Packit f574b8
		    cp = NULL;
Packit f574b8
		    StrAllocCopy(cp, "PATH_INFO=");
Packit f574b8
		    StrAllocCat(cp, path_info);
Packit f574b8
		    add_environment_value(cp);
Packit f574b8
		}
Packit f574b8
		if (non_empty(LYCgiDocumentRoot) && path_info != NULL) {
Packit f574b8
		    /* Construct and add PATH_TRANSLATED to env */
Packit f574b8
		    StrAllocCopy(document_root, LYCgiDocumentRoot);
Packit f574b8
		    LYTrimHtmlSep(document_root);
Packit f574b8
		    path_translated = document_root;
Packit f574b8
		    StrAllocCat(path_translated, path_info);
Packit f574b8
		    cp = NULL;
Packit f574b8
		    StrAllocCopy(cp, "PATH_TRANSLATED=");
Packit f574b8
		    StrAllocCat(cp, path_translated);
Packit f574b8
		    add_environment_value(cp);
Packit f574b8
		    FREE(path_translated);
Packit f574b8
		}
Packit f574b8
		/* End WebSter Mods  -jkt */
Packit f574b8
Packit f574b8
		execve(argv[0], argv, env);
Packit f574b8
		exec_errno = errno;
Packit f574b8
		PERROR("execve failed");
Packit f574b8
		printf("Content-Type: " STR_PLAINTEXT "\r\n\r\n");
Packit f574b8
		if (!anAnchor->isHEAD) {
Packit f574b8
		    printf("exec of %s failed", pgm);
Packit f574b8
		    printf(": %s.\r\n", LYStrerror(exec_errno));
Packit f574b8
		}
Packit f574b8
		fflush(stdout);
Packit f574b8
		fflush(stderr);
Packit f574b8
		_exit(1);
Packit f574b8
Packit f574b8
	    } else {		/* and the Ugly */
Packit f574b8
		HTAlert(CONNECT_FAILED);
Packit f574b8
		PERROR("fork() failed");
Packit f574b8
		close(fd1[0]);
Packit f574b8
		close(fd1[1]);
Packit f574b8
		close(fd2[0]);
Packit f574b8
		close(fd2[1]);
Packit f574b8
		status = -1;
Packit f574b8
	    }
Packit f574b8
Packit f574b8
	}
Packit f574b8
	if (target != NULL) {
Packit f574b8
	    (*target->isa->_free) (target);
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    FREE(path_info);
Packit f574b8
    FREE(pgm);
Packit f574b8
    FREE(orig_pgm);
Packit f574b8
#else /* VMS */
Packit f574b8
    HTStream *target;
Packit f574b8
    char *buf = 0;
Packit f574b8
Packit f574b8
    target = HTStreamStack(WWW_HTML,
Packit f574b8
			   format_out,
Packit f574b8
			   sink, anAnchor);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",
Packit f574b8
	       gettext("Good Advice"));
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, "

%s

\n", gettext("Good Advice"));
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, "%s 
Packit f574b8
	       gettext("An excellent http server for VMS is available via"));
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf,
Packit f574b8
	       "href=\"http://www.ecr6.ohio-state.edu/www/doc/serverinfo.html\"\n");
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, ">%s.\n", gettext("this link"));
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, "

%s\n",

Packit f574b8
	       gettext("It provides state of the art CGI script support.\n"));
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, "</body>\n</html>\n");
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    (*target->isa->_free) (target);
Packit f574b8
    FREE(buf);
Packit f574b8
    status = HT_LOADED;
Packit f574b8
#endif /* VMS */
Packit f574b8
#else /* LYNXCGI_LINKS */
Packit f574b8
    HTUserMsg(CGI_NOT_COMPILED);
Packit f574b8
    status = HT_NOT_LOADED;
Packit f574b8
#endif /* LYNXCGI_LINKS */
Packit f574b8
Packit f574b8
    (void) arg;
Packit f574b8
    (void) anAnchor;
Packit f574b8
    (void) format_out;
Packit f574b8
    (void) sink;
Packit f574b8
Packit f574b8
    return (status);
Packit f574b8
}
Packit f574b8
#endif /* __MINGW32__ */
Packit f574b8
Packit f574b8
#ifdef GLOBALDEF_IS_MACRO
Packit f574b8
#define _LYCGI_C_GLOBALDEF_1_INIT { "lynxcgi", LYLoadCGI, 0 }
Packit f574b8
GLOBALDEF(HTProtocol, LYLynxCGI, _LYCGI_C_GLOBALDEF_1_INIT);
Packit f574b8
#else
Packit f574b8
GLOBALDEF HTProtocol LYLynxCGI =
Packit f574b8
{"lynxcgi", LYLoadCGI, 0};
Packit f574b8
#endif /* GLOBALDEF_IS_MACRO */