From 2748fe4f6483f8cfb3c4f91a01e8d897b7d1ac47 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Mon, 5 Apr 2010 21:35:38 +0000 Subject: Make downloads work again. svn path=/trunk/netsurf/; revision=10243 --- content/content.c | 25 --------------------- content/content.h | 9 ++++---- content/hlcache.c | 52 +++++++++++++++++++++++++++++++++---------- content/hlcache.h | 10 +++++++++ content/llcache.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++------ content/llcache.h | 15 ++++++++++++- 6 files changed, 128 insertions(+), 49 deletions(-) (limited to 'content') diff --git a/content/content.c b/content/content.c index a247dda2b..a44eb2847 100644 --- a/content/content.c +++ b/content/content.c @@ -1409,28 +1409,3 @@ nserror content_abort(struct content *c) return llcache_handle_abort(c->llcache); } -/** - * Convert a content into a download - * - * \param h Content to convert - * \return Pointer to low-level cache handle - */ -llcache_handle *content_convert_to_download(hlcache_handle *h) -{ - struct content *c = hlcache_handle_get_content(h); - llcache_handle *stream = c->llcache; - - assert(c != NULL); - assert(c->status == CONTENT_STATUS_LOADING); - - /** \todo Is this safe? */ - c->llcache = NULL; - - /** \todo Tell the llcache to stream the data without caching it */ - - /** \todo Invalidate the content object so it's flushed from the - * cache at the earliest opportunity */ - - return stream; -} - diff --git a/content/content.h b/content/content.h index ef91135ee..b9af6c267 100644 --- a/content/content.h +++ b/content/content.h @@ -33,11 +33,10 @@ #include "content/content_type.h" #include "desktop/plot_style.h" -struct llcache_handle; - struct box; struct browser_window; struct content; +struct llcache_handle; struct hlcache_handle; struct object_params; @@ -63,6 +62,7 @@ typedef enum { CONTENT_MSG_REFORMAT, /**< content_reformat done */ CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */ CONTENT_MSG_REFRESH, /**< wants refresh */ + CONTENT_MSG_DOWNLOAD /**< download, not for display */ } content_msg; /** Extra data for some content_msg messages. */ @@ -82,6 +82,8 @@ union content_msg_data { float object_width, object_height; } redraw; int delay; /**< Minimum delay, for CONTENT_MSG_REFRESH */ + /** Low-level cache handle, for CONTENT_MSG_DOWNLOAD */ + struct llcache_handle *download; }; @@ -142,7 +144,4 @@ void content_invalidate_reuse_data(struct hlcache_handle *c); const char *content_get_refresh_url(struct hlcache_handle *c); struct bitmap *content_get_bitmap(struct hlcache_handle *c); -/* Download support */ -struct llcache_handle *content_convert_to_download(struct hlcache_handle *c); - #endif diff --git a/content/hlcache.c b/content/hlcache.c index 298fe8151..bbe0cd753 100644 --- a/content/hlcache.c +++ b/content/hlcache.c @@ -40,6 +40,8 @@ struct hlcache_retrieval_ctx { hlcache_handle *handle; /**< High-level handle for object */ + uint32_t flags; /**< Retrieval flags */ + const content_type *accepted_types; /**< Accepted types, or NULL */ hlcache_child_context child; /**< Child context */ @@ -67,7 +69,8 @@ static hlcache_entry *hlcache_content_list; static nserror hlcache_llcache_callback(llcache_handle *handle, const llcache_event *event, void *pw); static bool hlcache_type_is_acceptable(llcache_handle *llcache, - const content_type *accepted_types); + const content_type *accepted_types, + content_type *computed_type); static nserror hlcache_find_content(hlcache_retrieval_ctx *ctx); static void hlcache_content_callback(struct content *c, content_msg msg, union content_msg_data data, void *pw); @@ -104,6 +107,7 @@ nserror hlcache_handle_retrieve(const char *url, uint32_t flags, ctx->child.quirks = child->quirks; } + ctx->flags = flags; ctx->accepted_types = accepted_types; ctx->handle->cb = cb; @@ -227,10 +231,28 @@ nserror hlcache_llcache_callback(llcache_handle *handle, switch (event->type) { case LLCACHE_EVENT_HAD_HEADERS: - if (hlcache_type_is_acceptable(handle, ctx->accepted_types)) { + { + content_type type; + + if (hlcache_type_is_acceptable(handle, + ctx->accepted_types, &type)) { error = hlcache_find_content(ctx); if (error != NSERROR_OK) return error; + } else if (type == CONTENT_OTHER && + ctx->flags & HLCACHE_RETRIEVE_MAY_DOWNLOAD) { + /* Unknown type, and we can download, so convert */ + llcache_handle_force_stream(handle); + + if (ctx->handle->cb != NULL) { + hlcache_event hlevent; + + hlevent.type = CONTENT_MSG_DOWNLOAD; + hlevent.data.download = handle; + + ctx->handle->cb(ctx->handle, &hlevent, + ctx->handle->pw); + } } else { /* Unacceptable type: abort fetch and report error */ llcache_handle_abort(handle); @@ -249,6 +271,7 @@ nserror hlcache_llcache_callback(llcache_handle *handle, /* No longer require retrieval context */ free(ctx); + } break; case LLCACHE_EVENT_HAD_DATA: /* fall through */ @@ -277,19 +300,18 @@ nserror hlcache_llcache_callback(llcache_handle *handle, * * \param llcache Low-level cache object to consider * \param accepted_types Array of acceptable types, or NULL for any + * \param computed_type Pointer to location to receive computed type of object * \return True if the type is acceptable, false otherwise */ bool hlcache_type_is_acceptable(llcache_handle *llcache, - const content_type *accepted_types) + const content_type *accepted_types, content_type *computed_type) { const char *content_type_header; char *mime_type; http_parameter *params; content_type type; nserror error; - - if (accepted_types == NULL) - return true; + bool acceptable; content_type_header = llcache_handle_get_header(llcache, "Content-Type"); @@ -306,14 +328,22 @@ bool hlcache_type_is_acceptable(llcache_handle *llcache, free(mime_type); http_parameter_list_destroy(params); - while (*accepted_types != CONTENT_UNKNOWN) { - if (*accepted_types == type) - break; + if (accepted_types == NULL) { + acceptable = type != CONTENT_OTHER; + } else { + while (*accepted_types != CONTENT_UNKNOWN) { + if (*accepted_types == type) + break; + + accepted_types++; + } - accepted_types++; + acceptable = *accepted_types == type; } - return *accepted_types == type; + *computed_type = type; + + return acceptable; } /** diff --git a/content/hlcache.h b/content/hlcache.h index 1208b15c4..9f03052fa 100644 --- a/content/hlcache.h +++ b/content/hlcache.h @@ -53,6 +53,16 @@ typedef struct { typedef nserror (*hlcache_handle_callback)(hlcache_handle *handle, const hlcache_event *event, void *pw); +/** Flags for high-level cache object retrieval */ +enum hlcache_retrieve_flag { + /* Note: low-level cache retrieval flags occupy the bottom 16 bits of + * the flags word. High-level cache flags occupy the top 16 bits. + * To avoid confusion, high-level flags are allocated from bit 31 down. + */ + /** It's permitted to convert this request into a download */ + HLCACHE_RETRIEVE_MAY_DOWNLOAD = (1 << 31) +}; + /** * Retrieve a high-level cache handle for an object * diff --git a/content/llcache.c b/content/llcache.c index 94df0f6e5..7f44cc916 100644 --- a/content/llcache.c +++ b/content/llcache.c @@ -169,6 +169,8 @@ static nserror llcache_object_add_to_list(llcache_object *object, llcache_object **list); static nserror llcache_object_remove_from_list(llcache_object *object, llcache_object **list); +static bool llcache_object_in_list(const llcache_object *object, + const llcache_object *list); static nserror llcache_object_notify_users(llcache_object *object); @@ -364,6 +366,28 @@ nserror llcache_handle_abort(llcache_handle *handle) return error; } +/* See llcache.h for documentation */ +nserror llcache_handle_force_stream(llcache_handle *handle) +{ + llcache_object_user *user = (llcache_object_user *) handle; + llcache_object *object = handle->object; + + /* Cannot stream if there are multiple users */ + if (user->prev != NULL || user->next != NULL) + return NSERROR_OK; + + /* Forcibly uncache this object */ + if (llcache_object_in_list(object, llcache_cached_objects)) { + llcache_object_remove_from_list(object, + &llcache_cached_objects); + llcache_object_add_to_list(object, &llcache_uncached_objects); + } + + object->fetch.flags |= LLCACHE_RETRIEVE_STREAM_DATA; + + return NSERROR_OK; +} + /* See llcache.h for documentation */ const char *llcache_handle_get_url(const llcache_handle *handle) { @@ -1054,6 +1078,26 @@ nserror llcache_object_remove_from_list(llcache_object *object, return NSERROR_OK; } +/** + * Determine if a low-level cache object resides in a given list + * + * \param object Object to search for + * \param list List to search in + * \return True if object resides in list, false otherwise + */ +bool llcache_object_in_list(const llcache_object *object, + const llcache_object *list) +{ + while (list != NULL) { + if (list == object) + break; + + list = list->next; + } + + return list != NULL; +} + /** * Notify users of an object's current state * @@ -1139,16 +1183,24 @@ nserror llcache_object_notify_users(llcache_object *object) if (handle->state == LLCACHE_FETCH_DATA && objstate >= LLCACHE_FETCH_DATA && object->source_len > handle->bytes) { - size_t oldbytes = handle->bytes; + /* Construct HAD_DATA event */ + event.type = LLCACHE_EVENT_HAD_DATA; + event.data.data.buf = + object->source_data + handle->bytes; + event.data.data.len = + object->source_len - handle->bytes; /* Update record of last byte emitted */ - handle->bytes = object->source_len; - - /* Emit HAD_DATA event */ - event.type = LLCACHE_EVENT_HAD_DATA; - event.data.data.buf = object->source_data + oldbytes; - event.data.data.len = object->source_len - oldbytes; + if (object->fetch.flags & + LLCACHE_RETRIEVE_STREAM_DATA) { + /* Streaming, so reset to zero to + * minimise amount of cached source data */ + handle->bytes = object->source_len = 0; + } else { + handle->bytes = object->source_len; + } + /* Emit event */ error = handle->cb(handle, &event, handle->pw); if (error != NSERROR_OK) { user->iterator_target = false; diff --git a/content/llcache.h b/content/llcache.h index 434d0b641..3c965d3dc 100644 --- a/content/llcache.h +++ b/content/llcache.h @@ -82,6 +82,9 @@ typedef nserror (*llcache_handle_callback)(llcache_handle *handle, /** Flags for low-level cache object retrieval */ enum llcache_retrieve_flag { + /* Note: We're permitted a maximum of 16 flags which must reside in the + * bottom 16 bits of the flags word. See hlcache.h for further details. + */ /** Force a new fetch */ LLCACHE_RETRIEVE_FORCE_FETCH = (1 << 0), /** Requested URL was verified */ @@ -89,7 +92,9 @@ enum llcache_retrieve_flag { /** Permit content-type sniffing */ LLCACHE_RETRIEVE_SNIFF_TYPE = (1 << 2), /**< No error pages */ - LLCACHE_RETRIEVE_NO_ERROR_PAGES = (1 << 3) + LLCACHE_RETRIEVE_NO_ERROR_PAGES = (1 << 3), + /**< Stream data (implies that object is not cacheable) */ + LLCACHE_RETRIEVE_STREAM_DATA = (1 << 4) }; /** Low-level cache query types */ @@ -218,6 +223,14 @@ nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result); */ nserror llcache_handle_abort(llcache_handle *handle); +/** + * Force a low-level cache handle into streaming mode + * + * \param handle Handle to stream + * \return NSERROR_OK on success, appropriate error otherwise + */ +nserror llcache_handle_force_stream(llcache_handle *handle); + /** * Retrieve the post-redirect URL of a low-level cache object * -- cgit v1.2.3