PUBLIC void websCgiGatherOutput(Cgi *cgip) { Webs *wp; WebsStat sbuf; char buf[ME_GOAHEAD_LIMIT_HEADERS + 2]; ssize nbytes, skip; int fdout; /* OPT - currently polling and doing a stat each poll. Also doing open/close each chunk. If the CGI process writes partial headers, this repeatedly reads the data until complete headers are written or more than ME_GOAHEAD_LIMIT_HEADERS of data is received. */ if ((stat(cgip->stdOut, &sbuf) == 0) && (sbuf.st_size > cgip->fplacemark)) { if ((fdout = open(cgip->stdOut, O_RDONLY | O_BINARY, 0444)) >= 0) { /* Check to see if any data is available in the output file and send its contents to the socket. Write the HTTP header on our first pass. The header must fit into ME_GOAHEAD_LIMIT_BUFFER. */ wp = cgip->wp; lseek(fdout, cgip->fplacemark, SEEK_SET); while ((nbytes = read(fdout, buf, sizeof(buf))) > 0) { if (!(wp->flags & WEBS_HEADERS_CREATED)) { if ((skip = parseCgiHeaders(wp, buf)) == 0) { if (cgip->handle && sbuf.st_size < ME_GOAHEAD_LIMIT_HEADERS) { trace(5, "cgi: waiting for http headers"); break; } else { trace(5, "cgi: missing http headers - create default headers"); writeCgiHeaders(wp, HTTP_CODE_OK, -1, 0, 0); } } } trace(5, "cgi: write %d bytes to client", nbytes - skip); websWriteBlock(wp, &buf[skip], nbytes - skip); cgip->fplacemark += (off_t) nbytes; } close(fdout); } else { trace(5, "cgi: open failed"); } } }
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) { stok(cp, "\r\n", &cp); } for (; *cp && (*cp != '\r' && *cp != '\n') && cp < end; ) { key = slower(stok(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; } websWriteHeader(wp, key, "%s", value); } stok(value, "\r\n", &cp); } if (!doneHeaders) { writeCgiHeaders(wp, status, contentLength, location, contentType); } websWriteEndHeaders(wp); return end - buf; }