static void copyMappings(HttpRoute *route, MprJson *dest, MprJson *obj) { MprJson *child, *job, *jvalue; cchar *key, *value; int ji; for (ITERATE_CONFIG(route, obj, child, ji)) { if (child->type & MPR_JSON_OBJ) { job = mprCreateJson(MPR_JSON_OBJ); copyMappings(route, job, child); mprSetJsonObj(dest, child->name, job); } else { key = child->value; if (sends(key, "|time")) { key = ssplit(sclone(key), " \t|", NULL); if ((value = mprGetJson(route->config, key)) != 0) { mprSetJson(dest, child->name, itos(httpGetTicks(value)), MPR_JSON_NUMBER); } } else { if ((jvalue = mprGetJsonObj(route->config, key)) != 0) { mprSetJsonObj(dest, child->name, mprCloneJson(jvalue)); } } } } }
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); } }
int ls(char *root, int *cs, char *cmd, int *id) { pid_t pid; pid_t tpid; (void)root; pid = fork(); if (pid == -1) error("Fork error !\n"); g_except = 1; if (pid == 0) { dup2(*cs, 0), dup2(*cs, 1), dup2(*cs, 2); execv("/bin/ls", ssplit(cmd, ' ')); } else { tpid = wait4(pid, NULL, 0, NULL); while (tpid != pid) tpid = wait4(pid, NULL, 0, NULL); (void)!write(*cs, "\0", 1); printf("Sent ls results to client %d\n", *id); } return (1); }
/* Parse the cert info and write properties to the buffer. Modifies the info argument. */ static void parseCertFields(MprBuf *buf, char *info) { char c, *cp, *term, *key, *value; if (info) { key = 0; term = cp = info; do { c = *cp; if (c == '/' || c == '\0') { *cp = '\0'; key = ssplit(term, "=", &value); if (smatch(key, "emailAddress")) { key = "email"; } mprPutToBuf(buf, "\"%s\":\"%s\",", key, value); term = &cp[1]; *cp = c; } } while (*cp++ != '\0'); if (key) { mprAdjustBufEnd(buf, -1); } } }
/********************************************************************* * * Function : compile_host_pattern * * Description : Parses and "compiles" an old-school host pattern. * * Parameters : * 1 : url = Target pattern_spec to be filled in. * 2 : host_pattern = Host pattern to parse. * * Returns : JB_ERR_OK - Success * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ static jb_err compile_host_pattern(struct pattern_spec *url, const char *host_pattern) { char *v[150]; size_t size; char *p; /* * Parse domain part */ if (host_pattern[strlen(host_pattern) - 1] == '.') { url->pattern.url_spec.unanchored |= ANCHOR_RIGHT; } if (host_pattern[0] == '.') { url->pattern.url_spec.unanchored |= ANCHOR_LEFT; } /* * Split domain into components */ url->pattern.url_spec.dbuffer = strdup_or_die(host_pattern); /* * Map to lower case */ for (p = url->pattern.url_spec.dbuffer; *p ; p++) { *p = (char)privoxy_tolower(*p); } /* * Split the domain name into components */ url->pattern.url_spec.dcount = ssplit(url->pattern.url_spec.dbuffer, ".", v, SZ(v)); if (url->pattern.url_spec.dcount < 0) { free_pattern_spec(url); return JB_ERR_PARSE; } else if (url->pattern.url_spec.dcount != 0) { /* * Save a copy of the pointers in dvec */ size = (size_t)url->pattern.url_spec.dcount * sizeof(*url->pattern.url_spec.dvec); url->pattern.url_spec.dvec = malloc_or_die(size); memcpy(url->pattern.url_spec.dvec, v, size); } /* * else dcount == 0 in which case we needn't do anything, * since dvec will never be accessed and the pattern will * match all domains. */ return JB_ERR_OK; }
int cd(char *root, int *cs, char *cmd, int *id) { char **arg; char const *cur = get_cwd(); (void)id; arg = ssplit(cmd, ' '); if (scmp(root, cur, slen(root)) != 0) return (afree(arg), sc(cs, -2), error(CWD_DENIED), 0); go_dir(cs, root, cur, arg[1]); return (afree(arg), 1); }
/* password and authType can be null User may be a combined user:password */ PUBLIC void httpSetCredentials(HttpConn *conn, cchar *username, cchar *password, cchar *authType) { char *ptok; httpResetCredentials(conn); if (password == NULL && strchr(username, ':') != 0) { conn->username = ssplit(sclone(username), ":", &ptok); conn->password = sclone(ptok); } else { conn->username = sclone(username); conn->password = sclone(password); } if (authType) { conn->authType = sclone(authType); } }
/* Get all environment vars function get env(): Object */ static EjsAny *app_env(Ejs *ejs, EjsObj *app, int argc, EjsObj **argv) { #if VXWORKS return ESV(null); #else EjsPot *result; char **ep, *pair, *key, *value; result = ejsCreatePot(ejs, ESV(Object), 0); for (ep = environ; ep && *ep; ep++) { pair = sclone(*ep); key = ssplit(pair, "=", &value); ejsSetPropertyByName(ejs, result, EN(key), ejsCreateStringFromAsc(ejs, value)); } return result; #endif }
/* Parse the cert info and write properties to the buffer. Modifies the info argument. */ static void parseCertFields(MprBuf *buf, char *prefix, char *prefix2, char *info) { char c, *cp, *term, *key, *value; if (info) { term = cp = info; do { c = *cp; if (c == '/' || c == '\0') { *cp = '\0'; key = ssplit(term, "=", &value); if (smatch(key, "emailAddress")) { key = "EMAIL"; } mprPutToBuf(buf, "%s%s%s=%s,", prefix, prefix2, key, value); term = &cp[1]; *cp = c; } } while (*cp++ != '\0'); } }
struct url_spec dsplit(char *domain) { struct url_spec ret[1]; char *v[BUFSIZ]; int size; char *p; memset(ret, '\0', sizeof(*ret)); if((p = strrchr(domain, '.'))) { if(*(++p) == '\0') { ret->toplevel = 1; } } ret->dbuf = strdup(domain); /* map to lower case */ for(p = ret->dbuf; *p ; p++) *p = tolower(*p); /* split the domain name into components */ ret->dcnt = ssplit(ret->dbuf, ".", v, SZ(v), 1, 1); if(ret->dcnt <= 0) { memset(ret, '\0', sizeof(ret)); return(*ret); } /* save a copy of the pointers in dvec */ size = ret->dcnt * sizeof(*ret->dvec); if((ret->dvec = malloc(size))) { memcpy(ret->dvec, v, size); } return(*ret); }
int put(char *root, int *cs, char *cmd, int *id) { int fd; char **cmd_args; int len; int ret; (void)root; cmd_args = ssplit(cmd, ' '); if (!check_errors(cs, cmd_args)) return (0); ret = 0, send(*cs, (void *)&ret, sizeof(uint32_t), 0); if (!receive_file_header(cs, cmd_args, &len)) return (afree(cmd_args), 0); if ((fd = open(cmd_args[1], O_RDWR | O_CREAT, 0644)) == -1) return (afree(cmd_args), err_msg(OPEN_ERR), 0); write_streaming_packets(cs, fd, &len, id); close(fd); afree(cmd_args); if (ret = 1, send(*cs, (void *)&ret, sizeof(uint32_t), 0) == -1) return (0); return (1); }
/* Write upload data. This routine blocks. If you need non-blocking ... cut and paste. */ PUBLIC ssize httpWriteUploadData(HttpConn *conn, MprList *fileData, MprList *formData) { char *path, *pair, *key, *value, *name; cchar *type; ssize rc; int next; rc = 0; if (formData) { for (rc = next = 0; rc >= 0 && (pair = mprGetNextItem(formData, &next)) != 0; ) { key = ssplit(sclone(pair), "=", &value); rc += httpWrite(conn->writeq, "%s\r\nContent-Disposition: form-data; name=\"%s\";\r\n", conn->boundary, key); rc += httpWrite(conn->writeq, "Content-Type: application/x-www-form-urlencoded\r\n\r\n%s\r\n", value); } } if (fileData) { for (rc = next = 0; rc >= 0 && (path = mprGetNextItem(fileData, &next)) != 0; ) { if (!mprPathExists(path, R_OK)) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot open %s", path); return MPR_ERR_CANT_OPEN; } name = mprGetPathBase(path); rc += httpWrite(conn->writeq, "%s\r\nContent-Disposition: form-data; name=\"file%d\"; filename=\"%s\"\r\n", conn->boundary, next - 1, name); if ((type = mprLookupMime(MPR->mimeTypes, path)) != 0) { rc += httpWrite(conn->writeq, "Content-Type: %s\r\n", mprLookupMime(MPR->mimeTypes, path)); } httpWrite(conn->writeq, "\r\n"); if (blockingFileCopy(conn, path) < 0) { return MPR_ERR_CANT_WRITE; } rc += httpWrite(conn->writeq, "\r\n"); } } rc += httpWrite(conn->writeq, "%s--\r\n--", conn->boundary); return rc; }
/********************************************************************* * * Function : init_domain_components * * Description : Splits the domain name so we can compare it * against wildcards. It used to be part of * parse_http_url, but was separated because the * same code is required in chat in case of * intercepted requests. * * Parameters : * 1 : http = pointer to the http structure to hold elements. * * Returns : JB_ERR_OK on success * JB_ERR_PARSE on malformed command/URL * or >100 domains deep. * *********************************************************************/ jb_err init_domain_components(struct http_request *http) { char *vec[BUFFER_SIZE]; size_t size; char *p; http->dbuffer = strdup_or_die(http->host); /* map to lower case */ for (p = http->dbuffer; *p ; p++) { *p = (char)privoxy_tolower(*p); } /* split the domain name into components */ http->dcount = ssplit(http->dbuffer, ".", vec, SZ(vec)); if (http->dcount <= 0) { /* * Error: More than SZ(vec) components in domain * or: no components in domain */ log_error(LOG_LEVEL_ERROR, "More than SZ(vec) components in domain or none at all."); return JB_ERR_PARSE; } /* save a copy of the pointers in dvec */ size = (size_t)http->dcount * sizeof(*http->dvec); http->dvec = malloc_or_die(size); memcpy(http->dvec, vec, size); return JB_ERR_OK; }
/* Determine the windows program to invoke. Support UNIX style "#!/program" bang directives on windows. Also supports ".cmd" and ".bat" alternatives. */ static void prepWinProgram(MprCmd *cmd) { #if ME_WIN_LIKE MprFile *file; cchar *bat, *ext, *shell, *cp, *start; char bang[ME_MAX_FNAME + 1], *path, *pp; /* Map separators, convert carriage-returns and newlines to spaces and remove quotes on the command */ path = mprAlloc(slen(cmd->argv[0]) * 2 + 1); strcpy(path, cmd->argv[0]); for (pp = path; *pp; pp++) { if (*pp == '/') { *pp = '\\'; } else if (*pp == '\r' || *pp == '\n') { *pp = ' '; } } if (*path == '\"') { if ((pp = strrchr(++path, '"')) != 0) { *pp = '\0'; } path = sclone(path); } cmd->argv[0] = path; /* Support ".cmd" and ".bat" files that take precedence */ if ((ext = mprGetPathExt(path)) == 0) { if ((bat = mprSearchPath(mprJoinPathExt(path, ".cmd"), MPR_SEARCH_EXE, cmd->searchPath, NULL)) == 0) { bat = mprSearchPath(mprJoinPathExt(path, ".bat"), MPR_SEARCH_EXE, cmd->searchPath, NULL); } if (bat) { if ((shell = getenv("COMSPEC")) == 0) { shell = "cmd.exe"; } cmd->argv = mprRealloc((void*) cmd->argv, (cmd->argc + 4) * sizeof(char*)); memmove((void*) &cmd->argv[3], (void*) cmd->argv, sizeof(char*) * (cmd->argc + 1)); cmd->argv[0] = sclone(shell); cmd->argv[1] = sclone("/Q"); cmd->argv[2] = sclone("/C"); cmd->argv[3] = bat; cmd->argc += 3; cmd->argv[cmd->argc] = 0; return; } } if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) { if (mprReadFile(file, bang, ME_MAX_FNAME) > 0) { mprCloseFile(file); bang[ME_MAX_FNAME] = '\0'; if (bang[0] == '#' && bang[1] == '!') { cp = start = &bang[2]; shell = ssplit(&bang[2], "\r\n", NULL); if (!mprIsPathAbs(shell)) { /* If we cannot access the command shell and the command is not an absolute path, look in the same directory as the script. */ if (mprPathExists(shell, X_OK)) { shell = mprJoinPath(mprGetPathDir(path), shell); } } /* Get length of argv with NULL and add one */ assert(cmd->argv[cmd->argc] == 0); cmd->argv = mprRealloc((void*) cmd->argv, (cmd->argc + 2) * sizeof(char*)); cmd->argv[cmd->argc + 1] = 0; /* Copy up to make room to insert the shell argument. This copies the original NULL */ memmove((void*) &cmd->argv[1], (void*) cmd->argv, sizeof(char*) * cmd->argc); cmd->argv[0] = sclone(shell); cmd->argv[1] = path; cmd->argc += 1; assert(cmd->argv[cmd->argc] == 0); } } else { mprCloseFile(file); } } #endif }
/* WARNING: may yield */ PUBLIC int espLoadConfig(HttpRoute *route) { EspRoute *eroute; cchar *name, *package; bool modified; eroute = route->eroute; if (!route->update) { return 0; } package = mprJoinPath(mprGetPathDir(eroute->configFile), "package.json"); modified = 0; ifConfigModified(route, eroute->configFile, &modified); ifConfigModified(route, package, &modified); if (modified) { lock(esp); httpInitConfig(route); #if DEPRECATED || 1 /* Don't reload if configFile == package.json */ if (!mprSamePath(package, eroute->configFile)) { #endif if (mprPathExists(package, R_OK)) { if (httpLoadConfig(route, package) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } } } if (httpLoadConfig(route, eroute->configFile) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } if ((name = espGetConfig(route, "name", 0)) != 0) { eroute->appName = name; } if (espLoadCompilerRules(route) < 0) { return MPR_ERR_CANT_OPEN; } unlock(esp); } if (!route->cookie) { httpSetRouteCookie(route, sfmt("esp-%s", eroute->appName)); } if (route->database && !eroute->edi) { if (espOpenDatabase(route, route->database) < 0) { mprLog("error esp", 0, "Cannot open database %s", route->database); return MPR_ERR_CANT_LOAD; } } #if !ME_STATIC if (!(route->flags & HTTP_ROUTE_NO_LISTEN)) { MprJson *preload, *item; cchar *errMsg, *source; char *kind; int i; /* WARNING: may yield when compiling modules */ if (eroute->combine) { source = mprJoinPaths(route->home, httpGetDir(route, "CACHE"), sfmt("%s.c", eroute->appName), NULL); } else { source = mprJoinPaths(route->home, httpGetDir(route, "SRC"), "app.c", NULL); } lock(esp); if (espLoadModule(route, NULL, "app", source, &errMsg) < 0) { if (eroute->combine) { mprLog("error esp", 0, "%s", errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } if (!eroute->combine && (preload = mprGetJsonObj(route->config, "esp.preload")) != 0) { for (ITERATE_JSON(preload, item, i)) { source = ssplit(sclone(item->value), ":", &kind); if (*kind == '\0') { kind = "controller"; } source = mprJoinPaths(route->home, httpGetDir(route, "CONTROLLERS"), source, NULL); if (espLoadModule(route, NULL, kind, source, &errMsg) < 0) { mprLog("error esp", 0, "Cannot preload esp module %s. %s", source, errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } } unlock(esp); }
/********************************************************************* * * Function : parse_http_request * * Description : Parse out the host and port from the URL. Find the * hostname & path, port (if ':'), and/or password (if '@') * * Parameters : * 1 : req = HTTP request line to break down * 2 : http = pointer to the http structure to hold elements * * Returns : JB_ERR_OK on success * JB_ERR_CGI_PARAMS on malformed command/URL * or >100 domains deep. * *********************************************************************/ jb_err parse_http_request(const char *req, struct http_request *http) { char *buf; char *v[3]; int n; jb_err err; memset(http, '\0', sizeof(*http)); buf = strdup_or_die(req); n = ssplit(buf, " \r\n", v, SZ(v)); if (n != 3) { freez(buf); return JB_ERR_PARSE; } /* * Fail in case of unknown methods * which we might not handle correctly. * * XXX: There should be a config option * to forward requests with unknown methods * anyway. Most of them don't need special * steps. */ if (unknown_method(v[0])) { log_error(LOG_LEVEL_ERROR, "Unknown HTTP method detected: %s", v[0]); freez(buf); return JB_ERR_PARSE; } if (JB_ERR_OK != normalize_http_version(v[2])) { freez(buf); return JB_ERR_PARSE; } http->ssl = !strcmpic(v[0], "CONNECT"); err = parse_http_url(v[1], http, !http->ssl); if (err) { freez(buf); return err; } /* * Copy the details into the structure */ http->cmd = strdup_or_die(req); http->gpc = strdup_or_die(v[0]); http->ver = strdup_or_die(v[2]); http->ocmd = strdup_or_die(http->cmd); freez(buf); return JB_ERR_OK; }
static void processUploadHeader(Webs *wp, char *line) { WebsUpload *file; char *key, *headerTok, *rest, *nextPair, *value; if (line[0] == '\0') { wp->uploadState = UPLOAD_CONTENT_DATA; return; } trace(7, "Header line: %s", line); headerTok = line; stok(line, ": ", &rest); if (scaselesscmp(headerTok, "Content-Disposition") == 0) { /* The content disposition header describes either a form variable or an uploaded file. Content-Disposition: form-data; name="field1" >>blank line Field Data ---boundary Content-Disposition: form-data; name="field1" filename="user.file" >>blank line File data ---boundary */ key = rest; wfree(wp->uploadVar); wfree(wp->clientFilename); wp->uploadVar = wp->clientFilename = 0; while (key && stok(key, ";\r\n", &nextPair)) { key = strim(key, " ", WEBS_TRIM_BOTH); ssplit(key, "= ", &value); value = strim(value, "\"", WEBS_TRIM_BOTH); if (scaselesscmp(key, "form-data") == 0) { /* Nothing to do */ } else if (scaselesscmp(key, "name") == 0) { wfree(wp->uploadVar); wp->uploadVar = sclone(value); } else if (scaselesscmp(key, "filename") == 0) { if (wp->uploadVar == 0) { websError(wp, HTTP_CODE_BAD_REQUEST, "Bad upload state. Missing name field"); return; } value = websNormalizeUriPath(value); if (*value == '.' || !websValidUriChars(value) || strpbrk(value, "\\/:*?<>|~\"'%`^\n\r\t\f")) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Bad upload client filename"); wfree(value); return; } wfree(wp->clientFilename); wp->clientFilename = value; /* Create the file to hold the uploaded data */ wfree(wp->uploadTmp); if ((wp->uploadTmp = websTempFile(uploadDir, "tmp")) == 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot create upload temp file %s. Check upload temp dir %s", wp->uploadTmp, uploadDir); return; } trace(5, "File upload of: %s stored as %s", wp->clientFilename, wp->uploadTmp); if ((wp->upfd = open(wp->uploadTmp, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600)) < 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot open upload temp file %s", wp->uploadTmp); return; } /* Create the files[id] */ file = wp->currentFile = walloc(sizeof(WebsUpload)); memset(file, 0, sizeof(WebsUpload)); file->clientFilename = sclone(wp->clientFilename); file->filename = sclone(wp->uploadTmp); } key = nextPair; } } else if (scaselesscmp(headerTok, "Content-Type") == 0) { if (wp->clientFilename) { trace(5, "Set files[%s][CONTENT_TYPE] = %s", wp->uploadVar, rest); wp->currentFile->contentType = sclone(rest); } } }
/* If the program has a UNIX style "#!/program" string at the start of the file that program will be selected and the original program will be passed as the first arg to that program with argv[] appended after that. If the program is not found, this routine supports a safe intelligent search for the command. If all else fails, we just return in program the fileName we were passed in. script will be set if we are modifying the program to run and we have extracted the name of the file to run as a script. */ static void findExecutable(HttpConn *conn, char **program, char **script, char **bangScript, cchar *fileName) { HttpRx *rx; HttpTx *tx; HttpRoute *route; MprKey *kp; MprFile *file; cchar *actionProgram, *ext, *cmdShell, *cp, *start, *path; char buf[ME_MAX_FNAME + 1]; rx = conn->rx; tx = conn->tx; route = rx->route; *bangScript = 0; *script = 0; *program = 0; path = 0; actionProgram = mprGetMimeProgram(rx->route->mimeTypes, rx->mimeType); ext = tx->ext; /* If not found, go looking for the fileName with the extensions defined in appweb.conf. NOTE: we don't use PATH deliberately!!! */ if (access(fileName, X_OK) < 0) { for (kp = 0; (kp = mprGetNextKey(route->extensions, kp)) != 0; ) { path = sjoin(fileName, ".", kp->key, NULL); if (access(path, X_OK) == 0) { break; } path = 0; } if (kp) { ext = kp->key; } else { path = fileName; } } else { path = fileName; } assert(path && *path); #if ME_WIN_LIKE if (ext && (strcmp(ext, ".bat") == 0 || strcmp(ext, ".cmd") == 0)) { /* Let a mime action override COMSPEC */ if (actionProgram) { cmdShell = actionProgram; } else { cmdShell = getenv("COMSPEC"); } if (cmdShell == 0) { cmdShell = "cmd.exe"; } *script = sclone(path); *program = sclone(cmdShell); return; } #endif if (actionProgram) { *program = sclone(actionProgram); } else if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) { if (mprReadFile(file, buf, ME_MAX_FNAME) > 0) { mprCloseFile(file); buf[ME_MAX_FNAME] = '\0'; if (buf[0] == '#' && buf[1] == '!') { cp = start = &buf[2]; cmdShell = ssplit(&buf[2], "\r\n", NULL); if (!mprIsPathAbs(cmdShell)) { /* If we cannot access the command shell and the command is not an absolute path, look in the same directory as the script. */ if (mprPathExists(cmdShell, X_OK)) { cmdShell = mprJoinPath(mprGetPathDir(path), cmdShell); } } *program = sclone(cmdShell); *bangScript = sclone(path); return; } } else { mprCloseFile(file); } } if (actionProgram) { *program = sclone(actionProgram); *bangScript = sclone(path); } else { *program = sclone(path); } return; }
/* Parse the CGI output headers. Sample CGI program output: Content-type: text/html <html..... */ static bool parseCgiHeaders(Cgi *cgi, HttpPacket *packet) { HttpConn *conn; MprBuf *buf; char *endHeaders, *headers, *key, *value; ssize blen; int len; conn = cgi->conn; value = 0; buf = packet->content; headers = mprGetBufStart(buf); blen = mprGetBufLength(buf); /* Split the headers from the body. Add null to ensure we can search for line terminators. */ len = 0; if ((endHeaders = sncontains(headers, "\r\n\r\n", blen)) == NULL) { if ((endHeaders = sncontains(headers, "\n\n", blen)) == NULL) { if (mprGetCmdFd(cgi->cmd, MPR_CMD_STDOUT) >= 0 && strlen(headers) < ME_MAX_HEADERS) { /* Not EOF and less than max headers and have not yet seen an end of headers delimiter */ return 0; } } len = 2; } else { len = 4; } if (endHeaders > buf->end) { assert(endHeaders <= buf->end); return 0; } if (endHeaders) { endHeaders[len - 1] = '\0'; endHeaders += len; } /* Want to be tolerant of CGI programs that omit the status line. */ if (strncmp((char*) buf->start, "HTTP/1.", 7) == 0) { if (!parseFirstCgiResponse(cgi, packet)) { /* httpError already called */ return 0; } } if (endHeaders && strchr(mprGetBufStart(buf), ':')) { while (mprGetBufLength(buf) > 0 && buf->start[0] && (buf->start[0] != '\r' && buf->start[0] != '\n')) { if ((key = getCgiToken(buf, ":")) == 0) { key = "Bad Header"; } value = getCgiToken(buf, "\n"); while (isspace((uchar) *value)) { value++; } len = (int) strlen(value); while (len > 0 && (value[len - 1] == '\r' || value[len - 1] == '\n')) { value[len - 1] = '\0'; len--; } key = slower(key); if (strcmp(key, "location") == 0) { cgi->location = value; } else if (strcmp(key, "status") == 0) { httpSetStatus(conn, atoi(value)); } else if (strcmp(key, "content-type") == 0) { httpSetHeaderString(conn, "Content-Type", value); } else if (strcmp(key, "content-length") == 0) { httpSetContentLength(conn, (MprOff) stoi(value)); httpSetChunkSize(conn, 0); } else { /* Now pass all other headers back to the client */ key = ssplit(key, ":\r\n\t ", NULL); httpSetHeaderString(conn, key, value); } } buf->start = endHeaders; } return 1; }
static ssize parseCgiHeaders(Webs *wp, char *buf) { char *end, *cp, *key, *value, *location, *contentType; ssize len, contentLength; int status, doneHeaders; status = HTTP_CODE_OK; contentLength = -1; contentType = 0; location = 0; doneHeaders = 0; /* Look for end of headers */ if ((end = strstr(buf, "\r\n\r\n")) == NULL) { if ((end = strstr(buf, "\n\n")) == NULL) { return 0; } len = 2; } else { len = 4; } end[len - 1] = '\0'; end += len; cp = buf; if (!strchr(cp, ':')) { /* No headers found */ return 0; } if (strncmp(cp, "HTTP/1.", 7) == 0) { ssplit(cp, "\r\n", &cp); } for (; cp && *cp && (*cp != '\r' && *cp != '\n') && cp < end; ) { key = slower(ssplit(cp, ":", &value)); if (strcmp(key, "location") == 0) { location = value; } else if (strcmp(key, "status") == 0) { status = atoi(value); } else if (strcmp(key, "content-type") == 0) { contentType = value; } else if (strcmp(key, "content-length") == 0) { contentLength = atoi(value); } else { /* Now pass all other headers back to the client */ if (!doneHeaders) { writeCgiHeaders(wp, status, contentLength, location, contentType); doneHeaders = 1; } if (key && value && !strspn(key, "%<>/\\")) { websWriteHeader(wp, key, "%s", value); } else { trace(5, "cgi: bad response http header: \"%s\": \"%s\"", key, value); } } stok(value, "\r\n", &cp); } if (!doneHeaders) { writeCgiHeaders(wp, status, contentLength, location, contentType); } websWriteEndHeaders(wp); return end - buf; }