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; }
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; }