/* 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 int mdbLoad(Edi *edi, cchar *path) { cchar *data; ssize len; if ((data = mprReadPathContents(path, &len)) == 0) { return MPR_ERR_CANT_READ; } return mdbLoadFromString(edi, data); }
PUBLIC int httpSetGroupAccount(cchar *newGroup) { Http *http; http = HTTP; if (smatch(newGroup, "HTTP") || smatch(newGroup, "APPWEB")) { #if ME_UNIX_LIKE /* Only change group if root */ if (getuid() != 0) { return 0; } #endif #if MACOSX || FREEBSD newGroup = "_www"; #elif LINUX || ME_UNIX_LIKE { char *buf; newGroup = "nobody"; /* Debian has nogroup, Fedora has nobody. Ugh! */ if ((buf = mprReadPathContents("/etc/group", NULL)) != 0) { if (scontains(buf, "nogroup:")) { newGroup = "nogroup"; } } } #elif WINDOWS newGroup = "Administrator"; #endif } #if ME_UNIX_LIKE struct group *gp; if (snumber(newGroup)) { http->gid = atoi(newGroup); if ((gp = getgrgid(http->gid)) == 0) { mprLog("critical http", 0, "Bad group id: %d", http->gid); return MPR_ERR_CANT_ACCESS; } newGroup = gp->gr_name; } else { if ((gp = getgrnam(newGroup)) == 0) { mprLog("critical http", 0, "Bad group name: %s", newGroup); return MPR_ERR_CANT_ACCESS; } http->gid = gp->gr_gid; } http->groupChanged = 1; #endif http->group = sclone(newGroup); return 0; }
static int setKeyFile(SSL_CTX *ctx, cchar *keyFile) { RSA *key; BIO *bio; char *buf; int rc; assert(ctx); assert(keyFile); key = 0; bio = 0; buf = 0; rc = -1; if (ctx == NULL || keyFile == NULL) { ; } else if ((buf = mprReadPathContents(keyFile, NULL)) == 0) { mprLog("error openssl", 0, "Unable to read certificate %s", keyFile); } else if ((bio = BIO_new_mem_buf(buf, -1)) == 0) { mprLog("error openssl", 0, "Unable to allocate memory for key %s", keyFile); } else if ((key = PEM_read_bio_RSAPrivateKey(bio, NULL, 0, NULL)) == 0) { mprLog("error openssl", 0, "Unable to parse key %s", keyFile); } else if (SSL_CTX_use_RSAPrivateKey(ctx, key) != 1) { mprLog("error openssl", 0, "Unable to use key %s", keyFile); } else { rc = 0; } if (bio) { BIO_free(bio); } if (key) { RSA_free(key); } return rc; }
static int setCertFile(SSL_CTX *ctx, cchar *certFile) { X509 *cert; BIO *bio; char *buf; int rc; assert(ctx); assert(certFile); rc = -1; bio = 0; buf = 0; cert = 0; if (ctx == NULL) { return rc; } if ((buf = mprReadPathContents(certFile, NULL)) == 0) { mprLog("error openssl", 0, "Unable to read certificate %s", certFile); } else if ((bio = BIO_new_mem_buf(buf, -1)) == 0) { mprLog("error openssl", 0, "Unable to allocate memory for certificate %s", certFile); } else if ((cert = PEM_read_bio_X509(bio, NULL, 0, NULL)) == 0) { mprLog("error openssl", 0, "Unable to parse certificate %s", certFile); } else if (SSL_CTX_use_certificate(ctx, cert) != 1) { mprLog("error openssl", 0, "Unable to use certificate %s", certFile); } else { rc = 0; } if (bio) { BIO_free(bio); } if (cert) { X509_free(cert); } return rc; }
int APIENTRY WinMain(HINSTANCE inst, HINSTANCE junk, char *command, int junk2) { char **argv; cchar *documents, *home, *logs, *port, *ssl, *argp, *path, *contents, *revised; cchar *user, *group, *cache, *modules, *bak; int argc, err, nextArg; static void logHandler(int flags, int level, cchar *msg); if (mprCreate(0, NULL, MPR_USER_EVENTS_THREAD) == NULL) { exit(1); } if ((argc = mprMakeArgv(command, &argv, MPR_ARGV_ARGS_ONLY)) < 0) { return FALSE; } mprSetLogHandler(logHandler); #else int main(int argc, char **argv) { cchar *documents, *home, *logs, *port, *ssl, *argp, *path, *contents, *revised; cchar *user, *group, *cache, *modules, *bak; int err, nextArg; if (mprCreate(argc, argv, MPR_USER_EVENTS_THREAD) == NULL) { exit(1); } #endif documents = home = port = ssl = logs = user = group = cache = modules = 0; for (err = 0, nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--documents") && nextArg < argc) { documents = argv[++nextArg]; } else if (smatch(argp, "--home") && nextArg < argc) { home = argv[++nextArg]; } else if (smatch(argp, "--logs") && nextArg < argc) { logs = argv[++nextArg]; } else if (smatch(argp, "--port") && nextArg < argc) { port = argv[++nextArg]; } else if (smatch(argp, "--ssl") && nextArg < argc) { ssl = argv[++nextArg]; } else if (smatch(argp, "--user") && nextArg < argc) { user = argv[++nextArg]; } else if (smatch(argp, "--group") && nextArg < argc) { group = argv[++nextArg]; } else if (smatch(argp, "--cache") && nextArg < argc) { cache = argv[++nextArg]; } else if (smatch(argp, "--modules") && nextArg < argc) { modules = argv[++nextArg]; } else { err++; } } if (nextArg != (argc - 1)) { err++; } if (err) { #if BIT_WIN_LIKE mprUserError("Bad command line:"); #else mprUserError("Bad command line:\n" " Usage: pathConfig [options]\n" " Switches:\n" " --cache dir # Cache dir" " --documents dir # Static documents directory" " --group groupname # Group name" " --home dir # Server home directory" " --logs dir # Log directory" " --modules dir # moduels dir" " --port number # HTTP port number" " --user username # User name"); #endif return 1; } path = argv[nextArg++]; if ((contents = mprReadPathContents(path, NULL)) == 0) { mprUserError("Cannot read %s", path); return 1; } if (port) { contents = replace(contents, "Listen 80", "Listen %s", port); } if (ssl) { contents = replace(contents, "443", ssl); } if (documents) { contents = replace(contents, "DocumentRoot", "DocumentRoot \"%s\"", documents); } if (home) { contents = replace(contents, "ServerRoot", "ServerRoot \"%s\"", home); } if (logs) { contents = replace(contents, "ErrorLog", "ErrorLog \"%s\"", mprJoinPath(logs, "error.log")); contents = replace(contents, "AccessLog", "AccessLog \"%s\"", mprJoinPath(logs, "access.log")); } if (user) { contents = replace(contents, "UserAccount", "UserAccount %s", user); } if (group) { contents = replace(contents, "GroupAccount", "GroupAccount %s", group); } if (cache) { contents = replace(contents, "EspDir cache", "EspDir cache \"%s\"", cache); } if (modules) { contents = replace(contents, "LoadModulePath", "LoadModulePath \"%s\"", modules); } revised = mprGetTempPath(mprGetPathDir(path)); if (mprWritePathContents(revised, contents, -1, 0644) < 0) { mprUserError("Cannot write %s", revised); } bak = sfmt("%s.bak", path); mprDeletePath(bak); if (rename(path, bak) < 0) { mprUserError("Cannot save %s to %s: 0x%x", path, bak, mprGetError()); } mprDeletePath(path); if (rename(revised, path) < 0) { mprUserError("Cannot rename %s to %s: 0x%x", revised, path, mprGetError()); rename(bak, path); } return 0; }
PUBLIC int espEmail(HttpConn *conn, cchar *to, cchar *from, cchar *subject, MprTime date, cchar *mime, cchar *message, MprList *files) { MprList *lines; MprCmd *cmd; cchar *body, *boundary, *contents, *encoded, *file; char *out, *err; ssize length; int i, next, status; if (!from || !*from) { from = "anonymous"; } if (!subject || !*subject) { subject = "Mail message"; } if (!mime || !*mime) { mime = "text/plain"; } if (!date) { date = mprGetTime(); } boundary = sjoin("esp.mail=", mprGetMD5("BOUNDARY"), NULL); lines = mprCreateList(0, 0); mprAddItem(lines, sfmt("To: %s", to)); mprAddItem(lines, sfmt("From: %s", from)); mprAddItem(lines, sfmt("Date: %s", mprFormatLocalTime(0, date))); mprAddItem(lines, sfmt("Subject: %s", subject)); mprAddItem(lines, "MIME-Version: 1.0"); mprAddItem(lines, sfmt("Content-Type: multipart/mixed; boundary=%s", boundary)); mprAddItem(lines, ""); boundary = sjoin("--", boundary, NULL); mprAddItem(lines, boundary); mprAddItem(lines, sfmt("Content-Type: %s", mime)); mprAddItem(lines, ""); mprAddItem(lines, ""); mprAddItem(lines, message); for (ITERATE_ITEMS(files, file, next)) { mprAddItem(lines, boundary); if ((mime = mprLookupMime(NULL, file)) == 0) { mime = "application/octet-stream"; } mprAddItem(lines, "Content-Transfer-Encoding: base64"); mprAddItem(lines, sfmt("Content-Disposition: inline; filename=\"%s\"", mprGetPathBase(file))); mprAddItem(lines, sfmt("Content-Type: %s; name=\"%s\"", mime, mprGetPathBase(file))); mprAddItem(lines, ""); contents = mprReadPathContents(file, &length); encoded = mprEncode64Block(contents, length); for (i = 0; i < length; i += 76) { mprAddItem(lines, snclone(&encoded[i], i + 76)); } } mprAddItem(lines, sfmt("%s--", boundary)); body = mprListToString(lines, "\n"); httpTraceContent(conn, "esp.email", "context", body, slen(body), 0); cmd = mprCreateCmd(conn->dispatcher); if (mprRunCmd(cmd, "sendmail -t", NULL, body, &out, &err, -1, 0) < 0) { mprDestroyCmd(cmd); return MPR_ERR_CANT_OPEN; } if (mprWaitForCmd(cmd, ME_ESP_EMAIL_TIMEOUT) < 0) { httpTrace(conn, "esp.email.error", "error", "msg=\"Timeout waiting for command to complete\", timeout=%d, command=\"%s\"", ME_ESP_EMAIL_TIMEOUT, cmd->argv[0]); mprDestroyCmd(cmd); return MPR_ERR_CANT_COMPLETE; } if ((status = mprGetCmdExitStatus(cmd)) != 0) { httpTrace(conn, "esp.email.error", "error", "msg=\"Sendmail failed\", status=%d, error=\"%s\"", status, err); mprDestroyCmd(cmd); return MPR_ERR_CANT_WRITE; } mprDestroyCmd(cmd); 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; }
/* 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; }