[project @ 2004-06-10 23:55:23 by bursa]

Split fetchcache() into fetchcache() and fetchcache_go() to solve problems of callbacks being called before fetchcache() returns. Fix <style> breakage. Error handling fixes & improvements.

svn path=/import/netsurf/; revision=957
This commit is contained in:
James Bursa 2004-06-10 23:55:23 +00:00
parent d58147aa58
commit d938fe135b
7 changed files with 227 additions and 205 deletions

View File

@ -304,6 +304,7 @@ bool content_set_type(struct content *c, content_type type,
if (handler_map[type].create) { if (handler_map[type].create) {
if (!handler_map[type].create(c, params)) { if (!handler_map[type].create(c, params)) {
c->type = CONTENT_UNKNOWN;
c->status = CONTENT_STATUS_ERROR; c->status = CONTENT_STATUS_ERROR;
return false; return false;
} }

View File

@ -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 */ /* create the curl easy handle */
fetch->curl_handle = curl_easy_duphandle(fetch_blank_curl); fetch->curl_handle = curl_easy_duphandle(fetch_blank_curl);
if (!fetch->curl_handle) 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); codem = curl_multi_add_handle(curl_multi, fetch->curl_handle);
assert(codem == CURLM_OK || codem == CURLM_CALL_MULTI_PERFORM); 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; return fetch;
failed: failed:

View File

@ -36,18 +36,12 @@ static void fetchcache_error_page(struct content *c, const char *error);
/** /**
* Retrieve a URL or fetch, convert, and cache it. * Retrieve a URL or prepare to fetch, convert, and cache it.
*
* The referer may be 0.
* *
* The caller must supply a callback function which is called when anything * The caller must supply a callback function which is called when anything
* interesting happens to the content which is returned. See content.h. * 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 url address to fetch
* \param referer url of referring page, or 0 if none
* \param callback function to call when anything interesting happens to * \param callback function to call when anything interesting happens to
* the new content * the new content
* \param p1 user parameter for callback * \param p1 user parameter for callback
@ -59,27 +53,24 @@ static void fetchcache_error_page(struct content *c, const char *error);
* \param post_urlenc url encoded post data, or 0 if none * \param post_urlenc url encoded post data, or 0 if none
* \param post_multipart multipart post data, or 0 if none * \param post_multipart multipart post data, or 0 if none
* \param cookies send and accept cookies * \param cookies send and accept cookies
* \return a new content, or 0 if an error occurred * \return a new content, or 0 on memory exhaustion
*
* 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 (*callback)(content_msg msg, struct content *c, void *p1,
void *p2, union content_msg_data data), void *p2, union content_msg_data data),
void *p1, void *p2, unsigned long width, unsigned long height, void *p1, void *p2,
bool no_error_pages int width, int height,
#ifdef WITH_POST bool no_error_pages,
, char *post_urlenc, char *post_urlenc,
struct form_successful_control *post_multipart struct form_successful_control *post_multipart,
#endif bool cookies)
#ifdef WITH_COOKIES
,bool cookies
#endif
)
{ {
struct content *c; struct content *c;
char *url1; char *url1;
char *hash; char *hash;
char error_message[500];
url1 = strdup(url); url1 = strdup(url);
if (!url1) if (!url1)
@ -91,12 +82,9 @@ struct content * fetchcache(const char *url, char *referer,
LOG(("url %s", url1)); LOG(("url %s", url1));
#ifdef WITH_POST if (!post_urlenc && !post_multipart) {
if (!post_urlenc && !post_multipart)
#endif
{
c = cache_get(url1); c = cache_get(url1);
if (c != 0) { if (c) {
free(url1); free(url1);
content_add_user(c, callback, p1, p2); content_add_user(c, callback, p1, p2);
return c; return c;
@ -110,38 +98,96 @@ struct content * fetchcache(const char *url, char *referer,
} }
content_add_user(c, callback, p1, p2); content_add_user(c, callback, p1, p2);
#ifdef WITH_POST
if (!post_urlenc && !post_multipart) if (!post_urlenc && !post_multipart)
#endif
cache_put(c); cache_put(c);
c->width = width; c->width = width;
c->height = height; c->height = height;
c->no_error_pages = no_error_pages; 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; 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. * 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), if ((length = snprintf(error_page, sizeof(error_page),
messages_get("ErrorPage"), error)) < 0) messages_get("ErrorPage"), error)) < 0)
length = 0; length = 0;
content_set_type(c, CONTENT_HTML, "text/html", params); if (!content_set_type(c, CONTENT_HTML, "text/html", params))
content_process_data(c, error_page, length); return;
if (!content_process_data(c, error_page, length))
return;
content_convert(c, c->width, c->height); content_convert(c, c->width, c->height);
} }

View File

@ -2,40 +2,40 @@
* This file is part of NetSurf, http://netsurf.sourceforge.net/ * This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License, * Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license * http://www.opensource.org/licenses/gpl-license
* Copyright 2003 James Bursa <bursa@users.sourceforge.net> * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*/ */
/** \file /** \file
* High-level fetching, caching and conversion (interface). * High-level fetching, caching and conversion (interface).
* *
* The fetchcache() function retrieves a URL from the cache, or fetches, * The fetchcache() / fetchcache_go() pair of functions retrieve a URL from
* converts, and caches it if not cached. * the cache, or fetch, convert, and cache it if not cached.
*/ */
#ifndef _NETSURF_DESKTOP_FETCHCACHE_H_ #ifndef _NETSURF_DESKTOP_FETCHCACHE_H_
#define _NETSURF_DESKTOP_FETCHCACHE_H_ #define _NETSURF_DESKTOP_FETCHCACHE_H_
#include <stdbool.h> #include <stdbool.h>
#include "netsurf/utils/config.h"
#include "netsurf/content/content.h" #include "netsurf/content/content.h"
#ifdef WITH_POST
struct form_successful_control; 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 (*callback)(content_msg msg, struct content *c, void *p1,
void *p2, union content_msg_data data), void *p2, union content_msg_data data),
void *p1, void *p2, unsigned long width, unsigned long height, void *p1, void *p2,
bool no_error_pages int width, int height,
#ifdef WITH_POST bool no_error_pages,
, char *post_urlenc, char *post_urlenc,
struct form_successful_control *post_multipart struct form_successful_control *post_multipart,
#endif bool cookies);
#ifdef WITH_COOKIES void fetchcache_go(struct content *content, char *referer,
,bool cookies void (*callback)(content_msg msg, struct content *c, void *p1,
#endif void *p2, union content_msg_data data),
); void *p1, void *p2,
void fetchcache_init(void); char *post_urlenc,
struct form_successful_control *post_multipart,
bool cookies);
#endif #endif

