Beispiel #1
0
/*
 *  Load a module. Returns 0 if the modules is successfully loaded either statically or dynamically.
 */
MprModule *maLoadModule(MaHttp *http, cchar *name, cchar *libname)
{
    MprModule   *module;
    char        entryPoint[MPR_MAX_FNAME];
    char        *path;

    path = 0;

    module = mprLookupModule(http, name);
    if (module) {
        mprLog(http, MPR_CONFIG, "Activating module (Builtin) %s", name);
        return module;
    }
    mprSprintf(entryPoint, sizeof(entryPoint), "ma%sInit", name);
    entryPoint[2] = toupper((int) entryPoint[2]);

    if (libname == 0) {
        path = mprStrcat(http, -1, "mod_", name, BLD_SHOBJ, NULL);
    }
    if ((module = mprLoadModule(http, (libname) ? libname: path, entryPoint)) == 0) {
        return 0;
    }
    mprLog(http, MPR_CONFIG, "Activating module (Loadable) %s", name);
    return module;
}
Beispiel #2
0
/*
 *  Manage requests to directories. This will either do an external redirect back to the browser or do an internal 
 *  (transparent) redirection and serve different content back to the browser. This routine may modify the requested 
 *  URI and/or the request handler.
 */
static void processDirectory(MaConn *conn, bool *rescan)
{
    MaRequest       *req;
    MaResponse      *resp;
    MprFileInfo     *info;
    char            path[MPR_MAX_FNAME], urlBuf[MPR_MAX_FNAME], *index;
    int             len;

    req = conn->request;
    resp = conn->response;
    info = &resp->fileInfo;

    mprAssert(info->isDir);
    index = req->dir->indexName;
    if (req->url[strlen(req->url) - 1] == '/') {
        /*
         *  Internal directory redirections
         */
        len = (int) strlen(resp->filename);
        if (resp->filename[len - 1] == '/') {
            resp->filename[len - 1] = '\0';
        }
        path[0] = '\0';
        mprAssert(resp->filename && *resp->filename);
        mprAssert(index && *index);
        mprStrcat(path, sizeof(path), NULL, resp->filename, "/", index, NULL);
        if (mprAccess(resp, path, R_OK)) {
            /*
             *  Index file exists, so do an internal redirect to it. Client will not be aware of this happening.
             *  Must rematch the handler on return.
             */
            maSetRequestUri(conn, addIndex(conn, urlBuf, sizeof(urlBuf), index));

            resp->filename = mprStrdup(resp, path);
            mprGetFileInfo(conn, resp->filename, &resp->fileInfo);

            resp->extension = getExtension(conn);
            if ((resp->mimeType = (char*) maLookupMimeType(conn->host, resp->extension)) == 0) {
                resp->mimeType = (char*) "text/html";
            }
            *rescan = 1;
        }
        return;
    }

    /*
     *  External redirect. Ask the client to re-issue a request for a new location. See if an index exists and if so, 
     *  construct a new location for the index. If the index can't be accessed, just append a "/" to the URI and redirect.
     */
    if (req->parsedUri->query && req->parsedUri->query[0]) {
        mprSprintf(path, sizeof(path), "%s/%s?%s", req->url, index, req->parsedUri->query);
    } else {
        mprSprintf(path, sizeof(path), "%s/%s", req->url, index);
    }
    if (!mprAccess(resp, path, R_OK)) {
        mprSprintf(path, sizeof(path), "%s/", req->url);
    }
    maRedirect(conn, MPR_HTTP_CODE_MOVED_PERMANENTLY, path);
    resp->handler = conn->http->passHandler;
}
Beispiel #3
0
int maAddUser(MaAuth *auth, cchar *realm, cchar *user, cchar *password, bool enabled)
{
    MaUser  *up;

    char    *key;

    up = maCreateUser(auth, realm, user, password, enabled);
    if (up == 0) {
        return MPR_ERR_NO_MEMORY;
    }

    if (auth->users == 0) {
        auth->users = mprCreateHash(auth, -1);
    }
    key = mprStrcat(auth, -1, realm, ":", user, NULL);
    if (mprLookupHash(auth->users, key)) {
        mprFree(key);
        return MPR_ERR_ALREADY_EXISTS;
    }

    if (mprAddHash(auth->users, key, up) == 0) {
        mprFree(key);
        return MPR_ERR_NO_MEMORY;
    }
    mprFree(key);
    return 0;
}
Beispiel #4
0
static void initService()
{
    //  TOOD - serviceName should come from the command line program 
    serviceName = BLD_COMPANY "-" BLD_PRODUCT;
    serviceTitle = BLD_NAME;
    serviceStopped = 0;

    serviceProgram = mprStrcat(mpr, -1, mprGetAppDir(mpr), "/", BLD_PRODUCT, ".exe", NULL);
}
Beispiel #5
0
int maEnableUser(MaAuth *auth, cchar *realm, cchar *user)
{
    MaUser      *up;
    char        *key;

    up = 0;
    key = mprStrcat(auth, -1, realm, ":", user, NULL);    
    if (auth->users == 0 || (up = (MaUser*) mprLookupHash(auth->users, key)) == 0) {
        return MPR_ERR_CANT_ACCESS;
    }
    up->enabled = 1;
    return 0;
}
Beispiel #6
0
int maRemoveUser(MaAuth *auth, cchar *realm, cchar *user)
{
    char    *key;

    key = mprStrcat(auth, -1, realm, ":", user, NULL);
    if (auth->users == 0 || !mprLookupHash(auth->users, key)) {
        mprFree(key);
        return MPR_ERR_CANT_ACCESS;
    }
    mprRemoveHash(auth->users, key);
    mprFree(key);
    return 0;
}
Beispiel #7
0
void maSetHostIpAddrPort(MaHost *host, cchar *ipAddrPort)
{
    mprAssert(ipAddrPort);
    mprFree(host->ipAddrPort);

    if (*ipAddrPort == ':') {
        ++ipAddrPort;
    }
    if (isdigit((int) *ipAddrPort) && strchr(ipAddrPort, '.') == 0) {
        host->ipAddrPort = mprStrcat(host, -1, "127.0.0.1", ":", ipAddrPort, NULL);
    } else {
        host->ipAddrPort = mprStrdup(host, ipAddrPort);
    }
}
Beispiel #8
0
bool maIsUserEnabled(MaAuth *auth, cchar *realm, cchar *user)
{
    MaUser  *up;
    char    *key;

    up = 0;
    key = mprStrcat(auth, -1, realm, ":", user, NULL);
    if (auth->users == 0 || (up = (MaUser*) mprLookupHash(auth->users, key)) == 0) {
        mprFree(key);
        return 0;
    }
    mprFree(key);
    return up->enabled;
}
Beispiel #9
0
/*
 *  Security checks. Make sure we are staring with a safe environment
 */
int checkEnvironment(Mpr *mpr, cchar *program, cchar *home)
{
#if BLD_UNIX_LIKE
    char    *path;
    /*
     *  Ensure the binaries directory is in the path. Used by ejs to run ejsweb from /usr/local/bin
     */
    path = mprStrcat(mpr, -1, "PATH=", getenv("PATH"), ":", mprGetAppDir(mpr), NULL);
    putenv(path);
#endif
#if BLD_UNIX_LIKE
    if (unixSecurityChecks(mpr, program, home) < 0) {
        return -1;
    }
#endif
    return 0;
}
Beispiel #10
0
void maSetHostIpAddrPort(MaHost *host, cchar *ipAddrPort)
{
    char    buf[MPR_MAX_IP_ADDR_PORT];

    mprAssert(ipAddrPort);

    if (*ipAddrPort == ':') {
        ipAddrPort++;
    }
    if (isdigit((int) *ipAddrPort) && strchr(ipAddrPort, '.') == 0) {
        buf[0] = '\0';
        mprStrcat(buf, sizeof(buf), ":", "127.0.0.1", ipAddrPort, 0);
        ipAddrPort = buf;
    }

    mprFree(host->ipAddrPort);
    host->ipAddrPort = mprStrdup(host, ipAddrPort);
}
Beispiel #11
0
cchar *maGetNativePassword(MaConn *conn, cchar *realm, cchar *user)
{
    MaUser      *up;
    MaAuth      *auth;
    char        *key;

    auth = conn->request->auth;

    up = 0;
    key = mprStrcat(conn, -1, realm, ":", user, NULL);
    if (auth->users) {
        up = (MaUser*) mprLookupHash(auth->users, key);
    }
    mprFree(key);
    if (up == 0) {
        return 0;
    }
    return up->password;
}
Beispiel #12
0
/*
 *  Put an environment var
 *
 *  function putenv(key: String, value: String): void
 */
