/* * Load a module. Returns 0 if the modules is successfully loaded either statically or dynamically. */ MprModule *maLoadModule(MaHttp *http, cchar *name, cchar *libname) { MprModule *module; char entryPoint[MPR_MAX_FNAME]; char *path; path = 0; module = mprLookupModule(http, name); if (module) { mprLog(http, MPR_CONFIG, "Activating module (Builtin) %s", name); return module; } mprSprintf(entryPoint, sizeof(entryPoint), "ma%sInit", name); entryPoint[2] = toupper((int) entryPoint[2]); if (libname == 0) { path = mprStrcat(http, -1, "mod_", name, BLD_SHOBJ, NULL); } if ((module = mprLoadModule(http, (libname) ? libname: path, entryPoint)) == 0) { return 0; } mprLog(http, MPR_CONFIG, "Activating module (Loadable) %s", name); return module; }
/* * Manage requests to directories. This will either do an external redirect back to the browser or do an internal * (transparent) redirection and serve different content back to the browser. This routine may modify the requested * URI and/or the request handler. */ static void processDirectory(MaConn *conn, bool *rescan) { MaRequest *req; MaResponse *resp; MprFileInfo *info; char path[MPR_MAX_FNAME], urlBuf[MPR_MAX_FNAME], *index; int len; req = conn->request; resp = conn->response; info = &resp->fileInfo; mprAssert(info->isDir); index = req->dir->indexName; if (req->url[strlen(req->url) - 1] == '/') { /* * Internal directory redirections */ len = (int) strlen(resp->filename); if (resp->filename[len - 1] == '/') { resp->filename[len - 1] = '\0'; } path[0] = '\0'; mprAssert(resp->filename && *resp->filename); mprAssert(index && *index); mprStrcat(path, sizeof(path), NULL, resp->filename, "/", index, NULL); if (mprAccess(resp, path, R_OK)) { /* * Index file exists, so do an internal redirect to it. Client will not be aware of this happening. * Must rematch the handler on return. */ maSetRequestUri(conn, addIndex(conn, urlBuf, sizeof(urlBuf), index)); resp->filename = mprStrdup(resp, path); mprGetFileInfo(conn, resp->filename, &resp->fileInfo); resp->extension = getExtension(conn); if ((resp->mimeType = (char*) maLookupMimeType(conn->host, resp->extension)) == 0) { resp->mimeType = (char*) "text/html"; } *rescan = 1; } return; } /* * External redirect. Ask the client to re-issue a request for a new location. See if an index exists and if so, * construct a new location for the index. If the index can't be accessed, just append a "/" to the URI and redirect. */ if (req->parsedUri->query && req->parsedUri->query[0]) { mprSprintf(path, sizeof(path), "%s/%s?%s", req->url, index, req->parsedUri->query); } else { mprSprintf(path, sizeof(path), "%s/%s", req->url, index); } if (!mprAccess(resp, path, R_OK)) { mprSprintf(path, sizeof(path), "%s/", req->url); } maRedirect(conn, MPR_HTTP_CODE_MOVED_PERMANENTLY, path); resp->handler = conn->http->passHandler; }
int maAddUser(MaAuth *auth, cchar *realm, cchar *user, cchar *password, bool enabled) { MaUser *up; char *key; up = maCreateUser(auth, realm, user, password, enabled); if (up == 0) { return MPR_ERR_NO_MEMORY; } if (auth->users == 0) { auth->users = mprCreateHash(auth, -1); } key = mprStrcat(auth, -1, realm, ":", user, NULL); if (mprLookupHash(auth->users, key)) { mprFree(key); return MPR_ERR_ALREADY_EXISTS; } if (mprAddHash(auth->users, key, up) == 0) { mprFree(key); return MPR_ERR_NO_MEMORY; } mprFree(key); return 0; }
static void initService() { // TOOD - serviceName should come from the command line program serviceName = BLD_COMPANY "-" BLD_PRODUCT; serviceTitle = BLD_NAME; serviceStopped = 0; serviceProgram = mprStrcat(mpr, -1, mprGetAppDir(mpr), "/", BLD_PRODUCT, ".exe", NULL); }
int maEnableUser(MaAuth *auth, cchar *realm, cchar *user) { MaUser *up; char *key; up = 0; key = mprStrcat(auth, -1, realm, ":", user, NULL); if (auth->users == 0 || (up = (MaUser*) mprLookupHash(auth->users, key)) == 0) { return MPR_ERR_CANT_ACCESS; } up->enabled = 1; return 0; }
int maRemoveUser(MaAuth *auth, cchar *realm, cchar *user) { char *key; key = mprStrcat(auth, -1, realm, ":", user, NULL); if (auth->users == 0 || !mprLookupHash(auth->users, key)) { mprFree(key); return MPR_ERR_CANT_ACCESS; } mprRemoveHash(auth->users, key); mprFree(key); return 0; }
void maSetHostIpAddrPort(MaHost *host, cchar *ipAddrPort) { mprAssert(ipAddrPort); mprFree(host->ipAddrPort); if (*ipAddrPort == ':') { ++ipAddrPort; } if (isdigit((int) *ipAddrPort) && strchr(ipAddrPort, '.') == 0) { host->ipAddrPort = mprStrcat(host, -1, "127.0.0.1", ":", ipAddrPort, NULL); } else { host->ipAddrPort = mprStrdup(host, ipAddrPort); } }
bool maIsUserEnabled(MaAuth *auth, cchar *realm, cchar *user) { MaUser *up; char *key; up = 0; key = mprStrcat(auth, -1, realm, ":", user, NULL); if (auth->users == 0 || (up = (MaUser*) mprLookupHash(auth->users, key)) == 0) { mprFree(key); return 0; } mprFree(key); return up->enabled; }
/* * Security checks. Make sure we are staring with a safe environment */ int checkEnvironment(Mpr *mpr, cchar *program, cchar *home) { #if BLD_UNIX_LIKE char *path; /* * Ensure the binaries directory is in the path. Used by ejs to run ejsweb from /usr/local/bin */ path = mprStrcat(mpr, -1, "PATH=", getenv("PATH"), ":", mprGetAppDir(mpr), NULL); putenv(path); #endif #if BLD_UNIX_LIKE if (unixSecurityChecks(mpr, program, home) < 0) { return -1; } #endif return 0; }
void maSetHostIpAddrPort(MaHost *host, cchar *ipAddrPort) { char buf[MPR_MAX_IP_ADDR_PORT]; mprAssert(ipAddrPort); if (*ipAddrPort == ':') { ipAddrPort++; } if (isdigit((int) *ipAddrPort) && strchr(ipAddrPort, '.') == 0) { buf[0] = '\0'; mprStrcat(buf, sizeof(buf), ":", "127.0.0.1", ipAddrPort, 0); ipAddrPort = buf; } mprFree(host->ipAddrPort); host->ipAddrPort = mprStrdup(host, ipAddrPort); }
cchar *maGetNativePassword(MaConn *conn, cchar *realm, cchar *user) { MaUser *up; MaAuth *auth; char *key; auth = conn->request->auth; up = 0; key = mprStrcat(conn, -1, realm, ":", user, NULL); if (auth->users) { up = (MaUser*) mprLookupHash(auth->users, key); } mprFree(key); if (up == 0) { return 0; } return up->password; }
/* * Put an environment var * * function putenv(key: String, value: String): void */ static EjsVar *putEnvVar(Ejs *ejs, EjsObject *app, int argc, EjsVar **argv) { #if !WINCE #if BLD_UNIX_LIKE char *key, *value; key = mprStrdup(ejs, ejsGetString(argv[0])); value = mprStrdup(ejs, ejsGetString(argv[1])); setenv(key, value, 1); #else char *cmd; cmd = mprStrcat(app, -1, ejsGetString(argv[0]), "=", ejsGetString(argv[1]), NULL); putenv(cmd); #endif #endif return 0; }
MAIN(appweb, int argc, char **argv) { Mpr *mpr; MaHttp *http; cchar *ipAddrPort, *documentRoot, *argp, *logSpec; char *configFile, *ipAddr, *homeDir, *timeText, *ejsPrefix, *ejsPath, *changeRoot; int workers, outputVersion, argind, port; documentRoot = 0; changeRoot = ejsPrefix = ejsPath = 0; ipAddrPort = 0; ipAddr = 0; port = -1; logSpec = 0; server = 0; outputVersion = 0; workers = -1; configFile = BLD_FEATURE_CONFIG_FILE; homeDir = BLD_FEATURE_SERVER_ROOT; mpr = mprCreate(argc, argv, memoryFailure); argc = mpr->argc; argv = mpr->argv; #if BLD_FEATURE_ROMFS extern MprRomInode romFiles[]; mprSetRomFileSystem(mpr, romFiles); #endif if (osInit(mpr) < 0) { exit(2); } if (mprStart(mpr, 0) < 0) { mprUserError(mpr, "Can't start MPR for %s", mprGetAppName(mpr)); mprFree(mpr); return MPR_ERR_CANT_INITIALIZE; } for (argind = 1; argind < argc; argind++) { argp = argv[argind]; if (*argp != '-') { break; } if (strcmp(argp, "--config") == 0) { if (argind >= argc) { return printUsage(mpr); } configFile = argv[++argind]; #if BLD_UNIX_LIKE } else if (strcmp(argp, "--chroot") == 0) { if (argind >= argc) { return printUsage(mpr); } changeRoot = mprGetAbsPath(mpr, argv[++argind]); #endif } else if (strcmp(argp, "--debug") == 0 || strcmp(argp, "-D") == 0 || strcmp(argp, "-d") == 0 || strcmp(argp, "--debugger") == 0) { mprSetDebugMode(mpr, 1); } else if (strcmp(argp, "--ejs") == 0) { if (argind >= argc) { return printUsage(mpr); } ejsPrefix = mprStrdup(mpr, argv[++argind]); if ((ejsPath = strchr(ejsPrefix, ':')) != 0) { *ejsPath++ = '\0'; } ejsPath = mprGetAbsPath(mpr, ejsPath); } else if (strcmp(argp, "--home") == 0) { if (argind >= argc) { return printUsage(mpr); } homeDir = mprGetAbsPath(mpr, argv[++argind]); if (chdir((char*) homeDir) < 0) { mprPrintfError(mpr, "%s: Can't change directory to %s\n", mprGetAppName(mpr), homeDir); exit(2); } } else if (strcmp(argp, "--log") == 0 || strcmp(argp, "-l") == 0) { if (argind >= argc) { return printUsage(mpr); } logSpec = argv[++argind]; maStartLogging(mpr, logSpec); } else if (strcmp(argp, "--name") == 0 || strcmp(argp, "-n") == 0) { if (argind >= argc) { return printUsage(mpr); } mprSetAppName(mpr, argv[++argind], 0, 0); } else if (strcmp(argp, "--threads") == 0) { if (argind >= argc) { return printUsage(mpr); } workers = atoi(argv[++argind]); } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) { maStartLogging(mpr, "stdout:2"); } else if (strcmp(argp, "--version") == 0 || strcmp(argp, "-V") == 0) { outputVersion++; } else { mprPrintfError(mpr, "Unknown switch \"%s\"\n", argp); printUsage(mpr); exit(2); } } if (argc > argind) { if (argc > (argind + 2)) { return printUsage(mpr); } ipAddrPort = argv[argind++]; if (argc > argind) { documentRoot = argv[argind++]; } else { documentRoot = "."; } } if (outputVersion) { mprPrintf(mpr, "%s %s-%s\n", mprGetAppTitle(mpr), BLD_VERSION, BLD_NUMBER); exit(0); } if (ipAddrPort) { mprParseIp(mpr, ipAddrPort, &ipAddr, &port, MA_SERVER_DEFAULT_PORT_NUM); } else { #if BLD_FEATURE_CONFIG_PARSE if (configFile == 0) { configFile = mprStrcat(mpr, -1, mprGetAppName(mpr), ".conf", NULL); } if (!mprPathExists(mpr, configFile, R_OK)) { mprPrintfError(mpr, "Can't open config file %s\n", configFile); exit(2); } #else return printUsage(mpr); #endif #if !BLD_FEATURE_ROMFS if (homeDir == 0) { homeDir = mprGetPathParent(mpr, configFile); if (chdir((char*) homeDir) < 0) { mprPrintfError(mpr, "%s: Can't change directory to %s\n", mprGetAppName(mpr), homeDir); exit(2); } } #endif } homeDir = mprGetCurrentPath(mpr); if (checkEnvironment(mpr, argv[0], homeDir) < 0) { exit(3); } #if BLD_UNIX_LIKE if (changeRoot) { homeDir = mprGetAbsPath(mpr, changeRoot); if (chdir(homeDir) < 0) { mprError(mpr, "%s: Can't change directory to %s", homeDir); exit(4); } if (chroot(homeDir) < 0) { if (errno == EPERM) { mprError(mpr, "%s: Must be super user to use the --chroot option", mprGetAppName(mpr)); } else { mprError(mpr, "%s: Can't change change root directory to %s, errno %d", mprGetAppName(mpr), homeDir, errno); } exit(5); } } #endif /* * Create the top level HTTP service and default HTTP server. Set the initial server root to "." */ http = maCreateHttp(mpr); if (http == 0) { mprUserError(mpr, "Can't create HTTP service for %s", mprGetAppName(mpr)); return MPR_ERR_CANT_INITIALIZE; } server = maCreateServer(http, "default", ".", 0, -1); if (server == 0) { mprUserError(mpr, "Can't create HTTP server for %s", mprGetAppName(mpr)); return MPR_ERR_CANT_INITIALIZE; } if (maConfigureServer(mpr, http, server, configFile, ipAddr, port, documentRoot) < 0) { /* mprUserError(mpr, "Can't configure the server, exiting."); */ exit(6); } if (mpr->ipAddr) { mprLog(mpr, 2, "Server IP address %s", mpr->ipAddr); } timeText = mprFormatLocalTime(mpr, mprGetTime(mpr)); mprLog(mpr, 1, "Started at %s", timeText); mprFree(timeText); #if BLD_FEATURE_EJS if (ejsPrefix) { createEjsAlias(mpr, http, server, ejsPrefix, ejsPath); } #endif #if BLD_FEATURE_MULTITHREAD if (workers >= 0) { mprSetMaxWorkers(http, workers); } #endif #if BLD_WIN_LIKE if (!ejsPrefix) { writePort(server->defaultHost); } #endif if (maStartHttp(http) < 0) { mprUserError(mpr, "Can't start HTTP service, exiting."); exit(7); } #if BLD_FEATURE_MULTITHREAD mprLog(mpr, 1, "HTTP services are ready with max %d worker threads", mprGetMaxWorkers(mpr)); #else mprLog(mpr, 1, "HTTP services are ready (single-threaded)"); #endif /* * Service I/O events until instructed to exit */ while (!mprIsExiting(mpr)) { mprServiceEvents(mpr->dispatcher, -1, MPR_SERVICE_EVENTS | MPR_SERVICE_IO); } /* * Signal a graceful shutdown */ mprLog(http, 1, "Exiting ..."); maStopHttp(http); mprLog(http, 1, "Exit complete"); #if VXWORKS if (mprStop(mpr)) { mprFree(mpr); } #endif return 0; }
/* Start the command to run (stdIn and stdOut are named from the client's perspective) */ int startProcess(MprCmd *cmd) { MprCmdTaskFn entryFn; SYM_TYPE symType; char *entryPoint, *program; int i, pri; mprLog(cmd, 4, "cmd: start %s", cmd->program); entryPoint = 0; if (cmd->env) { for (i = 0; cmd->env[i]; i++) { if (strncmp(cmd->env[i], "entryPoint=", 11) == 0) { entryPoint = mprStrdup(cmd, cmd->env[i]); } } } program = mprGetPathBase(cmd, cmd->program); if (entryPoint == 0) { program = mprTrimPathExtension(cmd, program); #if BLD_HOST_CPU_ARCH == MPR_CPU_IX86 || BLD_HOST_CPU_ARCH == MPR_CPU_IX64 entryPoint = mprStrcat(cmd, -1, "_", program, "Main", NULL); #else entryPoint = mprStrcat(cmd, -1, program, "Main", NULL); #endif } if (symFindByName(sysSymTbl, entryPoint, (char**) &entryFn, &symType) < 0) { if (mprLoadModule(cmd, cmd->program, NULL) == 0) { mprError(cmd, "start: can't load DLL %s, errno %d", program, mprGetOsError()); return MPR_ERR_CANT_READ; } if (symFindByName(sysSymTbl, entryPoint, (char**) &entryFn, &symType) < 0) { mprError(cmd, "start: can't find symbol %s, errno %d", entryPoint, mprGetOsError()); return MPR_ERR_CANT_ACCESS; } } taskPriorityGet(taskIdSelf(), &pri); /* * Pass the server output file to become the client stdin. */ cmd->pid = taskSpawn(entryPoint, pri, VX_FP_TASK, MPR_DEFAULT_STACK, (FUNCPTR) cmdTaskEntry, (int) cmd->program, (int) entryFn, (int) cmd, 0, 0, 0, 0, 0, 0, 0); if (cmd->pid < 0) { mprError(cmd, "start: can't create task %s, errno %d", entryPoint, mprGetOsError()); mprFree(entryPoint); return MPR_ERR_CANT_CREATE; } mprLog(cmd, 7, "cmd, child taskId %d", cmd->pid); mprFree(entryPoint); if (semTake(cmd->startCond, MPR_TIMEOUT_START_TASK) != OK) { mprError(cmd, "start: child %s did not initialize, errno %d", cmd->program, mprGetOsError()); return MPR_ERR_CANT_CREATE; } semDelete(cmd->startCond); cmd->startCond = 0; return 0; }
/* * Determine if this user is specified as being eligible for this realm. We examine the requiredUsers and requiredGroups. */ static bool isUserValid(MaAuth *auth, cchar *realm, cchar *user) { MaGroup *gp; MaUser *up; cchar *tok, *gtok; char ubuf[80], gbuf[80], *key, *requiredUser, *group, *name; int rc, next; if (auth->anyValidUser) { key = mprStrcat(auth, -1, realm, ":", user, NULL); if (auth->users == 0) { return 0; } rc = mprLookupHash(auth->users, key) != 0; mprFree(key); return rc; } if (auth->requiredUsers) { tok = NULL; requiredUser = mprGetWordTok(ubuf, sizeof(ubuf), auth->requiredUsers, " \t", &tok); while (requiredUser) { if (strcmp(user, requiredUser) == 0) { return 1; } requiredUser = mprGetWordTok(ubuf, sizeof(ubuf), 0, " \t", &tok); } } if (auth->requiredGroups) { gtok = NULL; group = mprGetWordTok(gbuf, sizeof(gbuf), auth->requiredGroups, " \t", >ok); /* * For each group, check all the users in the group. */ while (group) { if (auth->groups == 0) { gp = 0; } else { gp = (MaGroup*) mprLookupHash(auth->groups, group); } if (gp == 0) { mprError(auth, "Can't find group %s", group); group = mprGetWordTok(gbuf, sizeof(gbuf), 0, " \t", >ok); continue; } for (next = 0; (name = mprGetNextItem(gp->users, &next)) != 0; ) { if (strcmp(user, name) == 0) { return 1; } } group = mprGetWordTok(gbuf, sizeof(gbuf), 0, " \t", >ok); } } if (auth->requiredAcl != 0) { key = mprStrcat(auth, -1, realm, ":", user, NULL); up = (MaUser*) mprLookupHash(auth->users, key); if (up) { mprLog(auth, 6, "UserRealm \"%s\" has ACL %lx, Required ACL %lx", key, up->acl, auth->requiredAcl); if (up->acl & auth->requiredAcl) { mprFree(key); return 1; } } mprFree(key); } return 0; }
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 bool parseArgs(Mpr *mpr, int argc, char **argv) { char *argp, *key, *value; int i, setWorkers; setWorkers = 0; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (strcmp(argp, "--benchmark") == 0 || strcmp(argp, "-b") == 0) { benchmark++; } else if (strcmp(argp, "--chunk") == 0) { if (nextArg >= argc) { return 0; } else { chunkSize = argv[++nextArg]; i = atoi(chunkSize); if (i < 0) { mprError(mpr, "Bad chunksize %d", i); return 0; } } } else if (strcmp(argp, "--continue") == 0) { continueOnErrors++; } else if (strcmp(argp, "--cookie") == 0) { if (nextArg >= argc) { return 0; } else { mprAddItem(headers, mprCreateKeyPair(headers, "Cookie", argv[++nextArg])); } } else if (strcmp(argp, "--debug") == 0 || strcmp(argp, "-D") == 0 || strcmp(argp, "--debugger") == 0) { mprSetDebugMode(mpr, 1); retries = 0; } else if (strcmp(argp, "--delete") == 0) { method = "DELETE"; } else if (strcmp(argp, "--form") == 0 || strcmp(argp, "-f") == 0) { if (nextArg >= argc) { return 0; } else { if (formData == 0) { formData = mprCreateList(mpr); } addFormVars(mpr, argv[++nextArg]); } } else if (strcmp(argp, "--header") == 0) { if (nextArg >= argc) { return 0; } else { key = argv[++nextArg]; if ((value = strchr(key, ':')) == 0) { mprError(mpr, "Bad header format. Must be \"key: value\""); return 0; } *value++ = '\0'; while (isspace((int) *value)) { value++; } mprAddItem(headers, mprCreateKeyPair(headers, key, value)); } } else if (strcmp(argp, "--host") == 0) { if (nextArg >= argc) { return 0; } else { host = argv[++nextArg]; } } else if (strcmp(argp, "--http") == 0) { if (nextArg >= argc) { return 0; } else { httpVersion = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--iterations") == 0 || strcmp(argp, "-i") == 0) { if (nextArg >= argc) { return 0; } else { iterations = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--log") == 0 || strcmp(argp, "-l") == 0) { if (nextArg >= argc) { return 0; } else { startLogging(mpr, argv[++nextArg]); } } else if (strcmp(argp, "--method") == 0) { if (nextArg >= argc) { return 0; } else { method = argv[++nextArg]; } } else if (strcmp(argp, "--noout") == 0 || strcmp(argp, "-n") == 0 || strcmp(argp, "--quiet") == 0 || strcmp(argp, "-q") == 0) { noout++; } else if (strcmp(argp, "--nofollow") == 0) { nofollow++; } else if (strcmp(argp, "--password") == 0 || strcmp(argp, "-p") == 0) { if (nextArg >= argc) { return 0; } else { password = argv[++nextArg]; } } else if (strcmp(argp, "--post") == 0) { method = "POST"; } else if (strcmp(argp, "--printable") == 0) { printable++; } else if (strcmp(argp, "--put") == 0) { method = "PUT"; } else if (strcmp(argp, "--range") == 0) { if (nextArg >= argc) { return 0; } else { if (ranges == 0) { ranges = mprAsprintf(mpr, -1, "bytes=%s", argv[++nextArg]); } else { ranges = mprStrcat(mpr, -1, ranges, ",", argv[++nextArg], NULL); } } } else if (strcmp(argp, "--retries") == 0 || strcmp(argp, "-r") == 0) { if (nextArg >= argc) { return 0; } else { retries = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--sequence") == 0) { sequence++; } else if (strcmp(argp, "--showCode") == 0 || strcmp(argp, "--showStatus") == 0) { showCode++; } else if (strcmp(argp, "--show") == 0 || strcmp(argp, "--showHeaders") == 0) { showHeaders++; } else if (strcmp(argp, "--single") == 0 || strcmp(argp, "-s") == 0) { singleStep++; } else if (strcmp(argp, "--threads") == 0 || strcmp(argp, "-t") == 0) { if (nextArg >= argc) { return 0; } else { loadThreads = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--timeout") == 0) { if (nextArg >= argc) { return 0; } else { timeout = atoi(argv[++nextArg]) * 1000; } } else if (strcmp(argp, "--upload") == 0 || strcmp(argp, "-u") == 0) { upload++; } else if (strcmp(argp, "--user") == 0 || strcmp(argp, "--username") == 0) { if (nextArg >= argc) { return 0; } else { username = argv[++nextArg]; } } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) { verbose++; } else if (strcmp(argp, "--workerTheads") == 0 || strcmp(argp, "-w") == 0) { if (nextArg >= argc) { return 0; } else { workers = atoi(argv[++nextArg]); } setWorkers++; } else { return 0; break; } } if (argc == nextArg) { return 0; } argc = argc - nextArg; argv = &argv[nextArg]; target = argv[argc - 1]; argc--; if (argc > 0) { /* * Files present on command line */ fileData = mprCreateList(mpr); for (i = 0; i < argc; i++) { mprAddItem(fileData, argv[i]); } } if (!setWorkers) { workers = loadThreads + 2; } if (method == 0) { if (upload || formData) { method = "POST"; } else if (fileData) { method = "PUT"; } else { method = "GET"; } } return 1; }
/* * Add a response cookie */ static void setCookie(void *handle, cchar *name, cchar *value, cchar *path, cchar *cookieDomain, int lifetime, bool isSecure) { struct tm tm; cchar *userAgent, *hostName; char dateStr[64], *cp, *expiresAtt, *expires, *domainAtt, *domain, *secure; if (path == 0) { path = "/"; } userAgent = getHeader(handle, "HTTP_USER_AGENT"); hostName = getHeader(handle, "HTTP_HOST"); /* * Fix for Safari and Bonjour addresses with a trailing ".". Safari discards cookies without a domain specifier * or with a domain that includes a trailing ".". Solution: include an explicit domain and trim the trailing ".". * * User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) * AppleWebKit/530.0+ (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 */ if (cookieDomain == 0 && userAgent && strstr(userAgent, "AppleWebKit") != 0) { domain = mprStrdup(mpr, hostName); if ((cp = strchr(domain, ':')) != 0) { *cp = '\0'; } if (*domain && domain[strlen(domain) - 1] == '.') { domain[strlen(domain) - 1] = '\0'; } else { domain = 0; } } else { domain = 0; } if (domain) { domainAtt = "; domain="; } else { domainAtt = ""; } if (lifetime > 0) { mprDecodeUniversalTime(mpr, &tm, mprGetTime(mpr) + (lifetime * MPR_TICKS_PER_SEC)); mprFormatTime(mpr, MPR_HTTP_DATE, &tm); expiresAtt = "; expires="; expires = dateStr; } else { expires = expiresAtt = ""; } if (isSecure) { secure = "; secure"; } else { secure = ";"; } /* * Allow multiple cookie headers. Even if the same name. Later definitions take precedence */ setHeader(handle, 1, "Set-Cookie", mprStrcat(mpr, -1, name, "=", value, "; path=", path, domainAtt, domain, expiresAtt, expires, secure, NULL)); setHeader(handle, 0, "Cache-control", "no-cache=\"set-cookie\""); }
/* * Parse the request headers. Return true if the header parsed. */ static bool parseHeaders(MaConn *conn, MaPacket *packet) { MaHostAddress *address; MaRequest *req; MaHost *host, *hp; MaLimits *limits; MprBuf *content; char keyBuf[MPR_MAX_STRING]; char *key, *value, *cp, *tok; int count, keepAlive; req = conn->request; host = req->host; content = packet->content; conn->request->headerPacket = packet; limits = &conn->http->limits; keepAlive = 0; strcpy(keyBuf, "HTTP_"); mprAssert(strstr((char*) content->start, "\r\n")); for (count = 0; content->start[0] != '\r' && !conn->connectionFailed; count++) { if (count >= limits->maxNumHeaders) { maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Too many headers"); return 0; } if ((key = getToken(conn, ":")) == 0 || *key == '\0') { maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad header format"); return 0; } value = getToken(conn, "\r\n"); while (isspace((int) *value)) { value++; } if (conn->requestFailed) { continue; } mprStrUpper(key); for (cp = key; *cp; cp++) { if (*cp == '-') { *cp = '_'; } } mprLog(req, 8, "Key %s, value %s", key, value); if (strspn(key, "%<>/\\") > 0) { maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad header key value"); continue; } /* * Define the header with a "HTTP_" prefix */ mprStrcpy(&keyBuf[5], sizeof(keyBuf) - 5, key); mprAddDuplicateHash(req->headers, keyBuf, value); switch (key[0]) { case 'A': if (strcmp(key, "AUTHORIZATION") == 0) { value = mprStrdup(req, value); req->authType = mprStrTok(value, " \t", &tok); req->authDetails = tok; } else if (strcmp(key, "ACCEPT_CHARSET") == 0) { req->acceptCharset = value; } else if (strcmp(key, "ACCEPT") == 0) { req->accept = value; } else if (strcmp(key, "ACCEPT_ENCODING") == 0) { req->acceptEncoding = value; } break; case 'C': if (strcmp(key, "CONTENT_LENGTH") == 0) { if (req->length >= 0) { maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Mulitple content length headers"); continue; } req->length = mprAtoi(value, 10); if (req->length < 0) { maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad content length"); continue; } if (req->length >= host->limits->maxBody) { maFailConnection(conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, "Request content length %Ld is too big. Limit %Ld", req->length, host->limits->maxBody); continue; } mprAssert(req->length >= 0); req->remainingContent = req->length; req->contentLengthStr = value; } else if (strcmp(key, "CONTENT_RANGE") == 0) { /* * This headers specifies the range of any posted body data * Format is: Content-Range: bytes n1-n2/length * Where n1 is first byte pos and n2 is last byte pos */ char *sp; int start, end, size; start = end = size = -1; sp = value; while (*sp && !isdigit((int) *sp)) { sp++; } if (*sp) { start = (int) mprAtoi(sp, 10); if ((sp = strchr(sp, '-')) != 0) { end = (int) mprAtoi(++sp, 10); } if ((sp = strchr(sp, '/')) != 0) { /* * Note this is not the content length transmitted, but the original size of the input of which * the client is transmitting only a portion. */ size = (int) mprAtoi(++sp, 10); } } if (start < 0 || end < 0 || size < 0 || end <= start) { maFailRequest(conn, MPR_HTTP_CODE_RANGE_NOT_SATISFIABLE, "Bad content range"); continue; } req->inputRange = maCreateRange(conn, start, end); } else if (strcmp(key, "CONTENT_TYPE") == 0) { req->mimeType = value; req->form = strstr(value, "application/x-www-form-urlencoded") != 0; } else if (strcmp(key, "COOKIE") == 0) { if (req->cookie && *req->cookie) { req->cookie = mprStrcat(req, -1, req->cookie, "; ", value, NULL); } else { req->cookie = value; } } else if (strcmp(key, "CONNECTION") == 0) { req->connection = value; if (mprStrcmpAnyCase(value, "KEEP-ALIVE") == 0) { keepAlive++; } else if (mprStrcmpAnyCase(value, "CLOSE") == 0) { conn->keepAliveCount = 0; } if (!host->keepAlive) { conn->keepAliveCount = 0; } } break; case 'F': req->forwarded = value; break; case 'H': if (strcmp(key, "HOST") == 0) { req->hostName = value; address = conn->address; if (maIsNamedVirtualHostAddress(address)) { hp = maLookupVirtualHost(address, value); if (hp == 0) { maFailRequest(conn, 404, "No host to serve request. Searching for %s", value); mprLog(conn, 1, "Can't find virtual host %s", value); continue; } req->host = hp; /* * Reassign this request to a new host */ maRemoveConn(host, conn); host = hp; conn->host = hp; maAddConn(hp, conn); } } break; case 'I': if ((strcmp(key, "IF_MODIFIED_SINCE") == 0) || (strcmp(key, "IF_UNMODIFIED_SINCE") == 0)) { MprTime newDate = 0; char *cp; bool ifModified = (key[3] == 'M'); if ((cp = strchr(value, ';')) != 0) { *cp = '\0'; } if (mprParseTime(conn, &newDate, value, MPR_UTC_TIMEZONE, NULL) < 0) { mprAssert(0); break; } if (newDate) { setIfModifiedDate(conn, newDate, ifModified); req->flags |= MA_REQ_IF_MODIFIED; } } else if ((strcmp(key, "IF_MATCH") == 0) || (strcmp(key, "IF_NONE_MATCH") == 0)) { char *word, *tok; bool ifMatch = key[3] == 'M'; if ((tok = strchr(value, ';')) != 0) { *tok = '\0'; } req->ifMatch = ifMatch; req->flags |= MA_REQ_IF_MODIFIED; value = mprStrdup(conn, value); word = mprStrTok(value, " ,", &tok); while (word) { addMatchEtag(conn, word); word = mprStrTok(0, " ,", &tok); } } else if (strcmp(key, "IF_RANGE") == 0) { char *word, *tok; if ((tok = strchr(value, ';')) != 0) { *tok = '\0'; } req->ifMatch = 1; req->flags |= MA_REQ_IF_MODIFIED; value = mprStrdup(conn, value); word = mprStrTok(value, " ,", &tok); while (word) { addMatchEtag(conn, word); word = mprStrTok(0, " ,", &tok); } } break; case 'P': if (strcmp(key, "PRAGMA") == 0) { req->pragma = value; } break; case 'R': if (strcmp(key, "RANGE") == 0) { if (!parseRange(conn, value)) { maFailRequest(conn, MPR_HTTP_CODE_RANGE_NOT_SATISFIABLE, "Bad range"); } } else if (strcmp(key, "REFERER") == 0) { /* NOTE: yes the header is misspelt in the spec */ req->referer = value; } break; case 'T': if (strcmp(key, "TRANSFER_ENCODING") == 0) { mprStrLower(value); if (strcmp(value, "chunked") == 0) { req->flags |= MA_REQ_CHUNKED; /* * This will be revised by the chunk filter as chunks are processed and will be set to zero when the * last chunk has been received. */ req->remainingContent = MAXINT; } } break; #if BLD_DEBUG case 'X': if (strcmp(key, "X_APPWEB_CHUNK_SIZE") == 0) { mprStrUpper(value); conn->response->chunkSize = atoi(value); if (conn->response->chunkSize <= 0) { conn->response->chunkSize = 0; } else if (conn->response->chunkSize > conn->http->limits.maxChunkSize) { conn->response->chunkSize = conn->http->limits.maxChunkSize; } } break; #endif case 'U': if (strcmp(key, "USER_AGENT") == 0) { req->userAgent = value; } break; } } if (conn->protocol == 0 && !keepAlive) { conn->keepAliveCount = 0; } if (!(req->flags & MA_REQ_CHUNKED)) { /* * Step over "\r\n" after headers. As an optimization, don't do this if chunked so chunking can parse a single * chunk delimiter of "\r\nSIZE ...\r\n" */ mprAdjustBufStart(content, 2); } mprLog(conn, 3, "Select host \"%s\"", conn->host->name); if (maSetRequestUri(conn, req->url, "") < 0) { maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad URI format"); return 0; } if (conn->host->secure) { req->parsedUri->scheme = mprStrdup(req, "https"); } req->parsedUri->port = conn->sock->port; req->parsedUri->host = req->hostName ? req->hostName : conn->host->name; return 1; }
int MprTestSession::setupTests(MprTestResult *result, Mpr *mpr, int argc, char *argv[], char *switches) { char switchBuf[80]; char *programName, *argp; int errflg, c, i, l; #if BLD_FEATURE_LOG char *logSpec; #endif this->mpr = mpr; programName = mprGetBaseName(argv[0]); errflg = 0; #if BLD_FEATURE_LOG logSpec = "stdout:1"; logger = new MprLogToFile(); #endif switchBuf[0] = '\0'; mprStrcat(switchBuf, sizeof(switchBuf), 0, "cDeg:i:l:n:msT:t:v?", switches, (void*) 0); MprCmdLine cmdLine(argc, argv, switchBuf); while ((c = cmdLine.next(&argp)) != EOF) { switch(c) { case 'c': result->setContinueOnFailures(1); break; case 'D': mprSetDebugMode(1); result->setDebugOnFailures(1); break; case 'e': needEventsThread = 1; break; case 'g': testGroups->parse(argp); break; case 'i': iterations = atoi(argp); break; case 'l': #if BLD_FEATURE_LOG logSpec = argp; #endif break; case 'n': l = atoi(argp); if (l == 0) { sessionLevel = MPR_BASIC; } else if (l == 1) { sessionLevel = MPR_THOROUGH; } else { sessionLevel = MPR_DEDICATED; } break; case 'm': mprRequestMemStats(1); break; case 's': result->setSingleStep(1); break; case 't': i = atoi(argp); if (i <= 0 || i > 100) { mprFprintf(MPR_STDERR, "%s: Bad number of threads (0-100)\n", programName); exit(2); } #if BLD_FEATURE_MULTITHREAD numThreads = i; #endif break; case 'T': #if BLD_FEATURE_MULTITHREAD poolThreads = atoi(argp); #endif break; case 'v': verbose++; break; default: // // Ignore args we don't understand // break; case '?': errflg++; break; } } if (errflg) { mprFprintf(MPR_STDERR, "usage: %s [-cDemsv] [-g groups] [-i iterations] " "[-l logSpec] [-n testLevel] [-T poolThreads] [-t threads]\n", programName); exit(2); } #if !BLD_FEATURE_MULTITHREAD needEventsThread = 0; #endif #if BLD_FEATURE_LOG mpr->addListener(logger); mpr->setLogSpec(logSpec); #endif initSignals(); this->argc = argc; this->argv = argv; this->firstArg = cmdLine.firstArg(); #if BLD_FEATURE_MULTITHREAD mpr->setMaxPoolThreads(poolThreads); #endif if (mpr->start(needEventsThread ? MPR_SERVICE_THREAD : 0) < 0) { return MPR_ERR_CANT_INITIALIZE; } result->adjustThreadCount(numThreads); result->setVerbosity(verbose); if (result->getListenerCount() == 0) { result->addListener(new MprTestListener("__default__")); } if (verbose) { mprFprintf(MPR_STDOUT, "Testing: iterations %d, threads %d, pool %d, service thread %d\n", iterations, numThreads, poolThreads, needEventsThread); } // // Use current session object for the main thread // sessions = (MprTestSession**) mprMalloc(sizeof(MprTestSession*) * numThreads); sessions[0] = this; if (sessions[0]->initializeClasses(result) < 0) { exit(3); } #if BLD_FEATURE_MULTITHREAD // // Now clone this session object for all other threads // for (i = 1; i < numThreads; i++) { char tName[64]; sessions[i] = this->newSession(); sessions[i]->setResult(result); sessions[i]->cloneSettings(this); mprSprintf(tName, sizeof(tName), "test.%d", i); } #endif 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; }
/* * When we come here, we've already matched either a location block or an extension */ static int run(request_rec *r) { EjsDirConfig *dir; EjsServerConfig *server; cchar *ext; MaRequest *req; MaResponse *resp; MaConn *conn; MaAlias *alias; MaLocation *location; EjsWeb *web; cchar *sep, *prefix; char *urlBase, *dir, *app, *url, *cp; int flags, locFlags; if (!r->handler || strcasecmp(r->handler, "ejs") != 0) { return DECLINED; } dir = getDir(r) server = getServer(r->XXX); // EjsAlias should probably be creating a directory block. These flags should probably be in a directory if (loc->flags & (MA_LOC_APP | MA_LOC_APP_DIR)) { /* * Send non-ejs content under web to another handler, typically the file handler. */ if (strncmp(&req->url[loc->prefixLen], "web/", 4) == 0) { if (!(ext && strcmp(ext, "ejs") == 0)) { return DECLINED; } } else { if (ext && strcmp(ext, "ejs") == 0) { maFormatBody(conn, "Bad Request", "Can't serve *.ejs files outside web directory"); maFailRequest(conn, MPR_HTTP_CODE_BAD_REQUEST, "Can't server *.ejs files outside web directory"); return HTTP_XXX; } } } flags = 0; url = 0; locFlags = location->flags; if (locFlags & MA_LOC_APP) { app = mprStrTrim(mprStrdup(q, prefix), "/"); url = &req->url[alias->prefixLen]; dir = mprStrdup(resp, alias->filename); if (*url != '/') { url--; } urlBase = mprStrdup(resp, prefix); } else if (locFlags & MA_LOC_APP_DIR) { url = &req->url[alias->prefixLen]; app = mprStrdup(resp, url); if ((cp = strchr(app, '/')) != 0) { url = mprStrdup(resp, cp); *cp = '\0'; } sep = prefix[strlen(prefix) - 1] == '/' ? "" : "/"; dir = mprStrcat(resp, &dir, alias->filename, sep, app, NULL); urlBase = mprStrcat(resp, prefix, sep, app, NULL); } else { app = 0; dir = mprStrdup(resp, alias->filename); url = &req->url[alias->prefixLen]; flags |= EJS_WEB_FLAG_SOLO; if (*url != '/') { url--; } urlBase = mprStrdup(resp, prefix); } mprStrTrim(urlBase, "/"); mprStrTrim(dir, "/"); if (location->flags & MA_LOC_BROWSER) { flags |= EJS_WEB_FLAG_BROWSER_ERRORS; } if (location->flags & MA_LOC_AUTO_SESSION) { flags |= EJS_WEB_FLAG_SESSION; } /* * Var Stand-Alone App AppDir * app 0 carmen carmen * dir /Users/mob/.... /Users/mob/hg/carmen /Users/mob/hg/carmen * urlBase /xg/carmen /carmen * url stock stock */ web = ejsCreateWebRequest(req, q->stage->stageData, conn, app, dir, urlBase, url, req->cookie, flags); if (web == 0) { maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't create Ejs web object for %s", req->url); return; } q->queueData = web; maSetHeader(conn, 0, "Last-Modified", req->host->currentDate); maDontCacheResponse(conn); if (r->method_number != M_GET) { return HTTP_METHOD_NOT_ALLOWED; } if (ejsProcessWebRequest((EjsWeb*) r, &msg) < 0) { if (web->flags & EJS_WEB_FLAG_BROWSER_ERRORS) { maFormatBody(conn, "Request Failed", "%s", msg); } maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, msg); mprFree(msg); } ap_set_content_type(r, "text/html"); ap_rputs("<html><title>Hello World!</title><body><p>Hello World</p></body></html>\r\n", r); #if 0 if ((err = set_content_length(r, r->finfo.st_stize)) || (err = set_last_modified(r, r->finfo.st_mtime))) return err; if (r->finof.st_mode == 0) return NOT_FOUND; fopen(r->filename, "r"); if (!r->main) { /* Not internal redirect */ apr_table_set(r->headers_out, "X-ejs", "Under construction"); } register_timeout("send", r); send_http_header(r); if (!r->header_only) send_fd(f, r); pfclose(r->pool, f); #endif return OK; }
int MaHost::mapToStorage(MaRequest *rq, char *path, int pathLen, char *uri, int flags) { MaAlias *ap; MaDir *dir; char urlBuf[MPR_HTTP_MAX_URL]; char *base, *aliasName, *prefix; int len, redirectCode, prefixLen; mprAssert(path); mprAssert(pathLen > 0); *path = '\0'; lock(); // // FUTURE - Could optimize by having a hash lookup for alias prefixes. // ap = (MaAlias*) aliases.getFirst(); while (ap) { aliasName = ap->getName(); prefix = ap->getPrefix(); prefixLen = ap->getPrefixLen(); // // Note that for Aliases with redirects, the aliasName is a URL and // not a document path. // if (strncmp(prefix, uri, prefixLen) == 0) { redirectCode = ap->getRedirectCode(); if (redirectCode) { if (flags & MPR_HTTP_REDIRECT) { rq->redirect(redirectCode, aliasName); rq->flushOutput(MPR_HTTP_FOREGROUND_FLUSH, MPR_HTTP_FINISH_REQUEST); } else { mprStrcpy(path, pathLen, aliasName); } unlock(); return 0; } base = &uri[prefixLen]; while (*base == '/') { base++; } if (aliasName[strlen(aliasName) - 1] == '/') { len = mprSprintf(path, pathLen, "%s%s", aliasName, base); } else if (*base) { len = mprSprintf(path, pathLen, "%s/%s", aliasName, base); } else { len = mprStrcpy(path, pathLen, aliasName); } dir = 0; if (*base != '\0') { // // There was some extra URI past the matching alias prefix // portion // #if WIN // // Windows will ignore trailing "." and " ". We must reject // here as the URL probably won't match due to the trailing // character and the copyHandler will return the unprocessed // content to the user. Bad. // int lastc = base[strlen(base) - 1]; if (lastc == '.' || lastc == ' ') { unlock(); return MPR_ERR_CANT_ACCESS; } #endif unlock(); return 0; } else { if (*prefix == '\0') { prefix = "/"; } // // The URL matched the alias exactly so we change the URI // to match the prefix as we may have changed the extension // mprStrcpy(urlBuf, sizeof(urlBuf), prefix); MaUrl *url = rq->getUrl(); if (strcmp(urlBuf, url->uri) != 0) { if (url->query && *url->query) { mprStrcat(urlBuf, sizeof(urlBuf), "?", url->query, (void*) 0); } if (flags & MPR_HTTP_REMATCH) { rq->setUri(urlBuf); rq->parseUri(); } } } if (flags & MPR_HTTP_REMATCH) { rq->deleteHandlers(); } unlock(); return 0; } ap = (MaAlias*) aliases.getNext(ap); } unlock(); return MPR_ERR_NOT_FOUND; }
/* * function Worker(script: String = null, options: Object = null) * * Script is optional. If supplied, the script is run immediately by a worker thread. This call * does not block. Options are: search and name. */ static EjsVar *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { Ejs *wejs; EjsVar *options, *value; EjsName qname; EjsWorker *self; cchar *search, *name; worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; options = (argc == 2) ? (EjsVar*) argv[1]: NULL; name = 0; search = ejs->ejsPath; if (options) { value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "search")); if (ejsIsString(value)) { search = ejsGetString(value); } value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "name")); if (ejsIsString(value)) { name = ejsGetString(value); } } if (name) { worker->name = mprStrdup(worker, name); } else { worker->name = mprAsprintf(worker, -1, "worker-%d", mprGetListCount(ejs->workers)); } /* * Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. */ wejs = ejsCreate(ejs->service, NULL, search, 0); if (wejs == 0) { ejsThrowMemoryError(ejs); return 0; } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = mprStrcat(self, -1, "inside-", worker->name, NULL); ejsSetProperty(ejs, (EjsVar*) worker, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(ejs, self->name)); ejsSetProperty(wejs, (EjsVar*) self, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(wejs, self->name)); ejsSetProperty(wejs, wejs->global, ES_ejs_sys_worker_self, (EjsVar*) self); /* * Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->globalBlock, 0, EJS_WORKER_NAMESPACE); /* * Make the inside worker permanent so we don't need to worry about whether worker->pair->ejs is valid */ self->obj.var.permanent = 1; if (argc > 0 && ejsIsPath(argv[0])) { addWorker(ejs, worker); worker->scriptFile = mprStrdup(worker, ((EjsPath*) argv[0])->path); worker->state = EJS_WORKER_STARTED; worker->obj.var.permanent = 1; if (mprStartWorker(ejs, (MprWorkerProc) workerMain, (void*) worker, MPR_NORMAL_PRIORITY) < 0) { ejsThrowStateError(ejs, "Can't start worker"); worker->obj.var.permanent = 0; return 0; } } return (EjsVar*) worker; }