Пример #1
0
static void readBody(HttpConn *conn, MprFile *outFile)
{
    char        buf[BIT_MAX_BUFFER];
    cchar       *result;
    ssize       bytes;

    while (!conn->error && conn->sock && (bytes = httpRead(conn, buf, sizeof(buf))) > 0) {
        if (!app->noout) {
            result = formatOutput(conn, buf, &bytes);
            if (result) {
                mprWriteFile(outFile, result, bytes);
            }
        }
#if FUTURE
        //  This should be pushed into a range filter.
        //  Buffer all output and then parsing can work
        type = httpGetHeader(conn, "Content-Type");
        if (scontains(type, "multipart/byteranges")) {
            if ((boundary = scontains(type, "boundary=")) != 0) {
                boundary += 9;
                if (*boundary) {
                    boundary = sfmt("--%s\r\n", boundary);
                }
            }
        }
#endif
    }
}
Пример #2
0
/*
    See if there is acceptable cached content for this request. If so, return true.
    Will setup tx->cacheBuffer as a side-effect if the output should be captured and cached.
 */
static bool fetchCachedResponse(HttpConn *conn)
{
    HttpTx      *tx;
    MprTime     modified, when;
    cchar       *value, *key, *tag;
    int         status, cacheOk, canUseClientCache;

    tx = conn->tx;

    /*
        Transparent caching. Manual caching must manually call httpWriteCached()
     */
    key = makeCacheKey(conn);
    if ((value = httpGetHeader(conn, "Cache-Control")) != 0 && 
            (scontains(value, "max-age=0") == 0 || scontains(value, "no-cache") == 0)) {
        mprLog(3, "Client reload. Cache-control header '%s' rejects use of cached content.", value);

    } else if ((tx->cachedContent = mprReadCache(conn->host->responseCache, key, &modified, 0)) != 0) {
        /*
            See if a NotModified response can be served. This is much faster than sending the response.
            Observe headers:
                If-None-Match: "ec18d-54-4d706a63"
                If-Modified-Since: Fri, 04 Mar 2012 04:28:19 GMT
            Set status to OK when content must be transmitted.
         */
        cacheOk = 1;
        canUseClientCache = 0;
        tag = mprGetMD5(key);
        if ((value = httpGetHeader(conn, "If-None-Match")) != 0) {
            canUseClientCache = 1;
            if (scmp(value, tag) != 0) {
                cacheOk = 0;
            }
        }
        if (cacheOk && (value = httpGetHeader(conn, "If-Modified-Since")) != 0) {
            canUseClientCache = 1;
            mprParseTime(&when, value, 0, 0);
            if (modified > when) {
                cacheOk = 0;
            }
        }
        status = (canUseClientCache && cacheOk) ? HTTP_CODE_NOT_MODIFIED : HTTP_CODE_OK;
        mprLog(3, "cacheHandler: Use cached content for %s, status %d", key, status);
        httpSetStatus(conn, status);
        httpSetHeader(conn, "Etag", mprGetMD5(key));
        httpSetHeader(conn, "Last-Modified", mprFormatUniversalTime(MPR_HTTP_DATE, modified));
        return 1;
    }
    mprLog(3, "cacheHandler: No cached content for %s", key);
    return 0;
}
Пример #3
0
/*
    Test if the version is acceptable based on the supplied critera.
    The acceptable formats for criteria are:

    VER                             Allows prereleases
    1.2.[*xX]                       Wild card version portion. (allows prereleases).
    ~VER                            Compatible with VER at the least significant level.
                                    ~1.2.3 == (>=1.2.3 <1.3.0) Compatible at the patch level
                                    ~1.2 == 1.2.x   Compatible at the minor level
                                    ~1 == 1.x   Compatible at the major level
    ^VER                            Compatible with VER at the most significant level.
                                    ^0.2.3 == 0.2.3 <= VER < 0.3.0
                                    ^1.2.3 == 1.2.3 <= VER < 2.0.0
    [>, >=, <, <=, ==, !=]VER       Create range relative to given version
    EXPR1 - EXPR2                   <=EXPR1 <=EXPR2
    EXPR1 || EXPR2 ...              EXPR1 OR EXPR2
    EXPR1 && EXPR2 ...              EXPR1 AND EXPR2
    EXPR1 EXPR2 ...                 EXPR1 AND EXPR2

    Pre-release versions will only match if the criteria contains a "-.*" prerelease suffix
*/
PUBLIC bool mprIsVersionObjAcceptable(MprVersion *vp, cchar *criteria)
{
    char        *expr, *exprTok, *range, *rangeTok, *low, *high;
    bool        allMatched;

    if (!vp->ok) {
        return 0;
    }
    if (!criteria || *criteria == '\0') {
        return 1;
    }
    criteria = cleanVersion(criteria);
    for (range = (char*) criteria; stok(range, "||", &rangeTok) != 0; range = rangeTok) {
        range = strim(range, " \t", 0);
        allMatched = 1;
        for (expr = (char*) range; sptok(expr, "&&", &exprTok) != 0; expr = exprTok) {
            if (scontains(expr, " - ")) {
                low = sptok(expr, " - ", &high);
                return inRange(vp, sjoin(">=", low, NULL)) && inRange(vp, sjoin("<=", high, NULL));
            }
            if (!inRange(vp, expr)) {
                allMatched = 0;
                break;
            }
        }
        if (allMatched) {
            return 1;
        }
    }
    return 0;
}
Пример #4
0
PUBLIC void espDefineAction(HttpRoute *route, cchar *target, void *callback)
{
    EspRoute    *eroute;
    char        *action, *controller;

    assert(route);
    assert(target && *target);
    assert(callback);

    eroute = ((EspRoute*) route->eroute)->top;
    if (target) {
#if DEPRECATED || 1
        /*
            Keep till version 6
         */
        if (scontains(target, "-cmd-")) {
            target = sreplace(target, "-cmd-", "/");
        } else if (schr(target, '-')) {
            controller = ssplit(sclone(target), "-", (char**) &action);
            target = sjoin(controller, "/", action, NULL);
        }
#endif
        if (!eroute->actions) {
            eroute->actions = mprCreateHash(-1, MPR_HASH_STATIC_VALUES);
        }
        mprAddKey(eroute->actions, target, callback);
    }
}
Пример #5
0
/*
    Check if the layout has changed. Returns false if the layout does not exist.
 */