static EjsVar *putEnvVar(Ejs *ejs, EjsObject *app, int argc, EjsVar **argv)
{

#if !WINCE
#if BLD_UNIX_LIKE
    char    *key, *value;

    key = mprStrdup(ejs, ejsGetString(argv[0]));
    value = mprStrdup(ejs, ejsGetString(argv[1]));
    setenv(key, value, 1);
#else
    char   *cmd;

    cmd = mprStrcat(app, -1, ejsGetString(argv[0]), "=", ejsGetString(argv[1]), NULL);
    putenv(cmd);
#endif
#endif
    return 0;
}
Beispiel #13
0
MAIN(appweb, int argc, char **argv)
{
    Mpr         *mpr;
    MaHttp      *http;
    cchar       *ipAddrPort, *documentRoot, *argp, *logSpec;
    char        *configFile, *ipAddr, *homeDir, *timeText, *ejsPrefix, *ejsPath, *changeRoot;
    int         workers, outputVersion, argind, port;
    
    documentRoot = 0;
    changeRoot = ejsPrefix = ejsPath = 0;
    ipAddrPort = 0;
    ipAddr = 0;
    port = -1;
    logSpec = 0;
    server = 0;
    outputVersion = 0;
    workers = -1;

    configFile = BLD_FEATURE_CONFIG_FILE;
    homeDir = BLD_FEATURE_SERVER_ROOT;

    mpr = mprCreate(argc, argv, memoryFailure);
    argc = mpr->argc;
    argv = mpr->argv;

#if BLD_FEATURE_ROMFS
    extern MprRomInode romFiles[];
    mprSetRomFileSystem(mpr, romFiles);
#endif

    if (osInit(mpr) < 0) {
        exit(2);
    }
    if (mprStart(mpr, 0) < 0) {
        mprUserError(mpr, "Can't start MPR for %s", mprGetAppName(mpr));
        mprFree(mpr);
        return MPR_ERR_CANT_INITIALIZE;
    }

    for (argind = 1; argind < argc; argind++) {
        argp = argv[argind];
        if (*argp != '-') {
            break;
        }
        if (strcmp(argp, "--config") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            configFile = argv[++argind];

#if BLD_UNIX_LIKE
        } else if (strcmp(argp, "--chroot") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            changeRoot = mprGetAbsPath(mpr, argv[++argind]);
#endif

        } else if (strcmp(argp, "--debug") == 0 || strcmp(argp, "-D") == 0 || 
                strcmp(argp, "-d") == 0 || strcmp(argp, "--debugger") == 0) {
            mprSetDebugMode(mpr, 1);

        } else if (strcmp(argp, "--ejs") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            ejsPrefix = mprStrdup(mpr, argv[++argind]);
            if ((ejsPath = strchr(ejsPrefix, ':')) != 0) {
                *ejsPath++ = '\0';
            }
            ejsPath = mprGetAbsPath(mpr, ejsPath);

        } else if (strcmp(argp, "--home") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            homeDir = mprGetAbsPath(mpr, argv[++argind]);
            if (chdir((char*) homeDir) < 0) {
                mprPrintfError(mpr, "%s: Can't change directory to %s\n", mprGetAppName(mpr), homeDir);
                exit(2);
            }

        } else if (strcmp(argp, "--log") == 0 || strcmp(argp, "-l") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            logSpec = argv[++argind];
            maStartLogging(mpr, logSpec);

        } else if (strcmp(argp, "--name") == 0 || strcmp(argp, "-n") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            mprSetAppName(mpr, argv[++argind], 0, 0);

        } else if (strcmp(argp, "--threads") == 0) {
            if (argind >= argc) {
                return printUsage(mpr);
            }
            workers = atoi(argv[++argind]);

        } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) {
            maStartLogging(mpr, "stdout:2");

        } else if (strcmp(argp, "--version") == 0 || strcmp(argp, "-V") == 0) {
            outputVersion++;

        } else {
            mprPrintfError(mpr, "Unknown switch \"%s\"\n", argp);
            printUsage(mpr);
            exit(2);
        }
    }

    if (argc > argind) {
        if (argc > (argind + 2)) {
            return printUsage(mpr);
        }
        ipAddrPort = argv[argind++];
        if (argc > argind) {
            documentRoot = argv[argind++];
        } else {
            documentRoot = ".";
        }
    }

    if (outputVersion) {
        mprPrintf(mpr, "%s %s-%s\n", mprGetAppTitle(mpr), BLD_VERSION, BLD_NUMBER);
        exit(0);
    }

    if (ipAddrPort) {
        mprParseIp(mpr, ipAddrPort, &ipAddr, &port, MA_SERVER_DEFAULT_PORT_NUM);
    } else {
#if BLD_FEATURE_CONFIG_PARSE
        if (configFile == 0) {
            configFile = mprStrcat(mpr, -1, mprGetAppName(mpr), ".conf", NULL);
        }
        if (!mprPathExists(mpr, configFile, R_OK)) {
            mprPrintfError(mpr, "Can't open config file %s\n", configFile);
            exit(2);
        }
#else
        return printUsage(mpr);
#endif
#if !BLD_FEATURE_ROMFS
        if (homeDir == 0) {
            homeDir = mprGetPathParent(mpr, configFile);
            if (chdir((char*) homeDir) < 0) {
                mprPrintfError(mpr, "%s: Can't change directory to %s\n", mprGetAppName(mpr), homeDir);
                exit(2);
            }
        }
#endif
    }
    homeDir = mprGetCurrentPath(mpr);
    if (checkEnvironment(mpr, argv[0], homeDir) < 0) {
        exit(3);
    }

#if BLD_UNIX_LIKE
    if (changeRoot) {
        homeDir = mprGetAbsPath(mpr, changeRoot);
        if (chdir(homeDir) < 0) {
            mprError(mpr, "%s: Can't change directory to %s", homeDir);
            exit(4);
        }
        if (chroot(homeDir) < 0) {
            if (errno == EPERM) {
                mprError(mpr, "%s: Must be super user to use the --chroot option", mprGetAppName(mpr));
            } else {
                mprError(mpr, "%s: Can't change change root directory to %s, errno %d",
                    mprGetAppName(mpr), homeDir, errno);
            }
            exit(5);
        }
    }
#endif

    /*
     *  Create the top level HTTP service and default HTTP server. Set the initial server root to "."
     */
    http = maCreateHttp(mpr);
    if (http == 0) {
        mprUserError(mpr, "Can't create HTTP service for %s", mprGetAppName(mpr));
        return MPR_ERR_CANT_INITIALIZE;
    }
    server = maCreateServer(http, "default", ".", 0, -1);
    if (server == 0) {
        mprUserError(mpr, "Can't create HTTP server for %s", mprGetAppName(mpr));
        return MPR_ERR_CANT_INITIALIZE;
    }
    if (maConfigureServer(mpr, http, server, configFile, ipAddr, port, documentRoot) < 0) {
        /* mprUserError(mpr, "Can't configure the server, exiting."); */
        exit(6);
    }
    if (mpr->ipAddr) {
        mprLog(mpr, 2, "Server IP address %s", mpr->ipAddr);
    }
    timeText = mprFormatLocalTime(mpr, mprGetTime(mpr));
    mprLog(mpr, 1, "Started at %s", timeText);
    mprFree(timeText);

