/* The base procedure is invoked prior to calling any and all actions on this route */ PUBLIC void espDefineBase(HttpRoute *route, EspProc baseProc) { HttpRoute *rp; EspRoute *eroute; int next; for (ITERATE_ITEMS(route->host->routes, rp, next)) { if ((eroute = route->eroute) != 0) { if (smatch(httpGetDir(rp, "CONTROLLERS"), httpGetDir(route, "CONTROLLERS"))) { eroute->commonController = baseProc; } } } }
/* Check if the layout has changed. Returns false if the layout does not exist. */ static bool layoutIsStale(EspRoute *eroute, cchar *source, cchar *module) { char *data, *lpath, *quote; cchar *layout, *layoutsDir; ssize len; bool stale; int recompile; stale = 0; layoutsDir = httpGetDir(eroute->route, "LAYOUTS"); if ((data = mprReadPathContents(source, &len)) != 0) { if ((lpath = scontains(data, "@ layout \"")) != 0) { lpath = strim(&lpath[10], " ", MPR_TRIM_BOTH); if ((quote = schr(lpath, '"')) != 0) { *quote = '\0'; } layout = (layoutsDir && *lpath) ? mprJoinPath(layoutsDir, lpath) : 0; } else { layout = (layoutsDir) ? mprJoinPath(layoutsDir, "default.esp") : 0; } if (layout) { stale = espModuleIsStale(layout, module, &recompile); if (stale) { mprLog("info esp", 4, "esp layout %s is newer than module %s", layout, module); } } } return stale; }
static cchar *getUploadDir(HttpRoute *route) { cchar *uploadDir; if ((uploadDir = httpGetDir(route, "upload")) == 0) { #if ME_WIN_LIKE uploadDir = mprNormalizePath(getenv("TEMP")); #else uploadDir = sclone("/tmp"); #endif } return uploadDir; }
/* <% 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); } } } }
/* WARNING: may yield */ PUBLIC int espLoadConfig(HttpRoute *route) { EspRoute *eroute; cchar *name, *package; bool modified; eroute = route->eroute; if (!route->update) { return 0; } package = mprJoinPath(mprGetPathDir(eroute->configFile), "package.json"); modified = 0; ifConfigModified(route, eroute->configFile, &modified); ifConfigModified(route, package, &modified); if (modified) { lock(esp); httpInitConfig(route); #if DEPRECATED || 1 /* Don't reload if configFile == package.json */ if (!mprSamePath(package, eroute->configFile)) { #endif if (mprPathExists(package, R_OK)) { if (httpLoadConfig(route, package) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } } } if (httpLoadConfig(route, eroute->configFile) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } if ((name = espGetConfig(route, "name", 0)) != 0) { eroute->appName = name; } if (espLoadCompilerRules(route) < 0) { return MPR_ERR_CANT_OPEN; } unlock(esp); } if (!route->cookie) { httpSetRouteCookie(route, sfmt("esp-%s", eroute->appName)); } if (route->database && !eroute->edi) { if (espOpenDatabase(route, route->database) < 0) { mprLog("error esp", 0, "Cannot open database %s", route->database); return MPR_ERR_CANT_LOAD; } } #if !ME_STATIC if (!(route->flags & HTTP_ROUTE_NO_LISTEN)) { MprJson *preload, *item; cchar *errMsg, *source; char *kind; int i; /* WARNING: may yield when compiling modules */ if (eroute->combine) { source = mprJoinPaths(route->home, httpGetDir(route, "CACHE"), sfmt("%s.c", eroute->appName), NULL); } else { source = mprJoinPaths(route->home, httpGetDir(route, "SRC"), "app.c", NULL); } lock(esp); if (espLoadModule(route, NULL, "app", source, &errMsg) < 0) { if (eroute->combine) { mprLog("error esp", 0, "%s", errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } if (!eroute->combine && (preload = mprGetJsonObj(route->config, "esp.preload")) != 0) { for (ITERATE_JSON(preload, item, i)) { source = ssplit(sclone(item->value), ":", &kind); if (*kind == '\0') { kind = "controller"; } source = mprJoinPaths(route->home, httpGetDir(route, "CONTROLLERS"), source, NULL); if (espLoadModule(route, NULL, kind, source, &errMsg) < 0) { mprLog("error esp", 0, "Cannot preload esp module %s. %s", source, errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } } unlock(esp); }
/* WARNING: GC yield */ PUBLIC int espLoadModule(HttpRoute *route, MprDispatcher *dispatcher, cchar *kind, cchar *source, cchar **errMsg) { EspRoute *eroute; MprModule *mp; cchar *appName, *cache, *cacheName, *canonical, *entry, *module; int isView, recompile; eroute = route->eroute; *errMsg = ""; #if VXWORKS /* Trim the drive for VxWorks where simulated host drives only exist on the target */ source = mprTrimPathDrive(source); #endif canonical = mprGetPortablePath(mprGetRelPath(source, route->home)); appName = eroute->appName; if (eroute->combine) { cacheName = appName; } else { cacheName = mprGetMD5WithPrefix(sfmt("%s:%s", appName, canonical), -1, sjoin(kind, "_", NULL)); } if ((cache = httpGetDir(route, "CACHE")) == 0) { cache = "cache"; } module = mprJoinPathExt(mprJoinPaths(route->home, cache, cacheName, NULL), ME_SHOBJ); lock(esp); if (route->update) { if (mprPathExists(source, R_OK)) { isView = smatch(kind, "view"); if (espModuleIsStale(source, module, &recompile) || (isView && layoutIsStale(eroute, source, module))) { if (recompile) { mprHoldBlocks(source, module, cacheName, NULL); if (!espCompile(route, dispatcher, source, module, cacheName, isView, (char**) errMsg)) { mprReleaseBlocks(source, module, cacheName, NULL); unlock(esp); return MPR_ERR_CANT_WRITE; } mprReleaseBlocks(source, module, cacheName, NULL); } } } } if (mprLookupModule(source) == 0) { if (!mprPathExists(module, R_OK)) { *errMsg = "Module does not exist"; unlock(esp); return MPR_ERR_CANT_FIND; } entry = getModuleEntry(eroute, kind, source, cacheName); if ((mp = mprCreateModule(source, module, entry, route)) == 0) { *errMsg = "Memory allocation error loading module"; unlock(esp); return MPR_ERR_MEMORY; } if (mprLoadModule(mp) < 0) { *errMsg = "Cannot load compiled esp module"; unlock(esp); return MPR_ERR_CANT_READ; } } unlock(esp); return 0; }
/* Run an action (may yield) */ static int runAction(HttpConn *conn) { HttpRx *rx; HttpRoute *route; EspRoute *eroute; EspReq *req; EspAction action; rx = conn->rx; req = conn->reqData; route = rx->route; eroute = route->eroute; assert(eroute); if (eroute->edi && eroute->edi->flags & EDI_PRIVATE) { cloneDatabase(conn); } else { req->edi = eroute->edi; } if (route->sourceName == 0 || *route->sourceName == '\0') { if (eroute->commonController) { (eroute->commonController)(conn); } return 1; } #if !ME_STATIC if (!eroute->combine && (route->update || !mprLookupKey(eroute->actions, rx->target))) { cchar *errMsg, *controllers, *controller; if ((controllers = httpGetDir(route, "CONTROLLERS")) == 0) { controllers = "."; } controllers = mprJoinPath(route->home, controllers); controller = schr(route->sourceName, '$') ? stemplateJson(route->sourceName, rx->params) : route->sourceName; controller = controllers ? mprJoinPath(controllers, controller) : mprJoinPath(route->home, controller); if (espLoadModule(route, conn->dispatcher, "controller", controller, &errMsg) < 0) { if (mprPathExists(controller, R_OK)) { httpError(conn, HTTP_CODE_NOT_FOUND, "%s", errMsg); return 0; } } } #endif /* !ME_STATIC */ assert(eroute->top); action = mprLookupKey(eroute->top->actions, rx->target); if (route->flags & HTTP_ROUTE_XSRF && !(rx->flags & HTTP_GET)) { if (!httpCheckSecurityToken(conn)) { httpSetStatus(conn, HTTP_CODE_UNAUTHORIZED); if (smatch(route->responseFormat, "json")) { httpTrace(conn, "esp.xsrf.error", "error", 0); espRenderString(conn, "{\"retry\": true, \"success\": 0, \"feedback\": {\"error\": \"Security token is stale. Please retry.\"}}"); espFinalize(conn); } else { httpError(conn, HTTP_CODE_UNAUTHORIZED, "Security token is stale. Please reload page."); } return 0; } } if (action) { httpAuthenticate(conn); setupFlash(conn); if (eroute->commonController) { (eroute->commonController)(conn); } if (!httpIsFinalized(conn)) { (action)(conn); } } return 1; }