Пример #1
0
/*
    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;
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
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;
}
Пример #5
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);
}
Пример #6
0
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;
}
Пример #7
0
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
}
Пример #8
0
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;
}
Пример #9
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 */
}
Пример #10
0
/*
    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;
}
Пример #11
0
/*
    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;
}
Пример #12
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;
}
Пример #13
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);
}
Пример #14
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;
}
Пример #15
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;
}
Пример #16
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;
}
Пример #17
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);
}
Пример #18
0
static int isDebugMode(EjsFiber *fp, EjsVar *thisObj, int argc, EjsVar **argv)
{
    ejsTrace(fp, "isDebugMode()\n");
    ejsSetReturnValueToInteger(fp, mprGetDebugMode(fp));
    return 0;
}
Пример #19
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);
}
Пример #20
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 (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;
}