Handle cookies in unverifiable transactions

svn path=/trunk/netsurf/; revision=3151
This commit is contained in:
John Mark Bell 2007-01-27 20:58:20 +00:00
parent cd98970628
commit df4dbaf4cf
11 changed files with 216 additions and 92 deletions

View File

@ -565,7 +565,8 @@ bool content_set_type(struct content *c, content_type type,
}
content_remove_user(c, callback, p1, p2);
content_broadcast(clone, CONTENT_MSG_NEWPTR, msg_data);
fetchcache_go(clone, 0, callback, p1, p2,
fetchcache_go(clone, fetch_get_referer(c->fetch),
callback, p1, p2,
clone->width, clone->height,
0, 0, false);
}

View File

@ -64,9 +64,10 @@ struct fetch {
bool abort; /**< Abort requested. */
bool stopped; /**< Download stopped on purpose. */
bool only_2xx; /**< Only HTTP 2xx responses acceptable. */
bool cookies; /**< Send & accept cookies. */
bool verifiable; /**< Transaction is verifiable */
char *url; /**< URL. */
char *referer; /**< URL for Referer header. */
bool send_referer; /**< Valid to send the referer */
void *p; /**< Private data for callback. */
struct curl_slist *headers; /**< List of request headers. */
char *host; /**< Host part of URL. */
@ -299,12 +300,12 @@ void fetch_quit(void)
* callbacks will contain this.
*/
struct fetch * fetch_start(char *url, char *referer,
struct fetch * fetch_start(const char *url, const char *referer,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size),
void *p, bool only_2xx, char *post_urlenc,
struct form_successful_control *post_multipart, bool cookies,
char *headers[])
void *p, bool only_2xx, const char *post_urlenc,
struct form_successful_control *post_multipart,
bool verifiable, char *headers[])
{
char *host;
struct fetch *fetch;
@ -355,13 +356,16 @@ struct fetch * fetch_start(char *url, char *referer,
fetch->abort = false;
fetch->stopped = false;
fetch->only_2xx = only_2xx;
fetch->cookies = cookies;
fetch->verifiable = verifiable;
fetch->url = strdup(url);
fetch->referer = 0;
fetch->send_referer = false;
/* only send the referer if the schemes match */
if (referer) {
if (ref1 && ref2 && strcasecmp(ref1, ref2) == 0)
fetch->referer = strdup(referer);
fetch->referer = strdup(referer);
if (option_send_referer && ref1 && ref2 &&
strcasecmp(ref1, ref2) == 0)
fetch->send_referer = true;
}
fetch->p = p;
fetch->headers = 0;
@ -394,9 +398,7 @@ struct fetch * fetch_start(char *url, char *referer,
fetch->r_prev = 0;
fetch->r_next = 0;
if (!fetch->url || (referer &&
(ref1 && ref2 && strcasecmp(ref1, ref2) == 0) &&
!fetch->referer) ||
if (!fetch->url || (referer && !fetch->referer) ||
(post_urlenc && !fetch->post_urlenc) ||
(post_multipart && !fetch->post_multipart))
goto failed;
@ -647,7 +649,7 @@ CURLcode fetch_set_options(struct fetch *f)
SETOPT(CURLOPT_WRITEDATA, f);
SETOPT(CURLOPT_WRITEHEADER, f);
SETOPT(CURLOPT_PROGRESSDATA, f);
SETOPT(CURLOPT_REFERER, f->referer);
SETOPT(CURLOPT_REFERER, f->send_referer ? f->referer : 0);
SETOPT(CURLOPT_HTTPHEADER, f->headers);
if (f->post_urlenc) {
SETOPT(CURLOPT_POSTFIELDS, f->post_urlenc);
@ -656,11 +658,11 @@ CURLcode fetch_set_options(struct fetch *f)
} else {
SETOPT(CURLOPT_HTTPGET, 1L);
}
if (f->cookies) {
f->cookie_string = urldb_get_cookie(f->url, f->referer);
if (f->cookie_string)
SETOPT(CURLOPT_COOKIE, f->cookie_string);
}
f->cookie_string = urldb_get_cookie(f->url);
if (f->cookie_string)
SETOPT(CURLOPT_COOKIE, f->cookie_string);
#ifdef WITH_AUTH
if ((auth = urldb_get_auth_details(f->url)) != NULL) {
SETOPT(CURLOPT_HTTPAUTH, CURLAUTH_ANY);
@ -1212,11 +1214,20 @@ size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
f->cachedata.last_modified =
curl_getdate(&data[i], NULL);
}
} else if (f->cookies && 11 < size &&
strncasecmp(data, "Set-Cookie:", 11) == 0) {
} else if (11 < size && strncasecmp(data, "Set-Cookie:", 11) == 0) {
/* extract Set-Cookie header */
SKIP_ST(11);
urldb_set_cookie(&data[i], f->url);
/* If the fetch is unverifiable and there's no referer,
* err on the side of caution and do not set the cookie */
if (f->verifiable || f->referer) {
/* If the transaction's verifiable, we don't require
* that the request uri and the referer domain match,
* so don't pass in the referer in this case. */
urldb_set_cookie(&data[i], f->url,
f->verifiable ? 0 : f->referer);
}
}
return size;
@ -1454,6 +1465,18 @@ long fetch_http_code(struct fetch *fetch)
}
/**
* Get the referer
*
* \param fetch fetch to retrieve referer from
* \return Pointer to referer string, or NULL if none.
*/
const char *fetch_get_referer(struct fetch *fetch)
{
return fetch->referer;
}
#ifdef WITH_SSL
/**
* OpenSSL Certificate verification callback

View File

@ -66,12 +66,12 @@ extern bool fetch_active;
extern CURLM *fetch_curl_multi;
void fetch_init(void);
struct fetch * fetch_start(char *url, char *referer,
struct fetch * fetch_start(const char *url, const char *referer,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size),
void *p, bool only_2xx, char *post_urlenc,
void *p, bool only_2xx, const char *post_urlenc,
struct form_successful_control *post_multipart,
bool cookies, char *headers[]);
bool verifiable, char *headers[]);
void fetch_abort(struct fetch *f);
void fetch_poll(void);
void fetch_quit(void);
@ -83,5 +83,6 @@ void fetch_change_callback(struct fetch *fetch,
unsigned long size),
void *p);
long fetch_http_code(struct fetch *fetch);
const char *fetch_get_referer(struct fetch *fetch);
#endif

View File

@ -58,7 +58,7 @@ static void fetchcache_notmodified(struct content *c, const void *data);
* of generating an error page
* \param post_urlenc url encoded post data, or 0 if none
* \param post_multipart multipart post data, or 0 if none
* \param cookies send and accept cookies
* \param verifiable this transaction is verifiable
* \param download download, rather than render content
* \return a new content, or 0 on memory exhaustion
*
@ -73,7 +73,7 @@ struct content * fetchcache(const char *url,
bool no_error_pages,
char *post_urlenc,
struct form_successful_control *post_multipart,
bool cookies,
bool verifiable,
bool download)
{
struct content *c;
@ -202,19 +202,19 @@ struct content * fetchcache(const char *url,
* \param height available space
* \param post_urlenc url encoded post data, or 0 if none
* \param post_multipart multipart post data, or 0 if none
* \param cookies send and accept cookies
* \param verifiable this transaction is verifiable
*
* Errors will be sent back through the callback.
*/
void fetchcache_go(struct content *content, char *referer,
void fetchcache_go(struct content *content, const char *referer,
void (*callback)(content_msg msg, struct content *c,
intptr_t p1, intptr_t p2, union content_msg_data data),
intptr_t p1, intptr_t p2,
int width, int height,
char *post_urlenc,
struct form_successful_control *post_multipart,
bool cookies)
bool verifiable)
{
char error_message[500];
union content_msg_data msg_data;
@ -307,7 +307,7 @@ void fetchcache_go(struct content *content, char *referer,
content->fetch = fetch_start(content->url, referer,
fetchcache_callback, content,
content->no_error_pages,
post_urlenc, post_multipart, cookies,
post_urlenc, post_multipart, verifiable,
headers);
for (i = 0; headers[i]; i++)
free(headers[i]);
@ -745,6 +745,20 @@ void fetchcache_notmodified(struct content *c, const void *data)
else {
/* No cached content, so unconditionally refetch */
struct content_user *u;
const char *ref = fetch_get_referer(c->fetch);
char *referer = NULL;
if (ref) {
referer = strdup(ref);
if (!referer) {
c->type = CONTENT_UNKNOWN;
c->status = CONTENT_STATUS_ERROR;
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR,
msg_data);
return;
}
}
fetch_abort(c->fetch);
c->fetch = 0;
@ -754,9 +768,12 @@ void fetchcache_notmodified(struct content *c, const void *data)
c->cache_data->etag = 0;
for (u = c->user_list->next; u; u = u->next) {
fetchcache_go(c, 0, u->callback, u->p1, u->p2,
c->width, c->height, 0, 0, false);
fetchcache_go(c, referer, u->callback, u->p1, u->p2,
c->width, c->height, 0, 0,
false);
}
free(referer);
}
}

View File

@ -30,15 +30,15 @@ struct content * fetchcache(const char *url,
bool no_error_pages,
char *post_urlenc,
struct form_successful_control *post_multipart,
bool cookies,
bool verifiable,
bool download);
void fetchcache_go(struct content *content, char *referer,
void fetchcache_go(struct content *content, const char *referer,
void (*callback)(content_msg msg, struct content *c,
intptr_t p1, intptr_t p2, union content_msg_data data),
intptr_t p1, intptr_t p2,
int width, int height,
char *post_urlenc,
struct form_successful_control *post_multipart,
bool cookies);
bool verifiable);
#endif

View File

@ -2336,12 +2336,9 @@ struct search_node *urldb_search_split(struct search_node *root)
* Retrieve cookies for an URL
*
* \param url URL being fetched
* \param referer Referring resource, or NULL
* \return Cookies string for libcurl (on heap), or NULL on error/no cookies
*
* \todo Handle unvalidated fetches
*/
char *urldb_get_cookie(const char *url, const char *referer)
char *urldb_get_cookie(const char *url)
{
const struct path_data *p, *q;
const struct host_part *h;
@ -2356,11 +2353,7 @@ char *urldb_get_cookie(const char *url, const char *referer)
assert(url);
// LOG(("%s : %s", url, referer));
// if (referer)
// /* No unvalidated fetches for now */
// return NULL;
// LOG(("%s", url));
urldb_add_url(url);
@ -2455,7 +2448,8 @@ char *urldb_get_cookie(const char *url, const char *referer)
version = c->version;
c->last_used = now;
cookies_update(c->domain, (struct cookie_data *)c);
cookies_update(c->domain,
(struct cookie_data *)c);
count++;
}
}
@ -2577,9 +2571,11 @@ char *urldb_get_cookie(const char *url, const char *referer)
*
* \param header Header to parse, with Set-Cookie: stripped
* \param url URL being fetched
* \param referer Referring resource, or 0 for verifiable transaction
* \return true on success, false otherwise
*/
bool urldb_set_cookie(const char *header, const char *url)
bool urldb_set_cookie(const char *header, const char *url,
const char *referer)
{
const char *cur = header, *end;
char *path, *host, *scheme, *urlt;
@ -2616,6 +2612,40 @@ bool urldb_set_cookie(const char *header, const char *url)
return false;
}
if (referer) {
char *rhost, *rscheme;
/* Ensure that url's host name domain matches
* referer's (4.3.5) */
res = url_scheme(referer, &rscheme);
if (res != URL_FUNC_OK) {
goto error;
}
res = url_host(referer, &rhost);
if (res != URL_FUNC_OK) {
free(rscheme);
goto error;
}
if (strcasecmp(scheme, rscheme) != 0) {
/* Schemes don't match => fail */
free(rhost);
free(rscheme);
goto error;
}
/* Domain match host names (both are FQDN or IP) */
if (strcasecmp(host, rhost) != 0) {
free(rhost);
free(rscheme);
goto error;
}
free(rhost);
free(rscheme);
}
end = cur + strlen(cur) - 2 /* Trailing CRLF */;
do {

View File

@ -98,8 +98,9 @@ void urldb_iterate_cookies(bool (*callback)(const char *domain,
void urldb_dump(void);
/* Cookies */
bool urldb_set_cookie(const char *header, const char *url);
char *urldb_get_cookie(const char *url, const char *referer);
bool urldb_set_cookie(const char *header, const char *url,
const char *referer);
char *urldb_get_cookie(const char *url);
void urldb_delete_cookie(const char *domain, const char *path, const char *name);
void urldb_load_cookies(const char *filename);
void urldb_save_cookies(const char *filename);

View File

@ -59,6 +59,11 @@ struct content browser_window_href_content;
/** maximum frame depth */
#define FRAME_DEPTH 8
static void browser_window_go_post(struct browser_window *bw,
const char *url, char *post_urlenc,
struct form_successful_control *post_multipart,
bool history_add, const char *referer, bool download,
bool verifiable);
static void browser_window_callback(content_msg msg, struct content *c,
intptr_t p1, intptr_t p2, union content_msg_data data);
static void browser_window_refresh(void *p);
@ -111,12 +116,12 @@ static void browser_window_scroll_box(struct browser_window *bw,
*
* \param url URL to start fetching in the new window (copied)
* \param clone The browser window to clone
* \param referer The referring uri
* \param referer The referring uri (copied), or 0 if none
*/
struct browser_window *browser_window_create(const char *url,
struct browser_window *clone,
char *referer, bool history_add)
const char *referer, bool history_add)
{
struct browser_window *bw;
@ -153,6 +158,7 @@ struct browser_window *browser_window_create(const char *url,
}
if (url)
browser_window_go(bw, url, referer, history_add);
return bw;
}
@ -162,18 +168,40 @@ struct browser_window *browser_window_create(const char *url,
*
* \param bw browser window
* \param url URL to start fetching (copied)
* \param referer the referring uri
* \param referer the referring uri (copied), or 0 if none
*
* Any existing fetches in the window are aborted.
*/
void browser_window_go(struct browser_window *bw, const char *url,
char* referer, bool history_add)
const char* referer, bool history_add)
{
browser_window_go_post(bw, url, 0, 0, history_add, referer, false);
/* All fetches passing through here are verifiable
* (i.e are the result of user action) */
browser_window_go_post(bw, url, 0, 0, history_add, referer,
false, true);
}
/**
* Start fetching a page in a browser window.
*
* \param bw browser window
* \param url URL to start fetching (copied)
* \param referer the referring uri (copied), or 0 if none
*
* Any existing fetches in the window are aborted.
*/
void browser_window_go_unverifiable(struct browser_window *bw,
const char *url, const char* referer, bool history_add)
{
/* All fetches passing through here are unverifiable
* (i.e are not the result of user action) */
browser_window_go_post(bw, url, 0, 0, history_add, referer,
false, false);
}
/**
* Start fetching a page in a browser window, POSTing form data.
*
@ -182,8 +210,9 @@ void browser_window_go(struct browser_window *bw, const char *url,
* \param post_urlenc url encoded post data, or 0 if none
* \param post_multipart multipart post data, or 0 if none
* \param history_add add to window history
* \param referer the referring uri
* \param referer the referring uri (copied), or 0 if none
* \param download download, rather than render the uri
* \param verifiable this transaction is verifiable
*
* Any existing fetches in the window are aborted.
*
@ -196,7 +225,8 @@ void browser_window_go(struct browser_window *bw, const char *url,
void browser_window_go_post(struct browser_window *bw, const char *url,
char *post_urlenc,
struct form_successful_control *post_multipart,
bool history_add, char *referer, bool download)
bool history_add, const char *referer, bool download,
bool verifiable)
{
struct content *c;
char *url2;
@ -215,7 +245,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
for (cur = bw; cur->parent; cur = cur->parent)
depth++;
if (depth > FRAME_DEPTH) {
LOG(("frame depth too high."));
LOG(("frame depth too high."));
return;
}
@ -287,7 +317,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
bw->history_add = history_add;
c = fetchcache(url2, browser_window_callback, (intptr_t) bw, 0,
width, height, false,
post_urlenc, post_multipart, true, download);
post_urlenc, post_multipart, verifiable, download);
free(url2);
if (!c) {
browser_window_set_status(bw, messages_get("NoMemory"));
@ -304,9 +334,9 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
}
bw->download = download;
fetchcache_go(c, option_send_referer ? referer : 0,
browser_window_callback, (intptr_t) bw, 0, width, height,
post_urlenc, post_multipart, true);
fetchcache_go(c, referer, browser_window_callback,
(intptr_t) bw, 0, width, height,
post_urlenc, post_multipart, verifiable);
}
@ -318,7 +348,6 @@ void browser_window_callback(content_msg msg, struct content *c,
intptr_t p1, intptr_t p2, union content_msg_data data)
{
struct browser_window *bw = (struct browser_window *) p1;
char status[40];
char url[256];
switch (msg) {
@ -453,7 +482,7 @@ void browser_window_callback(content_msg msg, struct content *c,
* referer across the redirect */
browser_window_go_post(bw, data.redirect, 0, 0,
bw->history_add, bw->referer,
bw->download);
bw->download, false);
break;
case CONTENT_MSG_REFORMAT:
@ -462,7 +491,7 @@ void browser_window_callback(content_msg msg, struct content *c,
/* reposition frames */
if (c->data.html.frameset)
browser_window_recalculate_frameset(bw);
/* reflow iframe positions */
/* reflow iframe positions */
if (c->data.html.iframe)
browser_window_recalculate_iframes(bw);
/* box tree may have changed, need to relabel */
@ -586,7 +615,7 @@ void browser_window_refresh(void *p)
bw->current_content->refresh)))
history_add = false;
browser_window_go(bw, bw->current_content->refresh,
browser_window_go_unverifiable(bw, bw->current_content->refresh,
bw->current_content->url, history_add);
}
@ -759,7 +788,7 @@ void browser_window_reload(struct browser_window *bw, bool all)
}
bw->current_content->fresh = false;
browser_window_go_post(bw, bw->current_content->url, 0, 0,
false, 0, false);
false, 0, false, true);
}
@ -1413,7 +1442,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
mouse & BROWSER_MOUSE_MOD_1) {
/* force download of link */
browser_window_go_post(bw, url, 0, 0, false,
c->url, true);
c->url, true, true);
} else if (mouse & BROWSER_MOUSE_CLICK_1) {
bw = browser_window_find_target(bw, target);
@ -1426,7 +1455,8 @@ void browser_window_mouse_action_html(struct browser_window *bw,
if (!browser_window_href_content.url)
warn_user("NoMemory", 0);
else
gui_window_save_as_link(bw->window, &browser_window_href_content);
gui_window_save_as_link(bw->window,
&browser_window_href_content);
} else if (mouse & BROWSER_MOUSE_CLICK_2) {
/* open link in new window */
browser_window_create(url, bw, c->url, true);
@ -2246,7 +2276,8 @@ void browser_form_submit(struct browser_window *bw, const char *target,
warn_user("NoMemory", 0);
return;
}
url = calloc(1, strlen(form->action) + strlen(data) + 2);
url = calloc(1, strlen(form->action) +
strlen(data) + 2);
if (!url) {
form_free_successful(success);
free(data);
@ -2259,8 +2290,8 @@ void browser_form_submit(struct browser_window *bw, const char *target,
else {
sprintf(url, "%s?%s", form->action, data);
}
browser_window_go(bw_form, url, bw->current_content->url,
true);
browser_window_go(bw_form, url,
bw->current_content->url, true);
break;
case method_POST_URLENC:
@ -2272,13 +2303,14 @@ void browser_form_submit(struct browser_window *bw, const char *target,
}
browser_window_go_post(bw_form, form->action, data, 0,
true, bw->current_content->url,
false);
false, true);
break;
case method_POST_MULTIPART:
browser_window_go_post(bw_form, form->action, 0, success,
true, bw->current_content->url,
false);
browser_window_go_post(bw_form, form->action, 0,
success, true,
bw->current_content->url,
false, true);
break;
default:

View File

@ -123,11 +123,11 @@ struct browser_window {
/** Window characteristics */
enum {
BROWSER_WINDOW_NORMAL,
BROWSER_WINDOW_IFRAME,
BROWSER_WINDOW_FRAME,
BROWSER_WINDOW_FRAMESET,
} browser_window_type;
BROWSER_WINDOW_NORMAL,
BROWSER_WINDOW_IFRAME,
BROWSER_WINDOW_FRAME,
BROWSER_WINDOW_FRAMESET,
} browser_window_type;
/** frameset characteristics */
int rows;
@ -179,13 +179,12 @@ typedef enum {
extern struct browser_window *current_redraw_browser;
struct browser_window * browser_window_create(const char *url,
struct browser_window *clone, char *referer, bool history_add);
struct browser_window *clone, const char *referer,
bool history_add);
void browser_window_go(struct browser_window *bw, const char *url,
char *referer, bool history_add);
void browser_window_go_post(struct browser_window *bw, const char *url,
char *post_urlenc,
struct form_successful_control *post_multipart,
bool history_add, char *referer, bool download);
const char *referer, bool history_add);
void browser_window_go_unverifiable(struct browser_window *bw,
const char *url, const char *referer, bool history_add);
void browser_window_update(struct browser_window *bw, bool scroll_to_top);
void browser_window_stop(struct browser_window *bw);
void browser_window_reload(struct browser_window *bw, bool all);

View File

@ -99,7 +99,8 @@ void browser_window_create_iframes(struct browser_window *bw,
for (cur = iframe; cur; cur = cur->next) {
window = &(bw->iframes[index++]);
if (cur->url)
browser_window_go(window, cur->url, NULL, true);
browser_window_go_unverifiable(window, cur->url,
bw->current_content->url, true);
}
}
@ -148,6 +149,7 @@ void browser_window_create_frameset(struct browser_window *bw,
int row, col, index;
struct content_html_frames *frame;
struct browser_window *window;
const char *referer;
assert(bw && frameset);
@ -174,9 +176,11 @@ void browser_window_create_frameset(struct browser_window *bw,
/* window characteristics */
window->drag_type = DRAGGING_NONE;
if (frame->children)
window->browser_window_type = BROWSER_WINDOW_FRAMESET;
window->browser_window_type =
BROWSER_WINDOW_FRAMESET;
else
window->browser_window_type = BROWSER_WINDOW_FRAME;
window->browser_window_type =
BROWSER_WINDOW_FRAME;
window->scrolling = frame->scrolling;
window->border = frame->border;
window->border_colour = frame->border_colour;
@ -212,6 +216,18 @@ void browser_window_create_frameset(struct browser_window *bw,
}
}
/* Use the URL of the first ancestor window containing html content
* as the referer */
for (window = bw; window->parent; window = window->parent) {
if (window->current_content &&
window->current_content->type == CONTENT_HTML)
break;
}
if (window->current_content)
referer = window->current_content->url;
else
referer = NULL;
/* 4. Launch content */
for (row = 0; row < bw->rows; row++) {
for (col = 0; col < bw->cols; col++) {
@ -219,8 +235,12 @@ void browser_window_create_frameset(struct browser_window *bw,
frame = &frameset->children[index];
window = &bw->children[index];
if (frame->url)
browser_window_go(window, frame->url, NULL, true);
if (frame->url) {
browser_window_go_unverifiable(window,
frame->url,
referer,
true);
}
}
}
}

View File

@ -1651,7 +1651,7 @@ bool plugin_start_fetch(struct plugin_stream *p, const char *url)
}
c = fetchcache(url2, plugin_stream_callback, (intptr_t)p, 0,
100, 100, true, 0, 0, true, true);
100, 100, true, 0, 0, false, true);
free(url2);
if (!c) {
return false;
@ -1659,7 +1659,7 @@ bool plugin_start_fetch(struct plugin_stream *p, const char *url)
p->c = c;
fetchcache_go(c, 0, plugin_stream_callback, (intptr_t)p, 0,
100, 100, 0, 0, true);
100, 100, 0, 0, false);
return true;
}