summaryrefslogtreecommitdiff
path: root/libsoup/soup-cookie-jar.c
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2008-11-04 20:30:37 +0000
committerDan Winship <danw@src.gnome.org>2008-11-04 20:30:37 +0000
commitae786f44ace1712be2b3899806202591cf074905 (patch)
tree4bd9e83b29db66f98908fb24e54518dd53a27a06 /libsoup/soup-cookie-jar.c
parent07279b0c7e1eb3c931c1ae201574a58609e0f6bc (diff)
downloadlibsoup-ae786f44ace1712be2b3899806202591cf074905.tar.gz
implementation of SoupCookieJar that persists to a text file in the old
* libsoup/soup-cookie-jar-text.c: implementation of SoupCookieJar that persists to a text file in the old Mozilla cookies.txt format. * libsoup/soup-cookie-jar-sqlite.c: implementation of SoupCookieJar that persists to an sqlite database in the new Mozilla cookies.sqlite format. (Part of libsoup-gnome.) * libsoup/soup-cookie-jar.c: add various functionality needed by the two new subclasses. Does not break API/ABI compat with 2.24. * libsoup/soup-cookie.c (soup_cookie_get_type): register SoupCookie as a boxed type. (domain_matches): fix a bug here that meant "foo.com" couldn't set a cookie for domain=.foo.com (soup_cookie_applies_to_uri): fix path checking * configure.in: if building --with-gnome, require sqlite3 svn path=/trunk/; revision=1200
Diffstat (limited to 'libsoup/soup-cookie-jar.c')
-rw-r--r--libsoup/soup-cookie-jar.c297
1 files changed, 243 insertions, 54 deletions
diff --git a/libsoup/soup-cookie-jar.c b/libsoup/soup-cookie-jar.c
index 9b717c5a..29a2de13 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-marshal.h"
#include "soup-message.h"
#include "soup-session-feature.h"
#include "soup-uri.h"
@@ -45,11 +46,32 @@ G_DEFINE_TYPE_WITH_CODE (SoupCookieJar, soup_cookie_jar, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
soup_cookie_jar_session_feature_init))
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+ PROP_0,
+
+ PROP_READ_ONLY,
+
+ LAST_PROP
+};
+
typedef struct {
+ gboolean constructed, read_only;
GHashTable *domains;
} SoupCookieJarPrivate;
#define SOUP_COOKIE_JAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_COOKIE_JAR, SoupCookieJarPrivate))
+static void set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec);
+
static void
soup_cookie_jar_init (SoupCookieJar *jar)
{
@@ -60,6 +82,14 @@ soup_cookie_jar_init (SoupCookieJar *jar)
}
static void
+constructed (GObject *object)
+{
+ SoupCookieJarPrivate *priv = SOUP_COOKIE_JAR_GET_PRIVATE (object);
+
+ priv->constructed = TRUE;
+}
+
+static void
finalize (GObject *object)
{
SoupCookieJarPrivate *priv = SOUP_COOKIE_JAR_GET_PRIVATE (object);
@@ -81,7 +111,29 @@ soup_cookie_jar_class_init (SoupCookieJarClass *jar_class)
g_type_class_add_private (jar_class, sizeof (SoupCookieJarPrivate));
+ object_class->constructed = constructed;
object_class->finalize = finalize;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SoupCookieJarClass, changed),
+ NULL, NULL,
+ soup_marshal_NONE__BOXED_BOXED,
+ G_TYPE_NONE, 2,
+ SOUP_TYPE_COOKIE | G_SIGNAL_TYPE_STATIC_SCOPE,
+ SOUP_TYPE_COOKIE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ g_object_class_install_property (
+ object_class, PROP_READ_ONLY,
+ g_param_spec_boolean (SOUP_COOKIE_JAR_READ_ONLY,
+ "Read-only",
+ "Whether or not the cookie jar is read-only",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
@@ -93,10 +145,45 @@ soup_cookie_jar_session_feature_init (SoupSessionFeatureInterface *feature_inter
feature_interface->request_unqueued = request_unqueued;
}
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ SoupCookieJarPrivate *priv =
+ SOUP_COOKIE_JAR_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_READ_ONLY:
+ priv->read_only = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ SoupCookieJarPrivate *priv =
+ SOUP_COOKIE_JAR_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_READ_ONLY:
+ g_value_set_boolean (value, priv->read_only);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
/**
* soup_cookie_jar_new:
*
- * Creates a new #SoupCookieJar.
+ * Creates a new #SoupCookieJar. The base #SoupCookieJar class does
+ * not support persistent storage of cookies; use a subclass for that.
*
* Returns: a new #SoupCookieJar
**/
@@ -106,18 +193,22 @@ soup_cookie_jar_new (void)
return g_object_new (SOUP_TYPE_COOKIE_JAR, NULL);
}
-/**
- * soup_cookie_jar_save:
- * @jar: a SoupCookieJar
- *
- * Tells @jar to save the state of its (non-session) cookies to some
- * sort of permanent storage.
- **/
void
soup_cookie_jar_save (SoupCookieJar *jar)
{
- if (SOUP_COOKIE_JAR_GET_CLASS (jar)->save)
- SOUP_COOKIE_JAR_GET_CLASS (jar)->save (jar);
+ /* Does nothing, obsolete */
+}
+
+static void
+soup_cookie_jar_changed (SoupCookieJar *jar,
+ SoupCookie *old, SoupCookie *new)
+{
+ SoupCookieJarPrivate *priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+
+ if (priv->read_only || !priv->constructed)
+ return;
+
+ g_signal_emit (jar, signals[CHANGED], 0, old, new);
}
/**
@@ -148,6 +239,7 @@ soup_cookie_jar_get_cookies (SoupCookieJar *jar, SoupURI *uri,
SoupCookieJarPrivate *priv;
GSList *cookies, *domain_cookies;
char *domain, *cur, *next, *result;
+ GSList *new_head, *cookies_to_remove = NULL, *p;
g_return_val_if_fail (SOUP_IS_COOKIE_JAR (jar), NULL);
priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
@@ -161,14 +253,23 @@ soup_cookie_jar_get_cookies (SoupCookieJar *jar, SoupURI *uri,
domain = cur = g_strdup_printf (".%s", uri->host);
next = domain + 1;
do {
- domain_cookies = g_hash_table_lookup (priv->domains, cur);
+ new_head = domain_cookies = g_hash_table_lookup (priv->domains, cur);
while (domain_cookies) {
+ GSList *next = domain_cookies->next;
SoupCookie *cookie = domain_cookies->data;
- if (soup_cookie_applies_to_uri (cookie, uri) &&
- (for_http || !cookie->http_only))
+ if (cookie->expires && soup_date_is_past (cookie->expires)) {
+ cookies_to_remove = g_slist_append (cookies_to_remove,
+ cookie);
+ new_head = g_slist_delete_link (new_head, domain_cookies);
+ g_hash_table_insert (priv->domains,
+ g_strdup (cur),
+ new_head);
+ } else if (soup_cookie_applies_to_uri (cookie, uri) &&
+ (for_http || !cookie->http_only))
cookies = g_slist_append (cookies, cookie);
- domain_cookies = domain_cookies->next;
+
+ domain_cookies = next;
}
cur = next;
if (cur)
@@ -176,6 +277,14 @@ soup_cookie_jar_get_cookies (SoupCookieJar *jar, SoupURI *uri,
} while (cur);
g_free (domain);
+ for (p = cookies_to_remove; p; p = p->next) {
+ SoupCookie *cookie = p->data;
+
+ soup_cookie_jar_changed (jar, cookie, NULL);
+ soup_cookie_free (cookie);
+ }
+ g_slist_free (cookies_to_remove);
+
if (cookies) {
/* FIXME: sort? */
result = soup_cookies_to_cookie_header (cookies);
@@ -185,63 +294,71 @@ soup_cookie_jar_get_cookies (SoupCookieJar *jar, SoupURI *uri,
return NULL;
}
-static GSList *
-get_cookies_for_domain (SoupCookieJar *jar, const char *domain)
-{
- SoupCookieJarPrivate *priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
- GSList *cookies, *orig_cookies, *c;
- SoupCookie *cookie;
-
- cookies = g_hash_table_lookup (priv->domains, domain);
- c = orig_cookies = cookies;
- while (c) {
- cookie = c->data;
- c = c->next;
- if (cookie->expires && soup_date_is_past (cookie->expires)) {
- cookies = g_slist_remove (cookies, cookie);
- soup_cookie_free (cookie);
- }
- }
-
- if (cookies != orig_cookies)
- g_hash_table_insert (priv->domains, g_strdup (domain), cookies);
- return cookies;
-}
-
-static void
-set_cookie (SoupCookieJar *jar, SoupCookie *cookie)
+/**
+ * soup_cookie_jar_add_cookie:
+ * @jar: a #SoupCookieJar
+ * @cookie: a #SoupCookie
+ *
+ * Adds @cookie to @jar, emitting the 'changed' signal if we are modifying
+ * an existing cookie or adding a valid new cookie ('valid' means
+ * that the cookie's expire date is not in the past).
+ *
+ * @cookie will be 'stolen' by the jar, so don't free it afterwards.
+ **/
+void
+soup_cookie_jar_add_cookie (SoupCookieJar *jar, SoupCookie *cookie)
{
- SoupCookieJarPrivate *priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+ SoupCookieJarPrivate *priv;
GSList *old_cookies, *oc, *prev = NULL;
SoupCookie *old_cookie;
- old_cookies = get_cookies_for_domain (jar, cookie->domain);
+ g_return_if_fail (SOUP_IS_COOKIE_JAR (jar));
+ g_return_if_fail (cookie != NULL);
+
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+ old_cookies = g_hash_table_lookup (priv->domains, cookie->domain);
for (oc = old_cookies; oc; oc = oc->next) {
old_cookie = oc->data;
if (!strcmp (cookie->name, old_cookie->name)) {
- /* The new cookie is a replacement for an old
- * cookie. It might be pre-expired, but we
- * don't worry about that here;
- * get_cookies_for_domain() will delete it
- * later.
- */
- soup_cookie_free (old_cookie);
- oc->data = cookie;
+ if (cookie->expires && soup_date_is_past (cookie->expires)) {
+ /* The new cookie has an expired date,
+ * this is the way the the server has
+ * of telling us that we have to
+ * remove the cookie.
+ */
+ old_cookies = g_slist_delete_link (old_cookies, oc);
+ g_hash_table_insert (priv->domains,
+ g_strdup (cookie->domain),
+ old_cookies);
+ soup_cookie_jar_changed (jar, old_cookie, NULL);
+ soup_cookie_free (old_cookie);
+ soup_cookie_free (cookie);
+ } else {
+ oc->data = cookie;
+ soup_cookie_jar_changed (jar, old_cookie, cookie);
+ soup_cookie_free (old_cookie);
+ }
+
return;
}
prev = oc;
}
/* The new cookie is... a new cookie */
- if (cookie->expires && soup_date_is_past (cookie->expires))
+ if (cookie->expires && soup_date_is_past (cookie->expires)) {
soup_cookie_free (cookie);
- else if (prev)
+ return;
+ }
+
+ if (prev)
prev = g_slist_append (prev, cookie);
else {
old_cookies = g_slist_append (NULL, cookie);
g_hash_table_insert (priv->domains, g_strdup (cookie->domain),
old_cookies);
}
+
+ soup_cookie_jar_changed (jar, NULL, cookie);
}
/**
@@ -264,8 +381,8 @@ soup_cookie_jar_set_cookie (SoupCookieJar *jar, SoupURI *uri,
soup_cookie = soup_cookie_parse (cookie, uri);
if (soup_cookie) {
- set_cookie (jar, soup_cookie);
- /* set_cookie will steal or free soup_cookie */
+ /* will steal or free soup_cookie */
+ soup_cookie_jar_add_cookie (jar, soup_cookie);
}
}
@@ -277,7 +394,7 @@ process_set_cookie_header (SoupMessage *msg, gpointer user_data)
new_cookies = soup_cookies_from_response (msg);
for (nc = new_cookies; nc; nc = nc->next)
- set_cookie (jar, nc->data);
+ soup_cookie_jar_add_cookie (jar, nc->data);
g_slist_free (new_cookies);
}
@@ -311,3 +428,75 @@ request_unqueued (SoupSessionFeature *feature, SoupSession *session,
g_signal_handlers_disconnect_by_func (msg, process_set_cookie_header, feature);
}
+/**
+ * soup_cookie_jar_all_cookies:
+ * @jar: a #SoupCookieJar
+ *
+ * Constructs a #GSList with every cookie inside the @jar.
+ * The cookies in the list are a copy of the original, so
+ * you have to free them when you are done with them.
+ *
+ * Return value: a #GSList with all the cookies in the @jar.
+ **/
+GSList *
+soup_cookie_jar_all_cookies (SoupCookieJar *jar)
+{
+ SoupCookieJarPrivate *priv;
+ GHashTableIter iter;
+ GSList *l = NULL;
+ gpointer key, value;
+
+ g_return_val_if_fail (SOUP_IS_COOKIE_JAR (jar), NULL);
+
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+
+ g_hash_table_iter_init (&iter, priv->domains);
+
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GSList *p, *cookies = value;
+ for (p = cookies; p; p = p->next)
+ l = g_slist_prepend (l, soup_cookie_copy (p->data));
+ }
+
+ return l;
+}
+
+/**
+ * soup_cookie_jar_delete_cookie:
+ * @jar: a #SoupCookieJar
+ * @cookie: a #SoupCookie
+ *
+ * Deletes @cookie from @jar, emitting the 'changed' signal.
+ **/
+void
+soup_cookie_jar_delete_cookie (SoupCookieJar *jar,
+ SoupCookie *cookie)
+{
+ SoupCookieJarPrivate *priv;
+ GSList *cookies, *p;
+ char *domain;
+
+ g_return_if_fail (SOUP_IS_COOKIE_JAR (jar));
+ g_return_if_fail (cookie != NULL);
+
+ priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar);
+
+ domain = g_strdup (cookie->domain);
+
+ cookies = g_hash_table_lookup (priv->domains, domain);
+ if (cookies == NULL)
+ return;
+
+ for (p = cookies; p; p = p->next ) {
+ SoupCookie *c = (SoupCookie*)p->data;
+ if (soup_cookie_equal (cookie, c)) {
+ cookies = g_slist_delete_link (cookies, p);
+ g_hash_table_insert (priv->domains,
+ domain,
+ cookies);
+ soup_cookie_jar_changed (jar, c, NULL);
+ soup_cookie_free (c);
+ return;
+ }
+ }
+}