summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2009-12-17 23:55:02 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2009-12-17 23:55:02 +0000
commit355799ce0bbb078237dfc1ae9874bbc5342acbc4 (patch)
tree7ca980c01c0d4d1d55a3b7b15418c95c5618afae /content
parent4346b2b62b940182575e6612e46234355afa083c (diff)
downloadnetsurf-355799ce0bbb078237dfc1ae9874bbc5342acbc4.tar.gz
netsurf-355799ce0bbb078237dfc1ae9874bbc5342acbc4.tar.bz2
Merge branches/MarkieB/gtkmain to trunk.
svn path=/trunk/netsurf/; revision=9729
Diffstat (limited to 'content')
-rw-r--r--content/content.c3
-rw-r--r--content/fetch.c4
-rw-r--r--content/fetch.h18
-rw-r--r--content/fetchcache.c127
-rw-r--r--content/fetchers/fetch_curl.c50
-rw-r--r--content/fetchers/fetch_data.c28
6 files changed, 161 insertions, 69 deletions
diff --git a/content/content.c b/content/content.c
index e00f3bcd6..8b6cfd47d 100644
--- a/content/content.c
+++ b/content/content.c
@@ -155,6 +155,9 @@ static const struct mime_entry mime_map[] = {
{"image/svg", CONTENT_SVG},
{"image/svg+xml", CONTENT_SVG},
#endif
+#ifdef WITH_BMP
+ {"image/vnd.microsoft.icon", CONTENT_ICO},
+#endif
#ifdef WITH_ARTWORKS
{"image/x-artworks", CONTENT_ARTWORKS},
#endif
diff --git a/content/fetch.c b/content/fetch.c
index a1417fee9..4fdeffb3d 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -601,11 +601,11 @@ bool fetch_get_verifiable(struct fetch *fetch)
void
fetch_send_callback(fetch_msg msg, struct fetch *fetch, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
/*LOG(("Fetcher sending callback. Fetch %p, fetcher %p data %p size %lu",
fetch, fetch->fetcher_handle, data, size)); */
- fetch->callback(msg, fetch->p, data, size);
+ fetch->callback(msg, fetch->p, data, size, errorcode);
}
diff --git a/content/fetch.h b/content/fetch.h
index 3206acc39..2666b8ffc 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -40,6 +40,19 @@ typedef enum {
FETCH_CERT_ERR,
} fetch_msg;
+typedef enum {
+ FETCH_ERROR_NO_ERROR,
+ FETCH_ERROR_CERT,
+ FETCH_ERROR_AUTHENTICATION,
+ FETCH_ERROR_HTTP_NOT2,
+ FETCH_ERROR_COULDNT_RESOLVE_HOST,
+ FETCH_ERROR_PARTIAL_FILE,
+ FETCH_ERROR_MEMORY,
+ FETCH_ERROR_URL,
+ FETCH_ERROR_ENCODING,
+ FETCH_ERROR_MISC
+} fetch_error_code;
+
struct content;
struct fetch;
struct form_successful_control;
@@ -58,7 +71,7 @@ struct ssl_cert_info {
extern bool fetch_active;
typedef void (*fetch_callback)(fetch_msg msg, void *p, const void *data,
- unsigned long size);
+ unsigned long size, fetch_error_code errorcode);
void fetch_init(void);
@@ -105,7 +118,8 @@ bool fetch_add_fetcher(const char *scheme,
fetcher_finalise finaliser);
void fetch_send_callback(fetch_msg msg, struct fetch *fetch,
- const void *data, unsigned long size);
+ const void *data, unsigned long size,
+ fetch_error_code errorcode);
void fetch_remove_from_queues(struct fetch *fetch);
void fetch_free(struct fetch *f);
void fetch_set_http_code(struct fetch *fetch, long http_code);
diff --git a/content/fetchcache.c b/content/fetchcache.c
index 8643cc1a2..87732d49e 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -38,6 +38,8 @@
#include "content/content.h"
#include "content/fetchcache.h"
#include "content/fetch.h"
+#include "desktop/options.h"
+#include "desktop/searchweb.h"
#include "content/urldb.h"
#include "utils/log.h"
#include "utils/messages.h"
@@ -49,17 +51,23 @@
static char error_page[1000];
static regex_t re_content_type;
static void fetchcache_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size);
+ unsigned long size, fetch_error_code errorcode);
static char *fetchcache_parse_type(const char *s, char **params[]);
static void fetchcache_parse_header(struct content *c, const char *data,
size_t size);
-static void fetchcache_error_page(struct content *c, const char *error);
+static void fetchcache_error_page(struct content *c, const char *error,
+ fetch_error_code errorcode);
+static void fetchcache_search_redirect(struct content *c, const char *error);
static void fetchcache_cache_update(struct content *c);
static void fetchcache_cache_clone(struct content *c,
const struct cache_data *data);
static void fetchcache_notmodified(struct content *c, const void *data);
static void fetchcache_redirect(struct content *c, const void *data,
unsigned long size);
+static void fetchcache_redirect_common(struct content *c, bool verifiable,
+ const char *url, const char *referer,
+ struct content *parent);
+
static void fetchcache_auth(struct content *c, const char *realm);
@@ -276,7 +284,8 @@ void fetchcache_go(struct content *content, const char *referer,
callback(CONTENT_MSG_ERROR,
content, p1, p2, msg_data);
} else {
- fetchcache_error_page(content, error_message);
+ fetchcache_error_page(content, error_message,
+ FETCH_ERROR_NO_ERROR);
}
return;
@@ -366,7 +375,8 @@ void fetchcache_go(struct content *content, const char *referer,
content_broadcast(content, CONTENT_MSG_ERROR,
msg_data);
} else {
- fetchcache_error_page(content, error_message);
+ fetchcache_error_page(content, error_message,
+ FETCH_ERROR_NO_ERROR);
}
}
@@ -405,7 +415,7 @@ void fetchcache_go(struct content *content, const char *referer,
*/
void fetchcache_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
bool res;
struct content *c = p;
@@ -506,7 +516,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const void *data,
msg_data);
} else {
content_reset(c);
- fetchcache_error_page(c, data);
+ fetchcache_error_page(c, data, errorcode);
}
break;
@@ -721,17 +731,29 @@ void fetchcache_parse_header(struct content *c, const char *data,
/**
- * Generate an error page.
- *
+ * Generate an error page. Optionally redirect to web search provider
* \param c empty content to generate the page in
* \param error message to display
*/
-void fetchcache_error_page(struct content *c, const char *error)
+void fetchcache_error_page(struct content *c, const char *error,
+ fetch_error_code errorcode)
{
const char *params[] = { 0 };
int length;
-
+ char *host;
+
+ if (option_search_url_bar) {
+ if (url_host(c->url, &host) != URL_FUNC_OK) {
+ warn_user(messages_get("NoMemory"), 0);
+ } else if ((strcasecmp(host, search_web_provider_host())
+ != 0) && (errorcode ==
+ FETCH_ERROR_COULDNT_RESOLVE_HOST)) {
+ fetchcache_search_redirect(c, error);
+ free(host);
+ return;
+ }
+ }
if ((length = snprintf(error_page, sizeof(error_page),
messages_get("ErrorPage"), error)) < 0)
length = 0;
@@ -746,6 +768,27 @@ void fetchcache_error_page(struct content *c, const char *error)
c->fresh = false;
}
+void fetchcache_search_redirect(struct content *c, const char *error)
+{
+ char *redirurl, *temp;
+
+ /* clear http:// plus trailing / from url, it is already escaped */
+ temp = strdup(c->url + SLEN("http://"));
+ if (temp == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ temp[strlen(temp)-1] = '\0';
+ redirurl = search_web_get_url(temp);
+ if (redirurl == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+
+ fetchcache_redirect_common(c, false, redirurl, NULL, c);
+ free(redirurl);
+ return;
+}
/**
* Update a content's cache state
@@ -930,7 +973,6 @@ void fetchcache_redirect(struct content *c, const void *data,
long http_code;
const char *ref;
struct content *parent;
- bool can_fetch;
bool parent_was_verifiable;
union content_msg_data msg_data;
url_func_result result;
@@ -1056,32 +1098,50 @@ void fetchcache_redirect(struct content *c, const void *data,
}
free(scheme);
-
- /* Determine if we've got a fetch handler for this url */
- can_fetch = fetch_can_fetch(url);
+ fetchcache_redirect_common(c, parent_was_verifiable, url, referer, parent);
+ free(url);
+ free(referer);
+}
+
+/**
+ * common logic from fetchcache_redirect() / fetchcache_search_redirect()
+ * \param c the content param from the original function
+ * \param verifiable parent_was_verifiable [false for search_redirect]
+ * \param url the url being considered; caller retains ownership
+ * \param referer referer [ / NULL particularly for search_redirect]
+ * \param parent parent content [ / c for search_redirect]
+ */
+void fetchcache_redirect_common(struct content *c, bool verifiable,
+ const char *url, const char *referer, struct content *parent)
+{
+ union content_msg_data msg_data;
+ bool can_fetch;
+ /* check there's a fetch handler */
+ can_fetch = fetch_can_fetch(url);
+
/* Process users of this content */
while (c->user_list->next) {
intptr_t p1, p2;
void (*callback)(content_msg msg,
- struct content *c, intptr_t p1,
- intptr_t p2,
- union content_msg_data data);
+ struct content *c, intptr_t p1,
+ intptr_t p2,
+ union content_msg_data data);
struct content *replacement;
-
+
p1 = c->user_list->next->p1;
p2 = c->user_list->next->p2;
callback = c->user_list->next->callback;
-
+
/* If we can't fetch this url, attempt to launch it */
if (!can_fetch) {
msg_data.launch_url = url;
callback(CONTENT_MSG_LAUNCH, c, p1, p2, msg_data);
}
-
+
/* Remove user */
content_remove_user(c, callback, p1, p2);
-
+
if (can_fetch) {
/* Get replacement content -- HTTP GET request */
@@ -1101,37 +1161,29 @@ void fetchcache_redirect(struct content *c, const void *data,
*/
replacement = fetchcache(url, callback, p1, p2,
c->width, c->height, c->no_error_pages,
- NULL, NULL, parent_was_verifiable,
+ NULL, NULL, verifiable,
c->download);
if (!replacement) {
msg_data.error = messages_get("BadRedirect");
content_broadcast(c, CONTENT_MSG_ERROR,
msg_data);
-
- free(url);
- free(referer);
return;
- }
-
+ }
/* Set replacement's redirect count to 1 greater
* than ours */
replacement->redirect_count = c->redirect_count + 1;
-
+
/* Notify user that content has changed */
msg_data.new_url = url;
callback(CONTENT_MSG_NEWPTR, replacement,
- p1, p2, msg_data);
-
+ p1, p2, msg_data);
+
/* Start fetching the replacement content */
fetchcache_go(replacement, referer, callback, p1, p2,
- c->width, c->height, NULL, NULL,
- parent_was_verifiable, parent);
+ c->width, c->height, NULL, NULL,
+ verifiable, parent);
}
}
-
- /* Clean up */
- free(url);
- free(referer);
}
/**
@@ -1218,7 +1270,8 @@ void fetchcache_auth(struct content *c, const char *realm)
msg_data.error = error_message;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
} else {
- fetchcache_error_page(c, error_message);
+ fetchcache_error_page(c, error_message,
+ FETCH_ERROR_URL);
}
}
diff --git a/content/fetchers/fetch_curl.c b/content/fetchers/fetch_curl.c
index 8efe0d726..67b74ef99 100644
--- a/content/fetchers/fetch_curl.c
+++ b/content/fetchers/fetch_curl.c
@@ -748,6 +748,7 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
{
bool finished = false;
bool error = false;
+ fetch_error_code errorcode = FETCH_ERROR_NO_ERROR;
bool cert = false;
bool abort_fetch;
struct curl_fetch_info *f;
@@ -778,8 +779,10 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
* Content-Length header. */
if (!f->had_headers && fetch_curl_process_headers(f))
; /* redirect with partial body, or similar */
- else
+ else {
error = true;
+ errorcode = FETCH_ERROR_PARTIAL_FILE;
+ }
} else if (result == CURLE_WRITE_ERROR && f->stopped)
/* CURLE_WRITE_ERROR occurs when fetch_curl_data
* returns 0, which we use to abort intentionally */
@@ -790,9 +793,14 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
memset(f->cert_data, 0, sizeof(f->cert_data));
cert = true;
}
+ else if (result == CURLE_COULDNT_RESOLVE_HOST) {
+ error = true;
+ errorcode = FETCH_ERROR_COULDNT_RESOLVE_HOST;
+ }
else {
LOG(("Unknown cURL response code %d", result));
error = true;
+ errorcode = FETCH_ERROR_MISC;
}
fetch_curl_stop(f);
@@ -800,7 +808,7 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
if (abort_fetch)
; /* fetch was aborted: no callback */
else if (finished)
- fetch_send_callback(FETCH_FINISHED, f->fetch_handle, 0, 0);
+ fetch_send_callback(FETCH_FINISHED, f->fetch_handle, 0, 0, errorcode);
else if (cert) {
int i;
BIO *mem;
@@ -877,14 +885,14 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
if (certs[i].cert->references == 0)
X509_free(certs[i].cert);
}
-
+ errorcode = FETCH_ERROR_CERT;
fetch_send_callback(FETCH_CERT_ERR, f->fetch_handle,
- &ssl_certs, i);
+ &ssl_certs, i, errorcode);
}
else if (error)
fetch_send_callback(FETCH_ERROR, f->fetch_handle,
- fetch_error_buffer, 0);
+ fetch_error_buffer, 0, errorcode);
fetch_free(f->fetch_handle);
}
@@ -910,14 +918,16 @@ int fetch_curl_progress(void *clientp, double dltotal, double dlnow,
human_friendly_bytesize(dlnow),
human_friendly_bytesize(dltotal));
fetch_send_callback(FETCH_PROGRESS, f->fetch_handle,
- fetch_progress_buffer,
- (unsigned long) percent);
+ fetch_progress_buffer,
+ (unsigned long) percent,
+ FETCH_ERROR_NO_ERROR);
} else {
snprintf(fetch_progress_buffer, 255,
messages_get("ProgressU"),
human_friendly_bytesize(dlnow));
fetch_send_callback(FETCH_PROGRESS, f->fetch_handle,
- fetch_progress_buffer, 0);
+ fetch_progress_buffer, 0,
+ FETCH_ERROR_NO_ERROR);
}
return 0;
@@ -977,7 +987,8 @@ size_t fetch_curl_data(char *data, size_t size, size_t nmemb,
/* send data to the caller */
/*LOG(("FETCH_DATA"));*/
- fetch_send_callback(FETCH_DATA, f->fetch_handle, data, size * nmemb);
+ fetch_send_callback(FETCH_DATA, f->fetch_handle, data, size * nmemb,
+ FETCH_ERROR_NO_ERROR);
if (f->abort) {
f->stopped = true;
@@ -1006,7 +1017,8 @@ size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
return 0;
}
- fetch_send_callback(FETCH_HEADER, f->fetch_handle, data, size);
+ fetch_send_callback(FETCH_HEADER, f->fetch_handle, data, size,
+ FETCH_ERROR_NO_ERROR);
#define SKIP_ST(o) for (i = (o); i < (int) size && (data[i] == ' ' || data[i] == '\t'); i++)
@@ -1100,20 +1112,23 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
if (http_code == 304 && !f->post_urlenc && !f->post_multipart) {
/* Not Modified && GET request */
- fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle, 0, 0);
+ fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle, 0, 0,
+ FETCH_ERROR_NO_ERROR);
return true;
}
/* handle HTTP redirects (3xx response codes) */
if (300 <= http_code && http_code < 400 && f->location != 0) {
LOG(("FETCH_REDIRECT, '%s'", f->location));
- fetch_send_callback(FETCH_REDIRECT, f->fetch_handle, f->location, 0);
+ fetch_send_callback(FETCH_REDIRECT, f->fetch_handle,
+ f->location, 0, FETCH_ERROR_NO_ERROR);
return true;
}
/* handle HTTP 401 (Authentication errors) */
if (http_code == 401) {
- fetch_send_callback(FETCH_AUTH, f->fetch_handle, f->realm,0);
+ fetch_send_callback(FETCH_AUTH, f->fetch_handle, f->realm,0,
+ FETCH_ERROR_AUTHENTICATION);
return true;
}
@@ -1121,7 +1136,8 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
if (f->only_2xx && strncmp(f->url, "http", 4) == 0 &&
(http_code < 200 || 299 < http_code)) {
fetch_send_callback(FETCH_ERROR, f->fetch_handle,
- messages_get("Not2xx"), 0);
+ messages_get("Not2xx"), 0,
+ FETCH_ERROR_HTTP_NOT2);
return true;
}
@@ -1141,7 +1157,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
"ETag: \"%10d\"", (int) s.st_mtime);
/* And send it to the header handler */
fetch_send_callback(FETCH_HEADER, f->fetch_handle, etag_buf,
- strlen(etag_buf));
+ strlen(etag_buf), FETCH_ERROR_NO_ERROR);
/* don't set last modified time so as to ensure that local
* files are revalidated at all times. */
@@ -1151,7 +1167,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
f->last_modified > s.st_mtime &&
f->file_etag == s.st_mtime) {
fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle,
- 0, 0);
+ 0, 0, FETCH_ERROR_NO_ERROR);
curl_free(url_path);
return true;
}
@@ -1167,7 +1183,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
curl_free(url_path);
LOG(("FETCH_TYPE, '%s'", type));
- fetch_send_callback(FETCH_TYPE, f->fetch_handle, type, f->content_length);
+ fetch_send_callback(FETCH_TYPE, f->fetch_handle, type, f->content_length, FETCH_ERROR_NO_ERROR);
if (f->abort)
return true;
diff --git a/content/fetchers/fetch_data.c b/content/fetchers/fetch_data.c
index 30274f51e..5b40b4ef6 100644
--- a/content/fetchers/fetch_data.c
+++ b/content/fetchers/fetch_data.c
@@ -129,10 +129,10 @@ static void fetch_data_abort(void *ctx)
static void fetch_data_send_callback(fetch_msg msg,
struct fetch_data_context *c, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
c->locked = true;
- fetch_send_callback(msg, c->parent_fetch, data, size);
+ fetch_send_callback(msg, c->parent_fetch, data, size, errorcode);
c->locked = false;
}
@@ -154,7 +154,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
if (strlen(c->url) < 6) {
/* 6 is the minimum possible length (data:,) */
fetch_data_send_callback(FETCH_ERROR, c,
- "Malformed data: URL", 0);
+ "Malformed data: URL", 0, FETCH_ERROR_URL);
return false;
}
@@ -164,7 +164,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
/* find the comma */
if ( (comma = strchr(params, ',')) == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Malformed data: URL", 0);
+ "Malformed data: URL", 0, FETCH_ERROR_URL);
return false;
}
@@ -179,7 +179,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
if (c->mimetype == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
"Unable to allocate memory for mimetype in data: URL",
- 0);
+ 0, FETCH_ERROR_MEMORY);
return false;
}
@@ -198,7 +198,8 @@ static bool fetch_data_process(struct fetch_data_context *c)
c->datalen = templen;
if (unescaped == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Unable to URL decode data: URL", 0);
+ "Unable to URL decode data: URL", 0,
+ FETCH_ERROR_ENCODING);
return false;
}
@@ -207,7 +208,8 @@ static bool fetch_data_process(struct fetch_data_context *c)
if (base64_decode(unescaped, c->datalen, c->data,
&(c->datalen)) == false) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Unable to Base64 decode data: URL", 0);
+ "Unable to Base64 decode data: URL", 0,
+ FETCH_ERROR_ENCODING);
curl_free(unescaped);
return false;
}
@@ -215,7 +217,8 @@ static bool fetch_data_process(struct fetch_data_context *c)
c->data = malloc(c->datalen);
if (c->data == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Unable to allocate memory for data: URL", 0);
+ "Unable to allocate memory for data: URL", 0,
+ FETCH_ERROR_MEMORY);
curl_free(unescaped);
return false;
}
@@ -271,14 +274,17 @@ static void fetch_data_poll(const char *scheme)
* call to fetch_data_send_callback().
*/
fetch_data_send_callback(FETCH_TYPE,
- c, c->mimetype, c->datalen);
+ c, c->mimetype, c->datalen,
+ FETCH_ERROR_NO_ERROR);
if (!c->aborted) {
fetch_data_send_callback(FETCH_DATA,
- c, c->data, c->datalen);
+ c, c->data, c->datalen,
+ FETCH_ERROR_NO_ERROR);
}
if (!c->aborted) {
fetch_data_send_callback(FETCH_FINISHED,
- c, &cachedata, 0);
+ c, &cachedata, 0,
+ FETCH_ERROR_NO_ERROR);
}
} else {
LOG(("Processing of %s failed!", c->url));