コード例 #1
0
ファイル: pipeline.c プロジェクト: jsjohnst/appweb
static bool mapToFile(MaConn *conn, bool *rescan)
{
    MaRequest   *req;
    MaResponse  *resp;

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

    if (resp->filename == 0) {
        resp->filename = makeFilename(conn, req->alias, req->url, 1);
    }
    req->dir = maLookupBestDir(req->host, resp->filename);

    if (req->dir == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_NOT_FOUND, "Missing directory block for %s", resp->filename);
        return 0;
    }

    mprAssert(req->dir);

    req->auth = req->dir->auth;

    if (!resp->fileInfo.valid && mprGetFileInfo(conn, resp->filename, &resp->fileInfo) < 0) {
#if UNUSED
        if (req->method & (MA_REQ_GET | MA_REQ_POST)) {
            maFailRequest(conn, MPR_HTTP_CODE_NOT_FOUND, "Can't open document: %s", resp->filename);
            return 0;
        }
#endif
    }
    if (resp->fileInfo.isDir) {
        processDirectory(conn, rescan);
    }
    return 1;
}
コード例 #2
0
ファイル: cgiHandler.c プロジェクト: varphone/appweb-3
/*
    Parse the CGI output first line
 */
static bool parseFirstCgiResponse(MaConn *conn, MprCmd *cmd)
{
    MprBuf          *buf;
    char            *protocol, *code, *message;
    
    buf = mprGetCmdBuf(cmd, MPR_CMD_STDOUT);
    
    protocol = getCgiToken(buf, " ");
    if (protocol == 0 || protocol[0] == '\0') {
        maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, "Bad CGI HTTP protocol response");
        return 0;
    }
    if (strncmp(protocol, "HTTP/1.", 7) != 0) {
        maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, "Unsupported CGI protocol");
        return 0;
    }
    code = getCgiToken(buf, " ");
    if (code == 0 || *code == '\0') {
        maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, "Bad CGI header response");
        return 0;
    }
    message = getCgiToken(buf, "\n");
    mprLog(conn, 4, "CGI status line: %s %s %s", protocol, code, message);
    return 1;
}
コード例 #3
0
ファイル: phpHandler.c プロジェクト: gamman/appweb-3
static void openPhp(MaQueue *q)
{
    MaRequest       *req;
    MaResponse      *resp;
    MaConn          *conn;

    conn = q->conn;
    if (!q->stage->stageData) {
        if (initializePhp(conn->http) < 0) {
            maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "PHP initialization failed");
        }
        q->stage->stageData = (void*) 1;
    }
    resp = conn->response;
    req = conn->request;

    switch (req->method) {
    case MA_REQ_GET:
    case MA_REQ_HEAD:
    case MA_REQ_POST:
    case MA_REQ_PUT:
        q->queueData = mprAllocObjZeroed(resp, MaPhp);
        maDontCacheResponse(conn);
        maSetHeader(conn, 0, "Last-Modified", req->host->currentDate);
        break;
                
    case MA_REQ_DELETE:
    default:
        maFailRequest(q->conn, MPR_HTTP_CODE_BAD_METHOD, "Method not supported by file handler: %s", req->methodName);
        break;
    }
}
コード例 #4
0
ファイル: ejsAppweb.c プロジェクト: jsjohnst/appweb
/*
 *  When we come here, we've already matched either a location block or an extension
 */