#if BLD_FEATURE_EJS
    if (ejsPrefix) {
        createEjsAlias(mpr, http, server, ejsPrefix, ejsPath);
    }
#endif

#if BLD_FEATURE_MULTITHREAD
    if (workers >= 0) {
        mprSetMaxWorkers(http, workers);
    }
#endif
#if BLD_WIN_LIKE
    if (!ejsPrefix) {
        writePort(server->defaultHost);
    }
#endif

    if (maStartHttp(http) < 0) {
        mprUserError(mpr, "Can't start HTTP service, exiting.");
        exit(7);
    }

#if BLD_FEATURE_MULTITHREAD
    mprLog(mpr, 1, "HTTP services are ready with max %d worker threads", mprGetMaxWorkers(mpr));
#else
    mprLog(mpr, 1, "HTTP services are ready (single-threaded)");
#endif

    /*
     *  Service I/O events until instructed to exit
     */
    while (!mprIsExiting(mpr)) {
        mprServiceEvents(mpr->dispatcher, -1, MPR_SERVICE_EVENTS | MPR_SERVICE_IO);
    }

    /*
     *  Signal a graceful shutdown
     */
    mprLog(http, 1, "Exiting ...");
    maStopHttp(http);
    mprLog(http, 1, "Exit complete");

#if VXWORKS
    if (mprStop(mpr)) {
        mprFree(mpr);
    }
#endif
    return 0;
}
Beispiel #14
0
/*
    Start the command to run (stdIn and stdOut are named from the client's perspective)
 */
int startProcess(MprCmd *cmd)
{
    MprCmdTaskFn    entryFn;
    SYM_TYPE        symType;
    char            *entryPoint, *program;
    int             i, pri;

    mprLog(cmd, 4, "cmd: start %s", cmd->program);

    entryPoint = 0;
    if (cmd->env) {
        for (i = 0; cmd->env[i]; i++) {
            if (strncmp(cmd->env[i], "entryPoint=", 11) == 0) {
                entryPoint = mprStrdup(cmd, cmd->env[i]);
            }
        }
    }
    program = mprGetPathBase(cmd, cmd->program);
    if (entryPoint == 0) {
        program = mprTrimPathExtension(cmd, program);
#if BLD_HOST_CPU_ARCH == MPR_CPU_IX86 || BLD_HOST_CPU_ARCH == MPR_CPU_IX64
        entryPoint = mprStrcat(cmd, -1, "_", program, "Main", NULL);
#else
        entryPoint = mprStrcat(cmd, -1, program, "Main", NULL);
#endif
    }

    if (symFindByName(sysSymTbl, entryPoint, (char**) &entryFn, &symType) < 0) {
        if (mprLoadModule(cmd, cmd->program, NULL) == 0) {
            mprError(cmd, "start: can't load DLL %s, errno %d", program, mprGetOsError());
            return MPR_ERR_CANT_READ;
        }
        if (symFindByName(sysSymTbl, entryPoint, (char**) &entryFn, &symType) < 0) {
            mprError(cmd, "start: can't find symbol %s, errno %d", entryPoint, mprGetOsError());
            return MPR_ERR_CANT_ACCESS;
        }
    }
    taskPriorityGet(taskIdSelf(), &pri);

    /*
     *  Pass the server output file to become the client stdin.
     */
    cmd->pid = taskSpawn(entryPoint, pri, VX_FP_TASK, MPR_DEFAULT_STACK, (FUNCPTR) cmdTaskEntry, 
        (int) cmd->program, (int) entryFn, (int) cmd, 0, 0, 0, 0, 0, 0, 0);

    if (cmd->pid < 0) {
        mprError(cmd, "start: can't create task %s, errno %d", entryPoint, mprGetOsError());
        mprFree(entryPoint);
        return MPR_ERR_CANT_CREATE;
    }

    mprLog(cmd, 7, "cmd, child taskId %d", cmd->pid);
    mprFree(entryPoint);

    if (semTake(cmd->startCond, MPR_TIMEOUT_START_TASK) != OK) {
        mprError(cmd, "start: child %s did not initialize, errno %d", cmd->program, mprGetOsError());
        return MPR_ERR_CANT_CREATE;
    }
    semDelete(cmd->startCond);
    cmd->startCond = 0;

    return 0;
}
Beispiel #15
0
/*
 *  Determine if this user is specified as being eligible for this realm. We examine the requiredUsers and requiredGroups.
 */
