diff --git a/content/content.c b/content/content.c index 3974e90fd..5b8956ab5 100644 --- a/content/content.c +++ b/content/content.c @@ -304,6 +304,7 @@ bool content_set_type(struct content *c, content_type type, if (handler_map[type].create) { if (!handler_map[type].create(c, params)) { + c->type = CONTENT_UNKNOWN; c->status = CONTENT_STATUS_ERROR; return false; } diff --git a/content/fetch.c b/content/fetch.c index b42e48ea7..f68dea739 100644 --- a/content/fetch.c +++ b/content/fetch.c @@ -302,12 +302,6 @@ struct fetch * fetch_start(char *url, char *referer, } } - fetch->next = fetch_list; - if (fetch_list != 0) - fetch_list->prev = fetch; - fetch_list = fetch; - fetch_active = true; - /* create the curl easy handle */ fetch->curl_handle = curl_easy_duphandle(fetch_blank_curl); if (!fetch->curl_handle) @@ -321,6 +315,12 @@ struct fetch * fetch_start(char *url, char *referer, codem = curl_multi_add_handle(curl_multi, fetch->curl_handle); assert(codem == CURLM_OK || codem == CURLM_CALL_MULTI_PERFORM); + fetch->next = fetch_list; + if (fetch_list != 0) + fetch_list->prev = fetch; + fetch_list = fetch; + fetch_active = true; + return fetch; failed: diff --git a/content/fetchcache.c b/content/fetchcache.c index 359b59809..1ddd2fe7a 100644 --- a/content/fetchcache.c +++ b/content/fetchcache.c @@ -36,50 +36,41 @@ static void fetchcache_error_page(struct content *c, const char *error); /** - * Retrieve a URL or fetch, convert, and cache it. - * - * The referer may be 0. + * Retrieve a URL or prepare to fetch, convert, and cache it. * * The caller must supply a callback function which is called when anything * interesting happens to the content which is returned. See content.h. * - * If an error occurs immediately, 0 may be returned. Later errors will be - * reported via the callback. + * \param url address to fetch + * \param callback function to call when anything interesting happens to + * the new content + * \param p1 user parameter for callback + * \param p2 user parameter for callback + * \param width available space + * \param height available space + * \param no_error_pages if an error occurs, send CONTENT_MSG_ERROR instead + * of generating an error page + * \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 on memory exhaustion * - * \param url address to fetch - * \param referer url of referring page, or 0 if none - * \param callback function to call when anything interesting happens to - * the new content - * \param p1 user parameter for callback - * \param p2 user parameter for callback - * \param width available space - * \param height available space - * \param no_error_pages if an error occurs, send CONTENT_MSG_ERROR instead - * of generating an error page - * \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 + * On success, call fetchcache_go() to start work on the new content. */ -struct content * fetchcache(const char *url, char *referer, +struct content * fetchcache(const char *url, void (*callback)(content_msg msg, struct content *c, void *p1, void *p2, union content_msg_data data), - void *p1, void *p2, unsigned long width, unsigned long height, - bool no_error_pages -#ifdef WITH_POST - , char *post_urlenc, - struct form_successful_control *post_multipart -#endif -#ifdef WITH_COOKIES - ,bool cookies -#endif - ) + void *p1, void *p2, + int width, int height, + bool no_error_pages, + char *post_urlenc, + struct form_successful_control *post_multipart, + bool cookies) { struct content *c; char *url1; char *hash; - char error_message[500]; url1 = strdup(url); if (!url1) @@ -91,12 +82,9 @@ struct content * fetchcache(const char *url, char *referer, LOG(("url %s", url1)); -#ifdef WITH_POST - if (!post_urlenc && !post_multipart) -#endif - { + if (!post_urlenc && !post_multipart) { c = cache_get(url1); - if (c != 0) { + if (c) { free(url1); content_add_user(c, callback, p1, p2); return c; @@ -110,38 +98,96 @@ struct content * fetchcache(const char *url, char *referer, } content_add_user(c, callback, p1, p2); -#ifdef WITH_POST if (!post_urlenc && !post_multipart) -#endif cache_put(c); c->width = width; c->height = height; c->no_error_pages = no_error_pages; - c->fetch = fetch_start(url1, referer, fetchcache_callback, c, no_error_pages -#ifdef WITH_POST - ,post_urlenc, post_multipart -#endif -#ifdef WITH_COOKIES - ,cookies -#endif - ); - if (!c->fetch) { - LOG(("warning: fetch_start failed")); - c->status = CONTENT_STATUS_ERROR; - if (no_error_pages) { - free(url1); - return 0; - } - snprintf(error_message, sizeof error_message, - messages_get("InvalidURL"), url1); - fetchcache_error_page(c, error_message); - } - free(url1); + return c; } +/** + * Start fetching and converting a content. + * + * \param url address to fetch + * \param referer referring URL, or 0 + * \param callback function to call when anything interesting happens to + * the new content + * \param p1 user parameter for callback + * \param p2 user parameter for callback + * \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 + * + * Errors will be sent back through the callback. + */ + +void fetchcache_go(struct content *content, char *referer, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, union content_msg_data data), + void *p1, void *p2, + char *post_urlenc, + struct form_successful_control *post_multipart, + bool cookies) +{ + char error_message[500]; + union content_msg_data msg_data; + + LOG(("url %s, status %s", content->url, + content_status_name[content->status])); + + if (content->status == CONTENT_STATUS_TYPE_UNKNOWN && content->fetch) { + /* fetching, but not yet received any response: + * no action required */ + + } else if (content->status == CONTENT_STATUS_TYPE_UNKNOWN) { + /* brand new content: start fetch */ + content->fetch = fetch_start(content->url, referer, + fetchcache_callback, content, + content->no_error_pages, + post_urlenc, post_multipart, cookies); + if (!content->fetch) { + LOG(("warning: fetch_start failed")); + snprintf(error_message, sizeof error_message, + messages_get("InvalidURL"), + content->url); + if (content->no_error_pages) { + content->status = CONTENT_STATUS_ERROR; + msg_data.error = error_message; + content_broadcast(content, CONTENT_MSG_ERROR, + msg_data); + } else { + fetchcache_error_page(content, error_message); + } + } + + /* in these remaining cases, we have to 'catch up' with the content's + * status, ie. send the same messages as if the content was + * gradually getting to the current status from TYPE_UNKNOWN */ + } else if (content->status == CONTENT_STATUS_LOADING) { + callback(CONTENT_MSG_LOADING, content, p1, p2, msg_data); + + } else if (content->status == CONTENT_STATUS_READY) { + callback(CONTENT_MSG_LOADING, content, p1, p2, msg_data); + callback(CONTENT_MSG_READY, content, p1, p2, msg_data); + + } else if (content->status == CONTENT_STATUS_DONE) { + callback(CONTENT_MSG_LOADING, content, p1, p2, msg_data); + callback(CONTENT_MSG_READY, content, p1, p2, msg_data); + callback(CONTENT_MSG_DONE, content, p1, p2, msg_data); + + } else if (content->status == CONTENT_STATUS_ERROR) { + /* shouldn't usually occur */ + msg_data.error = messages_get("MiscError"); + callback(CONTENT_MSG_ERROR, content, p1, p2, msg_data); + + } +} + + /** * Callback function for fetch. * @@ -327,8 +373,10 @@ void fetchcache_error_page(struct content *c, const char *error) if ((length = snprintf(error_page, sizeof(error_page), messages_get("ErrorPage"), error)) < 0) length = 0; - content_set_type(c, CONTENT_HTML, "text/html", params); - content_process_data(c, error_page, length); + if (!content_set_type(c, CONTENT_HTML, "text/html", params)) + return; + if (!content_process_data(c, error_page, length)) + return; content_convert(c, c->width, c->height); } diff --git a/content/fetchcache.h b/content/fetchcache.h index 3fadc3459..f20ab6cf9 100644 --- a/content/fetchcache.h +++ b/content/fetchcache.h @@ -2,40 +2,40 @@ * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 James Bursa + * Copyright 2004 James Bursa */ /** \file * High-level fetching, caching and conversion (interface). * - * The fetchcache() function retrieves a URL from the cache, or fetches, - * converts, and caches it if not cached. + * The fetchcache() / fetchcache_go() pair of functions retrieve a URL from + * the cache, or fetch, convert, and cache it if not cached. */ #ifndef _NETSURF_DESKTOP_FETCHCACHE_H_ #define _NETSURF_DESKTOP_FETCHCACHE_H_ #include -#include "netsurf/utils/config.h" #include "netsurf/content/content.h" -#ifdef WITH_POST struct form_successful_control; -#endif -struct content * fetchcache(const char *url, char *referer, +void fetchcache_init(void); +struct content * fetchcache(const char *url, void (*callback)(content_msg msg, struct content *c, void *p1, void *p2, union content_msg_data data), - void *p1, void *p2, unsigned long width, unsigned long height, - bool no_error_pages -#ifdef WITH_POST - , char *post_urlenc, - struct form_successful_control *post_multipart -#endif -#ifdef WITH_COOKIES - ,bool cookies -#endif - ); -void fetchcache_init(void); + void *p1, void *p2, + int width, int height, + bool no_error_pages, + char *post_urlenc, + struct form_successful_control *post_multipart, + bool cookies); +void fetchcache_go(struct content *content, char *referer, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, union content_msg_data data), + void *p1, void *p2, + char *post_urlenc, + struct form_successful_control *post_multipart, + bool cookies); #endif diff --git a/css/css.c b/css/css.c index 8239d77bf..3072c3a47 100644 --- a/css/css.c +++ b/css/css.c @@ -560,19 +560,15 @@ void css_atimport(struct content *c, struct css_node *node) c->data.css.import_count++; i = c->data.css.import_count - 1; c->data.css.import_url[i] = url1; - c->data.css.import_content[i] = fetchcache( - c->data.css.import_url[i], c->url, css_atimport_callback, - c, (void*)i, c->width, c->height, true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); - if (c->data.css.import_content[i] && - c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) + c->data.css.import_content[i] = fetchcache(c->data.css.import_url[i], + css_atimport_callback, c, (void *) i, + c->width, c->height, true, 0, 0, false); + if (c->data.css.import_content[i]) { c->active++; + fetchcache_go(c->data.css.import_content[i], c->url, + css_atimport_callback, c, (void *) i, + 0, 0, false); + } free(url); } @@ -625,18 +621,17 @@ void css_atimport_callback(content_msg msg, struct content *css, return; } c->data.css.import_content[i] = fetchcache( - c->data.css.import_url[i], c->url, css_atimport_callback, - c, (void*)i, css->width, css->height, true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); - if (c->data.css.import_content[i] && - c->data.css.import_content[i]->status != CONTENT_STATUS_DONE) + c->data.css.import_url[i], + css_atimport_callback, c, (void *) i, + css->width, css->height, true, 0, 0, + false); + if (c->data.css.import_content[i]) { c->active++; + fetchcache_go(c->data.css.import_content[i], + c->url, css_atimport_callback, + c, (void *) i, + 0, 0, false); + } break; default: diff --git a/desktop/browser.c b/desktop/browser.c index 2c8c28441..499d07997 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -152,7 +152,8 @@ void browser_window_go_post(struct browser_window *bw, const char *url, { struct content *c; char *url2; - union content_msg_data data; + + LOG(("bw %p, url %s", bw, url)); url2 = url_normalize(url); if (!url2) { @@ -165,36 +166,21 @@ void browser_window_go_post(struct browser_window *bw, const char *url, browser_window_set_status(bw, messages_get("Loading")); bw->history_add = history_add; bw->time0 = clock(); - if (strncmp(url2, "about:", 6) == 0) { - c = about_create(url2, browser_window_callback, bw, 0, - gui_window_get_width(bw->window), 0); - } - else { - c = fetchcache(url2, 0, - browser_window_callback, bw, 0, - gui_window_get_width(bw->window), 0, - false, - post_urlenc, post_multipart, - true); - } + c = fetchcache(url2, browser_window_callback, bw, 0, + gui_window_get_width(bw->window), 0, + false, + post_urlenc, post_multipart, true); free(url2); if (!c) { - browser_window_set_status(bw, messages_get("FetchFailed")); + browser_window_set_status(bw, messages_get("NoMemory")); + warn_user("NoMemory", 0); return; } bw->loading_content = c; browser_window_start_throbber(bw); - if (c->status == CONTENT_STATUS_READY) { - browser_window_callback(CONTENT_MSG_READY, c, bw, 0, data); - - } else if (c->status == CONTENT_STATUS_DONE) { - browser_window_callback(CONTENT_MSG_READY, c, bw, 0, data); - if (c->type == CONTENT_OTHER) - download_window_callback(CONTENT_MSG_DONE, c, bw, 0, data); - else - browser_window_callback(CONTENT_MSG_DONE, c, bw, 0, data); - } + fetchcache_go(c, 0, browser_window_callback, bw, 0, + post_urlenc, post_multipart, true); } diff --git a/render/html.c b/render/html.c index 0f8a87a8a..c3e94bd15 100644 --- a/render/html.c +++ b/render/html.c @@ -313,19 +313,13 @@ void html_find_stylesheets(struct content *c, xmlNode *head) #else "file:///home/james/Projects/netsurf/CSS", #endif - c->url, - html_convert_css_callback, - c, 0, c->width, c->height, true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); - assert(c->data.html.stylesheet_content[0] != 0); - if (c->data.html.stylesheet_content[0]->status != CONTENT_STATUS_DONE) - c->active++; + html_convert_css_callback, c, 0, + c->width, c->height, true, 0, 0, false); + assert(c->data.html.stylesheet_content[0]); + c->active++; + fetchcache_go(c->data.html.stylesheet_content[0], 0, + html_convert_css_callback, c, 0, + 0, 0, false); for (node = head == 0 ? 0 : head->children; node != 0; node = node->next) { if (node->type != XML_ELEMENT_NODE) @@ -377,19 +371,18 @@ void html_find_stylesheets(struct content *c, xmlNode *head) /* start fetch */ c->data.html.stylesheet_content = xrealloc(c->data.html.stylesheet_content, (i + 1) * sizeof(*c->data.html.stylesheet_content)); - c->data.html.stylesheet_content[i] = fetchcache(url, c->url, - html_convert_css_callback, c, (void*)i, - c->width, c->height, true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); - if (c->data.html.stylesheet_content[i] && - c->data.html.stylesheet_content[i]->status != CONTENT_STATUS_DONE) + c->data.html.stylesheet_content[i] = fetchcache(url, + html_convert_css_callback, + c, (void *) i, c->width, c->height, + true, 0, 0, false); + if (c->data.html.stylesheet_content[i]) { c->active++; + fetchcache_go(c->data.html.stylesheet_content[i], + c->url, + html_convert_css_callback, + c, (void *) i, + 0, 0, false); + } free(url); i++; @@ -418,19 +411,27 @@ void html_find_stylesheets(struct content *c, xmlNode *head) if (c->data.html.stylesheet_content[1] == 0) { const char *params[] = { 0 }; c->data.html.stylesheet_content[1] = - content_create(c->data.html.base_url); + content_create(c->data.html. + base_url); if (!c->data.html.stylesheet_content[1]) - return; - content_set_type(c->data.html.stylesheet_content[1], - CONTENT_CSS, "text/css", params); + return false; + if (!content_set_type(c->data.html. + stylesheet_content[1], + CONTENT_CSS, "text/css", + params)) + return false; } /* can't just use xmlNodeGetContent(node), because that won't give * the content of comments which may be used to 'hide' the content */ for (node2 = node->children; node2 != 0; node2 = node2->next) { data = xmlNodeGetContent(node2); - content_process_data(c->data.html.stylesheet_content[1], - data, strlen(data)); + if (!content_process_data(c->data.html. + stylesheet_content[1], + data, strlen(data))) { + xmlFree(data); + return false; + } xmlFree(data); } } @@ -441,8 +442,11 @@ void html_find_stylesheets(struct content *c, xmlNode *head) if (c->data.html.stylesheet_content[1] != 0) { if (css_convert(c->data.html.stylesheet_content[1], c->width, c->height)) { + content_add_user(c->data.html.stylesheet_content[1], + html_convert_css_callback, + c, (void *) 1); + } else { /* conversion failed */ - content_destroy(c->data.html.stylesheet_content[1]); c->data.html.stylesheet_content[1] = 0; } } @@ -512,19 +516,18 @@ void html_convert_css_callback(content_msg msg, struct content *css, case CONTENT_MSG_REDIRECT: c->active--; c->data.html.stylesheet_content[i] = fetchcache( - data.redirect, c->url, + data.redirect, html_convert_css_callback, - c, (void*)i, css->width, css->height, true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); - if (c->data.html.stylesheet_content[i] != 0 && - c->data.html.stylesheet_content[i]->status != CONTENT_STATUS_DONE) + c, (void *) i, css->width, css->height, + true, 0, 0, false); + if (c->data.html.stylesheet_content[i]) { c->active++; + fetchcache_go(c->data.html.stylesheet_content[i], + c->url, + html_convert_css_callback, + c, (void *) i, + 0, 0, false); + } break; #ifdef WITH_AUTH @@ -560,7 +563,6 @@ void html_fetch_object(struct content *c, char *url, struct box *box, bool background) { unsigned int i = c->data.html.object_count; - union content_msg_data data; /* add to object list */ c->data.html.object = xrealloc(c->data.html.object, @@ -571,23 +573,14 @@ void html_fetch_object(struct content *c, char *url, struct box *box, c->data.html.object[i].background = background; /* start fetch */ - c->data.html.object[i].content = fetchcache(url, c->url, - html_object_callback, - c, (void*)i, available_width, available_height, - true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); - + c->data.html.object[i].content = fetchcache(url, html_object_callback, + c, (void *) i, available_width, available_height, + true, 0, 0, false); if (c->data.html.object[i].content) { c->active++; - if (c->data.html.object[i].content->status == CONTENT_STATUS_DONE) - html_object_callback(CONTENT_MSG_DONE, - c->data.html.object[i].content, c, (void*)i, data); + fetchcache_go(c->data.html.object[i].content, c->url, + html_object_callback, c, (void *) i, + 0, 0, false); } c->data.html.object_count++; } @@ -623,8 +616,13 @@ void html_object_callback(content_msg msg, struct content *object, case CONTENT_MSG_READY: if (object->type == CONTENT_HTML) { - html_object_done(box, object, c->data.html.object[i].background); - content_reformat(c, c->available_width, 0); + html_object_done(box, object, + c->data.html.object[i].background); + if (c->status == CONTENT_STATUS_READY || + c->status == + CONTENT_STATUS_DONE) + content_reformat(c, + c->available_width, 0); } break; @@ -653,21 +651,15 @@ void html_object_callback(content_msg msg, struct content *object, free(c->data.html.object[i].url); c->data.html.object[i].url = xstrdup(data.redirect); c->data.html.object[i].content = fetchcache( - data.redirect, c->url, - html_object_callback, - c, (void*)i, 0, 0, true -#ifdef WITH_POST - , 0, 0 -#endif -#ifdef WITH_COOKIES - , false -#endif - ); + data.redirect, html_object_callback, + c, (void * ) i, 0, 0, true, 0, 0, + false); if (c->data.html.object[i].content) { c->active++; - if (c->data.html.object[i].content->status == CONTENT_STATUS_DONE) - html_object_callback(CONTENT_MSG_DONE, - c->data.html.object[i].content, c, (void*)i, data); + fetchcache_go(c->data.html.object[i].content, + c->url, html_object_callback, + c, (void * ) i, + 0, 0, false); } break;