Example #1
0
File: user.c Project: ppslinux/esp
/*
    Callback from httpLogin to verify credentials using the password defined in the database.
 */
static bool verifyUser(HttpConn *conn, cchar *username, cchar *password)
{
    HttpAuth    *auth;
    HttpUser    *user;
    HttpRx      *rx;
    EdiRec      *urec;

    rx = conn->rx;
    auth = rx->route->auth;

    if ((urec = readRecWhere("user", "username", "==", username)) == 0) {
        httpTrace(conn, "auth.login.error", "error", "msg: 'Cannot verify user', username: '******'", username);
        return 0;
    }
    if (!mprCheckPassword(password, getField(urec, "password"))) {
        httpTrace(conn, "auth.login.error", "error", "msg: 'Password failed to authenticate', username: '******'", username);
        mprSleep(500);
        return 0;
    }
    /*
        Cache the user and define the user roles. Thereafter, the app can use "httpCanUser" to test if the user
        has the required abilities (defined by their roles) to perform a given request or operation.
     */
    if ((user = httpLookupUser(auth, username)) == 0) {
        user = httpAddUser(auth, username, 0, ediGetFieldValue(urec, "roles"));
    }
    httpSetConnUser(conn, user);

    httpTrace(conn, "auth.login.authenticated", "context", "msg: 'User authenticated', username: '******'", username);
    return 1;
}
Example #2
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;
}
Example #3
0
PUBLIC ssize espRenderError(HttpConn *conn, int status, cchar *fmt, ...)
{
    va_list     args;
    HttpRx      *rx;
    ssize       written;
    cchar       *msg, *title, *text;

    va_start(args, fmt);

    rx = conn->rx;
    written = 0;

    if (!httpIsFinalized(conn)) {
        if (status == 0) {
            status = HTTP_CODE_INTERNAL_SERVER_ERROR;
        }
        title = sfmt("Request Error for \"%s\"", rx->pathInfo);
        msg = mprEscapeHtml(sfmtv(fmt, args));
        if (rx->route->flags & HTTP_ROUTE_SHOW_ERRORS) {
            text = sfmt(\
                        "<!DOCTYPE html>\r\n<html>\r\n<head><title>%s</title></head>\r\n" \
                        "<body>\r\n<h1>%s</h1>\r\n" \
                        "    <pre>%s</pre>\r\n" \
                        "    <p>To prevent errors being displayed in the browser, " \
                        "       set <b>ShowErrors off</b> in the appweb.conf file.</p>\r\n" \
                        "</body>\r\n</html>\r\n", title, title, msg);
            httpSetContentType(conn, "text/html");
            written += espRenderString(conn, text);
            espFinalize(conn);
            httpTrace(conn, "esp.error", "error", "msg=\"%s\", status=%d, uri=\"%s\"", msg, status, rx->pathInfo);
        }
    }
    va_end(args);
    return written;
}
Example #4
0
/*
    Authenticate a user using the session stored username. This will set HttpRx.authenticated if authentication succeeds.
    Note: this does not call httpLogin except for auto-login cases where a password is not used.
 */
PUBLIC bool httpAuthenticate(HttpConn *conn)
{
    HttpRx      *rx;
    HttpAuth    *auth;
    cchar       *ip, *username;

    rx = conn->rx;
    auth = rx->route->auth;

    if (!rx->authenticateProbed) {
        rx->authenticateProbed = 1;
        ip = httpGetSessionVar(conn, HTTP_SESSION_IP, 0);
        username = httpGetSessionVar(conn, HTTP_SESSION_USERNAME, 0);
        if (!smatch(ip, conn->ip) || !username) {
            if (auth->username && *auth->username) {
                /* Auto-login */
                httpLogin(conn, auth->username, NULL);
                username = httpGetSessionVar(conn, HTTP_SESSION_USERNAME, 0);
            }
            if (!username) {
                return 0;
            }
        }
        httpTrace(conn, "auth.login.authenticated", "context", 
            "msg: 'Using cached authentication data', username: '******'", username);
        conn->username = username;
        rx->authenticated = 1;
    }
    return rx->authenticated;
}
Example #5
0
/*
    Open the handler for a new request
 */
static int openCgi(HttpQueue *q)
{
    HttpConn    *conn;
    Cgi         *cgi;
    int         nproc;

    conn = q->conn;
    if ((nproc = (int) httpMonitorEvent(conn, HTTP_COUNTER_ACTIVE_PROCESSES, 1)) >= conn->limits->processMax) {
        httpTrace(conn, "cgi.limit.error", "error", 
            "msg=\"Too many concurrent processes\", activeProcesses=%d, maxProcesses=%d", 
            nproc, conn->limits->processMax);
        httpError(conn, HTTP_CODE_SERVICE_UNAVAILABLE, "Server overloaded");
        httpMonitorEvent(q->conn, HTTP_COUNTER_ACTIVE_PROCESSES, -1);
        return MPR_ERR_CANT_OPEN;
    }
    if ((cgi = mprAllocObj(Cgi, manageCgi)) == 0) {
        /* Normal mem handler recovery */ 
        return MPR_ERR_MEMORY;
    }
    httpTrimExtraPath(conn);
    httpMapFile(conn);
    httpCreateCGIParams(conn);

    q->queueData = q->pair->queueData = cgi;
    cgi->conn = conn;
    cgi->readq = httpCreateQueue(conn, conn->http->cgiConnector, HTTP_QUEUE_RX, 0);
    cgi->writeq = httpCreateQueue(conn, conn->http->cgiConnector, HTTP_QUEUE_TX, 0);
    cgi->readq->pair = cgi->writeq;
    cgi->writeq->pair = cgi->readq;
    cgi->writeq->queueData = cgi->readq->queueData = cgi;
    return 0;
}
Example #6
0
/*
    Remember this connections session as the current session. Use for single login tracking.
 */
