diff --git a/!NetSurf/Resources/en/Messages b/!NetSurf/Resources/en/Messages index 27b0d3d78..4cb99fa2a 100644 --- a/!NetSurf/Resources/en/Messages +++ b/!NetSurf/Resources/en/Messages @@ -450,11 +450,7 @@ Complete:Page complete (%gs) Redirecting:Redirecting... Processing:Processing document Formatting:Formatting document -FetchObjs:Loading %u %s -FetchObjs2:Loading %u %s: %s Done:Document done -FetchStyle:Loading %u %s -FetchStyle2:Loading %u %s: %s # Fetch warning/error messages - displayed in status bar # @@ -471,6 +467,47 @@ PNGError:PNG library error. MNGError:MNG library error. BadSprite:Invalid or corrupt Sprite data. +# HTTP status codes +# +HTTP0:OK +HTTP200:OK +HTTP201:Created +HTTP202:Accepted +HTTP203:Non-authoritative information +HTTP204:No content +HTTP205:Reset content +HTTP206:Partial content +HTTP300:Multiple choices +HTTP301:Moved permanently +HTTP302:Found +HTTP303:See other +HTTP304:Not modified +HTTP305:Use proxy +HTTP307:Temporary redirect +HTTP400:Bad request +HTTP401:Unauthorized +HTTP402:Payment required +HTTP403:Forbidden +HTTP404:Not found +HTTP405:Method not allowed +HTTP406:Not acceptable +HTTP407:Proxy authentication required +HTTP408:Request timeout +HTTP409:Conflict +HTTP410:Gone +HTTP411:Length required +HTTP412:Precondition failed +HTTP413:Request entity too large +HTTP414:Request-URI too long +HTTP415:Unsupported media type +HTTP416:Requested range not satisfiable +HTTP417:Expectation failed +HTTP500:Internal server error +HTTP501:Not implemented +HTTP502:Bad gateway +HTTP503:Service unavailable +HTTP504:Gateway timeout +HTTP505:HTTP version not supported # User interface # ============== diff --git a/content/content.c b/content/content.c index 0f23d25cc..d211bb109 100644 --- a/content/content.c +++ b/content/content.c @@ -2,7 +2,7 @@ * This file is part of NetSurf, http://netsurf-browser.org/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2005 James Bursa + * Copyright 2005-2007 James Bursa */ /** \file @@ -18,6 +18,7 @@ #include #include #include +#include #include "netsurf/utils/config.h" #include "netsurf/content/content.h" #include "netsurf/content/fetch.h" @@ -304,6 +305,7 @@ static const struct handler_entry handler_map[] = { #define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0])) +static void content_update_status(struct content *c); static void content_destroy(struct content *c); static void content_stop_check(struct content *c); @@ -373,6 +375,7 @@ struct content * content_create(const char *url) c->refresh = 0; c->bitmap = 0; c->fresh = false; + c->time = clock(); c->size = 0; c->title = 0; c->active = 0; @@ -380,13 +383,14 @@ struct content * content_create(const char *url) user_sentinel->p1 = user_sentinel->p2 = 0; user_sentinel->next = 0; c->user_list = user_sentinel; - content_set_status(c, messages_get("Loading")); + c->sub_status[0] = 0; c->locked = false; c->fetch = 0; c->source_data = 0; c->source_size = 0; c->source_allocated = 0; c->total_size = 0; + c->http_code = 0; c->no_error_pages = false; c->download = false; c->error_count = 0; @@ -400,6 +404,8 @@ struct content * content_create(const char *url) c->cache_data->etag = 0; c->cache_data->last_modified = 0; + content_set_status(c, messages_get("Loading")); + c->prev = 0; c->next = content_list; if (content_list) @@ -592,11 +598,38 @@ void content_set_status(struct content *c, const char *status_message, ...) int len; va_start(ap, status_message); - if ((len = vsnprintf(c->status_message, sizeof (c->status_message), + if ((len = vsnprintf(c->sub_status, sizeof (c->sub_status), status_message, ap)) < 0 || - (int)sizeof (c->status_message) <= len) - c->status_message[sizeof (c->status_message) - 1] = '\0'; + (int)sizeof (c->sub_status) <= len) + c->sub_status[sizeof (c->sub_status) - 1] = '\0'; va_end(ap); + + content_update_status(c); +} + + +void content_update_status(struct content *c) +{ + char token[20]; + const char *status; + clock_t time; + + snprintf(token, sizeof token, "HTTP%li", c->http_code); + status = messages_get(token); + if (status == token) + status = token + 4; + + if (c->status == CONTENT_STATUS_TYPE_UNKNOWN || + c->status == CONTENT_STATUS_LOADING || + c->status == CONTENT_STATUS_READY) + time = clock() - c->time; + else + time = c->time; + + snprintf(c->status_message, sizeof (c->status_message), + "%s (%.1fs) %s", status, + (float) time / CLOCKS_PER_SEC, c->sub_status); + /* LOG(("%s", c->status_message)); */ } @@ -704,7 +737,22 @@ void content_convert(struct content *c, int width, int height) c->status == CONTENT_STATUS_DONE); content_broadcast(c, CONTENT_MSG_READY, msg_data); if (c->status == CONTENT_STATUS_DONE) - content_broadcast(c, CONTENT_MSG_DONE, msg_data); + content_set_done(c); +} + + +/** + * Put a content in status CONTENT_STATUS_DONE. + */ + +void content_set_done(struct content *c) +{ + union content_msg_data msg_data; + + c->status = CONTENT_STATUS_DONE; + c->time = clock() - c->time; + content_update_status(c); + content_broadcast(c, CONTENT_MSG_DONE, msg_data); } diff --git a/content/content.h b/content/content.h index 123733ba9..268ba31a1 100644 --- a/content/content.h +++ b/content/content.h @@ -2,7 +2,7 @@ * This file is part of NetSurf, http://netsurf-browser.org/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2005 James Bursa + * Copyright 2005-2007 James Bursa * Copyright 2003 Philip Pemberton */ @@ -16,6 +16,7 @@ #define _NETSURF_DESKTOP_CONTENT_H_ #include +#include #include "netsurf/utils/config.h" #include "netsurf/content/content_type.h" #include "netsurf/css/css.h" @@ -178,6 +179,9 @@ struct content { * shared between users. */ bool fresh; struct cache_data *cache_data; /**< Cache control data */ + clock_t time; /**< Creation time, if TYPE_UNKNOWN, + LOADING or READY, + otherwise total time. */ unsigned int size; /**< Estimated size of all data associated with this content, except @@ -186,7 +190,8 @@ struct content { unsigned int active; /**< Number of child fetches or conversions currently in progress. */ struct content_user *user_list; /**< List of users. */ - char status_message[80]; /**< Text for status bar. */ + char status_message[120]; /**< Full text for status bar. */ + char sub_status[80]; /**< Status of content. */ /** Content is being processed: data structures may be inconsistent * and content must not be redrawn or modified. */ bool locked; @@ -196,6 +201,7 @@ struct content { unsigned long source_size; /**< Amount of data fetched so far. */ unsigned long source_allocated; /**< Amount of space allocated so far. */ unsigned long total_size; /**< Total data size, 0 if unknown. */ + long http_code; /**< HTTP status code, 0 if not HTTP. */ bool no_error_pages; /**< Used by fetchcache(). */ bool download; /**< Used by fetchcache(). */ @@ -226,6 +232,7 @@ void content_set_status(struct content *c, const char *status_message, ...); bool content_process_data(struct content *c, const char *data, unsigned int size); void content_convert(struct content *c, int width, int height); +void content_set_done(struct content *c); void content_reformat(struct content *c, int width, int height); void content_clean(void); void content_reset(struct content *c); diff --git a/content/fetchcache.c b/content/fetchcache.c index 220359df0..0a630661b 100644 --- a/content/fetchcache.c +++ b/content/fetchcache.c @@ -376,6 +376,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const void *data, switch (msg) { case FETCH_TYPE: c->total_size = size; + c->http_code = fetch_http_code(c->fetch); mime_type = fetchcache_parse_type(data, ¶ms); if (!mime_type) { msg_data.error = messages_get("NoMemory"); diff --git a/desktop/browser.c b/desktop/browser.c index 628fbc9b3..b3fe85127 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "curl/curl.h" #include "netsurf/utils/config.h" #include "netsurf/content/fetch.h" @@ -286,7 +285,6 @@ 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(); c = fetchcache(url2, browser_window_callback, (intptr_t) bw, 0, width, height, false, post_urlenc, post_multipart, true, download); @@ -347,6 +345,7 @@ void browser_window_callback(content_msg msg, struct content *c, url[sizeof url - 1] = 0; gui_window_set_url(bw->window, url); bw->refresh_interval = -1; + browser_window_set_status(bw, c->status_message); } break; @@ -414,10 +413,7 @@ void browser_window_callback(content_msg msg, struct content *c, assert(bw->current_content == c); browser_window_update(bw, false); - sprintf(status, messages_get("Complete"), - ((float) (clock() - bw->time0)) / - CLOCKS_PER_SEC); - browser_window_set_status(bw, status); + browser_window_set_status(bw, c->status_message); browser_window_stop_throbber(bw); history_update(bw->history, c); hotlist_visited(c); diff --git a/desktop/browser.h b/desktop/browser.h index c7bbaf8e3..8f0e74e89 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -74,8 +74,6 @@ struct browser_window { bool throbbing; /** Add loading_content to the window history when it loads. */ bool history_add; - /** Start time of fetching loading_content. */ - clock_t time0; /** Fragment identifier for current_content. */ char *frag_id; diff --git a/render/html.c b/render/html.c index 1e50a77fb..7b7844ae8 100644 --- a/render/html.c +++ b/render/html.c @@ -55,6 +55,20 @@ static bool html_object_type_permitted(const content_type type, static void html_object_refresh(void *p); static void html_destroy_frameset(struct content_html_frames *frameset); static void html_destroy_iframe(struct content_html_iframe *iframe); +static void html_set_status(struct content *c, const char *extra); + +static const char empty_document[] = + "" + "" + "" + "Empty document" + "" + "" + "