static bool layoutIsStale(EspRoute *eroute, cchar *source, cchar *module)
{
    char    *data, *lpath, *quote;
    cchar   *layout, *layoutsDir;
    ssize   len;
    bool    stale;
    int     recompile;

    stale = 0;
    layoutsDir = httpGetDir(eroute->route, "LAYOUTS");
    if ((data = mprReadPathContents(source, &len)) != 0) {
        if ((lpath = scontains(data, "@ layout \"")) != 0) {
            lpath = strim(&lpath[10], " ", MPR_TRIM_BOTH);
            if ((quote = schr(lpath, '"')) != 0) {
                *quote = '\0';
            }
            layout = (layoutsDir && *lpath) ? mprJoinPath(layoutsDir, lpath) : 0;
        } else {
            layout = (layoutsDir) ? mprJoinPath(layoutsDir, "default.esp") : 0;
        }
        if (layout) {
            stale = espModuleIsStale(layout, module, &recompile);
            if (stale) {
                mprLog("info esp", 4, "esp layout %s is newer than module %s", layout, module);
            }
        }
    }
    return stale;
}
Пример #6
0
PUBLIC int httpSetGroupAccount(cchar *newGroup)
{
    Http    *http;

    http = HTTP;
    if (smatch(newGroup, "HTTP") || smatch(newGroup, "APPWEB")) {
#if ME_UNIX_LIKE
        /* Only change group if root */
        if (getuid() != 0) {
            return 0;
        }
#endif
#if MACOSX || FREEBSD
        newGroup = "_www";
#elif LINUX || ME_UNIX_LIKE
{
        char    *buf;
        newGroup = "nobody";
        /*
            Debian has nogroup, Fedora has nobody. Ugh!
         */
        if ((buf = mprReadPathContents("/etc/group", NULL)) != 0) {
            if (scontains(buf, "nogroup:")) {
                newGroup = "nogroup";
            }
        }
}
#elif WINDOWS
        newGroup = "Administrator";
#endif
    }
#if ME_UNIX_LIKE
    struct group    *gp;

    if (snumber(newGroup)) {
        http->gid = atoi(newGroup);
        if ((gp = getgrgid(http->gid)) == 0) {
            mprLog("critical http", 0, "Bad group id: %d", http->gid);
            return MPR_ERR_CANT_ACCESS;
        }
        newGroup = gp->gr_name;

    } else {
        if ((gp = getgrnam(newGroup)) == 0) {
            mprLog("critical http", 0, "Bad group name: %s", newGroup);
            return MPR_ERR_CANT_ACCESS;
        }
        http->gid = gp->gr_gid;
    }
    http->groupChanged = 1;
#endif
    http->group = sclone(newGroup);
    return 0;
}
Пример #7
0
HttpHost *httpLookupHostOnEndpoint(HttpEndpoint *endpoint, cchar *name)
{
    HttpHost    *host;
    int         next;

    if (name == 0 || *name == '\0') {
        return mprGetFirstItem(endpoint->hosts);
    }
    for (next = 0; (host = mprGetNextItem(endpoint->hosts, &next)) != 0; ) {
        if (smatch(host->name, name)) {
            return host;
        }
        if (*host->name == '*') {
            if (host->name[1] == '\0') {
                return host;
            }
            if (scontains(name, &host->name[1])) {
                return host;
            }
        }
    }
    return 0;
}
Пример #8
0
MAIN(appweb, int argc, char **argv, char **envp)
{
    Mpr     *mpr;
    cchar   *argp, *jail;
    char    *logSpec, *traceSpec;
    int     argind;

    jail = 0;
    logSpec = 0;
    traceSpec = 0;

    if ((mpr = mprCreate(argc, argv, MPR_USER_EVENTS_THREAD)) == NULL) {
        exit(1);
    }
    if ((app = mprAllocObj(AppwebApp, manageApp)) == NULL) {
        exit(2);
    }
    mprAddRoot(app);
    mprAddStandardSignals();
#if ME_ROM
    extern MprRomInode romFiles[];
    mprSetRomFileSystem(romFiles);
#endif

    if (httpCreate(HTTP_CLIENT_SIDE | HTTP_SERVER_SIDE) == 0) {
        exit(3);
    }
    app->mpr = mpr;
    app->workers = -1;
    app->home = sclone(ME_SERVER_ROOT);
    app->documents = app->home;
    argc = mpr->argc;
    argv = (char**) mpr->argv;

    for (argind = 1; argind < argc; argind++) {
        argp = argv[argind];
        if (*argp != '-') {
            break;
        }
        if (smatch(argp, "--config") || smatch(argp, "--conf")) {
            if (argind >= argc) {
                usageError();
            }
            app->configFile = sclone(argv[++argind]);

#if ME_UNIX_LIKE
        } else if (smatch(argp, "--chroot")) {
            if (argind >= argc) {
                usageError();
            }
            jail = mprGetAbsPath(argv[++argind]);
#endif

        } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) {
            mprSetDebugMode(1);

        } else if (smatch(argp, "--exe")) {
            if (argind >= argc) {
                usageError();
            }
            mpr->argv[0] = mprGetAbsPath(argv[++argind]);
            mprSetAppPath(mpr->argv[0]);
            mprSetModuleSearchPath(NULL);

        } else if (smatch(argp, "--home")) {
            if (argind >= argc) {
                usageError();
            }
            app->home = sclone(argv[++argind]);
            if (chdir(app->home) < 0) {
                mprLog("error appweb", 0, "Cannot change directory to %s", app->home);
                exit(4);
            }

        } else if (smatch(argp, "--log") || smatch(argp, "-l")) {
            if (argind >= argc) {
                usageError();
            }
            logSpec = argv[++argind];

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

        } else if (smatch(argp, "--threads")) {
            if (argind >= argc) {
                usageError();
            }
            app->workers = atoi(argv[++argind]);

        } else if (smatch(argp, "--show") || smatch(argp, "-s")) {
            app->show = 1;

        } else if (smatch(argp, "--trace") || smatch(argp, "-t")) {
            if (argind >= argc) {
                usageError();
            }
            traceSpec = argv[++argind];

        } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) {
            if (!logSpec) {
                logSpec = sfmt("stderr:2");
            }
            if (!traceSpec) {
                traceSpec = sfmt("stderr:2");
            }

        } else if (smatch(argp, "--version") || smatch(argp, "-V")) {
            mprPrintf("%s\n", ME_VERSION);
            exit(0);

        } else if (*argp == '-' && isdigit((uchar) argp[1])) {
            if (!logSpec) {
                logSpec = sfmt("stderr:%d", (int) stoi(&argp[1]));
            }
            if (!traceSpec) {
                traceSpec = sfmt("stderr:%d", (int) stoi(&argp[1]));
            }

        } else if (smatch(argp, "-?") || scontains(argp, "-help")) {
            usageError();
            exit(5);

        } else if (*argp == '-') {
            mprLog("error appweb", 0, "Unknown switch \"%s\"", argp);
            usageError();
            exit(5);
        }
    }
    app->home = mprGetAbsPath(app->home);
    if (logSpec) {
        mprStartLogging(logSpec, MPR_LOG_DETAILED | MPR_LOG_CONFIG | MPR_LOG_CMDLINE);
    }
    if (traceSpec) {
        httpStartTracing(traceSpec);
    }
    if (mprStart() < 0) {
        mprLog("error appweb", 0, "Cannot start MPR");
        mprDestroy();
        return MPR_ERR_CANT_INITIALIZE;
    }
    if (checkEnvironment(argv[0]) < 0) {
        exit(6);
    }
    if (argc == argind && !app->configFile) {
        if (findAppwebConf() < 0) {
            exit(7);
        }
    }
    if (jail && changeRoot(jail) < 0) {
        exit(8);
    }
    if (createEndpoints(argc - argind, &argv[argind]) < 0) {
        return MPR_ERR_CANT_INITIALIZE;
    }
    if (maStartAppweb(app->appweb) < 0) {
        mprLog("error appweb", 0, "Cannot start HTTP service, exiting.");
        exit(9);
    }
    if (app->show) {
        httpLogRoutes(0, 0);
    }
    mprServiceEvents(-1, 0);

    mprLog("info appweb", 1, "Stopping Appweb ...");
    mprDestroy();
    return mprGetExitStatus();
}
Пример #9
0
/*
    Add cache configuration to the route. This can be called multiple times.
    Uris, extensions and methods may optionally provide a space or comma separated list of items.
    If URI is NULL or "*", cache all URIs for this route. Otherwise, cache only the given URIs. 
    The URIs may contain an ordered set of request parameters. For example: "/user/show?name=john&posts=true"
    Note: the URI should not include the route prefix (scriptName)
    The extensions should not contain ".". The methods may contain "*" for all methods.
 */
