/* Test if a request has expired relative to the default inactivity and request timeout limits. Set timeout to a non-zero value to apply an overriding smaller timeout Set timeout to a value in msec. If timeout is zero, override default limits and wait forever. If timeout is < 0, use default inactivity and duration timeouts. If timeout is > 0, then use this timeout as an additional timeout. */ PUBLIC bool httpRequestExpired(HttpConn *conn, MprTicks timeout) { HttpLimits *limits; MprTicks inactivityTimeout, requestTimeout; limits = conn->limits; if (mprGetDebugMode() || timeout == 0) { inactivityTimeout = requestTimeout = MPR_MAX_TIMEOUT; } else if (timeout < 0) { inactivityTimeout = limits->inactivityTimeout; requestTimeout = limits->requestTimeout; } else { inactivityTimeout = min(limits->inactivityTimeout, timeout); requestTimeout = min(limits->requestTimeout, timeout); } if (mprGetRemainingTicks(conn->started, requestTimeout) < 0) { if (requestTimeout != timeout) { httpTrace(conn, "timeout.duration", "error", "msg:'Request cancelled exceeded max duration',timeout:%lld", requestTimeout / 1000); } return 1; } if (mprGetRemainingTicks(conn->lastActivity, inactivityTimeout) < 0) { if (inactivityTimeout != timeout) { httpTrace(conn, "timeout.inactivity", "error", "msg:'Request cancelled due to inactivity',timeout:%lld", inactivityTimeout / 1000); } return 1; } return 0; }
/* Wait for I/O on all registered descriptors. Timeout is in milliseconds. Return the number of events serviced. Should only be called by the thread that calls mprServiceEvents */ PUBLIC void mprWaitForIO(MprWaitService *ws, MprTicks timeout) { MSG msg; assert(ws->hwnd); if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } #if BIT_DEBUG if (mprGetDebugMode() && timeout > 30000) { timeout = 30000; } #endif if (ws->needRecall) { mprDoWaitRecall(ws); return; } SetTimer(ws->hwnd, 0, (UINT) timeout, NULL); mprYield(MPR_YIELD_STICKY); if (GetMessage(&msg, NULL, 0, 0) == 0) { mprResetYield(); mprTerminate(MPR_EXIT_DEFAULT, -1); } else { mprClearWaiting(); mprResetYield(); TranslateMessage(&msg); DispatchMessage(&msg); } ws->wakeRequested = 0; }
/* Wait for I/O on all registered file descriptors. Timeout is in milliseconds. Return the number of events detected. */ PUBLIC void mprWaitForIO(MprWaitService *ws, MprTicks timeout) { struct epoll_event events[ME_MAX_EVENTS]; int nevents; if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } #if ME_DEBUG if (mprGetDebugMode() && timeout > 30000) { timeout = 30000; } #endif if (ws->needRecall) { mprDoWaitRecall(ws); return; } mprYield(MPR_YIELD_STICKY); if ((nevents = epoll_wait(ws->epoll, events, sizeof(events) / sizeof(struct epoll_event), timeout)) < 0) { if (errno != EINTR) { mprLog("error mpr event", 0, "epoll returned %d, errno %d", nevents, mprGetOsError()); } } mprClearWaiting(); mprResetYield(); if (nevents > 0) { serviceIO(ws, events, nevents); } ws->wakeRequested = 0; }
/* * Service I/O and return a count of characters that can be read without blocking. If the proces has completed, * then return 1 to indicate that read can be called. */ static int serviceCmdEvents(MprCmd *cmd, int channel, int timeout) { int rc, count, status; if (mprGetDebugMode(cmd)) { timeout = MAXINT; } if (cmd->files[channel].handle) { rc = PeekNamedPipe(cmd->files[channel].handle, NULL, 0, NULL, &count, NULL); if (rc && count > 0) { return count; } } if (cmd->process == 0) { return 1; } if ((status = WaitForSingleObject(cmd->process, timeout)) == WAIT_OBJECT_0) { if (cmd->requiredEof == 0) { mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); mprSignalCond(cmd->completeCond); return 0; } return 1; } return 0; }
/* * Start the host timer. This may create multiple timers -- no worry. maAddConn does its best to only schedule one. */ static void startTimer(MaHost *host) { if (mprGetDebugMode(host)) { return; } mprCreateTimerEvent(host, (MprEventProc) hostTimer, MA_TIMER_PERIOD, MPR_NORMAL_PRIORITY, host, MPR_EVENT_CONTINUOUS); }
bool MprTest::waitForTest(int timeout) { int mark; mark = mprGetTime(0); if (mprGetDebugMode()) { timeout = INT_MAX - mark - timeout - 1; } #if BLD_FEATURE_MULTITHREAD if (session->isRunningEventsThread()) { if (cond->waitForCond(timeout) < 0) { mprLog(1, "wait timeout %d, on test %s\n", timeout, getName()); return 0; } } else #endif { // // Use a short-nap here as complete may get set after testing at // the top of the loop and we may do a long wait for an event // that has already happened. // while (! condWakeFlag && mprGetTime(0) < (mark + timeout)) { session->getMprp()->serviceEvents(1, MPR_TEST_POLL_NAP); } if (condWakeFlag == 0) { mprLog(1, "wait2 timeout %d, on test %s\n", timeout, getName()); return 0; } condWakeFlag = 0; } return 1; }
void mprBreakpoint(char *file, int line, char *msg) { if (! mprGetDebugMode()) { return; } #if BLD_DEBUG #if BLD_HOST_CPU_ARCH == MPR_CPU_IX86 || BLD_HOST_CPU_ARCH == MPR_CPU_IX64 #if WIN __asm { int 3 } #else // abort(); asm("int $03"); // __asm__ __volatile__ ("int $03"); #endif #endif // IX86 #endif // BLD_DEBUG }
static int setupUnixSignals(Mpr *mpr) { struct sigaction act; _signalMpr = mpr; memset(&act, 0, sizeof(act)); act.sa_sigaction = catchSignal; act.sa_flags = 0; /* * Mask these when processing signals */ sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGALRM); sigaddset(&act.sa_mask, SIGCHLD); sigaddset(&act.sa_mask, SIGPIPE); sigaddset(&act.sa_mask, SIGTERM); sigaddset(&act.sa_mask, SIGUSR1); sigaddset(&act.sa_mask, SIGUSR2); if (!mprGetDebugMode(mpr)) { sigaddset(&act.sa_mask, SIGINT); } /* * Catch thse signals */ sigaction(SIGINT, &act, 0); sigaction(SIGQUIT, &act, 0); sigaction(SIGTERM, &act, 0); sigaction(SIGUSR1, &act, 0); /* * Ignore pipe signals */ signal(SIGPIPE, SIG_IGN); #if LINUX /* * Ignore signals from write requests to large files */ signal(SIGXFSZ, SIG_IGN); #endif return 0; }
static void setupSignals() { #if BLD_UNIX_LIKE struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_sigaction = catchSignal; act.sa_flags = 0; /* Mask these when processing signals */ sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGALRM); sigaddset(&act.sa_mask, SIGCHLD); sigaddset(&act.sa_mask, SIGPIPE); sigaddset(&act.sa_mask, SIGTERM); sigaddset(&act.sa_mask, SIGUSR1); sigaddset(&act.sa_mask, SIGUSR2); if (!mprGetDebugMode(NULL)) { sigaddset(&act.sa_mask, SIGINT); } /* Catch these signals */ sigaction(SIGINT, &act, 0); sigaction(SIGQUIT, &act, 0); sigaction(SIGTERM, &act, 0); sigaction(SIGUSR1, &act, 0); /* Ignore pipe signals */ signal(SIGPIPE, SIG_IGN); #if LINUX /* Ignore signals from write requests to large files */ signal(SIGXFSZ, SIG_IGN); #endif #endif /* BLD_UNIX_LIKE */ }
/* Wait for an event to complete signified by the 'completion' flag being set. This will wait for events on the dispatcher. The completion flag will be reset on return. */ PUBLIC bool mprWaitForCompletion(MprDispatcher *dispatcher, MprTicks timeout) { MprTicks mark; bool success; assert(timeout >= 0); if (dispatcher == 0) { dispatcher = MPR->dispatcher; } if (mprGetDebugMode()) { timeout *= 100; } for (mark = mprGetTicks(); !(dispatcher->flags & MPR_DISPATCHER_COMPLETE) && mprGetElapsedTicks(mark) < timeout; ) { mprWaitForEvent(dispatcher, 10, -1); } success = (dispatcher->flags & MPR_DISPATCHER_COMPLETE) ? 1 : 0; dispatcher->flags &= ~MPR_DISPATCHER_COMPLETE; return success; }
/* Wait for a command to complete. Return 0 if the command completed, otherwise it will return MPR_ERR_TIMEOUT. */ PUBLIC int mprWaitForCmd(MprCmd *cmd, MprTicks timeout) { MprTicks expires, remaining, delay; int64 dispatcherMark; assert(cmd); if (timeout < 0) { timeout = MAXINT; } if (mprGetDebugMode()) { timeout = MAXINT; } if (cmd->stopped) { timeout = 0; } expires = mprGetTicks() + timeout; remaining = timeout; /* Add root to allow callers to use mprRunCmd without first managing the cmd */ mprAddRoot(cmd); dispatcherMark = mprGetEventMark(cmd->dispatcher); while (!cmd->complete && remaining > 0) { if (mprShouldAbortRequests()) { break; } delay = (cmd->eofCount >= cmd->requiredEof) ? 10 : remaining; if (!MPR->eventing) { mprServiceEvents(delay, MPR_SERVICE_NO_BLOCK); delay = 0; } mprWaitForEvent(cmd->dispatcher, delay, dispatcherMark); remaining = (expires - mprGetTicks()); dispatcherMark = mprGetEventMark(cmd->dispatcher); } mprRemoveRoot(cmd); if (cmd->pid) { return MPR_ERR_TIMEOUT; } return 0; }
/* * Wait for a command to complete. Return 0 if the command completed, otherwise return MPR_ERR_TIMEOUT. * This will call mprReapCmd if requried. */ int mprWaitForCmd(MprCmd *cmd, int timeout) { MprTime mark; int complete, rc; if (timeout < 0) timeout = MAXINT; if (mprGetDebugMode(cmd)) timeout = MAXINT; mark = mprGetTime(cmd); complete = 0; do { if (cmd->requiredEof == 0) { if (mprReapCmd(cmd, 10) == 0) { mprSignalCond(cmd->completeCond); return 0; } } mprPollCmdPipes(cmd, timeout); rc = mprWaitForCondWithService(cmd->completeCond, 10); if (rc == 0) { complete++; break; } else if (rc != MPR_ERR_TIMEOUT) { mprAssert(0); } } while (mprGetElapsedTime(cmd, mark) <= timeout); if (!complete) { mprLog(cmd, 7, "cmd: mprWaitForCmd: timeout waiting for command to complete"); return MPR_ERR_TIMEOUT; } if (cmd->pid) { mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); } mprLog(cmd, 7, "cmd: waitForChild: status %d", cmd->status); return 0; }
PUBLIC void httpAddConn(HttpConn *conn) { Http *http; http = HTTP; http->now = mprGetTicks(); assert(http->now >= 0); conn->started = http->now; mprAddItem(http->connections, conn); updateCurrentDate(); lock(http); conn->seqno = (int) ++http->totalConnections; if (!http->timer) { #if ME_DEBUG if (!mprGetDebugMode()) #endif { http->timer = mprCreateTimerEvent(NULL, "httpTimer", HTTP_TIMER_PERIOD, httpTimer, http, MPR_EVENT_CONTINUOUS | MPR_EVENT_QUICK); } } unlock(http); }
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; }
int MaClient::sendRequest(char *host, int port, MprBuf* hdrBuf, char *postData, int postLen) { int len, rc; lock(); reset(); mprLog(3, tMod, "sendRequest: %s:%d\n", host, port); timestamp = mprGetTime(0); if (timeoutPeriod < 0) { timeoutPeriod = MPR_HTTP_CLIENT_TIMEOUT; } if (timeoutPeriod > 0) { if (!mprGetDebugMode()) { timer = new MprTimer(MPR_HTTP_TIMER_PERIOD, timeoutWrapper, (void *) this); } } if (sock == 0) { sock = new MprSocket(); mprLog(3, tMod, "Opening new socket on: %s:%d\n", host, port); rc = sock->openClient(host, port, MPR_SOCKET_NODELAY); if (rc < 0) { mprLog(MPR_ERROR, tMod, "Can't open socket on %s:%d, %d\n", host, port, rc); unlock(); sock->dispose(); sock = 0; return rc; } sock->setBufSize(-1, MPR_HTTP_CLIENT_BUFSIZE); } else { mprLog(3, tMod, "Reusing Keep-Alive socket on: %s:%d\n", host, port); } // // Remove this flush when pipelining is supported // inBuf->flush(); fd = sock->getFd(); // // Flush to the socket with any post data. Writes can fail because the // server prematurely closes a keep-alive connection. // len = hdrBuf->getLength(); if ((rc = sock->write(hdrBuf->getStart(), len)) != len) { flags |= MPR_HTTP_TERMINATED; unlock(); mprLog(MPR_ERROR, tMod, "Can't write to socket on %s:%d, %d\n", host, port, rc); return rc; } hdrBuf->addNull(); if (postData) { sock->setBlockingMode(1); if ((rc = sock->write(postData, postLen)) != postLen) { flags |= MPR_HTTP_TERMINATED; unlock(); mprLog(MPR_ERROR, tMod, "Can't write post data to socket on %s:%d, %d\n", host, port, rc); return rc; } sock->setBlockingMode(0); } sock->setCallback(readEventWrapper, (void*) this, 0, MPR_READABLE); // // If no callback, then we must block // if (callback == 0) { unlock(); while (state != MPR_HTTP_CLIENT_DONE) { // // If multithreaded and the events thread is not yet running, // we still want to work. // #if BLD_FEATURE_MULTITHREAD if (mprGetMpr()->isRunningEventsThread()) { completeCond->waitForCond(250); } else #endif mprGetMpr()->serviceEvents(1, 100); } } else { unlock(); } return 0; }
int MaClient::sendCore(char *method, char *requestUrl, char *postData, int postLen) { char abuf[MPR_HTTP_MAX_PASS * 2], encDetails[MPR_HTTP_MAX_PASS * 2]; char *host; int port, len, rc, nbytes; mprAssert(requestUrl && *requestUrl); lock(); reset(); mprLog(3, tMod, "sendCore: %s %s\n", method, requestUrl); this->method = mprStrdup(method); timestamp = mprGetTime(0); if (timeoutPeriod < 0) { timeoutPeriod = MPR_HTTP_CLIENT_TIMEOUT; } if (timeoutPeriod > 0) { if (!mprGetDebugMode()) { timer = new MprTimer(MPR_HTTP_TIMER_PERIOD, timeoutWrapper, (void *) this); } } if (*requestUrl == '/') { url.parse(requestUrl); host = (proxyHost) ? proxyHost : defaultHost; port = (proxyHost) ? proxyPort : defaultPort; } else { url.parse(requestUrl); host = (proxyHost) ? proxyHost : url.host; port = (proxyHost) ? proxyPort : url.port; } if (sock) { if (port != currentPort || strcmp(host, currentHost) != 0) { // // This request is for a different host or port. Must close socket. // sock->close(0); sock->dispose(); sock = 0; } } if (sock == 0) { sock = new MprSocket(); mprLog(3, tMod, "Opening new socket on: %s:%d\n", host, port); rc = sock->openClient(host, port, MPR_SOCKET_NODELAY); if (rc < 0) { mprLog(MPR_ERROR, tMod, "Can't open socket on %s:%d, %d\n", host, port, rc); unlock(); sock->dispose(); sock = 0; return rc; } sock->setBufSize(-1, MPR_HTTP_CLIENT_BUFSIZE); currentHost = mprStrdup(host); currentPort = port; } else { mprLog(3, tMod, "Reusing Keep-Alive socket on: %s:%d\n", host, port); } // // Remove this flush when pipelining is supported // inBuf->flush(); fd = sock->getFd(); if (proxyHost && *proxyHost) { if (url.query && *url.query) { outBuf->putFmt("%s http://%s:%d%s?%s HTTP/1.1\r\n", method, proxyHost, proxyPort, url.uri, url.query); } else { outBuf->putFmt("%s http://%s:%d%s HTTP/1.1\r\n", method, proxyHost, proxyPort, url.uri); } } else { if (url.query && *url.query) { outBuf->putFmt("%s %s?%s HTTP/1.1\r\n", method, url.uri, url.query); } else { outBuf->putFmt("%s %s HTTP/1.1\r\n", method, url.uri); } } if (serverAuthType) { if (strcmp(serverAuthType, "basic") == 0) { mprSprintf(abuf, sizeof(abuf), "%s:%s", user, password); maEncode64(encDetails, sizeof(encDetails), abuf); outBuf->putFmt("Authorization: %s %s\r\n", serverAuthType, encDetails); #if BLD_FEATURE_DIGEST } else if (strcmp(serverAuthType, "digest") == 0) { char a1Buf[256], a2Buf[256], digestBuf[256]; char *ha1, *ha2, *digest, *qop; authNc++; if (secret == 0) { if (createSecret() < 0) { mprLog(MPR_ERROR, tMod, "Can't create secret\n"); return MPR_ERR_CANT_INITIALIZE; } } mprFree(authCnonce); maCalcNonce(&authCnonce, secret, 0, realm); mprSprintf(a1Buf, sizeof(a1Buf), "%s:%s:%s", user, realm, password); ha1 = maMD5(a1Buf); mprSprintf(a2Buf, sizeof(a2Buf), "%s:%s", method, url.uri); ha2 = maMD5(a2Buf); qop = (serverQop) ? serverQop : (char*) ""; if (mprStrCmpAnyCase(serverQop, "auth") == 0) { mprSprintf(digestBuf, sizeof(digestBuf), "%s:%s:%08x:%s:%s:%s", ha1, serverNonce, authNc, authCnonce, serverQop, ha2); } else if (mprStrCmpAnyCase(serverQop, "auth-int") == 0) { mprSprintf(digestBuf, sizeof(digestBuf), "%s:%s:%08x:%s:%s:%s", ha1, serverNonce, authNc, authCnonce, serverQop, ha2); } else { qop = ""; mprSprintf(digestBuf, sizeof(digestBuf), "%s:%s:%s", ha1, serverNonce, ha2); } mprFree(ha1); mprFree(ha2); digest = maMD5(digestBuf); if (*qop == '\0') { outBuf->putFmt("Authorization: Digest " "username=\"%s\", realm=\"%s\", nonce=\"%s\", " "uri=\"%s\", response=\"%s\"\r\n", user, realm, serverNonce, url.uri, digest); } else if (strcmp(qop, "auth") == 0) { outBuf->putFmt("Authorization: Digest " "username=\"%s\", realm=\"%s\", domain=\"%s\", " "algorithm=\"MD5\", qop=\"%s\", cnonce=\"%s\", " "nc=\"%08x\", nonce=\"%s\", opaque=\"%s\", " "stale=\"FALSE\", uri=\"%s\", response=\"%s\"\r\n", user, realm, serverDomain, serverQop, authCnonce, authNc, serverNonce, serverOpaque, url.uri, digest); } else if (strcmp(qop, "auth-int") == 0) { ; } mprFree(digest); #endif // BLD_FEATURE_HTTP_DIGEST } } outBuf->putFmt("Host: %s\r\n", host); outBuf->putFmt("User-Agent: %s\r\n", MPR_HTTP_CLIENT_NAME); if (userFlags & MPR_HTTP_KEEP_ALIVE) { outBuf->putFmt("Connection: Keep-Alive\r\n"); } else { outBuf->putFmt("Connection: close\r\n"); } if (postLen > 0) { outBuf->putFmt("Content-Length: %d\r\n", postLen); } if (postData) { outBuf->putFmt("Content-Type: application/x-www-form-urlencoded\r\n"); } if (userHeaders) { outBuf->put(userHeaders); } outBuf->put("\r\n"); outBuf->addNull(); // // Flush to the socket with any post data. Writes can fail because the // server prematurely closes a keep-alive connection. // len = outBuf->getLength(); if ((rc = sock->write(outBuf->getStart(), len)) != len) { flags |= MPR_HTTP_TERMINATED; unlock(); mprLog(MPR_ERROR, tMod, "Can't write to socket on %s:%d, %d\n", host, port, rc); return rc; } #if BLD_DEBUG mprLog(3, MPR_RAW, tMod, "Request >>>>\n%s\n", outBuf->getStart()); #endif if (postData) { sock->setBlockingMode(1); for (len = 0; len < postLen; ) { nbytes = postLen - len; rc = sock->write(&postData[len], nbytes); #if BLD_DEBUG mprLog(3, MPR_RAW, tMod, "POST DATA %s\n", &postData[len]); #endif if (rc < 0) { unlock(); mprLog(MPR_ERROR, tMod, "Can't write post data to socket on %s:%d, %d\n", host, port, rc); flags |= MPR_HTTP_TERMINATED; sock->dispose(); sock = 0; return rc; } len += rc; } sock->setBlockingMode(0); } sock->setCallback(readEventWrapper, (void*) this, 0, MPR_READABLE); // // If no callback, then we must block // if (callback == 0) { unlock(); while (state != MPR_HTTP_CLIENT_DONE) { // // If multithreaded and the events thread is not yet running, // we still want to work. // #if BLD_FEATURE_MULTITHREAD if (mprGetMpr()->isRunningEventsThread() && mprGetMpr()->poolService->getMaxPoolThreads() > 0) { completeCond->waitForCond(250); } else #endif mprGetMpr()->serviceEvents(1, 100); } } else { unlock(); } 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); }
static int isDebugMode(EjsFiber *fp, EjsVar *thisObj, int argc, EjsVar **argv) { ejsTrace(fp, "isDebugMode()\n"); ejsSetReturnValueToInteger(fp, mprGetDebugMode(fp)); return 0; }
/* The http timer does maintenance activities and will fire per second while there are active requests. This routine will also be called by httpTerminate with event == 0 to signify a shutdown. NOTE: Because we lock the http here, connections cannot be deleted while we are modifying the list. */ static void httpTimer(Http *http, MprEvent *event) { HttpConn *conn; HttpStage *stage; HttpLimits *limits; MprModule *module; int next, active, abort; updateCurrentDate(); /* Check for any inactive connections or expired requests (inactivityTimeout and requestTimeout) OPT - could check for expired connections every 10 seconds. */ lock(http->connections); for (active = 0, next = 0; (conn = mprGetNextItem(http->connections, &next)) != 0; active++) { limits = conn->limits; if (!conn->timeoutEvent) { abort = mprIsStopping(); if (httpServerConn(conn) && (HTTP_STATE_CONNECTED < conn->state && conn->state < HTTP_STATE_PARSED) && (http->now - conn->started) > limits->requestParseTimeout) { conn->timeout = HTTP_PARSE_TIMEOUT; abort = 1; } else if ((http->now - conn->lastActivity) > limits->inactivityTimeout) { conn->timeout = HTTP_INACTIVITY_TIMEOUT; abort = 1; } else if ((http->now - conn->started) > limits->requestTimeout) { conn->timeout = HTTP_REQUEST_TIMEOUT; abort = 1; } else if (!event) { /* Called directly from httpStop to stop connections */ if (MPR->exitTimeout > 0) { if (conn->state == HTTP_STATE_COMPLETE || (HTTP_STATE_CONNECTED < conn->state && conn->state < HTTP_STATE_PARSED)) { abort = 1; } } else { abort = 1; } } if (abort && !mprGetDebugMode()) { httpScheduleConnTimeout(conn); } } } /* Check for unloadable modules OPT - could check for modules every minute */ if (mprGetListLength(http->connections) == 0) { for (next = 0; (module = mprGetNextItem(MPR->moduleService->modules, &next)) != 0; ) { if (module->timeout) { if (module->lastActivity + module->timeout < http->now) { mprLog("info http", 2, "Unloading inactive module %s", module->name); if ((stage = httpLookupStage(module->name)) != 0) { if (mprUnloadModule(module) < 0) { active++; } else { stage->flags |= HTTP_STAGE_UNLOADED; } } else { mprUnloadModule(module); } } else { active++; } } } } httpPruneMonitors(); if (active == 0 || mprIsStopping()) { if (event) { mprRemoveEvent(event); } http->timer = 0; /* Going to sleep now, so schedule a GC to free as much as possible. */ mprGC(MPR_GC_FORCE | MPR_GC_NO_BLOCK); } else { mprGC(MPR_GC_NO_BLOCK); } unlock(http->connections); }
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 (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; }