Пример #1
0
PUBLIC void httpReturnConn(HttpConn *conn)
{
    assert(conn->borrowed);
    if (conn->borrowed) {
        conn->borrowed = 0;
        mprRemoveRoot(conn);
        httpEnableConnEvents(conn);
    }
}
Пример #2
0
static void connTimeout(HttpConn *conn, MprEvent *mprEvent)
{
    HttpLimits  *limits;
    cchar       *event, *msg, *prefix;

    if (conn->destroyed) {
        return;
    }
    assert(conn->tx);
    assert(conn->rx);

    msg = 0;
    event = 0;
    limits = conn->limits;
    assert(limits);

    if (conn->timeoutCallback) {
        (conn->timeoutCallback)(conn);
    }
    if (!conn->connError) {
        prefix = (conn->state == HTTP_STATE_BEGIN) ? "Idle connection" : "Request";
        if (conn->timeout == HTTP_PARSE_TIMEOUT) {
            msg = sfmt("%s exceeded parse headers timeout of %lld sec", prefix, limits->requestParseTimeout  / 1000);
            event = "timeout.parse";

        } else if (conn->timeout == HTTP_INACTIVITY_TIMEOUT) {
            msg = sfmt("%s exceeded inactivity timeout of %lld sec", prefix, limits->inactivityTimeout / 1000);
            event = "timeout.inactivity";

        } else if (conn->timeout == HTTP_REQUEST_TIMEOUT) {
            msg = sfmt("%s exceeded timeout %lld sec", prefix, limits->requestTimeout / 1000);
            event = "timeout.duration";
        }
        if (conn->state < HTTP_STATE_FIRST) {
            httpDisconnect(conn);
            if (msg) {
                httpTrace(conn, event, "error", "msg:'%s'", msg);
            }
        } else {
            httpError(conn, HTTP_CODE_REQUEST_TIMEOUT, "%s", msg);
        }
    }
    if (httpClientConn(conn)) {
        httpDestroyConn(conn);
    } else {
        httpEnableConnEvents(conn);
    }
}
Пример #3
0
static EjsObj *startWebSocketRequest(Ejs *ejs, EjsWebSocket *ws)
{
    HttpConn        *conn;

    conn = ws->conn;
    if (ws->certFile) {
        if (!ws->ssl) {
            ws->ssl = mprCreateSsl(0);
        }
        mprSetSslCertFile(ws->ssl, ws->certFile);
    }
    if (httpConnect(conn, "GET", ws->uri, ws->ssl) < 0) {
        ejsThrowIOError(ejs, "Cannot issue request for \"%s\"", ws->uri);
        return 0;
    }
    httpEnableConnEvents(ws->conn);
    return 0;
}
Пример #4
0
/*
    function write(...data): Void
 */
static EjsNumber *http_write(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv)
{
    ssize     nbytes;

    hp->data = ejsCreateByteArray(ejs, -1);
    if (ejsWriteToByteArray(ejs, hp->data, 1, &argv[0]) < 0) {
        return 0;
    }
    if ((nbytes = writeHttpData(ejs, hp)) < 0) {
        return 0;
    }
    hp->writeCount += nbytes;
    if (hp->conn->async) {
        if (ejsGetByteArrayAvailableData(hp->data) > 0) {
            httpEnableConnEvents(hp->conn);
        }
    }
    return ejsCreateNumber(ejs, (MprNumber) nbytes);
}
Пример #5
0
static void receiveRequest(EjsRequest *req, MprEvent *event)
{
    Ejs             *ejs;
    EjsAny          *argv[1];
    EjsFunction     *onrequest;
    HttpConn        *conn;

    conn = req->conn;
    ejs = req->ejs;
    assert(ejs);

    onrequest = ejsGetProperty(ejs, req->server, ES_ejs_web_HttpServer_onrequest);
    if (!ejsIsFunction(ejs, onrequest)) {
        ejsThrowStateError(ejs, "HttpServer.onrequest is not a function");
        return;
    }
    argv[0] = req;
    ejsRunFunction(ejs, onrequest, req->server, 1, argv);
    if (conn->state == HTTP_STATE_BEGIN) {
        conn->ejs = 0;
        httpUsePrimary(conn);
    }
    httpEnableConnEvents(conn);
}
Пример #6
0
/*
    Wait for the connection to reach a given state.
    Should only be used on the client side.
    @param state Desired state. Set to zero if you want to wait for one I/O event.
    @param timeout Timeout in msec. If timeout is zero, wait forever. If timeout is < 0, use default inactivity
        and duration timeouts.
 */