static bool matchEjs(MaConn *conn, MaStage *handler, cchar *url)
{
    MaRequest   *req;
    MaLocation  *loc;
    EjsWeb      *web;
    cchar       *ext;
    char        urlbuf[MPR_MAX_FNAME];

    loc = conn->request->location;

#if UNUSED
    if (!(loc->flags & (MA_LOC_APP | MA_LOC_APP_DIR))) {
        return 1;
    }
#endif

    /*
     *  Send non-ejs content under web to another handler, typically the file handler.
     */
    req = conn->request;
    ext = conn->response->extension;

    if (ext && strcmp(ext, "mod") == 0) {
        maFormatBody(conn, "Bad Request", "Can't serve *.mod files");
        maFailRequest(conn, MPR_HTTP_CODE_BAD_REQUEST, "Can't server *.mod files");
        return 1;
    }

    if (parseUrl(conn) < 0) {
        return 1;
    }
    web = (EjsWeb*) conn->response->handlerData;

    /*
     *  TODO - need a more general way of handling these routes. Push back into the Ejscript framework
     */
    url = web->url;
    if (*url == '\0' || strcmp(url, "/") == 0) {
        mprSprintf(urlbuf, sizeof(urlbuf), "%s/web/index.ejs", web->appUrl);
        maSetRequestUri(conn, urlbuf);
        return 0;

    } else if (strcmp(url, "/favicon.ico") == 0) {
        mprSprintf(urlbuf, sizeof(urlbuf), "%s/web/favicon.ico", web->appUrl);
        maSetRequestUri(conn, urlbuf);
        return 0;

    } else if (strncmp(url, "/web/", 5) == 0 || *url == '\0') {
        if (!(ext && strcmp(ext, "ejs") == 0)) {
            return 0;
        }
    } else {
        if (loc->flags & (MA_LOC_APP | MA_LOC_APP_DIR) && 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 1;
}
コード例 #5
0
ファイル: ejsAppweb.c プロジェクト: jsjohnst/appweb
/*
 *  Run the Ejscript request. The routine runs when all input data has been received.
 */
static void runEjs(MaQueue *q)
{
    MaConn      *conn;
    MaRequest   *req;
    EjsWeb      *web;
    char        msg[MPR_MAX_STRING];

    conn = q->conn;
    req = conn->request;
    web = q->queueData = conn->response->handlerData;

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

    maPutForService(q, maCreateHeaderPacket(conn), 0);

    if (ejsRunWebRequest(web) < 0) {
        //  TODO - refactor. Want request failed to have an option which says send this output to the client also.
        if (web->flags & EJS_WEB_FLAG_BROWSER_ERRORS) {
            //  TODO - this API should allocate a buffer and not use a static buffer
            mprEscapeHtml(msg, sizeof(msg), web->error);
            maFormatBody(conn, "Request Failed", 
                "<h1>Ejscript error for \"%s\"</h1>\r\n<h2>%s</h2>\r\n"
                "<p>To prevent errors being displayed in the browser, "
                "use <b>\"EjsErrors log\"</b> in the config file.</p>\r\n",
            web->url, web->error);
        }
        maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, web->error);
    }
    maPutForService(q, maCreateEndPacket(conn), 1);
}
コード例 #6
0
ファイル: egiHandler.c プロジェクト: jsjohnst/appweb
static void upload(MaQueue *q)
{
    MaConn      *conn;
    char        *sw;
    char        *newLocation;
    int         responseStatus;

    conn = q->conn;
    newLocation = 0;
    responseStatus = 0;

    sw = (char*) strstr(maGetFormVar(conn, "QUERY_STRING", ""), "SWITCHES=");
    if (sw) {
        sw = mprStrdup(q, sw + 9);
        mprUrlDecode(sw, (int) strlen(sw) + 1, sw);
        if (*sw == '-') {
            if (sw[1] == 'l') {
                newLocation = sw + 3;
            } else if (sw[1] == 's') {
                responseStatus = atoi(sw + 3);
            }
        }
    }

    maSetResponseCode(conn, 200);
    maSetResponseMimeType(conn, "text/html");
    maDontCacheResponse(conn);

    /*
     *  Test writing headers. The Server header overwrote the "Server" header
     *
     *  maSetHeader(conn, "MyCustomHeader: true");
     *  maSetHeader(conn, "Server: private");
     */

    if (maGetCookies(conn) == 0) {
        maSetCookie(conn, "appwebTest", "Testing can be fun", 43200, "/", 0);
    }

    if (newLocation) {
        maRedirect(conn, 302, newLocation);

    } else if (responseStatus) {
        maFailRequest(conn, responseStatus, "Custom Status");

    } else {
        maWrite(q, "<HTML><TITLE>egiProgram: EGI Output</TITLE><BODY>\r\n");

        printRequestHeaders(q);
        printQueryData(q);
        printBodyData(q);

        maWrite(q, "</BODY></HTML>\r\n");
    }
    if (sw) {
        mprFree(sw);
    }
}
コード例 #7
0
ファイル: ejsAppweb.c プロジェクト: jsjohnst/appweb
static void error(void *handle, int code, cchar *fmt, ...)
{
    va_list     args;
    char        *msg;

    va_start(args, fmt);
    mprAllocVsprintf(handle, &msg, -1, fmt, args);

    maFailRequest(handle, code, "%s", msg);
}
コード例 #8
0
ファイル: authFilter.c プロジェクト: embedthis/appweb-3
/*
 *  Format an authentication response. This is typically a 401 response code.
 */
static void formatAuthResponse(MaConn *conn, MaAuth *auth, int code, char *msg, char *logMsg)
{
    MaRequest       *req;
#if BLD_FEATURE_AUTH_DIGEST
    char            *qopClass, *nonceStr, *etag;
#endif

    req = conn->request;
    if (logMsg == 0) {
        logMsg = msg;
    }

    mprLog(conn, 3, "formatAuthResponse: code %d, %s\n", code, logMsg);

    if (auth->type == MA_AUTH_BASIC) {
        maSetHeader(conn, 0, "WWW-Authenticate", "Basic realm=\"%s\"", auth->requiredRealm);

#if BLD_FEATURE_AUTH_DIGEST
    } else if (auth->type == MA_AUTH_DIGEST) {

        qopClass = auth->qop;

        /*
         *  Use the etag as our opaque string
         */
        etag = conn->response->etag;
        if (etag == 0) {
            etag = "";
        }
        if (etag[0] == '"') {
            etag = mprStrdup(req, etag);
            etag = mprStrTrim(etag, "\"");
        }
        mprCalcDigestNonce(req, &nonceStr, conn->host->secret, etag, auth->requiredRealm);

        if (strcmp(qopClass, "auth") == 0) {
            maSetHeader(conn, 0, "WWW-Authenticate", "Digest realm=\"%s\", domain=\"%s\", "
                "qop=\"auth\", nonce=\"%s\", opaque=\"%s\", algorithm=\"MD5\", stale=\"FALSE\"", 
                auth->requiredRealm, conn->host->name, nonceStr, etag);

        } else if (strcmp(qopClass, "auth-int") == 0) {
            maSetHeader(conn, 0, "WWW-Authenticate", "Digest realm=\"%s\", domain=\"%s\", "
                "qop=\"auth\", nonce=\"%s\", opaque=\"%s\", algorithm=\"MD5\", stale=\"FALSE\"", 
                auth->requiredRealm, conn->host->name, nonceStr, etag);

        } else {
            maSetHeader(conn, 0, "WWW-Authenticate", "Digest realm=\"%s\", nonce=\"%s\"", auth->requiredRealm, nonceStr);
        }
        mprFree(nonceStr);
#endif
    }

    maFailRequest(conn, code, "Authentication Error: %s", msg);
}
コード例 #9
0
ファイル: sendConnector.c プロジェクト: doghell/appweb-3
/*
 *  Invoked to initialize the send connector for a request
 */
static void sendOpen(MaQueue *q)
{
    MaConn          *conn;
    MaResponse      *resp;

    conn = q->conn;
    resp = conn->response;

    if (!conn->requestFailed && !(resp->flags & MA_RESP_NO_BODY)) {
        resp->file = mprOpen(q, resp->filename, O_RDONLY | O_BINARY, 0);
        if (resp->file == 0) {
            maFailRequest(conn, MPR_HTTP_CODE_NOT_FOUND, "Can't open document: %s", resp->filename);
        }
    }
}
コード例 #10
0
ファイル: cgiHandler.c プロジェクト: doghell/appweb-3
/*
    Accept incoming body data from the client (via the pipeline) destined for the CGI gateway. This is typically
    POST or PUT data.
 */
static void incomingCgiData(MaQueue *q, MaPacket *packet)
{
    MaConn      *conn;
    MaResponse  *resp;
    MaRequest   *req;
    MprCmd      *cmd;

    mprAssert(q);
    mprAssert(packet);
    
    conn = q->conn;
    resp = conn->response;
    req = conn->request;
    cmd = (MprCmd*) q->pair->queueData;
    if (cmd) {
        cmd->lastActivity = mprGetTime(cmd);
    }
    if (maGetPacketLength(packet) == 0) {
        /*
            End of input
         */
        if (req->remainingContent > 0) {
            /*
                Short incoming body data. Just kill the CGI process.
             */
            mprFree(cmd);
            q->queueData = 0;
            maFailRequest(conn, MPR_HTTP_CODE_BAD_REQUEST, "Client supplied insufficient body data");
        }
        if (req->form) {
            maAddVarsFromQueue(req->formVars, q);
        }

    } else {
        /*
            No service routine, we just need it to be queued for writeToCGI
         */
        if (req->form) {
            maJoinForService(q, packet, 0);
        } else {
            maPutForService(q, packet, 0);
        }
    }
    if (cmd) {
        writeToCGI(q);
    }
}
コード例 #11
0
ファイル: cgiHandler.c プロジェクト: varphone/appweb-3
static void writeToCGI(MaQueue *q)
{
    MaConn      *conn;
    MaPacket    *packet;
    MprCmd      *cmd;
    MprBuf      *buf;
    int         len, rc, err;

    cmd = (MprCmd*) q->pair->queueData;
    mprAssert(cmd);
    conn = q->conn;

    for (packet = maGet(q); packet && !conn->requestFailed; packet = maGet(q)) {
        buf = packet->content;
        len = mprGetBufLength(buf);
        mprAssert(len > 0);
        rc = mprWriteCmdPipe(cmd, MPR_CMD_STDIN, mprGetBufStart(buf), len);
        mprLog(q, 5, "CGI: write %d bytes to gateway. Rc rc %d, errno %d", len, rc, mprGetOsError());
        if (rc < 0) {
            err = mprGetError();
            if (err == EINTR) {
                continue;
            } else if (err == EAGAIN || err == EWOULDBLOCK) {
                break;
            }
            mprLog(q, 2, "CGI: write to gateway failed for %d bytes, rc %d, errno %d", len, rc, mprGetOsError());
            mprCloseCmdFd(cmd, MPR_CMD_STDIN);
            maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, "Can't write body data to CGI gateway");
            break;

        } else {
            mprLog(q, 5, "CGI: write to gateway %d bytes asked to write %d", rc, len);
            mprAdjustBufStart(buf, rc);
            if (mprGetBufLength(buf) > 0) {
                maPutBack(q, packet);
            } else {
                maFreePacket(q, packet);
            }
        }
    }
}
コード例 #12
0
ファイル: simpleEgi.c プロジェクト: doghell/appweb-3
static void myEgi(MaQueue *q)
{
	MaConn	*conn;

	conn = q->conn;

	maSetResponseCode(conn, 200);
	maWrite(q, "<HTML><TITLE>simpleEgi</TITLE><BODY>\r\n");
	maWrite(q, "<p>Name: %s</p>\n", maGetFormVar(conn, "name", "-"));
	maWrite(q, "<p>Address: %s</p>\n", maGetFormVar(conn, "address", "-"));
	maWrite(q, "</BODY></HTML>\r\n");

#if POSSIBLE
	/*
	 *	Useful things to do in egi forms
	 */
	maSetResponseCode(conn, 200);
	maSetResponseMimeType(conn, "text/plain");
	maDontCacheResponse(conn);
	maRedirect(conn, 302, "/myURl");
	maFailRequest(conn, 409, "My message : %d", 5);
#endif
}
コード例 #13
0
ファイル: egiHandler.c プロジェクト: jsjohnst/appweb
/*
 *  This runs when all input data has been received. The egi form must write all the data.
 *  It currently does not support forms that return before writing all the data.
 */
