summaryrefslogtreecommitdiff
path: root/src/cache.c
diff options
context:
space:
mode:
authorjcid <devnull@localhost>2007-11-28 15:09:07 +0100
committerjcid <devnull@localhost>2007-11-28 15:09:07 +0100
commitba08ee0b4e87d71aae5c96aff1bd89e5c1dd6827 (patch)
tree20b43f3a6620db27b1a1efd7ae346b718eb93022 /src/cache.c
parentb0358c3dea7a0f34dc494d82be08ae814a480a50 (diff)
Added HTTP-1.1's chunked transfer support!
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c82
1 files changed, 64 insertions, 18 deletions
diff --git a/src/cache.c b/src/cache.c
index 448ce3db..35bbf41e 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -58,7 +58,8 @@ typedef struct {
Dstr *Header; /* HTTP header */
const DilloUrl *Location; /* New URI for redirects */
Dstr *Data; /* Pointer to raw data */
- Decode *Decoder; /* Data decoder */
+ Decode *TransferDecoder; /* Transfer decoder (e.g., chunked) */
+ Decode *ContentDecoder; /* Data decoder (e.g., gzip) */
int ExpectedSize; /* Goal size of the HTTP transfer (0 if unknown)*/
int TransferSize; /* Actual length of the HTTP transfer */
uint_t Flags; /* Look Flag Defines in cache.h */
@@ -205,7 +206,8 @@ static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url)
NewEntry->Header = dStr_new("");
NewEntry->Location = NULL;
NewEntry->Data = dStr_sized_new(8*1024);
- NewEntry->Decoder = NULL;
+ NewEntry->TransferDecoder = NULL;
+ NewEntry->ContentDecoder = NULL;
NewEntry->ExpectedSize = 0;
NewEntry->TransferSize = 0;
NewEntry->Flags = 0;
@@ -469,6 +471,14 @@ static void Cache_parse_header(CacheEntry_t *entry,
#endif
if (HdrLen > 12) {
+ if (header[9] == '1' && header[10] == '0' && header[11] == '0') {
+ /* 100: Continue. The "real" header has not come yet. */
+ MSG("An actual 100 Continue header!\n");
+ entry->Flags &= ~CA_GotHeader;
+ dStr_free(entry->Header, 1);
+ entry->Header = dStr_new("");
+ return;
+ }
if (header[9] == '3' && header[10] == '0') {
/* 30x: URL redirection */
entry->Flags |= CA_Redirect;
@@ -487,8 +497,19 @@ static void Cache_parse_header(CacheEntry_t *entry,
}
if ((Length = Cache_parse_field(header, "Content-Length")) != NULL) {
- entry->Flags |= CA_GotLength;
- entry->ExpectedSize = MAX(strtol(Length, NULL, 10), 0);
+ char *tmp;
+ if ((tmp = Cache_parse_field(header, "Transfer-Encoding"))) {
+ /*
+ * BUG: Should test for _presence_ of headers, not whether they
+ * have content.
+ */
+ MSG_HTTP("Both Content-Length and Transfer-Encoding headers"
+ " received.\n");
+ dFree(tmp);
+ } else {
+ entry->Flags |= CA_GotLength;
+ entry->ExpectedSize = MAX(strtol(Length, NULL, 10), 0);
+ }
dFree(Length);
}
@@ -506,16 +527,24 @@ static void Cache_parse_header(CacheEntry_t *entry,
#endif /* !DISABLE_COOKIES */
/*
+ * Get Transfer-Encoding and initialize decoder
+ */
+ encoding = Cache_parse_field(header, "Transfer-Encoding");
+ entry->TransferDecoder = a_Decode_transfer_init(encoding);
+ dFree(encoding);
+
+ /*
* Get Content-Encoding and initialize decoder
*/
encoding = Cache_parse_field(header, "Content-Encoding");
- entry->Decoder = a_Decode_content_init(encoding);
+ entry->ContentDecoder = a_Decode_content_init(encoding);
dFree(encoding);
dbuf = dStr_sized_new(buf_size - HdrLen);
dStr_append_l(dbuf, buf + HdrLen, buf_size - HdrLen);
- dbuf = a_Decode_process(entry->Decoder, dbuf);
+ dbuf = a_Decode_process(entry->TransferDecoder, dbuf);
+ dbuf = a_Decode_process(entry->ContentDecoder, dbuf);
if (entry->ExpectedSize > 0) {
if (entry->ExpectedSize > HUGE_FILESIZE) {
@@ -582,6 +611,7 @@ static int Cache_get_header(CacheEntry_t *entry,
void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
const DilloUrl *Url)
{
+ int start = 0;
int len;
CacheEntry_t *entry = Cache_entry_search(Url);
Dstr *dbuf;
@@ -599,9 +629,13 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
}
entry->Flags |= CA_GotData;
entry->Flags &= ~CA_Stopped; /* it may catch up! */
- if (entry->Decoder) {
- a_Decode_free(entry->Decoder);
- entry->Decoder = NULL;
+ if (entry->TransferDecoder) {
+ a_Decode_free(entry->TransferDecoder);
+ entry->TransferDecoder = NULL;
+ }
+ if (entry->ContentDecoder) {
+ a_Decode_free(entry->ContentDecoder);
+ entry->ContentDecoder = NULL;
}
dStr_fit(entry->Data); /* fit buffer size! */
Cache_process_queue(entry);
@@ -612,15 +646,23 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
return;
}
+ /*
+ * Cache_get_header() will set CA_GotHeader if it has a full header, and
+ * Cache_parse_header() will unset it if the header turns out to have been
+ * merely an informational response from the server (i.e., 100 Continue)
+ */
if (!(entry->Flags & CA_GotHeader)) {
- /* Haven't got the whole header yet */
- len = Cache_get_header(entry, buf, buf_size);
- if (entry->Flags & CA_GotHeader) {
- entry->TransferSize = buf_size - len; /* body */
+ while ((len = Cache_get_header(entry, buf + start, buf_size - start))) {
+
/* Let's scan, allocate, and set things according to header info */
- Cache_parse_header(entry, buf, buf_size, len);
- /* Now that we have it parsed, let's update our clients */
- Cache_process_queue(entry);
+ Cache_parse_header(entry, buf + start, buf_size - start, len);
+ start += len;
+ if (entry->Flags & CA_GotHeader) {
+ entry->TransferSize = buf_size - start; /* body */
+ /* Now that we have it parsed, let's update our clients */
+ Cache_process_queue(entry);
+ return;
+ }
}
return;
}
@@ -633,9 +675,13 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
/* Assert we have a Decoder.
* BUG: this is a workaround, more study and a proper design
* for handling redirects is required */
- if (entry->Decoder != NULL) {
- dbuf = a_Decode_process(entry->Decoder, dbuf);
+ if (entry->TransferDecoder != NULL) {
+ dbuf = a_Decode_process(entry->TransferDecoder, dbuf);
+ }
+ if (entry->ContentDecoder != NULL) {
+ dbuf = a_Decode_process(entry->ContentDecoder, dbuf);
}
+
dStr_append_l(entry->Data, dbuf->str, dbuf->len);
dStr_free(dbuf, 1);