Example #1
0
/*
    Destroy a connection. This removes the connection from the list of connections.
 */
PUBLIC void httpDestroyConn(HttpConn *conn)
{
    if (!conn->destroyed && !conn->borrowed) {
        HTTP_NOTIFY(conn, HTTP_EVENT_DESTROY, 0);
        if (httpServerConn(conn)) {
            httpMonitorEvent(conn, HTTP_COUNTER_ACTIVE_CONNECTIONS, -1);
            if (conn->activeRequest) {
                httpMonitorEvent(conn, HTTP_COUNTER_ACTIVE_REQUESTS, -1);
                conn->activeRequest = 0;
            }
        }
        httpRemoveConn(conn);
        conn->input = 0;
        if (conn->tx) {
            httpClosePipeline(conn);
        }
        if (conn->sock) {
            mprCloseSocket(conn->sock, 0);
        }
        if (conn->dispatcher && conn->dispatcher->flags & MPR_DISPATCHER_AUTO) {
            mprDestroyDispatcher(conn->dispatcher);
        }
        conn->destroyed = 1;
    }
}
Example #2
0
void httpMatchHost(HttpConn *conn)
{ 
    MprSocket       *listenSock;
    HttpEndpoint    *endpoint;
    HttpHost        *host;
    Http            *http;

    http = conn->http;
    listenSock = conn->sock->listenSock;

    if ((endpoint = httpLookupEndpoint(http, listenSock->ip, listenSock->port)) == 0) {
        mprError("No listening endpoint for request from %s:%d", listenSock->ip, listenSock->port);
        mprCloseSocket(conn->sock, 0);
        return;
    }
    if (httpHasNamedVirtualHosts(endpoint)) {
        host = httpLookupHostOnEndpoint(endpoint, conn->rx->hostHeader);
    } else {
        host = mprGetFirstItem(endpoint->hosts);
    }
    if (host == 0) {
        httpSetConnHost(conn, 0);
        httpError(conn, HTTP_CODE_NOT_FOUND, "No host to serve request. Searching for %s", conn->rx->hostHeader);
        conn->host = mprGetFirstItem(endpoint->hosts);
        return;
    }
    if (conn->rx->traceLevel >= 0) {
        mprLog(conn->rx->traceLevel, "Select host: \"%s\"", host->name);
    }
    conn->host = host;
}
Example #3
0
void httpDestroyEndpoint(HttpEndpoint *endpoint)
{
    destroyEndpointConnections(endpoint);
    if (endpoint->sock) {
        mprCloseSocket(endpoint->sock, 0);
        endpoint->sock = 0;
    }
    httpRemoveEndpoint(MPR->httpService, endpoint);
}
Example #4
0
void httpStopEndpoint(HttpEndpoint *endpoint)
{
    HttpHost    *host;
    int         next;

    for (ITERATE_ITEMS(endpoint->hosts, host, next)) {
        httpStopHost(host);
    }
    if (endpoint->sock) {
        mprCloseSocket(endpoint->sock, 0);
        endpoint->sock = 0;
    }
}
Example #5
0
/*
 *  Cleanup a connection. Invoked automatically whenever the connection is freed.
 */
