static int setContentLength(HttpConn *conn, MprList *files) { MprPath info; MprOff len; char *path, *pair; int next; len = 0; if (app->upload) { httpEnableUpload(conn); return 0; } for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) { if (strcmp(path, "-") != 0) { if (mprGetPathInfo(path, &info) < 0) { mprError("Can't access file %s", path); return MPR_ERR_CANT_ACCESS; } len += info.size; } } if (app->formData) { for (next = 0; (pair = mprGetNextItem(app->formData, &next)) != 0; ) { len += slen(pair); } len += mprGetListLength(app->formData) - 1; } if (app->bodyData) { len += mprGetBufLength(app->bodyData); } if (len > 0) { httpSetContentLength(conn, len); } return 0; }
/* Handle Trace and Options requests. Handlers can do this themselves if they desire, but typically all Trace/Options requests come here. */ void httpHandleOptionsTrace(HttpConn *conn) { HttpRx *rx; HttpTx *tx; int flags; tx = conn->tx; rx = conn->rx; if (rx->flags & HTTP_TRACE) { /* The trace method is disabled by default unless 'TraceMethod on' is specified */ if (!conn->limits->enableTraceMethod) { tx->status = HTTP_CODE_NOT_ACCEPTABLE; httpFormatResponseBody(conn, "Trace Request Denied", "The TRACE method is disabled on this server."); } else { httpFormatResponse(conn, "%s %s %s\r\n", rx->method, rx->uri, conn->protocol); } /* This finalizes output and indicates the request is now complete */ httpFinalize(conn); } else if (rx->flags & HTTP_OPTIONS) { flags = tx->traceMethods; httpSetHeader(conn, "Allow", "OPTIONS%s%s%s%s%s%s", (conn->limits->enableTraceMethod) ? ",TRACE" : "", (flags & HTTP_STAGE_GET) ? ",GET" : "", (flags & HTTP_STAGE_HEAD) ? ",HEAD" : "", (flags & HTTP_STAGE_POST) ? ",POST" : "", (flags & HTTP_STAGE_PUT) ? ",PUT" : "", (flags & HTTP_STAGE_DELETE) ? ",DELETE" : ""); httpOmitBody(conn); httpSetContentLength(conn, 0); httpFinalize(conn); } }
/* 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; }
void espSetContentLength(HttpConn *conn, MprOff length) { httpSetContentLength(conn, length); }