PUBLIC int httpWait(HttpConn *conn, int state, MprTicks timeout)
{
    HttpLimits  *limits;
    MprTicks    delay, start;
    int64       dispatcherMark;
    int         justOne;

    limits = conn->limits;
    if (conn->endpoint) {
        assert(!conn->endpoint);
        return MPR_ERR_BAD_STATE;
    }
    if (conn->state <= HTTP_STATE_BEGIN) {
        return MPR_ERR_BAD_STATE;
    }
    if (state == 0) {
        /* Wait for just one I/O event */
        state = HTTP_STATE_FINALIZED;
        justOne = 1;
    } else {
        justOne = 0;
    }
    if (conn->error) {
        if (conn->state >= state) {
            return 0;
        }
        return MPR_ERR_BAD_STATE;
    }
    if (timeout < 0) {
        timeout = limits->requestTimeout;
    } else if (timeout == 0) {
        timeout = MPR_MAX_TIMEOUT;
    }
    if (state > HTTP_STATE_CONTENT) {
        httpFinalizeOutput(conn);
    }
    start = conn->http->now;
    dispatcherMark = mprGetEventMark(conn->dispatcher);
    while (conn->state < state && !conn->error && !mprIsSocketEof(conn->sock)) {
        if (httpRequestExpired(conn, -1)) {
            return MPR_ERR_TIMEOUT;
        }
        httpEnableConnEvents(conn);
        delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout));
        delay = max(delay, 0);
        mprWaitForEvent(conn->dispatcher, delay, dispatcherMark);
        if (justOne || (mprGetRemainingTicks(start, timeout) <= 0)) {
            break;
        }
        dispatcherMark = mprGetEventMark(conn->dispatcher);
    }
    if (conn->error) {
        return MPR_ERR_NOT_READY;
    }
    if (conn->state < state) {
        if (mprGetRemainingTicks(start, timeout) <= 0) {
            return MPR_ERR_TIMEOUT;
        }
        if (!justOne) {
            return MPR_ERR_CANT_READ;
        }
    }
    conn->lastActivity = conn->http->now;
    return 0;
}
Пример #7
0
/*
    Read data. If sync mode, this will block. If async, will never block.
    Will return what data is available up to the requested size.
    Timeout in milliseconds to wait. Set to -1 to use the default inactivity timeout. Set to zero to wait forever.
    Returns a count of bytes read. Returns zero if no data. EOF if returns zero and conn->state is > HTTP_STATE_CONTENT.
 */
PUBLIC ssize httpReadBlock(HttpConn *conn, char *buf, ssize size, MprTicks timeout, int flags)
{
    HttpPacket  *packet;
    HttpQueue   *q;
    HttpLimits  *limits;
    MprBuf      *content;
    MprTicks    start, delay;
    ssize       nbytes, len;
    int64       dispatcherMark;

    q = conn->readq;
    assert(q->count >= 0);
    assert(size >= 0);
    limits = conn->limits;

    if (flags == 0) {
        flags = conn->async ? HTTP_NON_BLOCK : HTTP_BLOCK;
    }
    if (timeout < 0) {
        timeout = limits->inactivityTimeout;
    } else if (timeout == 0) {
        timeout = MPR_MAX_TIMEOUT;
    }
    if (flags & HTTP_BLOCK) {
        start = conn->http->now;
        dispatcherMark = mprGetEventMark(conn->dispatcher);
        while (q->count <= 0 && !conn->error && (conn->state <= HTTP_STATE_CONTENT)) {
            if (httpRequestExpired(conn, -1)) {
                break;
            }
            delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout));
            httpEnableConnEvents(conn);
            mprWaitForEvent(conn->dispatcher, delay, dispatcherMark);
            if (mprGetRemainingTicks(start, timeout) <= 0) {
                break;
            }
            dispatcherMark = mprGetEventMark(conn->dispatcher);
        }
    }
    for (nbytes = 0; size > 0 && q->count > 0; ) {
        if ((packet = q->first) == 0) {
            break;
        }
        content = packet->content;
        len = mprGetBufLength(content);
        len = min(len, size);
        assert(len <= q->count);
        if (len > 0) {
            len = mprGetBlockFromBuf(content, buf, len);
            assert(len <= q->count);
        }
        buf += len;
        size -= len;
        q->count -= len;
        assert(q->count >= 0);
        nbytes += len;
        if (mprGetBufLength(content) == 0) {
            httpGetPacket(q);
        }
        if (flags & HTTP_NON_BLOCK) {
            break;
        }
    }
    assert(q->count >= 0);
    if (nbytes < size) {
        buf[nbytes] = '\0';
    }
    return nbytes;
}
Пример #8
0
/*
    function [get|put|delete|post...](uri = null, ...data): Http
 */