void httpAddCache(HttpRoute *route, cchar *methods, cchar *uris, cchar *extensions, cchar *types, MprTime clientLifespan, 
        MprTime serverLifespan, int flags)
{
    HttpCache   *cache;
    char        *item, *tok;

    cache = 0;
    if (!route->caching) {
        httpAddRouteHandler(route, "cacheHandler", "");
        httpAddRouteFilter(route, "cacheFilter", "", HTTP_STAGE_TX);
        route->caching = mprCreateList(0, 0);

    } else if (flags & HTTP_CACHE_RESET) {
        route->caching = mprCreateList(0, 0);

    } else if (route->parent && route->caching == route->parent->caching) {
        route->caching = mprCloneList(route->parent->caching);
    }
    if ((cache = mprAllocObj(HttpCache, manageHttpCache)) == 0) {
        return;
    }
    if (extensions) {
        cache->extensions = mprCreateHash(0, 0);
        for (item = stok(sclone(extensions), " \t,", &tok); item; item = stok(0, " \t,", &tok)) {
            if (smatch(item, "*")) {
                extensions = 0;
            } else {
                mprAddKey(cache->extensions, item, cache);
            }
        }
    } else if (types) {
        cache->types = mprCreateHash(0, 0);
        for (item = stok(sclone(types), " \t,", &tok); item; item = stok(0, " \t,", &tok)) {
            if (smatch(item, "*")) {
                extensions = 0;
            } else {
                mprAddKey(cache->types, item, cache);
            }
        }
    }
    if (methods) {
        cache->methods = mprCreateHash(0, MPR_HASH_CASELESS);
        for (item = stok(sclone(methods), " \t,", &tok); item; item = stok(0, " \t,", &tok)) {
            if (smatch(item, "*")) {
                methods = 0;
            } else {
                mprAddKey(cache->methods, item, cache);
            }
        }
    }
    if (uris) {
        cache->uris = mprCreateHash(0, 0);
        for (item = stok(sclone(uris), " \t,", &tok); item; item = stok(0, " \t,", &tok)) {
            if (flags & HTTP_CACHE_ONLY && route->prefix && !scontains(item, sfmt("prefix=%s", route->prefix))) {
                /*
                    Auto-add ?prefix=ROUTE_NAME if there is no query
                 */
                if (!schr(item, '?')) {
                    item = sfmt("%s?prefix=%s", item, route->prefix); 
                }
            }
            mprAddKey(cache->uris, item, cache);
        }
    }
    if (clientLifespan <= 0) {
        clientLifespan = route->lifespan;
    }
    cache->clientLifespan = clientLifespan;
    if (serverLifespan <= 0) {
        serverLifespan = route->lifespan;
    }
    cache->serverLifespan = serverLifespan;
    cache->flags = flags;
    mprAddItem(route->caching, cache);

#if UNUSED && KEEP
    mprLog(3, "Caching route %s for methods %s, URIs %s, extensions %s, types %s, client lifespan %d, server lifespan %d", 
        route->name,
        (methods) ? methods: "*",
        (uris) ? uris: "*",
        (extensions) ? extensions: "*",
        (types) ? types: "*",
        cache->clientLifespan / MPR_TICKS_PER_SEC);
        cache->serverLifespan / MPR_TICKS_PER_SEC);