PUBLIC void espSetCurrentSession(HttpConn *conn)
{
    EspRoute    *eroute;

    eroute = conn->rx->route->eroute;
    eroute->currentSession = httpGetSessionID(conn);
    httpTrace(conn, "esp.singular.set", "context", "msg=\"Set singluar user\", session=%s", eroute->currentSession);
}
Example #7
0
PUBLIC void espClearCurrentSession(HttpConn *conn)
{
    EspRoute    *eroute;

    eroute = conn->rx->route->eroute;
    if (eroute->currentSession) {
        httpTrace(conn, "esp.singular.clear", "context", "session=%s", eroute->currentSession);
    }
    eroute->currentSession = 0;
}
Example #8
0
/*
    Render a document by mapping a URL target to a document. The target is interpreted relative to route->documents.
    If target exists, then serve that.
    If target + extension exists, serve that.
    If target is a directory and an index.esp, return the index.esp without a redirect.
    If target is a directory without a trailing "/" but with an index.esp, do an external redirect to "URI/".
    If target does not end with ".esp", then do not serve that.
 */
PUBLIC void espRenderDocument(HttpConn *conn, cchar *target)
{
    HttpUri     *up;
    MprKey      *kp;
    cchar       *dest;

    assert(target);

    for (ITERATE_KEYS(conn->rx->route->extensions, kp)) {
        if (kp->key && *kp->key) {
            if ((dest = checkView(conn, target, 0, kp->key)) != 0) {
                espRenderView(conn, dest, 0);
                return;
            }
        }
    }
    if ((dest = checkView(conn, target, 0, "esp")) != 0) {
        espRenderView(conn, dest, 0);
        return;
    }
    if ((dest = checkView(conn, target, "index", "esp")) != 0) {
        /*
            Must do external redirect first if URL does not end with "/"
         */
        if (!sends(conn->rx->parsedUri->path, "/")) {
            up = conn->rx->parsedUri;
            httpRedirect(conn, HTTP_CODE_MOVED_PERMANENTLY, httpFormatUri(up->scheme, up->host,
                up->port, sjoin(up->path, "/", NULL), up->reference, up->query, 0));
            return;
        }
        espRenderView(conn, dest, 0);
        return;
    }
/* 
    Remove in version 6 
*/
#if DEPRECATED || 1
    if ((dest = checkView(conn, sjoin("app/", target, NULL), 0, "esp")) != 0) {
        espRenderView(conn, dest, 0);
        return;
    }
#endif
    /*
        Last chance, forward to the file handler ... not an ESP request. 
        This enables static file requests within ESP routes.
     */
    httpTrace(conn, "esp.handler", "context", "msg: 'Relay to the fileHandler");
    conn->rx->target = &conn->rx->pathInfo[1];
    httpMapFile(conn);
    if (conn->tx->fileInfo.isDir) {
        httpHandleDirectory(conn);
    }
    httpSetFileHandler(conn, 0);
}
Example #9
0
static void browserToCgiService(HttpQueue *q)
{
    HttpConn    *conn;
    HttpPacket  *packet;
    Cgi         *cgi;
    MprCmd      *cmd;
    MprBuf      *buf;
    ssize       rc, len;
    int         err;

    if ((cgi = q->queueData) == 0) {
        return;
    }
    assert(q == cgi->writeq);
    cmd = cgi->cmd;
    assert(cmd);
    conn = cgi->conn;

    for (packet = httpGetPacket(q); packet; packet = httpGetPacket(q)) {
        if ((buf = packet->content) == 0) {
            /* End packet */
            continue;
        }
        len = mprGetBufLength(buf);
        rc = mprWriteCmd(cmd, MPR_CMD_STDIN, mprGetBufStart(buf), len);
        if (rc < 0) {
            err = mprGetError();
            if (err == EINTR) {
                continue;
            } else if (err == EAGAIN || err == EWOULDBLOCK) {
                httpPutBackPacket(q, packet);
                break;
            }
            httpTrace(conn, "cgi.error", "error", "msg=\"Cannot write to CGI gateway\", errno=%d", mprGetOsError());
            mprCloseCmdFd(cmd, MPR_CMD_STDIN);
            httpDiscardQueueData(q, 1);
            httpError(conn, HTTP_CODE_BAD_GATEWAY, "Cannot write body data to CGI gateway");
            break;
        }
        mprAdjustBufStart(buf, rc);
        if (mprGetBufLength(buf) > 0) {
            httpPutBackPacket(q, packet);
            break;
        }
    }
    if (q->count > 0) {
        /* Wait for writable event so cgiCallback can recall this routine */
        mprEnableCmdEvents(cmd, MPR_CMD_STDIN);
    } else if (conn->rx->eof) {
        mprCloseCmdFd(cmd, MPR_CMD_STDIN);
    } else {
        mprDisableCmdEvents(cmd, MPR_CMD_STDIN);
    }
}
Example #10
0
/*
    Verify the user password for the "config" store based on the users defined via configuration directives.
    Password may be NULL only if using auto-login.
 */
