/* Allocate a new socket structure */ PUBLIC int socketAlloc(char *ip, int port, SocketAccept accept, int flags) { WebsSocket *sp; int sid; if ((sid = wallocObject(&socketList, &socketMax, sizeof(WebsSocket))) < 0) { return -1; } sp = socketList[sid]; sp->sid = sid; sp->accept = accept; sp->port = port; sp->fileHandle = -1; sp->saveMask = -1; if (ip) { sp->ip = sclone(ip); } sp->flags = flags & (SOCKET_BLOCK | SOCKET_LISTENING | SOCKET_NODELAY); return sid; }
/* Process a form request. Returns 1 always to indicate it handled the URL */ static bool cgiHandler(Webs *wp) { Cgi *cgip; WebsKey *s; char cgiPrefix[BIT_GOAHEAD_LIMIT_FILENAME], *stdIn, *stdOut, cwd[BIT_GOAHEAD_LIMIT_FILENAME]; char *cp, *cgiName, *cgiPath, **argp, **envp, **ep, *tok, *query, *dir, *extraPath; int n, envpsize, argpsize, pHandle, cid; assert(websValid(wp)); websSetEnv(wp); /* Extract the form name and then build the full path name. The form name will follow the first '/' in path. */ scopy(cgiPrefix, sizeof(cgiPrefix), wp->path); if ((cgiName = strchr(&cgiPrefix[1], '/')) == NULL) { websError(wp, HTTP_CODE_NOT_FOUND, "Missing CGI name"); return 1; } *cgiName++ = '\0'; getcwd(cwd, BIT_GOAHEAD_LIMIT_FILENAME); dir = wp->route->dir ? wp->route->dir : cwd; chdir(dir); extraPath = 0; if ((cp = strchr(cgiName, '/')) != NULL) { extraPath = sclone(cp); *cp = '\0'; websSetVar(wp, "PATH_INFO", extraPath); websSetVarFmt(wp, "PATH_TRANSLATED", "%s%s%s", dir, cgiPrefix, extraPath); wfree(extraPath); } else { websSetVar(wp, "PATH_INFO", ""); websSetVar(wp, "PATH_TRANSLATED", ""); } cgiPath = sfmt("%s%s/%s", dir, cgiPrefix, cgiName); websSetVarFmt(wp, "SCRIPT_NAME", "%s/%s", cgiPrefix, cgiName); websSetVar(wp, "SCRIPT_FILENAME", cgiPath); /* See if the file exists and is executable. If not error out. Don't do this step for VxWorks, since the module may already be part of the OS image, rather than in the file system. */ #if !VXWORKS { WebsStat sbuf; if (stat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) { error("Cannot find CGI program: ", cgiPath); websError(wp, HTTP_CODE_NOT_FOUND | WEBS_NOLOG, "CGI program file does not exist"); wfree(cgiPath); return 1; } #if BIT_WIN_LIKE if (strstr(cgiPath, ".exe") == NULL && strstr(cgiPath, ".bat") == NULL) #else if (access(cgiPath, X_OK) != 0) #endif { websError(wp, HTTP_CODE_NOT_FOUND, "CGI process file is not executable"); wfree(cgiPath); return 1; } } #endif /* ! VXWORKS */ /* Build command line arguments. Only used if there is no non-encoded = character. This is indicative of a ISINDEX query. POST separators are & and others are +. argp will point to a walloc'd array of pointers. Each pointer will point to substring within the query string. This array of string pointers is how the spawn or exec routines expect command line arguments to be passed. Since we don't know ahead of time how many individual items there are in the query string, the for loop includes logic to grow the array size via wrealloc. */ argpsize = 10; argp = walloc(argpsize * sizeof(char *)); *argp = cgiPath; n = 1; query = 0; if (strchr(wp->query, '=') == NULL) { query = sclone(wp->query); websDecodeUrl(query, query, strlen(query)); for (cp = stok(query, " ", &tok); cp != NULL; ) { *(argp+n) = cp; trace(5, "ARG[%d] %s", n, argp[n-1]); n++; if (n >= argpsize) { argpsize *= 2; argp = wrealloc(argp, argpsize * sizeof(char *)); } cp = stok(NULL, " ", &tok); } } *(argp+n) = NULL; /* Add all CGI variables to the environment strings to be passed to the spawned CGI process. This includes a few we don't already have in the symbol table, plus all those that are in the vars symbol table. envp will point to a walloc'd array of pointers. Each pointer will point to a walloc'd string containing the keyword value pair in the form keyword=value. Since we don't know ahead of time how many environment strings there will be the for loop includes logic to grow the array size via wrealloc. */ envpsize = 64; envp = walloc(envpsize * sizeof(char*)); for (n = 0, s = hashFirst(wp->vars); s != NULL; s = hashNext(wp->vars, s)) { if (s->content.valid && s->content.type == string && strcmp(s->name.value.string, "REMOTE_HOST") != 0 && strcmp(s->name.value.string, "HTTP_AUTHORIZATION") != 0) { envp[n++] = sfmt("%s=%s", s->name.value.string, s->content.value.string); trace(5, "Env[%d] %s", n, envp[n-1]); if (n >= envpsize) { envpsize *= 2; envp = wrealloc(envp, envpsize * sizeof(char *)); } } } *(envp+n) = NULL; /* Create temporary file name(s) for the child's stdin and stdout. For POST data the stdin temp file (and name) should already exist. */ if (wp->cgiStdin == NULL) { wp->cgiStdin = websGetCgiCommName(); } stdIn = wp->cgiStdin; stdOut = websGetCgiCommName(); /* Now launch the process. If not successful, do the cleanup of resources. If successful, the cleanup will be done after the process completes. */ if ((pHandle = launchCgi(cgiPath, argp, envp, stdIn, stdOut)) == -1) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "failed to spawn CGI task"); for (ep = envp; *ep != NULL; ep++) { wfree(*ep); } wfree(cgiPath); wfree(argp); wfree(envp); wfree(stdOut); wfree(query); } else { /* If the spawn was successful, put this wp on a queue to be checked for completion. */ cid = wallocObject(&cgiList, &cgiMax, sizeof(Cgi)); cgip = cgiList[cid]; cgip->handle = pHandle; cgip->stdIn = stdIn; cgip->stdOut = stdOut; cgip->cgiPath = cgiPath; cgip->argp = argp; cgip->envp = envp; cgip->wp = wp; cgip->fplacemark = 0; wfree(query); } /* Restore the current working directory after spawning child CGI */ chdir(cwd); return 1; }