static int crack(char_t *buf, char_t **key, char_t **val) { char_t *ptr; if ((ptr = gstrrchr(buf, '\n')) != NULL || (ptr = gstrrchr(buf, '\r')) != NULL) { *ptr = '\0'; } /* * Find the = sign. It must exist. */ if ((ptr = gstrstr(buf, T("="))) == NULL) { return -1; } *ptr++ = '\0'; *key = trim(buf); *val = trim(ptr); return 0; }
int websUrlParse(char_t *url, char_t **pbuf, char_t **phost, char_t **ppath, char_t **pport, char_t **pquery, char_t **pproto, char_t **ptag, char_t **pext) { char_t *tok, *cp, *host, *path, *port, *proto, *tag, *query, *ext; char_t *last_delim, *hostbuf, *portbuf, *buf; int c, len, ulen; a_assert(url); a_assert(pbuf); ulen = gstrlen(url); /* * We allocate enough to store separate hostname and port number fields. * As there are 3 strings in the one buffer, we need room for 3 null chars. * We allocate MAX_PORT_LEN char_t's for the port number. */ len = ulen * 2 + MAX_PORT_LEN + 3; if ((buf = balloc(B_L, len * sizeof(char_t))) == NULL) { return -1; } portbuf = &buf[len - MAX_PORT_LEN - 1]; hostbuf = &buf[ulen+1]; gstrcpy(buf, url); url = buf; /* * Convert the current listen port to a string. We use this if the URL has * no explicit port setting */ stritoa(websGetPort(), portbuf, MAX_PORT_LEN); port = portbuf; path = T("/"); proto = T("http"); host = T("localhost"); query = T(""); ext = htmExt; tag = T(""); if (gstrncmp(url, T("http://"), 7) == 0) { tok = &url[7]; tok[-3] = '\0'; proto = url; host = tok; for (cp = tok; *cp; cp++) { if (*cp == '/') { break; } if (*cp == ':') { *cp++ = '\0'; port = cp; tok = cp; } } if ((cp = gstrchr(tok, '/')) != NULL) { /* * If a full URL is supplied, we need to copy the host and port * portions into static buffers. */ c = *cp; *cp = '\0'; gstrncpy(hostbuf, host, ulen); gstrncpy(portbuf, port, MAX_PORT_LEN); *cp = c; host = hostbuf; port = portbuf; path = cp; tok = cp; } } else { path = url; tok = url; } /* * Parse the query string */ if ((cp = gstrchr(tok, '?')) != NULL) { *cp++ = '\0'; query = cp; path = tok; tok = query; } /* * Parse the fragment identifier */ if ((cp = gstrchr(tok, '#')) != NULL) { *cp++ = '\0'; if (*query == 0) { path = tok; } } /* * Only do the following if asked for the extension */ if (pext) { if ((cp = gstrrchr(path, '.')) != NULL) { if ((last_delim = gstrrchr(path, '/')) != NULL) { if (last_delim > cp) { ext = htmExt; } else { ext = cp; } } else { ext = cp; } } else { if (path[gstrlen(path) - 1] == '/') { ext = htmExt; } } } /* * Pass back the fields requested (if not NULL) */ if (phost) *phost = host; if (ppath) *ppath = path; if (pport) *pport = port; if (pproto) *pproto = proto; if (pquery) *pquery = query; if (ptag) *ptag = tag; if (pext) *pext = ext; *pbuf = buf; return 0; }
/* * Process a form request. Returns 1 always to indicate it handled the URL */ int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t* query) { cgiRec *cgip; sym_t *s; char_t cgiBuf[FNAMESIZE], *stdIn, *stdOut, cwd[FNAMESIZE]; char_t *cp, *cgiName, *cgiPath, **argp, **envp, **ep; int n, envpsize, argpsize, pHandle, cid; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path && *path == '/'); websStats.cgiHits++; /* * Extract the form name and then build the full path name. The form * name will follow the first '/' in path. */ gstrncpy(cgiBuf, path, TSZ(cgiBuf)); if ((cgiName = gstrchr(&cgiBuf[1], '/')) == NULL) { websError(wp, 200, T("Missing CGI name")); return 1; } cgiName++; if ((cp = gstrchr(cgiName, '/')) != NULL) { *cp = '\0'; } fmtAlloc(&cgiPath, FNAMESIZE, T("%s/%s/%s"), websGetDefaultDir(), CGI_BIN, cgiName); #ifndef VXWORKS /* * 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. */ { gstat_t sbuf; if (gstat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) { websError(wp, 200, T("CGI process file does not exist")); bfree(B_L, cgiPath); return 1; } #if (defined (WIN) || defined (CE)) if (gstrstr(cgiPath, T(".exe")) == NULL && gstrstr(cgiPath, T(".bat")) == NULL) { #elif (defined (NW)) if (gstrstr(cgiPath, T(".nlm")) == NULL) { #else if (gaccess(cgiPath, X_OK) != 0) { #endif /* WIN || CE */ websError(wp, 200, T("CGI process file is not executable")); bfree(B_L, cgiPath); return 1; } } #endif /* ! VXWORKS */ /* * Get the CWD for resetting after launching the child process CGI */ ggetcwd(cwd, FNAMESIZE); /* * Retrieve the directory of the child process CGI */ if ((cp = gstrrchr(cgiPath, '/')) != NULL) { *cp = '\0'; gchdir(cgiPath); *cp = '/'; } /* * 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 balloc'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 brealloc. */ argpsize = 10; argp = balloc(B_L, argpsize * sizeof(char_t *)); *argp = cgiPath; n = 1; if (gstrchr(query, '=') == NULL) { websDecodeUrl(query, query, gstrlen(query)); for (cp = gstrtok(query, T(" ")); cp != NULL; ) { *(argp+n) = cp; n++; if (n >= argpsize) { argpsize *= 2; argp = brealloc(B_L, argp, argpsize * sizeof(char_t *)); } cp = gstrtok(NULL, T(" ")); } } *(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 cgiVars symbol table. envp will point to a balloc'd array of * pointers. Each pointer will point to a balloc'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 brealloc. */ envpsize = WEBS_SYM_INIT; envp = balloc(B_L, envpsize * sizeof(char_t *)); n = 0; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("PATH_TRANSLATED"), cgiPath); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s/%s"),T("SCRIPT_NAME"), CGI_BIN, cgiName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("REMOTE_USER"), wp->userName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("AUTH_TYPE"), wp->authType); n++; for (s = symFirst(wp->cgiVars); s != NULL; s = symNext(wp->cgiVars)) { if (s->content.valid && s->content.type == string && gstrcmp(s->name.value.string, T("REMOTE_HOST")) != 0 && gstrcmp(s->name.value.string, T("HTTP_AUTHORIZATION")) != 0) { fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), s->name.value.string, s->content.value.string); n++; if (n >= envpsize) { envpsize *= 2; envp = brealloc(B_L, envp, envpsize * sizeof(char_t *)); } } } if (wp->flags & WEBS_CGI_UPLOAD){ // set filename into enviornment variables fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), T("UPLOAD_FILENAME"), wp->cgiStdin); n++; } *(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(wp); } stdIn = wp->cgiStdin; stdOut = websGetCgiCommName(wp); /* * 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 = websLaunchCgiProc(cgiPath, argp, envp, stdIn, stdOut)) == -1) { websError(wp, 200, T("failed to spawn CGI task")); for (ep = envp; *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgiPath); bfreeSafe(B_L, argp); bfreeSafe(B_L, envp); bfreeSafe(B_L, stdOut); } else { /* * If the spawn was successful, put this wp on a queue to be * checked for completion. */ cid = hAllocEntry((void***) &cgiList, &cgiMax, sizeof(cgiRec)); 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; websTimeoutCancel(wp); } /* * Restore the current working directory after spawning child CGI */ gchdir(cwd); return 1; } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has */ void websCgiGatherOutput (cgiRec *cgip) { gstat_t sbuf; char_t cgiBuf[FNAMESIZE]; if ((gstat(cgip->stdOut, &sbuf) == 0) && (sbuf.st_size > cgip->fplacemark)) { int fdout; fdout = gopen(cgip->stdOut, O_RDONLY | O_BINARY, 0444 ); /* * Check to see if any data is available in the * output file and send its contents to the socket. */ if (fdout >= 0) { webs_t wp = cgip->wp; int nRead; /* * Write the HTTP header on our first pass */ if (cgip->fplacemark == 0) { websWrite(wp, T("HTTP/1.0 200 OK\r\n")); } glseek(fdout, cgip->fplacemark, SEEK_SET); while ((nRead = gread(fdout, cgiBuf, FNAMESIZE)) > 0) { websWriteBlock(wp, cgiBuf, nRead); cgip->fplacemark += nRead; } gclose(fdout); } } } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has * completed, and if so, process its output and clean up. */ void websCgiCleanup() { cgiRec *cgip; webs_t wp; char_t **ep; int cid, nTries; for (cid = 0; cid < cgiMax; cid++) { if ((cgip = cgiList[cid]) != NULL) { int exit_status; wp = cgip->wp; websCgiGatherOutput (cgip); if ( websCheckCgiProc(cgip->handle, &exit_status) == 0) { /* * We get here if the CGI process has terminated. Clean up. */ nTries = 0; /* * Make sure we didn't miss something during a task switch. * Maximum wait is 100 times 10 msecs (1 second). */ while ((cgip->fplacemark == 0) && (nTries < 100)) { websCgiGatherOutput(cgip); /* * There are some cases when we detect app exit * before the file is ready. */ if (cgip->fplacemark == 0) { #ifdef WIN Sleep(10); #endif /* WIN*/ } nTries++; } if (cgip->fplacemark == 0) { websError(wp, 200, T("CGI generated no output")); } else { websDone(wp, 200); } /* * Remove the temporary re-direction files */ gunlink(cgip->stdIn); gunlink(cgip->stdOut); /* * Free all the memory buffers pointed to by cgip. * The stdin file name (wp->cgiStdin) gets freed as * part of websFree(). */ cgiMax = hFree((void***) &cgiList, cid); for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgip->cgiPath); bfreeSafe(B_L, cgip->argp); bfreeSafe(B_L, cgip->envp); bfreeSafe(B_L, cgip->stdOut); bfreeSafe(B_L, cgip); #if 0 //DAVIDM - we do not want this, netflash does it for us if(wp->has_firmware_upload_clean){ if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) != 0) return; sync(); doSystem("sleep 3 && reboot &"); } #endif } } } }
int websUrlParse(char_t *url, char_t **pbuf, char_t **phost, char_t **ppath, char_t **pport, char_t **pquery, char_t **pproto, char_t **ptag, char_t **pext) { char_t *tok, *cp, *host, *path, *port, *proto, *tag, *query, *ext; char_t *hostbuf, *portbuf, *buf; int c, len, ulen; a_assert(url); a_assert(pbuf); ulen = gstrlen(url); /* * We allocate enough to store separate hostname and port number fields. * As there are 3 strings in the one buffer, we need room for 3 null chars. * We allocate MAX_PORT_LEN char_t's for the port number. */ len = ulen * 2 + MAX_PORT_LEN + 3; if ((buf = balloc(B_L, len * sizeof(char_t))) == NULL) { return -1; } portbuf = &buf[len - MAX_PORT_LEN - 1]; hostbuf = &buf[ulen+1]; /* Handle any URL encoding. Otherwise a URL ending in ".as%70", for example, causes trouble. */ websDecodeUrl(buf, url, ulen); url = buf; /* * Convert the current listen port to a string. We use this if the URL has * no explicit port setting */ stritoa(websGetPort(), portbuf, MAX_PORT_LEN); port = portbuf; path = T("/"); proto = T("http"); host = T("localhost"); query = T(""); ext = htmExt; tag = T(""); if (gstrncmp(url, T("http://"), 7) == 0) { tok = &url[7]; tok[-3] = '\0'; proto = url; host = tok; for (cp = tok; *cp; cp++) { if (*cp == '/') { break; } if (*cp == ':') { *cp++ = '\0'; port = cp; tok = cp; } } if ((cp = gstrchr(tok, '/')) != NULL) { /* * If a full URL is supplied, we need to copy the host and port * portions into static buffers. */ c = *cp; *cp = '\0'; gstrncpy(hostbuf, host, ulen); gstrncpy(portbuf, port, MAX_PORT_LEN); *cp = c; host = hostbuf; port = portbuf; path = cp; tok = cp; } } else { path = url; tok = url; } /* * Parse the query string */ if ((cp = gstrchr(tok, '?')) != NULL) { *cp++ = '\0'; query = cp; path = tok; tok = query; } /* * Parse the fragment identifier */ if ((cp = gstrchr(tok, '#')) != NULL) { *cp++ = '\0'; if (*query == 0) { path = tok; } } /* * Only do the following if asked for the extension */ if (pext) { /* Later the path will be cleaned up for trailing slashes and so on. To be ready, we need to clean up here, much as in websValidateUrl. Otherwise a URL ending in "asp/" or "asP" sends Ejscript source to the browser. */ if ((cp = gstrrchr(path, '.')) != NULL) { const char_t* garbage = T("/\\"); int length = gstrcspn(cp, garbage); int garbageLength = gstrspn(cp + length, garbage); int ok = (length + garbageLength == (int) gstrlen(cp)); if (ok) { cp[length] = '\0'; #ifdef WIN strlower(cp); #endif ext = cp; } } } /* * Pass back the fields requested (if not NULL) */ if (phost) *phost = host; if (ppath) *ppath = path; if (pport) *pport = port; if (pproto) *pproto = proto; if (pquery) *pquery = query; if (ptag) *ptag = tag; if (pext) *pext = ext; *pbuf = buf; return 0; }
int websLaunchCgiProc(char_t *cgiPath, char_t **argp, char_t **envp, char_t *stdIn, char_t *stdOut) { SYM_TYPE ptype; char_t *p, *basename, *pEntry, *pname, *entryAddr, **pp; int priority, rc, fd; /* * Determine the basename, which is without path or the extension. */ if ((int)(p = gstrrchr(cgiPath, '/') + 1) == 1) { p = cgiPath; } basename = bstrdup(B_L, p); if ((p = gstrrchr(basename, '.')) != NULL) { *p = '\0'; } /* * Unload the module, if it is already loaded. Get the current task * priority. */ unld(cgiPath, 0); taskPriorityGet(taskIdSelf(), &priority); rc = fd = -1; /* * Set the entry point symbol name as described above. Look for an already * loaded entry point; if it exists, spawn the task accordingly. */ for (pp = envp, pEntry = NULL; pp != NULL && *pp != NULL; pp++) { if (gstrncmp(*pp, T("cgientry="), 9) == 0) { pEntry = bstrdup(B_L, *pp + 9); break; } } if (pEntry == NULL) { fmtAlloc(&pEntry, LF_PATHSIZE, T("%s_%s"), basename, T("cgientry")); } entryAddr = 0; if (symFindByName(sysSymTbl, pEntry, &entryAddr, &ptype) == -1) { fmtAlloc(&pname, VALUE_MAX_STRING, T("_%s"), pEntry); symFindByName(sysSymTbl, pname, &entryAddr, &ptype); bfreeSafe(B_L, pname); } if (entryAddr != 0) { rc = taskSpawn(pEntry, priority, 0, 20000, (void *)vxWebsCgiEntry, (int)entryAddr, (int)argp, (int)envp, (int)stdIn, (int)stdOut, 0, 0, 0, 0, 0); goto DONE; } /* * Try to load the module. */ if ((fd = gopen(cgiPath, O_RDONLY | O_BINARY, 0666)) < 0 || loadModule(fd, LOAD_GLOBAL_SYMBOLS) == NULL) { goto DONE; } if ((symFindByName(sysSymTbl, pEntry, &entryAddr, &ptype)) == -1) { fmtAlloc(&pname, VALUE_MAX_STRING, T("_%s"), pEntry); symFindByName(sysSymTbl, pname, &entryAddr, &ptype); bfreeSafe(B_L, pname); } if (entryAddr != 0) { rc = taskSpawn(pEntry, priority, 0, 20000, (void *)vxWebsCgiEntry, (int)entryAddr, (int)argp, (int)envp, (int)stdIn, (int)stdOut, 0, 0, 0, 0, 0); } DONE: if (fd != -1) { gclose(fd); } bfree(B_L, basename); bfree(B_L, pEntry); return rc; }