static int connectionDestructor(MaConn *conn)
{
    mprAssert(conn);
    mprAssert(conn->host);
    mprAssert(conn->sock);

    /*
     *  Must remove from the connection list first. This ensures that the host timer will not find the connection 
     *  nor mess with it anymore.
     */
    maRemoveConn(conn->host, conn);

    if (conn->sock) {
        mprLog(conn, 4, "Closing connection fd %d", conn->sock->fd);
        mprCloseSocket(conn->sock, conn->connectionFailed ? 0 : MPR_SOCKET_GRACEFUL);
        mprFree(conn->sock);
    }
    return 0;
}
Example #6
0
static HttpConn *openConnection(HttpConn *conn, struct MprSsl *ssl)
{
    Http        *http;
    HttpUri     *uri;
    MprSocket   *sp;
    char        *ip;
    int         port, rc;

    assert(conn);

    http = conn->http;
    uri = conn->tx->parsedUri;

    if (!uri->host) {
        ip = (http->proxyHost) ? http->proxyHost : http->defaultClientHost;
        port = (http->proxyHost) ? http->proxyPort : http->defaultClientPort;
    } else {
        ip = (http->proxyHost) ? http->proxyHost : uri->host;
        port = (http->proxyHost) ? http->proxyPort : uri->port;
    }
    if (port == 0) {
        port = (uri->secure) ? 443 : 80;
    }
    if (conn && conn->sock) {
        if (conn->keepAliveCount-- <= 0 || port != conn->port || strcmp(ip, conn->ip) != 0 ||
                uri->secure != (conn->sock->ssl != 0) || conn->sock->ssl != ssl) {
            /* 
                Cannot reuse current socket. Close and open a new one below.
             */
            mprCloseSocket(conn->sock, 0);
            conn->sock = 0;
        } else {
            httpTrace(conn, "connection.reuse", "context", "keepAlive:%d", conn->keepAliveCount);
        }
    }
    if (conn->sock) {
        return conn;
    }

    /*
        New socket
     */
    if ((sp = mprCreateSocket()) == 0) {
        httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Cannot create socket for %s", httpUriToString(uri, 0));
        return 0;
    }
    if ((rc = mprConnectSocket(sp, ip, port, MPR_SOCKET_NODELAY)) < 0) {
        httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Cannot open socket on %s:%d", ip, port);
        return 0;
    }
    conn->sock = sp;
    conn->ip = sclone(ip);
    conn->port = port;
    conn->keepAliveCount = (conn->limits->keepAliveMax) ? conn->limits->keepAliveMax : 0;

#if ME_COM_SSL
    /*
        Must be done even if using keep alive for repeat SSL requests
     */
    if (uri->secure) {
        char *peerName;
        if (ssl == 0) {
            ssl = mprCreateSsl(0);
        }
        peerName = isdigit(uri->host[0]) ? 0 : uri->host;
        if (mprUpgradeSocket(sp, ssl, peerName) < 0) {
            conn->errorMsg = sp->errorMsg;
            httpTrace(conn, "connection.upgrade.error", "error", "msg:'Cannot perform SSL upgrade. %s'", conn->errorMsg);
            return 0;
        }
        if (sp->peerCert) {
            httpTrace(conn, "context", "connection.ssl",
                "msg:'Connection secured with peer certificate', " \
                "secure:true,cipher:'%s',peerName:'%s',subject:'%s',issuer:'%s'",
                sp->cipher, sp->peerName, sp->peerCert, sp->peerCertIssuer);
        }
    }
#endif
#if ME_HTTP_WEB_SOCKETS
    if (uri->webSockets && httpUpgradeWebSocket(conn) < 0) {
        conn->errorMsg = sp->errorMsg;
        return 0;
    }
#endif
    httpTrace(conn, "connection.peer", "context", "peer:'%s:%d'", conn->ip, conn->port);
    return conn;
}
Example #7
0
/*  
    Accept a new client connection on a new socket. If multithreaded, this will come in on a worker thread 
    dedicated to this connection. This is called from the listen wait handler.
 */