static bool isUserValid(MaAuth *auth, cchar *realm, cchar *user)
{
    MaGroup         *gp;
    MaUser          *up;
    cchar           *tok, *gtok;
    char            ubuf[80], gbuf[80], *key, *requiredUser, *group, *name;
    int             rc, next;

    if (auth->anyValidUser) {
        key = mprStrcat(auth, -1, realm, ":", user, NULL);
        if (auth->users == 0) {
            return 0;
        }
        rc = mprLookupHash(auth->users, key) != 0;
        mprFree(key);
        return rc;
    }

    if (auth->requiredUsers) {
        tok = NULL;
        requiredUser = mprGetWordTok(ubuf, sizeof(ubuf), auth->requiredUsers, " \t", &tok);
        while (requiredUser) {
            if (strcmp(user, requiredUser) == 0) {
                return 1;
            }
            requiredUser = mprGetWordTok(ubuf, sizeof(ubuf), 0, " \t", &tok);
        }
    }

    if (auth->requiredGroups) {
        gtok = NULL;
        group = mprGetWordTok(gbuf, sizeof(gbuf), auth->requiredGroups, " \t", &gtok);
        /*
         *  For each group, check all the users in the group.
         */
        while (group) {
            if (auth->groups == 0) {
                gp = 0;
            } else {
                gp = (MaGroup*) mprLookupHash(auth->groups, group);
            }
            if (gp == 0) {
                mprError(auth, "Can't find group %s", group);
                group = mprGetWordTok(gbuf, sizeof(gbuf), 0, " \t", &gtok);
                continue;
            }

            for (next = 0; (name = mprGetNextItem(gp->users, &next)) != 0; ) {
                if (strcmp(user, name) == 0) {
                    return 1;
                }
            }
            group = mprGetWordTok(gbuf, sizeof(gbuf), 0, " \t", &gtok);
        }
    }

    if (auth->requiredAcl != 0) {
        key = mprStrcat(auth, -1, realm, ":", user, NULL);
        up = (MaUser*) mprLookupHash(auth->users, key);
        if (up) {
            mprLog(auth, 6, "UserRealm \"%s\" has ACL %lx, Required ACL %lx", key, up->acl, auth->requiredAcl);
            if (up->acl & auth->requiredAcl) {
                mprFree(key);
                return 1;
            }
        }
        mprFree(key);
    }
    return 0;
}
Beispiel #16
0
static void startCgi(MaQueue *q)
{
    MaRequest       *req;
    MaConn          *conn;
    MprCmd          *cmd;
    MprHash         *hp;
    cchar           *baseName;
    char            **argv, **envv, *fileName;
    int             index, argc, varCount;

    argv = 0;
    argc = 0;
    conn = q->conn;
    req = conn->request;
    if ((req->form || req->flags & MA_REQ_UPLOADING) && conn->state <= MPR_HTTP_STATE_CONTENT) {
        /*
            Delay starting the CGI process if uploading files or a form request. This enables env vars to be defined
            with file upload and form data before starting the CGI gateway.
         */
        return;
    }

    cmd = q->queueData = mprCreateCmd(req);
    if (conn->http->forkCallback) {
        cmd->forkCallback = conn->http->forkCallback;
        cmd->forkData = conn->http->forkData;
    }
    /*
        Build the commmand line arguments
     */
    argc = 1;                                   /* argv[0] == programName */
    buildArgs(conn, cmd, &argc, &argv);
    fileName = argv[0];

    baseName = mprGetPathBase(q, fileName);
    if (strncmp(baseName, "nph-", 4) == 0 || 
            (strlen(baseName) > 4 && strcmp(&baseName[strlen(baseName) - 4], "-nph") == 0)) {
        /*
            Pretend we've seen the header for Non-parsed Header CGI programs
         */
        cmd->userFlags |= MA_CGI_SEEN_HEADER;
    }

    /*
        Build environment variables
     */
    varCount = mprGetHashCount(req->headers) + mprGetHashCount(req->formVars);
    envv = (char**) mprAlloc(cmd, (varCount + 1) * (int) sizeof(char*));

    index = 0;
    hp = mprGetFirstHash(req->headers);
    while (hp) {
        if (hp->data) {
            envv[index] = mprStrcat(cmd, -1, hp->key, "=", (char*) hp->data, NULL);
            index++;
        }
        hp = mprGetNextHash(req->headers, hp);
    }
    hp = mprGetFirstHash(req->formVars);
    while (hp) {
        if (hp->data) {
            envv[index] = mprStrcat(cmd, -1, hp->key, "=", (char*) hp->data, NULL);
            index++;
        }
        hp = mprGetNextHash(req->formVars, hp);
    }
    envv[index] = 0;
    mprAssert(index <= varCount);

    cmd->stdoutBuf = mprCreateBuf(cmd, MA_BUFSIZE, -1);
    cmd->stderrBuf = mprCreateBuf(cmd, MA_BUFSIZE, -1);
    cmd->lastActivity = mprGetTime(cmd);

    mprSetCmdDir(cmd, mprGetPathDir(q, fileName));
    mprSetCmdCallback(cmd, cgiCallback, conn);

    maSetHeader(conn, 0, "Last-Modified", req->host->currentDate);
    maDontCacheResponse(conn);
    maPutForService(q, maCreateHeaderPacket(q), 0);

    if (mprStartCmd(cmd, argc, argv, envv, MPR_CMD_IN | MPR_CMD_OUT | MPR_CMD_ERR) < 0) {
        maFailRequest(conn, MPR_HTTP_CODE_SERVICE_UNAVAILABLE, "Can't run CGI process: %s, URI %s", fileName, req->url);
        return;
    }
    /*
        This will dedicate this thread to the connection. It will also put the socket into blocking mode.
     */
    maDedicateThreadToConn(conn);
}
Beispiel #17
0
static bool parseArgs(Mpr *mpr, int argc, char **argv)
{
    char    *argp, *key, *value;
    int     i, setWorkers;

    setWorkers = 0;

    for (nextArg = 1; nextArg < argc; nextArg++) {
        argp = argv[nextArg];
        if (*argp != '-') {
            break;
        }

        if (strcmp(argp, "--benchmark") == 0 || strcmp(argp, "-b") == 0) {
            benchmark++;

        } else if (strcmp(argp, "--chunk") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                chunkSize = argv[++nextArg];
                i = atoi(chunkSize);
                if (i < 0) {
                    mprError(mpr, "Bad chunksize %d", i);
                    return 0;
                }
            }

        } else if (strcmp(argp, "--continue") == 0) {
            continueOnErrors++;

        } else if (strcmp(argp, "--cookie") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                mprAddItem(headers, mprCreateKeyPair(headers, "Cookie", argv[++nextArg]));
            }

        } else if (strcmp(argp, "--debug") == 0 || strcmp(argp, "-D") == 0 || strcmp(argp, "--debugger") == 0) {
            mprSetDebugMode(mpr, 1);
            retries = 0;

        } else if (strcmp(argp, "--delete") == 0) {
            method = "DELETE";

        } else if (strcmp(argp, "--form") == 0 || strcmp(argp, "-f") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                if (formData == 0) {
                    formData = mprCreateList(mpr);
                }
                addFormVars(mpr, argv[++nextArg]);
            }

        } else if (strcmp(argp, "--header") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                key = argv[++nextArg];
                if ((value = strchr(key, ':')) == 0) {
                    mprError(mpr, "Bad header format. Must be \"key: value\"");
                    return 0;
                }
                *value++ = '\0';
                while (isspace((int) *value)) {
                    value++;
                }
                mprAddItem(headers, mprCreateKeyPair(headers, key, value));
            }

        } else if (strcmp(argp, "--host") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                host = argv[++nextArg];
            }

        } else if (strcmp(argp, "--http") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                httpVersion = atoi(argv[++nextArg]);
            }

        } else if (strcmp(argp, "--iterations") == 0 || strcmp(argp, "-i") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                iterations = atoi(argv[++nextArg]);
            }

        } else if (strcmp(argp, "--log") == 0 || strcmp(argp, "-l") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                startLogging(mpr, argv[++nextArg]);
            }

        } else if (strcmp(argp, "--method") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                method = argv[++nextArg];
            }

        } else if (strcmp(argp, "--noout") == 0 || strcmp(argp, "-n") == 0  ||
                   strcmp(argp, "--quiet") == 0 || strcmp(argp, "-q") == 0) {
            noout++;

        } else if (strcmp(argp, "--nofollow") == 0) {
            nofollow++;

        } else if (strcmp(argp, "--password") == 0 || strcmp(argp, "-p") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                password = argv[++nextArg];
            }

        } else if (strcmp(argp, "--post") == 0) {
            method = "POST";

        } else if (strcmp(argp, "--printable") == 0) {
            printable++;

        } else if (strcmp(argp, "--put") == 0) {
            method = "PUT";

        } else if (strcmp(argp, "--range") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                if (ranges == 0) {
                    ranges = mprAsprintf(mpr, -1, "bytes=%s", argv[++nextArg]);
                } else {
                    ranges = mprStrcat(mpr, -1, ranges, ",", argv[++nextArg], NULL);
                }
            }
            
        } else if (strcmp(argp, "--retries") == 0 || strcmp(argp, "-r") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                retries = atoi(argv[++nextArg]);
            }
            
        } else if (strcmp(argp, "--sequence") == 0) {
            sequence++;

        } else if (strcmp(argp, "--showCode") == 0 || strcmp(argp, "--showStatus") == 0) {
            showCode++;

        } else if (strcmp(argp, "--show") == 0 || strcmp(argp, "--showHeaders") == 0) {
            showHeaders++;

        } else if (strcmp(argp, "--single") == 0 || strcmp(argp, "-s") == 0) {
            singleStep++;

        } else if (strcmp(argp, "--threads") == 0 || strcmp(argp, "-t") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                loadThreads = atoi(argv[++nextArg]);
            }

        } else if (strcmp(argp, "--timeout") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                timeout = atoi(argv[++nextArg]) * 1000;
            }

        } else if (strcmp(argp, "--upload") == 0 || strcmp(argp, "-u") == 0) {
            upload++;

        } else if (strcmp(argp, "--user") == 0 || strcmp(argp, "--username") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                username = argv[++nextArg];
            }

        } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) {
            verbose++;

        } else if (strcmp(argp, "--workerTheads") == 0 || strcmp(argp, "-w") == 0) {
            if (nextArg >= argc) {
                return 0;
            } else {
                workers = atoi(argv[++nextArg]);
            }
            setWorkers++;

        } else {
            return 0;
            break;
        }
    }
    if (argc == nextArg) {
        return 0;
    }
    argc = argc - nextArg;
    argv = &argv[nextArg];
    target = argv[argc - 1];
    argc--;
    if (argc > 0) {
        /*
         *  Files present on command line
         */
        fileData = mprCreateList(mpr);
        for (i = 0; i < argc; i++) {
            mprAddItem(fileData, argv[i]);
        }
    }
    if (!setWorkers) {
        workers = loadThreads + 2;
    }
    if (method == 0) {
        if (upload || formData) {
            method = "POST";
        } else if (fileData) {
            method = "PUT";
        } else {
            method = "GET";
        }
    }
    return 1;
}
Beispiel #18
0
/*
 *  Add a response cookie
 */