static bool configVerifyUser(HttpConn *conn, cchar *username, cchar *password)
{
    HttpRx      *rx;
    HttpAuth    *auth;
    bool        success;
    char        *requiredPassword;

    rx = conn->rx;
    auth = rx->route->auth;
    if (!conn->user && (conn->user = mprLookupKey(auth->userCache, username)) == 0) {
        httpTrace(conn, "auth.login.error", "error", "msg: 'Unknown user', username:'******'", username);
        return 0;
    }
    if (password) {
        if (auth->realm == 0 || *auth->realm == '\0') {
            mprLog("error http auth", 0, "No AuthRealm defined");
        }
        requiredPassword = (rx->passwordDigest) ? rx->passwordDigest : conn->user->password;
        if (sncmp(requiredPassword, "BF", 2) == 0 && slen(requiredPassword) > 4 && isdigit(requiredPassword[2]) &&
                requiredPassword[3] == ':') {
            /* Blowifsh */
            success = mprCheckPassword(sfmt("%s:%s:%s", username, auth->realm, password), conn->user->password);

        } else {
            if (!conn->encoded) {
                password = mprGetMD5(sfmt("%s:%s:%s", username, auth->realm, password));
                conn->encoded = 1;
            }
            success = smatch(password, requiredPassword);
        }
        if (success) {
            httpTrace(conn, "auth.login.authenticated", "context", "msg:'User authenticated', username:'******'", username);
        } else {
            httpTrace(conn, "auth.login.error", "error", "msg:'Password failed to authenticate', username:'******'", username);
        }
        return success;
    }
    return 1;
}
Example #11
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);
    }
}
Example #12
0
/*
    Login the user and create an authenticated session state store
 */
PUBLIC bool httpLogin(HttpConn *conn, cchar *username, cchar *password)
{
    HttpRx          *rx;
    HttpAuth        *auth;
    HttpSession     *session;
    HttpVerifyUser  verifyUser;

    rx = conn->rx;
    auth = rx->route->auth;
    if (!username || !*username) {
        httpTrace(conn, "auth.login.error", "error", "msg: 'missing username'");
        return 0;
    }
    if (!auth->store) {
        mprLog("error http auth", 0, "No AuthStore defined");
        return 0;
    }
    if ((verifyUser = auth->verifyUser) == 0) {
        if (auth->parent && (verifyUser = auth->parent->verifyUser) == 0) {
            verifyUser = auth->store->verifyUser;
        }
    }
    if (!verifyUser) {
        mprLog("error http auth", 0, "No user verification routine defined on route %s", rx->route->name);
        return 0;
    }
    if (auth->username && *auth->username) {
        /* If using auto-login, replace the username */
        username = auth->username;
        password = 0;
    }
    if (!(verifyUser)(conn, username, password)) {
        return 0;
    }
    if (!auth->store->noSession) {
        if ((session = httpCreateSession(conn)) == 0) {
            /* Too many sessions */
            return 0;
        }
        httpSetSessionVar(conn, HTTP_SESSION_USERNAME, username);
        httpSetSessionVar(conn, HTTP_SESSION_IP, conn->ip);
    }
    rx->authenticated = 1;
    rx->authenticateProbed = 1;
    conn->username = sclone(username);
    conn->encoded = 0;
    return 1;
}
Example #13
0
/*
    Trace request body content
 */
PUBLIC bool httpTraceContent(HttpConn *conn, cchar *event, cchar *type, cchar *buf, ssize len, cchar *values, ...)
{
    Http        *http;
    HttpTrace   *trace;
    va_list     ap;
    int         level;

    assert(conn);
    assert(buf);

    http = HTTP;
    if (http->traceLevel == 0) {
        return 0;
    }
    if (conn) {
        if (conn->rx->skipTrace) {
            return 0;
        }
        trace = conn->trace;
    } else {
        trace = http->trace;
    }
    level = PTOI(mprLookupKey(trace->events, type));
    if (level == 0 || level > http->traceLevel) {
        return 0;
    }
    if (conn) {
        if ((smatch(event, "rx.body.data") && (conn->rx->bytesRead >= conn->trace->maxContent)) ||
            (smatch(event, "tx.body.data") && (conn->tx->bytesWritten >= conn->trace->maxContent))) {
            if (!conn->rx->webSocket) {
                conn->rx->skipTrace = 1;
                httpTrace(conn, event, type, "msg: 'Abbreviating body trace'");
            }
            return 0;
        }
    }
    if (values) {
        va_start(ap, values);
        values = sfmtv(values, ap);
        va_end(ap);
    }
    httpFormatTrace(trace, conn, event, type, values, buf, len);
    return 1;
}
Example #14
0
/*
    Read data from the peer. This will use the existing conn->input packet or allocate a new packet if required to 
    hold the data. The number of bytes read is stored in conn->lastRead. SSL connections are traced.
    Socket error messages are stored in conn->errorMsg.
 */