#endif
}
Пример #10
0
static bool process(cchar *operation, bool quiet)
{
    cchar   *name, *off, *path;
    int     rc, launch, update, service, upstart;

    /*
        No systemd support yet
     */
    rc = 1;
    name = app->serviceName;
    launch = upstart = update = service = 0;

    if (exists("/bin/launchctl") && exists("/Library/LaunchDaemons/com.%s.%s.plist", slower(BLD_COMPANY), name)) {
        launch++;

    } else if (exists("/sbin/start") && exists("/etc/init/rc.conf") &&
            (exists("/etc/init/%s.conf", name) || exists("/etc/init/%s.off", name))) {
        upstart++;

    } else if (exists("/usr/sbin/update-rc.d") && exists("/etc/init.d/%s", name)) {
        update++;

    } else if (exists("/sbin/service") && exists("/etc/init.d/%s", name)) {
        service++;

    } else {
        mprError("Can't locate system tool to manage service");
        return 0;
    }

    /*
        Operations
     */
    if (smatch(operation, "install")) {
        if (launch) {
            ;

        } else if (service) {
            if (!run("/sbin/chkconfig --del %s", name)) {
                rc = 0;
            } else if (!run("/sbin/chkconfig --add %s", name)) {
                rc = 0;
            } else if (!run("/sbin/chkconfig --level 5 %s", name)) {
                rc = 0;
            }

        } else if (update) {
            ;

        } else if (upstart) {
            ;
        }

    } else if (smatch(operation, "uninstall")) {
        process("disable", 1);

        if (launch) {
            ;

        } else if (service) {
            rc = run("/sbin/chkconfig --del %s", name);

        } else if (update) {
            ;

        } else if (upstart) {
            ;
        }

    } else if (smatch(operation, "enable")) {
        /* 
            Enable service (will start on reboot)
         */
        if (launch) {
            path = sfmt("/Library/LaunchDaemons/com.%s.%s.plist", slower(BLD_COMPANY), name);
            /* 
                Unfortunately, there is no launchctl command to do an enable without starting. So must do a stop below.
             */
            if (!run("/bin/launchctl load -w %s", path)) {
                rc = 0;
            } else {
                rc = process("stop", 1);
            }

        } else if (update) {
            rc = run("/usr/sbin/update-rc.d %s defaults 90 10", name);
            /*
                Not supported on older versions
                rc = run("/usr/sbin/update-rc.d %s enable", name);
             */

        } else if (service) {
            rc = run("/sbin/chkconfig %s on", name);

        } else if (upstart) {
            off = sfmt("/etc/init/%s.off", name);
            if (exists(off) && !run("mv %s /etc/init/%s.conf", off, name)) {
                rc = 0;
            }
        }

    } else if (smatch(operation, "disable")) {
        process("stop", 1);
        if (launch) {
            rc = run("/bin/launchctl unload -w /Library/LaunchDaemons/com.%s.%s.plist", slower(BLD_COMPANY), name);

        } else if (update) {
            /*  
                Not supported on older versions
                rc = run("/usr/sbin/update-rc.d %s disable", name);
             */
            rc = run("/usr/sbin/update-rc.d -f %s remove", name);

        } else if (service) {
            rc = run("/sbin/chkconfig %s off", name);

        } else if (upstart) {
            if (exists("/etc/init/%s.conf", name)) {
                rc = run("mv /etc/init/%s.conf /etc/init/%s.off", name, name);
            }
        }

    } else if (smatch(operation, "start")) {
        if (launch) {
            rc = run("/bin/launchctl load /Library/LaunchDaemons/com.%s.%s.plist", slower(BLD_COMPANY), name);

        } else if (service) {
            rc = run("/sbin/service %s start", name);

        } else if (update) {
            rc = run("/usr/sbin/invoke-rc.d --quiet %s start", name);

        } else if (upstart) {
            rc = run("/sbin/start %s", name);
            if (!rc) {
                if (scontains(app->error, "start: Job is already running", -1)) {
                    rc = 0;
                }
            }
        }

    } else if (smatch(operation, "stop")) {
        if (launch) {
            rc = run("/bin/launchctl unload /Library/LaunchDaemons/com.%s.%s.plist", slower(BLD_COMPANY), name);

        } else if (service) {
            if (!run("/sbin/service %s stop", name)) {
                rc = killPid();
            }

        } else if (update) {
            if (!run("/usr/sbin/invoke-rc.d --quiet %s stop", name)) {
                rc = killPid();
            }

        } else if (upstart) {
            if (exists("/etc/init/%s.conf", name)) {
                rc = run("/sbin/stop %s", name);
            }
        }

    } else if (smatch(operation, "reload")) {
        rc = process("restart", 0);

    } else if (smatch(operation, "restart")) {
        process("stop", 1);
        rc = process("start", 0);

    } else if (smatch(operation, "run")) {
        runService();
    }

    if (!quiet) {
        if (!rc && app->error && *app->error) {
            mprError("Can't run command: %s\nCommand output: %s\n", app->command, app->error);
        }
        /* Logging at level one will be visible if appman -v is used */
        if (app->error && *app->error) {
            mprLog(1, "Error: %s", app->error); 
        }
        if (app->output && *app->output) {
            mprLog(1, "Output: %s", app->output); 
        }
    }
    return rc;
}
Пример #11
0
/*
    Create and initialize a URI. This accepts full URIs with schemes (http:) and partial URLs
    Support IPv4 and [IPv6]. Supported forms:

        SCHEME://[::]:PORT/URI
        SCHEME://HOST:PORT/URI
        [::]:PORT/URI
        :PORT/URI
        HOST:PORT/URI
        PORT/URI
        /URI
        URI

        NOTE: HOST/URI is not supported and requires a scheme prefix. This is because it is ambiguous with a 
        relative uri path.

    Missing fields are null or zero.
 */
