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-auth.h"
|
||||||
#include "katze-http-cookies.h"
|
#include "katze-http-cookies.h"
|
||||||
|
#include "katze-http-cookies-sqlite.h"
|
||||||
#include "katze-throbber.h"
|
#include "katze-throbber.h"
|
||||||
#include "katze-utils.h"
|
#include "katze-utils.h"
|
||||||
#include "katze-item.h"
|
#include "katze-item.h"
|
||||||
|
|
|
@ -1158,6 +1158,8 @@ midori_load_soup_session_full (gpointer settings)
|
||||||
SoupCookieJar* jar;
|
SoupCookieJar* jar;
|
||||||
gchar* config_file;
|
gchar* config_file;
|
||||||
SoupSessionFeature* feature;
|
SoupSessionFeature* feature;
|
||||||
|
gboolean have_new_cookies;
|
||||||
|
SoupSessionFeature* feature_import;
|
||||||
|
|
||||||
midori_load_soup_session (settings);
|
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));
|
soup_session_add_feature (session, SOUP_SESSION_FEATURE (jar));
|
||||||
g_object_unref (jar);
|
g_object_unref (jar);
|
||||||
|
|
||||||
feature = g_object_new (KATZE_TYPE_HTTP_COOKIES, NULL);
|
katze_assign (config_file, build_config_filename ("cookies.db"));
|
||||||
config_file = build_config_filename ("cookies.txt");
|
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",
|
g_object_set_data_full (G_OBJECT (feature), "filename",
|
||||||
config_file, (GDestroyNotify)g_free);
|
config_file, (GDestroyNotify)g_free);
|
||||||
soup_session_add_feature (session, feature);
|
soup_session_add_feature (session, feature);
|
||||||
g_object_unref (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)
|
#if WEBKIT_CHECK_VERSION (1, 3, 11)
|
||||||
config_file = g_build_filename (g_get_user_cache_dir (),
|
config_file = g_build_filename (g_get_user_cache_dir (),
|
||||||
PACKAGE_NAME, "web", NULL);
|
PACKAGE_NAME, "web", NULL);
|
||||||
|
|
Loading…
Reference in a new issue