static void runEgi(MaQueue *q)
{
    MaConn          *conn;
    MaRequest       *req;
    MaEgiForm       *form;
    MaEgi           *egi;

    conn = q->conn;
    req = conn->request;
    egi = (MaEgi*) q->stage->stageData;
    
    maSetHeader(conn, 0, "Last-Modified", req->host->currentDate);
    maDontCacheResponse(conn);
    maPutForService(q, maCreateHeaderPacket(conn), 0);

    form = (MaEgiForm*) mprLookupHash(egi->forms, req->url);
    if (form == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_NOT_FOUND, "Egi Form: \"%s\" is not defined", req->url);
        
    } else {
        (*form)(q);
    }
    maPutForService(q, maCreateEndPacket(conn), 1);
}
コード例 #14
0
ファイル: cgiHandler.c プロジェクト: varphone/appweb-3
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);
}
コード例 #15
0
ファイル: ejsApache.c プロジェクト: embedthis/appweb-3
/*
 *  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;
}
コード例 #16
0
ファイル: request.c プロジェクト: gamman/appweb-3
/*
 *  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;
}
コード例 #17
0
ファイル: request.c プロジェクト: gamman/appweb-3
/*
 *  Parse the first line of a http request. Return true if the first line parsed. This is only called once all the headers
 *  have been read and buffered.
 */