PUBLIC HttpUri *httpCreateUri(cchar *uri, int flags)
{
    HttpUri     *up;
    char        *tok, *next;

    if ((up = mprAllocObj(HttpUri, manageUri)) == 0) {
        return 0;
    }
    tok = sclone(uri);

    /*
        [scheme://][hostname[:port]][/path[.ext]][#ref][?query]
        First trim query and then reference from the end
     */
    if ((next = schr(tok, '?')) != 0) {
        *next++ = '\0';
        up->query = sclone(next);
    }
    if ((next = schr(tok, '#')) != 0) {
        *next++ = '\0';
        up->reference = sclone(next);
    }

    /*
        [scheme://][hostname[:port]][/path]
     */
    if ((next = scontains(tok, "://")) != 0) {
        up->scheme = snclone(tok, (next - tok));
        if (smatch(up->scheme, "http")) {
            if (flags & HTTP_COMPLETE_URI) {
                up->port = 80;
            }
        } else if (smatch(up->scheme, "ws")) {
            if (flags & HTTP_COMPLETE_URI) {
                up->port = 80;
            }
            up->webSockets = 1;
        } else if (smatch(up->scheme, "https")) {
            if (flags & HTTP_COMPLETE_URI) {
                up->port = 443;
            }
            up->secure = 1;
        } else if (smatch(up->scheme, "wss")) {
            if (flags & HTTP_COMPLETE_URI) {
                up->port = 443;
            }
            up->secure = 1;
            up->webSockets = 1;
        }
        tok = &next[3];
    }

    /*
        [hostname[:port]][/path]
     */
    if (*tok == '[' && ((next = strchr(tok, ']')) != 0)) {
        /* IPv6  [::]:port/uri */
        up->host = snclone(&tok[1], (next - tok) - 1);
        tok = ++next;

    } else if (*tok && *tok != '/' && *tok != ':' && (up->scheme || strchr(tok, ':'))) {
        /*
            Supported forms:
                scheme://hostname
                hostname:port
         */
        if ((next = spbrk(tok, ":/")) == 0) {
            next = &tok[slen(tok)];
        }
        up->host = snclone(tok, next - tok);
        tok = next;
    }
    assert(tok);

    /* [:port][/path] */
    if (*tok == ':') {
        up->port = atoi(++tok);
        if ((tok = schr(tok, '/')) == 0) {
            tok = "";
        }
    }
    assert(tok);

    /* [/path] */
    if (*tok) {
        up->path = sclone(tok);
        /* path[.ext[/extra]] */
        if ((tok = srchr(up->path, '.')) != 0) {
            if (tok[1]) {
                if ((next = srchr(up->path, '/')) != 0) {
                    if (next < tok) {
                        up->ext = sclone(++tok);
                    }
                } else {
                    up->ext = sclone(++tok);
                }
            }
        }
    }
    if (flags & (HTTP_COMPLETE_URI | HTTP_COMPLETE_URI_PATH)) {
        if (up->path == 0 || *up->path == '\0') {
            up->path = sclone("/");
        }
    }
    up->secure = smatch(up->scheme, "https") || smatch(up->scheme, "wss");
    up->webSockets = (smatch(up->scheme, "ws") || smatch(up->scheme, "wss"));

    if (flags & HTTP_COMPLETE_URI) {
        if (!up->scheme) {
            up->scheme = sclone("http");
        }
        if (!up->host) {
            up->host = sclone("localhost");
        }
        if (!up->port) {
            up->port = up->secure ? 443 : 80;
        }
    }
    up->valid = httpValidUriChars(uri);
    return up;
}
Пример #12
0
/*
    Format a string URI from parts
 */
