/* Path is the path to the esp.json */ static int defineApp(HttpRoute *route, cchar *path) { EspRoute *eroute; if ((eroute = espRoute(route)) == 0) { return MPR_ERR_MEMORY; } eroute->top = eroute; if (path) { if (!mprPathExists(path, R_OK)) { mprLog("error esp", 0, "Cannot open %s", path); return MPR_ERR_CANT_FIND; } httpSetRouteHome(route, mprGetPathDir(path)); eroute->configFile = sclone(path); } espSetDefaultDirs(route); httpAddRouteHandler(route, "espHandler", ""); httpAddRouteIndex(route, "index.esp"); httpAddRouteIndex(route, "index.html"); httpSetRouteXsrf(route, 1); mprLog("info esp", 3, "ESP app: %s", path); return 0; }
static MprList *expandWild(Ejs *ejs, int argc, char **argv) { MprList *list; EjsArray *files; EjsPath *path, *dir; cchar *arg; int i, j; if ((list = mprCreateList(-1, 0)) == 0) { return 0; } for (i = 0; i < argc; i++) { if (schr(argv[i], '*')) { arg = mprNormalizePath(argv[i]); dir = ejsCreatePathFromAsc(ejs, mprGetPathDir(arg)); path = ejsCreatePathFromAsc(ejs, mprGetPathBase(arg)); if ((files = ejsGetPathFiles(ejs, dir, 1, (EjsObj**) (void*) &path)) == 0) { ejsClearException(ejs); mprAddItem(list, sclone(argv[i])); } else { for (j = 0; j < files->length; j++) { mprAddItem(list, ((EjsPath*) files->data[j])->value); } } } else { mprAddItem(list, sclone(argv[i])); } } return list; }
/* Set the platform objects location */ PUBLIC int httpSetPlatformDir(cchar *path) { Http *http; http = HTTP; if (path) { if (mprPathExists(path, X_OK)) { http->platformDir = mprGetAbsPath(path); } else { /* Possible source tree platform directory */ http->platformDir = mprJoinPath(mprGetPathDir(mprGetPathDir(mprGetPathDir(mprGetAppPath()))), path); if (!mprPathExists(http->platformDir, X_OK)) { http->platformDir = mprGetAbsPath(path); } } } else { http->platformDir = mprGetPathDir(mprGetPathDir(mprGetAppPath())); } return 0; }
static void outputHeader(HttpQueue *q, cchar *path, int nameSize) { Dir *dir; char *parent, *parentSuffix; int reverseOrder, fancy, isRootDir; dir = q->conn->data; fancy = 1; path = mprEscapeHtml(path); httpWrite(q, "<!DOCTYPE HTML PUBLIC \"-/*W3C//DTD HTML 3.2 Final//EN\">\r\n"); httpWrite(q, "<html>\r\n <head>\r\n <title>Index of %s</title>\r\n", path); httpWrite(q, " </head>\r\n"); httpWrite(q, "<body>\r\n"); httpWrite(q, "<h1>Index of %s</h1>\r\n", path); if (dir->sortOrder > 0) { reverseOrder = 'D'; } else { reverseOrder = 'A'; } if (dir->fancyIndexing == 0) { fancy = '0'; } else if (dir->fancyIndexing == 1) { fancy = '1'; } else if (dir->fancyIndexing == 2) { fancy = '2'; } parent = mprGetPathDir(path); if (parent[strlen(parent) - 1] != '/') { parentSuffix = "/"; } else { parentSuffix = ""; } isRootDir = (strcmp(path, "/") == 0); if (dir->fancyIndexing == 2) { httpWrite(q, "<table><tr><th><img src=\"/icons/blank.gif\" alt=\"[ICO]\" /></th>"); httpWrite(q, "<th><a href=\"?C=N;O=%c;F=%c\">Name</a></th>", reverseOrder, fancy); httpWrite(q, "<th><a href=\"?C=M;O=%c;F=%c\">Last modified</a></th>", reverseOrder, fancy); httpWrite(q, "<th><a href=\"?C=S;O=%c;F=%c\">Size</a></th>", reverseOrder, fancy); httpWrite(q, "<th><a href=\"?C=D;O=%c;F=%c\">Description</a></th>\r\n", reverseOrder, fancy); httpWrite(q, "</tr><tr><th colspan=\"5\"><hr /></th></tr>\r\n"); if (! isRootDir) { httpWrite(q, "<tr><td valign=\"top\"><img src=\"/icons/back.gif\""); httpWrite(q, "alt=\"[DIR]\" /></td><td><a href=\"%s%s\">", parent, parentSuffix); httpWrite(q, "Parent Directory</a></td>"); httpWrite(q, "<td align=\"right\"> - </td></tr>\r\n"); } } else if (dir->fancyIndexing == 1) { httpWrite(q, "<pre><img src=\"/icons/space.gif\" alt=\"Icon\" /> "); httpWrite(q, "<a href=\"?C=N;O=%c;F=%c\">Name</a>%*s", reverseOrder, fancy, nameSize - 3, " "); httpWrite(q, "<a href=\"?C=M;O=%c;F=%c\">Last modified</a> ", reverseOrder, fancy); httpWrite(q, "<a href=\"?C=S;O=%c;F=%c\">Size</a> ", reverseOrder, fancy); httpWrite(q, "<a href=\"?C=D;O=%c;F=%c\">Description</a>\r\n", reverseOrder, fancy); httpWrite(q, "<hr />"); if (! isRootDir) { httpWrite(q, "<img src=\"/icons/parent.gif\" alt=\"[DIR]\" />"); httpWrite(q, " <a href=\"%s%s\">Parent Directory</a>\r\n", parent, parentSuffix); } } else { httpWrite(q, "<ul>\n"); if (! isRootDir) { httpWrite(q, "<li><a href=\"%s%s\"> Parent Directory</a></li>\r\n", parent, parentSuffix); } } }
/* Executed by the child process */ static void cmdTaskEntry(char *program, MprCmdTaskFn entry, int cmdArg) { MprCmd *cmd; MprCmdFile *files; WIND_TCB *tcb; char *item; int inFd, outFd, errFd, id, next; cmd = (MprCmd*) cmdArg; /* Open standard I/O files (in/out are from the server's perspective) */ files = cmd->files; inFd = open(files[MPR_CMD_STDIN].name, O_RDONLY, 0666); outFd = open(files[MPR_CMD_STDOUT].name, O_WRONLY, 0666); errFd = open(files[MPR_CMD_STDERR].name, O_WRONLY, 0666); if (inFd < 0 || outFd < 0 || errFd < 0) { exit(255); } id = taskIdSelf(); ioTaskStdSet(id, 0, inFd); ioTaskStdSet(id, 1, outFd); ioTaskStdSet(id, 2, errFd); /* Now that we have opened the stdin and stdout, wakeup our parent. */ semGive(cmd->startCond); /* Create the environment */ if (envPrivateCreate(id, -1) < 0) { exit(254); } for (ITERATE_ITEMS(cmd->env, item, next)) { putenv(item); } #if !VXWORKS { char *dir; int rc; /* Set current directory if required WARNING: Setting working directory on VxWorks is global */ if (cmd->dir) { rc = chdir(cmd->dir); } else { dir = mprGetPathDir(cmd->program); rc = chdir(dir); } if (rc < 0) { mprLog("error mpr cmd", 0, "Cannot change directory to %s", cmd->dir); exit(255); } } #endif /* Call the user's entry point */ (entry)(cmd->argc, (char**) cmd->argv, (char**) cmd->env); tcb = taskTcb(id); cmd->status = tcb->exitCode; /* Cleanup */ envPrivateDestroy(id); close(inFd); close(outFd); close(errFd); semGive(cmd->exitCond); }
/* Determine the windows program to invoke. Support UNIX style "#!/program" bang directives on windows. Also supports ".cmd" and ".bat" alternatives. */ static void prepWinProgram(MprCmd *cmd) { #if ME_WIN_LIKE MprFile *file; cchar *bat, *ext, *shell, *cp, *start; char bang[ME_MAX_FNAME + 1], *path, *pp; /* Map separators, convert carriage-returns and newlines to spaces and remove quotes on the command */ path = mprAlloc(slen(cmd->argv[0]) * 2 + 1); strcpy(path, cmd->argv[0]); for (pp = path; *pp; pp++) { if (*pp == '/') { *pp = '\\'; } else if (*pp == '\r' || *pp == '\n') { *pp = ' '; } } if (*path == '\"') { if ((pp = strrchr(++path, '"')) != 0) { *pp = '\0'; } path = sclone(path); } cmd->argv[0] = path; /* Support ".cmd" and ".bat" files that take precedence */ if ((ext = mprGetPathExt(path)) == 0) { if ((bat = mprSearchPath(mprJoinPathExt(path, ".cmd"), MPR_SEARCH_EXE, cmd->searchPath, NULL)) == 0) { bat = mprSearchPath(mprJoinPathExt(path, ".bat"), MPR_SEARCH_EXE, cmd->searchPath, NULL); } if (bat) { if ((shell = getenv("COMSPEC")) == 0) { shell = "cmd.exe"; } cmd->argv = mprRealloc((void*) cmd->argv, (cmd->argc + 4) * sizeof(char*)); memmove((void*) &cmd->argv[3], (void*) cmd->argv, sizeof(char*) * (cmd->argc + 1)); cmd->argv[0] = sclone(shell); cmd->argv[1] = sclone("/Q"); cmd->argv[2] = sclone("/C"); cmd->argv[3] = bat; cmd->argc += 3; cmd->argv[cmd->argc] = 0; return; } } if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) { if (mprReadFile(file, bang, ME_MAX_FNAME) > 0) { mprCloseFile(file); bang[ME_MAX_FNAME] = '\0'; if (bang[0] == '#' && bang[1] == '!') { cp = start = &bang[2]; shell = ssplit(&bang[2], "\r\n", NULL); if (!mprIsPathAbs(shell)) { /* If we cannot access the command shell and the command is not an absolute path, look in the same directory as the script. */ if (mprPathExists(shell, X_OK)) { shell = mprJoinPath(mprGetPathDir(path), shell); } } /* Get length of argv with NULL and add one */ assert(cmd->argv[cmd->argc] == 0); cmd->argv = mprRealloc((void*) cmd->argv, (cmd->argc + 2) * sizeof(char*)); cmd->argv[cmd->argc + 1] = 0; /* Copy up to make room to insert the shell argument. This copies the original NULL */ memmove((void*) &cmd->argv[1], (void*) cmd->argv, sizeof(char*) * cmd->argc); cmd->argv[0] = sclone(shell); cmd->argv[1] = path; cmd->argc += 1; assert(cmd->argv[cmd->argc] == 0); } } else { mprCloseFile(file); } } #endif }
/* If the program has a UNIX style "#!/program" string at the start of the file that program will be selected and the original program will be passed as the first arg to that program with argv[] appended after that. If the program is not found, this routine supports a safe intelligent search for the command. If all else fails, we just return in program the fileName we were passed in. script will be set if we are modifying the program to run and we have extracted the name of the file to run as a script. */ static void findExecutable(HttpConn *conn, char **program, char **script, char **bangScript, cchar *fileName) { HttpRx *rx; HttpTx *tx; HttpRoute *route; MprKey *kp; MprFile *file; cchar *actionProgram, *ext, *cmdShell, *cp, *start, *path; char buf[ME_MAX_FNAME + 1]; rx = conn->rx; tx = conn->tx; route = rx->route; *bangScript = 0; *script = 0; *program = 0; path = 0; actionProgram = mprGetMimeProgram(rx->route->mimeTypes, rx->mimeType); ext = tx->ext; /* If not found, go looking for the fileName with the extensions defined in appweb.conf. NOTE: we don't use PATH deliberately!!! */ if (access(fileName, X_OK) < 0) { for (kp = 0; (kp = mprGetNextKey(route->extensions, kp)) != 0; ) { path = sjoin(fileName, ".", kp->key, NULL); if (access(path, X_OK) == 0) { break; } path = 0; } if (kp) { ext = kp->key; } else { path = fileName; } } else { path = fileName; } assert(path && *path); #if ME_WIN_LIKE if (ext && (strcmp(ext, ".bat") == 0 || strcmp(ext, ".cmd") == 0)) { /* Let a mime action override COMSPEC */ if (actionProgram) { cmdShell = actionProgram; } else { cmdShell = getenv("COMSPEC"); } if (cmdShell == 0) { cmdShell = "cmd.exe"; } *script = sclone(path); *program = sclone(cmdShell); return; } #endif if (actionProgram) { *program = sclone(actionProgram); } else if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) { if (mprReadFile(file, buf, ME_MAX_FNAME) > 0) { mprCloseFile(file); buf[ME_MAX_FNAME] = '\0'; if (buf[0] == '#' && buf[1] == '!') { cp = start = &buf[2]; cmdShell = ssplit(&buf[2], "\r\n", NULL); if (!mprIsPathAbs(cmdShell)) { /* If we cannot access the command shell and the command is not an absolute path, look in the same directory as the script. */ if (mprPathExists(cmdShell, X_OK)) { cmdShell = mprJoinPath(mprGetPathDir(path), cmdShell); } } *program = sclone(cmdShell); *bangScript = sclone(path); return; } } else { mprCloseFile(file); } } if (actionProgram) { *program = sclone(actionProgram); *bangScript = sclone(path); } else { *program = sclone(path); } return; }
/* Start the CGI command program. This commences the CGI gateway program. This will be called after content for form and upload requests (or if "RunHandler" before specified), otherwise it runs before receiving content data. */ static void startCgi(HttpQueue *q) { HttpRx *rx; HttpTx *tx; HttpRoute *route; HttpConn *conn; MprCmd *cmd; Cgi *cgi; cchar *baseName, **argv, *fileName, **envv; ssize varCount; int argc, count; argv = 0; argc = 0; cgi = q->queueData; conn = q->conn; rx = conn->rx; route = rx->route; tx = conn->tx; /* The command uses the conn dispatcher. This serializes all I/O for both the connection and the CGI gateway. */ if ((cmd = mprCreateCmd(conn->dispatcher)) == 0) { return; } cgi->cmd = cmd; if (conn->http->forkCallback) { cmd->forkCallback = conn->http->forkCallback; cmd->forkData = conn->http->forkData; } argc = 1; /* argv[0] == programName */ buildArgs(conn, cmd, &argc, &argv); fileName = argv[0]; baseName = mprGetPathBase(fileName); /* nph prefix means non-parsed-header. Don't parse the CGI output for a CGI header */ if (strncmp(baseName, "nph-", 4) == 0 || (strlen(baseName) > 4 && strcmp(&baseName[strlen(baseName) - 4], "-nph") == 0)) { /* Pretend we've seen the header for Non-parsed Header CGI programs */ cgi->seenHeader = 1; tx->flags |= HTTP_TX_USE_OWN_HEADERS; } /* Build environment variables */ varCount = mprGetHashLength(rx->headers) + mprGetHashLength(rx->svars) + mprGetJsonLength(rx->params); if ((envv = mprAlloc((varCount + 1) * sizeof(char*))) != 0) { count = copyParams(conn, envv, 0, rx->params, route->envPrefix); count = copyVars(conn, envv, count, rx->svars, ""); count = copyVars(conn, envv, count, rx->headers, "HTTP_"); assert(count <= varCount); } #if !VXWORKS /* This will be ignored on VxWorks because there is only one global current directory for all tasks */ mprSetCmdDir(cmd, mprGetPathDir(fileName)); #endif mprSetCmdCallback(cmd, cgiCallback, cgi); if (mprStartCmd(cmd, argc, argv, envv, MPR_CMD_IN | MPR_CMD_OUT | MPR_CMD_ERR) < 0) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot run CGI process: %s, URI %s", fileName, rx->uri); return; } #if ME_WIN_LIKE mprCreateEvent(conn->dispatcher, "cgi-win", 10, waitForCgi, cgi, MPR_EVENT_CONTINUOUS); #endif }
int APIENTRY WinMain(HINSTANCE inst, HINSTANCE junk, char *command, int junk2) { char **argv; cchar *documents, *home, *logs, *port, *ssl, *argp, *path, *contents, *revised; cchar *user, *group, *cache, *modules, *bak; int argc, err, nextArg; static void logHandler(int flags, int level, cchar *msg); if (mprCreate(0, NULL, MPR_USER_EVENTS_THREAD) == NULL) { exit(1); } if ((argc = mprMakeArgv(command, &argv, MPR_ARGV_ARGS_ONLY)) < 0) { return FALSE; } mprSetLogHandler(logHandler); #else int main(int argc, char **argv) { cchar *documents, *home, *logs, *port, *ssl, *argp, *path, *contents, *revised; cchar *user, *group, *cache, *modules, *bak; int err, nextArg; if (mprCreate(argc, argv, MPR_USER_EVENTS_THREAD) == NULL) { exit(1); } #endif documents = home = port = ssl = logs = user = group = cache = modules = 0; for (err = 0, nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--documents") && nextArg < argc) { documents = argv[++nextArg]; } else if (smatch(argp, "--home") && nextArg < argc) { home = argv[++nextArg]; } else if (smatch(argp, "--logs") && nextArg < argc) { logs = argv[++nextArg]; } else if (smatch(argp, "--port") && nextArg < argc) { port = argv[++nextArg]; } else if (smatch(argp, "--ssl") && nextArg < argc) { ssl = argv[++nextArg]; } else if (smatch(argp, "--user") && nextArg < argc) { user = argv[++nextArg]; } else if (smatch(argp, "--group") && nextArg < argc) { group = argv[++nextArg]; } else if (smatch(argp, "--cache") && nextArg < argc) { cache = argv[++nextArg]; } else if (smatch(argp, "--modules") && nextArg < argc) { modules = argv[++nextArg]; } else { err++; } } if (nextArg != (argc - 1)) { err++; } if (err) { #if BIT_WIN_LIKE mprUserError("Bad command line:"); #else mprUserError("Bad command line:\n" " Usage: pathConfig [options]\n" " Switches:\n" " --cache dir # Cache dir" " --documents dir # Static documents directory" " --group groupname # Group name" " --home dir # Server home directory" " --logs dir # Log directory" " --modules dir # moduels dir" " --port number # HTTP port number" " --user username # User name"); #endif return 1; } path = argv[nextArg++]; if ((contents = mprReadPathContents(path, NULL)) == 0) { mprUserError("Cannot read %s", path); return 1; } if (port) { contents = replace(contents, "Listen 80", "Listen %s", port); } if (ssl) { contents = replace(contents, "443", ssl); } if (documents) { contents = replace(contents, "DocumentRoot", "DocumentRoot \"%s\"", documents); } if (home) { contents = replace(contents, "ServerRoot", "ServerRoot \"%s\"", home); } if (logs) { contents = replace(contents, "ErrorLog", "ErrorLog \"%s\"", mprJoinPath(logs, "error.log")); contents = replace(contents, "AccessLog", "AccessLog \"%s\"", mprJoinPath(logs, "access.log")); } if (user) { contents = replace(contents, "UserAccount", "UserAccount %s", user); } if (group) { contents = replace(contents, "GroupAccount", "GroupAccount %s", group); } if (cache) { contents = replace(contents, "EspDir cache", "EspDir cache \"%s\"", cache); } if (modules) { contents = replace(contents, "LoadModulePath", "LoadModulePath \"%s\"", modules); } revised = mprGetTempPath(mprGetPathDir(path)); if (mprWritePathContents(revised, contents, -1, 0644) < 0) { mprUserError("Cannot write %s", revised); } bak = sfmt("%s.bak", path); mprDeletePath(bak); if (rename(path, bak) < 0) { mprUserError("Cannot save %s to %s: 0x%x", path, bak, mprGetError()); } mprDeletePath(path); if (rename(revised, path) < 0) { mprUserError("Cannot rename %s to %s: 0x%x", revised, path, mprGetError()); rename(bak, path); } return 0; }
/* If the program has a UNIX style "#!/program" string at the start of the file that program will be selected and the original program will be passed as the first arg to that program with argv[] appended after that. If the program is not found, this routine supports a safe intelligent search for the command. If all else fails, we just return in program the fileName we were passed in. script will be set if we are modifying the program to run and we have extracted the name of the file to run as a script. */ static void findExecutable(MaConn *conn, char **program, char **script, char **bangScript, char *fileName) { MaRequest *req; MaResponse *resp; MaLocation *location; MprHash *hp; MprFile *file; cchar *actionProgram, *ext, *cmdShell; char *tok, buf[MPR_MAX_FNAME + 1], *path; req = conn->request; resp = conn->response; location = req->location; *bangScript = 0; *script = 0; *program = 0; path = 0; actionProgram = maGetMimeActionProgram(conn->host, req->mimeType); ext = resp->extension; /* If not found, go looking for the fileName with the extensions defined in appweb.conf. NOTE: we don't use PATH deliberately!!! */ if (access(fileName, X_OK) < 0 /* && *ext == '\0' */) { for (hp = 0; (hp = mprGetNextHash(location->extensions, hp)) != 0; ) { path = mprStrcat(resp, -1, fileName, ".", hp->key, NULL); if (access(path, X_OK) == 0) { break; } mprFree(path); path = 0; } if (hp) { ext = hp->key; } else { path = fileName; } } else { path = fileName; } mprAssert(path && *path); #if BLD_WIN_LIKE if (ext && (strcmp(ext, ".bat") == 0 || strcmp(ext, ".cmd") == 0)) { /* Let a mime action override COMSPEC */ if (actionProgram) { cmdShell = actionProgram; } else { cmdShell = getenv("COMSPEC"); } if (cmdShell == 0) { cmdShell = "cmd.exe"; } *script = mprStrdup(resp, path); *program = mprStrdup(resp, cmdShell); return; } #endif if ((file = mprOpen(resp, path, O_RDONLY, 0)) != 0) { if (mprRead(file, buf, MPR_MAX_FNAME) > 0) { mprFree(file); buf[MPR_MAX_FNAME] = '\0'; if (buf[0] == '#' && buf[1] == '!') { cmdShell = mprStrTok(&buf[2], " \t\r\n", &tok); if (cmdShell[0] != '/' && (cmdShell[0] != '\0' && cmdShell[1] != ':')) { /* If we can't access the command shell and the command is not an absolute path, look in the same directory as the script. */ if (mprPathExists(resp, cmdShell, X_OK)) { cmdShell = mprJoinPath(resp, mprGetPathDir(resp, path), cmdShell); } } if (actionProgram) { *program = mprStrdup(resp, actionProgram); } else { *program = mprStrdup(resp, cmdShell); } *bangScript = mprStrdup(resp, path); return; } } else { mprFree(file); } } if (actionProgram) { *program = mprStrdup(resp, actionProgram); *bangScript = mprStrdup(resp, path); } else { *program = mprStrdup(resp, path); } return; }
static void startCgi(MaQueue *q) { MaRequest *req; MaConn *conn; MprCmd *cmd; MprHash *hp; cchar *baseName; char **argv, **envv, *fileName; int index, argc, varCount; argv = 0; argc = 0; conn = q->conn; req = conn->request; if ((req->form || req->flags & MA_REQ_UPLOADING) && conn->state <= MPR_HTTP_STATE_CONTENT) { /* Delay starting the CGI process if uploading files or a form request. This enables env vars to be defined with file upload and form data before starting the CGI gateway. */ return; } cmd = q->queueData = mprCreateCmd(req); if (conn->http->forkCallback) { cmd->forkCallback = conn->http->forkCallback; cmd->forkData = conn->http->forkData; } /* Build the commmand line arguments */ argc = 1; /* argv[0] == programName */ buildArgs(conn, cmd, &argc, &argv); fileName = argv[0]; baseName = mprGetPathBase(q, fileName); if (strncmp(baseName, "nph-", 4) == 0 || (strlen(baseName) > 4 && strcmp(&baseName[strlen(baseName) - 4], "-nph") == 0)) { /* Pretend we've seen the header for Non-parsed Header CGI programs */ cmd->userFlags |= MA_CGI_SEEN_HEADER; } /* Build environment variables */ varCount = mprGetHashCount(req->headers) + mprGetHashCount(req->formVars); envv = (char**) mprAlloc(cmd, (varCount + 1) * (int) sizeof(char*)); index = 0; hp = mprGetFirstHash(req->headers); while (hp) { if (hp->data) { envv[index] = mprStrcat(cmd, -1, hp->key, "=", (char*) hp->data, NULL); index++; } hp = mprGetNextHash(req->headers, hp); } hp = mprGetFirstHash(req->formVars); while (hp) { if (hp->data) { envv[index] = mprStrcat(cmd, -1, hp->key, "=", (char*) hp->data, NULL); index++; } hp = mprGetNextHash(req->formVars, hp); } envv[index] = 0; mprAssert(index <= varCount); cmd->stdoutBuf = mprCreateBuf(cmd, MA_BUFSIZE, -1); cmd->stderrBuf = mprCreateBuf(cmd, MA_BUFSIZE, -1); cmd->lastActivity = mprGetTime(cmd); mprSetCmdDir(cmd, mprGetPathDir(q, fileName)); mprSetCmdCallback(cmd, cgiCallback, conn); maSetHeader(conn, 0, "Last-Modified", req->host->currentDate); maDontCacheResponse(conn); maPutForService(q, maCreateHeaderPacket(q), 0); if (mprStartCmd(cmd, argc, argv, envv, MPR_CMD_IN | MPR_CMD_OUT | MPR_CMD_ERR) < 0) { maFailRequest(conn, MPR_HTTP_CODE_SERVICE_UNAVAILABLE, "Can't run CGI process: %s, URI %s", fileName, req->url); return; } /* This will dedicate this thread to the connection. It will also put the socket into blocking mode. */ maDedicateThreadToConn(conn); }
static void angel() { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; MprTime mark; ulong status; char *dir, *homeDir, *serviceArgs; char key[MPR_MAX_FNAME], path[MPR_MAX_FNAME], cmd[MPR_MAX_FNAME]; int createFlags, restartWarned; servicePid = 0; createFlags = 0; restartWarned = 0; #if USEFUL_FOR_DEBUG DebugBreak(); #endif /* * Read the service home directory and args. Default to the current dir if none specified. */ homeDir = 0; serviceArgs = 0; mprSprintf(key, sizeof(key), "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\%s", serviceName); mprReadRegistry(mpr, &homeDir, MPR_MAX_FNAME, key, "HomeDir"); mprReadRegistry(mpr, &serviceArgs, MPR_MAX_FNAME, key, "Args"); /* * Expect to find the service executable in the same directory as this angel program. */ if (serviceProgram == 0) { GetModuleFileName(0, path, sizeof(path)); dir = mprGetPathDir(mpr, path); mprSprintf(path, sizeof(path), "\"%s\\%s.exe\"", dir, BLD_PRODUCT); mprFree(dir); } else { mprSprintf(path, sizeof(path), "\"%s\"", serviceProgram); } if (serviceArgs && *serviceArgs) { mprSprintf(cmd, sizeof(cmd), "%s %s", path, serviceArgs); } else { mprSprintf(cmd, sizeof(cmd), "%s", path); } if (createConsole) { createFlags |= CREATE_NEW_CONSOLE; } mark = mprGetTime(mpr); while (! exiting) { if (mprGetElapsedTime(mpr, mark) > (3600 * 1000)) { mark = mprGetTime(mpr); restartCount = 0; restartWarned = 0; } if (servicePid == 0 && !serviceStopped) { if (restartCount >= RESTART_MAX) { if (! restartWarned) { mprError(mpr, "Too many restarts for %s, %d in ths last hour", appTitle, restartCount); restartWarned++; } /* * This is not a real heart-beat. We are only waiting till the service process exits. */ WaitForSingleObject(heartBeatEvent, heartBeatPeriod); continue; } memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); /* * Launch the process */ if (! CreateProcess(0, cmd, 0, 0, FALSE, createFlags, 0, homeDir, &startInfo, &procInfo)) { mprError(mpr, "Can't create process: %s, %d", cmd, mprGetOsError()); } else { servicePid = (int) procInfo.hProcess; } restartCount++; } WaitForSingleObject(heartBeatEvent, heartBeatPeriod); if (servicePid) { if (GetExitCodeProcess((HANDLE) servicePid, (ulong*) &status)) { if (status != STILL_ACTIVE) { CloseHandle((HANDLE) servicePid); servicePid = 0; } } else { CloseHandle((HANDLE) servicePid); servicePid = 0; } } if (verbose) { mprPrintf(mpr, "%s has exited with status %d\n", serviceProgram, status); mprPrintf(mpr, "%s will be restarted in 10 seconds\n", serviceProgram); } } mprFree(homeDir); mprFree(serviceArgs); }
/* Convert an ESP web page into C code Directives: <%@ include "file" Include an esp file <%@ layout "file" Specify a layout page to use. Use layout "" to disable layout management <%@ content Mark the location to substitute content in a layout pag <% Begin esp section containing C code <%^ global Put esp code at the global level <%^ start Put esp code at the start of the function <%^ end Put esp code at the end of the function <%= Begin esp section containing an expression to evaluate and substitute <%= [%fmt] Begin a formatted expression to evaluate and substitute. Format is normal printf format. Use %S for safe HTML escaped output. %> End esp section -%> End esp section and trim trailing newline @@var Substitue the value of a variable. Var can also be simple expressions (without spaces) @#field Lookup the current record for the value of the field. */ char *espBuildScript(HttpRoute *route, cchar *page, cchar *path, cchar *cacheName, cchar *layout, char **err) { EspParse parse; char *control, *incBuf, *incText, *global, *token, *body, *where; char *rest, *start, *end, *include, *line, *fmt, *layoutPage, *layoutBuf; ssize len; int tid; mprAssert(page); body = start = end = global = ""; *err = 0; memset(&parse, 0, sizeof(parse)); parse.data = (char*) page; parse.next = parse.data; if ((parse.token = mprCreateBuf(-1, -1)) == 0) { return 0; } tid = getEspToken(&parse); while (tid != ESP_TOK_EOF) { token = mprGetBufStart(parse.token); #if FUTURE if (parse.lineNumber != lastLine) { body = sfmt("\n# %d \"%s\"\n", parse.lineNumber, path); } #endif switch (tid) { case ESP_TOK_CODE: if (*token == '^') { for (token++; *token && isspace((int) *token); token++) ; where = stok(token, " \t\r\n", &rest); if (rest == 0) { ; } else if (scmp(where, "global") == 0) { global = sjoin(global, rest, NULL); } else if (scmp(where, "start") == 0) { if (*start == '\0') { start = " "; } start = sjoin(start, rest, NULL); } else if (scmp(where, "end") == 0) { if (*end == '\0') { end = " "; } end = sjoin(end, rest, NULL); } } else { body = sjoin(body, token, NULL); } break; case ESP_TOK_CONTROL: /* NOTE: layout parsing not supported */ control = stok(token, " \t\r\n", &token); if (scmp(control, "content") == 0) { body = sjoin(body, CONTENT_MARKER, NULL); } else if (scmp(control, "include") == 0) { if (token == 0) { token = ""; } token = strim(token, " \t\r\n\"", MPR_TRIM_BOTH); token = mprNormalizePath(token); if (token[0] == '/') { include = sclone(token); } else { include = mprJoinPath(mprGetPathDir(path), token); } if ((incText = mprReadPathContents(include, &len)) == 0) { *err = sfmt("Can't read include file: %s", include); return 0; } /* Recurse and process the include script */ incBuf = 0; if ((incBuf = espBuildScript(route, incText, include, NULL, NULL, err)) == 0) { return 0; } body = sjoin(body, incBuf, NULL); } else if (scmp(control, "layout") == 0) { token = strim(token, " \t\r\n\"", MPR_TRIM_BOTH); if (*token == '\0') { layout = 0; } else { token = mprNormalizePath(token); if (token[0] == '/') { layout = sclone(token); } else { layout = mprJoinPath(mprGetPathDir(path), token); } if (!mprPathExists(layout, F_OK)) { *err = sfmt("Can't access layout page %s", layout); return 0; } } } else { *err = sfmt("Unknown control %s at line %d", control, parse.lineNumber); return 0; } break; case ESP_TOK_ERR: return 0; case ESP_TOK_EXPR: /* <%= expr %> */ if (*token == '%') { fmt = stok(token, ": \t\r\n", &token); if (token == 0) { token = ""; } } else { fmt = "%s"; } token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); body = sjoin(body, " espRender(conn, \"", fmt, "\", ", token, ");\n", NULL); break; case ESP_TOK_FIELD: /* @#field */ token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); body = sjoin(body, " espRender(conn, getField(\"", token, "\"));\n", NULL); break; case ESP_TOK_LITERAL: line = joinLine(token, &len); body = sfmt("%s espRenderBlock(conn, \"%s\", %d);\n", body, line, len); break; case ESP_TOK_VAR: /* @@var */ token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); /* espRenderParam uses espRenderSafeString */ body = sjoin(body, " espRenderParam(conn, \"", token, "\");\n", NULL); break; default: return 0; } tid = getEspToken(&parse); } if (cacheName) { /* CacheName will only be set for the outermost invocation */ if (layout && mprPathExists(layout, R_OK)) { if ((layoutPage = mprReadPathContents(layout, &len)) == 0) { *err = sfmt("Can't read layout page: %s", layout); return 0; } layoutBuf = 0; if ((layoutBuf = espBuildScript(route, layoutPage, layout, NULL, NULL, err)) == 0) { return 0; } body = sreplace(layoutBuf, CONTENT_MARKER, body); } if (start && start[slen(start) - 1] != '\n') { start = sjoin(start, "\n", NULL); } if (end && end[slen(end) - 1] != '\n') { end = sjoin(end, "\n", NULL); } mprAssert(slen(path) > slen(route->dir)); mprAssert(sncmp(path, route->dir, slen(route->dir)) == 0); if (sncmp(path, route->dir, slen(route->dir)) == 0) { path = &path[slen(route->dir) + 1]; } body = sfmt(\ "/*\n Generated from %s\n */\n"\ "#include \"esp-app.h\"\n"\ "%s\n"\ "static void %s(HttpConn *conn) {\n"\ "%s%s%s"\ "}\n\n"\ "%s int esp_%s(HttpRoute *route, MprModule *module) {\n"\ " espDefineView(route, \"%s\", %s);\n"\ " return 0;\n"\ "}\n", path, global, cacheName, start, body, end, ESP_EXPORT_STRING, cacheName, mprGetPortablePath(path), cacheName); mprLog(6, "Create ESP script: \n%s\n", body); } return body; }
/* * Executed by the child process */ static void cmdTaskEntry(char *program, MprCmdTaskFn entry, int cmdArg) { MprCmd *cmd; MprCmdFile *files; WIND_TCB *tcb; char **ep, *dir; int inFd, outFd, errFd, id, rc; cmd = (MprCmd*) cmdArg; /* * Open standard I/O files (in/out are from the server's perspective) */ files = cmd->files; inFd = open(files[MPR_CMD_STDIN].name, O_RDONLY, 0666); outFd = open(files[MPR_CMD_STDOUT].name, O_WRONLY, 0666); errFd = open(files[MPR_CMD_STDERR].name, O_WRONLY, 0666); if (inFd < 0 || outFd < 0 || errFd < 0) { exit(255); } id = taskIdSelf(); ioTaskStdSet(id, 0, inFd); ioTaskStdSet(id, 1, outFd); ioTaskStdSet(id, 2, errFd); /* * Now that we have opened the stdin and stdout, wakeup our parent. */ semGive(cmd->startCond); /* * Create the environment */ if (envPrivateCreate(id, -1) < 0) { exit(254); } for (ep = cmd->env; ep && *ep; ep++) { putenv(*ep); } /* * Set current directory if required */ if (cmd->dir) { rc = chdir(cmd->dir); } else { dir = mprGetPathDir(cmd, cmd->program); rc = chdir(dir); mprFree(dir); } if (rc < 0) { mprLog(cmd, 0, "cmd: Can't change directory to %s", cmd->dir); exit(255); } /* * Call the user's entry point */ (entry)(cmd->argc, cmd->argv, cmd->env); tcb = taskTcb(id); cmd->status = tcb->exitCode; /* * Cleanup */ envPrivateDestroy(id); close(inFd); close(outFd); close(errFd); semGive(cmd->exitCond); }
/* WARNING: may yield */ PUBLIC int espLoadConfig(HttpRoute *route) { EspRoute *eroute; cchar *name, *package; bool modified; eroute = route->eroute; if (!route->update) { return 0; } package = mprJoinPath(mprGetPathDir(eroute->configFile), "package.json"); modified = 0; ifConfigModified(route, eroute->configFile, &modified); ifConfigModified(route, package, &modified); if (modified) { lock(esp); httpInitConfig(route); #if DEPRECATED || 1 /* Don't reload if configFile == package.json */ if (!mprSamePath(package, eroute->configFile)) { #endif if (mprPathExists(package, R_OK)) { if (httpLoadConfig(route, package) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } } } if (httpLoadConfig(route, eroute->configFile) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } if ((name = espGetConfig(route, "name", 0)) != 0) { eroute->appName = name; } if (espLoadCompilerRules(route) < 0) { return MPR_ERR_CANT_OPEN; } unlock(esp); } if (!route->cookie) { httpSetRouteCookie(route, sfmt("esp-%s", eroute->appName)); } if (route->database && !eroute->edi) { if (espOpenDatabase(route, route->database) < 0) { mprLog("error esp", 0, "Cannot open database %s", route->database); return MPR_ERR_CANT_LOAD; } } #if !ME_STATIC if (!(route->flags & HTTP_ROUTE_NO_LISTEN)) { MprJson *preload, *item; cchar *errMsg, *source; char *kind; int i; /* WARNING: may yield when compiling modules */ if (eroute->combine) { source = mprJoinPaths(route->home, httpGetDir(route, "CACHE"), sfmt("%s.c", eroute->appName), NULL); } else { source = mprJoinPaths(route->home, httpGetDir(route, "SRC"), "app.c", NULL); } lock(esp); if (espLoadModule(route, NULL, "app", source, &errMsg) < 0) { if (eroute->combine) { mprLog("error esp", 0, "%s", errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } if (!eroute->combine && (preload = mprGetJsonObj(route->config, "esp.preload")) != 0) { for (ITERATE_JSON(preload, item, i)) { source = ssplit(sclone(item->value), ":", &kind); if (*kind == '\0') { kind = "controller"; } source = mprJoinPaths(route->home, httpGetDir(route, "CONTROLLERS"), source, NULL); if (espLoadModule(route, NULL, kind, source, &errMsg) < 0) { mprLog("error esp", 0, "Cannot preload esp module %s. %s", source, errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } } unlock(esp); }