From f18bbd48c7265ef68e8559f20a74bd1b57a4d1cb Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 17 Oct 2012 21:52:43 +0100 Subject: Improve error handling in html content --- content/content.h | 5 +- desktop/browser.c | 119 ++++++++++++++++++++++++++++++++++++++++ render/html.c | 158 +++++++++++++++++++++++++++++++++++------------------- render/imagemap.c | 19 ++++--- render/imagemap.h | 2 +- utils/errors.h | 16 +++++- 6 files changed, 255 insertions(+), 64 deletions(-) diff --git a/content/content.h b/content/content.h index b07af4fe1..649f54dfa 100644 --- a/content/content.h +++ b/content/content.h @@ -67,6 +67,7 @@ typedef enum { CONTENT_MSG_READY, /**< may be displayed */ CONTENT_MSG_DONE, /**< finished */ CONTENT_MSG_ERROR, /**< error occurred */ + CONTENT_MSG_ERRORCODE, /**< error occurred return nserror */ CONTENT_MSG_STATUS, /**< new status string */ CONTENT_MSG_REFORMAT, /**< content_reformat done */ CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */ @@ -96,7 +97,9 @@ struct content_rfc5988_link { /** Extra data for some content_msg messages. */ union content_msg_data { /** CONTENT_MSG_ERROR - Error message */ - const char *error; + const char *error; + /** CONTENT_MSG_ERRORCODE - Error code */ + nserror errorcode; /** CONTENT_MSG_REDRAW - Area of content which needs redrawing */ struct { int x, y, width, height; diff --git a/desktop/browser.c b/desktop/browser.c index d3237f5ef..9fa359194 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -1187,6 +1187,121 @@ static void browser_window_update_favicon(hlcache_handle *c, nsurl_unref(nsurl); } +/** window callback errorcode handling */ +void +browser_window_callback_errorcode(hlcache_handle *c, + struct browser_window *bw, + nserror code) +{ + const char* message; + + switch (code) { + case NSERROR_OK: + /**< No error */ + message = messages_get("OK"); + break; + + case NSERROR_UNKNOWN: + /**< Unknown error */ + message = messages_get("Unknown"); + break; + + case NSERROR_NOMEM: + /**< Memory exhaustion */ + message = messages_get("NoMemory"); + break; + + case NSERROR_NO_FETCH_HANDLER: + /**< No fetch handler for URL scheme */ + message = messages_get("NoHandler"); + break; + + case NSERROR_NOT_FOUND: + /**< Requested item not found */ + message = messages_get("NotFound"); + break; + + case NSERROR_SAVE_FAILED: + /**< Failed to save data */ + message = messages_get("SaveFailed"); + break; + + case NSERROR_CLONE_FAILED: + /**< Failed to clone handle */ + message = messages_get("CloneFailed"); + break; + + case NSERROR_INIT_FAILED: + /**< Initialisation failed */ + message = messages_get("InitFailed"); + break; + + case NSERROR_MNG_ERROR: + /**< An MNG error occurred */ + message = messages_get("MNGError"); + break; + + case NSERROR_BAD_ENCODING: + /**< The character set is unknown */ + message = messages_get("BadEncoding"); + break; + + case NSERROR_NEED_DATA: + /**< More data needed */ + message = messages_get("NeedData"); + break; + + case NSERROR_BAD_PARAMETER: + /**< Bad Parameter */ + message = messages_get("BadParameter"); + break; + + case NSERROR_INVALID: + /**< Invalid data */ + message = messages_get("Invalid"); + break; + + case NSERROR_BOX_CONVERT: + /**< Box conversion failed */ + message = messages_get("BoxConvert"); + break; + + case NSERROR_STOPPED: + /**< Content conversion stopped */ + message = messages_get("Stopped"); + break; + + case NSERROR_DOM: + /**< DOM call returned error */ + message = messages_get("ParsingFail"); + break; + + case NSERROR_BAD_URL: + /**< Bad URL */ + message = messages_get("BadURL"); + break; + + } + + browser_window_set_status(bw, message); + + /* Only warn the user about errors in top-level windows */ + if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) { + warn_user(message, 0); + } + + if (c == bw->loading_content) { + bw->loading_content = NULL; + } else if (c == bw->current_content) { + bw->current_content = NULL; + browser_window_remove_caret(bw); + } + + hlcache_handle_release(c); + + browser_window_stop_throbber(bw); +} + /** * Callback for fetchcache() for browser window fetches. */ @@ -1320,6 +1435,10 @@ nserror browser_window_callback(hlcache_handle *c, browser_window_refresh, bw); break; + case CONTENT_MSG_ERRORCODE: + browser_window_callback_errorcode(c, bw, event->data.errorcode); + break; + case CONTENT_MSG_ERROR: browser_window_set_status(bw, event->data.error); diff --git a/render/html.c b/render/html.c index 09256a6fa..4e79e085e 100644 --- a/render/html.c +++ b/render/html.c @@ -113,13 +113,14 @@ static void html_box_convert_done(html_content *c, bool success) LOG(("Done XML to box (%p)", c)); /* Clean up and report error if unsuccessful or aborted */ - if ((success == false) || c->aborted) { + if ((success == false) || (c->aborted)) { + if (success == false) { + msg_data.errorcode = NSERROR_BOX_CONVERT; + } else { + msg_data.errorcode = NSERROR_STOPPED; + } html_destroy_objects(c); - if (success == false) - msg_data.error = messages_get("NoMemory"); - else - msg_data.error = messages_get("Stopped"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + content_broadcast(&c->base, CONTENT_MSG_ERRORCODE, msg_data); content_set_error(&c->base); return; } @@ -134,19 +135,22 @@ static void html_box_convert_done(html_content *c, bool success) exc = dom_document_get_document_element(c->document, (void *) &html); if ((exc != DOM_NO_ERR) || (html == NULL)) { + /** @todo should this call html_destroy_objects(c); + * like the other error paths + */ LOG(("error retrieving html element from dom")); - msg_data.error = messages_get("ParsingFail"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + msg_data.errorcode = NSERROR_DOM; + content_broadcast(&c->base, CONTENT_MSG_ERRORCODE, msg_data); content_set_error(&c->base); return; } /* extract image maps - can't do this sensibly in xml_to_box */ - if (imagemap_extract(c) == false) { + msg_data.errorcode = imagemap_extract(c); + if (msg_data.errorcode != NSERROR_OK) { LOG(("imagemap extraction failed")); html_destroy_objects(c); - msg_data.error = messages_get("NoMemory"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + content_broadcast(&c->base, CONTENT_MSG_ERRORCODE, msg_data); content_set_error(&c->base); dom_node_unref(html); return; @@ -159,8 +163,9 @@ static void html_box_convert_done(html_content *c, bool success) content_set_ready(&c->base); - if (c->base.active == 0) + if (c->base.active == 0) { content_set_done(&c->base); + } html_set_status(c, ""); dom_node_unref(html); @@ -413,9 +418,62 @@ html_create(const content_handler *handler, return NSERROR_OK; } +static nserror +parse_chunk_to_nserror(dom_hubbub_error error) +{ + switch (error) { + /* HUBBUB_REPROCESS is not handled here because it can + * never occur outside the hubbub treebuilder + */ -static bool + case DOM_HUBBUB_OK: + /* parsed ok */ + return NSERROR_OK; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED): + /* hubbub input paused */ + return NSERROR_OK; + + case DOM_HUBBUB_NOMEM: + /* out of memory error from DOM */ + return NSERROR_NOMEM; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE): + /* encoding changed */ + return NSERROR_ENCODING_CHANGE; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_NOMEM): + /* out of memory error from parser */ + return NSERROR_NOMEM; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_BADPARM): + return NSERROR_BAD_PARAMETER; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_INVALID): + return NSERROR_INVALID; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_FILENOTFOUND): + return NSERROR_NOT_FOUND; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_NEEDDATA): + return NSERROR_NEED_DATA; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_BADENCODING): + return NSERROR_BAD_ENCODING; + + case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_UNKNOWN): + /* currently only generated by the libdom hubbub binding */ + default: + /* unknown error */ + /** @todo better error handling and reporting */ + return NSERROR_UNKNOWN; + } + return NSERROR_UNKNOWN; +} + + +static nserror html_process_encoding_change(struct content *c, const char *data, unsigned int size) @@ -425,34 +483,30 @@ html_process_encoding_change(struct content *c, const char *encoding; const char *source_data; unsigned long source_size; - union content_msg_data msg_data; /* Retrieve new encoding */ encoding = dom_hubbub_parser_get_encoding(html->parser, &html->encoding_source); - if (encoding == NULL) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + return NSERROR_NOMEM; } - if (html->encoding != NULL) + if (html->encoding != NULL) { free(html->encoding); + } html->encoding = strdup(encoding); if (html->encoding == NULL) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + return NSERROR_NOMEM; } /* Destroy binding */ dom_hubbub_parser_destroy(html->parser); html->parser = NULL; - if (html->document != NULL) + if (html->document != NULL) { dom_node_unref(html->document); + } /* Create new binding, using the new encoding */ html->parser = dom_hubbub_parser_create(html->encoding, @@ -468,9 +522,7 @@ html_process_encoding_change(struct content *c, free(html->encoding); html->encoding = strdup("Windows-1252"); if (html->encoding == NULL) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + return NSERROR_NOMEM; } html->parser = dom_hubbub_parser_create(html->encoding, @@ -486,10 +538,7 @@ html_process_encoding_change(struct content *c, * parser errors back instead of everything being * OOM */ - - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + return NSERROR_NOMEM; } } @@ -498,21 +547,16 @@ html_process_encoding_change(struct content *c, /* Reprocess all the data. This is safe because * the encoding is now specified at parser start which means - * it cannot be changed again. */ - error = dom_hubbub_parser_parse_chunk(html->parser, (const uint8_t *)source_data, source_size); - - if ((error == DOM_HUBBUB_OK) || - (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED))) { - return true; - } - - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - - return false; + * it cannot be changed again. + */ + error = dom_hubbub_parser_parse_chunk(html->parser, + (const uint8_t *)source_data, + source_size); + return parse_chunk_to_nserror(error); } + /** * Process data for CONTENT_HTML. */ @@ -524,21 +568,27 @@ html_process_data(struct content *c, const char *data, unsigned int size) dom_hubbub_error error; union content_msg_data msg_data; - error = dom_hubbub_parser_parse_chunk(html->parser, (const uint8_t *) data, size); + msg_data.errorcode = NSERROR_OK; /* assume its all going to be ok */ - if ((error == DOM_HUBBUB_OK) || - (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED))) { - return true; - } else if (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE)) { - return html_process_encoding_change(c, data, size); - } + error = dom_hubbub_parser_parse_chunk(html->parser, + (const uint8_t *) data, + size); - /** @todo better error handling and reporting */ - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - + msg_data.errorcode = parse_chunk_to_nserror(error); + + /* deal with encoding change */ + if (msg_data.errorcode == NSERROR_ENCODING_CHANGE) { + msg_data.errorcode = html_process_encoding_change(c, data, size); + } + + /* broadcast the error if necessary */ + if (msg_data.errorcode != NSERROR_OK) { + content_broadcast(c, CONTENT_MSG_ERRORCODE, msg_data); + return false; + } + + return true; } diff --git a/render/imagemap.c b/render/imagemap.c index bf90443c4..c41b86d0b 100644 --- a/render/imagemap.c +++ b/render/imagemap.c @@ -251,23 +251,25 @@ void imagemap_dump(html_content *c) * \param map_str A dom_string which is "map" * \return false on memory exhaustion, true otherwise */ -bool +nserror imagemap_extract(html_content *c) { dom_nodelist *nlist; dom_exception exc; unsigned long mapnr; uint32_t maybe_maps; - + nserror ret = NSERROR_OK; + exc = dom_document_get_elements_by_tag_name(c->document, corestring_dom_map, &nlist); if (exc != DOM_NO_ERR) { - return false; + return NSERROR_DOM; } exc = dom_nodelist_get_length(nlist, &maybe_maps); if (exc != DOM_NO_ERR) { + ret = NSERROR_DOM; goto out_nlist; } @@ -276,6 +278,7 @@ imagemap_extract(html_content *c) dom_string *name; exc = dom_nodelist_item(nlist, mapnr, &node); if (exc != DOM_NO_ERR) { + ret = NSERROR_DOM; goto out_nlist; } @@ -283,6 +286,7 @@ imagemap_extract(html_content *c) &name); if (exc != DOM_NO_ERR) { dom_node_unref(node); + ret = NSERROR_DOM; goto out_nlist; } @@ -292,6 +296,7 @@ imagemap_extract(html_content *c) &name); if (exc != DOM_NO_ERR) { dom_node_unref(node); + ret = NSERROR_DOM; goto out_nlist; } } @@ -301,6 +306,7 @@ imagemap_extract(html_content *c) if (imagemap_extract_map(node, c, &entry) == false) { dom_string_unref(name); dom_node_unref(node); + ret = NSERROR_NOMEM; /** @todo check this */ goto out_nlist; } @@ -313,6 +319,7 @@ imagemap_extract(html_content *c) (imagemap_add(c, name, entry) == false)) { dom_string_unref(name); dom_node_unref(node); + ret = NSERROR_NOMEM; /** @todo check this */ goto out_nlist; } } @@ -321,14 +328,12 @@ imagemap_extract(html_content *c) dom_node_unref(node); } - dom_nodelist_unref(nlist); - - return true; out_nlist: dom_nodelist_unref(nlist); - return false; + + return ret; } /** diff --git a/render/imagemap.h b/render/imagemap.h index edbfea08f..d450cda86 100644 --- a/render/imagemap.h +++ b/render/imagemap.h @@ -28,7 +28,7 @@ struct hlcache_handle; void imagemap_destroy(struct html_content *c); void imagemap_dump(struct html_content *c); -bool imagemap_extract(struct html_content *c); +nserror imagemap_extract(struct html_content *c); nsurl *imagemap_get(struct html_content *c, const char *key, unsigned long x, unsigned long y, diff --git a/utils/errors.h b/utils/errors.h index 546709703..9ad613da6 100644 --- a/utils/errors.h +++ b/utils/errors.h @@ -29,6 +29,8 @@ typedef enum { NSERROR_OK, /**< No error */ + NSERROR_UNKNOWN, /**< Unknown error - DO *NOT* USE */ + NSERROR_NOMEM, /**< Memory exhaustion */ NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */ @@ -47,7 +49,19 @@ typedef enum { NSERROR_NEED_DATA, /**< More data needed */ - NSERROR_BAD_URL /**< More data needed */ + NSERROR_ENCODING_CHANGE, /**< The character changed */ + + NSERROR_BAD_PARAMETER, /**< Bad Parameter */ + + NSERROR_INVALID, /**< Invalid data */ + + NSERROR_BOX_CONVERT, /**< Box conversion failed */ + + NSERROR_STOPPED, /**< Content conversion stopped */ + + NSERROR_DOM, /**< DOM call returned error */ + + NSERROR_BAD_URL /**< Bad URL */ } nserror; #endif -- cgit v1.2.3