1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-cookie-jar-sqlite.c: ff sqlite-based cookie storage
5 * Using danw's soup-cookie-jar-text as template
6 * Copyright (C) 2008 Diego Escalante Urrelo
7 * Copyright (C) 2009 Collabora Ltd.
19 #include "soup-cookie-jar-sqlite.h"
20 #include "soup-cookie.h"
21 #include "soup-date.h"
24 * SECTION:soup-cookie-jar-sqlite
25 * @short_description: SQLite-based Cookie Jar
27 * #SoupCookieJarSqlite is a #SoupCookieJar that reads cookies from and
28 * writes them to an SQLite file in the new Mozilla format.
42 } SoupCookieJarSqlitePrivate;
44 #define SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_COOKIE_JAR_SQLITE, SoupCookieJarSqlitePrivate))
46 G_DEFINE_TYPE (SoupCookieJarSqlite, soup_cookie_jar_sqlite, SOUP_TYPE_COOKIE_JAR)
48 static void load (SoupCookieJar *jar);
49 static void changed (SoupCookieJar *jar,
50 SoupCookie *old_cookie,
51 SoupCookie *new_cookie);
53 static void set_property (GObject *object, guint prop_id,
54 const GValue *value, GParamSpec *pspec);
55 static void get_property (GObject *object, guint prop_id,
56 GValue *value, GParamSpec *pspec);
59 soup_cookie_jar_sqlite_init (SoupCookieJarSqlite *sqlite)
64 finalize (GObject *object)
66 SoupCookieJarSqlitePrivate *priv =
67 SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE (object);
69 g_free (priv->filename);
72 sqlite3_close (priv->db);
74 G_OBJECT_CLASS (soup_cookie_jar_sqlite_parent_class)->finalize (object);
78 soup_cookie_jar_sqlite_class_init (SoupCookieJarSqliteClass *sqlite_class)
80 SoupCookieJarClass *cookie_jar_class =
81 SOUP_COOKIE_JAR_CLASS (sqlite_class);
82 GObjectClass *object_class = G_OBJECT_CLASS (sqlite_class);
84 g_type_class_add_private (sqlite_class, sizeof (SoupCookieJarSqlitePrivate));
86 cookie_jar_class->changed = changed;
88 object_class->finalize = finalize;
89 object_class->set_property = set_property;
90 object_class->get_property = get_property;
93 * SOUP_COOKIE_JAR_SQLITE_FILENAME:
95 * Alias for the #SoupCookieJarSqlite:filename property. (The
96 * cookie-storage filename.)
98 g_object_class_install_property (
99 object_class, PROP_FILENAME,
100 g_param_spec_string (SOUP_COOKIE_JAR_SQLITE_FILENAME,
102 "Cookie-storage filename",
104 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
108 set_property (GObject *object, guint prop_id,
109 const GValue *value, GParamSpec *pspec)
111 SoupCookieJarSqlitePrivate *priv =
112 SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE (object);
116 priv->filename = g_value_dup_string (value);
117 load (SOUP_COOKIE_JAR (object));
120 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
126 get_property (GObject *object, guint prop_id,
127 GValue *value, GParamSpec *pspec)
129 SoupCookieJarSqlitePrivate *priv =
130 SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE (object);
134 g_value_set_string (value, priv->filename);
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
143 * soup_cookie_jar_sqlite_new:
144 * @filename: the filename to read to/write from, or %NULL
145 * @read_only: %TRUE if @filename is read-only
147 * Creates a #SoupCookieJarSqlite.
149 * @filename will be read in at startup to create an initial set of
150 * cookies. If @read_only is %FALSE, then the non-session cookies will
151 * be written to @filename when the 'changed' signal is emitted from
152 * the jar. (If @read_only is %TRUE, then the cookie jar will only be
153 * used for this session, and changes made to it will be lost when the
156 * Return value: the new #SoupCookieJar
161 soup_cookie_jar_sqlite_new (const char *filename, gboolean read_only)
163 g_return_val_if_fail (filename != NULL, NULL);
165 return g_object_new (SOUP_TYPE_COOKIE_JAR_SQLITE,
166 SOUP_COOKIE_JAR_SQLITE_FILENAME, filename,
167 SOUP_COOKIE_JAR_READ_ONLY, read_only,
171 #define QUERY_ALL "SELECT id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly FROM moz_cookies;"
172 #define CREATE_TABLE "CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, name TEXT, value TEXT, host TEXT, path TEXT,expiry INTEGER, lastAccessed INTEGER, isSecure INTEGER, isHttpOnly INTEGER)"
173 #define QUERY_INSERT "INSERT INTO moz_cookies VALUES(NULL, %Q, %Q, %Q, %Q, %d, NULL, %d, %d);"
174 #define QUERY_DELETE "DELETE FROM moz_cookies WHERE name=%Q AND host=%Q;"
190 callback (void *data, int argc, char **argv, char **colname)
192 SoupCookie *cookie = NULL;
193 SoupCookieJar *jar = SOUP_COOKIE_JAR (data);
195 char *name, *value, *host, *path;
199 gboolean http_only = FALSE, secure = FALSE;
203 name = argv[COL_NAME];
204 value = argv[COL_VALUE];
205 host = argv[COL_HOST];
206 path = argv[COL_PATH];
207 expire_time = strtoul (argv[COL_EXPIRY], NULL, 10);
209 if (now >= expire_time)
211 max_age = (expire_time - now <= G_MAXINT ? expire_time - now : G_MAXINT);
213 http_only = (g_strcmp0 (argv[COL_HTTP_ONLY], "1") == 0);
214 secure = (g_strcmp0 (argv[COL_SECURE], "1") == 0);
216 cookie = soup_cookie_new (name, value, host, path, max_age);
219 soup_cookie_set_secure (cookie, TRUE);
221 soup_cookie_set_http_only (cookie, TRUE);
223 soup_cookie_jar_add_cookie (jar, cookie);
229 try_create_table (sqlite3 *db)
233 if (sqlite3_exec (db, CREATE_TABLE, NULL, NULL, &error)) {
234 g_warning ("Failed to execute query: %s", error);
235 sqlite3_free (error);
240 exec_query_with_try_create_table (sqlite3 *db,
242 int (*callback)(void*,int,char**,char**),
246 gboolean try_create = TRUE;
249 if (sqlite3_exec (db, sql, callback, argument, &error)) {
252 try_create_table (db);
253 sqlite3_free (error);
257 g_warning ("Failed to execute query: %s", error);
258 sqlite3_free (error);
263 /* Follows sqlite3 convention; returns TRUE on error */
265 open_db (SoupCookieJar *jar)
267 SoupCookieJarSqlitePrivate *priv =
268 SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE (jar);
272 if (sqlite3_open (priv->filename, &priv->db)) {
273 sqlite3_close (priv->db);
275 g_warning ("Can't open %s", priv->filename);
279 if (sqlite3_exec (priv->db, "PRAGMA synchronous = OFF; PRAGMA secure_delete = 1;", NULL, NULL, &error)) {
280 g_warning ("Failed to execute query: %s", error);
281 sqlite3_free (error);
288 load (SoupCookieJar *jar)
290 SoupCookieJarSqlitePrivate *priv =
291 SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE (jar);
293 if (priv->db == NULL) {
298 exec_query_with_try_create_table (priv->db, QUERY_ALL, callback, jar);
302 changed (SoupCookieJar *jar,
303 SoupCookie *old_cookie,
304 SoupCookie *new_cookie)
306 SoupCookieJarSqlitePrivate *priv =
307 SOUP_COOKIE_JAR_SQLITE_GET_PRIVATE (jar);
310 if (priv->db == NULL) {
316 query = sqlite3_mprintf (QUERY_DELETE,
319 exec_query_with_try_create_table (priv->db, query, NULL, NULL);
320 sqlite3_free (query);
323 if (new_cookie && new_cookie->expires) {
326 expires = (gulong)soup_date_to_time_t (new_cookie->expires);
327 query = sqlite3_mprintf (QUERY_INSERT,
334 new_cookie->http_only);
335 exec_query_with_try_create_table (priv->db, query, NULL, NULL);
336 sqlite3_free (query);