[libsoup] Implement acceptance policies in SoupCookieJar
- From: Xan Lopez <xan src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libsoup] Implement acceptance policies in SoupCookieJar
- Date: Wed, 3 Feb 2010 19:24:43 +0000 (UTC)
commit 9deb863e27177ad47586b01be8b4e2ad91a62cc7
Author: Xan Lopez <xan gnome org>
Date: Thu Jan 28 18:31:08 2010 +0200
Implement acceptance policies in SoupCookieJar
Through the "accept-policy" property in the jar we can now set one
among three predetermined policies: accept all cookies
(SOUP_COOKIE_JAR_ACCEPT_ALWAYS), accept none
(SOUP_COOKIE_JAR_ACCEPT_NEVER) and only accept cookies set by the main
document we are loading (SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY).
A new property, "first-party", is added to SoupMessage so that the
application using libsoup can inform us of what is the main document
URI for each message that is requested.
libsoup/soup-cookie-jar.c | 166 +++++++++++++++++++++++++++++++++++++++-
libsoup/soup-cookie-jar.h | 46 +++++++-----
libsoup/soup-cookie.c | 25 +++++-
libsoup/soup-cookie.h | 3 +
libsoup/soup-message-private.h | 2 +
libsoup/soup-message.c | 76 ++++++++++++++++++
libsoup/soup-message.h | 4 +
tests/Makefile.am | 7 +-
tests/cookies-test.c | 119 ++++++++++++++++++++++++++++
9 files changed, 422 insertions(+), 26 deletions(-)
---
diff --git a/libsoup/soup-cookie-jar.c b/libsoup/soup-cookie-jar.c
index e5a80a6..8f0e62a 100644
--- a/libsoup/soup-cookie-jar.c
+++ b/libsoup/soup-cookie-jar.c
@@ -15,6 +15,7 @@
#include "soup-cookie.h"
#include "soup-cookie-jar.h"
#include "soup-date.h"
+#include "soup-enum-types.h"
#include "soup-marshal.h"
#include "soup-message.h"
#include "soup-session-feature.h"
@@ -57,6 +58,7 @@ enum {
PROP_0,
PROP_READ_ONLY,
+ PROP_ACCEPT_POLICY,
LAST_PROP
};
@@ -65,6 +67,7 @@ typedef struct {
gboolean constructed, read_only;
GHashTable *domains, *serials;
guint serial;
+ SoupCookieJarAcceptPolicy accept_policy;
} SoupCookieJarPrivate;
#define SOUP_COOKIE_JAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_COOKIE_JAR, SoupCookieJarPrivate))
@@ -82,6 +85,7 @@ soup_cookie_jar_init (SoupCookieJar *jar)
soup_str_case_equal,
g_free, NULL);
priv->serials = g_hash_table_new (NULL, NULL);
+ priv->accept_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
}
static void
@@ -158,6 +162,20 @@ soup_cookie_jar_class_init (SoupCookieJarClass *jar_class)
"Whether or not the cookie jar is read-only",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * SOUP_COOKIE_JAR_ACCEPT_POLICY:
+ *
+ * Alias for the #SoupCookieJar:accept-policy property.
+ **/
+ g_object_class_install_property (
+ object_class, PROP_ACCEPT_POLICY,
+ g_param_spec_enum (SOUP_COOKIE_JAR_ACCEPT_POLICY,
+ "Accept-policy",
+ "The policy the jar should follow to accept or reject cookies",
+ SOUP_TYPE_COOKIE_JAR_ACCEPT_POLICY,
+ SOUP_COOKIE_JAR_ACCEPT_ALWAYS,
+ G_PARAM_READWRITE));
}
static void
@@ -180,6 +198,9 @@ set_property (GObject *object, guint prop_id,
case PROP_READ_ONLY:
priv->read_only = g_value_get_boolean (value);
break;
+ case PROP_ACCEPT_POLICY:
+ priv->accept_policy = g_value_get_enum (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -197,6 +218,9 @@ get_property (GObject *object, guint prop_id,
case PROP_READ_ONLY:
g_value_set_boolean (value, priv->read_only);
break;
+ case PROP_ACCEPT_POLICY:
+ g_value_set_enum (value, priv->accept_policy);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -443,6 +467,12 @@ soup_cookie_jar_add_cookie (SoupCookieJar *jar, SoupCookie *cookie)
* Adds @cookie to @jar, exactly as though it had appeared in a
* Set-Cookie header returned from a request to @uri.
*
+ * Keep in mind that if the #SoupCookieJarAcceptPolicy
+ * %SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY is set you'll need to use
+ * soup_cookie_jar_set_cookie_with_first_party(), otherwise the jar
+ * will have no way of knowing if the cookie is being set by a third
+ * party or not.
+ *
* Since: 2.24
**/
void
@@ -450,6 +480,7 @@ soup_cookie_jar_set_cookie (SoupCookieJar *jar, SoupURI *uri,
const char *cookie)
{
SoupCookie *soup_cookie;
+ SoupCookieJarPrivate *priv;
g_return_if_fail (SOUP_IS_COOKIE_JAR (jar));
g_return_if_fail (uri != NULL);
@@ -458,6 +489,12 @@ soup_cookie_jar_set_cookie (SoupCookieJar *jar, SoupURI *uri,
if (!SOUP_URI_VALID_FOR_HTTP (uri))
return;
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+ if (priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_NEVER)
+ return;
+
+ g_return_if_fail (priv->accept_policy != SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
+
soup_cookie = soup_cookie_parse (cookie, uri);
if (soup_cookie) {
/* will steal or free soup_cookie */
@@ -465,15 +502,78 @@ soup_cookie_jar_set_cookie (SoupCookieJar *jar, SoupURI *uri,
}
}
+/**
+ * soup_cookie_jar_set_cookie_with_first_party:
+ * @jar: a #SoupCookieJar
+ * @uri: the URI setting the cookie
+ * @first_party: the URI for the main document
+ * @cookie: the stringified cookie to set
+ *
+ * Adds @cookie to @jar, exactly as though it had appeared in a
+ * Set-Cookie header returned from a request to @uri. @first_party
+ * will be used to reject cookies coming from third party resources in
+ * case such a security policy is set in the @jar.
+ *
+ * Since: 2.30
+ **/
+void
+soup_cookie_jar_set_cookie_with_first_party (SoupCookieJar *jar,
+ SoupURI *uri,
+ SoupURI *first_party,
+ const char *cookie)
+{
+ SoupCookie *soup_cookie;
+ SoupCookieJarPrivate *priv;
+
+ g_return_if_fail (SOUP_IS_COOKIE_JAR (jar));
+ g_return_if_fail (uri != NULL);
+ g_return_if_fail (first_party != NULL);
+ g_return_if_fail (cookie != NULL);
+
+ if (!SOUP_URI_VALID_FOR_HTTP (uri))
+ return;
+
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+ if (priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_NEVER)
+ return;
+
+ soup_cookie = soup_cookie_parse (cookie, uri);
+ if (soup_cookie) {
+ if (priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_ALWAYS ||
+ soup_cookie_domain_matches (soup_cookie, first_party->host)) {
+ /* will steal or free soup_cookie */
+ soup_cookie_jar_add_cookie (jar, soup_cookie);
+ } else {
+ soup_cookie_free (soup_cookie);
+ }
+ }
+}
+
static void
process_set_cookie_header (SoupMessage *msg, gpointer user_data)
{
SoupCookieJar *jar = user_data;
+ SoupCookieJarPrivate *priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
GSList *new_cookies, *nc;
+ if (priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_NEVER)
+ return;
+
new_cookies = soup_cookies_from_response (msg);
- for (nc = new_cookies; nc; nc = nc->next)
- soup_cookie_jar_add_cookie (jar, nc->data);
+ for (nc = new_cookies; nc; nc = nc->next) {
+ SoupURI *first_party = soup_message_get_first_party (msg);
+
+ if (first_party == NULL &&
+ priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY)
+ continue; /* Can't check anything */
+
+ if ((priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY &&
+ soup_cookie_domain_matches (nc->data, first_party->host)) ||
+ priv->accept_policy == SOUP_COOKIE_JAR_ACCEPT_ALWAYS)
+ soup_cookie_jar_add_cookie (jar, nc->data);
+ else
+ soup_cookie_free (nc->data);
+ }
g_slist_free (new_cookies);
}
@@ -586,3 +686,65 @@ soup_cookie_jar_delete_cookie (SoupCookieJar *jar,
}
}
}
+
+/**
+ * SoupCookieJarAcceptPolicy:
+ * @SOUP_COOKIE_JAR_ACCEPT_ALWAYS: accept all cookies unconditionally.
+ * @SOUP_COOKIE_JAR_ACCEPT_NEVER: reject all cookies unconditionally.
+ * @SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY: accept all cookies set by
+ * the main document loaded in the application using libsoup. An
+ * example of the most common case, web browsers, would be: If
+ * http://www.example.com is the page loaded, accept all cookies set
+ * by example.com, but if a resource from http://www.third-party.com
+ * is loaded from that page reject any cookie that it could try to
+ * set. For libsoup to be able to tell apart first party cookies from
+ * the rest, the application must call soup_message_set_first_party()
+ * on each outgoing #SoupMessage, setting the #SoupURI of the main
+ * document. If no first party is set in a message when this policy is
+ * in effect, cookies will be assumed to be third party by default.
+ *
+**/
+
+/**
+ * soup_cookie_jar_get_accept_policy:
+ * @jar: a #SoupCookieJar
+ *
+ * Returns: the #SoupCookieJarAcceptPolicy set in the @jar
+ *
+ * Since: 2.30
+ **/
+SoupCookieJarAcceptPolicy
+soup_cookie_jar_get_accept_policy (SoupCookieJar *jar)
+{
+ SoupCookieJarPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_COOKIE_JAR (jar), SOUP_COOKIE_JAR_ACCEPT_ALWAYS);
+
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+ return priv->accept_policy;
+}
+
+/**
+ * soup_cookie_jar_set_accept_policy:
+ * @jar: a #SoupCookieJar
+ * @policy: a #SoupCookieJarAcceptPolicy
+ *
+ * Sets @policy as the cookie acceptance policy for @jar.
+ *
+ * Since: 2.30
+ **/
+void
+soup_cookie_jar_set_accept_policy (SoupCookieJar *jar,
+ SoupCookieJarAcceptPolicy policy)
+{
+ SoupCookieJarPrivate *priv;
+
+ g_return_if_fail (SOUP_IS_COOKIE_JAR (jar));
+
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+
+ if (priv->accept_policy != policy) {
+ priv->accept_policy = policy;
+ g_object_notify (G_OBJECT (jar), SOUP_COOKIE_JAR_ACCEPT_POLICY);
+ }
+}
diff --git a/libsoup/soup-cookie-jar.h b/libsoup/soup-cookie-jar.h
index 3b0c3c6..eab64bf 100644
--- a/libsoup/soup-cookie-jar.h
+++ b/libsoup/soup-cookie-jar.h
@@ -39,29 +39,37 @@ typedef struct {
} SoupCookieJarClass;
#define SOUP_COOKIE_JAR_READ_ONLY "read-only"
+#define SOUP_COOKIE_JAR_ACCEPT_POLICY "accept-policy"
-GType soup_cookie_jar_get_type (void);
-
-SoupCookieJar *soup_cookie_jar_new (void);
+typedef enum {
+ SOUP_COOKIE_JAR_ACCEPT_ALWAYS,
+ SOUP_COOKIE_JAR_ACCEPT_NEVER,
+ SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY
+} SoupCookieJarAcceptPolicy;
+GType soup_cookie_jar_get_type (void);
+SoupCookieJar * soup_cookie_jar_new (void);
#ifndef LIBSOUP_DISABLE_DEPRECATED
-void soup_cookie_jar_save (SoupCookieJar *jar);
+void soup_cookie_jar_save (SoupCookieJar *jar);
#endif
-
-char *soup_cookie_jar_get_cookies (SoupCookieJar *jar,
- SoupURI *uri,
- gboolean for_http);
-void soup_cookie_jar_set_cookie (SoupCookieJar *jar,
- SoupURI *uri,
- const char *cookie);
-
-void soup_cookie_jar_add_cookie (SoupCookieJar *jar,
- SoupCookie *cookie);
-void soup_cookie_jar_delete_cookie (SoupCookieJar *jar,
- SoupCookie *cookie);
-
-GSList *soup_cookie_jar_all_cookies (SoupCookieJar *jar);
-
+char * soup_cookie_jar_get_cookies (SoupCookieJar *jar,
+ SoupURI *uri,
+ gboolean for_http);
+void soup_cookie_jar_set_cookie (SoupCookieJar *jar,
+ SoupURI *uri,
+ const char *cookie);
+void soup_cookie_jar_set_cookie_with_first_party (SoupCookieJar *jar,
+ SoupURI *uri,
+ SoupURI *first_party,
+ const char *cookie);
+void soup_cookie_jar_add_cookie (SoupCookieJar *jar,
+ SoupCookie *cookie);
+void soup_cookie_jar_delete_cookie (SoupCookieJar *jar,
+ SoupCookie *cookie);
+GSList * soup_cookie_jar_all_cookies (SoupCookieJar *jar);
+void soup_cookie_jar_set_accept_policy (SoupCookieJar *jar,
+ SoupCookieJarAcceptPolicy policy);
+SoupCookieJarAcceptPolicy soup_cookie_jar_get_accept_policy (SoupCookieJar *jar);
G_END_DECLS
diff --git a/libsoup/soup-cookie.c b/libsoup/soup-cookie.c
index 8ac39dc..7f51496 100644
--- a/libsoup/soup-cookie.c
+++ b/libsoup/soup-cookie.c
@@ -116,11 +116,30 @@ soup_cookie_copy (SoupCookie *cookie)
return copy;
}
-static gboolean
-domain_matches (const char *domain, const char *host)
+/**
+ * soup_cookie_domain_matches:
+ * @cookie: a #SoupCookie
+ * @host: a URI
+ *
+ * Checks if the @cookie's domain and @host match in the sense that
+ * @cookie should be sent when making a request to @host, or that
+ * @cookie should be accepted when receiving a response from @host.
+ *
+ * Return value: %TRUE if the domains match, %FALSE otherwise
+ *
+ * Since: 2.30
+ **/
+gboolean
+soup_cookie_domain_matches (SoupCookie *cookie, const char *host)
{
char *match;
int dlen;
+ const char *domain;
+
+ g_return_val_if_fail (cookie != NULL, FALSE);
+ g_return_val_if_fail (host != NULL, FALSE);
+
+ domain = cookie->domain;
if (!g_ascii_strcasecmp (domain, host))
return TRUE;
@@ -288,7 +307,7 @@ parse_one_cookie (const char *header, SoupURI *origin)
if (origin) {
/* Sanity-check domain */
if (cookie->domain) {
- if (!domain_matches (cookie->domain, origin->host)) {
+ if (!soup_cookie_domain_matches (cookie, origin->host)) {
soup_cookie_free (cookie);
return NULL;
}
diff --git a/libsoup/soup-cookie.h b/libsoup/soup-cookie.h
index 34a2aa4..8bccd90 100644
--- a/libsoup/soup-cookie.h
+++ b/libsoup/soup-cookie.h
@@ -76,6 +76,9 @@ void soup_cookies_free (GSList *cookies);
char *soup_cookies_to_cookie_header (GSList *cookies);
+gboolean soup_cookie_domain_matches (SoupCookie *cookie,
+ const char *host);
+
G_END_DECLS
#endif /* SOUP_COOKIE_H */
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index ee6221d..f279303 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -41,6 +41,8 @@ typedef struct {
GSList *disabled_features;
GSList *decoders;
+
+ SoupURI *first_party;
} SoupMessagePrivate;
#define SOUP_MESSAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_MESSAGE, SoupMessagePrivate))
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 4545e5c..5a0035f 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -119,6 +119,7 @@ enum {
PROP_SERVER_SIDE,
PROP_STATUS_CODE,
PROP_REASON_PHRASE,
+ PROP_FIRST_PARTY,
LAST_PROP
};
@@ -158,6 +159,8 @@ finalize (GObject *object)
if (priv->uri)
soup_uri_free (priv->uri);
+ if (priv->first_party)
+ soup_uri_free (priv->first_party);
if (priv->addr)
g_object_unref (priv->addr);
@@ -576,6 +579,21 @@ soup_message_class_init (SoupMessageClass *message_class)
"The HTTP response reason phrase",
NULL,
G_PARAM_READWRITE));
+
+ /**
+ * SOUP_MESSAGE_FIRST_PARTY:
+ *
+ * Alias for the #SoupMessage:first-party property. (The
+ * #SoupURI loaded in the application when the message was
+ * queued.)
+ **/
+ g_object_class_install_property (
+ object_class, PROP_FIRST_PARTY,
+ g_param_spec_boxed (SOUP_MESSAGE_FIRST_PARTY,
+ "First party",
+ "The URI loaded in the application when the message was requested.",
+ SOUP_TYPE_URI,
+ G_PARAM_READWRITE));
}
static void
@@ -612,6 +630,9 @@ set_property (GObject *object, guint prop_id,
soup_message_set_status_full (msg, msg->status_code,
g_value_get_string (value));
break;
+ case PROP_FIRST_PARTY:
+ soup_message_set_first_party (msg, g_value_get_boxed (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -647,6 +668,9 @@ get_property (GObject *object, guint prop_id,
case PROP_REASON_PHRASE:
g_value_set_string (value, msg->reason_phrase);
break;
+ case PROP_FIRST_PARTY:
+ g_value_set_boxed (value, priv->first_party);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1661,3 +1685,55 @@ soup_message_disables_feature (SoupMessage *msg, gpointer feature)
}
return FALSE;
}
+
+/**
+ * soup_message_get_first_party:
+ * @msg: a #SoupMessage
+ *
+ * Returns: the @msg's first party #SoupURI
+ *
+ * Since: 2.30
+ **/
+SoupURI*
+soup_message_get_first_party (SoupMessage *msg)
+{
+ SoupMessagePrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
+
+ priv = SOUP_MESSAGE_GET_PRIVATE (msg);
+ return priv->first_party;
+}
+
+/**
+ * soup_message_set_first_party:
+ * @msg: a #SoupMessage
+ * @first_party: the #SoupURI for the @msg's first party
+ *
+ * Sets @first_party as the main document #SoupURI for @msg. For
+ * details of when and how this is used refer to the documentation for
+ * #SoupCookieJarAcceptPolicy.
+ *
+ * Since: 2.30
+ **/
+void
+soup_message_set_first_party (SoupMessage *msg,
+ SoupURI *first_party)
+{
+ SoupMessagePrivate *priv;
+
+ g_return_if_fail (SOUP_IS_MESSAGE (msg));
+ g_return_if_fail (first_party != NULL);
+
+ priv = SOUP_MESSAGE_GET_PRIVATE (msg);
+
+ if (priv->first_party) {
+ if (soup_uri_equal (priv->first_party, first_party))
+ return;
+
+ soup_uri_free (priv->first_party);
+ }
+
+ priv->first_party = soup_uri_copy (first_party);
+ g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_FIRST_PARTY);
+}
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index 4fc9122..2638620 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -67,6 +67,7 @@ GType soup_message_get_type (void);
#define SOUP_MESSAGE_SERVER_SIDE "server-side"
#define SOUP_MESSAGE_STATUS_CODE "status-code"
#define SOUP_MESSAGE_REASON_PHRASE "reason-phrase"
+#define SOUP_MESSAGE_FIRST_PARTY "first-party"
SoupMessage *soup_message_new (const char *method,
const char *uri_string);
@@ -100,6 +101,9 @@ void soup_message_set_uri (SoupMessage *msg,
SoupURI *uri);
SoupAddress *soup_message_get_address (SoupMessage *msg);
+SoupURI *soup_message_get_first_party (SoupMessage *msg);
+void soup_message_set_first_party (SoupMessage *msg,
+ SoupURI *first_party);
typedef enum {
SOUP_MESSAGE_NO_REDIRECT = (1 << 1),
#ifndef LIBSOUP_DISABLE_DEPRECATED
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 194d151..b69d27a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -17,6 +17,7 @@ noinst_PROGRAMS = \
coding-test \
context-test \
continue-test \
+ cookies-test \
date \
dns \
forms-test \
@@ -33,7 +34,7 @@ noinst_PROGRAMS = \
timeout-test \
uri-parsing \
$(CURL_TESTS) \
- $(APACHE_TESTS) \
+ $(APACHE_TESTS) \
$(SSL_TESTS) \
$(XMLRPC_TESTS)
@@ -44,6 +45,7 @@ chunk_test_SOURCES = chunk-test.c $(TEST_SRCS)
coding_test_SOURCES = coding-test.c $(TEST_SRCS)
context_test_SOURCES = context-test.c $(TEST_SRCS)
continue_test_SOURCES = continue-test.c $(TEST_SRCS)
+cookies_test_SOURCES = cookies-test.c $(TEST_SRCS)
date_SOURCES = date.c $(TEST_SRCS)
dns_SOURCES = dns.c
forms_test_SOURCES = forms-test.c $(TEST_SRCS)
@@ -88,6 +90,7 @@ TESTS = \
coding-test \
context-test \
continue-test \
+ cookies-test \
date \
header-parsing \
misc-test \
@@ -97,7 +100,7 @@ TESTS = \
streaming-test \
timeout-test \
uri-parsing \
- $(APACHE_TESTS) \
+ $(APACHE_TESTS) \
$(CURL_TESTS) \
$(SSL_TESTS) \
$(XMLRPC_TESTS)
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
new file mode 100644
index 0000000..4e0c4d1
--- /dev/null
+++ b/tests/cookies-test.c
@@ -0,0 +1,119 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ */
+
+#include <glib.h>
+#include <libsoup/soup.h>
+
+#include "test-utils.h"
+
+SoupServer *server;
+SoupURI *first_party_uri, *third_party_uri;
+const char *first_party = "http://127.0.0.1/";
+const char *third_party = "http://localhost/";
+
+static void
+server_callback (SoupServer *server, SoupMessage *msg,
+ const char *path, GHashTable *query,
+ SoupClientContext *context, gpointer data)
+{
+ if (g_str_equal(path, "/index.html"))
+ soup_message_headers_replace (msg->response_headers,
+ "Set-Cookie",
+ "foo=bar");
+ else if (g_str_equal (path, "/foo.jpg"))
+ soup_message_headers_replace (msg->response_headers,
+ "Set-Cookie",
+ "baz=qux");
+ else
+ g_return_if_reached ();
+
+ soup_message_set_status (msg, SOUP_STATUS_OK);
+}
+
+typedef struct {
+ SoupCookieJarAcceptPolicy policy;
+ int n_cookies;
+} CookiesForPolicy;
+
+static const CookiesForPolicy validResults[] = {
+ { SOUP_COOKIE_JAR_ACCEPT_ALWAYS, 2 },
+ { SOUP_COOKIE_JAR_ACCEPT_NEVER, 0 },
+ { SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, 1 }
+};
+
+static void
+do_cookies_accept_policy_test (void)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ SoupURI *uri;
+ SoupCookieJar *jar;
+ GSList *l, *p;
+ int i;
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+ soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
+ jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR));
+
+ for (i = 0; i < G_N_ELEMENTS (validResults); i++) {
+ soup_cookie_jar_set_accept_policy (jar, validResults[i].policy);
+
+ uri = soup_uri_new_with_base (first_party_uri, "/index.html");
+ msg = soup_message_new_from_uri ("GET", uri);
+ soup_message_set_first_party (msg, first_party_uri);
+ soup_session_send_message (session, msg);
+ soup_uri_free (uri);
+ g_object_unref (msg);
+
+ /* We can't use to servers due to limitations in
+ * test_server, so let's swap first and third party here
+ * to simulate a cookie coming from a third party.
+ */
+ uri = soup_uri_new_with_base (first_party_uri, "/foo.jpg");
+ msg = soup_message_new_from_uri ("GET", uri);
+ soup_message_set_first_party (msg, third_party_uri);
+ soup_session_send_message (session, msg);
+ soup_uri_free (uri);
+ g_object_unref (msg);
+
+ l = soup_cookie_jar_all_cookies (jar);
+ if (g_slist_length (l) < validResults[i].n_cookies) {
+ debug_printf (1, " accepted less cookies than it should have\n");
+ errors++;
+ } else if (g_slist_length (l) > validResults[i].n_cookies) {
+ debug_printf (1, " accepted more cookies than it should have\n");
+ errors++;
+ }
+
+ for (p = l; p; p = p->next)
+ soup_cookie_jar_delete_cookie (jar, p->data);
+
+ g_slist_free (l);
+ }
+
+ soup_test_session_abort_unref (session);
+}
+
+int
+main (int argc, char **argv)
+{
+ test_init (argc, argv, NULL);
+
+ server = soup_test_server_new (TRUE);
+ soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
+ first_party_uri = soup_uri_new (first_party);
+ third_party_uri = soup_uri_new (third_party);
+ soup_uri_set_port (first_party_uri, soup_server_get_port (server));
+ soup_uri_set_port (third_party_uri, soup_server_get_port (server));
+
+ do_cookies_accept_policy_test ();
+
+ soup_uri_free (first_party_uri);
+ soup_uri_free (third_party_uri);
+
+ test_cleanup ();
+
+ return errors != 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]