static void readPeerData(HttpConn *conn)
{
    HttpPacket  *packet;
    ssize       size;

    if ((packet = getPacket(conn, &size)) != 0) {
        conn->lastRead = mprReadSocket(conn->sock, mprGetBufEnd(packet->content), size);
        if (conn->lastRead > 0) {
            mprAdjustBufEnd(packet->content, conn->lastRead);
        } else if (conn->lastRead < 0 && mprIsSocketEof(conn->sock)) {
            if (conn->state < HTTP_STATE_PARSED) {
                conn->error = 1;
                conn->rx->eof = 1;
            }
            conn->errorMsg = conn->sock->errorMsg ? conn->sock->errorMsg : sclone("Connection reset");
            conn->keepAliveCount = 0;
            conn->lastRead = 0;
            httpTrace(conn, "connection.close", "context", "msg:'%s'", conn->errorMsg);
        }
    }
}
Example #15
0
File: post.c Project: ppslinux/esp
/*
    Dynamic module initialization
 */
ESP_EXPORT int esp_controller_blog_post(HttpRoute *route, MprModule *module) {
    httpTrace(getConn(), "LOAD MODULE", "context", NULL);
    espDefineBase(route, common);
    espDefineAction(route, "post-create", createPost);
    espDefineAction(route, "post-remove", removePost);
    espDefineAction(route, "post-edit", editPost);
    espDefineAction(route, "post-get", getPost);
    espDefineAction(route, "post-init", initPost);
    espDefineAction(route, "post-list", listPost);
    espDefineAction(route, "post-update", updatePost);
    espDefineAction(route, "post-cmd-", listPost);
    espDefineAction(route, "post", redirectPost);
    
#if SAMPLE_VALIDATIONS
    Edi *edi = espGetRouteDatabase(route);
    ediAddValidation(edi, "present", "post", "title", 0);
    ediAddValidation(edi, "unique", "post", "title", 0);
    ediAddValidation(edi, "banned", "post", "body", "(swear|curse)");
    ediAddValidation(edi, "format", "post", "phone", "/^\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/");
#endif
    return 0;
}
Example #16
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;
}
Example #17
0
/*
    Run an action (may yield)
 */
static int runAction(HttpConn *conn)
{
    HttpRx      *rx;
    HttpRoute   *route;
    EspRoute    *eroute;
    EspReq      *req;
    EspAction   action;

    rx = conn->rx;
    req = conn->reqData;
    route = rx->route;
    eroute = route->eroute;
    assert(eroute);

    if (eroute->edi && eroute->edi->flags & EDI_PRIVATE) {
        cloneDatabase(conn);
    } else {
        req->edi = eroute->edi;
    }
    if (route->sourceName == 0 || *route->sourceName == '\0') {
        if (eroute->commonController) {
            (eroute->commonController)(conn);
        }
        return 1;
    }

#if !ME_STATIC
    if (!eroute->combine && (route->update || !mprLookupKey(eroute->actions, rx->target))) {
        cchar *errMsg, *controllers, *controller;
        if ((controllers = httpGetDir(route, "CONTROLLERS")) == 0) {
            controllers = ".";
        }
        controllers = mprJoinPath(route->home, controllers);
        controller = schr(route->sourceName, '$') ? stemplateJson(route->sourceName, rx->params) : route->sourceName;
        controller = controllers ? mprJoinPath(controllers, controller) : mprJoinPath(route->home, controller);
        if (espLoadModule(route, conn->dispatcher, "controller", controller, &errMsg) < 0) {
            if (mprPathExists(controller, R_OK)) {
                httpError(conn, HTTP_CODE_NOT_FOUND, "%s", errMsg);
                return 0;
            }
        }
    }
#endif /* !ME_STATIC */

    assert(eroute->top);
    action = mprLookupKey(eroute->top->actions, rx->target);

    if (route->flags & HTTP_ROUTE_XSRF && !(rx->flags & HTTP_GET)) {
        if (!httpCheckSecurityToken(conn)) {
            httpSetStatus(conn, HTTP_CODE_UNAUTHORIZED);
            if (smatch(route->responseFormat, "json")) {
                httpTrace(conn, "esp.xsrf.error", "error", 0);
                espRenderString(conn,
                    "{\"retry\": true, \"success\": 0, \"feedback\": {\"error\": \"Security token is stale. Please retry.\"}}");
                espFinalize(conn);
            } else {
                httpError(conn, HTTP_CODE_UNAUTHORIZED, "Security token is stale. Please reload page.");
            }
            return 0;
        }
    }
    if (action) {
        httpAuthenticate(conn);
        setupFlash(conn);
        if (eroute->commonController) {
            (eroute->commonController)(conn);
        }
        if (!httpIsFinalized(conn)) {
            (action)(conn);
        }
    }
    return 1;
}
Example #18
0
/*
    Can call this without being authenticated
 */