static void setCookie(void *handle, cchar *name, cchar *value, cchar *path, cchar *cookieDomain, int lifetime, bool isSecure)
{
    struct tm   tm;
    cchar       *userAgent, *hostName;
    char        dateStr[64], *cp, *expiresAtt, *expires, *domainAtt, *domain, *secure;

    if (path == 0) {
        path = "/";
    }

    userAgent = getHeader(handle, "HTTP_USER_AGENT");
    hostName = getHeader(handle, "HTTP_HOST");

    /*
     *  Fix for Safari and Bonjour addresses with a trailing ".". Safari discards cookies without a domain specifier
     *  or with a domain that includes a trailing ".". Solution: include an explicit domain and trim the trailing ".".
     *
     *   User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us)
     *       AppleWebKit/530.0+ (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1
     */
    if (cookieDomain == 0 && userAgent && strstr(userAgent, "AppleWebKit") != 0) {
        domain = mprStrdup(mpr, hostName);
        if ((cp = strchr(domain, ':')) != 0) {
            *cp = '\0';
        }
        if (*domain && domain[strlen(domain) - 1] == '.') {
            domain[strlen(domain) - 1] = '\0';
        } else {
            domain = 0;
        }
    } else {
        domain = 0;
    }
    if (domain) {
        domainAtt = "; domain=";
    } else {
        domainAtt = "";
    }
    if (lifetime > 0) {
        mprDecodeUniversalTime(mpr, &tm, mprGetTime(mpr) + (lifetime * MPR_TICKS_PER_SEC));
        mprFormatTime(mpr, MPR_HTTP_DATE, &tm);
        expiresAtt = "; expires=";
        expires = dateStr;

    } else {
        expires = expiresAtt = "";
    }
    if (isSecure) {
        secure = "; secure";
    } else {
        secure = ";";
    }

    /*
     *  Allow multiple cookie headers. Even if the same name. Later definitions take precedence
     */
    setHeader(handle, 1, "Set-Cookie",
              mprStrcat(mpr, -1, name, "=", value, "; path=", path, domainAtt, domain, expiresAtt, expires, secure, NULL));

    setHeader(handle, 0, "Cache-control", "no-cache=\"set-cookie\"");
}
Beispiel #19
0
/*
 *  Parse the request headers. Return true if the header parsed.
 */