Empty document

" + "

The document sent by the server is empty.

" + "" + ""; /** @@ -264,11 +278,15 @@ bool html_convert(struct content *c, int width, int height) union content_msg_data msg_data; /* finish parsing */ + if (c->source_size == 0) + htmlParseChunk(c->data.html.parser, empty_document, + sizeof empty_document, 0); htmlParseChunk(c->data.html.parser, "", 0, 1); document = c->data.html.parser->myDoc; /*xmlDebugDumpDocument(stderr, c->data.html.parser->myDoc);*/ htmlFreeParserCtxt(c->data.html.parser); c->data.html.parser = 0; + if (!document) { LOG(("Parsing failed")); msg_data.error = messages_get("ParsingFail"); @@ -353,24 +371,92 @@ bool html_convert(struct content *c, int width, int height) xmlFreeDoc(document); /* layout the box tree */ - content_set_status(c, messages_get("Formatting")); + html_set_status(c, messages_get("Formatting")); content_broadcast(c, CONTENT_MSG_STATUS, msg_data); LOG(("Layout document")); html_reformat(c, width, height); /*box_dump(c->data.html.layout->children, 0);*/ - if (c->active == 0) { + if (c->active == 0) c->status = CONTENT_STATUS_DONE; - content_set_status(c, messages_get("Done")); - } else { + else c->status = CONTENT_STATUS_READY; - content_set_status(c, messages_get("FetchObjs"), c->active, - messages_get((c->active == 1) ? "obj" : "objs")); - } + html_set_status(c, ""); return true; } + +/** + * Process elements in . + * + * \param c content structure + * \param head xml node of head element + * \return true on success, false on memory exhaustion + * + * The title and base href are extracted if present. + */ + +bool html_head(struct content *c, xmlNode *head) +{ + xmlNode *node; + xmlChar *s; + + c->title = 0; + + for (node = head->children; node != 0; node = node->next) { + if (node->type != XML_ELEMENT_NODE) + continue; + + LOG(("Node: %s", node->name)); + if (!c->title && strcmp(node->name, "title") == 0) { + xmlChar *title = xmlNodeGetContent(node); + if (!title) + return false; + char *title2 = squash_whitespace(title); + xmlFree(title); + if (!title2) + return false; + c->title = talloc_strdup(c, title2); + free(title2); + if (!c->title) + return false; + + } else if (strcmp(node->name, "base") == 0) { + char *href = (char *) xmlGetProp(node, + (const xmlChar *) "href"); + if (href) { + char *url; + url_func_result res; + res = url_normalize(href, &url); + if (res == URL_FUNC_OK) { + c->data.html.base_url = + talloc_strdup(c, url); + free(url); + } + xmlFree(href); + } + /* don't use the central values to ease freeing later on */ + if ((s = xmlGetProp(node, (const xmlChar *) "target"))) { + if ((!strcasecmp(s, "_blank")) || (!strcasecmp(s, "_top")) || + (!strcasecmp(s, "_parent")) || + (!strcasecmp(s, "_self")) || + ('a' <= s[0] && s[0] <= 'z') || + ('A' <= s[0] && s[0] <= 'Z')) { /* [6.16] */ + c->data.html.base_target = talloc_strdup(c, s); + if (!c->data.html.base_target) { + xmlFree(s); + return false; + } + } + xmlFree(s); + } + } + } + return true; +} + + /** * Search for meta refresh * @@ -483,75 +569,6 @@ bool html_meta_refresh(struct content *c, xmlNode *head) return true; } -/** - * Process elements in . - * - * \param c content structure - * \param head xml node of head element - * \return true on success, false on memory exhaustion - * - * The title and base href are extracted if present. - */ - -bool html_head(struct content *c, xmlNode *head) -{ - xmlNode *node; - xmlChar *s; - - c->title = 0; - - for (node = head->children; node != 0; node = node->next) { - if (node->type != XML_ELEMENT_NODE) - continue; - - LOG(("Node: %s", node->name)); - if (!c->title && strcmp(node->name, "title") == 0) { - xmlChar *title = xmlNodeGetContent(node); - if (!title) - return false; - char *title2 = squash_whitespace(title); - xmlFree(title); - if (!title2) - return false; - c->title = talloc_strdup(c, title2); - free(title2); - if (!c->title) - return false; - - } else if (strcmp(node->name, "base") == 0) { - char *href = (char *) xmlGetProp(node, - (const xmlChar *) "href"); - if (href) { - char *url; - url_func_result res; - res = url_normalize(href, &url); - if (res == URL_FUNC_OK) { - c->data.html.base_url = - talloc_strdup(c, url); - free(url); - } - xmlFree(href); - } - /* don't use the central values to ease freeing later on */ - if ((s = xmlGetProp(node, (const xmlChar *) "target"))) { - if ((!strcasecmp(s, "_blank")) || (!strcasecmp(s, "_top")) || - (!strcasecmp(s, "_parent")) || - (!strcasecmp(s, "_self")) || - ('a' <= s[0] && s[0] <= 'z') || - ('A' <= s[0] && s[0] <= 'Z')) { /* [6.16] */ - c->data.html.base_target = talloc_strdup(c, s); - if (!c->data.html.base_target) { - xmlFree(s); - return false; - } - } - xmlFree(s); - } - } - } - return true; -} - /** * Process inline stylesheets and fetch linked stylesheets. @@ -762,9 +779,7 @@ bool html_find_stylesheets(struct content *c, xmlNode *head) /* complete the fetches */ while (c->active != 0) { if (c->active != last_active) { - content_set_status(c, messages_get("FetchStyle"), - c->active, - messages_get((c->active == 1) ? "styl" : "styls")); + html_set_status(c, ""); content_broadcast(c, CONTENT_MSG_STATUS, msg_data); last_active = c->active; } @@ -820,7 +835,7 @@ void html_convert_css_callback(content_msg msg, struct content *css, c->data.html.stylesheet_content[i] = 0; c->active--; content_add_error(c, "NotCSS", 0); - content_set_status(c, messages_get("NotCSS")); + html_set_status(c, messages_get("NotCSS")); content_broadcast(c, CONTENT_MSG_STATUS, data); content_remove_user(css, html_convert_css_callback, @@ -854,10 +869,7 @@ void html_convert_css_callback(content_msg msg, struct content *css, break; case CONTENT_MSG_STATUS: - content_set_status(c, messages_get("FetchStyle2"), - c->active, - messages_get((c->active == 1) ? "styl" : "styls"), - css->status_message); + html_set_status(c, css->status_message); content_broadcast(c, CONTENT_MSG_STATUS, data); break; @@ -1063,7 +1075,7 @@ void html_object_callback(content_msg msg, struct content *object, c->data.html.object[i].content = 0; c->active--; content_add_error(c, "?", 0); - content_set_status(c, messages_get("BadObject")); + html_set_status(c, messages_get("BadObject")); content_broadcast(c, CONTENT_MSG_STATUS, data); content_remove_user(object, html_object_callback, (intptr_t) c, i); @@ -1094,18 +1106,14 @@ void html_object_callback(content_msg msg, struct content *object, c->data.html.object[i].content = 0; c->active--; content_add_error(c, "?", 0); - content_set_status(c, messages_get("ObjError"), - data.error); + html_set_status(c, data.error); content_broadcast(c, CONTENT_MSG_STATUS, data); html_object_failed(box, c, c->data.html.object[i].background); break; case CONTENT_MSG_STATUS: - content_set_status(c, messages_get("FetchObjs2"), - c->active, - messages_get((c->active == 1) ? "obj" : "objs"), - object->status_message); + html_set_status(c, object->status_message); /* content_broadcast(c, CONTENT_MSG_STATUS, 0); */ break; @@ -1202,13 +1210,11 @@ void html_object_callback(content_msg msg, struct content *object, msg == CONTENT_MSG_AUTH)) { /* all objects have arrived */ content_reformat(c, c->available_width, c->height); - c->status = CONTENT_STATUS_DONE; - content_set_status(c, messages_get("Done")); - content_broadcast(c, CONTENT_MSG_DONE, data); + html_set_status(c, ""); + content_set_done(c); } if (c->status == CONTENT_STATUS_READY) - content_set_status(c, messages_get("FetchObjs"), c->active, - messages_get((c->active == 1) ? "obj" : "objs")); + html_set_status(c, ""); } @@ -1536,6 +1542,30 @@ void html_destroy_iframe(struct content_html_iframe *iframe) { } +/** + * Set the content status. + */ + +void html_set_status(struct content *c, const char *extra) +{ + unsigned int stylesheets = 0, objects = 0; + if (c->data.html.object_count == 0) + stylesheets = c->data.html.stylesheet_count - c->active; + else { + stylesheets = c->data.html.stylesheet_count; + objects = c->data.html.object_count - c->active; + } + content_set_status(c, "%u/%u %s %u/%u %s %s", + stylesheets, c->data.html.stylesheet_count, + messages_get((c->data.html.stylesheet_count == 1) ? + "styl" : "styls"), + objects, c->data.html.object_count, + messages_get((c->data.html.object_count == 1) ? + "obj" : "objs"), + extra); +} + + /** * Handle a window containing a CONTENT_HTML being opened. */