static void publishPackage() {
    HttpConn    *conn;
    EdiRec      *rec;
    cchar       *email, *password, *name, *endpoint;
    bool        checkPassword;

    name = param("name");
    endpoint = param("endpoint");
    password = param("password");
    email = param("email");

    conn = getConn();
    if (!name || !*name || !endpoint || !*endpoint) {
        sendResult(feedback("error", "Missing name or endpoint parameters"));
        return;
    }
    if (!email || !*email) {
        sendResult(feedback("error", "Missing email parameter"));
        return;
    }
    if (canUser("edit", 0) && smatch(conn->username, name)) {
        checkPassword = 0;
        httpTrace(conn, "auth.login.authenticated", "context", "msg=\"Authenticated for package\", pak=%s", name);
    } else {
        if (!password || !*password) {
            sendResult(feedback("error", "Missing password parameter"));
            return;
        }
        checkPassword = 1;
    }
    if ((rec = readRecWhere("pak", "name", "==", name)) != 0) {
        if (checkPassword && !mprCheckPassword(password, getField(rec, "password"))) {
            sendResult(feedback("error", "Package already exists but invalid password"));
            return;
        }
        setFields(rec, params());

    } else {
#if FUTURE
        cchar   *uri, *response, *err;
        uri = strim(endpoint, ".git", MPR_TRIM_END);
        uri = sjoin(uri, "/raw/master/package.json", NULL);
        status = httpRequest("GET", uri, NULL, &response, &err);

        if (status != 200) {
            feedback("warn", "Could not verify endpoint");
        } else {
            if (!response || mprParseJson(response) == 0) {
                feedback("warn", "Could not verify endpoint package.json");
            }
        }
#endif
        if ((rec = createRec("pak", params())) == 0) {
            sendResult(feedback("error", "Cannot create package record"));
            return;
        }
    }
    setField(rec, "password", mprMakePassword(password, PASSWORD_SALT, PASSWORD_ROUNDS));

    if (!(updateRec(rec))) {
        sendResult(feedback("error", "Cannot save package details"));
        return;
    }
    sendRec(rec);
}
Example #19
0
/*
    Process the content data.
    Returns < 0 on error
            == 0 when more data is needed
            == 1 when data successfully written
 */
static int processUploadData(HttpQueue *q)
{
    HttpConn        *conn;
    HttpPacket      *packet;
    MprBuf          *content;
    Upload          *up;
    ssize           size, dataLen;
    bool            pureData;
    char            *data, *bp, *key;

    conn = q->conn;
    up = q->queueData;
    content = q->first->content;
    packet = 0;

    size = mprGetBufLength(content);
    if (size < up->boundaryLen) {
        /*  Incomplete boundary. Return and get more data */
        return 0;
    }
    bp = getBoundary(mprGetBufStart(content), size, up->boundary, up->boundaryLen, &pureData);
    if (bp == 0) {
        if (up->clientFilename) {
            /*
                No signature found yet. probably more data to come. Must handle split boundaries.
             */
            data = mprGetBufStart(content);
            dataLen = pureData ? size : (size - (up->boundaryLen - 1));
            if (dataLen > 0) {
                if (writeToFile(q, mprGetBufStart(content), dataLen) < 0) {
                    return MPR_ERR_CANT_WRITE;
                }
            }
            mprAdjustBufStart(content, dataLen);
            return 0;       /* Get more data */
        }
    }
    data = mprGetBufStart(content);
    dataLen = (bp) ? (bp - data) : mprGetBufLength(content);

    if (dataLen > 0) {
        mprAdjustBufStart(content, dataLen);
        /*
            This is the CRLF before the boundary
         */
        if (dataLen >= 2 && data[dataLen - 2] == '\r' && data[dataLen - 1] == '\n') {
            dataLen -= 2;
        }
        if (up->clientFilename) {
            /*
                Write the last bit of file data and add to the list of files and define environment variables
             */
            if (writeToFile(q, data, dataLen) < 0) {
                return MPR_ERR_CANT_WRITE;
            }
            defineFileFields(q, up);

        } else {
            /*
                Normal string form data variables
             */
            data[dataLen] = '\0';
#if KEEP
            httpTrace(conn, "request.upload.variables", "context", "'%s':'%s'", up->name, data);
#endif
            key = mprUriDecode(up->name);
            data = mprUriDecode(data);
            httpSetParam(conn, key, data);

            if (packet == 0) {
                packet = httpCreatePacket(ME_MAX_BUFFER);
            }
            if (httpGetPacketLength(packet) > 0) {
                /*
                    Need to add www-form-urlencoding separators
                 */
                mprPutCharToBuf(packet->content, '&');
            } else {
                conn->rx->mimeType = sclone("application/x-www-form-urlencoded");

            }
            mprPutToBuf(packet->content, "%s=%s", up->name, data);
        }
    }
    if (up->clientFilename) {
        /*
            Now have all the data (we've seen the boundary)
         */
        mprCloseFile(up->file);
        up->file = 0;
        up->clientFilename = 0;
    }
    if (packet) {
        httpPutPacketToNext(q, packet);
    }
    up->contentState = HTTP_UPLOAD_BOUNDARY;
    return 0;
}
Example #20
0
File: post.c Project: ppslinux/esp
/*
    Initialize a new resource for the client to complete
 */
static void initPost() { 
    httpTrace(getConn(), "INIT POST", "context", NULL);
    createRec("post", 0);
    httpTrace(getConn(), "RENDER VIEW", "context", NULL);
    renderView("post/post-edit");
}
Example #21
0
/*
    Expecting content headers. A blank line indicates the start of the data.
    Returns  < 0  Request or state error
    Returns == 0  Successfully parsed the input line.
 */