static bool parseHeaders(MaConn *conn, MaPacket *packet)
{
    MaHostAddress   *address;
    MaRequest       *req;
    MaHost          *host, *hp;
    MaLimits        *limits;
    MprBuf          *content;
    char            keyBuf[MPR_MAX_STRING];
    char            *key, *value, *cp, *tok;
    int             count, keepAlive;

    req = conn->request;
    host = req->host;
    content = packet->content;
    conn->request->headerPacket = packet;
    limits = &conn->http->limits;
    keepAlive = 0;

    strcpy(keyBuf, "HTTP_");
    mprAssert(strstr((char*) content->start, "\r\n"));

    for (count = 0; content->start[0] != '\r' && !conn->connectionFailed; count++) {

        if (count >= limits->maxNumHeaders) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Too many headers");
            return 0;
        }
        if ((key = getToken(conn, ":")) == 0 || *key == '\0') {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad header format");
            return 0;
        }

        value = getToken(conn, "\r\n");
        while (isspace((int) *value)) {
            value++;
        }
        if (conn->requestFailed) {
            continue;
        }
        mprStrUpper(key);
        for (cp = key; *cp; cp++) {
            if (*cp == '-') {
                *cp = '_';
            }
        }
        mprLog(req, 8, "Key %s, value %s", key, value);
        if (strspn(key, "%<>/\\") > 0) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad header key value");
            continue;
        }

        /*
         *  Define the header with a "HTTP_" prefix
         */
        mprStrcpy(&keyBuf[5], sizeof(keyBuf) - 5, key);
        mprAddDuplicateHash(req->headers, keyBuf, value);

        switch (key[0]) {
        case 'A':
            if (strcmp(key, "AUTHORIZATION") == 0) {
                value = mprStrdup(req, value);
                req->authType = mprStrTok(value, " \t", &tok);
                req->authDetails = tok;

            } else if (strcmp(key, "ACCEPT_CHARSET") == 0) {
                req->acceptCharset = value;

            } else if (strcmp(key, "ACCEPT") == 0) {
                req->accept = value;

            } else if (strcmp(key, "ACCEPT_ENCODING") == 0) {
                req->acceptEncoding = value;
            }
            break;

        case 'C':
            if (strcmp(key, "CONTENT_LENGTH") == 0) {
                if (req->length >= 0) {
                    maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Mulitple content length headers");
                    continue;
                }
                req->length = mprAtoi(value, 10);
                if (req->length < 0) {
                    maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad content length");
                    continue;
                }
                if (req->length >= host->limits->maxBody) {
                    maFailConnection(conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, 
                        "Request content length %Ld is too big. Limit %Ld", req->length, host->limits->maxBody);
                    continue;
                }
                mprAssert(req->length >= 0);
                req->remainingContent = req->length;
                req->contentLengthStr = value;

            } else if (strcmp(key, "CONTENT_RANGE") == 0) {
                /*
                 *  This headers specifies the range of any posted body data
                 *  Format is:  Content-Range: bytes n1-n2/length
                 *  Where n1 is first byte pos and n2 is last byte pos
                 */
                char    *sp;
                int     start, end, size;

                start = end = size = -1;
                sp = value;
                while (*sp && !isdigit((int) *sp)) {
                    sp++;
                }
                if (*sp) {
                    start = (int) mprAtoi(sp, 10);

                    if ((sp = strchr(sp, '-')) != 0) {
                        end = (int) mprAtoi(++sp, 10);
                    }
                    if ((sp = strchr(sp, '/')) != 0) {
                        /*
                         *  Note this is not the content length transmitted, but the original size of the input of which 
                         *  the client is transmitting only a portion.
                         */
                        size = (int) mprAtoi(++sp, 10);
                    }
                }
                if (start < 0 || end < 0 || size < 0 || end <= start) {
                    maFailRequest(conn, MPR_HTTP_CODE_RANGE_NOT_SATISFIABLE, "Bad content range");
                    continue;
                }
                req->inputRange = maCreateRange(conn, start, end);

            } else if (strcmp(key, "CONTENT_TYPE") == 0) {
                req->mimeType = value;
                req->form = strstr(value, "application/x-www-form-urlencoded") != 0;

            } else if (strcmp(key, "COOKIE") == 0) {
                if (req->cookie && *req->cookie) {
                    req->cookie = mprStrcat(req, -1, req->cookie, "; ", value, NULL);
                } else {
                    req->cookie = value;
                }

            } else if (strcmp(key, "CONNECTION") == 0) {
                req->connection = value;
                if (mprStrcmpAnyCase(value, "KEEP-ALIVE") == 0) {
                    keepAlive++;

                } else if (mprStrcmpAnyCase(value, "CLOSE") == 0) {
                    conn->keepAliveCount = 0;
                }
                if (!host->keepAlive) {
                    conn->keepAliveCount = 0;
                }
            }
            break;

        case 'F':
            req->forwarded = value;
            break;

        case 'H':
            if (strcmp(key, "HOST") == 0) {
                req->hostName = value;
                address = conn->address;
                if (maIsNamedVirtualHostAddress(address)) {
                    hp = maLookupVirtualHost(address, value);
                    if (hp == 0) {
                        maFailRequest(conn, 404, "No host to serve request. Searching for %s", value);
                        mprLog(conn, 1, "Can't find virtual host %s", value);
                        continue;
                    }
                    req->host = hp;
                    /*
                     *  Reassign this request to a new host
                     */
                    maRemoveConn(host, conn);
                    host = hp;
                    conn->host = hp;
                    maAddConn(hp, conn);
                }
            }
            break;

        case 'I':
            if ((strcmp(key, "IF_MODIFIED_SINCE") == 0) || (strcmp(key, "IF_UNMODIFIED_SINCE") == 0)) {
                MprTime     newDate = 0;
                char        *cp;
                bool        ifModified = (key[3] == 'M');

                if ((cp = strchr(value, ';')) != 0) {
                    *cp = '\0';
                }
                if (mprParseTime(conn, &newDate, value, MPR_UTC_TIMEZONE, NULL) < 0) {
                    mprAssert(0);
                    break;
                }
                if (newDate) {
                    setIfModifiedDate(conn, newDate, ifModified);
                    req->flags |= MA_REQ_IF_MODIFIED;
                }

            } else if ((strcmp(key, "IF_MATCH") == 0) || (strcmp(key, "IF_NONE_MATCH") == 0)) {
                char    *word, *tok;
                bool    ifMatch = key[3] == 'M';

                if ((tok = strchr(value, ';')) != 0) {
                    *tok = '\0';
                }
                req->ifMatch = ifMatch;
                req->flags |= MA_REQ_IF_MODIFIED;

                value = mprStrdup(conn, value);
                word = mprStrTok(value, " ,", &tok);
                while (word) {
                    addMatchEtag(conn, word);
                    word = mprStrTok(0, " ,", &tok);
                }

            } else if (strcmp(key, "IF_RANGE") == 0) {
                char    *word, *tok;

                if ((tok = strchr(value, ';')) != 0) {
                    *tok = '\0';
                }
                req->ifMatch = 1;
                req->flags |= MA_REQ_IF_MODIFIED;

                value = mprStrdup(conn, value);
                word = mprStrTok(value, " ,", &tok);
                while (word) {
                    addMatchEtag(conn, word);
                    word = mprStrTok(0, " ,", &tok);
                }
            }
            break;

        case 'P':
            if (strcmp(key, "PRAGMA") == 0) {
                req->pragma = value;
            }
            break;

        case 'R':
            if (strcmp(key, "RANGE") == 0) {
                if (!parseRange(conn, value)) {
                    maFailRequest(conn, MPR_HTTP_CODE_RANGE_NOT_SATISFIABLE, "Bad range");
                }
            } else if (strcmp(key, "REFERER") == 0) {
                /* NOTE: yes the header is misspelt in the spec */
                req->referer = value;
            }
            break;

        case 'T':
            if (strcmp(key, "TRANSFER_ENCODING") == 0) {
                mprStrLower(value);
                if (strcmp(value, "chunked") == 0) {
                    req->flags |= MA_REQ_CHUNKED;
                    /*
                     *  This will be revised by the chunk filter as chunks are processed and will be set to zero when the
                     *  last chunk has been received.
                     */
                    req->remainingContent = MAXINT;
                }
            }
            break;
        
#if BLD_DEBUG
        case 'X':
            if (strcmp(key, "X_APPWEB_CHUNK_SIZE") == 0) {
                mprStrUpper(value);
                conn->response->chunkSize = atoi(value);
                if (conn->response->chunkSize <= 0) {
                    conn->response->chunkSize = 0;
                } else if (conn->response->chunkSize > conn->http->limits.maxChunkSize) {
                    conn->response->chunkSize = conn->http->limits.maxChunkSize;
                }
            }
            break;
#endif

        case 'U':
            if (strcmp(key, "USER_AGENT") == 0) {
                req->userAgent = value;
            }
            break;
        }
    }
    if (conn->protocol == 0 && !keepAlive) {
        conn->keepAliveCount = 0;
    }
    if (!(req->flags & MA_REQ_CHUNKED)) {
        /*  
         *  Step over "\r\n" after headers. As an optimization, don't do this if chunked so chunking can parse a single
         *  chunk delimiter of "\r\nSIZE ...\r\n"
         */
        mprAdjustBufStart(content, 2);
    }
    mprLog(conn, 3, "Select host \"%s\"", conn->host->name);

    if (maSetRequestUri(conn, req->url, "") < 0) {
        maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad URI format");
        return 0;
    }
    if (conn->host->secure) {
        req->parsedUri->scheme = mprStrdup(req, "https");
    }
    req->parsedUri->port = conn->sock->port;
    req->parsedUri->host = req->hostName ? req->hostName : conn->host->name;
    return 1;
}
Beispiel #20
0
int MprTestSession::setupTests(MprTestResult *result, Mpr *mpr, int argc, 
	char *argv[], char *switches)
{
	char			switchBuf[80];
	char			*programName, *argp;
	int				errflg, c, i, l;
#if BLD_FEATURE_LOG
	char			*logSpec;
#endif

	this->mpr = mpr;
	programName = mprGetBaseName(argv[0]);
	errflg = 0;
#if BLD_FEATURE_LOG
	logSpec = "stdout:1";
	logger = new MprLogToFile();
#endif

	switchBuf[0] = '\0';
	mprStrcat(switchBuf, sizeof(switchBuf), 0, "cDeg:i:l:n:msT:t:v?", 
		switches, (void*) 0);
	MprCmdLine	cmdLine(argc, argv, switchBuf);

	while ((c = cmdLine.next(&argp)) != EOF) {
		switch(c) {
		case 'c':
			result->setContinueOnFailures(1);
			break;

		case 'D':
			mprSetDebugMode(1);
			result->setDebugOnFailures(1);
			break;

		case 'e':
			needEventsThread = 1;
			break;

		case 'g':
			testGroups->parse(argp);
			break;

		case 'i':
			iterations = atoi(argp);
			break;

		case 'l':
#if BLD_FEATURE_LOG
			logSpec = argp;
#endif
			break;

		case 'n':
			l = atoi(argp);
			if (l == 0) {
				sessionLevel = MPR_BASIC;
			} else if (l == 1) {
				sessionLevel = MPR_THOROUGH;
			} else {
				sessionLevel = MPR_DEDICATED;
			}
			break;

		case 'm':
			mprRequestMemStats(1);
			break;

		case 's':
			result->setSingleStep(1);
			break;

		case 't':
			i = atoi(argp);
			if (i <= 0 || i > 100) {
				mprFprintf(MPR_STDERR, "%s: Bad number of threads (0-100)\n", 
					programName);
				exit(2);
			
			}
#if BLD_FEATURE_MULTITHREAD
			numThreads = i;
#endif
			break;

		case 'T':
#if BLD_FEATURE_MULTITHREAD
			poolThreads = atoi(argp);
#endif
			break;

		case 'v':
			verbose++;
			break;

		default:
			//
			//	Ignore args we don't understand
			//
			break;

		case '?':
			errflg++;
			break;
		}
	}
	if (errflg) {
		mprFprintf(MPR_STDERR, 
			"usage: %s [-cDemsv] [-g groups] [-i iterations] "
			"[-l logSpec] [-n testLevel] [-T poolThreads] [-t threads]\n", 
			programName);
		exit(2);
	}

#if !BLD_FEATURE_MULTITHREAD
	needEventsThread = 0;
#endif

#if BLD_FEATURE_LOG
	mpr->addListener(logger);
	mpr->setLogSpec(logSpec);
#endif

	initSignals();

	this->argc = argc;
	this->argv = argv;
	this->firstArg = cmdLine.firstArg();

#if BLD_FEATURE_MULTITHREAD
	mpr->setMaxPoolThreads(poolThreads);
#endif
	if (mpr->start(needEventsThread ? MPR_SERVICE_THREAD : 0) < 0) {
		return MPR_ERR_CANT_INITIALIZE;
	}

	result->adjustThreadCount(numThreads);
	result->setVerbosity(verbose);
	if (result->getListenerCount() == 0) {
		result->addListener(new MprTestListener("__default__"));
	}

	if (verbose) {
		mprFprintf(MPR_STDOUT, 
			"Testing: iterations %d, threads %d, pool %d, service thread %d\n", 
			iterations, numThreads, poolThreads, needEventsThread);
	}

	//
	//	Use current session object for the main thread
	//
	sessions = (MprTestSession**) mprMalloc(sizeof(MprTestSession*) * 
		numThreads);
	sessions[0] = this;
	if (sessions[0]->initializeClasses(result) < 0) {
		exit(3);
	}

#if BLD_FEATURE_MULTITHREAD
	//
	//	Now clone this session object for all other threads
	//
	for (i = 1; i < numThreads; i++) {
		char tName[64];
		sessions[i] = this->newSession();
		sessions[i]->setResult(result);
		sessions[i]->cloneSettings(this);
		mprSprintf(tName, sizeof(tName), "test.%d", i);
	}
#endif
	return 0;
}
Beispiel #21
0
/*
    If the program has a UNIX style "#!/program" string at the start of the file that program will be selected 
    and the original program will be passed as the first arg to that program with argv[] appended after that. If 
    the program is not found, this routine supports a safe intelligent search for the command. If all else fails, 
    we just return in program the fileName we were passed in. script will be set if we are modifying the program 
    to run and we have extracted the name of the file to run as a script.
 */
