summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2008-02-03 12:04:48 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2008-02-03 12:04:48 +0000
commitad6fcea6b008638ca532436ecf8ba9fe7e41ffdd (patch)
tree7928f5211a6cd644dcfd764b1c67cf3f6b8ed121
parenteb2c2e3f63056e7f8b992f17f94a9418ac311a0f (diff)
downloadnetsurf-ad6fcea6b008638ca532436ecf8ba9fe7e41ffdd.tar.gz
netsurf-ad6fcea6b008638ca532436ecf8ba9fe7e41ffdd.tar.bz2
Add url_fragment to extract fragment from URL
Optionally allow url_compare to ignore fragments in comparison Fix handling of url_compare result in a few places Fix redirects which contain fragments in the Location header svn path=/trunk/netsurf/; revision=3826
-rw-r--r--content/content.c1
-rw-r--r--content/content.h5
-rw-r--r--content/fetchcache.c18
-rw-r--r--desktop/browser.c71
-rw-r--r--render/directory.c4
-rw-r--r--riscos/menus.c6
-rw-r--r--riscos/window.c4
-rw-r--r--utils/url.c53
-rw-r--r--utils/url.h3
9 files changed, 118 insertions, 47 deletions
diff --git a/content/content.c b/content/content.c
index c8389d80e..9310eb180 100644
--- a/content/content.c
+++ b/content/content.c
@@ -608,6 +608,7 @@ bool content_set_type(struct content *c, content_type type,
return false;
}
content_remove_user(c, callback, p1, p2);
+ msg_data.new_url = NULL;
content_broadcast(clone, CONTENT_MSG_NEWPTR, msg_data);
fetchcache_go(clone, referer,
callback, p1, p2,
diff --git a/content/content.h b/content/content.h
index 324af952f..7fb11ca2a 100644
--- a/content/content.h
+++ b/content/content.h
@@ -84,7 +84,7 @@ typedef enum {
CONTENT_MSG_STATUS, /**< new status string */
CONTENT_MSG_REFORMAT, /**< content_reformat done */
CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */
- CONTENT_MSG_NEWPTR, /**< address of structure has changed */
+ CONTENT_MSG_NEWPTR, /**< structure has been replaced */
CONTENT_MSG_REFRESH, /**< wants refresh */
#ifdef WITH_AUTH
CONTENT_MSG_AUTH, /**< authentication required */
@@ -97,7 +97,8 @@ typedef enum {
/** Extra data for some content_msg messages. */
union content_msg_data {
const char *error; /**< Error message, for CONTENT_MSG_ERROR. */
- char *redirect; /**< Redirect URL, for CONTENT_MSG_REDIRECT. */
+ const char *new_url; /**< Replacement URL (or NULL if the same
+ * as previous), for CONTENT_MSG_NEWPTR. */
/** Area of content which needs redrawing, for CONTENT_MSG_REDRAW. */
struct {
float x, y, width, height;
diff --git a/content/fetchcache.c b/content/fetchcache.c
index b6b17a618..4fdbb93ca 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -689,6 +689,8 @@ void fetchcache_notmodified(struct content *c, const void *data)
}
content_remove_user(c, callback, p1, p2);
+
+ msg_data.new_url = NULL;
callback(CONTENT_MSG_NEWPTR, fb, p1, p2, msg_data);
/* and catch user up with fallback's state */
@@ -786,25 +788,26 @@ void fetchcache_redirect(struct content *c, const void *data,
{
char *url, *url1;
char *referer, *parent_url;
- long http_code = fetch_http_code(c->fetch);
- const char *ref = fetch_get_referer(c->fetch);
- const char *parent = fetch_get_parent_url(c->fetch);
+ long http_code;
+ const char *ref;
+ const char *parent;
union content_msg_data msg_data;
url_func_result result;
/* Preconditions */
assert(c && data);
assert(c->status == CONTENT_STATUS_TYPE_UNKNOWN);
- /* Ensure a redirect happened */
- assert(300 <= http_code && http_code <= 399);
- /* 304 is handled by fetch_notmodified() */
- assert(http_code != 304);
/* Extract fetch details */
http_code = fetch_http_code(c->fetch);
ref = fetch_get_referer(c->fetch);
parent = fetch_get_parent_url(c->fetch);
+ /* Ensure a redirect happened */
+ assert(300 <= http_code && http_code <= 399);
+ /* 304 is handled by fetch_notmodified() */
+ assert(http_code != 304);
+
/* Clone referer and parent url
* originals are destroyed in fetch_abort() */
referer = ref ? strdup(ref) : NULL;
@@ -941,6 +944,7 @@ void fetchcache_redirect(struct content *c, const void *data,
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);
/* Start fetching the replacement content */
diff --git a/desktop/browser.c b/desktop/browser.c
index 1f2709ec8..3cfcd0352 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -262,7 +262,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
{
struct content *c;
char *url2;
- char *hash;
+ char *fragment;
url_func_result res;
char url_buf[256];
int depth = 0;
@@ -296,38 +296,38 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
if (!download)
gui_window_set_url(bw->window, url2);
+ free(bw->frag_id);
+ bw->frag_id = NULL;
+
/* find any fragment identifier on end of URL */
- hash = strchr(url2, '#');
- if (bw->frag_id) {
- free(bw->frag_id);
- bw->frag_id = 0;
- }
- if (hash) {
- char *frag = curl_unescape(hash+1, strlen(hash + 1));
- if (!frag) {
- free(url2);
- warn_user("NoMemory", 0);
- return;
- }
+ res = url_fragment(url2, &fragment);
+ if (res == URL_FUNC_NOMEM) {
+ free(url2);
+ warn_user("NoMemory", 0);
+ return;
+ } else if (res == URL_FUNC_OK) {
+ bool same_url = false;
- bw->frag_id = strdup(frag);
- curl_free(frag);
+ bw->frag_id = fragment;
- if (!bw->frag_id) {
- free(url2);
- warn_user("NoMemory", 0);
- return;
+ /* Compare new URL with existing one (ignoring fragments) */
+ if (bw->current_content && bw->current_content->url) {
+ res = url_compare(bw->current_content->url, url2,
+ true, &same_url);
+ if (res == URL_FUNC_NOMEM) {
+ free(url2);
+ warn_user("NoMemory", 0);
+ return;
+ } else if (res == URL_FUNC_FAILED) {
+ same_url = false;
+ }
}
/* if we're simply moving to another ID on the same page,
* don't bother to fetch, just update the window.
*/
- if (!post_urlenc && !post_multipart && !strchr(url2, '?') &&
- bw->current_content && bw->current_content->url &&
- strncasecmp(bw->current_content->url,
- url2, hash - url2) == 0 &&
- strlen(bw->current_content->url) ==
- (unsigned int)(hash - url2)) {
+ if (same_url && !post_urlenc && !post_multipart &&
+ !strchr(url2, '?')) {
free(url2);
browser_window_update(bw, false);
snprintf(url_buf, sizeof url_buf, "%s#%s",
@@ -532,6 +532,27 @@ void browser_window_callback(content_msg msg, struct content *c,
case CONTENT_MSG_NEWPTR:
bw->loading_content = c;
+ if (data.new_url) {
+ /* Replacement URL too, so check for new fragment */
+ char *fragment;
+ url_func_result res;
+
+ /* Remove any existing fragment */
+ free(bw->frag_id);
+ bw->frag_id = NULL;
+
+ /* Extract new one, if any */
+ res = url_fragment(data.new_url, &fragment);
+ if (res == URL_FUNC_OK) {
+ /* Save for later use */
+ bw->frag_id = fragment;
+ }
+ /* Ignore memory exhaustion here -- it'll simply result
+ * in the window being scrolled to the top rather than
+ * to the fragment. That's acceptable, given that it's
+ * likely that more important things will complain
+ * about memory shortage. */
+ }
break;
#ifdef WITH_AUTH
diff --git a/render/directory.c b/render/directory.c
index 2f280fabe..61abf1b1f 100644
--- a/render/directory.c
+++ b/render/directory.c
@@ -96,8 +96,8 @@ bool directory_convert(struct content *c, int width, int height) {
res = url_parent(c->url, &up);
if (res == URL_FUNC_OK) {
- res = url_compare(c->url, up, &compare);
- if (!compare) {
+ res = url_compare(c->url, up, false, &compare);
+ if ((res == URL_FUNC_OK) && !compare) {
snprintf(buffer, sizeof(buffer),
"<a href=\"..\">[..]</a>\n");
htmlParseChunk(c->data.html.parser, buffer,
diff --git a/riscos/menus.c b/riscos/menus.c
index ff4537179..adfb9a109 100644
--- a/riscos/menus.c
+++ b/riscos/menus.c
@@ -1989,8 +1989,10 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
if (result) {
res = url_parent(c->url, &parent);
if (res == URL_FUNC_OK) {
- res = url_compare(c->url, parent, &compare);
- result = !compare;
+ res = url_compare(c->url, parent,
+ false, &compare);
+ if (res == URL_FUNC_OK)
+ result = !compare;
free(parent);
} else {
result = false;
diff --git a/riscos/window.c b/riscos/window.c
index 7824bbe7a..21e57b9f8 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -3329,8 +3329,8 @@ bool ro_gui_window_navigate_up(struct gui_window *g, const char *url) {
res = url_parent(url, &parent);
if (res == URL_FUNC_OK) {
- res = url_compare(url, parent, &compare);
- if (!compare && (res == URL_FUNC_OK))
+ res = url_compare(url, parent, false, &compare);
+ if ((res == URL_FUNC_OK) && !compare)
browser_window_go(g->bw, parent, 0, true);
free(parent);
}
diff --git a/utils/url.c b/utils/url.c
index 3a43e1765..ac46944eb 100644
--- a/utils/url.c
+++ b/utils/url.c
@@ -30,6 +30,7 @@
#include <strings.h>
#include <sys/types.h>
#include <regex.h>
+#include "curl/curl.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/utils.h"
@@ -719,6 +720,44 @@ url_func_result url_leafname(const char *url, char **result)
}
/**
+ * Extract fragment from an URL
+ * This will unescape any %xx entities in the fragment
+ *
+ * \param url an absolute URL
+ * \param result pointer to pointer to buffer to hold result
+ * \return URL_FUNC_OK on success
+ */
+
+url_func_result url_fragment(const char *url, char **result)
+{
+ url_func_result status;
+ struct url_components components;
+
+ assert(url);
+
+ status = url_get_components(url, &components);
+ if (status == URL_FUNC_OK) {
+ if (!components.fragment) {
+ status = URL_FUNC_FAILED;
+ } else {
+ char *frag = curl_unescape(components.fragment,
+ strlen(components.fragment));
+ if (!frag) {
+ status = URL_FUNC_NOMEM;
+ } else {
+ *result = strdup(frag);
+ if (!(*result))
+ status = URL_FUNC_NOMEM;
+ curl_free(frag);
+ }
+ }
+ }
+
+ url_destroy_components(&components);
+ return status;
+}
+
+/**
* Attempt to find a nice filename for a URL.
*
* \param url an absolute URL
@@ -897,12 +936,14 @@ url_func_result url_escape(const char *unescaped, bool sptoplus,
/**
* Compare two absolute, normalized URLs
*
- * \param url1 URL 1
- * \param url2 URL 2
- * \param result Pointer to location to store result (true if URLs match)
+ * \param url1 URL 1
+ * \param url2 URL 2
+ * \param nofrag Ignore fragment part in comparison
+ * \param result Pointer to location to store result (true if URLs match)
* \return URL_FUNC_OK on success
*/
-url_func_result url_compare(const char *url1, const char *url2, bool *result)
+url_func_result url_compare(const char *url1, const char *url2,
+ bool nofrag, bool *result)
{
url_func_result status;
struct url_components c1, c2;
@@ -930,7 +971,7 @@ url_func_result url_compare(const char *url1, const char *url2, bool *result)
((c1.path && c2.path) || (!c1.path && !c2.path)) &&
((c1.query && c2.query) ||
(!c1.query && !c2.query)) &&
- ((c1.fragment && c2.fragment) ||
+ (nofrag || (c1.fragment && c2.fragment) ||
(!c1.fragment && !c2.fragment))) {
if (c1.scheme)
@@ -946,7 +987,7 @@ url_func_result url_compare(const char *url1, const char *url2, bool *result)
if (c1.query)
res &= strcmp(c1.query, c2.query) == 0;
- if (c1.fragment)
+ if (!nofrag && c1.fragment)
res &= strcmp(c1.fragment, c2.fragment) == 0;
} else {
/* Can't match */
diff --git a/utils/url.h b/utils/url.h
index b35b6e376..9a1b934a5 100644
--- a/utils/url.h
+++ b/utils/url.h
@@ -54,8 +54,9 @@ url_func_result url_parent(const char *url, char **result);
url_func_result url_plq(const char *url, char **result);
url_func_result url_path(const char *url, char **result);
url_func_result url_leafname(const char *url, char **result);
+url_func_result url_fragment(const char *url, char **result);
url_func_result url_compare(const char *url1, const char *url2,
- bool *result);
+ bool nofrag, bool *result);
url_func_result url_get_components(const char *url,
struct url_components *result);