static int processUploadHeader(HttpQueue *q, char *line)
{
    HttpConn        *conn;
    HttpRx          *rx;
    HttpUploadFile  *file;
    Upload          *up;
    cchar           *uploadDir;
    char            *key, *headerTok, *rest, *nextPair, *value;

    conn = q->conn;
    rx = conn->rx;
    up = q->queueData;

    if (line[0] == '\0') {
        up->contentState = HTTP_UPLOAD_CONTENT_DATA;
        return 0;
    }

    headerTok = line;
    stok(line, ": ", &rest);

    if (scaselesscmp(headerTok, "Content-Disposition") == 0) {
        /*
            The content disposition header describes either a form
            variable or an uploaded file.

            Content-Disposition: form-data; name="field1"
            >>blank line
            Field Data
            ---boundary

            Content-Disposition: form-data; name="field1" ->
                filename="user.file"
            >>blank line
            File data
            ---boundary
         */
        key = rest;
        up->name = up->clientFilename = 0;
        while (key && stok(key, ";\r\n", &nextPair)) {

            key = strim(key, " ", MPR_TRIM_BOTH);
            stok(key, "= ", &value);
            value = strim(value, "\"", MPR_TRIM_BOTH);

            if (scaselesscmp(key, "form-data") == 0) {
                /* Nothing to do */

            } else if (scaselesscmp(key, "name") == 0) {
                up->name = sclone(value);

            } else if (scaselesscmp(key, "filename") == 0) {
                if (up->name == 0) {
                    httpError(conn, HTTP_CODE_BAD_REQUEST, "Bad upload state. Missing name field");
                    return MPR_ERR_BAD_STATE;
                }
                /*
                    Client filenames must be simple filenames without illegal characters or path separators.
                    We are deliberately restrictive here to assist users that may use the clientFilename in shell scripts.
                    They MUST still sanitize for their environment, but some extra caution is worthwhile.
                 */
                value = mprNormalizePath(value);
                if (*value == '.' || !httpValidUriChars(value) || strpbrk(value, "\\/:*?<>|~\"'%`^\n\r\t\f")) {
                    httpError(conn, HTTP_CODE_BAD_REQUEST, "Bad upload client filename.");
                    return MPR_ERR_BAD_STATE;
                }
                up->clientFilename = sclone(value);
                /*
                    Create the file to hold the uploaded data
                 */
                uploadDir = getUploadDir(rx->route);
                up->tmpPath = mprGetTempPath(uploadDir);
                if (up->tmpPath == 0) {
                    if (!mprPathExists(uploadDir, X_OK)) {
                        mprLog("http error", 0, "Cannot access upload directory %s", uploadDir);
                    }
                    httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR,
                        "Cannot create upload temp file %s. Check upload temp dir %s", up->tmpPath, uploadDir);
                    return MPR_ERR_CANT_OPEN;
                }
                httpTrace(conn, "request.upload.file", "context", "clientFilename:'%s',filename:'%s'", 
                    up->clientFilename, up->tmpPath);

                up->file = mprOpenFile(up->tmpPath, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
                if (up->file == 0) {
                    httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot open upload temp file %s", up->tmpPath);
                    return MPR_ERR_BAD_STATE;
                }
                /*
                    Create the files[id]
                 */
                file = up->currentFile = mprAllocObj(HttpUploadFile, manageHttpUploadFile);
                file->clientFilename = up->clientFilename;
                file->filename = up->tmpPath;
                file->name = up->name;
                addUploadFile(conn, file);
            }
            key = nextPair;
        }

    } else if (scaselesscmp(headerTok, "Content-Type") == 0) {
        if (up->clientFilename) {
            up->currentFile->contentType = sclone(rest);
        }
    }
    return 0;
}
Example #22
0
PUBLIC void httpCreateTxPipeline(HttpConn *conn, HttpRoute *route)
{
    Http        *http;
    HttpTx      *tx;
    HttpRx      *rx;
    HttpQueue   *q;
    HttpStage   *stage, *filter;
    int         next;

    assert(conn);
    assert(route);

    http = conn->http;
    rx = conn->rx;
    tx = conn->tx;

    tx->outputPipeline = mprCreateList(-1, MPR_LIST_STABLE);
    if (httpServerConn(conn)) {
        if (tx->handler == 0 || tx->finalized) {
            tx->handler = http->passHandler;
        }
        mprAddItem(tx->outputPipeline, tx->handler);
    }
    if (route->outputStages) {
        for (next = 0; (filter = mprGetNextItem(route->outputStages, &next)) != 0; ) {
            if (matchFilter(conn, filter, route, HTTP_STAGE_TX) == HTTP_ROUTE_OK) {
                mprAddItem(tx->outputPipeline, filter);
                tx->flags |= HTTP_TX_HAS_FILTERS;
            }
        }
    }
    if (tx->connector == 0) {
#if !ME_ROM
        if (tx->handler == http->fileHandler && (rx->flags & HTTP_GET) && !(tx->flags & HTTP_TX_HAS_FILTERS) && 
                !conn->secure && !httpTracing(conn)) {
            tx->connector = http->sendConnector;
        } else 
#endif
        tx->connector = (route && route->connector) ? route->connector : http->netConnector;
    }
    mprAddItem(tx->outputPipeline, tx->connector);

    /*  Create the outgoing queue heads and open the queues */
    q = tx->queue[HTTP_QUEUE_TX];
    for (next = 0; (stage = mprGetNextItem(tx->outputPipeline, &next)) != 0; ) {
        q = httpCreateQueue(conn, stage, HTTP_QUEUE_TX, q);
    }
    conn->connectorq = tx->queue[HTTP_QUEUE_TX]->prevQ;

    /*
        Double the connector max hi-water mark. This optimization permits connectors to accept packets without 
        unnecesary flow control.
     */
    conn->connectorq->max *= 2;

    pairQueues(conn);

    /*
        Put the header before opening the queues incase an open routine actually services and completes the request
     */
    httpPutForService(conn->writeq, httpCreateHeaderPacket(), HTTP_DELAY_SERVICE);

    /*
        Open the pipeline stages. This calls the open entrypoints on all stages.
     */
    openQueues(conn);

    if (conn->error) {
        if (tx->handler != http->passHandler) {
            tx->handler = http->passHandler;
            httpAssignQueue(conn->writeq, tx->handler, HTTP_QUEUE_TX);
        }
    }
    tx->flags |= HTTP_TX_PIPELINE;

    if (conn->endpoint) {
        httpTrace(conn, "request.pipeline", "context",  
            "route:'%s',handler:'%s',target:'%s',endpoint:'%s:%d',host:'%s',referrer:'%s',filename:'%s'",
            rx->route->pattern, tx->handler->name, rx->route->targetRule, conn->endpoint->ip, conn->endpoint->port,
            conn->host->name ? conn->host->name : "default", rx->referrer ? rx->referrer : "", 
            tx->filename ? tx->filename : "");
    }
}
Example #23
0
PUBLIC int espEmail(HttpConn *conn, cchar *to, cchar *from, cchar *subject, MprTime date, cchar *mime,
                    cchar *message, MprList *files)
{
    MprList         *lines;
    MprCmd          *cmd;
    cchar           *body, *boundary, *contents, *encoded, *file;
    char            *out, *err;
    ssize           length;
    int             i, next, status;

    if (!from || !*from) {
        from = "anonymous";
    }
    if (!subject || !*subject) {
        subject = "Mail message";
    }
    if (!mime || !*mime) {
        mime = "text/plain";
    }
    if (!date) {
        date = mprGetTime();
    }
    boundary = sjoin("esp.mail=", mprGetMD5("BOUNDARY"), NULL);
    lines = mprCreateList(0, 0);

    mprAddItem(lines, sfmt("To: %s", to));
    mprAddItem(lines, sfmt("From: %s", from));
    mprAddItem(lines, sfmt("Date: %s", mprFormatLocalTime(0, date)));
    mprAddItem(lines, sfmt("Subject: %s", subject));
    mprAddItem(lines, "MIME-Version: 1.0");
    mprAddItem(lines, sfmt("Content-Type: multipart/mixed; boundary=%s", boundary));
    mprAddItem(lines, "");

    boundary = sjoin("--", boundary, NULL);

    mprAddItem(lines, boundary);
    mprAddItem(lines, sfmt("Content-Type: %s", mime));
    mprAddItem(lines, "");
    mprAddItem(lines, "");
    mprAddItem(lines, message);

    for (ITERATE_ITEMS(files, file, next)) {
        mprAddItem(lines, boundary);
        if ((mime = mprLookupMime(NULL, file)) == 0) {
            mime = "application/octet-stream";
        }
        mprAddItem(lines, "Content-Transfer-Encoding: base64");
        mprAddItem(lines, sfmt("Content-Disposition: inline; filename=\"%s\"", mprGetPathBase(file)));
        mprAddItem(lines, sfmt("Content-Type: %s; name=\"%s\"", mime, mprGetPathBase(file)));
        mprAddItem(lines, "");
        contents = mprReadPathContents(file, &length);
        encoded = mprEncode64Block(contents, length);
        for (i = 0; i < length; i += 76) {
            mprAddItem(lines, snclone(&encoded[i], i + 76));
        }
    }
    mprAddItem(lines, sfmt("%s--", boundary));

    body = mprListToString(lines, "\n");
    httpTraceContent(conn, "esp.email", "context", body, slen(body), 0);

    cmd = mprCreateCmd(conn->dispatcher);
    if (mprRunCmd(cmd, "sendmail -t", NULL, body, &out, &err, -1, 0) < 0) {
        mprDestroyCmd(cmd);
        return MPR_ERR_CANT_OPEN;
    }
    if (mprWaitForCmd(cmd, ME_ESP_EMAIL_TIMEOUT) < 0) {
        httpTrace(conn, "esp.email.error", "error",
                  "msg=\"Timeout waiting for command to complete\", timeout=%d, command=\"%s\"",
                  ME_ESP_EMAIL_TIMEOUT, cmd->argv[0]);
        mprDestroyCmd(cmd);
        return MPR_ERR_CANT_COMPLETE;
    }
    if ((status = mprGetCmdExitStatus(cmd)) != 0) {
        httpTrace(conn, "esp.email.error", "error", "msg=\"Sendmail failed\", status=%d, error=\"%s\"", status, err);
        mprDestroyCmd(cmd);
        return MPR_ERR_CANT_WRITE;
    }
    mprDestroyCmd(cmd);
    return 0;
}
Example #24
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;
}
Example #25
0
static int openFileHandler(HttpQueue *q)
{
    HttpRx      *rx;
    HttpTx      *tx;
    HttpConn    *conn;
    MprPath     *info;
    char        *date, dbuf[16];
    MprHash     *dateCache;

    conn = q->conn;
    tx = conn->tx;
    rx = conn->rx;
    info = &tx->fileInfo;

    if (conn->error) {
        return MPR_ERR_CANT_OPEN;
    }
    if (rx->flags & (HTTP_GET | HTTP_HEAD | HTTP_POST)) {
        if (!(info->valid || info->isDir)) {
            httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot find document");
            return 0;
        } 
        if (!tx->etag) {
            /* Set the etag for caching in the client */
            tx->etag = sfmt("\"%llx-%llx-%llx\"", (int64) info->inode, (int64) info->size, (int64) info->mtime);
        }
        if (info->mtime) {
            dateCache = conn->http->dateCache;
            if ((date = mprLookupKey(dateCache, itosbuf(dbuf, sizeof(dbuf), (int64) info->mtime, 10))) == 0) {
                if (!dateCache || mprGetHashLength(dateCache) > 128) {
                    conn->http->dateCache = dateCache = mprCreateHash(0, 0);
                }
                date = httpGetDateString(&tx->fileInfo);
                mprAddKey(dateCache, itosbuf(dbuf, sizeof(dbuf), (int64) info->mtime, 10), date);
            }
            httpSetHeaderString(conn, "Last-Modified", date);
        }
        if (httpContentNotModified(conn)) {
            httpSetStatus(conn, HTTP_CODE_NOT_MODIFIED);
            httpOmitBody(conn);
            tx->length = -1;
        }
        if (!tx->fileInfo.isReg && !tx->fileInfo.isLink) {
            httpTrace(conn, "request.document.error", "error", "msg: 'Document is not a regular file', filename: '%s'", 
                tx->filename);
            httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot serve document");
            
        } else if (tx->fileInfo.size > conn->limits->transmissionBodySize) {
            httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE,
                "Http transmission aborted. File size exceeds max body of %'lld bytes",
                    conn->limits->transmissionBodySize);
            
        } else if (!(tx->connector == conn->http->sendConnector)) {
            /*
                If using the net connector, open the file if a body must be sent with the response. The file will be
                automatically closed when the request completes.
             */
            if (!(tx->flags & HTTP_TX_NO_BODY)) {
                tx->file = mprOpenFile(tx->filename, O_RDONLY | O_BINARY, 0);
                if (tx->file == 0) {
                    if (rx->referrer && *rx->referrer) {
                        httpTrace(conn, "request.document.error", "error", 
                            "msg: 'Cannot open document', filename: '%s', referrer: '%s'", 
                            tx->filename, rx->referrer);
                    } else {
                        httpTrace(conn, "request.document.error", "error", 
                            "msg: 'Cannot open document', filename: '%s'", tx->filename);
                    }
                    httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot open document");
                }
            }
        }
    } else if (rx->flags & (HTTP_DELETE | HTTP_OPTIONS | HTTP_PUT)) {
        ;
    } else {
        httpError(conn, HTTP_CODE_BAD_METHOD, "Unsupported method");
    }
    return 0;
}
Example #26
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 #27
0
PUBLIC void httpSendOutgoingService(HttpQueue *q)
{
    HttpConn    *conn;
    HttpTx      *tx;
    MprFile     *file;
    MprOff      written;
    int         errCode;

    conn = q->conn;
    tx = conn->tx;
    conn->lastActivity = conn->http->now;

    if (tx->finalizedConnector) {
        return;
    }
    if (tx->flags & HTTP_TX_NO_BODY) {
        httpDiscardQueueData(q, 1);
    }
    if ((tx->bytesWritten + q->ioCount) > conn->limits->txBodySize && conn->limits->txBodySize < HTTP_UNLIMITED) {
        httpLimitError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE | ((tx->bytesWritten) ? HTTP_ABORT : 0),
            "Http transmission aborted. Exceeded max body of %lld bytes", conn->limits->txBodySize);
        if (tx->bytesWritten) {
            httpFinalizeConnector(conn);
            return;
        }
    }
    tx->writeBlocked = 0;

    if (q->ioIndex == 0) {
        buildSendVec(q);
    }
    /*
        No need to loop around as send file tries to write as much of the file as possible.
        If not eof, will always have the socket blocked.
     */
    file = q->ioFile ? tx->file : 0;
    written = mprSendFileToSocket(conn->sock, file, q->ioPos, q->ioCount, q->iovec, q->ioIndex, NULL, 0);
    if (written < 0) {
        errCode = mprGetError();
        if (errCode == EAGAIN || errCode == EWOULDBLOCK) {
            /*  Socket full, wait for an I/O event */
            tx->writeBlocked = 1;
        } else {
            if (errCode != EPIPE && errCode != ECONNRESET && errCode != ECONNABORTED && errCode != ENOTCONN) {
                httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "sendConnector: error, errCode %d", errCode);
            } else {
                httpDisconnect(conn);
            }
            httpFinalizeConnector(conn);
        }
        httpTrace(conn, "connection.io.error", "error", "msg:'Connector write error',errno:%d", errCode);

    } else if (written > 0) {
        tx->bytesWritten += written;
        freeSendPackets(q, written);
        adjustSendVec(q, written);
    }
    if (q->first && q->first->flags & HTTP_PACKET_END) {
        httpFinalizeConnector(conn);
        httpGetPacket(q);
    }
}