/* * Search for a handler by request extension. If that fails, use handler custom matching. * If all that fails, return the catch-all handler (fileHandler) */ static MaStage *findHandlerByExtension(MaConn *conn) { MaRequest *req; MaResponse *resp; MaStage *handler; MaLocation *location; int next; req = conn->request; resp = conn->response; location = req->location; resp->extension = getExtension(conn); if (*resp->extension) { handler = maGetHandlerByExtension(location, resp->extension); if (checkStage(conn, handler)) { return handler; } } /* * Failed to match by extension, so perform custom handler matching. May need a filename (dir handler) */ resp->filename = makeFilename(conn, req->alias, req->url, 1); for (next = 0; (handler = mprGetNextItem(location->handlers, &next)) != 0; ) { if (handler->match && handler->match(conn, handler, req->url)) { if (checkStage(conn, handler)) { resp->handler = handler; return handler; } } } /* * Failed to match. Return any catch-all handler. */ handler = maGetHandlerByExtension(location, ""); if (handler == 0) { /* * Could be missing a catch-all in the config file, so invoke the file handler. */ handler = maLookupStage(conn->http, "fileHandler"); } mprAssert(handler); // TODO - should we be setting this here? resp->handler = handler; return checkStage(conn, handler); }
int maUnloadModule(MaHttp *http, cchar *name) { MprModule *module; MaStage *stage; if ((module = mprLookupModule(http, name)) == 0) { return MPR_ERR_CANT_ACCESS; } if (module->timeout) { if ((stage = maLookupStage(http, name)) != 0) { stage->flags |= MA_STAGE_UNLOADED; } mprUnloadModule(module); } return 0; }
static int parseDir(MaHttp *http, cchar *key, char *value, MaConfigState *state) { MaStage *handler; Dir *dir; char *name, *extensions, *option, *nextTok, *junk; handler = maLookupStage(http, "dirHandler"); dir = handler->stageData; mprAssert(dir); if (mprStrcmpAnyCase(key, "AddIcon") == 0) { /* AddIcon file ext ext ext */ /* Not yet supported */ name = mprStrTok(value, " \t", &extensions); parseWords(dir->extList, extensions); return 1; } else if (mprStrcmpAnyCase(key, "DefaultIcon") == 0) { /* DefaultIcon file */ /* Not yet supported */ dir->defaultIcon = mprStrTok(value, " \t", &junk); return 1; } else if (mprStrcmpAnyCase(key, "IndexOrder") == 0) { /* IndexOrder ascending|descending name|date|size */ mprFree(dir->sortField); dir->sortField = 0; option = mprStrTok(value, " \t", &dir->sortField); if (mprStrcmpAnyCase(option, "ascending") == 0) { dir->sortOrder = 1; } else { dir->sortOrder = -1; } if (dir->sortField) { dir->sortField = mprStrdup(dir, dir->sortField); } return 1; } else if (mprStrcmpAnyCase(key, "IndexIgnore") == 0) { /* IndexIgnore pat ... */ /* Not yet supported */ parseWords(dir->ignoreList, value); return 1; } else if (mprStrcmpAnyCase(key, "IndexOptions") == 0) { /* IndexOptions FancyIndexing|FoldersFirst ... (set of options) */ option = mprStrTok(value, " \t", &nextTok); while (option) { if (mprStrcmpAnyCase(option, "FancyIndexing") == 0) { dir->fancyIndexing = 1; } else if (mprStrcmpAnyCase(option, "HTMLTable") == 0) { dir->fancyIndexing = 2; } else if (mprStrcmpAnyCase(option, "FoldersFirst") == 0) { dir->foldersFirst = 1; } option = mprStrTok(nextTok, " \t", &nextTok); } return 1; } else if (mprStrcmpAnyCase(key, "Options") == 0) { /* Options Indexes */ option = mprStrTok(value, " \t", &nextTok); while (option) { if (mprStrcmpAnyCase(option, "Indexes") == 0) { dir->enabled = 1; } option = mprStrTok(nextTok, " \t", &nextTok); } return 1; } return 0; }
static int parseEjs(MaHttp *http, cchar *key, char *value, MaConfigState *state) { MaLocation *location; MaServer *server; MaHost *host; char *prefix, *path; int flags; host = state->host; server = state->server; location = state->location; flags = location->flags & (MA_LOC_BROWSER | MA_LOC_AUTO_SESSION); #if UNUSED MaStage *ejsHandler; EjsWebControl *web; if (mprStrcmpAnyCase(key, "Ejs") == 0) { path = mprStrTrim(value, "\""); mprCleanFilename(http, path); if (!mprAccess(http, path, X_OK)) { mprError(http, "Can't access Ejs path %s", path); return MPR_ERR_BAD_SYNTAX; } if ((ejsHandler = maLookupStage(http, "ejsHandler")) == 0) { mprError(http, "Ejscript module is not loaded"); return MPR_ERR_BAD_SYNTAX; } web = (EjsWebControl*) ejsHandler->stageData; web->ejsLibDir = path; } else #endif if (mprStrcmpAnyCase(key, "EjsApp") == 0) { if (mprStrcmpAnyCase(value, "on") == 0) { location->flags |= MA_LOC_APP; } else { location->flags &= ~MA_LOC_APP; } return 1; } else if (mprStrcmpAnyCase(key, "EjsAppDir") == 0) { if (mprStrcmpAnyCase(value, "on") == 0) { location->flags |= MA_LOC_APP_DIR; } else { location->flags &= ~MA_LOC_APP_DIR; } return 1; } else if (mprStrcmpAnyCase(key, "EjsAppAlias") == 0) { if (maSplitConfigValue(server, &prefix, &path, value, 1) < 0 || path == 0 || prefix == 0) { return MPR_ERR_BAD_SYNTAX; } location = maCreateLocationAlias(http, state, prefix, path, "ejsHandler", MA_LOC_APP | flags); if (location == 0) { return MPR_ERR_BAD_SYNTAX; } return 1; } else if (mprStrcmpAnyCase(key, "EjsAppDirAlias") == 0) { if (maSplitConfigValue(server, &prefix, &path, value, 1) < 0 || path == 0 || prefix == 0) { return MPR_ERR_BAD_SYNTAX; } location = maCreateLocationAlias(http, state, prefix, path, "ejsHandler", MA_LOC_APP_DIR | flags); if (location == 0) { return MPR_ERR_BAD_SYNTAX; } return 1; } else if (mprStrcmpAnyCase(key, "EjsErrors") == 0) { if (mprStrcmpAnyCase(value, "browser") == 0) { location->flags |= MA_LOC_BROWSER; } else { location->flags &= ~MA_LOC_BROWSER; } return 1; } else if (mprStrcmpAnyCase(key, "EjsSessionTimeout") == 0) { if (value == 0) { return MPR_ERR_BAD_SYNTAX; } if (! mprGetDebugMode(http)) { location->sessionTimeout = atoi(mprStrTrim(value, "\"")); } return 1; } else if (mprStrcmpAnyCase(key, "EjsSession") == 0) { if (mprStrcmpAnyCase(value, "on") == 0) { location->flags |= MA_LOC_AUTO_SESSION; } else { location->flags &= ~MA_LOC_AUTO_SESSION; } return 1; } return 0; }
/* * The host timer does maintenance activities and will fire per second while there is active requests. * When multi-threaded, the host timer runs as an event off the service thread. Because we lock the host here, * connections cannot be deleted while we are modifying the list. */ static void hostTimer(MaHost *host, MprEvent *event) { Mpr *mpr; MaStage *stage; MaConn *conn; MprModule *module; MaHttp *http; int next, count; mprAssert(event); http = host->server->http; /* * Locking ensures connections won't be deleted */ lock(host); updateCurrentDate(host); mprLog(host, 8, "hostTimer: %d active connections", mprGetListCount(host->connections)); /* * Check for any expired connections */ for (count = 0, next = 0; (conn = mprGetNextItem(host->connections, &next)) != 0; count++) { /* * Workaround for a GCC bug when comparing two 64bit numerics directly. Need a temporary. */ int64 diff = conn->expire - host->now; if (diff < 0 && !mprGetDebugMode(host)) { conn->keepAliveCount = 0; if (!conn->disconnected) { if (conn->request) { mprLog(host, 6, "Open request timed out due to inactivity: %s", conn->request->url); } else { mprLog(host, 6, "Idle connection timed out"); } conn->disconnected = 1; mprDisconnectSocket(conn->sock); } } } /* Check for unloadable modules - must be idle */ mpr = mprGetMpr(http); if (mprGetListCount(host->connections) == 0) { for (next = 0; (module = mprGetNextItem(mpr->moduleService->modules, &next)) != 0; ) { if (module->timeout) { if (module->lastActivity + module->timeout < host->now) { if ((stage = maLookupStage(http, module->name)) != 0) { mprLog(host, 2, "Unloading inactive module %s", module->name); if (stage->match) { mprError(conn, "Can't unload modules with match routines"); module->timeout = 0; } else { maUnloadModule(http, module->name); stage->flags |= MA_STAGE_UNLOADED; } } else { maUnloadModule(http, module->name); } } else { count++; } } } } if (count == 0) { mprFree(event); host->timer = 0; } unlock(host); }