Improve error handling in html content

This commit is contained in:
Vincent Sanders 2012-10-17 21:52:43 +01:00
parent 35eb251244
commit f18bbd48c7
6 changed files with 255 additions and 64 deletions

View File

@ -67,6 +67,7 @@ typedef enum {
CONTENT_MSG_READY, /**< may be displayed */ CONTENT_MSG_READY, /**< may be displayed */
CONTENT_MSG_DONE, /**< finished */ CONTENT_MSG_DONE, /**< finished */
CONTENT_MSG_ERROR, /**< error occurred */ CONTENT_MSG_ERROR, /**< error occurred */
CONTENT_MSG_ERRORCODE, /**< error occurred return nserror */
CONTENT_MSG_STATUS, /**< new status string */ CONTENT_MSG_STATUS, /**< new status string */
CONTENT_MSG_REFORMAT, /**< content_reformat done */ CONTENT_MSG_REFORMAT, /**< content_reformat done */
CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */ CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */
@ -96,7 +97,9 @@ struct content_rfc5988_link {
/** Extra data for some content_msg messages. */ /** Extra data for some content_msg messages. */
union content_msg_data { union content_msg_data {
/** CONTENT_MSG_ERROR - Error message */ /** 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 */ /** CONTENT_MSG_REDRAW - Area of content which needs redrawing */
struct { struct {
int x, y, width, height; int x, y, width, height;

View File

@ -1187,6 +1187,121 @@ static void browser_window_update_favicon(hlcache_handle *c,
nsurl_unref(nsurl); 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. * Callback for fetchcache() for browser window fetches.
*/ */
@ -1320,6 +1435,10 @@ nserror browser_window_callback(hlcache_handle *c,
browser_window_refresh, bw); browser_window_refresh, bw);
break; break;
case CONTENT_MSG_ERRORCODE:
browser_window_callback_errorcode(c, bw, event->data.errorcode);
break;
case CONTENT_MSG_ERROR: case CONTENT_MSG_ERROR:
browser_window_set_status(bw, event->data.error); browser_window_set_status(bw, event->data.error);

View File

@ -113,13 +113,14 @@ static void html_box_convert_done(html_content *c, bool success)
LOG(("Done XML to box (%p)", c)); LOG(("Done XML to box (%p)", c));
/* Clean up and report error if unsuccessful or aborted */ /* 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); html_destroy_objects(c);
if (success == false) content_broadcast(&c->base, CONTENT_MSG_ERRORCODE, msg_data);
msg_data.error = messages_get("NoMemory");
else
msg_data.error = messages_get("Stopped");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
content_set_error(&c->base); content_set_error(&c->base);
return; 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); exc = dom_document_get_document_element(c->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) { 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")); LOG(("error retrieving html element from dom"));
msg_data.error = messages_get("ParsingFail"); msg_data.errorcode = NSERROR_DOM;
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); content_broadcast(&c->base, CONTENT_MSG_ERRORCODE, msg_data);
content_set_error(&c->base); content_set_error(&c->base);
return; return;
} }
/* extract image maps - can't do this sensibly in xml_to_box */ /* 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")); LOG(("imagemap extraction failed"));
html_destroy_objects(c); html_destroy_objects(c);
msg_data.error = messages_get("NoMemory"); content_broadcast(&c->base, CONTENT_MSG_ERRORCODE, msg_data);
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
content_set_error(&c->base); content_set_error(&c->base);
dom_node_unref(html); dom_node_unref(html);
return; return;
@ -159,8 +163,9 @@ static void html_box_convert_done(html_content *c, bool success)
content_set_ready(&c->base); content_set_ready(&c->base);
if (c->base.active == 0) if (c->base.active == 0) {
content_set_done(&c->base); content_set_done(&c->base);
}
html_set_status(c, ""); html_set_status(c, "");
dom_node_unref(html); dom_node_unref(html);
@ -413,9 +418,62 @@ html_create(const content_handler *handler,
return NSERROR_OK; 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
*/
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 bool static nserror
html_process_encoding_change(struct content *c, html_process_encoding_change(struct content *c,
const char *data, const char *data,
unsigned int size) unsigned int size)
@ -425,34 +483,30 @@ html_process_encoding_change(struct content *c,
const char *encoding; const char *encoding;
const char *source_data; const char *source_data;
unsigned long source_size; unsigned long source_size;
union content_msg_data msg_data;
/* Retrieve new encoding */ /* Retrieve new encoding */
encoding = dom_hubbub_parser_get_encoding(html->parser, encoding = dom_hubbub_parser_get_encoding(html->parser,
&html->encoding_source); &html->encoding_source);
if (encoding == NULL) { if (encoding == NULL) {
msg_data.error = messages_get("NoMemory"); return NSERROR_NOMEM;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
} }
if (html->encoding != NULL) if (html->encoding != NULL) {
free(html->encoding); free(html->encoding);
}
html->encoding = strdup(encoding); html->encoding = strdup(encoding);
if (html->encoding == NULL) { if (html->encoding == NULL) {
msg_data.error = messages_get("NoMemory"); return NSERROR_NOMEM;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
} }
/* Destroy binding */ /* Destroy binding */
dom_hubbub_parser_destroy(html->parser); dom_hubbub_parser_destroy(html->parser);
html->parser = NULL; html->parser = NULL;
if (html->document != NULL) if (html->document != NULL) {
dom_node_unref(html->document); dom_node_unref(html->document);
}
/* Create new binding, using the new encoding */ /* Create new binding, using the new encoding */
html->parser = dom_hubbub_parser_create(html->encoding, html->parser = dom_hubbub_parser_create(html->encoding,
@ -468,9 +522,7 @@ html_process_encoding_change(struct content *c,
free(html->encoding); free(html->encoding);
html->encoding = strdup("Windows-1252"); html->encoding = strdup("Windows-1252");
if (html->encoding == NULL) { if (html->encoding == NULL) {
msg_data.error = messages_get("NoMemory"); return NSERROR_NOMEM;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
} }
html->parser = dom_hubbub_parser_create(html->encoding, 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 * parser errors back instead of everything being
* OOM * OOM
*/ */
return NSERROR_NOMEM;
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
} }
} }
@ -498,21 +547,16 @@ html_process_encoding_change(struct content *c,
/* Reprocess all the data. This is safe because /* Reprocess all the data. This is safe because
* the encoding is now specified at parser start which means * the encoding is now specified at parser start which means
* it cannot be changed again. */ * it cannot be changed again.
error = dom_hubbub_parser_parse_chunk(html->parser, (const uint8_t *)source_data, source_size); */
error = dom_hubbub_parser_parse_chunk(html->parser,
if ((error == DOM_HUBBUB_OK) || (const uint8_t *)source_data,
(error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED))) { source_size);
return true;
}
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
return parse_chunk_to_nserror(error);
} }
/** /**
* Process data for CONTENT_HTML. * 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; dom_hubbub_error error;
union content_msg_data msg_data; 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_parser_parse_chunk(html->parser,
(error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED))) { (const uint8_t *) data,
return true; size);
} else if (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE)) {
return html_process_encoding_change(c, 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;
} }

View File

@ -251,23 +251,25 @@ void imagemap_dump(html_content *c)
* \param map_str A dom_string which is "map" * \param map_str A dom_string which is "map"
* \return false on memory exhaustion, true otherwise * \return false on memory exhaustion, true otherwise
*/ */
bool nserror
imagemap_extract(html_content *c) imagemap_extract(html_content *c)
{ {
dom_nodelist *nlist; dom_nodelist *nlist;
dom_exception exc; dom_exception exc;
unsigned long mapnr; unsigned long mapnr;
uint32_t maybe_maps; uint32_t maybe_maps;
nserror ret = NSERROR_OK;
exc = dom_document_get_elements_by_tag_name(c->document, exc = dom_document_get_elements_by_tag_name(c->document,
corestring_dom_map, corestring_dom_map,
&nlist); &nlist);
if (exc != DOM_NO_ERR) { if (exc != DOM_NO_ERR) {
return false; return NSERROR_DOM;
} }
exc = dom_nodelist_get_length(nlist, &maybe_maps); exc = dom_nodelist_get_length(nlist, &maybe_maps);
if (exc != DOM_NO_ERR) { if (exc != DOM_NO_ERR) {
ret = NSERROR_DOM;
goto out_nlist; goto out_nlist;
} }
@ -276,6 +278,7 @@ imagemap_extract(html_content *c)
dom_string *name; dom_string *name;
exc = dom_nodelist_item(nlist, mapnr, &node); exc = dom_nodelist_item(nlist, mapnr, &node);
if (exc != DOM_NO_ERR) { if (exc != DOM_NO_ERR) {
ret = NSERROR_DOM;
goto out_nlist; goto out_nlist;
} }
@ -283,6 +286,7 @@ imagemap_extract(html_content *c)
&name); &name);
if (exc != DOM_NO_ERR) { if (exc != DOM_NO_ERR) {
dom_node_unref(node); dom_node_unref(node);
ret = NSERROR_DOM;
goto out_nlist; goto out_nlist;
} }
@ -292,6 +296,7 @@ imagemap_extract(html_content *c)
&name); &name);
if (exc != DOM_NO_ERR) { if (exc != DOM_NO_ERR) {
dom_node_unref(node); dom_node_unref(node);
ret = NSERROR_DOM;
goto out_nlist; goto out_nlist;
} }
} }
@ -301,6 +306,7 @@ imagemap_extract(html_content *c)
if (imagemap_extract_map(node, c, &entry) == false) { if (imagemap_extract_map(node, c, &entry) == false) {
dom_string_unref(name); dom_string_unref(name);
dom_node_unref(node); dom_node_unref(node);
ret = NSERROR_NOMEM; /** @todo check this */
goto out_nlist; goto out_nlist;
} }
@ -313,6 +319,7 @@ imagemap_extract(html_content *c)
(imagemap_add(c, name, entry) == false)) { (imagemap_add(c, name, entry) == false)) {
dom_string_unref(name); dom_string_unref(name);
dom_node_unref(node); dom_node_unref(node);
ret = NSERROR_NOMEM; /** @todo check this */
goto out_nlist; goto out_nlist;
} }
} }
@ -321,14 +328,12 @@ imagemap_extract(html_content *c)
dom_node_unref(node); dom_node_unref(node);
} }
dom_nodelist_unref(nlist);
return true;
out_nlist: out_nlist:
dom_nodelist_unref(nlist); dom_nodelist_unref(nlist);
return false;
return ret;
} }
/** /**

View File

@ -28,7 +28,7 @@ struct hlcache_handle;
void imagemap_destroy(struct html_content *c); void imagemap_destroy(struct html_content *c);
void imagemap_dump(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, nsurl *imagemap_get(struct html_content *c, const char *key,
unsigned long x, unsigned long y, unsigned long x, unsigned long y,

View File

@ -29,6 +29,8 @@
typedef enum { typedef enum {
NSERROR_OK, /**< No error */ NSERROR_OK, /**< No error */
NSERROR_UNKNOWN, /**< Unknown error - DO *NOT* USE */
NSERROR_NOMEM, /**< Memory exhaustion */ NSERROR_NOMEM, /**< Memory exhaustion */
NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */ NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */
@ -47,7 +49,19 @@ typedef enum {
NSERROR_NEED_DATA, /**< More data needed */ 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; } nserror;
#endif #endif