PUBLIC char *httpFormatUri(cchar *scheme, cchar *host, int port, cchar *path, cchar *reference, cchar *query, int flags)
{
    char    *uri;
    cchar   *portStr, *hostDelim, *portDelim, *pathDelim, *queryDelim, *referenceDelim, *cp;

    portDelim = "";
    portStr = "";
    hostDelim = "";

    if (flags & HTTP_COMPLETE_URI) {
        if (scheme == 0 || *scheme == '\0') {
            scheme = "http";
        }
        if (host == 0 || *host == '\0') {
            if (port || path || reference || query) {
                host = "localhost";
            }
        }
    } 
    if (scheme) {
        hostDelim = "://";
    }
    if (!host) {
        host = "";
    }
    if (mprIsIPv6(host)) {
        if (*host != '[') {
            host = sfmt("[%s]", host);
        } else if ((cp = scontains(host, "]:")) != 0) {
            port = 0;
        }
    } else if (schr(host, ':')) {
        port = 0;
    }
    if (port != 0 && port != getDefaultPort(scheme)) {
        portStr = itos(port);
        portDelim = ":";
    }
    if (scheme == 0) {
        scheme = "";
    }
    if (path && *path) {
        if (*host) {
            pathDelim = (*path == '/') ? "" :  "/";
        } else {
            pathDelim = "";
        }
    } else {
        pathDelim = path = "";
    }
    if (reference && *reference) {
        referenceDelim = "#";
    } else {
        referenceDelim = reference = "";
    }
    if (query && *query) {
        queryDelim = "?";
    } else {
        queryDelim = query = "";
    }
    if (*portDelim) {
        uri = sjoin(scheme, hostDelim, host, portDelim, portStr, pathDelim, path, referenceDelim, reference, 
            queryDelim, query, NULL);
    } else {
        uri = sjoin(scheme, hostDelim, host, pathDelim, path, referenceDelim, reference, queryDelim, query, NULL);
    }
    return uri;
}
Пример #13
0
MAIN(http, int argc, char **argv, char **envp)
{
    Mpr     *mpr;
    cchar   *argp;
    char    *logSpec, *traceSpec;
    int     argind;

    logSpec = 0;
    traceSpec = 0;

    if ((mpr = mprCreate(argc, argv, MPR_USER_EVENTS_THREAD)) == NULL) {
        exit(1);
    }
    if ((app = mprAllocObj(App, manageApp)) == NULL) {
        exit(2);
    }
    mprAddRoot(app);
    mprAddStandardSignals();

    if (httpCreate(HTTP_CLIENT_SIDE | HTTP_SERVER_SIDE) < 0) {
        exit(2);
    }
    app->mpr = mpr;
    app->home = mprGetCurrentPath();
    argc = mpr->argc;
    argv = (char**) mpr->argv;

    for (argind = 1; argind < argc; argind++) {
        argp = argv[argind];
        if (*argp != '-') {
            break;
        }
        if (smatch(argp, "--config") || smatch(argp, "--conf")) {
            if (argind >= argc) {
                usageError();
            }
            app->configFile = sclone(argv[++argind]);

        } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) {
            mprSetDebugMode(1);

        } else if (smatch(argp, "--log") || smatch(argp, "-l")) {
            if (argind >= argc) {
                usageError();
            }
            logSpec = argv[++argind];

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

        } else if (smatch(argp, "--show") || smatch(argp, "-s")) {
            app->show = 1;

        } else if (smatch(argp, "--trace") || smatch(argp, "-t")) {
            if (argind >= argc) {
                usageError();
            }
            traceSpec = argv[++argind];

        } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) {
            if (!logSpec) {
                logSpec = sfmt("stderr:2");
            }
            if (!traceSpec) {
                traceSpec = sfmt("stderr:2");
            }

        } else if (smatch(argp, "--version") || smatch(argp, "-V")) {
            mprPrintf("%s\n", ME_VERSION);
            exit(0);

        } else if (*argp == '-' && isdigit((uchar) argp[1])) {
            if (!logSpec) {
                logSpec = sfmt("stderr:%d", (int) stoi(&argp[1]));
            }
            if (!traceSpec) {
                traceSpec = sfmt("stderr:%d", (int) stoi(&argp[1]));
            }

        } else if (smatch(argp, "-?") || scontains(argp, "-help")) {
            usageError();
            exit(3);

        } else if (*argp == '-') {
            mprLog("error http", 0, "Unknown switch \"%s\"", argp);
            usageError();
            exit(4);
        }
    }
    if (logSpec) {
        mprStartLogging(logSpec, MPR_LOG_CMDLINE);
    }
    if (traceSpec) {
        httpStartTracing(traceSpec);
    }
    if (mprStart() < 0) {
        mprLog("error http", 0, "Cannot start MPR");
        mprDestroy();
        return MPR_ERR_CANT_INITIALIZE;
    }
    if (argc == argind && !app->configFile) {
        if (findConfig() < 0) {
            exit(5);
        }
    }
    if (createEndpoints(argc - argind, &argv[argind]) < 0) {
        return MPR_ERR_CANT_INITIALIZE;
    }
    if (httpStartEndpoints() < 0) {
        mprLog("error http", 0, "Cannot start HTTP service, exiting.");
        exit(6);
    }
    if (app->show) {
        httpLogRoutes(0, 0);
    }
    mprServiceEvents(-1, 0);

    mprLog("info http", 1, "Stopping http-server ...");
    mprDestroy();
    return mprGetExitStatus();
}