From 08177fa58119f9e67fdffb32ee20dbf05bd4fa78 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Thu, 10 Jun 2004 20:41:26 +0000 Subject: [project @ 2004-06-10 20:41:26 by bursa] Add global content list. Better error handling in content code. Improved code documentation. Remove some obsolete functions. Implement debug window listing contents. svn path=/import/netsurf/; revision=951 --- content/content.c | 292 ++++++++++++++++++++++++++++++++++++--------------- content/content.h | 100 ++++++++++++++++-- content/fetch.c | 8 +- content/fetchcache.c | 41 +++++--- 4 files changed, 328 insertions(+), 113 deletions(-) (limited to 'content') diff --git a/content/content.c b/content/content.c index a002c04fd..268b36433 100644 --- a/content/content.c +++ b/content/content.c @@ -45,6 +45,10 @@ #include "netsurf/utils/utils.h" +/** Linked list of all content structures. May include more than one content + * per URL. Doubly-linked. */ +struct content *content_list = 0; + /** An entry in mime_map. */ struct mime_entry { char mime_type[40]; @@ -79,17 +83,50 @@ static const struct mime_entry mime_map[] = { }; #define MIME_MAP_COUNT (sizeof(mime_map) / sizeof(mime_map[0])) +const char *content_type_name[] = { + "HTML", + "TEXTPLAIN", + "CSS", +#ifdef WITH_JPEG + "JPEG", +#endif +#ifdef WITH_GIF + "GIF", +#endif +#ifdef WITH_PNG + "PNG", +#endif +#ifdef WITH_SPRITE + "SPRITE", +#endif +#ifdef WITH_DRAW + "DRAW", +#endif +#ifdef WITH_PLUGIN + "PLUGIN", +#endif + "OTHER", + "UNKNOWN" +}; + +const char *content_status_name[] = { + "TYPE_UNKNOWN", + "LOADING", + "READY", + "DONE", + "ERROR" +}; + /** An entry in handler_map. */ struct handler_entry { - void (*create)(struct content *c, const char *params[]); - void (*process_data)(struct content *c, char *data, unsigned long size); - int (*convert)(struct content *c, unsigned int width, unsigned int height); - void (*revive)(struct content *c, unsigned int width, unsigned int height); - void (*reformat)(struct content *c, unsigned int width, unsigned int height); + bool (*create)(struct content *c, const char *params[]); + bool (*process_data)(struct content *c, char *data, unsigned int size); + bool (*convert)(struct content *c, int width, int height); + void (*reformat)(struct content *c, int width, int height); void (*destroy)(struct content *c); - void (*redraw)(struct content *c, long x, long y, - unsigned long width, unsigned long height, - long clip_x0, long clip_y0, long clip_x1, long clip_y1, + void (*redraw)(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale); void (*add_instance)(struct content *c, struct browser_window *bw, struct content *page, struct box *box, @@ -104,39 +141,39 @@ struct handler_entry { /** A table of handler functions, indexed by ::content_type. * Must be ordered as enum ::content_type. */ static const struct handler_entry handler_map[] = { - {html_create, html_process_data, html_convert, html_revive, + {html_create, html_process_data, html_convert, html_reformat, html_destroy, html_redraw, html_add_instance, html_remove_instance, html_reshape_instance}, {textplain_create, html_process_data, textplain_convert, - 0, 0, 0, 0, 0, 0, 0}, - {0, 0, css_convert, css_revive, 0, css_destroy, 0, 0, 0, 0}, + 0, 0, 0, 0, 0, 0}, + {0, 0, css_convert, 0, css_destroy, 0, 0, 0, 0}, #ifdef WITH_JPEG - {nsjpeg_create, 0, nsjpeg_convert, 0, + {nsjpeg_create, 0, nsjpeg_convert, 0, nsjpeg_destroy, nsjpeg_redraw, 0, 0, 0}, #endif #ifdef WITH_GIF - {nsgif_create, 0, nsgif_convert, 0, + {nsgif_create, 0, nsgif_convert, 0, nsgif_destroy, nsgif_redraw, 0, 0, 0}, #endif #ifdef WITH_PNG - {nspng_create, nspng_process_data, nspng_convert, 0, + {nspng_create, nspng_process_data, nspng_convert, 0, nspng_destroy, nspng_redraw, 0, 0, 0}, #endif #ifdef WITH_SPRITE - {sprite_create, sprite_process_data, sprite_convert, sprite_revive, - sprite_reformat, sprite_destroy, sprite_redraw, 0, 0, 0}, + {sprite_create, sprite_process_data, sprite_convert, + 0, sprite_destroy, sprite_redraw, 0, 0, 0}, #endif #ifdef WITH_DRAW - {0, 0, draw_convert, 0, + {0, 0, draw_convert, 0, draw_destroy, draw_redraw, 0, 0, 0}, #endif #ifdef WITH_PLUGIN - {plugin_create, plugin_process_data, plugin_convert, plugin_revive, + {plugin_create, plugin_process_data, plugin_convert, plugin_reformat, plugin_destroy, plugin_redraw, plugin_add_instance, plugin_remove_instance, plugin_reshape_instance}, #endif - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + {0, 0, 0, 0, 0, 0, 0, 0, 0} }; #define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0])) @@ -166,33 +203,62 @@ content_type content_lookup(const char *mime_type) /** * Create a new content structure. * + * \param url URL of content, copied + * \return the new content structure, or 0 on memory exhaustion + * * The type is initialised to CONTENT_UNKNOWN, and the status to * CONTENT_STATUS_TYPE_UNKNOWN. */ -struct content * content_create(char *url) +struct content * content_create(const char *url) { struct content *c; struct content_user *user_sentinel; LOG(("url %s", url)); - c = xcalloc(1, sizeof(struct content)); - c->url = xstrdup(url); + c = malloc(sizeof(struct content)); + if (!c) + return 0; + user_sentinel = malloc(sizeof *user_sentinel); + if (!user_sentinel) { + free(c); + return 0; + } + c->url = strdup(url); + if (!c->url) { + free(c); + free(user_sentinel); + return 0; + } c->type = CONTENT_UNKNOWN; + c->mime_type = 0; c->status = CONTENT_STATUS_TYPE_UNKNOWN; + c->width = 0; + c->height = 0; + c->available_width = 0; c->cache = 0; c->size = sizeof(struct content); - c->fetch = 0; - c->source_data = 0; - c->source_size = 0; - c->mime_type = 0; - content_set_status(c, messages_get("Loading")); - user_sentinel = xcalloc(1, sizeof(*user_sentinel)); + c->title = 0; + c->active = 0; user_sentinel->callback = 0; user_sentinel->p1 = user_sentinel->p2 = 0; user_sentinel->next = 0; c->user_list = user_sentinel; + content_set_status(c, messages_get("Loading")); + c->fetch = 0; + c->source_data = 0; + c->source_size = 0; + c->total_size = 0; c->lock = 0; c->destroy_pending = false; + c->no_error_pages = false; + c->error_count = 0; + + c->prev = 0; + c->next = content_list; + if (content_list) + content_list->prev = c; + content_list = c; + return c; } @@ -200,34 +266,51 @@ struct content * content_create(char *url) /** * Initialise the content for the specified type. * + * \param c content structure + * \param type content_type to initialise to + * \param mime_type MIME-type string for this content + * \param params array of strings, ordered attribute, value, attribute, ..., 0 + * \return true on success, false on error and error broadcast to users and + * possibly reported + * * The type is updated to the given type, and a copy of mime_type is taken. The * status is changed to CONTENT_STATUS_LOADING. CONTENT_MSG_LOADING is sent to * all users. The create function for the type is called to initialise the type * specific parts of the content structure. - * - * \param c content structure - * \param type content_type to initialise to - * \param mime_type MIME-type string for this content - * \param params array of strings, ordered attribute, value, attribute, ..., 0 */ -void content_set_type(struct content *c, content_type type, +bool content_set_type(struct content *c, content_type type, const char *mime_type, const char *params[]) { - union content_msg_data data; + union content_msg_data msg_data; + assert(c != 0); assert(c->status == CONTENT_STATUS_TYPE_UNKNOWN); assert(type < CONTENT_UNKNOWN); + LOG(("content %s, type %i", c->url, type)); + + c->mime_type = strdup(mime_type); + if (!c->mime_type) { + c->status = CONTENT_STATUS_ERROR; + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + } + c->type = type; - c->mime_type = xstrdup(mime_type); c->status = CONTENT_STATUS_LOADING; - c->source_data = xcalloc(0, 1); - if (handler_map[type].create) - handler_map[type].create(c, params); - content_broadcast(c, CONTENT_MSG_LOADING, data); - /* c may be destroyed at this point as a result of - * CONTENT_MSG_LOADING, so must not be accessed */ + + if (handler_map[type].create) { + if (!handler_map[type].create(c, params)) { + c->status = CONTENT_STATUS_ERROR; + return false; + } + } + + content_broadcast(c, CONTENT_MSG_LOADING, msg_data); + return true; } @@ -255,19 +338,44 @@ void content_set_status(struct content *c, const char *status_message, ...) * Process a block of source data. * * Calls the process_data function for the content. + * + * \param c content structure + * \param data new data to process + * \param size size of data + * \return true on success, false on error and error broadcast to users and + * possibly reported */ -void content_process_data(struct content *c, char *data, unsigned long size) +bool content_process_data(struct content *c, char *data, unsigned int size) { - assert(c != 0); + char *source_data; + union content_msg_data msg_data; + + assert(c); + assert(c->type < HANDLER_MAP_COUNT); assert(c->status == CONTENT_STATUS_LOADING); - LOG(("content %s, size %lu", c->url, size)); - c->source_data = xrealloc(c->source_data, c->source_size + size); + LOG(("content %s, size %u", c->url, size)); + + source_data = realloc(c->source_data, c->source_size + size); + if (!source_data) { + c->status = CONTENT_STATUS_ERROR; + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + } + c->source_data = source_data; memcpy(c->source_data + c->source_size, data, size); c->source_size += size; c->size += size; - if (handler_map[c->type].process_data) - handler_map[c->type].process_data(c, data, size); + + if (handler_map[c->type].process_data) { + if (!handler_map[c->type].process_data(c, data, size)) { + c->status = CONTENT_STATUS_ERROR; + return false; + } + } + return true; } @@ -281,54 +389,34 @@ void content_process_data(struct content *c, char *data, unsigned long size) * CONTENT_MSG_READY is sent to all users. * - If the conversion succeeds and is complete, the content gets status * CONTENT_STATUS_DONE, and CONTENT_MSG_READY then CONTENT_MSG_DONE are sent. - * - If the conversion fails, CONTENT_MSG_ERROR is sent. The content is then - * destroyed and must no longer be used. + * - If the conversion fails, CONTENT_MSG_ERROR is sent. The content will soon + * be destroyed and must no longer be used. */ -void content_convert(struct content *c, unsigned long width, unsigned long height) +void content_convert(struct content *c, int width, int height) { - union content_msg_data data; - assert(c != 0); + union content_msg_data msg_data; + + assert(c); assert(c->type < HANDLER_MAP_COUNT); assert(c->status == CONTENT_STATUS_LOADING); LOG(("content %s", c->url)); + c->available_width = width; if (handler_map[c->type].convert) { - if (handler_map[c->type].convert(c, width, height)) { - /* convert failed, destroy content */ - data.error = "Conversion failed"; - content_broadcast(c, CONTENT_MSG_ERROR, data); - if (c->cache) - cache_destroy(c); - content_destroy(c); + if (!handler_map[c->type].convert(c, width, height)) { + c->status = CONTENT_STATUS_ERROR; return; } } else { c->status = CONTENT_STATUS_DONE; } + assert(c->status == CONTENT_STATUS_READY || c->status == CONTENT_STATUS_DONE); - content_broadcast(c, CONTENT_MSG_READY, data); + content_broadcast(c, CONTENT_MSG_READY, msg_data); if (c->status == CONTENT_STATUS_DONE) - content_broadcast(c, CONTENT_MSG_DONE, data); -} - - -/** - * Fix content that has been loaded from the cache. - * - * Calls the revive function for the content. The content will be processed for - * display, for example dependencies loaded or reformated to current width. - */ - -void content_revive(struct content *c, unsigned long width, unsigned long height) -{ - assert(0); /* unmaintained */ - assert(c != 0); - if (c->status != CONTENT_STATUS_DONE) - return; - c->available_width = width; - handler_map[c->type].revive(c, width, height); + content_broadcast(c, CONTENT_MSG_DONE, msg_data); } @@ -338,7 +426,7 @@ void content_revive(struct content *c, unsigned long width, unsigned long height * Calls the reformat function for the content. */ -void content_reformat(struct content *c, unsigned long width, unsigned long height) +void content_reformat(struct content *c, int width, int height) { union content_msg_data data; assert(c != 0); @@ -352,6 +440,29 @@ void content_reformat(struct content *c, unsigned long width, unsigned long heig } +/** + * Destroys any contents in the content_list with no users or in + * CONTENT_STATUS_ERROR, and not with an active fetch or cached. + */ + +void content_clean(void) +{ + struct content *c, *next; + + for (c = content_list; c; c = next) { + next = c->next; + if (((!c->user_list->next && !c->cache) || + c->status == CONTENT_STATUS_ERROR) && + !c->fetch) { + LOG(("%p %s", c, c->url)); + if (c->cache) + cache_destroy(c); + content_destroy(c); + } + } +} + + /** * Destroy and free a content. * @@ -371,6 +482,13 @@ void content_destroy(struct content *c) return; } + if (c->next) + c->next->prev = c->prev; + if (c->prev) + c->prev->next = c->next; + else + content_list = c->next; + if (c->type < HANDLER_MAP_COUNT && handler_map[c->type].destroy) handler_map[c->type].destroy(c); for (user = c->user_list; user != 0; user = next) { @@ -411,9 +529,9 @@ void content_reset(struct content *c) * Calls the redraw function for the content, if it exists. */ -void content_redraw(struct content *c, long x, long y, - unsigned long width, unsigned long height, - long clip_x0, long clip_y0, long clip_x1, long clip_y1, +void content_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale) { assert(c != 0); @@ -570,3 +688,9 @@ void content_reshape_instance(struct content *c, struct browser_window *bw, handler_map[c->type].reshape_instance(c, bw, page, box, params, state); } + + +void content_add_error(struct content *c, const char *token, + unsigned int line) +{ +} diff --git a/content/content.h b/content/content.h index 13c4092ce..3fcbd39fe 100644 --- a/content/content.h +++ b/content/content.h @@ -14,12 +14,73 @@ * Each content has a type. The type is used to call a specific implementation * of functions such as content_process_data(). * + * The source data fetched from the URL is placed in the source_data buffer as + * it arrives. + * * Contents have an associated set of users, which are informed by a callback * when the state of the content changes or something interesting happens. * * Optionally, contents may have instances (depending on type). Instances * represent copies of the same URL, for example if a page is open in two * windows, or a page contains the same image twice. + * + * The status of a content follows a fixed order. Certain content functions + * change the state, and each change of state results in a message to all users + * of the content. The diagram below shows this: + * \dot + * digraph status { + * node [shape=plaintext, fontname=Helvetica, fontsize=9]; + * edge [fontname=Helvetica, fontsize=9]; + * + * content_create -> TYPE_UNKNOWN [style=bold]; + * TYPE_UNKNOWN -> content_set_type [style=bold]; + * content_set_type -> LOADING [label=MSG_LOADING, style=bold]; + * content_set_type -> ERROR [label=MSG_ERROR]; + * LOADING -> content_process_data [style=bold]; + * content_process_data -> LOADING [style=bold]; + * content_process_data -> ERROR [label=MSG_ERROR]; + * LOADING -> content_convert [style=bold]; + * content_convert -> READY [label=MSG_READY, style=bold]; + * content_convert -> DONE [label="MSG_READY\nMSG_DONE", style=bold]; + * content_convert -> ERROR [label=MSG_ERROR]; + * READY -> READY [style=bold]; + * READY -> DONE [label=MSG_DONE, style=bold]; + * + * TYPE_UNKNOWN [shape=ellipse]; + * LOADING [shape=ellipse]; + * READY [shape=ellipse]; + * DONE [shape=ellipse]; + * ERROR [shape=ellipse]; + * } + * \enddot + * + * To implement a new content type, implement the following functions: + * + * - type_create(): called to initialise type-specific fields in the + * content structure. Optional. + * + * - type_process_data(): called when some data arrives. Optional. + * + * - type_convert(): called when data has finished arriving. The + * content needs to be converted for display. Must set the status to one of + * CONTENT_STATUS_READY or CONTENT_STATUS_DONE if no error occurs. Optional, + * but probably required for non-trivial types. + * + * - type_reformat(): called when, for example, the window has been + * resized, and the content needs reformatting for the new size. Optional. + * + * - type_destroy(): called when the content is being destroyed. Free all + * resources. Optional. + * + * - type_redraw(): called to plot the content to screen. + * + * - type_(add|remove|reshape)_instance: ask James, this will probably + * be redesigned sometime. + * + * - type_create(), type_process_data(), type_convert(): + * if an error occurs, must broadcast CONTENT_MSG_ERROR and return false. + * Optionally use warn_user() for serious errors. The _destroy function will + * be called soon after. */ #ifndef _NETSURF_DESKTOP_CONTENT_H_ @@ -111,7 +172,9 @@ struct content { converted and is not safe to display. */ CONTENT_STATUS_READY, /**< Some parts of content still being loaded, but can be displayed. */ - CONTENT_STATUS_DONE /**< All finished. */ + CONTENT_STATUS_DONE, /**< All finished. */ + CONTENT_STATUS_ERROR /**< Error occurred, content will be + destroyed imminently. */ } status; /**< Current status. */ int width, height; /**< Dimensions, if applicable. */ @@ -147,7 +210,6 @@ struct content { char *title; /**< Title for browser window. */ unsigned int active; /**< Number of child fetches or conversions currently in progress. */ - int error; /**< Non-0 if an error has occurred. */ struct content_user *user_list; /**< List of users. */ char status_message[80]; /**< Text for status bar. */ @@ -159,26 +221,40 @@ struct content { int lock; /**< Content in use, do not destroy. */ bool destroy_pending; /**< Destroy when lock returns to 0. */ bool no_error_pages; /**< Used by fetchcache(). */ + + /** Array of first n rendering errors or warnings. */ + struct { + const char *token; + unsigned int line; /**< Line no, 0 if not applicable. */ + } error_list[40]; + unsigned int error_count; /**< Number of valid error entries. */ + + struct content *prev; /**< Previous in global content list. */ + struct content *next; /**< Next in global content list. */ }; +extern struct content *content_list; +extern const char *content_type_name[]; +extern const char *content_status_name[]; + struct browser_window; content_type content_lookup(const char *mime_type); -struct content * content_create(char *url); -void content_set_type(struct content *c, content_type type, +struct content * content_create(const char *url); +bool content_set_type(struct content *c, content_type type, const char *mime_type, const char *params[]); void content_set_status(struct content *c, const char *status_message, ...); -void content_process_data(struct content *c, char *data, unsigned long size); -void content_convert(struct content *c, unsigned long width, unsigned long height); -void content_revive(struct content *c, unsigned long width, unsigned long height); -void content_reformat(struct content *c, unsigned long width, unsigned long height); +bool content_process_data(struct content *c, char *data, unsigned int size); +void content_convert(struct content *c, int width, int height); +void content_reformat(struct content *c, int width, int height); +void content_clean(void); void content_destroy(struct content *c); void content_reset(struct content *c); -void content_redraw(struct content *c, long x, long y, - unsigned long width, unsigned long height, - long clip_x0, long clip_y0, long clip_x1, long clip_y1, +void content_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale); void content_add_user(struct content *c, void (*callback)(content_msg msg, struct content *c, void *p1, @@ -199,5 +275,7 @@ void content_remove_instance(struct content *c, struct browser_window *bw, void content_reshape_instance(struct content *c, struct browser_window *bw, struct content *page, struct box *box, struct object_params *params, void **state); +void content_add_error(struct content *c, const char *token, + unsigned int line); #endif diff --git a/content/fetch.c b/content/fetch.c index c8630f343..52d7effc5 100644 --- a/content/fetch.c +++ b/content/fetch.c @@ -31,9 +31,6 @@ #include "curl/curl.h" #include "netsurf/utils/config.h" #include "netsurf/content/fetch.h" -#ifdef riscos -#include "netsurf/desktop/gui.h" -#endif #include "netsurf/desktop/options.h" #ifdef WITH_AUTH #include "netsurf/desktop/401login.h" @@ -587,6 +584,11 @@ size_t fetch_curl_data(void * data, size_t size, size_t nmemb, struct fetch *f) /* send data to the caller */ LOG(("FETCH_DATA")); f->callback(FETCH_DATA, f->p, data, size * nmemb); + if (f->aborting) { + f->locked--; + f->stopped = true; + return 0; + } f->locked--; return size * nmemb; diff --git a/content/fetchcache.c b/content/fetchcache.c index 164a11231..359b59809 100644 --- a/content/fetchcache.c +++ b/content/fetchcache.c @@ -59,7 +59,7 @@ static void fetchcache_error_page(struct content *c, const char *error); * \param post_urlenc url encoded post data, or 0 if none * \param post_multipart multipart post data, or 0 if none * \param cookies send and accept cookies - * \return a new content, or 0 if an error occurred and no_error_pages is true + * \return a new content, or 0 if an error occurred */ struct content * fetchcache(const char *url, char *referer, @@ -77,12 +77,16 @@ struct content * fetchcache(const char *url, char *referer, ) { struct content *c; - char *url1 = xstrdup(url); - char *hash = strchr(url1, '#'); + char *url1; + char *hash; char error_message[500]; + url1 = strdup(url); + if (!url1) + return 0; + /* strip fragment identifier */ - if (hash != 0) + if ((hash = strchr(url1, '#'))) *hash = 0; LOG(("url %s", url1)); @@ -100,6 +104,10 @@ struct content * fetchcache(const char *url, char *referer, } c = content_create(url1); + if (!c) { + free(url1); + return 0; + } content_add_user(c, callback, p1, p2); #ifdef WITH_POST @@ -118,12 +126,10 @@ struct content * fetchcache(const char *url, char *referer, ,cookies #endif ); - if (c->fetch == 0) { + if (!c->fetch) { LOG(("warning: fetch_start failed")); - if (c->cache) - cache_destroy(c); + c->status = CONTENT_STATUS_ERROR; if (no_error_pages) { - content_destroy(c); free(url1); return 0; } @@ -144,6 +150,7 @@ struct content * fetchcache(const char *url, char *referer, void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) { + bool res; struct content *c = p; content_type type; char *mime_type, *url; @@ -159,11 +166,13 @@ void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) mime_type = fetchcache_parse_type(data, ¶ms); type = content_lookup(mime_type); LOG(("FETCH_TYPE, type %u", type)); - content_set_type(c, type, mime_type, (const char**)params); + res = content_set_type(c, type, mime_type, params); free(mime_type); for (i = 0; params[i]; i++) free(params[i]); free(params); + if (!res) + fetch_abort(c->fetch); if (c->cache && c->type == CONTENT_OTHER) cache_destroy(c); break; @@ -181,7 +190,8 @@ void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) messages_get("Received"), human_friendly_bytesize(c->source_size + size)); content_broadcast(c, CONTENT_MSG_STATUS, msg_data); - content_process_data(c, data, size); + if (!content_process_data(c, data, size)) + fetch_abort(c->fetch); break; case FETCH_FINISHED: @@ -199,9 +209,10 @@ void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) if (c->cache) cache_destroy(c); if (c->no_error_pages) { + c->status = CONTENT_STATUS_ERROR; msg_data.error = data; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - content_destroy(c); + content_broadcast(c, CONTENT_MSG_ERROR, + msg_data); } else { content_reset(c); fetchcache_error_page(c, data); @@ -233,15 +244,15 @@ void fetchcache_callback(fetch_msg msg, void *p, char *data, unsigned long size) c->fetch = 0; msg_data.auth_realm = data; content_broadcast(c, CONTENT_MSG_AUTH, msg_data); - cache_destroy(c); + if (c->cache) + cache_destroy(c); break; #endif default: assert(0); } - if (--(c->lock) == 0 && c->destroy_pending) - content_destroy(c); + c->lock--; } -- cgit v1.2.3