static bool parseFirstLine(MaConn *conn, MaPacket *packet)
{
    MaRequest   *req;
    MaResponse  *resp;
    MaHost      *host;
    MprBuf      *content;
    cchar       *endp;
    char        *methodName, *uri, *httpProtocol;
    int         method, len;

    req = conn->request = maCreateRequest(conn);
    resp = conn->response = maCreateResponse(conn);
    host = conn->host;

#if BLD_DEBUG    
    req->startTime = mprGetTime(conn);
    req->startTicks = mprGetTicks();
#endif

    methodName = getToken(conn, " ");
    if (*methodName == '\0') {
        maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad request method name");
        return 0;
    }

    method = 0;
    switch (methodName[0]) {
    case 'D':
        if (strcmp(methodName, "DELETE") == 0) {
            method = MA_REQ_DELETE;
        }
        break;

    case 'G':
        if (strcmp(methodName, "GET") == 0) {
            method = MA_REQ_GET;
        }
        break;

    case 'P':
        if (strcmp(methodName, "POST") == 0) {
            method = MA_REQ_POST;

        } else if (strcmp(methodName, "PUT") == 0) {
            method = MA_REQ_PUT;
        }
        break;

    case 'H':
        if (strcmp(methodName, "HEAD") == 0) {
            method = MA_REQ_HEAD;
            resp->flags |= MA_RESP_NO_BODY;
        }
        break;

    case 'O':
        if (strcmp(methodName, "OPTIONS") == 0) {
            method = MA_REQ_OPTIONS;
            resp->flags |= MA_RESP_NO_BODY;
        }
        break;

    case 'T':
        if (strcmp(methodName, "TRACE") == 0) {
            method = MA_REQ_TRACE;
            resp->flags |= MA_RESP_NO_BODY;
        }
        break;
    }

    if (method == 0) {
        maFailConnection(conn, MPR_HTTP_CODE_BAD_METHOD, "Bad method");
        return 0;
    }
    uri = getToken(conn, " ");
    if (*uri == '\0') {
        maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad HTTP request. Bad URI.");
        return 0;
    }
    if ((int) strlen(uri) >= conn->http->limits.maxUrl) {
        maFailRequest(conn, MPR_HTTP_CODE_REQUEST_URL_TOO_LARGE, "Bad request. URI too long.");
        return 0;
    }
    httpProtocol = getToken(conn, "\r\n");
    if (strcmp(httpProtocol, "HTTP/1.1") == 0) {
        conn->protocol = 1;

    } else if (strcmp(httpProtocol, "HTTP/1.0") == 0) {
        conn->protocol = 0;
        if (method == MA_REQ_POST || method == MA_REQ_PUT) {
            req->remainingContent = MAXINT;
        }

    } else {
        maFailConnection(conn, MPR_HTTP_CODE_NOT_ACCEPTABLE, "Unsupported HTTP protocol");
        return 0;
    }
    req->method = method;
    req->methodName = methodName;
    req->httpProtocol = httpProtocol;
    req->url = uri;

    if ((conn->trace = maSetupTrace(host, conn->response->extension)) != 0) {
        if (maShouldTrace(conn, MA_TRACE_REQUEST | MA_TRACE_HEADERS)) {
            mprLog(req, host->traceLevel, "\n@@@ New request from %s:%d to %s:%d\n%s %s %s", 
                conn->remoteIpAddr, conn->remotePort, conn->sock->ipAddr, conn->sock->port,
                methodName, uri, httpProtocol);
            content = packet->content;
            endp = strstr((char*) content->start, "\r\n\r\n");
            len = (endp) ? (int) (endp - mprGetBufStart(content) + 4) : 0;
            maTraceContent(conn, packet, len, 0, MA_TRACE_REQUEST | MA_TRACE_HEADERS);
        }
    } else {
        mprLog(conn, 2, "%s %s %s", methodName, uri, httpProtocol);
    }
    return 1;
}
コード例 #18
0
ファイル: phpHandler.c プロジェクト: gamman/appweb-3
static void runPhp(MaQueue *q)
{
    MaConn              *conn;
    MaRequest           *req;
    MaResponse          *resp;
    MaPhp               *php;
    FILE                *fp;
    char                shebang[MPR_MAX_STRING];
    zend_file_handle    file_handle;

    TSRMLS_FETCH();

    conn = q->conn;
    req = conn->request;
    resp = conn->response;
    php = q->queueData;

    maPutForService(q, maCreateHeaderPacket(q), 0);

    /*
     *  Set the request context
     */
    zend_first_try {
        php->var_array = 0;
        SG(server_context) = conn;
        if (req->user) {
            SG(request_info).auth_user = estrdup(req->user);
        }
        if (req->password) {
            SG(request_info).auth_password = estrdup(req->password);
        }
        if (req->authType && req->authDetails) {
            SG(request_info).auth_digest = estrdup(mprAsprintf(req, -1, "%s %s", req->authType, req->authDetails));
        }
        SG(request_info).auth_password = req->password;
        SG(request_info).content_type = req->mimeType;
        SG(request_info).content_length = req->length;
        SG(sapi_headers).http_response_code = MPR_HTTP_CODE_OK;
        SG(request_info).path_translated = resp->filename;
        SG(request_info).query_string = req->parsedUri->query;
        SG(request_info).request_method = req->methodName;
        SG(request_info).request_uri = req->url;

        /*
         *  Workaround on MAC OS X where the SIGPROF is given to the wrong thread
         */
        PG(max_input_time) = -1;
        EG(timeout_seconds) = 0;

        /* The readPostData callback may be invoked during startup */
        php_request_startup(TSRMLS_C);
        CG(zend_lineno) = 0;

    } zend_catch {
        mprError(q, "Can't start PHP request");
        zend_try {
            php_request_shutdown(0);
        } zend_end_try();
        maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "PHP initialization failed");
        return;
    } zend_end_try();


    /*
     *  Execute the script file
     */
    file_handle.filename = resp->filename;
    file_handle.free_filename = 0;
    file_handle.opened_path = 0;

