/* function get verifyIssuer(): Boolean */ static EjsBoolean *http_verifyIssuer(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } return hp->ssl->verifyIssuer ? ESV(true) : ESV(false); }
/* function WebSocket(uri: Uri, protocols = null, options) options = { certificate: Path, verify: Boolean, } */ static EjsWebSocket *wsConstructor(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsAny *certificate; bool verify; assert(ejsIsPot(ejs, ws)); ejsLoadHttpService(ejs); ws->ejs = ejs; verify = 0; ws->uri = httpUriToString(((EjsUri*) argv[0])->uri, 0); if (argc >= 2) { if (ejsIs(ejs, argv[1], Array)) { ws->protocols = sclone((ejsToString(ejs, argv[1]))->value); } else if (ejsIs(ejs, argv[1], String)) { ws->protocols = sclone(((EjsString*) argv[1])->value); } else { ws->protocols = sclone("chat"); } } else { ws->protocols = sclone("chat"); } if (*ws->protocols == '\0') { ejsThrowArgError(ejs, "Bad protocol"); return 0; } if (argc >= 3) { ws->frames = ejsGetPropertyByName(ejs, argv[2], EN("frames")) == ESV(true); verify = ejsGetPropertyByName(ejs, argv[2], EN("verify")) == ESV(true); if ((certificate = ejsGetPropertyByName(ejs, argv[2], EN("certificate"))) != 0) { ws->certFile = ejsToMulti(ejs, argv[0]); } } if ((ws->conn = httpCreateConn(MPR->httpService, NULL, ejs->dispatcher)) == 0) { ejsThrowMemoryError(ejs); return 0; } httpSetAsync(ws->conn, 1); httpPrepClientConn(ws->conn, 0); httpSetConnNotifier(ws->conn, webSocketNotify); httpSetWebSocketProtocols(ws->conn, ws->protocols); httpSetConnContext(ws->conn, ws); if (sstarts(ws->uri, "wss")) { ws->ssl = mprCreateSsl(0); mprVerifySslIssuer(ws->ssl, verify); mprVerifySslPeer(ws->ssl, verify); #if FUTURE if (!hp->caFile) { //MOB - Some define for this. hp->caFile = mprJoinPath(mprGetAppDir(), "http-ca.crt"); } mprSetSslCaFile(hp->ssl, hp->caFile); mprSetSslCaFile(hp->ssl, mprJoinPath(mprGetAppDir(), "http-ca.crt")); #endif } startWebSocketRequest(ejs, ws); return ws; }
/* function set provider(name: String): Void */ static EjsObj *http_set_provider(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } mprSetSslProvider(hp->ssl, ejsToMulti(ejs, argv[0])); return 0; }
/* function secure(keyFile: Path, certFile: Path!, protocols: Array? = null, ciphers: Array? = null): Void */ static EjsObj *hs_secure(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { #if ME_COM_SSL EjsArray *protocols; cchar *token; int mask, protoMask, i; if (sp->ssl == 0 && ((sp->ssl = mprCreateSsl(1)) == 0)) { return 0; } if (!ejsIs(ejs, argv[0], Null)) { mprSetSslKeyFile(sp->ssl, ejsToMulti(ejs, argv[0])); } if (!ejsIs(ejs, argv[1], Null)) { mprSetSslCertFile(sp->ssl, ejsToMulti(ejs, argv[1])); } if (argc >= 3 && ejsIs(ejs, argv[2], Array)) { protocols = (EjsArray*) argv[2]; protoMask = 0; for (i = 0; i < protocols->length; i++) { token = ejsToMulti(ejs, ejsGetProperty(ejs, protocols, i)); mask = -1; if (*token == '-') { token++; mask = 0; } else if (*token == '+') { token++; } if (scaselesscmp(token, "SSLv2") == 0) { protoMask &= ~(MPR_PROTO_SSLV2 & ~mask); protoMask |= (MPR_PROTO_SSLV2 & mask); } else if (scaselesscmp(token, "SSLv3") == 0) { protoMask &= ~(MPR_PROTO_SSLV3 & ~mask); protoMask |= (MPR_PROTO_SSLV3 & mask); } else if (scaselesscmp(token, "TLSv1") == 0) { protoMask &= ~(MPR_PROTO_TLSV1 & ~mask); protoMask |= (MPR_PROTO_TLSV1 & mask); } else if (scaselesscmp(token, "ALL") == 0) { protoMask &= ~(MPR_PROTO_ALL & ~mask); protoMask |= (MPR_PROTO_ALL & mask); } } mprSetSslProtocols(sp->ssl, protoMask); } if (argc >= 4 && ejsIs(ejs, argv[3], Array)) { mprSetSslCiphers(sp->ssl, ejsToMulti(ejs, argv[3])); } #else ejsThrowReferenceError(ejs, "SSL support was not included in the build"); #endif return 0; }
/* function set verifyIssuer(on: Boolean): Void */ static EjsObj *http_set_verifyIssuer(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { int verifyIssuer; verifyIssuer = (argv[0] == ESV(true)); if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } mprVerifySslIssuer(hp->ssl, verifyIssuer); return 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; }
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; }
MAIN(httpMain, int argc, char **argv, char **envp) { MprTime start; double elapsed; if (mprCreate(argc, argv, MPR_USER_EVENTS_THREAD) == 0) { return MPR_ERR_MEMORY; } if ((app = mprAllocObj(App, manageApp)) == 0) { return MPR_ERR_MEMORY; } mprAddRoot(app); mprAddStandardSignals(); initSettings(); if (!parseArgs(argc, argv)) { showUsage(); return MPR_ERR_BAD_ARGS; } mprSetMaxWorkers(app->workers); #if BIT_FEATURE_SSL if (!mprLoadSsl(1)) { mprError("Can't load SSL"); exit(1); } if (app->insecure || app->cert) { app->ssl = mprCreateSsl(); mprVerifySslServers(app->ssl, !app->insecure); if (app->cert) { mprSetSslCertFile(app->ssl, app->cert); } } #endif if (mprStart() < 0) { mprError("Can't start MPR for %s", mprGetAppTitle()); exit(2); } start = mprGetTime(); app->http = httpCreate(); httpEaseLimits(app->http->clientLimits); processing(); mprServiceEvents(-1, 0); if (app->benchmark) { elapsed = (double) (mprGetTime() - start); if (app->fetchCount == 0) { elapsed = 0; app->fetchCount = 1; } mprPrintf("\nRequest Count: %13d\n", app->fetchCount); mprPrintf("Time elapsed: %13.4f sec\n", elapsed / 1000.0); mprPrintf("Time per request: %13.4f sec\n", elapsed / 1000.0 / app->fetchCount); mprPrintf("Requests per second: %13.4f\n", app->fetchCount * 1.0 / (elapsed / 1000.0)); mprPrintf("Load threads: %13d\n", app->loadThreads); mprPrintf("Worker threads: %13d\n", app->workers); } if (!app->success && app->verbose) { mprError("Request failed"); } return (app->success) ? 0 : 255; }
/* 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; }
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; }
/* Upgrade a standard socket to use SSL/TLS. Used by both clients and servers to upgrade a socket for SSL. If a client, this may block while connecting. */ static int upgradeOss(MprSocket *sp, MprSsl *ssl, cchar *requiredPeerName) { OpenSocket *osp; OpenConfig *cfg; int rc; assert(sp); if (ssl == 0) { ssl = mprCreateSsl(sp->flags & MPR_SOCKET_SERVER); } if ((osp = (OpenSocket*) mprAllocObj(OpenSocket, manageOpenSocket)) == 0) { return MPR_ERR_MEMORY; } osp->sock = sp; sp->sslSocket = osp; sp->ssl = ssl; lock(ssl); if (configOss(ssl, sp->flags, &sp->errorMsg) < 0) { unlock(ssl); return MPR_ERR_CANT_INITIALIZE; } unlock(ssl); /* Create and configure the SSL struct */ cfg = osp->cfg = sp->ssl->config; if ((osp->handle = (SSL*) SSL_new(cfg->ctx)) == 0) { return MPR_ERR_BAD_STATE; } SSL_set_app_data(osp->handle, (void*) osp); /* Create a socket bio. We don't use the BIO except as storage for the fd */ if ((osp->bio = BIO_new_socket((int) sp->fd, BIO_NOCLOSE)) == 0) { return MPR_ERR_BAD_STATE; } SSL_set_bio(osp->handle, osp->bio, osp->bio); if (sp->flags & MPR_SOCKET_SERVER) { SSL_set_accept_state(osp->handle); } else { if (requiredPeerName) { osp->requiredPeerName = sclone(requiredPeerName); #if OPENSSL_VERSION_NUMBER >= 0x10002000L X509_VERIFY_PARAM *param = param = SSL_get0_param(osp->handle); X509_VERIFY_PARAM_set_hostflags(param, 0); X509_VERIFY_PARAM_set1_host(param, requiredPeerName, 0); #endif } /* Block while connecting */ mprSetSocketBlockingMode(sp, 1); sp->errorMsg = 0; if ((rc = SSL_connect(osp->handle)) < 1) { if (sp->errorMsg) { mprLog("info mpr ssl openssl", 4, "Connect failed: %s", sp->errorMsg); } else { mprLog("info mpr ssl openssl", 4, "Connect failed: error %s", getOssError(sp)); } return MPR_ERR_CANT_CONNECT; } if (rc > 0 && checkPeerCertName(sp) < 0) { return MPR_ERR_CANT_CONNECT; } setSecured(sp); mprSetSocketBlockingMode(sp, 0); } #if defined(ME_MPR_SSL_RENEGOTIATE) && !ME_MPR_SSL_RENEGOTIATE /* Disable renegotiation after the initial handshake if renegotiate is explicitly set to false (CVE-2009-3555). Note: this really is a bogus CVE as disabling renegotiation is not required nor does it enhance security if used with up-to-date (patched) SSL stacks. */ if (osp->handle->s3) { osp->handle->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } #endif return 0; }
static int parseArgs(int argc, char **argv) { char *argp, *key, *value; int i, setWorkers, nextArg, ssl; setWorkers = 0; ssl = 0; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--auth")) { if (nextArg >= argc) { return showUsage(); } else { app->authType = slower(argv[++nextArg]); } } else if (smatch(argp, "--benchmark") || smatch(argp, "-b")) { app->benchmark++; } else if (smatch(argp, "--ca")) { if (nextArg >= argc) { return showUsage(); } else { app->ca = sclone(argv[++nextArg]); if (!mprPathExists(app->ca, R_OK)) { mprError("Cannot find ca file %s", app->ca); return MPR_ERR_BAD_ARGS; } } ssl = 1; } else if (smatch(argp, "--cert")) { if (nextArg >= argc) { return showUsage(); } else { app->cert = sclone(argv[++nextArg]); if (!mprPathExists(app->cert, R_OK)) { mprError("Cannot find cert file %s", app->cert); return MPR_ERR_BAD_ARGS; } } ssl = 1; } else if (smatch(argp, "--chunk")) { if (nextArg >= argc) { return showUsage(); } else { value = argv[++nextArg]; app->chunkSize = atoi(value); if (app->chunkSize < 0) { mprError("Bad chunksize %d", app->chunkSize); return MPR_ERR_BAD_ARGS; } } } else if (smatch(argp, "--ciphers")) { if (nextArg >= argc) { return showUsage(); } else { app->ciphers = sclone(argv[++nextArg]); } ssl = 1; } else if (smatch(argp, "--continue") || smatch(argp, "-c")) { app->continueOnErrors++; } else if (smatch(argp, "--cookie")) { if (nextArg >= argc) { return showUsage(); } else { mprAddItem(app->headers, mprCreateKeyPair("Cookie", argv[++nextArg], 0)); } } else if (smatch(argp, "--data")) { if (nextArg >= argc) { return showUsage(); } else { if (app->bodyData == 0) { app->bodyData = mprCreateBuf(-1, -1); } mprPutStringToBuf(app->bodyData, argv[++nextArg]); } } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); app->retries = 0; app->timeout = MAXINT; } else if (smatch(argp, "--delete")) { app->method = "DELETE"; } else if (smatch(argp, "--form") || smatch(argp, "-f")) { if (nextArg >= argc) { return showUsage(); } else { if (app->formData == 0) { app->formData = mprCreateList(-1, 0); } addFormVars(argv[++nextArg]); } } else if (smatch(argp, "--header")) { if (nextArg >= argc) { return showUsage(); } else { key = argv[++nextArg]; if ((value = strchr(key, ':')) == 0) { mprError("Bad header format. Must be \"key: value\""); return MPR_ERR_BAD_ARGS; } *value++ = '\0'; while (isspace((uchar) *value)) { value++; } mprAddItem(app->headers, mprCreateKeyPair(key, value, 0)); } } else if (smatch(argp, "--host")) { if (nextArg >= argc) { return showUsage(); } else { app->host = argv[++nextArg]; if (*app->host == ':') { app->host = &app->host[1]; } if (isPort(app->host)) { app->host = sfmt("http://127.0.0.1:%s", app->host); } else { app->host = sclone(app->host); } } } else if (smatch(argp, "--iterations") || smatch(argp, "-i")) { if (nextArg >= argc) { return showUsage(); } else { app->iterations = atoi(argv[++nextArg]); } } else if (smatch(argp, "--key")) { if (nextArg >= argc) { return showUsage(); } else { app->key = sclone(argv[++nextArg]); if (!mprPathExists(app->key, R_OK)) { mprError("Cannot find key file %s", app->key); return MPR_ERR_BAD_ARGS; } } ssl = 1; } else if (smatch(argp, "--log") || smatch(argp, "-l")) { if (nextArg >= argc) { return showUsage(); } else { mprStartLogging(argv[++nextArg], 0); } } else if (smatch(argp, "--method") || smatch(argp, "-m")) { if (nextArg >= argc) { return showUsage(); } else { app->method = argv[++nextArg]; } } else if (smatch(argp, "--out") || smatch(argp, "-o")) { if (nextArg >= argc) { return showUsage(); } else { app->outFilename = sclone(argv[++nextArg]); } } else if (smatch(argp, "--noout") || smatch(argp, "-n") || smatch(argp, "--quiet") || smatch(argp, "-q")) { app->noout++; } else if (smatch(argp, "--nofollow")) { app->nofollow++; } else if (smatch(argp, "--password") || smatch(argp, "-p")) { if (nextArg >= argc) { return showUsage(); } else { app->password = sclone(argv[++nextArg]); } } else if (smatch(argp, "--post")) { app->method = "POST"; } else if (smatch(argp, "--printable")) { app->printable++; } else if (smatch(argp, "--protocol")) { if (nextArg >= argc) { return showUsage(); } else { app->protocol = supper(argv[++nextArg]); } } else if (smatch(argp, "--provider")) { /* Undocumented SSL provider selection */ if (nextArg >= argc) { return showUsage(); } else { app->provider = sclone(argv[++nextArg]); } ssl = 1; } else if (smatch(argp, "--put")) { app->method = "PUT"; } else if (smatch(argp, "--range")) { if (nextArg >= argc) { return showUsage(); } else { if (app->ranges == 0) { app->ranges = sfmt("bytes=%s", argv[++nextArg]); } else { app->ranges = srejoin(app->ranges, ",", argv[++nextArg], NULL); } } } else if (smatch(argp, "--retries") || smatch(argp, "-r")) { if (nextArg >= argc) { return showUsage(); } else { app->retries = atoi(argv[++nextArg]); } } else if (smatch(argp, "--self")) { /* Undocumented. Allow self-signed certs. Users should just not set --verify */ app->verifyIssuer = 0; ssl = 1; } else if (smatch(argp, "--sequence")) { app->sequence++; } else if (smatch(argp, "--showHeaders") || smatch(argp, "--show") || smatch(argp, "-s")) { app->showHeaders++; } else if (smatch(argp, "--showStatus") || smatch(argp, "--showCode")) { app->showStatus++; } else if (smatch(argp, "--single") || smatch(argp, "-s")) { app->singleStep++; } else if (smatch(argp, "--text")) { app->text++; } else if (smatch(argp, "--threads") || smatch(argp, "-t")) { if (nextArg >= argc) { return showUsage(); } else { app->loadThreads = atoi(argv[++nextArg]); } } else if (smatch(argp, "--timeout")) { if (nextArg >= argc) { return showUsage(); } else { app->timeout = atoi(argv[++nextArg]) * MPR_TICKS_PER_SEC; } } else if (smatch(argp, "--upload") || smatch(argp, "-u")) { app->upload++; } else if (smatch(argp, "--user") || smatch(argp, "--username")) { if (nextArg >= argc) { return showUsage(); } else { app->username = argv[++nextArg]; } // DEPRECATE validate. Preserve verify. } else if (smatch(argp, "--validate") || smatch(argp, "--verify")) { app->verifyPeer = 1; ssl = 1; } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { app->verbose++; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprEprintf("%s %s\n" "Copyright (C) Embedthis Software 2003-2013\n" "Copyright (C) Michael O'Brien 2003-2013\n", BIT_TITLE, BIT_VERSION); exit(0); } else if (smatch(argp, "--workerTheads") || smatch(argp, "-w")) { if (nextArg >= argc) { return showUsage(); } else { app->workers = atoi(argv[++nextArg]); } setWorkers++; } else if (smatch(argp, "--zero")) { app->zeroOnErrors++; } else if (smatch(argp, "--")) { nextArg++; break; } else if (smatch(argp, "-")) { break; } else { return showUsage(); } } if (argc == nextArg) { return showUsage(); } app->nextArg = nextArg; argc = argc - nextArg; argv = &argv[nextArg]; app->target = argv[argc - 1]; if (--argc > 0) { /* Files present on command line */ app->files = mprCreateList(argc, MPR_LIST_STATIC_VALUES); for (i = 0; i < argc; i++) { mprAddItem(app->files, argv[i]); } } if (!setWorkers) { app->workers = app->loadThreads + 2; } if (app->method == 0) { if (app->bodyData || app->formData || app->upload) { app->method = "POST"; } else if (app->files) { app->method = "PUT"; } else { app->method = "GET"; } } #if BIT_PACK_SSL { HttpUri *uri = httpCreateUri(app->target, 0); if (uri->secure || ssl) { app->ssl = mprCreateSsl(0); if (app->provider) { mprSetSslProvider(app->ssl, app->provider); } if (app->cert) { if (!app->key) { mprError("Must specify key file"); return 0; } mprSetSslCertFile(app->ssl, app->cert); mprSetSslKeyFile(app->ssl, app->key); } if (app->ca) { mprLog(4, "Using CA: \"%s\"", app->ca); mprSetSslCaFile(app->ssl, app->ca); } if (app->verifyIssuer == -1) { app->verifyIssuer = app->verifyPeer ? 1 : 0; } mprVerifySslPeer(app->ssl, app->verifyPeer); mprVerifySslIssuer(app->ssl, app->verifyIssuer); if (app->ciphers) { mprSetSslCiphers(app->ssl, app->ciphers); } } else { mprVerifySslPeer(NULL, 0); } } #else /* Suppress comp warning */ mprNop(&ssl); #endif return 0; }
static HttpConn *openConnection(HttpConn *conn, cchar *url, struct MprSsl *ssl) { Http *http; HttpUri *uri; MprSocket *sp; char *ip; int port, rc, level; mprAssert(conn); http = conn->http; uri = httpCreateUri(url, HTTP_COMPLETE_URI); conn->tx->parsedUri = uri; if (*url == '/') { 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) { httpCloseConn(conn); } else { mprLog(4, "Http: reusing keep-alive socket on: %s:%d", ip, port); } } if (conn->sock) { return conn; } if ((sp = mprCreateSocket()) == 0) { httpError(conn, HTTP_CODE_COMMS_ERROR, "Can't create socket for %s", url); return 0; } if ((rc = mprConnectSocket(sp, ip, port, 0)) < 0) { httpError(conn, HTTP_CODE_COMMS_ERROR, "Can't open socket on %s:%d", ip, port); return 0; } #if BIT_PACK_SSL /* Must be done even if using keep alive for repeat SSL requests */ if (uri->secure) { if (ssl == 0) { ssl = mprCreateSsl(); } if (mprUpgradeSocket(sp, ssl, 0) < 0) { conn->errorMsg = sp->errorMsg; return 0; } } #endif conn->sock = sp; conn->ip = sclone(ip); conn->port = port; conn->secure = uri->secure; conn->keepAliveCount = (conn->limits->keepAliveMax) ? conn->limits->keepAliveMax : -1; if ((level = httpShouldTrace(conn, HTTP_TRACE_RX, HTTP_TRACE_CONN, NULL)) >= 0) { mprLog(level, "### Outgoing connection from %s:%d to %s:%d", conn->ip, conn->port, conn->sock->ip, conn->sock->port); } return conn; }