/* Constructor function File(path: Object, options: Object = null) */ static EjsFile *fileConstructor(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsObj *pp, *options; cchar *path; if (argc < 1 || argc > 2) { ejsThrowArgError(ejs, "Bad args"); return 0; } pp = argv[0]; if (ejsIs(ejs, pp, Path)) { path = ((EjsPath*) pp)->value; } else if (ejsIs(ejs, pp, String)) { path = ejsToMulti(ejs, pp); } else { ejsThrowIOError(ejs, "Bad path"); return 0; } fp->path = mprNormalizePath(path); if (argc == 2) { options = (argc >= 2) ? argv[1] : 0; openFile(ejs, fp, 1, &options); } return fp; }
static MprList *expandWild(Ejs *ejs, int argc, char **argv) { MprList *list; EjsArray *files; EjsPath *path, *dir; cchar *arg; int i, j; if ((list = mprCreateList(-1, 0)) == 0) { return 0; } for (i = 0; i < argc; i++) { if (schr(argv[i], '*')) { arg = mprNormalizePath(argv[i]); dir = ejsCreatePathFromAsc(ejs, mprGetPathDir(arg)); path = ejsCreatePathFromAsc(ejs, mprGetPathBase(arg)); if ((files = ejsGetPathFiles(ejs, dir, 1, (EjsObj**) (void*) &path)) == 0) { ejsClearException(ejs); mprAddItem(list, sclone(argv[i])); } else { for (j = 0; j < files->length; j++) { mprAddItem(list, ((EjsPath*) files->data[j])->value); } } } else { mprAddItem(list, sclone(argv[i])); } } return list; }
/* Search for a module "filename" in the modulePath. Return the result in "result" */ PUBLIC char *mprSearchForModule(cchar *filename) { #if ME_COMPILER_HAS_DYN_LOAD char *path, *f, *searchPath, *dir, *tok; filename = mprNormalizePath(filename); /* Search for the path directly */ if ((path = probe(filename)) != 0) { return path; } /* Search in the searchPath */ searchPath = sclone(mprGetModuleSearchPath()); tok = 0; dir = stok(searchPath, MPR_SEARCH_SEP, &tok); while (dir && *dir) { f = mprJoinPath(dir, filename); if ((path = probe(f)) != 0) { return path; } dir = stok(0, MPR_SEARCH_SEP, &tok); } #endif /* ME_COMPILER_HAS_DYN_LOAD */ return 0; }
/* Search for a module "filename" in the modulePath. Return the result in "result" */ char *mprSearchForModule(cchar *filename) { #if BIT_HAS_DYN_LOAD char *path, *f, *searchPath, *dir, *tok; filename = mprNormalizePath(filename); /* Search for the path directly */ if ((path = probe(filename)) != 0) { mprLog(6, "Found native module %s at %s", filename, path); return path; } /* Search in the searchPath */ searchPath = sclone(mprGetModuleSearchPath()); tok = 0; dir = stok(searchPath, MPR_SEARCH_SEP, &tok); while (dir && *dir) { f = mprJoinPath(dir, filename); if ((path = probe(f)) != 0) { mprLog(6, "Found native module %s at %s", filename, path); return path; } dir = stok(0, MPR_SEARCH_SEP, &tok); } #endif /* BIT_HAS_DYN_LOAD */ return 0; }
static char *getOutDir(cchar *name) { #if DEBUG_IDE return mprGetAppDir(); #else return mprNormalizePath(sfmt("%s/../%s", mprGetAppDir(), name)); #endif }
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; }
static void testAbsPath(MprTestGroup *gp) { char *path; #if MANUAL_TESTING path = mprNormalizePath("/"); path = mprNormalizePath("C:/"); path = mprNormalizePath("C:/abc"); path = mprNormalizePath(""); path = mprNormalizePath("c:abc"); path = mprNormalizePath("abc"); path = mprGetAbsPath("/"); path = mprGetAbsPath("C:/"); path = mprGetAbsPath("C:/abc"); path = mprGetAbsPath(""); path = mprGetAbsPath("c:abc"); path = mprGetAbsPath("abc"); #endif path = mprGetAbsPath(""); assert(mprIsPathAbs(path)); path = mprGetAbsPath("/"); assert(mprIsPathAbs(path)); path = mprGetAbsPath("../../../../../../../../../../.."); assert(mprIsPathAbs(path)); assert(mprIsPathAbs(mprGetAbsPath("Makefile"))); /* Manually check incase mprIsAbs gets it wrong */ path = mprGetAbsPath("Makefile"); assert(path && *path); assert(mprIsPathAbs(path)); #if BIT_WIN_LIKE assert(isalpha(path[0])); assert(path[1] == ':' && path[2] == '\\'); #elif BIT_UNIX_LIKE assert(path[0] == '/' && path[1] != '/'); #endif assert(strcmp(mprGetPathBase(path), "Makefile") == 0); }
static void testRelPath(MprTestGroup *gp) { char *path, *absPath; path = mprGetRelPath("Makefile", 0); assert(strcmp(path, "Makefile") == 0); path = mprNormalizePath("../a.b"); assert(strcmp(path, "../a.b") == 0); path = mprGetRelPath("/", 0); assert(mprIsPathRel(path)); assert(strncmp(path, "../", 3) == 0); path = mprGetRelPath("//", 0); assert(mprIsPathRel(path)); assert(strncmp(path, "../", 3) == 0); path = mprGetRelPath("/tmp", 0); assert(mprIsPathRel(path)); assert(strncmp(path, "../", 3) == 0); path = mprGetRelPath("/Unknown/someone/junk", 0); assert(mprIsPathRel(path)); assert(strncmp(path, "../", 3) == 0); path = mprGetRelPath("/Users/mob/junk", 0); assert(mprIsPathRel(path)); assert(strncmp(path, "../", 3) == 0); path = mprGetRelPath("/Users/mob/././../mob/junk", 0); assert(mprIsPathRel(path)); assert(strncmp(path, "../", 3) == 0); path = mprGetRelPath(".", 0); assert(strcmp(path, ".") == 0); path = mprGetRelPath("..", 0); assert(strcmp(path, "..") == 0); path = mprGetRelPath("/Users/mob/github/admin", 0); assert(sstarts(path, "..")); path = mprGetRelPath("/Users/mob/git", 0); path = mprGetRelPath("/Users/mob/git/mpr/test", 0); /* Can't really test the result of this */ absPath = mprGetAbsPath("Makefile"); assert(mprIsPathAbs(absPath)); path = mprGetRelPath(absPath, 0); assert(!mprIsPathAbs(path)); assert(strcmp(path, "Makefile") == 0); #if FUTURE // MOB - problem in that we don't know the cwd when testMpr runs // Test relative to an origin out = mprGetAbsPath("../../out"); cwd = mprGetCurrentPath(); assert(smatch(mprGetRelPath(cwd, out), "../src/test")); #endif }
static void testNormalize(MprTestGroup *gp) { char *path; assert(strcmp(mprNormalizePath(""), "") == 0); assert(strcmp(mprNormalizePath("/"), "/") == 0); assert(strcmp(mprNormalizePath("."), ".") == 0); assert(strcmp(mprNormalizePath("abc/"), "abc") == 0); assert(strcmp(mprNormalizePath("./"), ".") == 0); assert(strcmp(mprNormalizePath("../"), "..") == 0); assert(strcmp(mprNormalizePath("/.."), "/") == 0); assert(strcmp(mprNormalizePath("./.."), "..") == 0); assert(strcmp(mprNormalizePath("//.."), "/") == 0); assert(strcmp(mprNormalizePath("/abc/.."), "/") == 0); assert(strcmp(mprNormalizePath("abc/.."), ".") == 0); assert(strcmp(mprNormalizePath("/abc/../def"), "/def") == 0); assert(strcmp(mprNormalizePath("/abc/../def/../xyz"), "/xyz") == 0); assert(strcmp(mprNormalizePath("/abc/def/../.."), "/") == 0); assert(strcmp(mprNormalizePath("/abc/def/../../xyz"), "/xyz") == 0); assert(strcmp(mprNormalizePath("/abc/def/.././../xyz"), "/xyz") == 0); assert(strcmp(mprNormalizePath("//a//b//./././c/d/e/f/../../g"), "/a/b/c/d/g") == 0); assert(strcmp(mprNormalizePath("../../modules/ejs.mod"), "../../modules/ejs.mod") == 0); path = mprNormalizePath("//a//b//./././c/d/e/f/../../g"); assert(strcmp(path, "/a/b/c/d/g") == 0); #if VXWORKS || BIT_WIN_LIKE path = mprNormalizePath("\\\\a\\\\b\\\\.\\.\\.\\c\\d\\e\\f\\..\\..\\g"); mprAssert(strcmp(path, "\\a\\b\\c\\d\\g") == 0); assert(strcmp(mprNormalizePath("host:"), "host:.") == 0); assert(strcmp(mprNormalizePath("host:/"), "host:/") == 0); assert(strcmp(mprNormalizePath("host:////"), "host:/") == 0); assert(strcmp(mprNormalizePath("host:abc"), "host:abc") == 0); assert(strcmp(mprNormalizePath("c:abc"), "c:abc") == 0); #endif }
/* 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; }
/* 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; }