View File

@ -560,19 +560,15 @@ void css_atimport(struct content *c, struct css_node *node)
c->data.css.import_count++; c->data.css.import_count++;
i = c->data.css.import_count - 1; i = c->data.css.import_count - 1;
c->data.css.import_url[i] = url1; c->data.css.import_url[i] = url1;
c->data.css.import_content[i] = fetchcache( c->data.css.import_content[i] = fetchcache(c->data.css.import_url[i],
c->data.css.import_url[i], c->url, css_atimport_callback, css_atimport_callback, c, (void *) i,
c, (void*)i, c->width, c->height, true c->width, c->height, true, 0, 0, false);
#ifdef WITH_POST if (c->data.css.import_content[i]) {
, 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->active++; c->active++;
fetchcache_go(c->data.css.import_content[i], c->url,
css_atimport_callback, c, (void *) i,
0, 0, false);
}
free(url); free(url);
} }
@ -625,18 +621,17 @@ void css_atimport_callback(content_msg msg, struct content *css,
return; return;
} }
c->data.css.import_content[i] = fetchcache( c->data.css.import_content[i] = fetchcache(
c->data.css.import_url[i], c->url, css_atimport_callback, c->data.css.import_url[i],
c, (void*)i, css->width, css->height, true css_atimport_callback, c, (void *) i,
#ifdef WITH_POST css->width, css->height, true, 0, 0,
, 0, 0 false);
#endif if (c->data.css.import_content[i]) {
#ifdef WITH_COOKIES
, false
#endif
);
if (c->data.css.import_content[i] &&
c->data.css.import_content[i]->status != CONTENT_STATUS_DONE)
c->active++; c->active++;
fetchcache_go(c->data.css.import_content[i],
c->url, css_atimport_callback,
c, (void *) i,
0, 0, false);
}
break; break;
default: default:

View File