#if LOAD_FROM_FILE
    file_handle.type = ZEND_HANDLE_FILENAME;
#else
    file_handle.type = ZEND_HANDLE_FP;
    if ((fp = fopen(resp->filename, "r")) == NULL) {
        maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR,  "PHP can't open script");
        return;
    }
    /*
        Check for shebang and skip
     */
    file_handle.handle.fp = fp;
    shebang[0] = '\0';
    if (fgets(shebang, sizeof(shebang), file_handle.handle.fp) != 0) {
        if (shebang[0] != '#' || shebang[1] != '!') {
            fseek(fp, 0L, SEEK_SET);
        }
    }
#endif

    zend_try {
        php_execute_script(&file_handle TSRMLS_CC);
        if (!SG(headers_sent)) {
            sapi_send_headers(TSRMLS_C);
        }
    } zend_catch {
        php_request_shutdown(0);
        maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR,  "PHP script execution failed");
        return;
    } zend_end_try();

    zend_try {
        php_request_shutdown(0);
    } zend_end_try();

    maPutForService(q, maCreateEndPacket(q), 1);
}
コード例 #19
0
ファイル: ejsAppweb.c プロジェクト: jsjohnst/appweb
static int parseUrl(MaConn *conn)
{
    EjsWeb          *web;
    EjsWebControl   *control;
    MaRequest       *req;
    MaResponse      *resp;
    MaAlias         *alias;
    MaLocation      *location;
    char            *baseDir, *cp, *url, *baseUrl;
    int             flags, locFlags;

    resp = conn->response;
    req = conn->request;
    alias = req->alias;
    location = req->location;
    locFlags = location->flags;
    url = req->url;
    
    flags = 0;
    if (locFlags & MA_LOC_APP_DIR) {
        flags |= EJS_WEB_FLAG_APP;
        mprAllocSprintf(resp, &baseDir, -1, "%s%s", alias->filename, &req->url[alias->prefixLen]);
        if ((cp = strchr(&baseDir[strlen(alias->filename) + 1], '/')) != 0) {
            *cp = '\0';
        }
        mprAllocSprintf(resp, &baseUrl, -1, "%s%s", alias->prefix, &req->url[alias->prefixLen]);
        if ((cp = strchr(&baseUrl[alias->prefixLen + 1], '/')) != 0) {
            *cp = '\0';
        }
        if (*url) {
            /* Step over the directory and app name */
            while (*++url != '/') ;
            if (*url) {
                while (*++url != '/') ;
            }
        }
            
    } else {
        if (locFlags & MA_LOC_APP) {
            flags |= EJS_WEB_FLAG_APP;
        }
        baseDir = alias->filename;
        if (alias->prefixLen > 0) {
            /* Step over the application name (same as alias prefix) */
            url = &url[alias->prefixLen];
            if (*url != '/' && url[-1] == '/') {
                url--;
            }
        }
        baseUrl = alias->prefix;
    }
    
    if (location->flags & MA_LOC_BROWSER) {
        flags |= EJS_WEB_FLAG_BROWSER_ERRORS;
    }
    if (location->flags & MA_LOC_AUTO_SESSION) {
        flags |= EJS_WEB_FLAG_SESSION;
    }

    control = conn->http->ejsHandler->stageData;
    web = ejsCreateWebRequest(req, control, conn, baseUrl, url, baseDir, flags);
    if (web == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't create Ejs web object for %s", req->url);
        return EJS_ERR;
    }
    resp->handlerData = web;

    return 0;
}
コード例 #20
0
ファイル: authFilter.c プロジェクト: embedthis/appweb-3
/*
 *  Match the request for authorization. This implements basic and digest authentication.
 */
