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 (scaselessmatch(header->key, "User-Agent")) { httpSetHeaderString(conn, header->key, header->value); } else { httpAppendHeaderString(conn, header->key, header->value); } } if (app->text) { httpSetHeader(conn, "Accept", "text/plain"); } if (app->sequence) { static int next = 0; seq = itos(next++); httpSetHeaderString(conn, "X-Http-Seq", seq); } if (app->ranges) { httpSetHeaderString(conn, "Range", app->ranges); } if (app->formData) { httpSetContentType(conn, "application/x-www-form-urlencoded"); } if (setContentLength(conn, files) < 0) { return MPR_ERR_CANT_OPEN; } return 0; }
/* Append a header. If already defined, the value is catenated to the pre-existing value after a ", " separator. As per the HTTP/1.1 spec. */ void espAppendHeader(HttpConn *conn, cchar *key, cchar *fmt, ...) { va_list vargs; mprAssert(key && *key); mprAssert(fmt && *fmt); va_start(vargs, fmt); httpAppendHeaderString(conn, key, sfmt(fmt, vargs)); va_end(vargs); }
/* function setHeader(key: String, value: String, overwrite: Boolean = true): Void */ static EjsObj *http_setHeader(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { HttpConn *conn; cchar *key, *value; bool overwrite; assert(argc >= 2); conn = hp->conn; if (conn->state >= HTTP_STATE_CONNECTED) { ejsThrowArgError(ejs, "Cannot update request headers once the request has started"); return 0; } key = ejsToMulti(ejs, argv[0]); value = ejsToMulti(ejs, argv[1]); overwrite = (argc == 3) ? ejsGetBoolean(ejs, argv[2]) : 1; if (overwrite) { httpSetHeaderString(hp->conn, key, value); } else { httpAppendHeaderString(hp->conn, key, value); } return 0; }
/* Append a header string. If already defined, the value is catenated to the pre-existing value after a ", " separator. As per the HTTP/1.1 spec. */ void espAppendHeaderString(HttpConn *conn, cchar *key, cchar *value) { httpAppendHeaderString(conn, key, value); }
/* Set headers for httpWriteHeaders. This defines standard headers. */ static void setHeaders(HttpConn *conn, HttpPacket *packet) { HttpRx *rx; HttpTx *tx; HttpRoute *route; HttpRange *range; MprKeyValue *item; MprOff length; cchar *mimeType; int next; assert(packet->flags == HTTP_PACKET_HEADER); rx = conn->rx; tx = conn->tx; route = rx->route; /* Mandatory headers that must be defined here use httpSetHeader which overwrites existing values. */ httpAddHeaderString(conn, "Date", conn->http->currentDate); if (tx->ext && route) { if ((mimeType = (char*) mprLookupMime(route->mimeTypes, tx->ext)) != 0) { if (conn->error) { httpAddHeaderString(conn, "Content-Type", "text/html"); } else { httpAddHeaderString(conn, "Content-Type", mimeType); } } } if (tx->etag) { httpAddHeader(conn, "ETag", "%s", tx->etag); } length = tx->length > 0 ? tx->length : 0; if (rx->flags & HTTP_HEAD) { conn->tx->flags |= HTTP_TX_NO_BODY; httpDiscardData(conn, HTTP_QUEUE_TX); if (tx->chunkSize <= 0) { httpAddHeader(conn, "Content-Length", "%Ld", length); } } else if (tx->length < 0 && tx->chunkSize > 0) { httpSetHeaderString(conn, "Transfer-Encoding", "chunked"); } else if (conn->endpoint) { /* Server must not emit a content length header for 1XX, 204 and 304 status */ if (!((100 <= tx->status && tx->status <= 199) || tx->status == 204 || tx->status == 304 || tx->flags & HTTP_TX_NO_LENGTH)) { httpAddHeader(conn, "Content-Length", "%Ld", length); } } else if (tx->length > 0) { /* client with body */ httpAddHeader(conn, "Content-Length", "%Ld", length); } if (tx->outputRanges) { if (tx->outputRanges->next == 0) { range = tx->outputRanges; if (tx->entityLength > 0) { httpSetHeader(conn, "Content-Range", "bytes %Ld-%Ld/%Ld", range->start, range->end - 1, tx->entityLength); } else { httpSetHeader(conn, "Content-Range", "bytes %Ld-%Ld/*", range->start, range->end - 1); } } else { httpSetHeader(conn, "Content-Type", "multipart/byteranges; boundary=%s", tx->rangeBoundary); } httpSetHeader(conn, "Accept-Ranges", "bytes"); } if (conn->endpoint) { if (!(route->flags & HTTP_ROUTE_STEALTH)) { httpAddHeaderString(conn, "Server", conn->http->software); } /* If keepAliveCount == 1 */ if (--conn->keepAliveCount > 0) { assert(conn->keepAliveCount >= 1); httpAddHeaderString(conn, "Connection", "Keep-Alive"); httpAddHeader(conn, "Keep-Alive", "timeout=%Ld, max=%d", conn->limits->inactivityTimeout / 1000, conn->keepAliveCount); } else { /* Tell the peer to close the connection */ httpAddHeaderString(conn, "Connection", "close"); } if (route->flags & HTTP_ROUTE_CORS) { setCorsHeaders(conn); } /* Apply response headers */ for (ITERATE_ITEMS(route->headers, item, next)) { if (item->flags == HTTP_ROUTE_ADD_HEADER) { httpAddHeaderString(conn, item->key, item->value); } else if (item->flags == HTTP_ROUTE_APPEND_HEADER) { httpAppendHeaderString(conn, item->key, item->value); } else if (item->flags == HTTP_ROUTE_REMOVE_HEADER) { httpRemoveHeader(conn, item->key); } else if (item->flags == HTTP_ROUTE_SET_HEADER) { httpSetHeaderString(conn, item->key, item->value); } } } }