static void cacheAtClient(HttpConn *conn) { HttpTx *tx; HttpCache *cache; cchar *value; tx = conn->tx; cache = conn->tx->cache; if (!mprLookupKey(tx->headers, "Cache-Control")) { if ((value = mprLookupKey(conn->tx->headers, "Cache-Control")) != 0) { if (strstr(value, "max-age") == 0) { httpAppendHeader(conn, "Cache-Control", "max-age=%d", cache->clientLifespan / MPR_TICKS_PER_SEC); } } else { httpAddHeader(conn, "Cache-Control", "max-age=%d", cache->clientLifespan / MPR_TICKS_PER_SEC); } #if UNUSED && KEEP { /* Old HTTP/1.0 clients don't understand Cache-Control */ struct tm tm; mprDecodeUniversalTime(&tm, conn->http->now + (expires * MPR_TICKS_PER_SEC)); httpAddHeader(conn, "Expires", "%s", mprFormatTime(MPR_HTTP_DATE, &tm)); } #endif } }
/* Add the client 'Authorization' header for authenticated requests Must first get a 401 response to get the authData. */ PUBLIC bool httpDigestSetHeaders(HttpConn *conn, cchar *username, cchar *password) { Http *http; HttpTx *tx; DigestData *dp; char *ha1, *ha2, *digest, *cnonce; http = conn->http; tx = conn->tx; if ((dp = conn->authData) == 0) { /* Need to await a failing auth response */ return 0; } cnonce = sfmt("%s:%s:%x", http->secret, dp->realm, (int) http->now); ha1 = mprGetMD5(sfmt("%s:%s:%s", username, dp->realm, password)); ha2 = mprGetMD5(sfmt("%s:%s", tx->method, tx->parsedUri->path)); if (smatch(dp->qop, "auth")) { digest = mprGetMD5(sfmt("%s:%s:%08x:%s:%s:%s", ha1, dp->nonce, dp->nc, cnonce, dp->qop, ha2)); httpAddHeader(conn, "Authorization", "Digest username=\"%s\", realm=\"%s\", domain=\"%s\", " "algorithm=\"MD5\", qop=\"%s\", cnonce=\"%s\", nc=\"%08x\", nonce=\"%s\", opaque=\"%s\", " "stale=\"FALSE\", uri=\"%s\", response=\"%s\"", username, dp->realm, dp->domain, dp->qop, cnonce, dp->nc, dp->nonce, dp->opaque, tx->parsedUri->path, digest); } else { digest = mprGetMD5(sfmt("%s:%s:%s", ha1, dp->nonce, ha2)); httpAddHeader(conn, "Authorization", "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " "uri=\"%s\", response=\"%s\"", username, dp->realm, dp->nonce, tx->parsedUri->path, digest); } return 1; }
static void setDefaultHeaders(HttpStream *stream) { HttpAuthType *ap; assert(stream); if (stream->username && stream->authType && ((ap = httpLookupAuthType(stream->authType)) != 0)) { if ((ap->setAuth)(stream, stream->username, stream->password)) { stream->authRequested = 1; } } if (stream->net->protocol < 2) { if (stream->port != 80 && stream->port != 443) { if (schr(stream->ip, ':')) { httpAddHeader(stream, "Host", "[%s]:%d", stream->ip, stream->port); } else { httpAddHeader(stream, "Host", "%s:%d", stream->ip, stream->port); } } else { httpAddHeaderString(stream, "Host", stream->ip); } if (stream->keepAliveCount > 0) { httpSetHeaderString(stream, "Connection", "Keep-Alive"); } else { httpSetHeaderString(stream, "Connection", "close"); } } httpAddHeaderString(stream, "Accept", "*/*"); }
static void setDefaultHeaders(HttpConn *conn) { HttpAuthType *ap; assert(conn); if (smatch(conn->protocol, "HTTP/1.0")) { conn->http10 = 1; } if (conn->username && conn->authType) { if ((ap = httpLookupAuthType(conn->authType)) != 0) { if ((ap->setAuth)(conn, conn->username, conn->password)) { conn->authRequested = 1; } } } if (conn->port != 80 && conn->port != 443) { httpAddHeader(conn, "Host", "%s:%d", conn->ip, conn->port); } else { httpAddHeaderString(conn, "Host", conn->ip); } httpAddHeaderString(conn, "Accept", "*/*"); if (conn->keepAliveCount > 0) { httpSetHeaderString(conn, "Connection", "Keep-Alive"); } else { httpSetHeaderString(conn, "Connection", "close"); } }
/* Define headers and create an empty header packet that will be filled later by the pipeline. */ static int setClientHeaders(HttpConn *conn) { HttpAuthType *authType; mprAssert(conn); if (smatch(conn->protocol, "HTTP/1.0")) { conn->http10 = 1; } if (conn->authType && (authType = httpLookupAuthType(conn->authType)) != 0) { (authType->setAuth)(conn); conn->setCredentials = 1; } if (conn->port != 80) { httpAddHeader(conn, "Host", "%s:%d", conn->ip, conn->port); } else { httpAddHeaderString(conn, "Host", conn->ip); } #if UNUSED if (conn->http10 && !smatch(conn->tx->method, "GET")) { conn->keepAliveCount = 0; } #endif if (conn->keepAliveCount > 0) { httpSetHeaderString(conn, "Connection", "Keep-Alive"); } else { httpSetHeaderString(conn, "Connection", "close"); } return 0; }
/* Parse cached content of the form: headers \n\n data Set headers in the current requeset and return a reference to the data portion */ static cchar *setHeadersFromCache(HttpConn *conn, cchar *content) { cchar *data; char *header, *headers, *key, *value, *tok; if ((data = strstr(content, "\n\n")) == 0) { data = content; } else { headers = snclone(content, data - content); data += 2; for (header = stok(headers, "\n", &tok); header; header = stok(NULL, "\n", &tok)) { key = stok(header, ": ", &value); if (smatch(key, "X-Status")) { conn->tx->status = (int) stoi(value); } else { httpAddHeader(conn, key, value); } } } return data; }
/* 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); } } } }