/* * 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); }
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; } }
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); } }
static void runDir(MaQueue *q) { MaConn *conn; MaResponse *resp; MaRequest *req; MprList *list; MprDirEntry *dp; Dir *dir; cchar *filename; uint nameSize; int next; conn = q->conn; req = conn->request; resp = conn->response; dir = q->stage->stageData; filename = resp->filename; mprAssert(filename); maDontCacheResponse(conn); maSetHeader(conn, 0, "Last-Modified", req->host->currentDate); maPutForService(q, maCreateHeaderPacket(q), 0); parseQuery(conn); list = mprGetPathFiles(conn, filename, 1); if (list == 0) { maWrite(q, "<h2>Can't get file list</h2>\r\n"); outputFooter(q); return; } if (dir->pattern) { filterDirList(conn, list); } sortList(conn, list); /* * Get max filename */ nameSize = 0; for (next = 0; (dp = mprGetNextItem(list, &next)) != 0; ) { nameSize = max((int) strlen(dp->name), nameSize); } nameSize = max(nameSize, 22); outputHeader(q, req->url, nameSize); for (next = 0; (dp = mprGetNextItem(list, &next)) != 0; ) { outputLine(q, dp, filename, nameSize); } outputFooter(q); maPutForService(q, maCreateEndPacket(conn), 1); mprFree(list); }
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 }
/* * 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); }
static void reportFailure(MaConn *conn, int code, cchar *fmt, va_list args) { MaResponse *resp; MaRequest *req; cchar *url, *status; char *emsg, *msg, *filename; mprAssert(fmt); if (conn->requestFailed) { return; } conn->requestFailed = 1; if (fmt == 0) { fmt = ""; } req = conn->request; resp = conn->response; maDontCacheResponse(conn); msg = mprVasprintf(conn, MA_BUFSIZE, fmt, args); if (resp == 0 || req == 0) { mprLog(conn, 2, "\"%s\", code %d: %s.", mprGetHttpCodeString(conn, code), code, msg); } else { resp->code = code; filename = resp->filename ? resp->filename : 0; /* 711 is a custom error used by the test suite. */ if (code != 711) { mprLog(resp, 2, "Error: \"%s\", code %d for URI \"%s\", file \"%s\": %s.", mprGetHttpCodeString(conn, code), code, req->url ? req->url : "", filename ? filename : "", msg); } /* * Use an error document rather than standard error boilerplate. */ if (req->location) { url = maLookupErrorDocument(req->location, code); if (url && *url) { maRedirect(conn, 302, url); mprFree(msg); return; } } /* * If the headers have already been filled, this alternate response body will be ignored. */ if (resp->altBody == 0) { status = mprGetHttpCodeString(conn, code); /* * For security, escape the message */ emsg = mprEscapeHtml(resp, msg); resp->altBody = mprAsprintf(resp, -1, "<!DOCTYPE html>\r\n" "<html><head><title>Document Error: %s</title></head>\r\n" "<body><h2>Access Error: %d -- %s</h2>\r\n<p>%s</p>\r\n</body>\r\n</html>\r\n", status, code, status, emsg); } resp->flags |= MA_RESP_NO_BODY; } mprFree(msg); }
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); }
/* * 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; }