static bool matchAuth(MaConn *conn, MaStage *stage, cchar *url)
{
    MaRequest   *req;
    MaAuth      *auth;
    AuthData    *ad;
    cchar       *requiredPassword;
    char        *msg;
    int         actualAuthType;

    req = conn->request;
    auth = req->auth;

    if (auth == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, Authorization enabled.");
        return 1;
    }
    if ((ad = mprAllocObjZeroed(req, AuthData)) == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, Server Error.");
        return 1;
    }
    if (auth->type == 0) {
        formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, Authorization required.", 0);
        return 1;
    }
    if (req->authDetails == 0) {
        formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, Missing authorization details.", 0);
        return 1;
    }
    if (mprStrcmpAnyCase(req->authType, "basic") == 0) {
        decodeBasicAuth(conn, ad);
        actualAuthType = MA_AUTH_BASIC;

#if BLD_FEATURE_AUTH_DIGEST
    } else if (mprStrcmpAnyCase(req->authType, "digest") == 0) {
        if (decodeDigestDetails(conn, ad) < 0) {
            maFailRequest(conn, 400, "Bad authorization header");
            return 1;
        }
        actualAuthType = MA_AUTH_DIGEST;
#endif
    } else {
        actualAuthType = MA_AUTH_UNKNOWN;
    }
    mprLog(conn, 4, "openAuth: type %d, url %s\nDetails %s\n", auth->type, req->url, req->authDetails);

    if (ad->userName == 0) {
        formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, Missing user name.", 0);
        return 1;
    }
    if (auth->type != actualAuthType) {
        formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, Wrong authentication protocol.", 0);
        return 1;
    }

    /*
     *  Some backend methods can't return the password and will simply do everything in validateUserCredentials. 
     *  In this case, they and will return "". That is okay.
     */
    if ((requiredPassword = getPassword(conn, auth->requiredRealm, ad->userName)) == 0) {
        formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, "Access Denied, authentication error.", 
            "User not defined");
        return 1;
    }