HttpConn *httpAcceptConn(HttpEndpoint *endpoint, MprEvent *event)
{
    HttpConn        *conn;
    MprSocket       *sock;
    MprDispatcher   *dispatcher;
    MprEvent        e;
    int             level;

    mprAssert(endpoint);
    mprAssert(event);

    /*
        This will block in sync mode until a connection arrives
     */
    if ((sock = mprAcceptSocket(endpoint->sock)) == 0) {
        if (endpoint->sock->handler) {
            mprEnableSocketEvents(endpoint->sock, MPR_READABLE);
        }
        return 0;
    }
    if (endpoint->ssl) {
        if (mprUpgradeSocket(sock, endpoint->ssl, 1) < 0) {
            mprCloseSocket(sock, 0);
            return 0;
        }
    }
    if (endpoint->sock->handler) {
        /* Re-enable events on the listen socket */
        mprEnableSocketEvents(endpoint->sock, MPR_READABLE);
    }
    dispatcher = event->dispatcher;

    if (mprShouldDenyNewRequests()) {
        mprCloseSocket(sock, 0);
        return 0;
    }
    if ((conn = httpCreateConn(endpoint->http, endpoint, dispatcher)) == 0) {
        mprCloseSocket(sock, 0);
        return 0;
    }
    conn->notifier = endpoint->notifier;
    conn->async = endpoint->async;
    conn->endpoint = endpoint;
    conn->sock = sock;
    conn->port = sock->port;
    conn->ip = sclone(sock->ip);
    conn->secure = (endpoint->ssl != 0);

    if (!httpValidateLimits(endpoint, HTTP_VALIDATE_OPEN_CONN, conn)) {
        conn->endpoint = 0;
        httpDestroyConn(conn);
        return 0;
    }
    mprAssert(conn->state == HTTP_STATE_BEGIN);
    httpSetState(conn, HTTP_STATE_CONNECTED);

    if ((level = httpShouldTrace(conn, HTTP_TRACE_RX, HTTP_TRACE_CONN, NULL)) >= 0) {
        mprLog(level, "### Incoming connection from %s:%d to %s:%d %s", 
            conn->ip, conn->port, sock->acceptIp, sock->acceptPort, conn->secure ? "(secure)" : "");
    }
    e.mask = MPR_READABLE;
    e.timestamp = conn->http->now;
    (conn->ioCallback)(conn, &e);
    return conn;
}
Example #8
0
PUBLIC int httpConnect(HttpStream *stream, cchar *method, cchar *url, MprSsl *ssl)
{
    HttpNet     *net;
    HttpTx      *tx;
    HttpUri     *uri;
    cchar       *ip, *protocol;
    int         port;

    assert(stream);
    assert(method && *method);
    assert(url && *url);

    net = stream->net;
    if (httpServerStream(stream)) {
        mprLog("client error", 0, "Cannot call httpConnect() in a server");
        return MPR_ERR_BAD_STATE;
    }
    if (net->protocol <= 0) {
        mprLog("client error", 0, "HTTP protocol to use has not been defined");
        return MPR_ERR_BAD_STATE;
    }
    if (stream->tx == 0 || stream->state != HTTP_STATE_BEGIN) {
        httpResetClientStream(stream, 0);
    }
    tx = stream->tx;
    tx->method = supper(method);
    stream->authRequested = 0;
    stream->startMark = mprGetHiResTicks();

    if ((uri = tx->parsedUri = httpCreateUri(url, HTTP_COMPLETE_URI_PATH)) == 0) {
        return MPR_ERR_BAD_ARGS;
    }
    ssl = uri->secure ? (ssl ? ssl : mprCreateSsl(0)) : 0;
    httpGetUriAddress(uri, &ip, &port);

    if (net->sock) {
        if (net->error) {
            mprCloseSocket(net->sock, 0);
            net->sock = 0;

        } else if (canUse(net, stream, uri, ssl, ip, port)) {
            httpLog(net->trace, "client.connection.reuse", "context", "reuse:%d", stream->keepAliveCount);

        } else {
            if (net->protocol >= 2) {
                if (mprGetListLength(net->streams) > 1) {
                    httpError(stream, HTTP_CODE_COMMS_ERROR, "Cannot use network for %s due to other existing requests", ip);
                    return MPR_ERR_CANT_FIND;
                }
            } else {
                mprCloseSocket(net->sock, 0);
                net->sock = 0;
            }
        }
    }
    if (!net->sock) {
        if (httpConnectNet(net, ip, port, ssl) < 0) {
            return MPR_ERR_CANT_CONNECT;
        }
        stream->net = net;
        stream->sock = net->sock;
        stream->ip = net->ip;
        stream->port = net->port;
        stream->keepAliveCount = (net->protocol >= 2) ? 0 : stream->limits->keepAliveMax;

#if ME_HTTP_WEB_SOCKETS
        if (net->protocol == 1 && uri->webSockets && httpUpgradeWebSocket(stream) < 0) {
            stream->errorMsg = net->errorMsg = net->sock->errorMsg;
            return 0;
        }
#endif
    }
    httpCreatePipeline(stream);
    setDefaultHeaders(stream);
    httpSetState(stream, HTTP_STATE_CONNECTED);
    protocol = net->protocol < 2 ? "HTTP/1.1" : "HTTP/2";
    httpLog(net->trace, "client.request", "request", "method='%s', url='%s', protocol='%s'", tx->method, url, protocol);
    return 0;
}
Example #9
0
/*
    Accept a new client connection on a new socket.
    This will come in on a worker thread with a new dispatcher dedicated to this connection.
 */
