static int sendRequest(HttpConn *conn, cchar *method, cchar *url, MprList *files) { if (httpConnect(conn, method, url, app->ssl) < 0) { mprError("Cannot process request for \"%s\"\n%s", url, httpGetError(conn)); return MPR_ERR_CANT_OPEN; } /* This program does not do full-duplex writes with reads. ie. if you have a request that sends and receives data in parallel -- http will do the writes first then read the response. */ if (app->bodyData || app->formData || files) { if (app->chunkSize > 0) { httpSetChunkSize(conn, app->chunkSize); } if (writeBody(conn, files) < 0) { mprError("Cannot write body data to \"%s\". %s", url, httpGetError(conn)); return MPR_ERR_CANT_WRITE; } } assert(!mprGetCurrentThread()->yielded); httpFinalizeOutput(conn); return 0; }
static int prepRequest(HttpConn *conn, MprList *files, int retry) { MprKeyValue *header; char *seq; int next; httpPrepClientConn(conn, retry); for (next = 0; (header = mprGetNextItem(app->headers, &next)) != 0; ) { if (scasematch(header->key, "User-Agent")) { httpSetHeader(conn, header->key, header->value); } else { httpAppendHeader(conn, header->key, header->value); } } if (app->text) { httpSetHeader(conn, "Accept", "text/plain"); } if (app->sequence) { static int next = 0; seq = itos(next++); httpSetHeader(conn, "X-Http-Seq", seq); } if (app->ranges) { httpSetHeader(conn, "Range", app->ranges); } if (app->formData) { httpSetHeader(conn, "Content-Type", "application/x-www-form-urlencoded"); } if (app->chunkSize > 0) { httpSetChunkSize(conn, app->chunkSize); } if (setContentLength(conn, files) < 0) { return MPR_ERR_CANT_OPEN; } return 0; }
/* 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; }