#if BLD_FEATURE_AUTH_DIGEST
    if (auth->type == MA_AUTH_DIGEST) {
        char *requiredDigest;
        if (strcmp(ad->qop, auth->qop) != 0) {
            formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, 
                "Access Denied, Quality of protection does not match.", 0);
            return 1;
        }
        mprCalcDigest(req, &requiredDigest, 0, requiredPassword, ad->realm, req->url, ad->nonce, ad->qop, ad->nc, ad->cnonce,
            req->methodName);
        requiredPassword = requiredDigest;
    }
#endif
    if (!validateUserCredentials(conn, auth->requiredRealm, ad->userName, ad->password, requiredPassword, &msg)) {
        formatAuthResponse(conn, auth, MPR_HTTP_CODE_UNAUTHORIZED, 
            "Access denied, authentication error", msg);
        return 1;
    }
    return 0;
}
コード例 #21
0
ファイル: pipeline.c プロジェクト: jsjohnst/appweb
/*
 *  Create stages for the request pipeline.
 */
void maCreatePipeline(MaConn *conn)
{
    MaHttp          *http;
    MaHost          *host;
    MaResponse      *resp;
    MaRequest       *req;
    MaStage         *handler;
    MaLocation      *location;
    MaStage         *stage, *connector;
    MaFilter        *filter;
    MaQueue         *q, *qhead, *rq, *rqhead;
    int             next;

    req = conn->request;
    resp = conn->response;
    host = req->host;
    location = req->location;
    handler = resp->handler;
    http = conn->http;

    mprAssert(req);
    mprAssert(location->outputStages);

    /*
     *  Create the output pipeline for this request. Handler first, then filters, connector last.
     */
    resp->outputPipeline = mprCreateList(resp);

    /*
     *  Add the handler and filters. Switch to the pass handler if any errors have occurred so far. Only add the 
     *  filters if the request has not failed.
     */
    if (conn->requestFailed) {
        resp->handler = http->passHandler;
        mprAddItem(resp->outputPipeline, resp->handler);

    } else {
        mprAddItem(resp->outputPipeline, resp->handler);
        for (next = 0; (filter = mprGetNextItem(location->outputStages, &next)) != 0; ) {
            if (filter->stage == http->authFilter) {
                if (req->auth->type == 0 && req->auth->type == 0) {
                    continue;
                }
            }
            if (filter->stage == http->rangeFilter && (req->ranges == 0 || handler == http->fileHandler)) {
                continue;
            }
            if ((filter->stage->flags & MA_STAGE_ALL & req->method) == 0) {
                continue;
            }
            /*
             *  Remove the chunk filter chunking if it is explicitly turned off vi a the X_APPWEB_CHUNK_SIZE header setting
             *  the chunk size to zero. Also remove if using the fileHandler which always knows the entity length and an
             *  explicit chunk size has not been requested.
             */
            if (filter->stage == http->chunkFilter) {
                if ((handler == http->fileHandler && resp->chunkSize < 0) || resp->chunkSize == 0) {
                    continue;
                }
            }
            if (matchFilter(conn, filter)) {
                mprAddItem(resp->outputPipeline, filter->stage);
            }
        }
    }
    
    connector = location->connector;
#if BLD_FEATURE_SEND
    if (resp->handler == http->fileHandler && connector == http->netConnector && 
        http->sendConnector && !req->ranges && !host->secure) {
        /*
         *  Switch (transparently) to the send connector if serving whole static file content via the net connector
         */
        connector = http->sendConnector;
    }
#endif
    resp->connector = connector;
    if ((connector->flags & MA_STAGE_ALL & req->method) == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_BAD_REQUEST, "Connector \"%s\" does not support the \"%s\" method \"%s\"", 
            connector->name, req->methodName);
        return;
    }
    mprAddItem(resp->outputPipeline, connector);

    /*
     *  Create the outgoing queue heads and open the queues
     */
    q = &resp->queue[MA_QUEUE_SEND];
    for (next = 0; (stage = mprGetNextItem(resp->outputPipeline, &next)) != 0; ) {
        q = maCreateQueue(conn, stage, MA_QUEUE_SEND, q);
    }

    /*
     *  Create the receive pipeline for this request. Connector first, handler last
     */
    if (req->remainingContent > 0) {
        req->inputPipeline = mprCreateList(resp);

        mprAddItem(req->inputPipeline, connector);
        if (!conn->requestFailed) {
            for (next = 0; (filter = mprGetNextItem(location->inputStages, &next)) != 0; ) {
                if (filter->stage == http->authFilter || !matchFilter(conn, filter)) {
                    continue;
                }
                if ((filter->stage->flags & MA_STAGE_ALL & req->method) == 0) {
                    continue;
                }
                mprAddItem(req->inputPipeline, filter->stage);
            }
        }
        mprAddItem(req->inputPipeline, handler);

        /*
         *  Create the incoming queue heads and open the queues.
         */
        q = &resp->queue[MA_QUEUE_RECEIVE];
        for (next = 0; (stage = mprGetNextItem(req->inputPipeline, &next)) != 0; ) {
            q = maCreateQueue(conn, stage, MA_QUEUE_RECEIVE, q);
        }
    }

    /*
     *  Pair up the send and receive queues. NOTE: can't use a stage multiple times.
     */
    qhead = &resp->queue[MA_QUEUE_SEND];
    rqhead = &resp->queue[MA_QUEUE_RECEIVE];
    for (q = qhead->nextQ; q != qhead; q = q->nextQ) {
        for (rq = rqhead->nextQ; rq != rqhead; rq = rq->nextQ) {
            if (q->stage == rq->stage) {
                q->pair = rq;
                rq->pair = q;
            }
        }
    }

    /*
     *  Open the queues (keep going on errors)
     */
    qhead = &resp->queue[MA_QUEUE_SEND];
    for (q = qhead->nextQ; q != qhead; q = q->nextQ) {
        if (q->open && !(q->flags & MA_QUEUE_OPEN)) {
            q->flags |= MA_QUEUE_OPEN;
            openQ(q);
        }
    }

    if (req->remainingContent > 0) {
        qhead = &resp->queue[MA_QUEUE_RECEIVE];
        for (q = qhead->nextQ; q != qhead; q = q->nextQ) {
            if (q->open && !(q->flags & MA_QUEUE_OPEN)) {
                if (q->pair == 0 || !(q->pair->flags & MA_QUEUE_OPEN)) {
                    q->flags |= MA_QUEUE_OPEN;
                    openQ(q);
                }
            }
        }
    }
}
コード例 #22
0
ファイル: ejsApache.c プロジェクト: embedthis/appweb-3
static void error(void *handle, int code, cchar *msg)
{
    maFailRequest(handle, code, "%s", msg);
}
コード例 #23
0
ファイル: pipeline.c プロジェクト: jsjohnst/appweb
/*
 *  Find the matching handler for a request. If any errors occur, the pass handler is used to pass errors onto the 
 *  net/sendfile connectors to send to the client. This routine may rewrite the request URI and may redirect the request.
 */
