📄 lycgi.c
字号:
/* Lynx CGI support LYCgi.c** ================**** Authors** GL George Lindholm <George.Lindholm@ubc.ca>**** History** 15 Jun 95 Created as way to provide a lynx based service with** dynamic pages without the need for a http daemon. GL** 27 Jun 95 Added <index> (command line) support. Various cleanup** and bug fixes. GL** 04 Sep 97 Added support for PATH_INFO scripts. JKT**** Bugs** If the called scripts aborts before sending the mime headers then** lynx hangs.**** Should do something about SIGPIPE, (but then it should never happen)**** No support for redirection. Or mime-types.**** Should try and parse for a HTTP 1.1 header in case we are "calling" a** nph- script.*/ #include "HTUtils.h"#include "tcp.h"#include "HTTP.h"#include "HTParse.h"#include "HTTCP.h"#include "HTFormat.h"#include "HTFile.h"#include "HTAlert.h"#include "HTMIME.h"#include "HTAABrow.h"#include "LYGlobalDefs.h"#include "LYUtils.h"#include "HTML.h"#include "HTInit.h"#include "LYGetFile.h"#include "LYBookmark.h"#include "GridText.h"#include <ctype.h>#include "LYCgi.h"#include "LYSignal.h"#include "LYLocal.h"#include "LYLeaks.h"#define FREE(x) if (x) {free(x); x = NULL;}struct _HTStream { HTStreamClass * isa;};PRIVATE char **env = NULL; /* Environment variables */PRIVATE int envc_size = 0; /* Slots in environment array */PRIVATE int envc = 0; /* Slots used so far */#ifdef LYNXCGI_LINKSPRIVATE char user_agent[64];PRIVATE char server_software[64];#endif /* LYNXCGI_LINKS */PRIVATE void add_environment_value PARAMS((char *env_value));/* * Simple routine for expanding the environment array and adding a value to * it */PRIVATE void add_environment_value ARGS1( char *, env_value){ if (envc == envc_size) { /* Need some more slots */ envc_size += 10; if (env) env = (char **)realloc(env, sizeof(env[0]) * (envc_size + 2)); /* + terminator and base 0 */ else env = (char **)malloc(sizeof(env[0]) * (envc_size + 2)); /* + terminator and base 0 */ if (env == NULL) { outofmem(__FILE__, "LYCgi"); } } env[envc++] = env_value; env[envc] = NULL; /* Make sure it is always properly terminated */} /* * Add the value of an existing environment variable to those passed on to the * lynxcgi script. */PUBLIC void add_lynxcgi_environment ARGS1( CONST char *, variable_name){ char *env_value; env_value = getenv(variable_name); if (env_value != NULL) { char *add_value = NULL; add_value = (char *)malloc(strlen(variable_name) + strlen(env_value) + 2); if (add_value == NULL) { outofmem(__FILE__, "LYCgi"); } strcpy(add_value, variable_name); strcat(add_value, "="); strcat(add_value, env_value); add_environment_value(add_value); }}PRIVATE int LYLoadCGI ARGS4( CONST char *, arg, HTParentAnchor *, anAnchor, HTFormat, format_out, HTStream*, sink){ int status;#ifdef LYNXCGI_LINKS#ifndef VMS char *cp; struct stat stat_buf; char *pgm = NULL; /* executable */ char *pgm_args = NULL; /* and its argument(s) */ int statrv; char *orig_pgm = NULL; /* Path up to ? as given, URL-escaped*/ char *document_root = NULL; /* Corrected value of DOCUMENT_ROOT */ char *path_info = NULL; /* PATH_INFO extracted from pgm */ char *pgm_buff = NULL; /* PATH_INFO extraction buffer */ char *path_translated; /* From document_root/path_info */ if (!arg || !*arg || strlen(arg) <= 8) { HTAlert(BAD_REQUEST); status = -2; return(status); } else { if (strncmp(arg, "lynxcgi://localhost", 19) == 0) { StrAllocCopy(pgm, arg+19); } else { StrAllocCopy(pgm, arg+8); } if ((cp=strchr(pgm, '?')) != NULL) { /* Need to terminate executable */ *cp++ = '\0'; pgm_args = cp; } } StrAllocCopy(orig_pgm, pgm); if ((cp=strchr(pgm, '#')) != NULL) { /* * Strip a #fragment from path. In this case any pgm_args * found above will also be bogus, since the '?' came after * the '#' and is part of the fragment. Note that we don't * handle the case where a '#' appears after a '?' properly * according to URL rules. - kw */ *cp = '\0'; pgm_args = NULL; } HTUnEscape(pgm); /* BEGIN WebSter Mods */ /* If pgm is not stat-able, see if PATH_INFO data is at the end of pgm */ if ((statrv = stat(pgm, &stat_buf)) < 0) { StrAllocCopy(pgm_buff, pgm); while (statrv < 0 || (statrv = stat(pgm_buff, &stat_buf)) < 0) { if ((cp=strrchr(pgm_buff, '/')) != NULL) { *cp = '\0'; statrv = 999; /* force new stat() - kw */ } else { if (TRACE) perror("LYNXCGI: strrchr(pgm_buff, '/') returned NULL"); break; } } if (statrv < 0) { /* Did not find PATH_INFO data */ if (TRACE) perror("LYNXCGI: stat() of pgm_buff failed"); } else { /* Found PATH_INFO data. Strip it off of pgm and into path_info. */ StrAllocCopy(path_info, pgm+strlen(pgm_buff)); strcpy(pgm, pgm_buff); if (TRACE) fprintf(stderr, "LYNXCGI: stat() of %s succeeded, path_info=\"%s\".\n", pgm_buff, path_info); } FREE(pgm_buff); } /* END WebSter Mods */ if (statrv != 0) { /* * Neither the path as given nor any components examined by * backing up were stat()able. - kw */ HTAlert("Unable to access cgi script"); if (TRACE) { perror("LYNXCGI: stat() failed"); } status = -4; } else if (!(S_ISREG(stat_buf.st_mode) && stat_buf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) { /* * Not a runnable file, See if we can load it using "file:" code. */ char *new_arg = NULL; /* * But try "file:" only if the file we are looking at is the path * as given (no path_info was extracted), otherwise it will be * to confusing to know just what file is loaded. - kw */ if (path_info) { if (TRACE) { fprintf(stderr, "%s is not a file and %s not an executable, giving up.\n", orig_pgm, pgm); } FREE(path_info); FREE(pgm); FREE(orig_pgm); status = -4; return(status); } StrAllocCopy(new_arg, "file://localhost"); StrAllocCat(new_arg, orig_pgm); if (TRACE) { fprintf(stderr, "%s is not an executable file, passing the buck.\n", arg); } status = HTLoadFile(new_arg, anAnchor, format_out, sink); FREE(new_arg); } else if (path_info && anAnchor != HTMainAnchor && !(reloading && anAnchor->document) && strcmp(arg, HTLoadedDocumentURL()) && HText_AreDifferent(anAnchor, arg) && HTUnEscape(orig_pgm) && !exec_ok(HTLoadedDocumentURL(), orig_pgm, CGI_PATH)) { /* exec_ok gives out msg. */ /* * If we have extra path info and are not just reloading * the current, check the full file path (after unescaping) * now to catch forbidden segments. - kw */ status = HT_NOT_LOADED; } else if (no_lynxcgi) { _statusline(CGI_DISABLED); sleep(MessageSecs); status = HT_NOT_LOADED; } else if (no_bookmark_exec && anAnchor != HTMainAnchor && !(reloading && anAnchor->document) && strcmp(arg, HTLoadedDocumentURL()) && HText_AreDifferent(anAnchor, arg) && HTLoadedDocumentBookmark()) { /* * If we are reloading a lynxcgi document that had already been * loaded, the various checks above should allow it even if * no_bookmark_exec is TRUE an we are not now coming from a * bookmark page. - kw */ _statusline(BOOKMARK_EXEC_DISABLED); sleep(MessageSecs); status = HT_NOT_LOADED; } else if (anAnchor != HTMainAnchor && !(reloading && anAnchor->document) && strcmp(arg, HTLoadedDocumentURL()) && HText_AreDifferent(anAnchor, arg) && !exec_ok(HTLoadedDocumentURL(), pgm, CGI_PATH)) { /* exec_ok gives out msg. */ /* * If we are reloading a lynxcgi document that had already been * loaded, the various checks above should allow it even if * exec_ok() would reject it because we are not now coming from * a document with a URL allowed by TRUSTED_LYNXCGI rules. - kw */ status = HT_NOT_LOADED; } else { HTFormat format_in; HTStream *target = NULL; /* Unconverted data */ int fd1[2], fd2[2]; char buf[1024]; pid_t pid;#if HAVE_TYPE_UNIONWAIT union wait wstatus;#else int wstatus;#endif if (anAnchor->isHEAD || keep_mime_headers) { /* Show output as plain text */ format_in = WWW_PLAINTEXT; } else { /* Decode full HTTP response */ format_in = HTAtom_for("www/mime"); } target = HTStreamStack(format_in, format_out, sink, anAnchor); if (!target || target == NULL) { sprintf(buf, CANNOT_CONVERT_I_TO_O, HTAtom_name(format_in), HTAtom_name(format_out)); _statusline(buf); sleep(AlertSecs); status = HT_NOT_LOADED; } else if (anAnchor->post_data && pipe(fd1) < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -