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
This commit is contained in:
John Mark Bell 2008-02-03 12:04:48 +00:00
parent eb2c2e3f63
commit ad6fcea6b0
9 changed files with 118 additions and 47 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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);
}

View File

@ -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"
@ -718,6 +719,44 @@ url_func_result url_leafname(const char *url, char **result)
return status;
}
/**
* 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.
*
@ -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 */

View File

@ -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);