void maMatchHandler(MaConn *conn)
{
    MaRequest       *req;
    MaResponse      *resp;
    MaHost          *host;
    MaAlias         *alias;
    MaStage         *handler;
    bool            rescan;
    int             loopCount;

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

    /*
     *  Find the alias that applies for this url. There is always a catch-all alias for the document root.
     */
    alias = req->alias = maGetAlias(host, req->url);
    mprAssert(alias);
    if (alias->redirectCode) {
        // TODO - what about internal redirects?
        maRedirect(conn, alias->redirectCode, alias->uri);
        return;
    }

    if (conn->requestFailed || conn->request->method & (MA_REQ_OPTIONS | MA_REQ_TRACE)) {
        handler = conn->http->passHandler;
        return;
    }

    /*
     *  Get the best (innermost) location block and see if a handler is explicitly set for that location block.
     *  Possibly rewrite the url and retry.
     */
    loopCount = MA_MAX_REWRITE;
    do {
        rescan = 0;
        if ((handler = findLocationHandler(conn)) == 0) {
            /*
             *  Didn't find a location block handler, so try to match by extension and by handler match() routines.
             *  This may invoke processDirectory which may redirect and thus require reprocessing -- hence the loop.
             */
            handler = findHandlerByExtension(conn);
        }

        if (handler && !(handler->flags & MA_STAGE_VIRTUAL)) {
            if (!mapToFile(conn, &rescan)) {
                return;
            }
        }
    } while (handler && rescan && loopCount-- > 0);

    if (handler == 0) {
        maFailRequest(conn, MPR_HTTP_CODE_BAD_METHOD, "Requested method %s not supported for URL: %s", 
            req->methodName, req->url);
        handler = conn->http->passHandler;
    }
    resp->handler = handler;

    mprLog(resp, 4, "Select handler: \"%s\" for \"%s\"", handler->name, req->url);

    setEnv(conn);
}