static void findExecutable(MaConn *conn, char **program, char **script, char **bangScript, char *fileName)
{
    MaRequest       *req;
    MaResponse      *resp;
    MaLocation      *location;
    MprHash         *hp;
    MprFile         *file;
    cchar           *actionProgram, *ext, *cmdShell;
    char            *tok, buf[MPR_MAX_FNAME + 1], *path;

    req = conn->request;
    resp = conn->response;
    location = req->location;

    *bangScript = 0;
    *script = 0;
    *program = 0;
    path = 0;

    actionProgram = maGetMimeActionProgram(conn->host, req->mimeType);
    ext = resp->extension;

    /*
        If not found, go looking for the fileName with the extensions defined in appweb.conf. 
        NOTE: we don't use PATH deliberately!!!
     */
    if (access(fileName, X_OK) < 0 /* && *ext == '\0' */) {
        for (hp = 0; (hp = mprGetNextHash(location->extensions, hp)) != 0; ) {
            path = mprStrcat(resp, -1, fileName, ".", hp->key, NULL);
            if (access(path, X_OK) == 0) {
                break;
            }
            mprFree(path);
            path = 0;
        }
        if (hp) {
            ext = hp->key;
        } else {
            path = fileName;
        }

    } else {
        path = fileName;
    }
    mprAssert(path && *path);

#if BLD_WIN_LIKE
    if (ext && (strcmp(ext, ".bat") == 0 || strcmp(ext, ".cmd") == 0)) {
        /*
            Let a mime action override COMSPEC
         */
        if (actionProgram) {
            cmdShell = actionProgram;
        } else {
            cmdShell = getenv("COMSPEC");
        }
        if (cmdShell == 0) {
            cmdShell = "cmd.exe";
        }
        *script = mprStrdup(resp, path);
        *program = mprStrdup(resp, cmdShell);
        return;
    }
#endif

    if ((file = mprOpen(resp, path, O_RDONLY, 0)) != 0) {
        if (mprRead(file, buf, MPR_MAX_FNAME) > 0) {
            mprFree(file);
            buf[MPR_MAX_FNAME] = '\0';
            if (buf[0] == '#' && buf[1] == '!') {
                cmdShell = mprStrTok(&buf[2], " \t\r\n", &tok);
                if (cmdShell[0] != '/' && (cmdShell[0] != '\0' && cmdShell[1] != ':')) {
                    /*
                        If we can't access the command shell and the command is not an absolute path, 
                        look in the same directory as the script.
                     */
                    if (mprPathExists(resp, cmdShell, X_OK)) {
                        cmdShell = mprJoinPath(resp, mprGetPathDir(resp, path), cmdShell);
                    }
                }
                if (actionProgram) {
                    *program = mprStrdup(resp, actionProgram);
                } else {
                    *program = mprStrdup(resp, cmdShell);
                }
                *bangScript = mprStrdup(resp, path);
                return;
            }
        } else {
            mprFree(file);
        }
    }

    if (actionProgram) {
        *program = mprStrdup(resp, actionProgram);
        *bangScript = mprStrdup(resp, path);
    } else {
        *program = mprStrdup(resp, path);
    }
    return;
}
Beispiel #22
0
/*
 *  When we come here, we've already matched either a location block or an extension
 */
static int run(request_rec *r) 
{
    EjsDirConfig        *dir;
    EjsServerConfig     *server;
    cchar               *ext;

    MaRequest       *req;
    MaResponse      *resp;
    MaConn          *conn;
    MaAlias         *alias;
    MaLocation      *location;
    EjsWeb          *web;
    cchar           *sep, *prefix;
    char            *urlBase, *dir, *app, *url, *cp;
    int             flags, locFlags;

    if (!r->handler || strcasecmp(r->handler, "ejs") != 0) {
        return DECLINED;
    }

    dir = getDir(r)
    server = getServer(r->XXX);

    //  EjsAlias should probably be creating a directory block. These flags should probably be in a directory
    if (loc->flags & (MA_LOC_APP | MA_LOC_APP_DIR)) {

        /*
         *  Send non-ejs content under web to another handler, typically the file handler.
         */
        if (strncmp(&req->url[loc->prefixLen], "web/", 4) == 0) {
            if (!(ext && strcmp(ext, "ejs") == 0)) {
                return DECLINED;
            }

        } else {
            if (ext && strcmp(ext, "ejs") == 0) {
                maFormatBody(conn, "Bad Request", "Can't serve *.ejs files outside web directory");
                maFailRequest(conn, MPR_HTTP_CODE_BAD_REQUEST, "Can't server *.ejs files outside web directory");
                return HTTP_XXX;
            }
        }
    }

    flags = 0;
    url = 0;

    locFlags = location->flags;
    
    if (locFlags & MA_LOC_APP) {
        app = mprStrTrim(mprStrdup(q, prefix), "/");
        url = &req->url[alias->prefixLen];
        dir = mprStrdup(resp, alias->filename);
        if (*url != '/') {
            url--;
        }
        urlBase = mprStrdup(resp, prefix);
        
    } else if (locFlags & MA_LOC_APP_DIR) {
        url = &req->url[alias->prefixLen];
        app = mprStrdup(resp, url);
        if ((cp = strchr(app, '/')) != 0) {
            url = mprStrdup(resp, cp);
            *cp = '\0';
        }
        sep = prefix[strlen(prefix) - 1] == '/' ? "" : "/";
        dir = mprStrcat(resp, &dir, alias->filename, sep, app, NULL);
        urlBase = mprStrcat(resp, prefix, sep, app, NULL);

    } else {
        app = 0;
        dir = mprStrdup(resp, alias->filename);
        url = &req->url[alias->prefixLen];
        flags |= EJS_WEB_FLAG_SOLO;
        if (*url != '/') {
            url--;
        }        
        urlBase = mprStrdup(resp, prefix);
    }
    mprStrTrim(urlBase, "/");
    mprStrTrim(dir, "/");
    
    if (location->flags & MA_LOC_BROWSER) {
        flags |= EJS_WEB_FLAG_BROWSER_ERRORS;
    }
    if (location->flags & MA_LOC_AUTO_SESSION) {
        flags |= EJS_WEB_FLAG_SESSION;
    }

    /*
     *  Var         Stand-Alone             App                         AppDir
     *  app         0                       carmen                      carmen
     *  dir         /Users/mob/....         /Users/mob/hg/carmen        /Users/mob/hg/carmen
     *  urlBase                             /xg/carmen                  /carmen
     *  url                                 stock                       stock
     */
    web = ejsCreateWebRequest(req, q->stage->stageData, conn, app, dir, urlBase, url, req->cookie, flags);
    if (web == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't create Ejs web object for %s", req->url);
        return;
    }
    q->queueData = web;
    maSetHeader(conn, 0, "Last-Modified", req->host->currentDate);
    maDontCacheResponse(conn);

    if (r->method_number != M_GET) {
        return HTTP_METHOD_NOT_ALLOWED;
    }

    if (ejsProcessWebRequest((EjsWeb*) r, &msg) < 0) {
        if (web->flags & EJS_WEB_FLAG_BROWSER_ERRORS) {
            maFormatBody(conn, "Request Failed", "%s", msg);
        }
        maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, msg);
        mprFree(msg);
    }

    ap_set_content_type(r, "text/html");
    ap_rputs("<html><title>Hello World!</title><body><p>Hello World</p></body></html>\r\n", r);

