diff options
author | jcid <devnull@localhost> | 2008-06-02 04:27:43 +0200 |
---|---|---|
committer | jcid <devnull@localhost> | 2008-06-02 04:27:43 +0200 |
commit | c9332309b606361609ace591be1266ab59f9c0d4 (patch) | |
tree | c54450e2eb5f582c21fa74167cbdf424e8e4dd32 /src/cache.c | |
parent | cf987dd5f89ceb29fcf71bc95eedb95145fa7c05 (diff) |
- Moved charset decoding into cache.
Diffstat (limited to 'src/cache.c')
-rw-r--r-- | src/cache.c | 156 |
1 files changed, 137 insertions, 19 deletions
diff --git a/src/cache.c b/src/cache.c index 8e33a6c6..c178b8b3 100644 --- a/src/cache.c +++ b/src/cache.c @@ -58,11 +58,14 @@ typedef struct { Dstr *Header; /* HTTP header */ const DilloUrl *Location; /* New URI for redirects */ Dstr *Data; /* Pointer to raw data */ + Dstr *UTF8Data; /* Data after charset translation */ + int DataRefcount; /* Reference count */ Decode *TransferDecoder; /* Transfer decoder (e.g., chunked) */ Decode *ContentDecoder; /* Data decoder (e.g., gzip) */ + Decode *CharsetDecoder; /* Translates text to UTF-8 encoding */ 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 */ + uint_t Flags; /* See Flag Defines in cache.h */ } CacheEntry_t; @@ -207,8 +210,11 @@ 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->UTF8Data = NULL; + NewEntry->DataRefcount = 0; NewEntry->TransferDecoder = NULL; NewEntry->ContentDecoder = NULL; + NewEntry->CharsetDecoder = NULL; NewEntry->ExpectedSize = 0; NewEntry->TransferSize = 0; NewEntry->Flags = CA_IsEmpty; @@ -296,6 +302,9 @@ static void Cache_entry_free(CacheEntry_t *entry) dStr_free(entry->Header, TRUE); a_Url_free((DilloUrl *)entry->Location); dStr_free(entry->Data, 1); + dStr_free(entry->UTF8Data, 1); + if (entry->CharsetDecoder) + a_Decode_free(entry->CharsetDecoder); dFree(entry); } @@ -393,6 +402,43 @@ uint_t a_Cache_get_flags(const DilloUrl *url) } /* + * Reference the cache data. + */ +static void Cache_ref_data(CacheEntry_t *entry) +{ + if (entry) { + entry->DataRefcount++; + _MSG("DataRefcount++: %d\n", entry->DataRefcount); + if (entry->CharsetDecoder && entry->DataRefcount == 1) { + entry->UTF8Data = a_Decode_process(entry->CharsetDecoder, + entry->Data->str, + entry->Data->len); + } + } +} + +/* + * Unreference the cache data. + */ +static void Cache_unref_data(CacheEntry_t *entry) +{ + if (entry) { + entry->DataRefcount--; + _MSG("DataRefcount--: %d\n", entry->DataRefcount); + + if (entry->CharsetDecoder) { + if (entry->DataRefcount == 0) { + dStr_free(entry->UTF8Data, 1); + entry->UTF8Data = NULL; + } else if (entry->DataRefcount < 0) { + MSG_ERR("Cache_unref_data: negative refcount\n"); + entry->DataRefcount = 0; + } + } + } +} + +/* * Get current content type. */ static const char *Cache_current_content_type(CacheEntry_t *entry) @@ -412,25 +458,54 @@ const char *a_Cache_get_content_type(const DilloUrl *url) } /* + * Get pointer to entry's data. + */ +static Dstr *Cache_data(CacheEntry_t *entry) +{ + return entry->UTF8Data ? entry->UTF8Data : entry->Data; +} + +/* * Change Content-Type for cache entry found by url. * Return new content type. */ const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype, bool_t force) { - const char *ret; + const char *curr; CacheEntry_t *entry = Cache_entry_search_with_redirect(url); - if (!entry) { - ret = NULL; - } else { - if (force == TRUE || entry->TypeMeta == NULL) { - dFree(entry->TypeMeta); - entry->TypeMeta = dStrdup(ctype); - } - ret = entry->TypeMeta; + if (!entry) + return NULL; + + curr = Cache_current_content_type(entry); + if (entry->TypeMeta && (force == FALSE)) { + /* it's already been set */ + return curr; + } + + if (a_Misc_content_type_cmp(curr, ctype)) { + char *charset; + + dFree(entry->TypeMeta); + curr = entry->TypeMeta = dStrdup(ctype); + + if (entry->CharsetDecoder) + a_Decode_free(entry->CharsetDecoder); + a_Misc_parse_content_type(ctype, NULL, NULL, &charset); + entry->CharsetDecoder = a_Decode_charset_init(charset); + dFree(charset); + + dStr_free(entry->UTF8Data, 1); + if (entry->CharsetDecoder && entry->DataRefcount > 0) + entry->UTF8Data = a_Decode_process(entry->CharsetDecoder, + entry->Data->str, + entry->Data->len); + else + entry->UTF8Data = NULL; } - return ret; + + return curr; } /* @@ -440,12 +515,28 @@ const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype, int a_Cache_get_buf(const DilloUrl *Url, char **PBuf, int *BufSize) { CacheEntry_t *entry = Cache_entry_search_with_redirect(Url); - *BufSize = (entry) ? entry->Data->len : 0; - *PBuf = (entry) ? entry->Data->str : NULL; + if (entry) { + Cache_ref_data(entry); + Dstr *data = Cache_data(entry); + *PBuf = data->str; + *BufSize = data->len; + } else { + *PBuf = NULL; + *BufSize = 0; + } return (entry ? 1 : 0); } /* + * Unreference the data buffer when no longer using it. + */ +void a_Cache_unref_buf(const DilloUrl *Url) +{ + Cache_unref_data(Cache_entry_search_with_redirect(Url)); +} + + +/* * Extract a single field from the header, allocating and storing the value * in 'field'. ('fieldname' must not include the trailing ':') * Return a new string with the field-content if found (NULL on error) @@ -526,7 +617,7 @@ static Dlist *Cache_parse_multiple_fields(const char *header, static void Cache_parse_header(CacheEntry_t *entry) { char *header = entry->Header->str; - char *Length, *Type, *location_str, *encoding; + char *Length, *Type, *location_str, *encoding, *charset; #ifndef DISABLE_COOKIES Dlist *Cookies; #endif @@ -622,6 +713,7 @@ static void Cache_parse_header(CacheEntry_t *entry) dStr_free(entry->Data, 1); entry->Data = dStr_sized_new(MIN(entry->ExpectedSize, MAX_INIT_BUF)); } + Cache_ref_data(entry); /* Get Content-Type */ if ((Type = Cache_parse_field(header, "Content-Type")) == NULL) { @@ -635,6 +727,13 @@ static void Cache_parse_header(CacheEntry_t *entry) /* This Content-Type is not trusted. It's checked against real data * in Cache_process_queue(); only then CA_GotContentType becomes true. */ + a_Misc_parse_content_type(Type, NULL, NULL, &charset); + if (charset) { + entry->CharsetDecoder = a_Decode_charset_init(charset); + if (entry->CharsetDecoder) + entry->UTF8Data = dStr_new(""); + dFree(charset); + } } } @@ -712,6 +811,9 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, } dStr_fit(entry->Data); /* fit buffer size! */ Cache_process_queue(entry); + if (entry->Flags & CA_GotHeader) { + Cache_unref_data(entry); + } return; } else if (Op == IOAbort) { /* unused */ @@ -753,6 +855,13 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, dStr_free(dbuf, 0); } dStr_append_l(entry->Data, str, len); + + if (entry->UTF8Data) { + Dstr *dbuf = a_Decode_process(entry->CharsetDecoder, str, len); + dStr_append_l(entry->UTF8Data, dbuf->str, dbuf->len); + dStr_free(dbuf, 1); + } + if (entry->TransferDecoder || entry->ContentDecoder) dFree((char *)str); @@ -860,6 +969,7 @@ static void Cache_process_queue(CacheEntry_t *entry) uint_t i; int st; const char *Type; + Dstr *data; CacheClient_t *Client; DilloWeb *ClientWeb; BrowserWindow *Client_bw = NULL; @@ -954,8 +1064,14 @@ static void Cache_process_queue(CacheEntry_t *entry) } /* Send data to our client */ - if ((Client->BufSize = entry->Data->len) > 0) { - Client->Buf = entry->Data->str; + if (ClientWeb->flags & WEB_Download) { + /* for download, always provide original data, not translated */ + data = entry->Data; + } else { + data = Cache_data(entry); + } + if ((Client->BufSize = data->len) > 0) { + Client->Buf = data->str; (Client->Callback)(CA_Send, Client); } @@ -1001,10 +1117,12 @@ static void Cache_process_queue(CacheEntry_t *entry) */ static void Cache_delayed_process_queue_callback(void *data) { - void *entry; + CacheEntry_t *entry; - while ((entry = dList_nth_data(DelayedQueue, 0))) { - Cache_process_queue((CacheEntry_t *)entry); + while ((entry = (CacheEntry_t *)dList_nth_data(DelayedQueue, 0))) { + Cache_ref_data(entry); + Cache_process_queue(entry); + Cache_unref_data(entry); /* note that if Cache_process_queue removes the entry, * the following dList_remove has no effect. */ dList_remove(DelayedQueue, entry); |