1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-cookie-jar-db.c: database-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.
18 #include "soup-cookie-jar-db.h"
22 * SECTION:soup-cookie-jar-db
23 * @short_description: Database-based Cookie Jar
25 * #SoupCookieJarDB is a #SoupCookieJar that reads cookies from and
26 * writes them to a sqlite database in the new Mozilla format.
28 * (This is identical to <literal>SoupCookieJarSqlite</literal> in
29 * libsoup-gnome; it has just been moved into libsoup proper, and
30 * renamed to avoid conflicting.)
44 } SoupCookieJarDBPrivate;
46 #define SOUP_COOKIE_JAR_DB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_COOKIE_JAR_DB, SoupCookieJarDBPrivate))
48 G_DEFINE_TYPE (SoupCookieJarDB, soup_cookie_jar_db, SOUP_TYPE_COOKIE_JAR)
50 static void load (SoupCookieJar *jar);
53 soup_cookie_jar_db_init (SoupCookieJarDB *db)
58 soup_cookie_jar_db_finalize (GObject *object)
60 SoupCookieJarDBPrivate *priv =
61 SOUP_COOKIE_JAR_DB_GET_PRIVATE (object);
63 g_free (priv->filename);
64 g_clear_pointer (&priv->db, sqlite3_close);
66 G_OBJECT_CLASS (soup_cookie_jar_db_parent_class)->finalize (object);
70 soup_cookie_jar_db_set_property (GObject *object, guint prop_id,
71 const GValue *value, GParamSpec *pspec)
73 SoupCookieJarDBPrivate *priv =
74 SOUP_COOKIE_JAR_DB_GET_PRIVATE (object);
78 priv->filename = g_value_dup_string (value);
79 load (SOUP_COOKIE_JAR (object));
82 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
88 soup_cookie_jar_db_get_property (GObject *object, guint prop_id,
89 GValue *value, GParamSpec *pspec)
91 SoupCookieJarDBPrivate *priv =
92 SOUP_COOKIE_JAR_DB_GET_PRIVATE (object);
96 g_value_set_string (value, priv->filename);
99 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
105 * soup_cookie_jar_db_new:
106 * @filename: the filename to read to/write from, or %NULL
107 * @read_only: %TRUE if @filename is read-only
109 * Creates a #SoupCookieJarDB.
111 * @filename will be read in at startup to create an initial set of
112 * cookies. If @read_only is %FALSE, then the non-session cookies will
113 * be written to @filename when the 'changed' signal is emitted from
114 * the jar. (If @read_only is %TRUE, then the cookie jar will only be
115 * used for this session, and changes made to it will be lost when the
118 * Return value: the new #SoupCookieJar
123 soup_cookie_jar_db_new (const char *filename, gboolean read_only)
125 g_return_val_if_fail (filename != NULL, NULL);
127 return g_object_new (SOUP_TYPE_COOKIE_JAR_DB,
128 SOUP_COOKIE_JAR_DB_FILENAME, filename,
129 SOUP_COOKIE_JAR_READ_ONLY, read_only,
133 #define QUERY_ALL "SELECT id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly FROM moz_cookies;"
134 #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)"
135 #define QUERY_INSERT "INSERT INTO moz_cookies VALUES(NULL, %Q, %Q, %Q, %Q, %d, NULL, %d, %d);"
136 #define QUERY_DELETE "DELETE FROM moz_cookies WHERE name=%Q AND host=%Q;"
152 callback (void *data, int argc, char **argv, char **colname)
154 SoupCookie *cookie = NULL;
155 SoupCookieJar *jar = SOUP_COOKIE_JAR (data);
157 char *name, *value, *host, *path;
161 gboolean http_only = FALSE, secure = FALSE;
165 name = argv[COL_NAME];
166 value = argv[COL_VALUE];
167 host = argv[COL_HOST];
168 path = argv[COL_PATH];
169 expire_time = strtoul (argv[COL_EXPIRY], NULL, 10);
171 if (now >= expire_time)
173 max_age = (expire_time - now <= G_MAXINT ? expire_time - now : G_MAXINT);
175 http_only = (g_strcmp0 (argv[COL_HTTP_ONLY], "1") == 0);
176 secure = (g_strcmp0 (argv[COL_SECURE], "1") == 0);
178 cookie = soup_cookie_new (name, value, host, path, max_age);
181 soup_cookie_set_secure (cookie, TRUE);
183 soup_cookie_set_http_only (cookie, TRUE);
185 soup_cookie_jar_add_cookie (jar, cookie);
191 try_create_table (sqlite3 *db)
195 if (sqlite3_exec (db, CREATE_TABLE, NULL, NULL, &error)) {
196 g_warning ("Failed to execute query: %s", error);
197 sqlite3_free (error);
202 exec_query_with_try_create_table (sqlite3 *db,
204 int (*callback)(void*,int,char**,char**),
208 gboolean try_create = TRUE;
211 if (sqlite3_exec (db, sql, callback, argument, &error)) {
214 try_create_table (db);
215 sqlite3_free (error);
219 g_warning ("Failed to execute query: %s", error);
220 sqlite3_free (error);
225 /* Follows sqlite3 convention; returns TRUE on error */
227 open_db (SoupCookieJar *jar)
229 SoupCookieJarDBPrivate *priv =
230 SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar);
234 if (sqlite3_open (priv->filename, &priv->db)) {
235 sqlite3_close (priv->db);
237 g_warning ("Can't open %s", priv->filename);
241 if (sqlite3_exec (priv->db, "PRAGMA synchronous = OFF; PRAGMA secure_delete = 1;", NULL, NULL, &error)) {
242 g_warning ("Failed to execute query: %s", error);
243 sqlite3_free (error);
250 load (SoupCookieJar *jar)
252 SoupCookieJarDBPrivate *priv =
253 SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar);
255 if (priv->db == NULL) {
260 exec_query_with_try_create_table (priv->db, QUERY_ALL, callback, jar);
264 soup_cookie_jar_db_changed (SoupCookieJar *jar,
265 SoupCookie *old_cookie,
266 SoupCookie *new_cookie)
268 SoupCookieJarDBPrivate *priv =
269 SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar);
272 if (priv->db == NULL) {
278 query = sqlite3_mprintf (QUERY_DELETE,
281 exec_query_with_try_create_table (priv->db, query, NULL, NULL);
282 sqlite3_free (query);
285 if (new_cookie && new_cookie->expires) {
288 expires = (gulong)soup_date_to_time_t (new_cookie->expires);
289 query = sqlite3_mprintf (QUERY_INSERT,
296 new_cookie->http_only);
297 exec_query_with_try_create_table (priv->db, query, NULL, NULL);
298 sqlite3_free (query);
303 soup_cookie_jar_db_is_persistent (SoupCookieJar *jar)
309 soup_cookie_jar_db_class_init (SoupCookieJarDBClass *db_class)
311 SoupCookieJarClass *cookie_jar_class =
312 SOUP_COOKIE_JAR_CLASS (db_class);
313 GObjectClass *object_class = G_OBJECT_CLASS (db_class);
315 g_type_class_add_private (db_class, sizeof (SoupCookieJarDBPrivate));
317 cookie_jar_class->is_persistent = soup_cookie_jar_db_is_persistent;
318 cookie_jar_class->changed = soup_cookie_jar_db_changed;
320 object_class->finalize = soup_cookie_jar_db_finalize;
321 object_class->set_property = soup_cookie_jar_db_set_property;
322 object_class->get_property = soup_cookie_jar_db_get_property;
325 * SOUP_COOKIE_JAR_DB_FILENAME:
327 * Alias for the #SoupCookieJarDB:filename property. (The
328 * cookie-storage filename.)
330 g_object_class_install_property (
331 object_class, PROP_FILENAME,
332 g_param_spec_string (SOUP_COOKIE_JAR_DB_FILENAME,
334 "Cookie-storage filename",
336 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));