Implement sqlite3 cookie storage backend
From now on cookies are stored in an sqlite3 database, existing cookies are imported on first startup.
This commit is contained in:
parent
eeb4b7b391
commit
f5447b921f
4 changed files with 360 additions and 2 deletions
298
katze/katze-http-cookies-sqlite.c
Normal file
298
katze/katze-http-cookies-sqlite.c
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
Copyright (C) 2008-2010 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2011 Alexander Butenko <a.butenka@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "katze-http-cookies-sqlite.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <glib/gi18n.h>
|
||||
#include <libsoup/soup.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#define QUERY_ALL "SELECT id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly FROM moz_cookies;"
|
||||
#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)"
|
||||
#define QUERY_INSERT "INSERT INTO moz_cookies VALUES(NULL, %Q, %Q, %Q, %Q, %d, NULL, %d, %d);"
|
||||
#define QUERY_DELETE "DELETE FROM moz_cookies WHERE name=%Q AND host=%Q;"
|
||||
|
||||
enum {
|
||||
COL_ID,
|
||||
COL_NAME,
|
||||
COL_VALUE,
|
||||
COL_HOST,
|
||||
COL_PATH,
|
||||
COL_EXPIRY,
|
||||
COL_LAST_ACCESS,
|
||||
COL_SECURE,
|
||||
COL_HTTP_ONLY,
|
||||
N_COL,
|
||||
};
|
||||
|
||||
struct _KatzeHttpCookiesSqlite
|
||||
{
|
||||
GObject parent_instance;
|
||||
gchar* filename;
|
||||
SoupCookieJar* jar;
|
||||
sqlite3 *db;
|
||||
guint counter;
|
||||
};
|
||||
|
||||
struct _KatzeHttpCookiesSqliteClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_session_feature_iface_init (SoupSessionFeatureInterface *iface,
|
||||
gpointer data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (KatzeHttpCookiesSqlite, katze_http_cookies_sqlite, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
|
||||
katze_http_cookies_sqlite_session_feature_iface_init));
|
||||
|
||||
/* Cookie jar saving into sqlite database
|
||||
Copyright (C) 2008 Diego Escalante Urrelo
|
||||
Copyright (C) 2009 Collabora Ltd.
|
||||
Mostly copied from libSoup 2.30, coding style retained */
|
||||
|
||||
static void
|
||||
try_create_table (sqlite3 *db)
|
||||
{
|
||||
char *error = NULL;
|
||||
|
||||
if (sqlite3_exec (db, CREATE_TABLE, NULL, NULL, &error)) {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exec_query_with_try_create_table (sqlite3* db,
|
||||
const char* sql,
|
||||
int (*callback)(void*,int,char**,char**),
|
||||
void *argument)
|
||||
{
|
||||
char *error = NULL;
|
||||
gboolean try_create = TRUE;
|
||||
|
||||
try_exec:
|
||||
if (sqlite3_exec (db, sql, callback, argument, &error)) {
|
||||
if (try_create) {
|
||||
try_create = FALSE;
|
||||
try_create_table (db);
|
||||
sqlite3_free (error);
|
||||
error = NULL;
|
||||
goto try_exec;
|
||||
} else {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
callback (void *data, int argc, char **argv, char **colname)
|
||||
{
|
||||
SoupCookie *cookie = NULL;
|
||||
SoupCookieJar *jar = SOUP_COOKIE_JAR (data);
|
||||
|
||||
char *name, *value, *host, *path;
|
||||
gint64 expire_time;
|
||||
time_t now;
|
||||
int max_age;
|
||||
gboolean http_only = FALSE, secure = FALSE;
|
||||
|
||||
now = time (NULL);
|
||||
|
||||
name = argv[COL_NAME];
|
||||
value = argv[COL_VALUE];
|
||||
host = argv[COL_HOST];
|
||||
path = argv[COL_PATH];
|
||||
expire_time = g_ascii_strtoull (argv[COL_EXPIRY], NULL, 10);
|
||||
|
||||
if (now >= expire_time)
|
||||
return 0;
|
||||
max_age = (expire_time - now <= G_MAXINT ? expire_time - now : G_MAXINT);
|
||||
|
||||
http_only = (g_strcmp0 (argv[COL_HTTP_ONLY], "1") == 0);
|
||||
secure = (g_strcmp0 (argv[COL_SECURE], "1") == 0);
|
||||
|
||||
cookie = soup_cookie_new (name, value, host, path, max_age);
|
||||
|
||||
if (secure)
|
||||
soup_cookie_set_secure (cookie, TRUE);
|
||||
if (http_only)
|
||||
soup_cookie_set_http_only (cookie, TRUE);
|
||||
|
||||
soup_cookie_jar_add_cookie (jar, cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Follows sqlite3 convention; returns TRUE on error */
|
||||
static gboolean
|
||||
katze_http_cookies_sqlite_open_db (KatzeHttpCookiesSqlite* http_cookies)
|
||||
{
|
||||
char *error = NULL;
|
||||
|
||||
if (sqlite3_open (http_cookies->filename, &http_cookies->db)) {
|
||||
sqlite3_close (http_cookies->db);
|
||||
g_warning ("Can't open %s", http_cookies->filename);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (sqlite3_exec (http_cookies->db, "PRAGMA synchronous = OFF; PRAGMA secure_delete = 1;", NULL, NULL, &error)) {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_load (KatzeHttpCookiesSqlite* http_cookies)
|
||||
{
|
||||
if (http_cookies->db == NULL) {
|
||||
if (katze_http_cookies_sqlite_open_db (http_cookies))
|
||||
return;
|
||||
}
|
||||
|
||||
exec_query_with_try_create_table (http_cookies->db, QUERY_ALL, callback, http_cookies->jar);
|
||||
}
|
||||
static void
|
||||
katze_http_cookies_sqlite_jar_changed_cb (SoupCookieJar* jar,
|
||||
SoupCookie* old_cookie,
|
||||
SoupCookie* new_cookie,
|
||||
KatzeHttpCookiesSqlite* http_cookies)
|
||||
{
|
||||
GObject* settings;
|
||||
char *query;
|
||||
time_t expires = 0; /* Avoid warning */
|
||||
|
||||
if (http_cookies->db == NULL) {
|
||||
if (katze_http_cookies_sqlite_open_db (http_cookies))
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_cookie && new_cookie->expires)
|
||||
{
|
||||
gint age;
|
||||
|
||||
expires = soup_date_to_time_t (new_cookie->expires);
|
||||
settings = g_object_get_data (G_OBJECT (jar), "midori-settings");
|
||||
age = katze_object_get_int (settings, "maximum-cookie-age");
|
||||
if (age > 0)
|
||||
{
|
||||
SoupDate* max_date = soup_date_new_from_now (
|
||||
age * SOUP_COOKIE_MAX_AGE_ONE_DAY);
|
||||
if (soup_date_to_time_t (new_cookie->expires)
|
||||
> soup_date_to_time_t (max_date))
|
||||
soup_cookie_set_expires (new_cookie, max_date);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An age of 0 to SoupCookie means already-expired
|
||||
A user choosing 0 days probably expects 1 hour. */
|
||||
soup_cookie_set_max_age (new_cookie, SOUP_COOKIE_MAX_AGE_ONE_HOUR);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_getenv ("MIDORI_COOKIES_DEBUG") != NULL)
|
||||
http_cookies->counter++;
|
||||
|
||||
if (old_cookie) {
|
||||
query = sqlite3_mprintf (QUERY_DELETE,
|
||||
old_cookie->name,
|
||||
old_cookie->domain);
|
||||
exec_query_with_try_create_table (http_cookies->db, query, NULL, NULL);
|
||||
sqlite3_free (query);
|
||||
}
|
||||
|
||||
if (new_cookie && new_cookie->expires) {
|
||||
|
||||
query = sqlite3_mprintf (QUERY_INSERT,
|
||||
new_cookie->name,
|
||||
new_cookie->value,
|
||||
new_cookie->domain,
|
||||
new_cookie->path,
|
||||
expires,
|
||||
new_cookie->secure,
|
||||
new_cookie->http_only);
|
||||
exec_query_with_try_create_table (http_cookies->db, query, NULL, NULL);
|
||||
sqlite3_free (query);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_attach (SoupSessionFeature* feature,
|
||||
SoupSession* session)
|
||||
{
|
||||
KatzeHttpCookiesSqlite* http_cookies = (KatzeHttpCookiesSqlite*)feature;
|
||||
const gchar* filename = g_object_get_data (G_OBJECT (feature), "filename");
|
||||
SoupSessionFeature* jar = soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR);
|
||||
g_return_if_fail (jar != NULL);
|
||||
g_return_if_fail (filename != NULL);
|
||||
katze_assign (http_cookies->filename, g_strdup (filename));
|
||||
http_cookies->jar = g_object_ref (jar);
|
||||
katze_http_cookies_sqlite_open_db (http_cookies);
|
||||
katze_http_cookies_sqlite_load (http_cookies);
|
||||
g_signal_connect (jar, "changed",
|
||||
G_CALLBACK (katze_http_cookies_sqlite_jar_changed_cb), feature);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_detach (SoupSessionFeature* feature,
|
||||
SoupSession* session)
|
||||
{
|
||||
KatzeHttpCookiesSqlite* http_cookies = (KatzeHttpCookiesSqlite*)feature;
|
||||
katze_assign (http_cookies->filename, NULL);
|
||||
katze_object_assign (http_cookies->jar, NULL);
|
||||
sqlite3_close (http_cookies->db);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_session_feature_iface_init (SoupSessionFeatureInterface *iface,
|
||||
gpointer data)
|
||||
{
|
||||
iface->attach = katze_http_cookies_sqlite_attach;
|
||||
iface->detach = katze_http_cookies_sqlite_detach;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_finalize (GObject* object)
|
||||
{
|
||||
katze_http_cookies_sqlite_detach ((SoupSessionFeature*)object, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_class_init (KatzeHttpCookiesSqliteClass* class)
|
||||
{
|
||||
GObjectClass* gobject_class = (GObjectClass*)class;
|
||||
gobject_class->finalize = katze_http_cookies_sqlite_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_init (KatzeHttpCookiesSqlite* http_cookies)
|
||||
{
|
||||
http_cookies->filename = NULL;
|
||||
http_cookies->jar = NULL;
|
||||
http_cookies->db = NULL;
|
||||
http_cookies->counter = 0;
|
||||
}
|
42
katze/katze-http-cookies-sqlite.h
Normal file
42
katze/katze-http-cookies-sqlite.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#ifndef __KATZE_HTTP_COOKIES_SQLITE_H__
|
||||
#define __KATZE_HTTP_COOKIES_SQLITE_H__
|
||||
|
||||
#include "katze-utils.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KATZE_TYPE_HTTP_COOKIES_SQLITE \
|
||||
(katze_http_cookies_sqlite_get_type ())
|
||||
#define KATZE_HTTP_COOKIES_SQLITE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_HTTP_COOKIES_SQLITE, KatzeHttpCookiesSqlite))
|
||||
#define KATZE_HTTP_COOKIES_SQLITE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_HTTP_COOKIES_SQLITE, KatzeHttpCookiesSqliteClass))
|
||||
#define KATZE_IS_HTTP_COOKIES_SQLITE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_HTTP_COOKIES_SQLITE))
|
||||
#define KATZE_IS_HTTP_COOKIES_SQLITE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_HTTP_COOKIES_SQLITE))
|
||||
#define KATZE_HTTP_COOKIES_SQLITE_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_HTTP_COOKIES_SQLITE, KatzeHttpCookiesSqliteClass))
|
||||
|
||||
typedef struct _KatzeHttpCookiesSqlite KatzeHttpCookiesSqlite;
|
||||
typedef struct _KatzeHttpCookiesSqliteClass KatzeHttpCookiesSqliteClass;
|
||||
|
||||
GType
|
||||
katze_http_cookies_sqlite_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __KATZE_HTTP_COOKIES_SQLITE_H__ */
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "katze-http-auth.h"
|
||||
#include "katze-http-cookies.h"
|
||||
#include "katze-http-cookies-sqlite.h"
|
||||
#include "katze-throbber.h"
|
||||
#include "katze-utils.h"
|
||||
#include "katze-item.h"
|
||||
|
|
|
@ -1158,6 +1158,8 @@ midori_load_soup_session_full (gpointer settings)
|
|||
SoupCookieJar* jar;
|
||||
gchar* config_file;
|
||||
SoupSessionFeature* feature;
|
||||
gboolean have_new_cookies;
|
||||
SoupSessionFeature* feature_import;
|
||||
|
||||
midori_load_soup_session (settings);
|
||||
|
||||
|
@ -1172,13 +1174,28 @@ midori_load_soup_session_full (gpointer settings)
|
|||
soup_session_add_feature (session, SOUP_SESSION_FEATURE (jar));
|
||||
g_object_unref (jar);
|
||||
|
||||
feature = g_object_new (KATZE_TYPE_HTTP_COOKIES, NULL);
|
||||
config_file = build_config_filename ("cookies.txt");
|
||||
katze_assign (config_file, build_config_filename ("cookies.db"));
|
||||
have_new_cookies = g_access (config_file, F_OK) == 0;
|
||||
feature = g_object_new (KATZE_TYPE_HTTP_COOKIES_SQLITE, NULL);
|
||||
g_object_set_data_full (G_OBJECT (feature), "filename",
|
||||
config_file, (GDestroyNotify)g_free);
|
||||
soup_session_add_feature (session, feature);
|
||||
g_object_unref (feature);
|
||||
|
||||
if (!have_new_cookies)
|
||||
{
|
||||
katze_assign (config_file, build_config_filename ("cookies.txt"));
|
||||
if (g_access (config_file, F_OK) == 0)
|
||||
{
|
||||
g_message ("Importing cookies from txt to sqlite3");
|
||||
feature_import = g_object_new (KATZE_TYPE_HTTP_COOKIES, NULL);
|
||||
g_object_set_data_full (G_OBJECT (feature_import), "filename",
|
||||
config_file, (GDestroyNotify)g_free);
|
||||
soup_session_add_feature (session, SOUP_SESSION_FEATURE (feature_import));
|
||||
soup_session_remove_feature (session, SOUP_SESSION_FEATURE (feature_import));
|
||||
}
|
||||
}
|
||||
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 11)
|
||||
config_file = g_build_filename (g_get_user_cache_dir (),
|
||||
PACKAGE_NAME, "web", NULL);
|
||||
|
|
Loading…
Reference in a new issue