/* Check if the target/filename.ext is registered as a view or exists as a file */ static cchar *checkView(HttpConn *conn, cchar *target, cchar *filename, cchar *ext) { MprPath info; EspRoute *eroute; cchar *path; if (filename) { target = mprJoinPath(target, filename); } if (ext && *ext) { if (!smatch(mprGetPathExt(target), ext)) { target = sjoin(target, ".", ext, NULL); } } eroute = conn->rx->route->eroute; if (mprLookupKey(eroute->views, target)) { return target; } path = mprJoinPath(conn->rx->route->documents, target); if (mprGetPathInfo(path, &info) == 0 && !info.isDir) { return target; } if (conn->rx->route->map && !(conn->tx->flags & HTTP_TX_NO_MAP)) { path = httpMapContent(conn, path); if (mprGetPathInfo(path, &info) == 0 && !info.isDir) { return target; } } return 0; }
static int setContentLength(HttpConn *conn, MprList *files) { MprPath info; MprOff len; char *path, *pair; int next; len = 0; if (app->upload) { httpEnableUpload(conn); return 0; } for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) { if (strcmp(path, "-") != 0) { if (mprGetPathInfo(path, &info) < 0) { mprError("Can't access file %s", path); return MPR_ERR_CANT_ACCESS; } len += info.size; } } if (app->formData) { for (next = 0; (pair = mprGetNextItem(app->formData, &next)) != 0; ) { len += slen(pair); } len += mprGetListLength(app->formData) - 1; } if (app->bodyData) { len += mprGetBufLength(app->bodyData); } if (len > 0) { httpSetContentLength(conn, len); } return 0; }
/* Action to run in response to the "test/output" URI */ static void output_action() { Output *output; /* Don't automatically finalize (complete) the request when this routine returns. This keeps the connection open. */ dontAutoFinalize(); /* Define the event notifier. We're interested in WRITABLE events */ setNotifier(output_callback); /* Open a file for output. Could use open/write, but we use the MPR equivalents for cross-platform I/O. */ output = mprAllocObj(Output, manageOutput); if ((output->file = mprOpenFile(OUTPUT_FILE, O_RDONLY, 0)) == 0) { httpError(getConn(), HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot open huge.txt"); return; } mprGetPathInfo(OUTPUT_FILE, &output->info); /* Save a reference to our output state */ setData(output); }
PUBLIC int ecOpenFileStream(EcCompiler *cp, cchar *path) { EcFileStream *fs; MprPath info; char *contents; if ((fs = ecCreateStream(cp, sizeof(EcFileStream), path, manageFileStream)) == 0) { return MPR_ERR_MEMORY; } if ((fs->file = mprOpenFile(path, O_RDONLY | O_BINARY, 0666)) == 0) { return MPR_ERR_CANT_OPEN; } if (mprGetPathInfo(path, &info) < 0 || info.size < 0) { mprCloseFile(fs->file); return MPR_ERR_CANT_ACCESS; } if ((contents = mprAlloc((int) info.size + 1)) == 0) { mprCloseFile(fs->file); return MPR_ERR_MEMORY; } if (mprReadFile(fs->file, contents, (int) info.size) != (int) info.size) { mprCloseFile(fs->file); return MPR_ERR_CANT_READ; } contents[info.size] = '\0'; ecSetStreamBuf((EcStream*) fs, contents, (ssize) info.size); mprCloseFile(fs->file); fs->file = 0; return 0; }
static int setContentLength(MprHttp *http, MprList *fields, MprList *files) { MprPath info; char *path, *pair; int64 len; int next; len = 0; if (upload) { /* Easier to use chunking than to calculate the full multipart-mime upload content */ mprSetHttpChunked(http, 1); mprEnableHttpUpload(http); return 0; } else { for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) { if (mprGetPathInfo(http, path, &info) < 0) { mprError(http, "Can't access file %s", path); return MPR_ERR_CANT_ACCESS; } len += info.size; } if (fields) { for (next = 0; (pair = mprGetNextItem(fields, &next)) != 0; ) { len += strlen(pair); } len += mprGetListCount(fields) - 1; } } if (len > (16 * MPR_HTTP_BUFSIZE)) { mprSetHttpChunked(http, 1); } else { mprSetHttpBody(http, NULL, (int) len); } return 0; }
/* Test if a module has been updated (is stale). This will unload the module if it loaded but stale. Set recompile to true if the source is absent or more recent. Will return false if the source does not exist (important for testing layouts). */ PUBLIC bool espModuleIsStale(cchar *source, cchar *module, int *recompile) { MprModule *mp; MprPath sinfo, minfo; *recompile = 0; mprGetPathInfo(module, &minfo); if (!minfo.valid) { if ((mp = mprLookupModule(source)) != 0) { if (!espUnloadModule(source, ME_ESP_RELOAD_TIMEOUT)) { mprLog("error esp", 0, "Cannot unload module %s. Connections still open. Continue using old version.", source); return 0; } } *recompile = 1; mprLog("info esp", 4, "Source %s is newer than module %s, recompiling ...", source, module); return 1; } mprGetPathInfo(source, &sinfo); if (sinfo.valid && sinfo.mtime > minfo.mtime) { if ((mp = mprLookupModule(source)) != 0) { if (!espUnloadModule(source, ME_ESP_RELOAD_TIMEOUT)) { mprLog("warn esp", 4, "Cannot unload module %s. Connections still open. Continue using old version.", source); return 0; } } *recompile = 1; mprLog("info esp", 4, "Source %s is newer than module %s, recompiling ...", source, module); return 1; } if ((mp = mprLookupModule(source)) != 0) { if (minfo.mtime > mp->modified) { /* Module file has been updated */ if (!espUnloadModule(source, ME_ESP_RELOAD_TIMEOUT)) { mprLog("warn esp", 4, "Cannot unload module %s. Connections still open. Continue using old version.", source); return 0; } mprLog("info esp", 4, "Module %s has been externally updated, reloading ...", module); return 1; } } /* Loaded module is current */ return 0; }
/* Get the size of the file associated with this File object. override function get size(): Number */ static EjsObj *getFileSize(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { MprPath info; if (mprGetPathInfo(fp->path, &info) < 0) { return (EjsObj*) ESV(minusOne); } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) info.size); }
/* Test if a module has been updated (is stale). This will unload the module if it is stale and loaded */ bool espModuleIsStale(cchar *source, cchar *module, int *recompile) { MprModule *mp; MprPath sinfo, minfo; *recompile = 0; mprGetPathInfo(module, &minfo); if (!minfo.valid) { *recompile = 1; if ((mp = mprLookupModule(source)) != 0) { if (!espUnloadModule(source, 0)) { mprError("Can't unload module %s. Connections still open. Continue using old version.", source); return 0; } } return 1; } mprGetPathInfo(source, &sinfo); /* Use >= to ensure we reload. This may cause redundant reloads as mtime has a 1 sec granularity. */ if (sinfo.valid && sinfo.mtime >= minfo.mtime) { if ((mp = mprLookupModule(source)) != 0) { if (!espUnloadModule(source, 0)) { mprError("Can't unload module %s. Connections still open. Continue using old version.", source); return 0; } } *recompile = 1; return 1; } if ((mp = mprLookupModule(source)) != 0) { if (minfo.mtime > mp->modified) { /* Module file has been updated */ if (!espUnloadModule(source, 0)) { mprError("Can't unload module %s. Connections still open. Continue using old version.", source); return 0; } return 1; } } /* Loaded module is current */ return 0; }
/* Constructor function open(options: Object = null): File NOTE: options can be an options hash or as mode string */ static EjsObj *openFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsObj *options; cchar *mode; int perms, omode; if (argc < 0 || argc > 1) { ejsThrowArgError(ejs, "Bad args"); return 0; } options = argv[0]; if (argc == 0 || !ejsIsDefined(ejs, options)) { omode = O_RDONLY | O_BINARY; perms = EJS_FILE_PERMS; fp->mode = EJS_FILE_READ; mode = "r"; } else { if (ejsIs(ejs, options, String)) { mode = ejsToMulti(ejs, options); perms = EJS_FILE_PERMS; } else { perms = ejsGetNumOption(ejs, options, "permissions", EJS_FILE_PERMS, 1); mode = getStrOption(ejs, options, "mode", "r", 1); if (ejs->exception) { return 0; } } omode = mapMode(mode); if (!(omode & O_WRONLY)) { fp->mode |= EJS_FILE_READ; } if (omode & (O_WRONLY | O_RDWR)) { fp->mode |= EJS_FILE_WRITE; } } fp->modeString = sclone(mode); fp->perms = perms; if (fp->file) { mprCloseFile(fp->file); } fp->file = mprOpenFile(fp->path, omode, perms); if (fp->file == 0) { ejsThrowIOError(ejs, "Cannot open %s", fp->path); return 0; } if (options) { ejsSetPathAttributes(ejs, fp->path, options); } #if ME_CC_MMU && FUTURE mprGetPathInfo(&fp->info); fp->mapped = mapFile(fp, fp->info.size, MPR_MAP_READ | MPR_MAP_WRITE); #endif fp->mode |= EJS_FILE_OPEN; return (EjsObj*) fp; }
PUBLIC bool httpFileExists(HttpConn *conn) { HttpTx *tx; tx = conn->tx; if (!tx->fileInfo.checked) { mprGetPathInfo(tx->filename, &tx->fileInfo); } return tx->fileInfo.valid; }
PUBLIC int mprLoadNativeModule(MprModule *mp) { MprModuleEntry fn; MprPath info; char *at; void *handle; assert(mp); /* Search the image incase the module has been statically linked */ #ifdef RTLD_DEFAULT handle = RTLD_DEFAULT; #else #ifdef RTLD_MAIN_ONLY handle = RTLD_MAIN_ONLY; #else handle = 0; #endif #endif if (!mp->entry || !dlsym(handle, mp->entry)) { if ((at = mprSearchForModule(mp->path)) == 0) { mprError("Cannot find module \"%s\", cwd: \"%s\", search path \"%s\"", mp->path, mprGetCurrentPath(), mprGetModuleSearchPath()); return MPR_ERR_CANT_ACCESS; } mp->path = at; mprGetPathInfo(mp->path, &info); mp->modified = info.mtime; mprLog(2, "Loading native module %s", mprGetPathBase(mp->path)); if ((handle = dlopen(mp->path, RTLD_LAZY | RTLD_GLOBAL)) == 0) { mprError("Cannot load module %s\nReason: \"%s\"", mp->path, dlerror()); return MPR_ERR_CANT_OPEN; } mp->handle = handle; } else if (mp->entry) { mprLog(2, "Activating native module %s", mp->name); } if (mp->entry) { if ((fn = (MprModuleEntry) dlsym(handle, mp->entry)) != 0) { if ((fn)(mp->moduleData, mp) < 0) { mprError("Initialization for module %s failed", mp->name); dlclose(handle); return MPR_ERR_CANT_INITIALIZE; } } else { mprError("Cannot load module %s\nReason: can't find function \"%s\"", mp->path, mp->entry); dlclose(handle); return MPR_ERR_CANT_READ; } } return 0; }
/* Test if a module has been updated (is stale). This will unload the module if it loaded but stale. */ PUBLIC bool espModuleIsStale(cchar *source, cchar *module, int *recompile) { MprModule *mp; MprPath sinfo, minfo; *recompile = 0; mprGetPathInfo(module, &minfo); if (!minfo.valid) { *recompile = 1; if ((mp = mprLookupModule(source)) != 0) { if (!espUnloadModule(source, 0)) { mprError("Cannot unload module %s. Connections still open. Continue using old version.", source); return 0; } } return 1; } mprGetPathInfo(source, &sinfo); if (sinfo.valid && sinfo.mtime > minfo.mtime) { if ((mp = mprLookupModule(source)) != 0) { if (!espUnloadModule(source, 0)) { mprError("Cannot unload module %s. Connections still open. Continue using old version.", source); return 0; } } *recompile = 1; return 1; } if ((mp = mprLookupModule(source)) != 0) { if (minfo.mtime > mp->modified) { /* Module file has been updated */ if (!espUnloadModule(source, 0)) { mprError("Cannot unload module %s. Connections still open. Continue using old version.", source); return 0; } return 1; } } /* Loaded module is current */ return 0; }
PUBLIC int mprLoadNativeModule(MprModule *mp) { MprModuleEntry fn; void *handle; assert(mp); if ((handle = (HANDLE) MPR->appInstance) == 0) { handle = GetModuleHandle(NULL); } if (!handle || !mp->entry || !GetProcAddress(handle, mp->entry)) { #if ME_STATIC mprLog("error mpr", 0, "Cannot load module %s, product built static", mp->name); return MPR_ERR_BAD_STATE; #else MprPath info; char *at, *baseName; if ((at = mprSearchForModule(mp->path)) == 0) { mprLog("error mpr", 0, "Cannot find module \"%s\", cwd=\"%s\", search=\"%s\"", mp->path, mprGetCurrentPath(), mprGetModuleSearchPath()); return MPR_ERR_CANT_ACCESS; } mp->path = at; mprGetPathInfo(mp->path, &info); mp->modified = info.mtime; baseName = mprGetPathBase(mp->path); mprLog("info mpr", 4, "Loading native module %s", baseName); if ((handle = LoadLibrary(wide(mp->path))) == 0) { mprLog("error mpr", 0, "Cannot load module %s, errno=\"%d\"", mp->path, mprGetOsError()); return MPR_ERR_CANT_READ; } mp->handle = handle; #endif /* !ME_STATIC */ } else if (mp->entry) { mprLog("info mpr", 4, "Activating native module %s", mp->name); } if (mp->entry) { if ((fn = (MprModuleEntry) GetProcAddress((HINSTANCE) handle, mp->entry)) == 0) { mprLog("error mpr", 0, "Cannot load module %s, cannot find function \"%s\"", mp->name, mp->entry); FreeLibrary((HINSTANCE) handle); return MPR_ERR_CANT_ACCESS; } if ((fn)(mp->moduleData, mp) < 0) { mprLog("error mpr", 0, "Initialization for module %s failed", mp->name); FreeLibrary((HINSTANCE) handle); return MPR_ERR_CANT_INITIALIZE; } } return 0; }
int maSetRequestUri(MaConn *conn, cchar *uri, cchar *query) { MaRequest *req; MaResponse *resp; MaHost *host; MprUri *prior; char *cp; if (uri == 0 || *uri == 0) { uri = "/"; } host = conn->host; req = conn->request; resp = conn->response; prior = req->parsedUri; if ((req->parsedUri = mprParseUri(req, uri)) == 0) { return MPR_ERR_BAD_ARGS; } if (prior) { if ((cp = strstr(uri, "://")) == 0) { req->parsedUri->scheme = prior->scheme; req->parsedUri->host = prior->host; } else if (strchr(&cp[3], ':') == 0) { req->parsedUri->port = prior->port; } } if (query == 0 && prior) { req->parsedUri->query = prior->query; } else if (*query) { req->parsedUri->query = mprStrdup(req->parsedUri, query); } req->url = mprValidateUrl(req, mprUrlDecode(req, req->parsedUri->url)); req->alias = maGetAlias(host, req->url); resp->filename = maMakeFilename(conn, req->alias, req->url, 1); if ((req->dir = maLookupBestDir(req->host, resp->filename)) != 0) { if (req->dir->auth) { req->auth = req->dir->auth; } } req->location = maLookupBestLocation(host, req->url); if (req->auth == 0) { req->auth = req->location->auth; } mprGetPathInfo(conn, resp->filename, &resp->fileInfo); resp->extension = maGetExtension(conn); if ((resp->mimeType = (char*) maLookupMimeType(host, resp->extension)) == 0) { resp->mimeType = (char*) "text/html"; } return 0; }
/* Read data bytes from a file function readBytes(count: Number = -1): ByteArray */ static EjsObj *readFileBytes(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *result; MprPath info; ssize count, totalRead; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } result = ejsCreateByteArray(ejs, count); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } totalRead = readData(ejs, fp, result, 0, count); if (totalRead < 0) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } else if (totalRead == 0) { return ESV(null); } ejsSetByteArrayPositions(ejs, result, 0, totalRead); return (EjsObj*) result; }
/* Read data bytes from a file. If offset is < 0, then append to the write position. function read(buffer: ByteArray, offset: Number = 0, count: Number = -1): Number */ static EjsNumber *readFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *buffer; MprPath info; ssize offset, count, totalRead; assert(1 <= argc && argc <= 3); buffer = (EjsByteArray*) argv[0]; offset = (argc >= 2) ? ejsGetInt(ejs, argv[1]): 0; count = (argc >= 3) ? ejsGetInt(ejs, argv[2]): -1; if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (offset >= buffer->size) { ejsThrowOutOfBoundsError(ejs, "Bad read offset value"); return 0; } if (offset < 0) { offset = buffer->writePosition; } else if (offset == 0) { ejsSetByteArrayPositions(ejs, buffer, 0, 0); } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } totalRead = readData(ejs, fp, buffer, offset, count); if (totalRead < 0) { return 0; } else if (totalRead == 0) { return ESV(zero); } ejsSetByteArrayPositions(ejs, buffer, -1, offset + totalRead); return ejsCreateNumber(ejs, (MprNumber) totalRead); }
/* Read data as a string function readString(count: Number = -1): String */ static EjsString *readFileString(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsString *result; MprPath info; ssize totalRead; int count; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } if ((result = ejsCreateBareString(ejs, count)) == NULL) { ejsThrowMemoryError(ejs); return 0; } totalRead = mprReadFile(fp->file, result->value, count); if (totalRead != count) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } return ejsInternString(result); }
/* * Called to rotate the access log */ void maRotateAccessLog(MaHost *host) { MprPath info; struct tm tm; MprTime when; char bak[MPR_MAX_FNAME]; if (mprGetPathInfo(host, host->logPath, &info) == 0) { when = mprGetTime(host); mprDecodeUniversalTime(host, &tm, when); mprSprintf(bak, sizeof(bak), "%s-%02d-%02d-%02d-%02d:%02d:%02d", host->logPath, tm.tm_mon, tm.tm_mday, tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); mprFree(host->accessLog); rename(host->logPath, bak); unlink(host->logPath); host->accessLog = mprOpen(host, host->logPath, O_CREAT | O_TRUNC | O_WRONLY | O_TEXT, 0664); } }
/* The incoming callback is invoked to receive body data */ static void incomingFile(HttpQueue *q, HttpPacket *packet) { HttpConn *conn; HttpTx *tx; HttpRx *rx; HttpRange *range; MprBuf *buf; MprFile *file; ssize len; conn = q->conn; tx = conn->tx; rx = conn->rx; file = (MprFile*) q->queueData; if (file == 0) { /* Not a PUT so just ignore the incoming data. */ return; } if (httpGetPacketLength(packet) == 0) { /* End of input */ if (file) { mprCloseFile(file); } q->queueData = 0; if (!tx->etag) { /* Set the etag for caching in the client */ mprGetPathInfo(tx->filename, &tx->fileInfo); tx->etag = sfmt("\"%llx-%llx-%llx\"", tx->fileInfo.inode, tx->fileInfo.size, tx->fileInfo.mtime); } return; } buf = packet->content; len = mprGetBufLength(buf); assert(len > 0); range = rx->inputRange; if (range && mprSeekFile(file, SEEK_SET, range->start) != range->start) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot seek to range start to %lld", range->start); } else if (mprWriteFile(file, mprGetBufStart(buf), len) != len) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot PUT to %s", tx->filename); } }
/* Encode the files as C code */ static int binToC(MprList *files, char *romName, char *prefix) { MprPath info; MprFile *file; char buf[512]; char *filename, *cp, *sl, *p; ssize len; int next, i, j; mprPrintf("/*\n %s -- Compiled Files\n */\n", romName); mprPrintf("#include \"mpr.h\"\n\n"); mprPrintf("#if BIT_FEATURE_ROMFS\n"); /* Open each input file and compile */ for (next = 0; (filename = mprGetNextItem(files, &next)) != 0; ) { if (mprGetPathInfo(filename, &info) == 0 && info.isDir) { continue; } if ((file = mprOpenFile(filename, O_RDONLY | O_BINARY, 0666)) < 0) { mprError("Can't open file %s\n", filename); return -1; } mprPrintf("static uchar _file_%d[] = {\n", next); while ((len = mprReadFile(file, buf, sizeof(buf))) > 0) { p = buf; for (i = 0; i < len; ) { mprPrintf(" "); for (j = 0; p < &buf[len] && j < 16; j++, p++) { mprPrintf("%3d,", (unsigned char) *p); } i += j; mprPrintf("\n"); } } mprPrintf(" 0 };\n\n"); mprCloseFile(file); } /* Now output the page index */ mprPrintf("MprRomInode %s[] = {\n", romName); for (next = 0; (filename = mprGetNextItem(files, &next)) != 0; ) { /* Replace the prefix with a leading "/" */ if (strncmp(filename, prefix, strlen(prefix)) == 0) { cp = &filename[strlen(prefix)]; } else { cp = filename; } while((sl = strchr(filename, '\\')) != NULL) { *sl = '/'; } if (*cp == '/') { cp++; } if (*cp == '.' && cp[1] == '\0') { cp++; } if (mprGetPathInfo(filename, &info) == 0 && info.isDir) { mprPrintf(" { \"%s\", 0, 0, 0 },\n", cp); continue; } mprPrintf(" { \"%s\", _file_%d, %d, %d },\n", cp, next, (int) info.size, next); } mprPrintf(" { 0, 0, 0, 0 },\n"); mprPrintf("};\n"); mprPrintf("#endif /* BIT_FEATURE_ROMFS */\n"); return 0; }
static int handleDirectory(HttpConn *conn) { HttpRx *rx; HttpTx *tx; HttpRoute *route; HttpUri *req; MprPath *info; cchar *index, *pathInfo, *uri; char *path; int next; rx = conn->rx; tx = conn->tx; req = rx->parsedUri; route = rx->route; info = &tx->fileInfo; /* Manage requests for directories */ if (!sends(req->path, "/")) { /* Append "/" and do an external redirect. Use the original request URI. */ pathInfo = sjoin(req->path, "/", NULL); uri = httpFormatUri(req->scheme, req->host, req->port, pathInfo, req->reference, req->query, 0); httpRedirect(conn, HTTP_CODE_MOVED_PERMANENTLY, uri); return HTTP_ROUTE_OK; } if (route->indexes) { /* Ends with a "/" so do internal redirection to an index file */ for (ITERATE_ITEMS(route->indexes, index, next)) { /* Internal directory redirections. Transparently append index. Test indexes in order. */ path = mprJoinPath(tx->filename, index); if (mprPathExists(path, R_OK)) { pathInfo = sjoin(rx->scriptName, rx->pathInfo, index, NULL); uri = httpFormatUri(req->scheme, req->host, req->port, pathInfo, req->reference, req->query, 0); httpSetUri(conn, uri); tx->filename = path; tx->ext = httpGetExt(conn); mprGetPathInfo(tx->filename, info); return HTTP_ROUTE_REROUTE; } } } #if ME_COM_DIR /* Directory Listing. 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 && httpRenderDirListing(conn)) { tx->handler = conn->http->dirHandler; tx->connector = conn->http->netConnector; return HTTP_ROUTE_OK; } #endif return HTTP_ROUTE_OK; }
/* * Start the command to run (stdIn and stdOut are named from the client's perspective). This is the lower-level way to * run a command. The caller needs to do code like mprRunCmd() themselves to wait for completion and to send/receive data. * The routine does not wait. Callers must call mprWaitForCmd to wait for the command to complete. */ int mprStartCmd(MprCmd *cmd, int argc, char **argv, char **envp, int flags) { MprPath info; char *program; int rc; mprAssert(argv); mprAssert(argc > 0); if (argc <= 0 || argv == NULL || argv[0] == NULL) { return MPR_ERR_BAD_STATE; } resetCmd(cmd); program = argv[0]; cmd->program = program; cmd->flags = flags; if (sanitizeArgs(cmd, argc, argv, envp) < 0) { return MPR_ERR_NO_MEMORY; } if (access(program, X_OK) < 0) { program = mprJoinPathExt(cmd, program, BLD_EXE); if (access(program, X_OK) < 0) { mprLog(cmd, 1, "cmd: can't access %s, errno %d", program, mprGetOsError()); return MPR_ERR_CANT_ACCESS; } } if (mprGetPathInfo(cmd, program, &info) == 0 && info.isDir) { mprLog(cmd, 1, "cmd: program \"%s\", is a directory", program); return MPR_ERR_CANT_ACCESS; } #if CYGWIN mprGlobalLock(cmd); #endif if (mprMakeCmdIO(cmd) < 0) { #if CYGWIN mprGlobalUnlock(cmd); #endif return MPR_ERR_CANT_OPEN; } /* * Determine how many end-of-files will be seen when the child dies */ cmd->requiredEof = 0; if (cmd->flags & MPR_CMD_OUT) { cmd->requiredEof++; } if (cmd->flags & MPR_CMD_ERR) { cmd->requiredEof++; } #if UNUSED && KEEP && NON_BLOCKING #if BLD_UNIX_LIKE || VXWORKS { int stdinFd, stdoutFd, stderrFd, nonBlock; stdinFd = cmd->files[MPR_CMD_STDIN].fd; stdoutFd = cmd->files[MPR_CMD_STDOUT].fd; stderrFd = cmd->files[MPR_CMD_STDERR].fd; nonBlock = 1; /* * Put the stdout and stderr into non-blocking mode. Windows can't do this because both ends of the pipe * share the same blocking mode (Ugh!). */ #if VXWORKS if (stdoutFd >= 0) { ioctl(stdoutFd, FIONBIO, (int) &nonBlock); } if (stderrFd >= 0) { ioctl(stderrFd, FIONBIO, (int) &nonBlock); } #else if (stdoutFd >= 0) { fcntl(stdoutFd, F_SETFL, fcntl(stdoutFd, F_GETFL) | O_NONBLOCK); } if (stderrFd >= 0) { fcntl(stderrFd, F_SETFL, fcntl(stderrFd, F_GETFL) | O_NONBLOCK); } #endif if (stdoutFd >= 0) { cmd->handlers[MPR_CMD_STDOUT] = mprCreateWaitHandler(cmd, stdoutFd, MPR_READABLE, (MprWaitProc) stdoutCallback, cmd, MPR_NORMAL_PRIORITY, MPR_WAIT_THREAD); } if (stderrFd >= 0) { cmd->handlers[MPR_CMD_STDERR] = mprCreateWaitHandler(cmd, stderrFd, MPR_READABLE, (MprWaitProc) stderrCallback, cmd, MPR_NORMAL_PRIORITY, MPR_WAIT_THREAD); if (stdoutFd >= 0) { /* * Delay enabling stderr events until stdout is complete */ mprDisableWaitEvents(cmd->handlers[MPR_CMD_STDERR]); } } } #endif #endif rc = startProcess(cmd); #if CYGWIN mprGlobalUnlock(cmd); #endif return rc; }
/* 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; }
/* Load the config.json */ PUBLIC int espLoadConfig(HttpRoute *route) { EspRoute *eroute; MprJson *msettings; MprPath cinfo; cchar *cpath, *value; eroute = route->eroute; cpath = mprJoinPath(route->documents, "config.json"); if (mprGetPathInfo(cpath, &cinfo) == 0) { if (eroute->config && cinfo.mtime > eroute->configLoaded) { eroute->config = 0; } eroute->configLoaded = cinfo.mtime; } if (!eroute->config) { if ((eroute->config = mprLoadJson(cpath)) != 0) { /* Blend the mode properties into settings */ eroute->mode = mprGetJsonValue(eroute->config, "mode", 0); if ((msettings = mprGetJson(eroute->config, sfmt("modes.%s", eroute->mode), 0)) != 0) { mprBlendJson(mprLookupJson(eroute->config, "settings"), msettings, 0); } if ((value = espGetConfig(route, "settings.showErrors", 0)) != 0) { httpSetRouteShowErrors(route, smatch(value, "true")); } if ((value = espGetConfig(route, "settings.update", 0)) != 0) { eroute->update = smatch(value, "true"); } if ((value = espGetConfig(route, "settings.keepSource", 0)) != 0) { eroute->keepSource = smatch(value, "true"); } if ((eroute->serverPrefix = espGetConfig(route, "settings.serverPrefix", 0)) == 0) { eroute->serverPrefix = sclone(BIT_ESP_SERVER_PREFIX); } if ((value = espGetConfig(route, "settings.login.name", 0)) != 0) { /* Automatic login as this user. Password not required */ httpSetAuthUsername(route->auth, value); } if ((value = espGetConfig(route, "settings.xsrfToken", 0)) != 0) { httpSetRouteXsrf(route, smatch(value, "true")); } if ((value = espGetConfig(route, "settings.sendJson", 0)) != 0) { eroute->json = smatch(value, "true"); } if (espTestConfig(route, "settings.map", "compressed")) { httpAddRouteMapping(route, "js,css,less", "min.${1}.gz, min.${1}, ${1}.gz"); httpAddRouteMapping(route, "html,xml", "${1}.gz"); } if (!eroute->database) { if ((eroute->database = espGetConfig(route, "server.database", 0)) != 0) { if (espOpenDatabase(route, eroute->database) < 0) { mprError("Cannot open database %s", eroute->database); return MPR_ERR_CANT_OPEN; } } } eroute->json = espTestConfig(route, "settings.json", "1"); } else { eroute->config = mprCreateJson(MPR_JSON_OBJ); espAddComponent(route, "legacy-mvc"); } if (espHasComponent(route, "legacy-mvc")) { eroute->legacy = 1; } } return 0; }
/* Start the command to run (stdIn and stdOut are named from the client's perspective). This is the lower-level way to run a command. The caller needs to do code like mprRunCmd() themselves to wait for completion and to send/receive data. The routine does not wait. Callers must call mprWaitForCmd to wait for the command to complete. */ PUBLIC int mprStartCmd(MprCmd *cmd, int argc, cchar **argv, cchar **envp, int flags) { MprPath info; cchar *pair; int rc, next, i; assert(cmd); assert(argv); if (argc <= 0 || argv == NULL || argv[0] == NULL) { return MPR_ERR_BAD_ARGS; } resetCmd(cmd, 0); cmd->flags = flags; cmd->argc = argc; cmd->argv = mprAlloc((argc + 1) * sizeof(char*)); for (i = 0; i < argc; i++) { cmd->argv[i] = sclone(argv[i]); } cmd->argv[i] = 0; prepWinProgram(cmd); if ((cmd->program = mprSearchPath(cmd->argv[0], MPR_SEARCH_EXE, cmd->searchPath, NULL)) == 0) { mprLog("error mpr cmd", 0, "Cannot access %s, errno %d", cmd->argv[0], mprGetOsError()); return MPR_ERR_CANT_ACCESS; } if (mprGetPathInfo(cmd->program, &info) == 0 && info.isDir) { mprLog("error mpr cmd", 0, "Program \"%s\", is a directory", cmd->program); return MPR_ERR_CANT_ACCESS; } mprLog("info mpr cmd", 6, "Program: %s", cmd->program); cmd->argv[0] = cmd->program; prepWinCommand(cmd); if (envp == 0) { envp = cmd->defaultEnv; } if (blendEnv(cmd, envp, flags) < 0) { return MPR_ERR_MEMORY; } for (i = 0; i < cmd->argc; i++) { mprLog("info mpr cmd", 6, " arg[%d]: %s", i, cmd->argv[i]); } for (ITERATE_ITEMS(cmd->env, pair, next)) { mprLog("info mpr cmd", 6, " env[%d]: %s", next, pair); } slock(cmd); if (makeCmdIO(cmd) < 0) { sunlock(cmd); return MPR_ERR_CANT_OPEN; } /* Determine how many end-of-files will be seen when the child dies */ cmd->requiredEof = 0; if (cmd->flags & MPR_CMD_OUT) { cmd->requiredEof++; } if (cmd->flags & MPR_CMD_ERR) { cmd->requiredEof++; } if (addCmdHandlers(cmd) < 0) { mprLog("error mpr cmd", 0, "Cannot open command handlers - insufficient I/O handles"); return MPR_ERR_CANT_OPEN; } rc = startProcess(cmd); cmd->originalPid = cmd->pid; mprAddItem(MPR->cmdService->cmds, cmd); sunlock(cmd); #if ME_WIN_LIKE if (!rc) { mprCreateTimerEvent(cmd->dispatcher, "pollWinTimer", 10, pollWinTimer, cmd, 0); } #endif return rc; }
/* Return an iterator to enumerate the bytes in the file. For use with "for each ..." iterator native function getValues(): Iterator */ static EjsObj *getFileValues(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { mprGetPathInfo(fp->path, &fp->info); return (EjsObj*) ejsCreateIterator(ejs, fp, -1, nextValue, 0, NULL); }
static void outputLine(HttpQueue *q, MprDirEntry *ep, cchar *path, int nameSize) { MprPath info; MprTime when; Dir *dir; char *newPath, sizeBuf[16], timeBuf[48], *icon; struct tm tm; bool isDir; int len; cchar *ext, *mimeType; char *dirSuffix; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; path = mprEscapeHtml(path); dir = q->conn->data; if (ep->size >= (1024 * 1024 * 1024)) { fmtNum(sizeBuf, sizeof(sizeBuf), (int) ep->size, 1024 * 1024 * 1024, "G"); } else if (ep->size >= (1024 * 1024)) { fmtNum(sizeBuf, sizeof(sizeBuf), (int) ep->size, 1024 * 1024, "M"); } else if (ep->size >= 1024) { fmtNum(sizeBuf, sizeof(sizeBuf), (int) ep->size, 1024, "K"); } else { fmt(sizeBuf, sizeof(sizeBuf), "%6d", (int) ep->size); } newPath = mprJoinPath(path, ep->name); if (mprGetPathInfo(newPath, &info) < 0) { when = mprGetTime(); isDir = 0; } else { isDir = info.isDir ? 1 : 0; when = (MprTime) info.mtime * MPR_TICKS_PER_SEC; } if (isDir) { icon = "folder"; dirSuffix = "/"; } else { ext = mprGetPathExt(ep->name); if (ext && (mimeType = mprLookupMime(q->conn->rx->route->mimeTypes, ext)) != 0) { if (strcmp(ext, "es") == 0 || strcmp(ext, "ejs") == 0 || strcmp(ext, "php") == 0) { icon = "text"; } else if (strstr(mimeType, "text") != 0) { icon = "text"; } else { icon = "compressed"; } } else { icon = "compressed"; } dirSuffix = ""; } mprDecodeLocalTime(&tm, when); fmt(timeBuf, sizeof(timeBuf), "%02d-%3s-%4d %02d:%02d", tm.tm_mday, months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour, tm.tm_min); len = (int) strlen(ep->name) + (int) strlen(dirSuffix); if (dir->fancyIndexing == 2) { httpWrite(q, "<tr><td valign=\"top\">"); httpWrite(q, "<img src=\"/icons/%s.gif\" alt=\"[ ]\", /></td>", icon); httpWrite(q, "<td><a href=\"%s%s\">%s%s</a></td>", ep->name, dirSuffix, ep->name, dirSuffix); httpWrite(q, "<td>%s</td><td>%s</td></tr>\r\n", timeBuf, sizeBuf); } else if (dir->fancyIndexing == 1) { httpWrite(q, "<img src=\"/icons/%s.gif\" alt=\"[ ]\", /> ", icon); httpWrite(q, "<a href=\"%s%s\">%s%s</a>%-*s %17s %4s\r\n", ep->name, dirSuffix, ep->name, dirSuffix, nameSize - len, "", timeBuf, sizeBuf); } else { httpWrite(q, "<li><a href=\"%s%s\"> %s%s</a></li>\r\n", ep->name, dirSuffix, ep->name, dirSuffix); } }
/* Return the default iterator for use with "for ... in". This returns byte offsets in the file. iterator native function get(): Iterator */ static EjsIterator *getFileIterator(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { mprGetPathInfo(fp->path, &fp->info); return ejsCreateIterator(ejs, fp, -1, nextKey, 0, NULL); }