+ - do not cut off "; parameter" from "digitized" Content-Type
+ http fields
+ - Added X-Request-URI for persistent connection debugging
+ (Henrik Nordstrom)
- Added Polish error pages from Maciej Kozinski.
- Fixed hash_first/hash_next bugs with **Current pointer.
Replaced with *next pointer.
- Changed URN menu output to be sorted.
- Added fast select(2) timeouts when using ASYNC_IO.
- Added ARP ACL support for Linux (David Luyer).
- - Added binary http headers to requests (still under construction)
+ - Added binary http headers to requests
- request_t objects are now created and destroyed in a consistent way
- Fixed cache control printf bug
- Added a lot of new http header ids
- Improved Connection: header handling; now both Connection and
- Proxy-Connection headers are checked
+ Proxy-Connection headers are checked for connection directives
- Connection request header is now handled correctly regardless
of its position and the number of entries
- - Better handling of persistent connection "clues" in HTTP headers
+ - Only replies with valid Content-Length can be sent with keep-alive
+ connection directive (Henrik Nordstrom)
+ - Better handling of persistent connection "clues" in HTTP headers;
+ the decision now depends on HTTP version (and User-Agent exceptions)
- Removed handling of "length=" directive in IMS headers;
the directive is not in the HTTP/1.1 standard;
standing by for objections
- allowed/denied headers are now checked using bit masks instead of
strcmp loops
- removed Uri: from allowed headers; Uri is deprecated in RFC 2068
- - removed processing of Request-Range header (no in specs?)
+ - removed processing of Request-Range header (not in specs?)
- Fixed byte-order bugs in cacheDigestHashKey.
- Changed hash_remove_link() to return void.
- Changed ipcache_gethostbyname() to return NULL if
(3) 'no_cache' access list for specifing objects which should not
be cached.
(3) What to do about ACL's and URL escaping?
-(3) Alex's HTTP Header todo list
- - http_request will be replaced with HttpRequest with changes
- similar to (http_reply -> HttpReply) transition.
- - Http replies and request will be parsed once on
- receiver(reader) end and will remain in compiled form after
- that. No "raw" header buffer will be preserved.
- - Request and reply headers (with start-lines) are likely to be
- written in compiled form as metadata to swap files.
- - Dynamic memory allocation will be revised once again. Most of
- xstrdup calls and local buffers will be replaced with better
- alternatives with static pre-allocation of resources. This work
- has been started already.
- - Statistics collected on Http* objects and memory management
- routines will be enhanced.
- - A lot of current oddities with freshly added code should go away as
- we debug and polish things. Comments discussing current code
- problems will be deleted; hopefully, along with the problems.
(3) Full request headers for CONNECT requests.
(4) ** Everywhere that we use 'pattern' or such, use ACL elements instead.
(4) ** Double check that MemBuf.size is used correctly everywhere (AR)
(4) Refresh based on content types. This means we'll need an enum of
known content types added to StoreEntry. Unknown types will lose.
+(4) Write binary headers as metadata?
(5) X-Proxy-hops header?
(5) internalize redirectors?
- Replace bcopy with xmemcpy
(4) ** FTP PUT (KA)
(1) SSL doesn't work with Proxy Authentication
+(3) HTTP Header todo list (AR)
/*
- * $Id: HttpBody.cc,v 1.10 1998/05/22 23:43:49 wessels Exp $
+ * $Id: HttpBody.cc,v 1.11 1998/05/27 22:51:39 rousskov Exp $
*
* DEBUG: section 56 HTTP Message Body
* AUTHOR: Alex Rousskov
httpBodyPackInto(const HttpBody * body, Packer * p)
{
assert(body && p);
- /* assume it was a 0-terminating buffer */
+ /* assume it was a 0-terminated buffer */
if (body->size)
packerAppend(p, body->buf, body->size - 1);
}
/*
- * $Id: HttpHdrExtField.cc,v 1.3 1998/04/06 22:32:06 wessels Exp $
+ * $Id: HttpHdrExtField.cc,v 1.4 1998/05/27 22:51:40 rousskov Exp $
*
* DEBUG: section 69 HTTP Header: Extension Field
* AUTHOR: Alex Rousskov
while (value_start < field_end && isspace(*value_start))
value_start++;
- /* cut off "; parameter" from Content-Type @?@ why? */
- if (!strncasecmp(field_start, "Content-Type:", 13)) {
- const int l = strcspn(value_start, ";\t ");
- if (l > 0 && value_start + l < field_end)
- field_end = value_start + l;
- }
return httpHdrExtFieldDoCreate(
field_start, name_end - field_start,
value_start, field_end - value_start);
/*
- * $Id: HttpHeader.cc,v 1.36 1998/05/22 23:43:52 wessels Exp $
+ * $Id: HttpHeader.cc,v 1.37 1998/05/27 22:51:41 rousskov Exp $
*
* DEBUG: section 55 HTTP Header
* AUTHOR: Alex Rousskov
*/
-/* To-Do: fix parseCount stats @?@ @?@ */
-
-
/*
* local types
*/
{"Age", HDR_ALLOW, ftStr},
{"Authorization", HDR_AUTHORIZATION, ftStr}, /* for now */
{"Cache-Control", HDR_CACHE_CONTROL, ftPCc},
- {"Connection", HDR_CONNECTION, ftStr}, /* for now */
+ {"Connection", HDR_CONNECTION, ftStr},
+ {"Content-Base", HDR_CONTENT_BASE, ftStr},
{"Content-Encoding", HDR_CONTENT_ENCODING, ftStr},
{"Content-Language", HDR_CONTENT_LANGUAGE, ftStr},
{"Content-Length", HDR_CONTENT_LENGTH, ftInt},
+ {"Content-Location", HDR_CONTENT_LOCATION, ftStr},
{"Content-MD5", HDR_CONTENT_MD5, ftStr}, /* for now */
{"Content-Range", HDR_CONTENT_RANGE, ftPContRange},
{"Content-Type", HDR_CONTENT_TYPE, ftStr},
{"X-Cache", HDR_X_CACHE, ftStr},
{"X-Cache-Lookup", HDR_X_CACHE_LOOKUP, ftStr},
{"X-Forwarded-For", HDR_X_FORWARDED_FOR, ftStr},
+ {"X-Request-URI", HDR_X_REQUEST_URI, ftStr},
{"X-Squid-Error", HDR_X_SQUID_ERROR, ftStr},
{"Other:", HDR_OTHER, ftStr} /* ':' will not allow matches */
};
/* entity-headers */
static http_hdr_type EntityHeadersArr[] =
{
- HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
- HDR_CONTENT_RANGE, HDR_ETAG, HDR_EXPIRES, HDR_LAST_MODIFIED, HDR_LINK, HDR_OTHER
+ HDR_ALLOW, HDR_CONTENT_BASE, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE,
+ HDR_CONTENT_LENGTH, HDR_CONTENT_LOCATION, HDR_CONTENT_MD5,
+ HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_ETAG, HDR_EXPIRES, HDR_LAST_MODIFIED, HDR_LINK,
+ HDR_OTHER
};
static HttpHeaderMask ReplyHeadersMask; /* set run-time using ReplyHeaders */
{
HDR_ACCEPT, HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE,
HDR_ACCEPT_RANGES, HDR_AGE,
- HDR_CONTENT_MD5, HDR_CONTENT_TYPE,
HDR_LOCATION, HDR_MAX_FORWARDS,
HDR_MIME_VERSION, HDR_PUBLIC, HDR_RETRY_AFTER, HDR_SERVER, HDR_SET_COOKIE,
HDR_VARY,
HDR_WARNING, HDR_PROXY_CONNECTION, HDR_X_CACHE,
- HDR_X_CACHE_LOOKUP,
+ HDR_X_CACHE_LOOKUP,
+ HDR_X_REQUEST_URI,
HDR_X_SQUID_ERROR
};
/* header accounting */
static HttpHeaderStat HttpHeaderStats[] =
{
- {"reply"},
+ {"all"},
{"request"},
- {"all"}
+ {"reply"}
};
-static int HttpHeaderStatCount = sizeof(HttpHeaderStats) / sizeof(*HttpHeaderStats);
+static int HttpHeaderStatCount = countof(HttpHeaderStats);
/* global counters */
static int HeaderParsedCount = 0;
#define assert_eid(id) assert((id) >= 0 && (id) < HDR_ENUM_END)
-static int httpHeaderDelById(HttpHeader * hdr, http_hdr_type id);
-static void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos);
-
static HttpHeaderEntry *httpHeaderEntryCreate(http_hdr_type id, const char *name, const char *value);
static void httpHeaderEntryDestroy(HttpHeaderEntry * e);
static HttpHeaderEntry *httpHeaderEntryParseCreate(const char *field_start, const char *field_end);
int i;
/* check that we have enough space for masks */
assert(8 * sizeof(HttpHeaderMask) >= HDR_ENUM_END);
+ /* all headers must be described */
+ assert(countof(HeadersAttrs) == HDR_ENUM_END);
Headers = httpHeaderBuildFieldsInfo(HeadersAttrs, HDR_ENUM_END);
/* create masks */
httpHeaderMaskInit(&ListHeadersMask);
*/
void
-httpHeaderInit(HttpHeader * hdr)
+httpHeaderInit(HttpHeader * hdr, http_hdr_owner_type owner)
{
- assert(hdr);
- debug(55, 7) ("init-ing hdr: %p\n", hdr);
+ assert(hdr && (owner == hoRequest || owner == hoReply));
+ debug(55, 7) ("init-ing hdr: %p owner: %d\n", hdr, owner);
memset(hdr, 0, sizeof(*hdr));
+ hdr->owner = owner;
arrayInit(&hdr->entries);
}
HttpHeaderPos pos = HttpHeaderInitPos;
HttpHeaderEntry *e;
- debug(55, 7) ("cleaning hdr: %p\n", hdr);
- assert(hdr);
+ assert(hdr && (hdr->owner == hoRequest || hdr->owner == hoReply));
+ debug(55, 7) ("cleaning hdr: %p owner: %d\n", hdr, hdr->owner);
statHistCount(&HttpHeaderStats[0].hdrUCountDistr, hdr->entries.count);
+ statHistCount(&HttpHeaderStats[hdr->owner].hdrUCountDistr, hdr->entries.count);
HeaderDestroyedCount++;
NonEmptyHeaderDestroyedCount += hdr->entries.count > 0;
while ((e = httpHeaderGetEntry(hdr, &pos))) {
- /* fix this for req headers @?@ */
statHistCount(&HttpHeaderStats[0].fieldTypeDistr, e->id);
+ statHistCount(&HttpHeaderStats[hdr->owner].fieldTypeDistr, e->id);
/* tmp hack to avoid coredumps */
if (e->id < 0 || e->id >= HDR_ENUM_END)
debug(55, 0) ("httpHeaderClean BUG: entry[%d] is invalid (%d). Ignored.\n",
arrayClean(&hdr->entries);
}
+/* append entries (also see httpHeaderUpdate) */
+void
+httpHeaderAppend(HttpHeader * dest, const HttpHeader * src)
+{
+ const HttpHeaderEntry *e;
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ assert(src && dest);
+ assert(src != dest);
+ debug(55, 7) ("appending hdr: %p += %p\n", dest, src);
+
+ while ((e = httpHeaderGetEntry(src, &pos))) {
+ httpHeaderAddEntry(dest, httpHeaderEntryClone(e));
+ }
+}
+
/* use fresh entries to replace old ones */
void
-httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh)
+httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask *denied_mask)
{
- HttpHeaderEntry *e;
- HttpHeaderEntry *e_clone;
+ const HttpHeaderEntry *e;
HttpHeaderPos pos = HttpHeaderInitPos;
assert(old && fresh);
assert(old != fresh);
debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh);
while ((e = httpHeaderGetEntry(fresh, &pos))) {
+ /* deny bad guys (ok to check for HDR_OTHER) here */
+ if (denied_mask && CBIT_TEST(*denied_mask, e->id))
+ continue;
httpHeaderDelByName(old, strBuf(e->name));
- e_clone = httpHeaderEntryClone(e);
- httpHeaderAddEntry(old, e_clone);
+ httpHeaderAddEntry(old, httpHeaderEntryClone(e));
}
}
static int
httpHeaderReset(HttpHeader * hdr)
{
+ http_hdr_owner_type ho = hdr->owner;
+ assert(hdr);
+ ho = hdr->owner;
httpHeaderClean(hdr);
- httpHeaderInit(hdr);
+ httpHeaderInit(hdr, ho);
return 0;
}
return count;
}
-static int
+/* deletes all entries with a given id, returns the #entries deleted */
+int
httpHeaderDelById(HttpHeader * hdr, http_hdr_type id)
{
int count = 0;
HttpHeaderPos pos = HttpHeaderInitPos;
HttpHeaderEntry *e;
debug(55, 8) ("%p del-by-id %d\n", hdr, id);
+ assert(hdr);
+ assert_eid(id);
+ assert_eid(id != HDR_OTHER); /* does not make sense */
if (!CBIT_TEST(hdr->mask, id))
return 0;
while ((e = httpHeaderGetEntry(hdr, &pos))) {
* deletes an entry at pos and leaves a gap; leaving a gap makes it
* possible to iterate(search) and delete fields at the same time
*/
-static void
+void
httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos)
{
- httpHeaderEntryDestroy(hdr->entries.items[pos]);
+ HttpHeaderEntry *e;
+ assert(pos >= HttpHeaderInitPos && pos < hdr->entries.count);
+ e = hdr->entries.items[pos];
hdr->entries.items[pos] = NULL;
+ /* decrement header length, allow for ": " and crlf */
+ hdr->len -= strLen(e->name) + 2 + strLen(e->value) + 2;
+ assert(hdr->len >= 0);
+ httpHeaderEntryDestroy(e);
}
else
CBIT_SET(hdr->mask, e->id);
arrayAppend(&hdr->entries, e);
+ /* increment header length, allow for ": " and crlf */
+ hdr->len += strLen(e->name) + 2 + strLen(e->value) + 2;
}
/* return a list of entries with the same id separated by ',' and ws */
void
httpHeaderPutAuth(HttpHeader * hdr, const char *authScheme, const char *realm)
{
- MemBuf mb;
assert(hdr && authScheme && realm);
- memBufDefInit(&mb);
- memBufPrintf(&mb, "%s realm=\"%s\"", authScheme, realm);
- httpHeaderPutStr(hdr, HDR_WWW_AUTHENTICATE, mb.buf);
- memBufClean(&mb);
+ httpHeaderPutStrf(hdr, HDR_WWW_AUTHENTICATE, "%s realm=\"%s\"", authScheme, realm);
}
void
return NULL;
s = httpHeaderGetList(hdr, HDR_CACHE_CONTROL);
cc = httpHdrCcParseCreate(&s);
- /* fix this for req headers @?@ */
- if (cc)
+ if (cc) {
httpHdrCcUpdateStats(cc, &HttpHeaderStats[0].ccTypeDistr);
+ httpHdrCcUpdateStats(cc, &HttpHeaderStats[hdr->owner].ccTypeDistr);
+ }
httpHeaderNoteParsedEntry(HDR_CACHE_CONTROL, s, !cc);
stringClean(&s);
return cc;
http_hdr_type ht;
assert(e);
- /* fix this (including summing for totals) for req hdrs @?@ */
- for (i = 0; i < 1 /*HttpHeaderStatCount */ ; i++) {
+ for (i = 1; i < HttpHeaderStatCount; i++) {
httpHeaderStatDump(HttpHeaderStats + i, e);
storeAppendPrintf(e, "%s\n", "<br>");
}
- storeAppendPrintf(e, "%s\n", "<hr size=1 noshade>");
/* field stats */
storeAppendPrintf(e, "<h3>Http Fields Stats (replies and requests)</h3>\n");
storeAppendPrintf(e, "%2s\t %-20s\t %5s\t %6s\t %6s\n",
/*
- * $Id: HttpHeaderTools.cc,v 1.13 1998/05/22 23:43:53 wessels Exp $
+ * $Id: HttpHeaderTools.cc,v 1.14 1998/05/27 22:51:42 rousskov Exp $
*
* DEBUG: section 66 HTTP Header Tools
* AUTHOR: Alex Rousskov
#include "squid.h"
static int httpHeaderStrCmp(const char *h1, const char *h2, int len);
+static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs);
HttpHeaderFieldInfo *
return -1;
}
+/* same as httpHeaderPutStr, but formats the string using snprintf first */
+#ifdef __STDC__
+void
+httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+void
+httpHeaderPutStrf(va_alist)
+ va_dcl
+{
+ va_list args;
+ HttpHeader *hdr = NULL;
+ http_hdr_type id = HDR_ENUM_END;
+ const char *fmt = NULL;
+ va_start(args);
+ hdr = va_arg(args, HttpHeader *);
+ id = va_arg(args, http_hdr_type);
+ fmt = va_arg(args, char *);
+#endif
+ httpHeaderPutStrvf(hdr, id, fmt, args);
+ va_end(args);
+}
+
+/* used by httpHeaderPutStrf */
+static void
+httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs)
+{
+#if OLD_CODE
+ LOCAL_ARRAY(char, buf, 4096);
+ buf[0] = '\0';
+ vsnprintf(buf, 4096, fmt, vargs);
+ httpHeaderPutStr(hdr, id, buf);
+#else
+ MemBuf mb;
+ memBufDefInit(&mb);
+ memBufVPrintf(&mb, fmt, vargs);
+ httpHeaderPutStr(hdr, id, mb.buf);
+ memBufClean(&mb);
+#endif
+}
+
+
/*
* return true if a given directive is found in at least one of the "connection" header-fields
* note: if HDR_PROXY_CONNECTION is present we ignore HDR_CONNECTION
strListAdd(String * str, const char *item, char del)
{
assert(str && item);
- if (strLen(*str))
- stringAppend(str, &del, 1);
+ if (strLen(*str)) {
+ char buf[3] = { del, ' ', '\0' };
+ stringAppend(str, buf, 2);
+ }
stringAppend(str, item, strlen(item));
}
hstr_len -= 2;
else if (strstr(hstr, "\n\n"))
hstr_len -= 1;
- httpHeaderInit(&hdr);
+ httpHeaderInit(&hdr, hoReply);
/* debugLevels[55] = 8; */
parse_success = httpHeaderParse(&hdr, hstr, hstr + hstr_len);
/* debugLevels[55] = 2; */
--- /dev/null
+
+/*
+ * $Id: HttpMsg.cc,v 1.2 1998/05/27 22:51:43 rousskov Exp $
+ *
+ * DEBUG: section 74 HTTP Message
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "squid.h"
+
+
+/* find end of headers */
+int
+httpMsgIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end)
+{
+ /* adopted with mods from mime_headers_end() */
+ const char *p1 = strstr(*parse_start, "\n\r\n");
+ const char *p2 = strstr(*parse_start, "\n\n");
+ const char *end = NULL;
+
+ if (p1 && p2)
+ end = p1 < p2 ? p1 : p2;
+ else
+ end = p1 ? p1 : p2;
+
+ if (end) {
+ *blk_start = *parse_start;
+ *blk_end = end + 1;
+ *parse_start = end + (end == p1 ? 3 : 2);
+ return 1;
+ }
+ /* no headers, case 1 */
+ if ((*parse_start)[0] == '\r' && (*parse_start)[1] == '\n') {
+ *blk_start = *parse_start;
+ *blk_end = *blk_start;
+ *parse_start += 2;
+ return 1;
+ }
+ /* no headers, case 2 */
+ if ((*parse_start)[0] == '\n') {
+ /* no headers */
+ *blk_start = *parse_start;
+ *blk_end = *blk_start;
+ *parse_start += 1;
+ return 1;
+ }
+ /* failure */
+ return 0;
+}
+
+/* returns true if connection should be "persistent"
+ * after processing this message */
+int
+httpMsgIsPersistent(float http_ver, const HttpHeader * hdr)
+{
+ if (http_ver >= 1.1) {
+ /*
+ * for modern versions of HTTP: persistent unless there is
+ * a "Connection: close" header.
+ */
+ return !httpHeaderHasConnDir(hdr, "close");
+ } else {
+ /*
+ * Persistent connections in Netscape 3.x are allegedly broken,
+ * return false if it is a browser connection. If there is a
+ * VIA header, then we assume this is NOT a browser connection.
+ */
+ const char *agent = httpHeaderGetStr(hdr, HDR_USER_AGENT);
+ if (agent && !httpHeaderHas(hdr, HDR_VIA)) {
+ if (!strncasecmp(agent, "Mozilla/3.", 10))
+ return 0;
+ if (!strncasecmp(agent, "Netscape/3.", 11))
+ return 0;
+ }
+ /* for old versions of HTTP: persistent if has "keep-alive" */
+ return httpHeaderHasConnDir(hdr, "keep-alive");
+ }
+}
/*
- * $Id: HttpReply.cc,v 1.24 1998/05/22 23:43:54 wessels Exp $
+ * $Id: HttpReply.cc,v 1.25 1998/05/27 22:51:44 rousskov Exp $
*
* DEBUG: section 58 HTTP Reply (Response)
* AUTHOR: Alex Rousskov
/* local constants */
+/* these entity-headers must be ignored if a bogus server sends them in 304 */
+static HttpHeaderMask Denied304HeadersMask;
+static http_hdr_type Denied304HeadersArr[] =
+{
+ HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
+ HDR_CONTENT_LOCATION, HDR_CONTENT_RANGE, HDR_LAST_MODIFIED, HDR_LINK,
+ HDR_OTHER
+};
+
/* local routines */
+static void httpReplyInit(HttpReply * rep);
+static void httpReplyClean(HttpReply * rep);
static void httpReplyDoDestroy(HttpReply * rep);
static void httpReplyHdrCacheInit(HttpReply * rep);
static void httpReplyHdrCacheClean(HttpReply * rep);
static int httpReplyIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end);
+/* module initialization */
+void
+httpReplyInitModule()
+{
+ httpHeaderMaskInit(&Denied304HeadersMask);
+ httpHeaderCalcMask(&Denied304HeadersMask, (const int *) Denied304HeadersArr, countof(Denied304HeadersArr));
+}
+
+
HttpReply *
httpReplyCreate()
{
rep->hdr_sz = 0;
rep->pstate = psReadyToParseStartLine;
httpBodyInit(&rep->body);
- httpHeaderInit(&rep->header);
+ httpHeaderInit(&rep->header, hoReply);
httpReplyHdrCacheInit(rep);
httpStatusLineInit(&rep->sline);
}
httpReplyDoDestroy(new_rep);
}
-/* parses a buffer that may not be 0-terminated */
+/* parses a 4K buffer that may not be 0-terminated; returns true on success */
int
httpReplyParse(HttpReply * rep, const char *buf)
{
/*
* this extra buffer/copy will be eliminated when headers become meta-data
* in store. Currently we have to xstrncpy the buffer becuase store.c may
- * feed a non 0-terminated buffer to us @?@.
+ * feed a non 0-terminated buffer to us.
*/
char *headers = memAllocate(MEM_4K_BUF);
int success;
/* clean cache */
httpReplyHdrCacheClean(rep);
/* update raw headers */
- httpHeaderUpdate(&rep->header, &freshRep->header);
+ httpHeaderUpdate(&rep->header, &freshRep->header, &Denied304HeadersMask);
/* init cache */
httpReplyHdrCacheInit(rep);
}
*parse_start = *blk_end;
return 1;
}
-
-/* find end of headers */
-int
-httpMsgIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end)
-{
- /* adopted with mods from mime_headers_end() */
- const char *p1 = strstr(*parse_start, "\n\r\n");
- const char *p2 = strstr(*parse_start, "\n\n");
- const char *end = NULL;
-
- if (p1 && p2)
- end = p1 < p2 ? p1 : p2;
- else
- end = p1 ? p1 : p2;
-
- if (end) {
- *blk_start = *parse_start;
- *blk_end = end + 1;
- *parse_start = end + (end == p1 ? 3 : 2);
- return 1;
- }
- /* no headers, case 1 */
- if ((*parse_start)[0] == '\r' && (*parse_start)[1] == '\n') {
- *blk_start = *parse_start;
- *blk_end = *blk_start;
- *parse_start += 2;
- return 1;
- }
- /* no headers, case 2 */
- if ((*parse_start)[0] == '\n') {
- /* no headers */
- *blk_start = *parse_start;
- *blk_end = *blk_start;
- *parse_start += 1;
- return 1;
- }
- /* failure */
- return 0;
-}
-
-/*
- *returns true if connection should be "persistent" after processing
- this message
- */
-int
-httpMsgIsPersistent(float http_ver, const HttpHeader * hdr)
-{
- if (http_ver >= 1.1) {
- /*
- * for modern versions of HTTP: persistent unless there is
- * a "Connection: close" header.
- */
- return !httpHeaderHasConnDir(hdr, "close");
- } else {
- /*
- * Persistent connections in Netscape 3.x are allegedly broken,
- * return false if it is a browser connection. If there is a
- * VIA header, then we assume this is NOT a browser connection.
- */
- const char *agent = httpHeaderGetStr(hdr, HDR_USER_AGENT);
- if (agent && !httpHeaderHas(hdr, HDR_VIA)) {
- if (!strncasecmp(agent, "Mozilla/3.", 10))
- return 0;
- if (!strncasecmp(agent, "Netscape/3.", 11))
- return 0;
- }
- /* for old versions of HTTP: persistent if has "keep-alive" */
- return httpHeaderHasConnDir(hdr, "keep-alive");
- }
-}
/*
- * $Id: HttpRequest.cc,v 1.4 1998/05/22 23:43:56 wessels Exp $
+ * $Id: HttpRequest.cc,v 1.5 1998/05/27 22:51:45 rousskov Exp $
*
* DEBUG: section 73 HTTP Request
* AUTHOR: Duane Wessels
stringReset(&req->urlpath, urlpath);
req->max_age = -1;
req->max_forwards = -1;
+ httpHeaderInit(&req->header, hoRequest);
return req;
}
requestDestroy(request_t * req)
{
assert(req);
+#if OLD_CODE
safe_free(req->prefix);
+#endif
safe_free(req->body);
stringClean(&req->urlpath);
httpHeaderClean(&req->header);
return httpHeaderParse(&req->header, blk_start, blk_end);
}
+/* swaps out request-line and headers, appends <crlf> terminator */
void
-httpRequestSetHeaders(request_t * req, method_t method, const char *uri, const char *header_str)
+httpRequestSwapOut(const request_t *req, StoreEntry *e)
{
+ assert(req && e);
+ /* store request-line */
+ storeAppendPrintf(e, "%s %s HTTP/1.0\r\n",
+ RequestMethodStr[req->method], req->urlpath);
+ /* store headers */
+ {
+ Packer p;
+ packerToStoreInit(&p, e);
+ httpHeaderPackInto(&req->header, &p);
+ packerClean(&p);
+ }
+ /* trailer */
+ storeAppend(e, "\r\n", 2);
+}
+
+#if UNUSED_CODE
+void
+httpRequestSetHeaders(request_t *req, method_t method, const char *uri, const char *header_str)
+{
+#if OLD_CODE
MemBuf mb;
assert(req && uri && header_str);
assert(!req->prefix);
req->prefix = xstrdup(mb.buf);
req->prefix_sz = mb.size;
memBufClean(&mb);
+#else
+ assert(req && uri && header_str);
+ assert(!req->header.len);
+#endif
httpHeaderParse(&req->header, header_str, header_str + strlen(header_str));
}
+#endif
+
+/* returns the length of request line + headers + crlf */
+int
+httpRequestPrefixLen(const request_t *req)
+{
+ assert(req);
+ return strlen(RequestMethodStr[req->method]) + 1 +
+ strLen(req->urlpath) + 1 +
+ 4+1+3 + 2 +
+ req->header.len + 2;
+}
/* returns true if header is allowed to be passed on */
int
#
# Makefile for the Squid Object Cache server
#
-# $Id: Makefile.in,v 1.149 1998/05/11 18:44:29 rousskov Exp $
+# $Id: Makefile.in,v 1.150 1998/05/27 22:51:46 rousskov Exp $
#
# Uncomment and customize the following to suit your needs:
#
HttpHeader.o \
HttpHeaderTools.o \
HttpBody.o \
+ HttpMsg.o \
HttpReply.o \
HttpRequest.o \
icmp.o \
/*
- * $Id: MemBuf.cc,v 1.9 1998/05/22 23:43:57 wessels Exp $
+ * $Id: MemBuf.cc,v 1.10 1998/05/27 22:51:47 rousskov Exp $
*
* DEBUG: section 59 auto-growing Memory Buffer with printf
* AUTHOR: Alex Rousskov
*/
/*
- * To-Do: uses memory pools for .buf recycling @?@ @?@
+ * To-Do: use memory pools for .buf recycling @?@ @?@
*/
/*
* ...
*
* -- write
- * comm_write(buf.buf, memBufFreeFunc(&buf), ...);
- *
+ * comm_write_mbuf(fd, buf, handler, data);
+ *
* -- *iff* you did not give the buffer away, free it yourself
* -- memBufClean(&buf);
* }
assert(mb->buf);
assert(mb->freefunc); /* not frozen */
- (*mb->freefunc) (mb->buf); /* freeze */
+ (*mb->freefunc) (mb->buf); /* free */
+ mb->freefunc = NULL; /* freeze */
mb->buf = NULL;
mb->size = mb->capacity = 0;
}
assert(mb->buf);
assert(mb->freefunc); /* not frozen */
/* @?@ we do not init buf with '\0', do we have to for vsnprintf?? @?@ */
- /* assert in Grow should quit first, but we do not want to have a scare (1) loop */
+ /* assert in Grow should quit first, but we do not want to have a scary infinite loop */
while (mb->capacity <= mb->max_capacity) {
mb_size_t free_space = mb->capacity - mb->size;
/* put as much as we can */
else
break;
}
- mb->size += sz - 1; /* note that we cut 0-terminator as store does @?@ @?@ */
+ assert(sz > 0);
+ mb->size += sz - 1; /* note that we cut 0-terminator as store does */
}
/*
/*
- * $Id: access_log.cc,v 1.30 1998/05/24 03:47:19 wessels Exp $
+ * $Id: access_log.cc,v 1.31 1998/05/27 22:51:47 rousskov Exp $
*
* DEBUG: section 46 Access Log
* AUTHOR: Duane Wessels
if (!al->http.content_type || *al->http.content_type == '\0')
al->http.content_type = dash_str;
if (!al->cache.ident || *al->cache.ident == '\0') {
+ /* argh, binary headers did not come through */
t = mime_get_header(al->headers.request, "Proxy-authorization:");
if (t == NULL) {
al->cache.ident = dash_str;
/*
- * $Id: asn.cc,v 1.36 1998/05/11 18:44:32 rousskov Exp $
+ * $Id: asn.cc,v 1.37 1998/05/27 22:51:48 rousskov Exp $
*
* DEBUG: section 53 AS Number handling
* AUTHOR: Duane Wessels, Kostas Anagnostakis
#if OLD_CODE
asState->request->headers = xstrdup("\r\n");
asState->request->headers_sz = strlen(asState->request->headers);
-#else
- httpRequestSetHeaders(asState->request, METHOD_GET, asres, "");
#endif
if ((e = storeGet(k)) == NULL) {
e = storeCreateEntry(asres, asres, 0, METHOD_GET);
/*
- * $Id: client_side.cc,v 1.316 1998/05/27 20:31:33 wessels Exp $
+ * $Id: client_side.cc,v 1.317 1998/05/27 22:51:49 rousskov Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
static void CheckQuickAbort(clientHttpRequest *);
static void checkFailureRatio(err_type, hier_code);
static void clientProcessMiss(clientHttpRequest *);
-static void clientAppendReplyHeader(char *, const char *, size_t *, size_t);
-size_t clientBuildReplyHeader(clientHttpRequest *, char *, size_t, size_t *, char *, size_t);
+static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply *rep);
static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *);
static RH clientRedirectDone;
new_request->headers = xstrdup(old_request->headers);
new_request->headers_sz = old_request->headers_sz;
#else
- new_request->prefix = xstrdup(old_request->prefix);
- new_request->prefix_sz = old_request->prefix_sz;
- httpHeaderUpdate(&new_request->header, &old_request->header);
+ httpHeaderAppend(&new_request->header, &old_request->header);
#endif
new_request->client_addr = old_request->client_addr;
EBIT_SET(new_request->flags, REQ_REDIRECTED);
return 1;
}
+#if UNUSED_CODE
static void
updateCDJunkStats()
{
/* rewrite */
}
+#endif
void
clientUpdateCounters(clientHttpRequest * http)
http->al.cache.msec = tvSubMsec(http->start, current_time);
http->al.cache.ident = conn->ident.ident;
if (request) {
+ Packer p;
+ MemBuf mb;
+ memBufDefInit(&mb);
+ packerToMemInit(&p, &mb);
+ httpHeaderPackInto(&request->header, &p);
http->al.http.method = request->method;
- http->al.headers.request = request->prefix;
+ http->al.headers.request = xstrdup(mb.buf);
http->al.hier = request->hier;
+ packerClean(&p);
+ memBufClean(&mb);
}
accessLogLog(&http->al);
clientUpdateCounters(http);
checkFailureRatio(request->err_type, http->al.hier.code);
safe_free(http->uri);
safe_free(http->log_uri);
+ safe_free(http->al.headers.request);
safe_free(http->al.headers.reply);
if (entry) {
http->entry = NULL;
return 0;
}
+#if OLD_CODE
static void
clientAppendReplyHeader(char *hdr, const char *line, size_t * sz, size_t max)
{
strcat(hdr + (*sz), crlf);
*sz = n;
}
+#endif
-/* this entire function has to be rewriten using new interfaces @?@ @?@ */
-size_t
+#if OLD_CODE /* use new interfaces instead */
+static size_t
clientBuildReplyHeader(clientHttpRequest * http,
char *hdr_in,
size_t hdr_in_sz,
memFree(MEM_4K_BUF, ybuf);
return len;
}
+#endif
+
+static void
+clientBuildReplyHeader(clientHttpRequest * http, HttpReply *rep)
+{
+ HttpHeader *hdr = &rep->header;
+ int is_hit = isTcpHit(http->log_type);
+#if DONT_FILTER_THESE
+ /* but you might want to if you run Squid as an HTTP accelerator */
+ httpHeaderDelById(hdr, HDR_ACCEPT_RANGES);
+ httpHeaderDelById(hdr, HDR_ETAG);
+#endif
+ httpHeaderDelById(hdr, HDR_PROXY_CONNECTION);
+ /* here: Keep-Alive is a field-name, not a connection directive! */
+ httpHeaderDelByName(hdr, "Keep-Alive");
+ /* remove Set-Cookie if a hit */
+ if (is_hit)
+ httpHeaderDelById(hdr, HDR_SET_COOKIE);
+ /* handle Connection header */
+ if (httpHeaderHas(hdr, HDR_CONNECTION)) {
+ /* anything that matches Connection list member will be deleted */
+ String strConnection = httpHeaderGetList(hdr, HDR_CONNECTION);
+ const HttpHeaderEntry *e;
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ while ((e = httpHeaderGetEntry(hdr, &pos))) {
+ if (strListIsMember(&strConnection, strBuf(e->name), ','))
+ httpHeaderDelAt(hdr, pos);
+ }
+ httpHeaderDelById(hdr, HDR_CONNECTION);
+ stringClean(&strConnection);
+ }
+ /* Append X-Cache */
+ httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
+ is_hit ? "HIT" : "MISS", getMyHostname());
+#if USE_CACHE_DIGESTS
+ /* Append X-Cache-Lookup: -- temporary hack, to be removed @?@ @?@ */
+ httpHeaderPutStrf(hdr, HDR_X_CACHE_LOOKUP, "%s from %s:%d",
+ http->lookup_type ? http->lookup_type : "NONE",
+ getMyHostname(), Config.Port.http->i);
+#endif
+ /* Only replies with valid Content-Length can be sent with keep-alive */
+ if (http->request->method != METHOD_HEAD &&
+ http->entry->mem_obj->reply->content_length < 0)
+ EBIT_CLR(http->request->flags, REQ_PROXY_KEEPALIVE);
+ /* Signal keep-alive if needed */
+ if (EBIT_TEST(http->request->flags, REQ_PROXY_KEEPALIVE))
+ httpHeaderPutStr(hdr,
+ http->flags.accel ? HDR_CONNECTION : HDR_PROXY_CONNECTION,
+ "keep-alive");
+#if ADD_X_REQUEST_URI
+ /*
+ * Knowing the URI of the request is useful when debugging persistent
+ * connections in a client; we cannot guarantee the order of http headers,
+ * but X-Request-URI is likely to be the very last header to ease use from a
+ * debugger [hdr->entries.count-1].
+ */
+ httpHeaderPutStr(hdr, HDR_X_REQUEST_URI,
+ http->entry->mem_obj->url ? http->entry->mem_obj->url : http->uri);
+#endif
+}
+
+static HttpReply*
+clientBuildReply(clientHttpRequest * http, const char *buf, size_t size)
+{
+ HttpReply *rep = httpReplyCreate();
+ assert(size <= 4096); /* httpReplyParse depends on this */
+ if (httpReplyParse(rep, buf)) {
+ /* enforce 1.0 reply version */
+ rep->sline.version = 1.0;
+ /* do header conversions */
+ clientBuildReplyHeader(http, rep);
+ } else {
+ /* parsing failure, get rid of the invalid reply */
+ httpReplyDestroy(rep);
+ rep = NULL;
+ }
+ return rep;
+}
static void
clientCacheHit(void *data, char *buf, ssize_t size)
}
}
+/*
+ * accepts chunk of a http message in buf, parses prefix, filters headers and
+ * such, writes processed message to the client's socket
+ */
static void
clientSendMoreData(void *data, char *buf, ssize_t size)
{
StoreEntry *entry = http->entry;
ConnStateData *conn = http->conn;
int fd = conn->fd;
+#if OLD_CODE
size_t hdrlen;
size_t l = 0;
size_t writelen;
char *newbuf;
FREE *freefunc = memFree4K;
+#else
+ HttpReply *rep = NULL;
+ FREE *freefunc = memFree4K;
+ const char *body_buf = buf;
+ ssize_t body_size = size;
+#endif
debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size);
assert(size <= SM_PAGE_SIZE);
assert(http->request != NULL);
freefunc(buf);
return;
}
+#if OLD_CODE
writelen = size;
+#endif
if (http->out.offset == 0) {
if (Config.onoff.log_mime_hdrs) {
size_t k;
xstrncpy(http->al.headers.reply, buf, k);
}
}
+#if OLD_CODE
newbuf = memAllocate(MEM_8K_BUF);
hdrlen = 0;
l = clientBuildReplyHeader(http, buf, size, &hdrlen, newbuf, 8192);
buf = newbuf;
freefunc = memFree8K;
newbuf = NULL;
+#else
+ rep = clientBuildReply(http, buf, size);
+ if (rep) {
+ body_size = size - rep->hdr_sz;
+ assert(body_size >= 0);
+ body_buf = buf + rep->hdr_sz;
+ debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n",
+ body_size, rep->hdr_sz);
+#endif
} else {
+#if OLD_CODE
memFree(MEM_8K_BUF, newbuf);
newbuf = NULL;
+#endif
if (size < SM_PAGE_SIZE && entry->store_status == STORE_PENDING) {
/* wait for more to arrive */
storeClientCopy(entry,
* ick, this is gross
*/
if (http->request->method == METHOD_HEAD) {
- size_t k;
- if ((k = headersEnd(buf, size))) {
- writelen = k;
+ size_t k = 0;
+ if (rep)
+ body_size = 0; /* do not forward body for HEAD replies */
+ else
+ k = body_size = headersEnd(buf, size); /* unparseable reply, stop and end-of-headers */
+ if (rep || k) {
/* force end */
if (entry->store_status == STORE_PENDING)
http->out.offset = entry->mem_obj->inmem_hi;
http->out.offset = objectLen(entry);
}
}
+#if OLD_CODE
comm_write(fd, buf, writelen, clientWriteComplete, http, freefunc);
+#else
+ if (rep || (body_buf && body_size)) {
+ MemBuf mb;
+ /* init mb; put status line and headers if any */
+ if (rep) {
+ mb = httpReplyPack(rep);
+ httpReplyDestroy(rep);
+ rep = NULL;
+ } else {
+ memBufInit(&mb, body_size, body_size);
+ }
+ /* append body if any */
+ if (body_buf && body_size)
+ memBufAppend(&mb, body_buf, body_size);
+ /* write */
+ comm_write_mbuf(fd, mb, clientWriteComplete, http);
+ }
+ /* if we don't do it, who will? */
+ freefunc(buf);
+#endif
}
static
storeBuffer(http->entry);
rep = httpReplyCreate();
httpReplySetHeaders(rep, 1.0, HTTP_OK, NULL, "text/plain",
- r->prefix_sz, 0, squid_curtime);
+ httpRequestPrefixLen(r), 0, squid_curtime);
httpReplySwapOut(rep, http->entry);
httpReplyDestroy(rep);
+#if OLD_CODE
storeAppend(http->entry, r->prefix, r->prefix_sz);
+#else
+ httpRequestSwapOut(r, http->entry);
+#endif
storeComplete(http->entry);
return;
}
ErrorState *err = NULL;
debug(33, 4) ("clientProcessMiss: '%s %s'\n",
RequestMethodStr[r->method], url);
+#if OLD_CODE
debug(33, 10) ("clientProcessMiss: prefix:\n%s\n", r->prefix);
+#endif
/*
* We might have a left-over StoreEntry from a failed cache hit
* or IMS request.
http->log_uri = xstrdup(urlCanonicalClean(request));
request->client_addr = conn->peer.sin_addr;
request->http_ver = http->http_ver;
+#if OLD_CODE
request->prefix = prefix;
request->prefix_sz = http->req_sz;
+#endif
if (!urlCheckRequest(request)) {
err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
err->src_addr = conn->peer.sin_addr;
fatal("Cannot open HTTP Port");
}
-int
+#if OLD_CODE
+static int
handleConnectionHeader(int flag, char *where, char *what)
{
char *t, *p, *wh;
xfree(wh);
return 1;
}
+#endif
void
clientHttpConnectionsClose(void)
HDR_AUTHORIZATION,
HDR_CACHE_CONTROL,
HDR_CONNECTION,
+ HDR_CONTENT_BASE,
HDR_CONTENT_ENCODING,
HDR_CONTENT_LANGUAGE,
HDR_CONTENT_LENGTH,
+ HDR_CONTENT_LOCATION,
HDR_CONTENT_MD5,
HDR_CONTENT_RANGE,
HDR_CONTENT_TYPE,
HDR_X_CACHE,
HDR_X_CACHE_LOOKUP, /* tmp hack, remove later */
HDR_X_FORWARDED_FOR,
+ HDR_X_REQUEST_URI, /* appended if ADD_X_REQUEST_URI is #defined */
HDR_X_SQUID_ERROR,
HDR_OTHER,
HDR_ENUM_END
ftPContRange
} field_type;
+/* possible owners of http header */
+typedef enum {
+ hoNone,
+ hoRequest,
+ hoReply
+} http_hdr_owner_type;
+
typedef enum {
HIER_NONE,
DIRECT,
REQ_PROXYING,
REQ_REFRESH,
REQ_USED_PROXY_AUTH,
- REQ_CC_ONLY_IF_CACHED,
REQ_REDIRECTED
};
/*
- * $Id: errorpage.cc,v 1.133 1998/05/26 23:56:20 wessels Exp $
+ * $Id: errorpage.cc,v 1.134 1998/05/27 22:51:52 rousskov Exp $
*
* DEBUG: section 4 Error Generation
* AUTHOR: Duane Wessels
HttpReply *
errorBuildReply(ErrorState * err)
{
- char err_hdr[CVT_BUF_SZ];
HttpReply *rep = httpReplyCreate();
MemBuf content = errorBuildContent(err);
/* no LMT for error pages; error pages expire immediately */
httpReplySetHeaders(rep, 1.0, err->http_status, NULL, "text/html", content.size, 0, squid_curtime);
/*
* include some information for downstream caches. Implicit
- * replaceable content This isn't quite sufficient. xerrno is not
+ * replaceable content. This isn't quite sufficient. xerrno is not
* necessarily meaningful to another system, so we really should
* expand it. Additionally, we should identify ourselves. Someone
* might want to know. Someone _will_ want to know OTOH, the first
* X-CACHE-MISS entry should tell us who.
*/
- snprintf(err_hdr, CVT_BUF_SZ, "%s %d",
+ httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%s %d",
err_type_str[err->page_id], err->xerrno);
- httpHeaderPutStr(&rep->header, HDR_X_SQUID_ERROR, err_hdr);
httpBodySet(&rep->body, content.buf, content.size + 1, NULL);
memBufClean(&content);
return rep;
/*
- * $Id: http.cc,v 1.275 1998/05/26 23:04:13 wessels Exp $
+ * $Id: http.cc,v 1.276 1998/05/27 22:51:53 rousskov Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
httpState->reply_hdr);
/* Parse headers into reply structure */
- /* Old code never parsed headers if headersEnd failed, was it intentional ? @?@ @?@ */
- /* what happens if we fail to parse here? @?@ @?@ */
+ /* what happens if we fail to parse here? */
httpReplyParse(reply, httpState->reply_hdr); /* httpState->eof); */
storeTimestampsSet(entry);
/* Check if object is cacheable or not based on reply code */
const HttpHeaderEntry *e;
HttpHeaderPos pos = HttpHeaderInitPos;
+#if OLD_CODE
assert(orig_request->prefix != NULL);
debug(11, 3) ("httpBuildRequestHeader:\n%s", orig_request->prefix);
- httpHeaderInit(hdr_out);
-
+#endif
+ httpHeaderInit(hdr_out, hoRequest);
+
/* append our IMS header */
if (entry && entry->lastmod > -1 && request->method == METHOD_GET)
httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, entry->lastmod);
if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
} else {
- snprintf(bbuf, BBUF_SZ, "%s:%d",
+ httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
orig_request->host, (int) orig_request->port);
- httpHeaderPutStr(hdr_out, HDR_HOST, bbuf);
}
}
/* append Cache-Control, add max-age if not there already */
/*
- * $Id: main.cc,v 1.251 1998/05/15 15:16:25 wessels Exp $
+ * $Id: main.cc,v 1.252 1998/05/27 22:51:54 rousskov Exp $
*
* DEBUG: section 1 Startup and Main Loop
* AUTHOR: Harvest Derived
useragentOpenLog();
httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
httpAnonInitModule(); /* must go before accepting requests */
+ httpReplyInitModule(); /* must go before accepting replies */
errorInitialize();
accessLogInit();
#ifdef SQUID_SNMP
/*
- * $Id: mime.cc,v 1.65 1998/05/08 23:29:28 wessels Exp $
+ * $Id: mime.cc,v 1.66 1998/05/27 22:51:55 rousskov Exp $
*
* DEBUG: section 25 MIME Parsing
* AUTHOR: Harvest Derived
return 0;
}
+#if UNUSED_CODE
/*
* mk_mime_hdr - Generates a MIME header using the given parameters.
* You can call mk_mime_hdr with a 'lmt = time(NULL) - ttl' to
if (size > 0)
snprintf(content_length, 100, "Content-Length: %d\r\n", size);
- /* NOTE: don't know size of result thus didn't change
- * to snprintf(). Should be done sometime! */
-
snprintf(result, MAX_MIME, "Server: %s/%s\r\n%s%s%sContent-Type: %s\r\n%s",
appname,
version_string,
content_length);
return 0;
}
-
+#endif
const char *
mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field)
/*
- * $Id: net_db.cc,v 1.110 1998/05/26 19:12:21 wessels Exp $
+ * $Id: net_db.cc,v 1.111 1998/05/27 22:51:56 rousskov Exp $
*
* DEBUG: section 37 Network Measurement Database
* AUTHOR: Duane Wessels
#if OLD_CODE
ex->r->headers = xstrdup("\r\n");
ex->r->headers_sz = strlen(ex->r->headers);
-#else
- httpRequestSetHeaders(ex->r, METHOD_GET, uri, "");
#endif
ex->r->http_ver = 1.0;
ex->e = storeCreateEntry(uri, uri, 0, METHOD_GET);
/*
- * $Id: peer_digest.cc,v 1.32 1998/05/26 23:45:32 rousskov Exp $
+ * $Id: peer_digest.cc,v 1.33 1998/05/27 22:51:57 rousskov Exp $
*
* DEBUG: section 72 Peer Digest Routines
* AUTHOR: Alex Rousskov
requestLink(req);
assert(req);
/* add custom headers */
+#if OLD_CODE
/* rewrite this when requests get rid of "prefix" */
assert(!req->prefix);
{
httpRequestSetHeaders(req, METHOD_GET, url, mb.buf);
memBufClean(&mb);
}
+#else
+ assert(!req->header.len);
+ {
+ HttpHdrCc *cc = httpHdrCcCreate();
+ EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
+ httpHeaderPutStr(&req->header, HDR_ACCEPT, StoreDigestMimeStr);
+ httpHeaderPutStr(&req->header, HDR_ACCEPT, "text/html");
+ httpHeaderPutCc(&req->header, cc);
+ httpHdrCcDestroy(cc);
+ }
+#endif
/* create fetch state structure */
fetch = memAllocate(MEM_DIGEST_FETCH_STATE);
cbdataAdd(fetch, MEM_DIGEST_FETCH_STATE);
}
/* free state structures, disables digest on error */
-/* this probably should mimic httpRequestFree() but it does not! @?@ @?@ */
static void
peerDigestFetchFinish(DigestFetchState * fetch, char *buf, const char *err_msg)
{
const time_t expires = fetch->entry->expires;
const time_t fetch_resp_time = squid_curtime - fetch->start_time;
const int b_read = (fetch->entry->store_status == STORE_PENDING) ?
- mem->inmem_hi : mem->object_sz;
+ mem->inmem_hi : mem->object_sz;
+ const int req_len = req ? httpRequestPrefixLen(req) : 0;
assert(req);
/* final checks */
if (!err_msg) {
}
/* update global stats */
/* note: outgoing numbers are not precise! @?@ */
- kb_incr(&Counter.cd.kbytes_sent, req->prefix_sz);
+ kb_incr(&Counter.cd.kbytes_sent, req_len);
kb_incr(&Counter.cd.kbytes_recv, (size_t) b_read);
Counter.cd.msgs_sent++;
Counter.cd.msgs_recv++;
/* update peer stats */
- kb_incr(&peer->digest.stats.kbytes_sent, req->prefix_sz);
+ kb_incr(&peer->digest.stats.kbytes_sent, req_len);
kb_incr(&peer->digest.stats.kbytes_recv, (size_t) b_read);
peer->digest.stats.msgs_sent++;
peer->digest.stats.msgs_recv++;
extern void clientHttpConnectionsClose(void);
extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, int);
extern int isTcpHit(log_type);
-extern int handleConnectionHeader(int flag, char *where, char *what);
extern int commSetNonBlocking(int fd);
extern void commSetCloseOnExec(int fd);
extern const char *getStringPrefix(const char *str, const char *end);
extern int httpHeaderParseInt(const char *start, int *val);
extern int httpHeaderParseSize(const char *start, size_t * sz);
+#ifdef __STDC__
+extern void httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt, ...);
+#else
+extern void httpHeaderPutStrf()
+#endif
/* Http Header */
extern void httpHeaderInitModule();
extern void httpHeaderCleanModule();
/* init/clean */
-extern void httpHeaderInit(HttpHeader * hdr);
+extern void httpHeaderInit(HttpHeader * hdr, http_hdr_owner_type owner);
extern void httpHeaderClean(HttpHeader * hdr);
-/* update */
-extern void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh);
+/* append/update */
+extern void httpHeaderAppend(HttpHeader * dest, const HttpHeader * src);
+extern void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask *denied_mask);
/* parse/pack */
extern int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end);
extern void httpHeaderPackInto(const HttpHeader * hdr, Packer * p);
extern const char *httpHeaderGetAuth(const HttpHeader * hdr, http_hdr_type id, const char *authScheme);
extern String httpHeaderGetList(const HttpHeader * hdr, http_hdr_type id);
extern int httpHeaderDelByName(HttpHeader * hdr, const char *name);
+extern int httpHeaderDelById(HttpHeader * hdr, http_hdr_type id);
+extern void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos);
/* avoid using these low level routines */
extern HttpHeaderEntry *httpHeaderGetEntry(const HttpHeader * hdr, HttpHeaderPos * pos);
extern HttpHeaderEntry *httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id);
extern int httpMsgIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end);
/* Http Reply */
+extern void httpReplyInitModule();
+/* create/destroy */
extern HttpReply *httpReplyCreate();
-extern void httpReplyInit(HttpReply * rep);
-extern void httpReplyClean(HttpReply * rep);
extern void httpReplyDestroy(HttpReply * rep);
/* reset: clean, then init */
extern void httpReplyReset(HttpReply * rep);
extern request_t *requestLink(request_t *);
extern void requestUnlink(request_t *);
extern int httpRequestParseHeader(request_t * req, const char *parse_start);
-extern void httpRequestSetHeaders(request_t *, method_t, const char *uri, const char *header_str);
+extern void httpRequestSwapOut(const request_t *req, StoreEntry *e);
+extern int httpRequestPrefixLen(const request_t *req);
extern int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
extern void icmpOpen(void);
extern char *mime_headers_end(const char *mime);
#endif
extern size_t headersEnd(const char *, size_t);
-extern int mk_mime_hdr(char *result, const char *type, int size, time_t ttl, time_t lmt);
extern const char *mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field);
extern void mimeInit(char *filename);
/*
- * $Id: store.cc,v 1.420 1998/05/27 16:15:24 wessels Exp $
+ * $Id: store.cc,v 1.421 1998/05/27 22:52:00 rousskov Exp $
*
* DEBUG: section 20 Storage Manager
* AUTHOR: Harvest Derived
storeTimestampsSet(StoreEntry * entry)
{
time_t served_date = -1;
- HttpReply *reply = entry->mem_obj->reply;
+ const HttpReply *reply = entry->mem_obj->reply;
served_date = reply->date;
if (served_date < 0)
served_date = squid_curtime;
*/
struct _HttpBody {
/* private, never dereference these */
- char *buf; /* null terminating _text_ buffer, not for binary stuff */
+ char *buf; /* null terminated _text_ buffer, not for binary stuff */
FREE *freefunc; /* used to free() .buf */
int size;
};
/* protected, do not use these, use interface functions instead */
Array entries; /* parsed fields in raw format */
HttpHeaderMask mask; /* bit set <=> entry present */
+ http_hdr_owner_type owner; /* request or reply */
+ int len; /* length when packed, not counting terminating '\0' */
};
struct _HttpReply {
off_t offset;
size_t size;
} out;
- size_t req_sz;
+ size_t req_sz; /* raw request size on input, not current request size */
StoreEntry *entry;
StoreEntry *old_entry;
log_type log_type;
char *headers;
size_t headers_sz;
#else
-#if TEST_STAGE_CODE
- const char *prefix;
- const size_t prefix_sz;
- const HttpHeader header;
-#else
- char *prefix;
- size_t prefix_sz;
HttpHeader header;
-#endif
#endif
char *body;
size_t body_sz;
typedef void AIOCB(void *, int aio_return, int aio_errno);
typedef void CWCB(int fd, char *, size_t size, int flag, void *data);
typedef void CNCB(int fd, int status, void *);
+
typedef void FREE(void *);
typedef void FOCB(void *, int fd, int errcode);
typedef void EVH(void *);
/*
*
- * $Id: urn.cc,v 1.33 1998/05/11 18:44:48 rousskov Exp $
+ * $Id: urn.cc,v 1.34 1998/05/27 22:52:03 rousskov Exp $
*
* DEBUG: section 52 URN Parsing
* AUTHOR: Kostas Anagnostakis
urlres_r->headers = xstrdup("Accept: text/plain\r\n\r\n");
urlres_r->headers_sz = strlen(urlres_r->headers);
#else
- httpRequestSetHeaders(urlres_r, METHOD_GET, urlres, "Accept: text/plain\r\n");
+ httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain");
#endif
if ((urlres_e = storeGet(k)) == NULL) {
urlres_e = storeCreateEntry(urlres, urlres, 0, METHOD_GET);
/*
- * $Id: wais.cc,v 1.107 1998/05/11 18:44:48 rousskov Exp $
+ * $Id: wais.cc,v 1.108 1998/05/27 22:52:04 rousskov Exp $
*
* DEBUG: section 24 WAIS Relay
* AUTHOR: Harvest Derived
method_t method;
char *relayhost;
int relayport;
- char *request_hdr;
+ const HttpHeader *request_hdr;
char request[MAX_URL];
} WaisStateData;
waisSendRequest(int fd, void *data)
{
WaisStateData *waisState = data;
+#if OLD_CODE
int len = strlen(waisState->request) + 4;
char *buf = NULL;
+#else
+ MemBuf mb;
+#endif
const char *Method = RequestMethodStr[waisState->method];
debug(24, 5) ("waisSendRequest: FD %d\n", fd);
+#if OLD_CODE
if (Method)
len += strlen(Method);
if (waisState->request_hdr)
snprintf(buf, len + 1, "%s %s\r\n", Method, waisState->request);
debug(24, 6) ("waisSendRequest: buf: %s\n", buf);
comm_write(fd, buf, len, waisSendComplete, waisState, xfree);
+#else
+ memBufPrintf(&mb, "%s %s", Method, waisState->request);
+ if (waisState->request_hdr) {
+ Packer p;
+ packerToMemInit(&p, &mb);
+ httpHeaderPackInto(waisState->request_hdr, &p);
+ packerClean(&p);
+ }
+ memBufPrintf(&mb, "\r\n");
+ debug(24, 6) ("waisSendRequest: buf: %s\n", mb.buf);
+ comm_write_mbuf(fd, mb, waisSendComplete, waisState);
+#endif
if (EBIT_TEST(waisState->entry->flag, ENTRY_CACHABLE))
storeSetPublicKey(waisState->entry); /* Make it public */
}
waisState->method = method;
waisState->relayhost = Config.Wais.relayHost;
waisState->relayport = Config.Wais.relayPort;
- waisState->request_hdr = request->prefix;
+ waisState->request_hdr = &request->header;
waisState->fd = fd;
waisState->entry = entry;
xstrncpy(waisState->request, url, MAX_URL);