PUBLIC HttpConn *httpAcceptConn(HttpEndpoint *endpoint, MprEvent *event)
{
    Http        *http;
    HttpConn    *conn;
    HttpAddress *address;
    MprSocket   *sock;
    int64       value;

    assert(event);
    assert(event->dispatcher);
    assert(endpoint);

    sock = event->sock;
    http = endpoint->http;

    if (mprShouldDenyNewRequests()) {
        mprCloseSocket(sock, 0);
        return 0;
    }
    if ((conn = httpCreateConn(endpoint, event->dispatcher)) == 0) {
        mprCloseSocket(sock, 0);
        return 0;
    }
    conn->notifier = endpoint->notifier;
    conn->async = endpoint->async;
    conn->endpoint = endpoint;
    conn->sock = sock;
    conn->port = sock->port;
    conn->ip = sclone(sock->ip);

    if ((value = httpMonitorEvent(conn, HTTP_COUNTER_ACTIVE_CONNECTIONS, 1)) > conn->limits->connectionsMax) {
        httpTrace(conn, "connection.accept.error", "error", "msg:'Too many concurrent connections',active:%d,max:%d", 
            (int) value, conn->limits->connectionsMax);
        httpDestroyConn(conn);
        return 0;
    }
    if (mprGetHashLength(http->addresses) > conn->limits->clientMax) {
        httpTrace(conn, "connection.accept.error", "error", "msg:'Too many concurrent clients',active:%d,max:%d", 
            mprGetHashLength(http->addresses), conn->limits->clientMax);
        httpDestroyConn(conn);
        return 0;
    }
    address = conn->address;
    if (address && address->banUntil) {
        if (address->banUntil < http->now) {
            httpTrace(conn, "monitor.ban.stop", "context", "client:'%s'", conn->ip);
            address->banUntil = 0;
        } else {
            if (address->banStatus) {
                httpError(conn, HTTP_CLOSE | address->banStatus,
                    "Connection refused, client banned: %s", address->banMsg ? address->banMsg : "");
            } else {
                httpDestroyConn(conn);
                return 0;
            }
        }
    }
    if (endpoint->ssl) {
        if (mprUpgradeSocket(sock, endpoint->ssl, 0) < 0) {
            httpDisconnect(conn);
            httpTrace(conn, "connection.upgrade.error", "error", "msg:'Cannot upgrade socket. %s'", sock->errorMsg);
            httpMonitorEvent(conn, HTTP_COUNTER_SSL_ERRORS, 1);
            httpDestroyConn(conn);
            return 0;
        }
    }
    assert(conn->state == HTTP_STATE_BEGIN);
    httpSetState(conn, HTTP_STATE_CONNECTED);

    httpTrace(conn, "connection.accept.new", "context", "peer:'%s',endpoint:'%s:%d'", 
        conn->ip, sock->acceptIp, sock->acceptPort);
    
    event->mask = MPR_READABLE;
    event->timestamp = conn->http->now;
    (conn->ioCallback)(conn, event);
    return conn;
}