static EjsHttp *startHttpRequest(Ejs *ejs, EjsHttp *hp, char *method, int argc, EjsObj **argv)
{
    EjsArray        *args;
    EjsByteArray    *data;
    EjsNumber       *written;
    EjsUri          *uriObj;
    HttpConn        *conn;
    ssize           nbytes;

    conn = hp->conn;
    hp->responseCache = 0;
    hp->requestContentCount = 0;
    mprFlushBuf(hp->responseContent);

    if (argc >= 1 && !ejsIs(ejs, argv[0], Null)) {
        uriObj = (EjsUri*) argv[0];
        hp->uri = httpUriToString(uriObj->uri, HTTP_COMPLETE_URI);
    }
    if (argc == 2 && ejsIs(ejs, argv[1], Array)) {
        args = (EjsArray*) argv[1];
        if (args->length > 0) {
            data = ejsCreateByteArray(ejs, -1);
            written = ejsWriteToByteArray(ejs, data, 1, &argv[1]);
            mprPutBlockToBuf(hp->requestContent, (char*) data->value, (int) written->value);
            mprAddNullToBuf(hp->requestContent);
            assert(written > 0);
        }
    }
    if (hp->uri == 0) {
        ejsThrowArgError(ejs, "URL is not defined");
        return 0;
    }
    if (method && strcmp(hp->method, method) != 0) {
        hp->method = sclone(method);
    }
    if (hp->method == 0) {
        ejsThrowArgError(ejs, "HTTP Method is not defined");
        return 0;
    }
    if (hp->certFile) {
        if (!hp->ssl) {
            hp->ssl = mprCreateSsl(0);
        }
        mprSetSslCertFile(hp->ssl, hp->certFile);
        if (!hp->keyFile) {
            ejsThrowStateError(ejs, "Must define a Http.key to use with a certificate");
        }
        mprSetSslKeyFile(hp->ssl, hp->keyFile);
    }
    if (hp->caFile) {
        if (!hp->ssl) {
            hp->ssl = mprCreateSsl(0);
        }
        mprSetSslCaFile(hp->ssl, hp->caFile);
    }
    if (httpConnect(conn, hp->method, hp->uri, hp->ssl) < 0) {
        ejsThrowIOError(ejs, "Cannot issue request for \"%s\"", hp->uri);
        return 0;
    }
    if (mprGetBufLength(hp->requestContent) > 0) {
        nbytes = httpWriteBlock(conn->writeq, mprGetBufStart(hp->requestContent), mprGetBufLength(hp->requestContent),
            HTTP_BLOCK);
        if (nbytes < 0) {
            ejsThrowIOError(ejs, "Cannot write request data for \"%s\"", hp->uri);
            return 0;
        } else if (nbytes > 0) {
            assert(nbytes == mprGetBufLength(hp->requestContent));
            mprAdjustBufStart(hp->requestContent, nbytes);
            hp->requestContentCount += nbytes;
        }
        httpFinalize(conn);
    }
    httpNotify(conn, HTTP_EVENT_WRITABLE, 0);
    if (conn->async) {
        httpEnableConnEvents(hp->conn);
    }
    return hp;
}
Пример #9
0
/*
    Handle IO on the connection. Initially the conn->dispatcher will be set to the server->dispatcher and the first 
    I/O event will be handled on the server thread (or main thread). A request handler may create a new 
    conn->dispatcher and transfer execution to a worker thread if required.
 */
PUBLIC void httpIO(HttpConn *conn, int eventMask)
{
    MprSocket   *sp;

    sp = conn->sock;
    if (conn->destroyed) {
        /* Connection has been destroyed */
        return;
    }
    if (conn->state < HTTP_STATE_PARSED && mprShouldDenyNewRequests()) {
        httpDestroyConn(conn);
        return;
    }
    assert(conn->tx);
    assert(conn->rx);

#if DEPRECATED || 1
    /* Just IO state asserting */
    if (conn->io) {
        assert(!conn->io);
        return;
    }
    conn->io = 1;
#endif

    if ((eventMask & MPR_WRITABLE) && conn->connectorq) {
        httpResumeQueue(conn->connectorq);
    }
    if (eventMask & MPR_READABLE) {
        readPeerData(conn);
    }
    if (sp->secured && !conn->secure) {
        conn->secure = 1;
        if (sp->peerCert) {
            httpTrace(conn, "connection.ssl", "context", "msg:'Connection secured with peer certificate'," \
                "secure:true,cipher:'%s',peerName:'%s',subject:'%s',issuer:'%s',session:'%s'",
                sp->cipher, sp->peerName, sp->peerCert, sp->peerCertIssuer, sp->session);
        } else {
            httpTrace(conn, "connection.ssl", "context",
                "msg:'Connection secured without peer certificate',secure:true,cipher:'%s',session:'%s'",
                sp->cipher, sp->session);
        }
        if (mprGetLogLevel() >= 5) {
            mprLog("info http ssl", 5, "SSL State: %s", mprGetSocketState(sp));
        }
    }
    /*
        Process one or more complete requests in the packet
     */
    do {
        /* This is and must be the only place httpProtocol is ever called */
        httpProtocol(conn);
    } while (conn->endpoint && conn->state == HTTP_STATE_COMPLETE && prepForNext(conn));

    /*
        When a request completes, prepForNext will reset the state to HTTP_STATE_BEGIN
     */
    if (conn->state < HTTP_STATE_PARSED && conn->endpoint && (mprIsSocketEof(conn->sock) || (conn->keepAliveCount <= 0))) {
        httpDestroyConn(conn);
    } else if (!mprIsSocketEof(conn->sock) && conn->async && !conn->delay) {
        httpEnableConnEvents(conn);
    }
    conn->io = 0;
}