@ -152,7 +152,8 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
{ {
struct content *c; struct content *c;
char *url2; char *url2;
union content_msg_data data;
LOG(("bw %p, url %s", bw, url));
url2 = url_normalize(url); url2 = url_normalize(url);
if (!url2) { 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")); browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = history_add; bw->history_add = history_add;
bw->time0 = clock(); bw->time0 = clock();
if (strncmp(url2, "about:", 6) == 0) { c = fetchcache(url2, browser_window_callback, bw, 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, gui_window_get_width(bw->window), 0,
false, false,
post_urlenc, post_multipart, post_urlenc, post_multipart, true);
true);
}
free(url2); free(url2);
if (!c) { if (!c) {
browser_window_set_status(bw, messages_get("FetchFailed")); browser_window_set_status(bw, messages_get("NoMemory"));
warn_user("NoMemory", 0);
return; return;
} }
bw->loading_content = c; bw->loading_content = c;
browser_window_start_throbber(bw); browser_window_start_throbber(bw);
if (c->status == CONTENT_STATUS_READY) { fetchcache_go(c, 0, browser_window_callback, bw, 0,
browser_window_callback(CONTENT_MSG_READY, c, bw, 0, data); post_urlenc, post_multipart, true);
} 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);
}
} }

View File

@ -313,19 +313,13 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
#else #else
"file:///home/james/Projects/netsurf/CSS", "file:///home/james/Projects/netsurf/CSS",
#endif #endif
c->url, html_convert_css_callback, c, 0,
html_convert_css_callback, c->width, c->height, true, 0, 0, false);
c, 0, c->width, c->height, true assert(c->data.html.stylesheet_content[0]);
#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++; 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) { for (node = head == 0 ? 0 : head->children; node != 0; node = node->next) {
if (node->type != XML_ELEMENT_NODE) if (node->type != XML_ELEMENT_NODE)
@ -377,19 +371,18 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
/* start fetch */ /* start fetch */
c->data.html.stylesheet_content = xrealloc(c->data.html.stylesheet_content, c->data.html.stylesheet_content = xrealloc(c->data.html.stylesheet_content,
(i + 1) * sizeof(*c->data.html.stylesheet_content)); (i + 1) * sizeof(*c->data.html.stylesheet_content));
c->data.html.stylesheet_content[i] = fetchcache(url, c->url, c->data.html.stylesheet_content[i] = fetchcache(url,
html_convert_css_callback, c, (void*)i, html_convert_css_callback,
c->width, c->height, true c, (void *) i, c->width, c->height,
#ifdef WITH_POST true, 0, 0, false);
, 0, 0 if (c->data.html.stylesheet_content[i]) {
#endif
#ifdef WITH_COOKIES
, false
#endif
);
if (c->data.html.stylesheet_content[i] &&
c->data.html.stylesheet_content[i]->status != CONTENT_STATUS_DONE)
c->active++; c->active++;
fetchcache_go(c->data.html.stylesheet_content[i],
c->url,
html_convert_css_callback,
c, (void *) i,
0, 0, false);
}
free(url); free(url);
i++; i++;
@ -418,19 +411,27 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
if (c->data.html.stylesheet_content[1] == 0) { if (c->data.html.stylesheet_content[1] == 0) {
const char *params[] = { 0 }; const char *params[] = { 0 };
c->data.html.stylesheet_content[1] = 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]) if (!c->data.html.stylesheet_content[1])
return; return false;
content_set_type(c->data.html.stylesheet_content[1], if (!content_set_type(c->data.html.
CONTENT_CSS, "text/css", params); stylesheet_content[1],
CONTENT_CSS, "text/css",
params))
return false;
} }
/* can't just use xmlNodeGetContent(node), because that won't give /* can't just use xmlNodeGetContent(node), because that won't give
* the content of comments which may be used to 'hide' the content */ * the content of comments which may be used to 'hide' the content */
for (node2 = node->children; node2 != 0; node2 = node2->next) { for (node2 = node->children; node2 != 0; node2 = node2->next) {
data = xmlNodeGetContent(node2); data = xmlNodeGetContent(node2);
content_process_data(c->data.html.stylesheet_content[1], if (!content_process_data(c->data.html.
data, strlen(data)); stylesheet_content[1],
data, strlen(data))) {
xmlFree(data);
return false;
}
xmlFree(data); xmlFree(data);
} }
} }
@ -441,8 +442,11 @@ void html_find_stylesheets(struct content *c, xmlNode *head)
if (c->data.html.stylesheet_content[1] != 0) { if (c->data.html.stylesheet_content[1] != 0) {
if (css_convert(c->data.html.stylesheet_content[1], c->width, if (css_convert(c->data.html.stylesheet_content[1], c->width,
c->height)) { c->height)) {
content_add_user(c->data.html.stylesheet_content[1],
html_convert_css_callback,
c, (void *) 1);
} else {
/* conversion failed */ /* conversion failed */
content_destroy(c->data.html.stylesheet_content[1]);
c->data.html.stylesheet_content[1] = 0; 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: case CONTENT_MSG_REDIRECT:
c->active--; c->active--;
c->data.html.stylesheet_content[i] = fetchcache( c->data.html.stylesheet_content[i] = fetchcache(
data.redirect, c->url, data.redirect,
html_convert_css_callback, html_convert_css_callback,
c, (void*)i, css->width, css->height, true c, (void *) i, css->width, css->height,
#ifdef WITH_POST true, 0, 0, false);
, 0, 0 if (c->data.html.stylesheet_content[i]) {
#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->active++; c->active++;
fetchcache_go(c->data.html.stylesheet_content[i],
c->url,
html_convert_css_callback,
c, (void *) i,
0, 0, false);
}
break; break;
#ifdef WITH_AUTH #ifdef WITH_AUTH
@ -560,7 +563,6 @@ void html_fetch_object(struct content *c, char *url, struct box *box,
bool background) bool background)
{ {
unsigned int i = c->data.html.object_count; unsigned int i = c->data.html.object_count;
union content_msg_data data;
/* add to object list */ /* add to object list */
c->data.html.object = xrealloc(c->data.html.object, 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; c->data.html.object[i].background = background;
/* start fetch */ /* start fetch */
c->data.html.object[i].content = fetchcache(url, c->url, c->data.html.object[i].content = fetchcache(url, html_object_callback,
html_object_callback, c, (void *) i, available_width, available_height,
c, (void*)i, available_width, available_height, true, 0, 0, false);
true
#ifdef WITH_POST
, 0, 0
#endif
#ifdef WITH_COOKIES
, false
#endif
);
if (c->data.html.object[i].content) { if (c->data.html.object[i].content) {
c->active++; c->active++;
if (c->data.html.object[i].content->status == CONTENT_STATUS_DONE) fetchcache_go(c->data.html.object[i].content, c->url,
html_object_callback(CONTENT_MSG_DONE, html_object_callback, c, (void *) i,
c->data.html.object[i].content, c, (void*)i, data); 0, 0, false);
} }
c->data.html.object_count++; c->data.html.object_count++;
} }
@ -623,8 +616,13 @@ void html_object_callback(content_msg msg, struct content *object,
case CONTENT_MSG_READY: case CONTENT_MSG_READY:
if (object->type == CONTENT_HTML) { if (object->type == CONTENT_HTML) {
html_object_done(box, object, c->data.html.object[i].background); html_object_done(box, object,
content_reformat(c, c->available_width, 0); 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; break;
@ -653,21 +651,15 @@ void html_object_callback(content_msg msg, struct content *object,
free(c->data.html.object[i].url); free(c->data.html.object[i].url);
c->data.html.object[i].url = xstrdup(data.redirect); c->data.html.object[i].url = xstrdup(data.redirect);
c->data.html.object[i].content = fetchcache( c->data.html.object[i].content = fetchcache(
data.redirect, c->url, data.redirect, html_object_callback,
html_object_callback, c, (void * ) i, 0, 0, true, 0, 0,
c, (void*)i, 0, 0, true false);
#ifdef WITH_POST
, 0, 0
#endif
#ifdef WITH_COOKIES
, false
#endif
);
if (c->data.html.object[i].content) { if (c->data.html.object[i].content) {
c->active++; c->active++;
if (c->data.html.object[i].content->status == CONTENT_STATUS_DONE) fetchcache_go(c->data.html.object[i].content,
html_object_callback(CONTENT_MSG_DONE, c->url, html_object_callback,
c->data.html.object[i].content, c, (void*)i, data); c, (void * ) i,
0, 0, false);
} }
break; break;