#if 0
    if ((err = set_content_length(r, r->finfo.st_stize)) || (err = set_last_modified(r, r->finfo.st_mtime)))
        return err;
    if (r->finof.st_mode == 0) 
        return NOT_FOUND;
    fopen(r->filename, "r");

    if (!r->main) {
        /* Not internal redirect */
        apr_table_set(r->headers_out, "X-ejs", "Under construction");
    }
    register_timeout("send", r);
    send_http_header(r);
    if (!r->header_only)
        send_fd(f, r);
    pfclose(r->pool, f);
#endif

    return OK;
}
Beispiel #23
0
int MaHost::mapToStorage(MaRequest *rq, char *path, int pathLen, char *uri,
	int flags)
{
	MaAlias		*ap;
	MaDir		*dir;
	char		urlBuf[MPR_HTTP_MAX_URL];
	char		*base, *aliasName, *prefix;
	int			len, redirectCode, prefixLen;

	mprAssert(path);
	mprAssert(pathLen > 0);

	*path = '\0';

	lock();

	//
	//	FUTURE - Could optimize by having a hash lookup for alias prefixes.
	//
	ap = (MaAlias*) aliases.getFirst();
	while (ap) {
		aliasName = ap->getName();
		prefix = ap->getPrefix();
		prefixLen = ap->getPrefixLen();

		//
		//	Note that for Aliases with redirects, the aliasName is a URL and
		//	not a document path.
		//
		if (strncmp(prefix, uri, prefixLen) == 0) {
			redirectCode = ap->getRedirectCode();
			if (redirectCode) {
				if (flags & MPR_HTTP_REDIRECT) {
					rq->redirect(redirectCode, aliasName);
					rq->flushOutput(MPR_HTTP_FOREGROUND_FLUSH, 
						MPR_HTTP_FINISH_REQUEST);
				} else {
					mprStrcpy(path, pathLen, aliasName);
				}
				unlock();
				return 0;
			}

			base = &uri[prefixLen];
			while (*base == '/') {
				base++;
			}
			if (aliasName[strlen(aliasName) - 1] == '/') {
				len = mprSprintf(path, pathLen, "%s%s", aliasName, base);
			} else if (*base) {
				len = mprSprintf(path, pathLen, "%s/%s", aliasName, base);
			} else {
				len = mprStrcpy(path, pathLen, aliasName);
			}

			dir = 0;

			if (*base != '\0') {
				//
				//	There was some extra URI past the matching alias prefix 
				//	portion
				//
#if WIN
				//
				//	Windows will ignore trailing "." and " ". We must reject
				//	here as the URL probably won't match due to the trailing
				//	character and the copyHandler will return the unprocessed
				//	content to the user. Bad.
				//
				int lastc = base[strlen(base) - 1];
				if (lastc == '.' || lastc == ' ') {
					unlock();
					return MPR_ERR_CANT_ACCESS;
				}
#endif		
				unlock();
				return 0;

			} else {
				if (*prefix == '\0') {
					prefix = "/";
				}
				//
				//	The URL matched the alias exactly so we change the URI
				//	to match the prefix as we may have changed the extension
				//
				mprStrcpy(urlBuf, sizeof(urlBuf), prefix);

				MaUrl *url = rq->getUrl();

				if (strcmp(urlBuf, url->uri) != 0) {
					if (url->query && *url->query) {
						mprStrcat(urlBuf, sizeof(urlBuf), "?", url->query, 
							(void*) 0);
					}
					if (flags & MPR_HTTP_REMATCH) {
						rq->setUri(urlBuf);
						rq->parseUri();
					}
				}
			}

			if (flags & MPR_HTTP_REMATCH) {
				rq->deleteHandlers();
			}
			unlock();
			return 0;
		}
		ap = (MaAlias*) aliases.getNext(ap);
	}
	unlock();
	return MPR_ERR_NOT_FOUND;
}
Beispiel #24
0
/*
 *  function Worker(script: String = null, options: Object = null)
 *
 *  Script is optional. If supplied, the script is run immediately by a worker thread. This call
 *  does not block. Options are: search and name.
 */
static EjsVar *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv)
{
    Ejs             *wejs;
    EjsVar          *options, *value;
    EjsName         qname;
    EjsWorker       *self;
    cchar           *search, *name;

    worker->ejs = ejs;
    worker->state = EJS_WORKER_BEGIN;

    options = (argc == 2) ? (EjsVar*) argv[1]: NULL;
    name = 0;

    search = ejs->ejsPath;
    if (options) {
        value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "search"));
        if (ejsIsString(value)) {
            search = ejsGetString(value);
        }
        value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "name"));
        if (ejsIsString(value)) {
            name = ejsGetString(value);
        }
    }

    if (name) {
        worker->name = mprStrdup(worker, name);
    } else {
        worker->name = mprAsprintf(worker, -1, "worker-%d", mprGetListCount(ejs->workers));
    }

    /*
     *  Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker.
     */
    wejs = ejsCreate(ejs->service, NULL, search, 0);
    if (wejs == 0) {
        ejsThrowMemoryError(ejs);
        return 0;
    }
    worker->pair = self = ejsCreateWorker(wejs);
    self->state = EJS_WORKER_BEGIN;
    self->ejs = wejs;
    self->inside = 1;
    self->pair = worker;
    self->name = mprStrcat(self, -1, "inside-", worker->name, NULL);

    ejsSetProperty(ejs,  (EjsVar*) worker, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(ejs, self->name));
    ejsSetProperty(wejs, (EjsVar*) self,   ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(wejs, self->name));
    ejsSetProperty(wejs, wejs->global, ES_ejs_sys_worker_self, (EjsVar*) self);

    /*
     *  Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...)
     */
    ejsDefineReservedNamespace(wejs, wejs->globalBlock, 0, EJS_WORKER_NAMESPACE);

    /*
     *  Make the inside worker permanent so we don't need to worry about whether worker->pair->ejs is valid
     */
    self->obj.var.permanent = 1;
    
    if (argc > 0 && ejsIsPath(argv[0])) {
        addWorker(ejs, worker);
        worker->scriptFile = mprStrdup(worker, ((EjsPath*) argv[0])->path);
        worker->state = EJS_WORKER_STARTED;
        worker->obj.var.permanent = 1;
        if (mprStartWorker(ejs, (MprWorkerProc) workerMain, (void*) worker, MPR_NORMAL_PRIORITY) < 0) {
            ejsThrowStateError(ejs, "Can't start worker");
            worker->obj.var.permanent = 0;
            return 0;
        }
    }
    return (EjsVar*) worker;
}