/* If ME_CONFIG_FILE is defined, use that as the base name for appweb.conf. Otherwise, use "programName.conf". Search order is: "."/BASE ME_SERVER_ROOT/BASE EXE/../BASE EXE/../appweb.conf */ static int findAppwebConf() { char *base, *filename; if (ME_CONFIG_FILE) { base = sclone(ME_CONFIG_FILE); } else { base = mprJoinPathExt(mprGetAppName(), ".conf"); } #if !ME_ROM filename = base; if (!mprPathExists(filename, R_OK)) { filename = mprJoinPath(app->home, base); if (!mprPathExists(filename, R_OK)) { filename = mprJoinPath(mprGetPathParent(mprGetAppDir()), base); if (!mprPathExists(filename, R_OK)) { filename = mprJoinPath(mprGetPathParent(mprGetAppDir()), "appweb.conf"); if (!mprPathExists(filename, R_OK)) { mprError("Cannot find config file %s", base); return MPR_ERR_CANT_OPEN; } } } } #endif app->configFile = filename; return 0; }
PUBLIC int maSetPlatform(cchar *platformPath) { MaAppweb *appweb; MprDirEntry *dp; cchar *platform, *dir, *junk, *appwebExe; int next, i, notrace; appweb = MPR->appwebService; notrace = !platformPath; if (!platformPath) { platformPath = appweb->localPlatform; } appweb->platform = appweb->platformDir = 0; platform = mprGetPathBase(platformPath); if (mprPathExists(platformPath, X_OK) && mprIsPathDir(platformPath)) { appweb->platform = platform; appweb->platformDir = sclone(platformPath); } else if (smatch(platform, appweb->localPlatform)) { /* If running inside an appweb source tree, locate the platform directory */ appwebExe = mprJoinPath(mprGetAppDir(), "appweb" BIT_EXE); if (mprPathExists(appwebExe, R_OK)) { appweb->platform = appweb->localPlatform; appweb->platformDir = mprGetPathParent(mprGetAppDir()); } else { /* Check installed appweb */ appwebExe = BIT_VAPP_PREFIX "/bin/appweb" BIT_EXE; if (mprPathExists(appwebExe, R_OK)) { appweb->platform = appweb->localPlatform; appweb->platformDir = sclone(BIT_VAPP_PREFIX); } } } /* Last chance. Search up the tree for a similar platform directory. This permits specifying a partial platform like "vxworks" without architecture and profile. */ if (!appweb->platformDir) { dir = mprGetCurrentPath(); for (i = 0; !mprSamePath(dir, "/") && i < 64; i++) { for (ITERATE_ITEMS(mprGetPathFiles(dir, 0), dp, next)) { if (dp->isDir && sstarts(mprGetPathBase(dp->name), platform)) { appweb->platform = mprGetPathBase(dp->name); appweb->platformDir = mprJoinPath(dir, dp->name); break; } } dir = mprGetPathParent(dir); } }
/* Set the current working directory function chdir(value: String|Path): void */ static EjsObj *app_chdir(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { cchar *path; assert(argc == 1); if (ejsIs(ejs, argv[0], Path)) { path = ((EjsPath*) argv[0])->value; } else if (ejsIs(ejs, argv[0], String)) { path = ejsToMulti(ejs, argv[0]); } else { ejsThrowIOError(ejs, "Bad path"); return NULL; } #if WINDOWS { MprFileSystem *fs; fs = mprLookupFileSystem(path); if (!mprPathExists(path, X_OK) && *path == '/') { path = sjoin(fs->cygwin, path, NULL); } } #endif if (chdir((char*) path) < 0) { ejsThrowIOError(ejs, "Cannot change the current directory"); } return 0; }
/* 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 Edi *mdbOpen(cchar *source, int flags) { Mdb *mdb; if (flags & EDI_LITERAL) { flags |= EDI_NO_SAVE; if ((mdb = mdbCreate("literal", flags)) == 0) { return 0; } if (mdbLoadFromString((Edi*) mdb, source) < 0) { return 0; } } else { if (!mprPathExists(source, R_OK) && !(flags & EDI_CREATE)) { return 0; } if ((mdb = mdbCreate(source, flags)) == 0) { return 0; } if (mdbLoad((Edi*) mdb, source) < 0) { return 0; } } return (Edi*) mdb; }
/* Return true if the shared library in "file" can be found. Return the actual path in *path. The filename may not have a shared library extension which is typical so calling code can be cross platform. */ static char *probe(cchar *filename) { char *path; assert(filename && *filename); if (mprPathExists(filename, R_OK)) { return sclone(filename); } if (strstr(filename, ME_SHOBJ) == 0) { path = sjoin(filename, ME_SHOBJ, NULL); if (mprPathExists(path, R_OK)) { return path; } } return 0; }
static int process(EjsMod *mp, cchar *output, int argc, char **argv) { Ejs *ejs; EjsModule *module; MprFile *outfile; MprList *depends; int count, i, next, moduleCount; ejs = mp->ejs; if (output) { outfile = mprOpenFile(output, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0664); } else { outfile = 0; } ejs->loaderCallback = (mp->listing) ? emListingLoadCallback : 0; mp->firstGlobal = ejsGetLength(ejs, ejs->global); /* For each module on the command line */ for (i = 0; i < argc && !mp->fatalError; i++) { moduleCount = mprGetListLength(ejs->modules); ejs->loadData = mp; if (!mprPathExists(argv[i], R_OK)) { mprError("Can't access module %s", argv[i]); return EJS_ERR; } if ((ejsLoadModule(ejs, ejsCreateStringFromAsc(ejs, argv[i]), -1, -1, EJS_LOADER_NO_INIT)) < 0) { ejs->loaderCallback = NULL; mprError("Can't load module %s\n%s", argv[i], ejsGetErrorMsg(ejs, 0)); return EJS_ERR; } if (mp->genSlots) { for (next = moduleCount; (module = mprGetNextItem(ejs->modules, &next)) != 0; ) { emCreateSlotFiles(mp, module, outfile); } } if (mp->depends) { depends = mprCreateList(-1, 0); for (next = moduleCount; (module = mprGetNextItem(ejs->modules, &next)) != 0; ) { getDepends(ejs, depends, module); } count = mprGetListLength(depends); for (next = 1; (module = mprGetNextItem(depends, &next)) != 0; ) { int version = module->version; mprPrintf("%@-%d.%d.%d%s", module->name, EJS_MAJOR(version), EJS_MINOR(version), EJS_PATCH(version), (next >= count) ? "" : " "); } printf("\n"); } } if (mp->html || mp->xml) { emCreateDoc(mp); } mprCloseFile(outfile); return 0; }
static void setAppDefaults() { app->appName = mprGetAppName(); app->serviceProgram = sclone(SERVICE_PROGRAM); app->serviceName = sclone(SERVICE_NAME); app->serviceHome = mprGetNativePath(SERVICE_HOME); app->retries = RESTART_MAX; app->signal = SIGTERM; if (mprPathExists("/var/run", X_OK) && getuid() == 0) { app->pidDir = sclone("/var/run"); } else if (mprPathExists("/tmp", X_OK)) { app->pidDir = sclone("/tmp"); } else if (mprPathExists("/Temp", X_OK)) { app->pidDir = sclone("/Temp"); } else { app->pidDir = sclone("."); } }
static int findConfig() { char *base, *filename; base = sclone("http.json"); filename = base; if (!mprPathExists(filename, R_OK)) { filename = mprJoinPath(mprGetPathParent(mprGetAppDir()), base); if (!mprPathExists(filename, R_OK)) { filename = mprJoinPath(mprGetPathParent(mprGetAppDir()), base); if (!mprPathExists(filename, R_OK)) { mprError("Cannot find config file %s", base); return MPR_ERR_CANT_OPEN; } } } app->configFile = filename; return 0; }
static void testTemp(MprTestGroup *gp) { char *path; path = mprGetTempPath(NULL); assert(path && *path); assert(mprIsPathAbs(path)); assert(mprPathExists(path, F_OK)); mprDeletePath(path); }
static void testCopyPath(MprTestGroup *gp) { MprFile *file; char *from, *to; from = sfmt("copyTest-%s.tmp", mprGetCurrentThreadName(gp)); assert(from != 0); file = mprOpenFile(from, O_CREAT | O_TRUNC | O_WRONLY, 0664); assert(file != 0); mprWriteFileString(file, "Hello World"); mprCloseFile(file); to = sfmt("newTest-%s.tmp", mprGetCurrentThreadName(gp)); assert(mprPathExists(from, F_OK)); mprCopyPath(from, to, 0664); assert(mprPathExists(to, F_OK)); mprDeletePath(from); mprDeletePath(to); }
/* Return true if the shared library in "file" can be found. Return the actual path in *path. The filename may not have a shared library extension which is typical so calling code can be cross platform. */ static char *probe(cchar *filename) { char *path; mprAssert(filename && *filename); mprLog(7, "Probe for native module %s", filename); if (mprPathExists(filename, R_OK)) { return sclone(filename); } if (strstr(filename, BIT_SHOBJ) == 0) { path = sjoin(filename, BIT_SHOBJ, NULL); mprLog(7, "Probe for native module %s", path); if (mprPathExists(path, R_OK)) { return path; } } return 0; }
static bool exists(cchar *fmt, ...) { va_list args; cchar *path; bool rc; va_start(args, fmt); path = sfmtv(fmt, args); rc = mprPathExists(path, F_OK); va_end(args); return rc; }
/* 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 int findConfigFile() { cchar *userPath; userPath = app->configFile; if (app->configFile == 0) { app->configFile = mprJoinPathExt(mprGetAppName(), ".conf"); } if (!mprPathExists(app->configFile, R_OK)) { if (!userPath) { app->configFile = mprJoinPath(app->home, "appweb.conf"); if (!mprPathExists(app->configFile, R_OK)) { app->configFile = mprJoinPath(mprGetAppDir(), sfmt("../%s/%s.conf", BLD_LIB_NAME, mprGetAppName())); } } if (!mprPathExists(app->configFile, R_OK)) { mprError("Can't open config file %s", app->configFile); return MPR_ERR_CANT_OPEN; } } return 0; }
static int findAppwebConf() { cchar *userPath; userPath = app->configFile; if (!app->configFile || *app->configFile == '\0') { app->configFile = mprJoinPathExt(mprGetAppName(), ".conf"); } #if !BIT_ROM if (!mprPathExists(app->configFile, R_OK)) { if (!userPath) { app->configFile = mprJoinPath(app->home, "appweb.conf"); if (!mprPathExists(app->configFile, R_OK)) { app->configFile = mprJoinPath(mprGetAppDir(), sfmt("%s.conf", mprGetAppName())); } } if (!mprPathExists(app->configFile, R_OK)) { mprError("Cannot open config file %s", app->configFile); return MPR_ERR_CANT_OPEN; } } #endif return 0; }
/* * Set the Server Root directory. We convert path into an absolute path. */ void maSetServerRoot(MaServer *server, cchar *path) { if (path == 0 || BLD_FEATURE_ROMFS) { path = "."; } #if !VXWORKS /* * VxWorks stat() is broken if using a network FTP server. */ if (! mprPathExists(server, path, R_OK)) { mprError(server, "Can't access ServerRoot directory %s", path); return; } #endif mprFree(server->serverRoot); server->serverRoot = mprGetAbsPath(server, path); }
/* Set the home directory (Server Root). We convert path into an absolute path. */ void maSetServerHome(MaServer *server, cchar *path) { if (path == 0 || BLD_FEATURE_ROMFS) { path = "."; } #if !VXWORKS /* VxWorks stat() is broken if using a network FTP server. */ if (! mprPathExists(path, R_OK)) { mprError("Can't access ServerRoot directory %s", path); return; } #endif server->home = mprGetAbsPath(path); mprLog(MPR_CONFIG, "Set server root to: \"%s\"", server->home); }
/* Write upload data. This routine blocks. If you need non-blocking ... cut and paste. */ PUBLIC ssize httpWriteUploadData(HttpConn *conn, MprList *fileData, MprList *formData) { char *path, *pair, *key, *value, *name; cchar *type; ssize rc; int next; rc = 0; if (formData) { for (rc = next = 0; rc >= 0 && (pair = mprGetNextItem(formData, &next)) != 0; ) { key = ssplit(sclone(pair), "=", &value); rc += httpWrite(conn->writeq, "%s\r\nContent-Disposition: form-data; name=\"%s\";\r\n", conn->boundary, key); rc += httpWrite(conn->writeq, "Content-Type: application/x-www-form-urlencoded\r\n\r\n%s\r\n", value); } } if (fileData) { for (rc = next = 0; rc >= 0 && (path = mprGetNextItem(fileData, &next)) != 0; ) { if (!mprPathExists(path, R_OK)) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot open %s", path); return MPR_ERR_CANT_OPEN; } name = mprGetPathBase(path); rc += httpWrite(conn->writeq, "%s\r\nContent-Disposition: form-data; name=\"file%d\"; filename=\"%s\"\r\n", conn->boundary, next - 1, name); if ((type = mprLookupMime(MPR->mimeTypes, path)) != 0) { rc += httpWrite(conn->writeq, "Content-Type: %s\r\n", mprLookupMime(MPR->mimeTypes, path)); } httpWrite(conn->writeq, "\r\n"); if (blockingFileCopy(conn, path) < 0) { return MPR_ERR_CANT_WRITE; } rc += httpWrite(conn->writeq, "\r\n"); } } rc += httpWrite(conn->writeq, "%s--\r\n--", conn->boundary); return rc; }
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; }
/* 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; }
/* 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 }
static int parseArgs(int argc, char **argv) { char *argp, *key, *value; int i, setWorkers, nextArg, ssl; setWorkers = 0; ssl = 0; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--auth")) { if (nextArg >= argc) { return showUsage(); } else { app->authType = slower(argv[++nextArg]); } } else if (smatch(argp, "--benchmark") || smatch(argp, "-b")) { app->benchmark++; } else if (smatch(argp, "--ca")) { if (nextArg >= argc) { return showUsage(); } else { app->ca = sclone(argv[++nextArg]); if (!mprPathExists(app->ca, R_OK)) { mprError("Cannot find ca file %s", app->ca); return MPR_ERR_BAD_ARGS; } } ssl = 1; } else if (smatch(argp, "--cert")) { if (nextArg >= argc) { return showUsage(); } else { app->cert = sclone(argv[++nextArg]); if (!mprPathExists(app->cert, R_OK)) { mprError("Cannot find cert file %s", app->cert); return MPR_ERR_BAD_ARGS; } } ssl = 1; } else if (smatch(argp, "--chunk")) { if (nextArg >= argc) { return showUsage(); } else { value = argv[++nextArg]; app->chunkSize = atoi(value); if (app->chunkSize < 0) { mprError("Bad chunksize %d", app->chunkSize); return MPR_ERR_BAD_ARGS; } } } else if (smatch(argp, "--ciphers")) { if (nextArg >= argc) { return showUsage(); } else { app->ciphers = sclone(argv[++nextArg]); } ssl = 1; } else if (smatch(argp, "--continue") || smatch(argp, "-c")) { app->continueOnErrors++; } else if (smatch(argp, "--cookie")) { if (nextArg >= argc) { return showUsage(); } else { mprAddItem(app->headers, mprCreateKeyPair("Cookie", argv[++nextArg], 0)); } } else if (smatch(argp, "--data")) { if (nextArg >= argc) { return showUsage(); } else { if (app->bodyData == 0) { app->bodyData = mprCreateBuf(-1, -1); } mprPutStringToBuf(app->bodyData, argv[++nextArg]); } } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); app->retries = 0; app->timeout = MAXINT; } else if (smatch(argp, "--delete")) { app->method = "DELETE"; } else if (smatch(argp, "--form") || smatch(argp, "-f")) { if (nextArg >= argc) { return showUsage(); } else { if (app->formData == 0) { app->formData = mprCreateList(-1, 0); } addFormVars(argv[++nextArg]); } } else if (smatch(argp, "--header")) { if (nextArg >= argc) { return showUsage(); } else { key = argv[++nextArg]; if ((value = strchr(key, ':')) == 0) { mprError("Bad header format. Must be \"key: value\""); return MPR_ERR_BAD_ARGS; } *value++ = '\0'; while (isspace((uchar) *value)) { value++; } mprAddItem(app->headers, mprCreateKeyPair(key, value, 0)); } } else if (smatch(argp, "--host")) { if (nextArg >= argc) { return showUsage(); } else { app->host = argv[++nextArg]; if (*app->host == ':') { app->host = &app->host[1]; } if (isPort(app->host)) { app->host = sfmt("http://127.0.0.1:%s", app->host); } else { app->host = sclone(app->host); } } } else if (smatch(argp, "--iterations") || smatch(argp, "-i")) { if (nextArg >= argc) { return showUsage(); } else { app->iterations = atoi(argv[++nextArg]); } } else if (smatch(argp, "--key")) { if (nextArg >= argc) { return showUsage(); } else { app->key = sclone(argv[++nextArg]); if (!mprPathExists(app->key, R_OK)) { mprError("Cannot find key file %s", app->key); return MPR_ERR_BAD_ARGS; } } ssl = 1; } else if (smatch(argp, "--log") || smatch(argp, "-l")) { if (nextArg >= argc) { return showUsage(); } else { mprStartLogging(argv[++nextArg], 0); } } else if (smatch(argp, "--method") || smatch(argp, "-m")) { if (nextArg >= argc) { return showUsage(); } else { app->method = argv[++nextArg]; } } else if (smatch(argp, "--out") || smatch(argp, "-o")) { if (nextArg >= argc) { return showUsage(); } else { app->outFilename = sclone(argv[++nextArg]); } } else if (smatch(argp, "--noout") || smatch(argp, "-n") || smatch(argp, "--quiet") || smatch(argp, "-q")) { app->noout++; } else if (smatch(argp, "--nofollow")) { app->nofollow++; } else if (smatch(argp, "--password") || smatch(argp, "-p")) { if (nextArg >= argc) { return showUsage(); } else { app->password = sclone(argv[++nextArg]); } } else if (smatch(argp, "--post")) { app->method = "POST"; } else if (smatch(argp, "--printable")) { app->printable++; } else if (smatch(argp, "--protocol")) { if (nextArg >= argc) { return showUsage(); } else { app->protocol = supper(argv[++nextArg]); } } else if (smatch(argp, "--provider")) { /* Undocumented SSL provider selection */ if (nextArg >= argc) { return showUsage(); } else { app->provider = sclone(argv[++nextArg]); } ssl = 1; } else if (smatch(argp, "--put")) { app->method = "PUT"; } else if (smatch(argp, "--range")) { if (nextArg >= argc) { return showUsage(); } else { if (app->ranges == 0) { app->ranges = sfmt("bytes=%s", argv[++nextArg]); } else { app->ranges = srejoin(app->ranges, ",", argv[++nextArg], NULL); } } } else if (smatch(argp, "--retries") || smatch(argp, "-r")) { if (nextArg >= argc) { return showUsage(); } else { app->retries = atoi(argv[++nextArg]); } } else if (smatch(argp, "--self")) { /* Undocumented. Allow self-signed certs. Users should just not set --verify */ app->verifyIssuer = 0; ssl = 1; } else if (smatch(argp, "--sequence")) { app->sequence++; } else if (smatch(argp, "--showHeaders") || smatch(argp, "--show") || smatch(argp, "-s")) { app->showHeaders++; } else if (smatch(argp, "--showStatus") || smatch(argp, "--showCode")) { app->showStatus++; } else if (smatch(argp, "--single") || smatch(argp, "-s")) { app->singleStep++; } else if (smatch(argp, "--text")) { app->text++; } else if (smatch(argp, "--threads") || smatch(argp, "-t")) { if (nextArg >= argc) { return showUsage(); } else { app->loadThreads = atoi(argv[++nextArg]); } } else if (smatch(argp, "--timeout")) { if (nextArg >= argc) { return showUsage(); } else { app->timeout = atoi(argv[++nextArg]) * MPR_TICKS_PER_SEC; } } else if (smatch(argp, "--upload") || smatch(argp, "-u")) { app->upload++; } else if (smatch(argp, "--user") || smatch(argp, "--username")) { if (nextArg >= argc) { return showUsage(); } else { app->username = argv[++nextArg]; } // DEPRECATE validate. Preserve verify. } else if (smatch(argp, "--validate") || smatch(argp, "--verify")) { app->verifyPeer = 1; ssl = 1; } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { app->verbose++; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprEprintf("%s %s\n" "Copyright (C) Embedthis Software 2003-2013\n" "Copyright (C) Michael O'Brien 2003-2013\n", BIT_TITLE, BIT_VERSION); exit(0); } else if (smatch(argp, "--workerTheads") || smatch(argp, "-w")) { if (nextArg >= argc) { return showUsage(); } else { app->workers = atoi(argv[++nextArg]); } setWorkers++; } else if (smatch(argp, "--zero")) { app->zeroOnErrors++; } else if (smatch(argp, "--")) { nextArg++; break; } else if (smatch(argp, "-")) { break; } else { return showUsage(); } } if (argc == nextArg) { return showUsage(); } app->nextArg = nextArg; argc = argc - nextArg; argv = &argv[nextArg]; app->target = argv[argc - 1]; if (--argc > 0) { /* Files present on command line */ app->files = mprCreateList(argc, MPR_LIST_STATIC_VALUES); for (i = 0; i < argc; i++) { mprAddItem(app->files, argv[i]); } } if (!setWorkers) { app->workers = app->loadThreads + 2; } if (app->method == 0) { if (app->bodyData || app->formData || app->upload) { app->method = "POST"; } else if (app->files) { app->method = "PUT"; } else { app->method = "GET"; } } #if BIT_PACK_SSL { HttpUri *uri = httpCreateUri(app->target, 0); if (uri->secure || ssl) { app->ssl = mprCreateSsl(0); if (app->provider) { mprSetSslProvider(app->ssl, app->provider); } if (app->cert) { if (!app->key) { mprError("Must specify key file"); return 0; } mprSetSslCertFile(app->ssl, app->cert); mprSetSslKeyFile(app->ssl, app->key); } if (app->ca) { mprLog(4, "Using CA: \"%s\"", app->ca); mprSetSslCaFile(app->ssl, app->ca); } if (app->verifyIssuer == -1) { app->verifyIssuer = app->verifyPeer ? 1 : 0; } mprVerifySslPeer(app->ssl, app->verifyPeer); mprVerifySslIssuer(app->ssl, app->verifyIssuer); if (app->ciphers) { mprSetSslCiphers(app->ssl, app->ciphers); } } else { mprVerifySslPeer(NULL, 0); } } #else /* Suppress comp warning */ mprNop(&ssl); #endif return 0; }
/* Compile a view or controller cacheName MD5 cache name (not a full path) source ESP source file name module Module file name */ bool espCompile(HttpConn *conn, cchar *source, cchar *module, cchar *cacheName, int isView) { MprFile *fp; HttpRx *rx; HttpRoute *route; EspRoute *eroute; cchar *csource; char *layout, *script, *page, *err; ssize len; rx = conn->rx; route = rx->route; eroute = route->eroute; layout = 0; if (isView) { if ((page = mprReadPathContents(source, &len)) == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't read %s", source); return 0; } /* Use layouts iff there is a source defined on the route. Only MVC/controllers based apps do this. */ if (eroute->layoutsDir) { #if UNUSED layout = mprSamePath(eroute->layoutsDir, route->dir) ? 0 : mprJoinPath(eroute->layoutsDir, "default.esp"); #else layout = mprJoinPath(eroute->layoutsDir, "default.esp"); #endif } if ((script = espBuildScript(route, page, source, cacheName, layout, &err)) == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't build %s, error %s", source, err); return 0; } csource = mprJoinPathExt(mprTrimPathExt(module), ".c"); if ((fp = mprOpenFile(csource, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0664)) == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't open compiled script file %s", csource); return 0; } len = slen(script); if (mprWriteFile(fp, script, len) != len) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't write compiled script file %s", csource); mprCloseFile(fp); return 0; } mprCloseFile(fp); } else { csource = source; } mprMakeDir(eroute->cacheDir, 0775, -1, -1, 1); /* WARNING: GC yield here */ if (runCommand(conn, eroute->compile, csource, module) < 0) { return 0; } if (eroute->link) { /* WARNING: GC yield here */ if (runCommand(conn, eroute->link, csource, module) < 0) { return 0; } #if !(BLD_DEBUG && MACOSX) /* MAC needs the object for debug information */ mprDeletePath(mprJoinPathExt(mprTrimPathExt(module), BLD_OBJ)); #endif } #if BLD_WIN_LIKE { /* Windows leaves intermediate object in the current directory */ cchar *obj; obj = mprReplacePathExt(mprGetPathBase(csource), BLD_OBJ); if (mprPathExists(obj, F_OK)) { mprDeletePath(obj); } } #endif if (!eroute->keepSource && isView) { mprDeletePath(csource); } return 1; }
/* <% stylesheets(patterns); %> Where patterns may contain *, ** and !pattern for exclusion */ PUBLIC void stylesheets(cchar *patterns) { HttpStream *stream; HttpRx *rx; HttpRoute *route; EspRoute *eroute; MprList *files; cchar *filename, *ext, *uri, *path, *kind, *version, *clientDir; int next; stream = getStream(); rx = stream->rx; route = rx->route; eroute = route->eroute; patterns = httpExpandRouteVars(route, patterns); clientDir = httpGetDir(route, "documents"); if (!patterns || !*patterns) { version = espGetConfig(route, "version", "1.0.0"); if (eroute->combineSheet) { /* Previously computed combined stylesheet filename */ stylesheets(eroute->combineSheet); } else if (espGetConfig(route, "http.content.combine[@=css]", 0)) { if (espGetConfig(route, "http.content.minify[@=css]", 0)) { eroute->combineSheet = sfmt("css/all-%s.min.css", version); } else { eroute->combineSheet = sfmt("css/all-%s.css", version); } stylesheets(eroute->combineSheet); } else { /* Not combining into a single stylesheet, so give priority to all.less over all.css if present Load a pure CSS incase some styles need to be applied before the lesssheet is parsed */ ext = espGetConfig(route, "http.content.stylesheets", "css"); filename = mprJoinPathExt("css/all", ext); path = mprJoinPath(clientDir, filename); if (mprPathExists(path, R_OK)) { stylesheets(filename); } else if (!smatch(ext, "less")) { path = mprJoinPath(clientDir, "css/all.less"); if (mprPathExists(path, R_OK)) { stylesheets("css/all.less"); } } } } else { if (sends(patterns, "all.less")) { path = mprJoinPath(clientDir, "css/fix.css"); if (mprPathExists(path, R_OK)) { stylesheets("css/fix.css"); } } if ((files = mprGlobPathFiles(clientDir, patterns, MPR_PATH_RELATIVE)) == 0 || mprGetListLength(files) == 0) { files = mprCreateList(0, 0); mprAddItem(files, patterns); } for (ITERATE_ITEMS(files, path, next)) { path = sjoin("~/", strim(path, ".gz", MPR_TRIM_END), NULL); uri = httpLink(stream, path); kind = mprGetPathExt(path); if (smatch(kind, "css")) { espRender(stream, "<link rel='stylesheet' type='text/css' href='%s' />\n", uri); } else { espRender(stream, "<link rel='stylesheet/%s' type='text/css' href='%s' />\n", kind, uri); } } } }
/* 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; }
/* Test if the request matches. This may delegate the request to the dirHandler if a directory listing is required. */ static int matchFileHandler(HttpConn *conn, HttpRoute *route, int dir) { HttpRx *rx; HttpTx *tx; HttpUri *prior; MprPath *info, zipInfo; cchar *index; char *path, *pathInfo, *uri, *zipfile; int next; printf("\n matchFileHandler \n"); rx = conn->rx; tx = conn->tx; rx = conn->rx; prior = rx->parsedUri; info = &tx->fileInfo; httpMapFile(conn, route); assure(info->checked); if (rx->flags & (HTTP_DELETE | HTTP_PUT)) { return HTTP_ROUTE_OK; } if (info->isDir) { /* Manage requests for directories */ if (!sends(rx->pathInfo, "/")) { /* Append "/" and do an external redirect */ pathInfo = sjoin(rx->pathInfo, "/", NULL); uri = httpFormatUri(prior->scheme, prior->host, prior->port, pathInfo, prior->reference, prior->query, 0); httpRedirect(conn, HTTP_CODE_MOVED_PERMANENTLY, uri); return HTTP_ROUTE_OK; } if (route->indicies) { /* Ends with a "/" so do internal redirection to an index file */ for (ITERATE_ITEMS(route->indicies, index, next)) { /* Internal directory redirections. Transparently append index. Test indicies in order. */ path = mprJoinPath(tx->filename, index); if (mprPathExists(path, R_OK)) { pathInfo = sjoin(rx->scriptName, rx->pathInfo, index, NULL); uri = httpFormatUri(prior->scheme, prior->host, prior->port, pathInfo, prior->reference, prior->query, 0); httpSetUri(conn, uri); tx->filename = path; tx->ext = httpGetExt(conn); mprGetPathInfo(tx->filename, info); return HTTP_ROUTE_REROUTE; } } } /* If a directory, test if a directory listing should be rendered. If so, delegate to the dirHandler. Cannot use the sendFile handler and must use the netConnector. */ if (info->isDir && maRenderDirListing(conn)) { tx->handler = conn->http->dirHandler; tx->connector = conn->http->netConnector; return HTTP_ROUTE_OK; } } if (!info->valid && (route->flags & HTTP_ROUTE_GZIP) && rx->acceptEncoding && strstr(rx->acceptEncoding, "gzip") != 0) { /* If the route accepts zipped data and a zipped file exists, then transparently respond with it. */ zipfile = sfmt("%s.gz", tx->filename); if (mprGetPathInfo(zipfile, &zipInfo) == 0) { tx->filename = zipfile; tx->fileInfo = zipInfo; httpSetHeader(conn, "Content-Encoding", "gzip"); } } if (rx->flags & (HTTP_GET | HTTP_HEAD | HTTP_POST) && info->valid && !info->isDir && tx->length < 0) { /* The sendFile connector is optimized on some platforms to use the sendfile() system call. Set the entity length for the sendFile connector to utilize. */ httpSetEntityLength(conn, tx->fileInfo.size); } printf("\n-------------------------\n"); printf("tx->filename:\t%s",tx->filename); printf("\n-------------------------\n"); return HTTP_ROUTE_OK; }
/* Expecting content headers. A blank line indicates the start of the data. Returns < 0 Request or state error Returns == 0 Successfully parsed the input line. */ static int processUploadHeader(HttpQueue *q, char *line) { HttpConn *conn; HttpRx *rx; HttpUploadFile *file; Upload *up; cchar *uploadDir; char *key, *headerTok, *rest, *nextPair, *value; conn = q->conn; rx = conn->rx; up = q->queueData; if (line[0] == '\0') { up->contentState = HTTP_UPLOAD_CONTENT_DATA; return 0; } headerTok = line; stok(line, ": ", &rest); if (scaselesscmp(headerTok, "Content-Disposition") == 0) { /* The content disposition header describes either a form variable or an uploaded file. Content-Disposition: form-data; name="field1" >>blank line Field Data ---boundary Content-Disposition: form-data; name="field1" -> filename="user.file" >>blank line File data ---boundary */ key = rest; up->name = up->clientFilename = 0; while (key && stok(key, ";\r\n", &nextPair)) { key = strim(key, " ", MPR_TRIM_BOTH); stok(key, "= ", &value); value = strim(value, "\"", MPR_TRIM_BOTH); if (scaselesscmp(key, "form-data") == 0) { /* Nothing to do */ } else if (scaselesscmp(key, "name") == 0) { up->name = sclone(value); } else if (scaselesscmp(key, "filename") == 0) { if (up->name == 0) { httpError(conn, HTTP_CODE_BAD_REQUEST, "Bad upload state. Missing name field"); return MPR_ERR_BAD_STATE; } /* Client filenames must be simple filenames without illegal characters or path separators. We are deliberately restrictive here to assist users that may use the clientFilename in shell scripts. They MUST still sanitize for their environment, but some extra caution is worthwhile. */ value = mprNormalizePath(value); if (*value == '.' || !httpValidUriChars(value) || strpbrk(value, "\\/:*?<>|~\"'%`^\n\r\t\f")) { httpError(conn, HTTP_CODE_BAD_REQUEST, "Bad upload client filename."); return MPR_ERR_BAD_STATE; } up->clientFilename = sclone(value); /* Create the file to hold the uploaded data */ uploadDir = getUploadDir(rx->route); up->tmpPath = mprGetTempPath(uploadDir); if (up->tmpPath == 0) { if (!mprPathExists(uploadDir, X_OK)) { mprLog("http error", 0, "Cannot access upload directory %s", uploadDir); } httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot create upload temp file %s. Check upload temp dir %s", up->tmpPath, uploadDir); return MPR_ERR_CANT_OPEN; } httpTrace(conn, "request.upload.file", "context", "clientFilename:'%s',filename:'%s'", up->clientFilename, up->tmpPath); up->file = mprOpenFile(up->tmpPath, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600); if (up->file == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot open upload temp file %s", up->tmpPath); return MPR_ERR_BAD_STATE; } /* Create the files[id] */ file = up->currentFile = mprAllocObj(HttpUploadFile, manageHttpUploadFile); file->clientFilename = up->clientFilename; file->filename = up->tmpPath; file->name = up->name; addUploadFile(conn, file); } key = nextPair; } } else if (scaselesscmp(headerTok, "Content-Type") == 0) { if (up->clientFilename) { up->currentFile->contentType = sclone(rest); } } return 0; }
/* Configure the server. If the configFile is defined, use it. If not, then consider home, documents, ip and port. */ int maConfigureServer(MaServer *server, cchar *configFile, cchar *home, cchar *documents, cchar *ip, int port) { MaAppweb *appweb; Http *http; HttpEndpoint *endpoint; HttpHost *host; HttpRoute *route; char *path; appweb = server->appweb; http = appweb->http; if (configFile) { path = mprGetAbsPath(configFile); if (maParseConfig(server, path, 0) < 0) { /* mprUserError("Can't configure server using %s", path); */ return MPR_ERR_CANT_INITIALIZE; } return 0; } else { mprLog(2, "DocumentRoot %s", documents); if ((endpoint = httpCreateConfiguredEndpoint(home, documents, ip, port)) == 0) { return MPR_ERR_CANT_OPEN; } maAddEndpoint(server, endpoint); host = mprGetFirstItem(endpoint->hosts); mprAssert(host); route = mprGetFirstItem(host->routes); mprAssert(route); #if UNUSED searchPath = getSearchPath(dir); mprSetModuleSearchPath(searchPath); #endif #if BLD_FEATURE_CGI maLoadModule(appweb, "cgiHandler", "mod_cgi"); if (httpLookupStage(http, "cgiHandler")) { httpAddRouteHandler(route, "cgiHandler", "cgi cgi-nph bat cmd pl py"); /* Add cgi-bin with a route for the /cgi-bin URL prefix. */ path = "cgi-bin"; if (mprPathExists(path, X_OK)) { HttpRoute *cgiRoute; cgiRoute = httpCreateAliasRoute(route, "/cgi-bin/", path, 0); mprLog(4, "ScriptAlias \"/cgi-bin/\":\"%s\"", path); httpSetRouteHandler(cgiRoute, "cgiHandler"); httpFinalizeRoute(cgiRoute); } } #endif #if BLD_FEATURE_ESP maLoadModule(appweb, "espHandler", "mod_esp"); if (httpLookupStage(http, "espHandler")) { httpAddRouteHandler(route, "espHandler", "esp"); } #endif #if BLD_FEATURE_EJSCRIPT maLoadModule(appweb, "ejsHandler", "mod_ejs"); if (httpLookupStage(http, "ejsHandler")) { httpAddRouteHandler(route, "ejsHandler", "ejs"); } #endif #if BLD_FEATURE_PHP maLoadModule(appweb, "phpHandler", "mod_php"); if (httpLookupStage(http, "phpHandler")) { httpAddRouteHandler(route, "phpHandler", "php"); } #endif httpAddRouteHandler(route, "fileHandler", ""); httpFinalizeRoute(route); } if (home) { maSetServerHome(server, home); } if (ip || port > 0) { maSetServerAddress(server, ip, port); } return 0; }
/* 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; }