From barry.scott@onelan.co.uk Tue Apr 1 13:42:07 2014 Return-Path: X-Original-To: libsoup-list@gnome.org Delivered-To: libsoup-list@gnome.org Received: from localhost (localhost.localdomain [127.0.0.1]) by restaurant.gnome.org (Postfix) with ESMTP id 9DD6176967; Tue, 1 Apr 2014 13:42:07 +0000 (UTC) X-Virus-Scanned: by amavisd-new at gnome.org X-Spam-Flag: NO X-Spam-Score: -0.499 X-Spam-Level: X-Spam-Status: No, score=-0.499 tagged_above=-999 required=2 tests=[BAYES_05=-0.5, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001] autolearn=ham Received: from restaurant.gnome.org ([127.0.0.1]) by localhost (restaurant.gnome.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 24NU648457po; Tue, 1 Apr 2014 13:42:05 +0000 (UTC) Received: from claranet-outbound-smtp00.uk.clara.net (claranet-outbound-smtp00.uk.clara.net [195.8.89.33]) by restaurant.gnome.org (Postfix) with ESMTP id E5B2A7695A; Tue, 1 Apr 2014 13:41:46 +0000 (UTC) Received: from 110.100.155.90.in-addr.arpa ([90.155.100.110]:30945 helo=f19barry.office.onelan.co.uk) by relay10.mail.eu.clara.net (relay.clara.net [81.171.239.30]:1025) with esmtpsa (authdaemon_plain:barry.scott@onelan.co.uk) (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) id 1WUywg-00030R-31 (return-path ); Tue, 01 Apr 2014 13:41:43 +0000 From: Barry Scott To: libsoup-list@gnome.org Subject: Re: libsoup proxy resolver Date: Tue, 01 Apr 2014 14:41:42 +0100 Message-ID: <4099385.6CrxtaU7vY@f19barry.office.onelan.co.uk> Organization: ONELAN Limited User-Agent: KMail/4.12.3 (Linux/3.13.4-200.fc20.x86_64; KDE/4.12.3; x86_64; ; ) In-Reply-To: <5325B2BD.1000207@gnome.org> References: <2691072.NBg5NUucvq@f19barry.office.onelan.co.uk> <5325B2BD.1000207@gnome.org> MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="nextPart1904298.J9VLXtIzbP" Content-Transfer-Encoding: 7Bit X-BeenThere: libsoup-list@gnome.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "discussion of libsoup, an HTTP library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 01 Apr 2014 13:42:07 -0000 This is a multi-part message in MIME format. --nextPart1904298.J9VLXtIzbP Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" On Sun 16 Mar 2014 10:18:37 Dan Winship wrote: > On 03/13/2014 12:47 PM, Barry Scott wrote: > > In my project I use my own proxy resolver with webkitgtk3 and libsoup. > > > > When I compile I am told that the SOUP_TYPE_PROXY_URI_RESOLVER is > > deprecated. > > > > What is the interface that replaces this? It is not documented as far as > > I can see. > > The online documentation doesn't include deprecated classes, but you can > read the docs out of the source files still. From soup-proxy-uri-resolver.c: > > * Deprecated: #SoupSession now has a #SoupSession:proxy-resolver > * property that takes a #GProxyResolver (which is semantically > * identical to #SoupProxyURIResolver). > > So, if you need customer proxy resolution, you can implement > GProxyResolver instead of SoupProxyURIResolver. Although there's a good > chance that GSimpleProxyResolver will do what you need, and you can just > create one of those and use that as the session's proxy-resolver. Thanks for the information. You are right GSimpleProxyResolver offers all the options we need. Barry --nextPart1904298.J9VLXtIzbP Content-Transfer-Encoding: 7Bit Content-Type: text/html; charset="us-ascii"

On Sun 16 Mar 2014 10:18:37 Dan Winship wrote:

> On 03/13/2014 12:47 PM, Barry Scott wrote:

> > In my project I use my own proxy resolver with webkitgtk3 and libsoup.

> >

> > When I compile I am told that the SOUP_TYPE_PROXY_URI_RESOLVER is

> > deprecated.

> >

> > What is the interface that replaces this? It is not documented as far as

> > I can see.

>

> The online documentation doesn't include deprecated classes, but you can

> read the docs out of the source files still. From soup-proxy-uri-resolver.c:

>

> * Deprecated: #SoupSession now has a #SoupSession:proxy-resolver

> * property that takes a #GProxyResolver (which is semantically

> * identical to #SoupProxyURIResolver).

>

> So, if you need customer proxy resolution, you can implement

> GProxyResolver instead of SoupProxyURIResolver. Although there's a good

> chance that GSimpleProxyResolver will do what you need, and you can just

> create one of those and use that as the session's proxy-resolver.

 

Thanks for the information.

 

You are right GSimpleProxyResolver offers all the options we need.

 

Barry

 

--nextPart1904298.J9VLXtIzbP-- From joseph.artsimovich@gmail.com Wed Apr 9 17:03:41 2014 Return-Path: X-Original-To: libsoup-list@gnome.org Delivered-To: libsoup-list@gnome.org Received: from localhost (localhost.localdomain [127.0.0.1]) by restaurant.gnome.org (Postfix) with ESMTP id 6529476261 for ; Wed, 9 Apr 2014 17:03:41 +0000 (UTC) X-Virus-Scanned: by amavisd-new at gnome.org X-Spam-Flag: NO X-Spam-Score: -2.6 X-Spam-Level: X-Spam-Status: No, score=-2.6 tagged_above=-999 required=2 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001] autolearn=ham Received: from restaurant.gnome.org ([127.0.0.1]) by localhost (restaurant.gnome.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BlLG6AIEPsYv for ; Wed, 9 Apr 2014 17:03:40 +0000 (UTC) Received: from mail-wg0-f47.google.com (mail-wg0-f47.google.com [74.125.82.47]) by restaurant.gnome.org (Postfix) with ESMTP id 2E0277624D for ; Wed, 9 Apr 2014 17:03:21 +0000 (UTC) Received: by mail-wg0-f47.google.com with SMTP id x12so2760690wgg.6 for ; Wed, 09 Apr 2014 10:03:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=R5LRpJan+kADzYVexKWh21/y9aWKYjDJ26iUoZ054hs=; b=DlBcfwffdWnJQJIs8i/U4Ovw47Mzl5+XyNR3AWHO9xMqUhLlsY81Qo6sPr6mMsiK9Y WRHFKfRrv0+gbW7uQgayasReEW3rJrob++3/27f7iq+/a50wlfshZFBH16pEU5JeFOaR Z1pJctI+XNp3OUENEuw8zfMUOTebR0pGRJ+T9frsYYZAsSxURy5Ra1i8bBkdoqPE9AJ/ CEirSKkEITKzCk7TMKgtPh0sgfh1+N6ggzlZFNhyMRHYlFBl951wHiTHT4c4VQNlKBTt rLmpm/aAidmRBmv12wutXTeEnDOcrjcgWXNsFHUpkTrjOEbDWJkRM8Yh5Q4WNVVKVvsR /4/w== X-Received: by 10.180.12.233 with SMTP id b9mr37941846wic.8.1397062999778; Wed, 09 Apr 2014 10:03:19 -0700 (PDT) Received: from [172.20.35.124] ([31.221.37.8]) by mx.google.com with ESMTPSA id h1sm2510700wjy.7.2014.04.09.10.03.17 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 09 Apr 2014 10:03:18 -0700 (PDT) Sender: Joseph Artsimovich Message-ID: <53457D55.70408@youview.com> Date: Wed, 09 Apr 2014 18:03:17 +0100 From: Joseph Artsimovich User-Agent: Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 MIME-Version: 1.0 To: libsoup-list@gnome.org Subject: Memory leak in soup_cookie_jar_delete_cookie() Content-Type: multipart/mixed; boundary="------------050504080101070305040301" X-BeenThere: libsoup-list@gnome.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "discussion of libsoup, an HTTP library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 Apr 2014 17:03:41 -0000 This is a multi-part message in MIME format. --------------050504080101070305040301 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit A memory leak would happen when asked to delete a matching cookie from a cookie jar that doesn't contain any matching cookies. Please see the attached patch. -- Joseph Artsimovich Software Engineer at YouView TV Ltd --------------050504080101070305040301 Content-Type: text/x-patch; name="0001-Fix-a-memory-leak-in-soup_cookie_jar_delete_cookie.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-Fix-a-memory-leak-in-soup_cookie_jar_delete_cookie.patc"; filename*1="h" >From 27762f83bf8d447e3cb4856919586a43e08089cc Mon Sep 17 00:00:00 2001 From: Joseph Artsimovich Date: Wed, 9 Apr 2014 17:30:35 +0100 Subject: [PATCH] Fix a memory leak in soup_cookie_jar_delete_cookie() A memory leak would happen when asked to delete a matching cookie from a cookie jar that doesn't contain any matching cookies. --- libsoup/soup-cookie-jar.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libsoup/soup-cookie-jar.c b/libsoup/soup-cookie-jar.c index 8322970..03f3d48 100644 --- a/libsoup/soup-cookie-jar.c +++ b/libsoup/soup-cookie-jar.c @@ -758,9 +758,7 @@ soup_cookie_jar_delete_cookie (SoupCookieJar *jar, priv = SOUP_COOKIE_JAR_GET_PRIVATE (jar); - domain = g_strdup (cookie->domain); - - cookies = g_hash_table_lookup (priv->domains, domain); + cookies = g_hash_table_lookup (priv->domains, cookie->domain); if (cookies == NULL) return; @@ -768,6 +766,7 @@ soup_cookie_jar_delete_cookie (SoupCookieJar *jar, SoupCookie *c = (SoupCookie*)p->data; if (soup_cookie_equal (cookie, c)) { cookies = g_slist_delete_link (cookies, p); + domain = g_strdup (cookie->domain); g_hash_table_insert (priv->domains, domain, cookies); -- 1.7.1 --------------050504080101070305040301-- From danw@gnome.org Tue Apr 15 15:21:04 2014 Return-Path: X-Original-To: libsoup-list@gnome.org Delivered-To: libsoup-list@gnome.org Received: from localhost (localhost.localdomain [127.0.0.1]) by restaurant.gnome.org (Postfix) with ESMTP id 047FD76964 for ; Tue, 15 Apr 2014 15:21:04 +0000 (UTC) X-Virus-Scanned: by amavisd-new at gnome.org X-Spam-Flag: NO X-Spam-Score: -1.121 X-Spam-Level: X-Spam-Status: No, score=-1.121 tagged_above=-999 required=2 tests=[BAYES_00=-1.9, SPF_NEUTRAL=0.779] autolearn=no Received: from restaurant.gnome.org ([127.0.0.1]) by localhost (restaurant.gnome.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZfyJ6g2SzFBI for ; Tue, 15 Apr 2014 15:21:03 +0000 (UTC) Received: from mysterion.org (mysterion.org [66.228.43.119]) by restaurant.gnome.org (Postfix) with ESMTP id 6DF0E7695F for ; Tue, 15 Apr 2014 15:20:44 +0000 (UTC) Message-ID: <534D4E5A.7040002@gnome.org> Date: Tue, 15 Apr 2014 11:20:58 -0400 From: Dan Winship User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 MIME-Version: 1.0 To: Joseph Artsimovich , libsoup-list@gnome.org Subject: Re: Memory leak in soup_cookie_jar_delete_cookie() References: <53457D55.70408@youview.com> In-Reply-To: <53457D55.70408@youview.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-BeenThere: libsoup-list@gnome.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "discussion of libsoup, an HTTP library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Apr 2014 15:21:04 -0000 On 04/09/2014 01:03 PM, Joseph Artsimovich wrote: > A memory leak would happen when asked to delete a matching cookie from > a cookie jar that doesn't contain any matching cookies. > > Please see the attached patch. Thanks, committed. -- Dan From joseph.artsimovich@gmail.com Wed Apr 16 15:04:38 2014 Return-Path: X-Original-To: libsoup-list@gnome.org Delivered-To: libsoup-list@gnome.org Received: from localhost (localhost.localdomain [127.0.0.1]) by restaurant.gnome.org (Postfix) with ESMTP id DDDBB76970 for ; Wed, 16 Apr 2014 15:04:38 +0000 (UTC) X-Virus-Scanned: by amavisd-new at gnome.org X-Spam-Flag: NO X-Spam-Score: -2.6 X-Spam-Level: X-Spam-Status: No, score=-2.6 tagged_above=-999 required=2 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001] autolearn=ham Received: from restaurant.gnome.org ([127.0.0.1]) by localhost (restaurant.gnome.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id t0gy9mi9dgqh for ; Wed, 16 Apr 2014 15:04:36 +0000 (UTC) Received: from mail-wi0-f179.google.com (mail-wi0-f179.google.com [209.85.212.179]) by restaurant.gnome.org (Postfix) with ESMTP id DC63376983 for ; Wed, 16 Apr 2014 15:04:17 +0000 (UTC) Received: by mail-wi0-f179.google.com with SMTP id z2so1532512wiv.12 for ; Wed, 16 Apr 2014 08:04:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=l7REYz94CRHgTGqB8XBvYCrPbDHtU6OMtS26g7rx4Dk=; b=XXESKEbvc+OI0MmTL7DJ1ORGiksWu/MAQ6APxjl93mIGnOOwXK2YphlROooD+cBIzP iJXRClHSigpGkyvonoLJ/l3CznFvy+kWqtGDL7FXNVB2R1fsDq/Q03qCk7uklUb5FWLm ZXobtuhvhrjN08PyV9uvnA7bOr/UZnoaWoENQoFCuwP7Ipdk6OonWHkgXkyxA8Rd5lt5 Ge59/xN/+16eLclIKpN2wiXSUCo0VFR7+jf9KFuSBh8ICbi4elimi8OBvTMkdIv8pHmh EOyRiUNq86dAGO0oahKCm8AhGgEkkncginmp11+NvGka9mn0kOnT8rcfSDeNoi8BjZl5 H2rA== X-Received: by 10.180.211.207 with SMTP id ne15mr19745256wic.31.1397660655257; Wed, 16 Apr 2014 08:04:15 -0700 (PDT) Received: from [172.20.35.124] ([31.221.37.8]) by mx.google.com with ESMTPSA id rx9sm34710650wjb.20.2014.04.16.08.04.13 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 16 Apr 2014 08:04:14 -0700 (PDT) Sender: Joseph Artsimovich Message-ID: <534E9BED.30504@youview.com> Date: Wed, 16 Apr 2014 16:04:13 +0100 From: Joseph Artsimovich User-Agent: Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 MIME-Version: 1.0 To: libsoup-list@gnome.org Subject: Ability to pass a custom listening socket to SoupServer Content-Type: multipart/mixed; boundary="------------080600010308030604030603" X-BeenThere: libsoup-list@gnome.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "discussion of libsoup, an HTTP library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Apr 2014 15:04:38 -0000 This is a multi-part message in MIME format. --------------080600010308030604030603 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Hi, I posted this patch a while ago, but we never got all the way through reviewing it. I've updated it against git master and I am asking for another review. -- Joseph Artsimovich Software Engineer at YouView TV Ltd --------------080600010308030604030603 Content-Type: text/x-patch; name="0001-Make-it-possible-to-provide-a-custom-listening-socke.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-Make-it-possible-to-provide-a-custom-listening-socke.pa"; filename*1="tch" >From e31f2e767228e7bb238d6716d2d9b6e788feed52 Mon Sep 17 00:00:00 2001 From: Joseph Artsimovich Date: Thu, 22 Aug 2013 16:13:46 +0100 Subject: [PATCH] Make it possible to provide a custom listening socket to SoupServer The patch makes it possible to support systemd socket activation [1] mechanism in applications using SoupServer. The idea behind systemd socket activation is to launch a server application on demand, when someone tries to connect to it. The application gets passed a listening socket with a connection pending on it, and from that point it's the application's responsibility to accept new connections. Instead of adding support for systemd specifically, this patch introduces a more general ability to provide a custom listening socket to SoupServer. This works like this: sock = g_socket_new(...); g_socket_bind(sock, ...); g_socket_listen(sock, ...); server = soup_server_new(SOUP_SERVER_LISTEN_SOCKET, sock, NULL); [1]: http://0pointer.de/blog/projects/socket-activation.html --- libsoup/soup-server.c | 24 +++++++ libsoup/soup-server.h | 1 + libsoup/soup-socket.c | 102 ++++++++++++++++++++++--------- libsoup/soup-socket.h | 1 + tests/Makefile.am | 1 + tests/listen-socket-test.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 244 insertions(+), 30 deletions(-) create mode 100644 tests/listen-socket-test.c diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c index 07d801d..fb90b44 100644 --- a/libsoup/soup-server.c +++ b/libsoup/soup-server.c @@ -97,6 +97,7 @@ typedef struct { GMainLoop *loop; SoupSocket *listen_sock; + GSocket *listen_sock_prop; GSList *clients; gboolean raw_paths; @@ -126,6 +127,7 @@ enum { PROP_SERVER_HEADER, PROP_HTTP_ALIASES, PROP_HTTPS_ALIASES, + PROP_LISTEN_SOCKET, LAST_PROP }; @@ -167,6 +169,7 @@ soup_server_finalize (GObject *object) g_free (priv->server_header); g_clear_object (&priv->listen_sock); + g_clear_object (&priv->listen_sock_prop); while (priv->clients) { SoupClientContext *client = priv->clients->data; @@ -245,6 +248,7 @@ soup_server_constructor (GType type, soup_socket_new (SOUP_SOCKET_LOCAL_ADDRESS, priv->iface, SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_cert, SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context, + SOUP_SOCKET_LISTEN_SOCKET, priv->listen_sock_prop, NULL); if (!soup_socket_listen (priv->listen_sock)) { g_object_unref (server); @@ -345,6 +349,9 @@ soup_server_set_property (GObject *object, guint prop_id, case PROP_HTTPS_ALIASES: set_aliases (&priv->https_aliases, g_value_get_boxed (value)); break; + case PROP_LISTEN_SOCKET: + priv->listen_sock_prop = g_value_dup_object (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -737,6 +744,23 @@ soup_server_class_init (SoupServerClass *server_class) "URI schemes that are considered aliases for 'https'", G_TYPE_STRV, G_PARAM_READWRITE)); + + /** SOUP_SERVER_LISTEN_SOCKET: + * + * Alias for the #SoupServer:listen-socket property. Makes it possible + * to provide a socket to be used for listening for incoming connections. + * The provided socket has to be in listening state already. Passing a + * null pointer as a value of this property is allowed and has no effect. + * When #SoupServer:listen-socket property is set, #SoupServer:interface + * and #SoupServer:port are ignored. + */ + g_object_class_install_property ( + object_class, PROP_LISTEN_SOCKET, + g_param_spec_object (SOUP_SERVER_LISTEN_SOCKET, + "Listening socket", + "Socket in listening state", + G_TYPE_SOCKET, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } /** diff --git a/libsoup/soup-server.h b/libsoup/soup-server.h index 0d09322..9d82d54 100644 --- a/libsoup/soup-server.h +++ b/libsoup/soup-server.h @@ -66,6 +66,7 @@ typedef void (*SoupServerCallback) (SoupServer *server, #define SOUP_SERVER_SERVER_HEADER "server-header" #define SOUP_SERVER_HTTP_ALIASES "http-aliases" #define SOUP_SERVER_HTTPS_ALIASES "https-aliases" +#define SOUP_SERVER_LISTEN_SOCKET "listen-socket" SoupServer *soup_server_new (const char *optname1, ...) G_GNUC_NULL_TERMINATED; diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index b9f1dfc..c399b07 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -60,6 +60,7 @@ enum { PROP_TLS_CERTIFICATE, PROP_TLS_ERRORS, PROP_PROXY_RESOLVER, + PROP_LISTEN_SOCKET, LAST_PROP }; @@ -68,6 +69,7 @@ typedef struct { SoupAddress *local_addr, *remote_addr; GIOStream *conn, *iostream; GSocket *gsock; + GSocket *listen_sock; GInputStream *istream; GOutputStream *ostream; GTlsCertificateFlags tls_errors; @@ -142,6 +144,7 @@ soup_socket_finalize (GObject *object) disconnect_internal (SOUP_SOCKET (object), TRUE); } + g_clear_object (&priv->listen_sock); g_clear_object (&priv->conn); g_clear_object (&priv->iostream); g_clear_object (&priv->istream); @@ -229,6 +232,9 @@ soup_socket_set_property (GObject *object, guint prop_id, case PROP_CLEAN_DISPOSE: priv->clean_dispose = g_value_get_boolean (value); break; + case PROP_LISTEN_SOCKET: + priv->listen_sock = g_value_dup_object (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -628,6 +634,24 @@ soup_socket_class_init (SoupSocketClass *socket_class) "GProxyResolver to use", G_TYPE_PROXY_RESOLVER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * SOUP_SOCKET_LISTEN_SOCKET: + * + * Alias for the #SoupSocket:listen-socket property. Makes it possible + * to provide a socket to be used for listening for incoming connections. + * The provided socket has to be in listening state already. Passing a + * null pointer as a value of this property is allowed and has no effect. + * When #SoupSocket:listen-socket property is set, #SoupSocket:local-address + * is ignored. + **/ + g_object_class_install_property ( + object_class, PROP_LISTEN_SOCKET, + g_param_spec_object (SOUP_SOCKET_LISTEN_SOCKET, + "Listening socket", + "Socket in listening state", + G_TYPE_SOCKET, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } @@ -1025,8 +1049,12 @@ listen_watch (GObject *pollable, gpointer data) * @sock: a server #SoupSocket (which must not already be connected or * listening) * - * Makes @sock start listening on its local address. When connections - * come in, @sock will emit #SoupSocket::new_connection. + * Makes @sock start listening on its local address, or whatever address + * #SoupSocket::listen-socket is bound to, if it was provided. + * Note than even though #SoupSocket::listen-socket must already be + * in listening state, a call to soup_socket_listen() is still required. + * + * When connections come in, @sock will emit #SoupSocket::new_connection. * * Return value: whether or not @sock is now listening. **/ @@ -1035,53 +1063,67 @@ soup_socket_listen (SoupSocket *sock) { SoupSocketPrivate *priv; - GSocketAddress *addr; + GSocketAddress *addr = NULL; g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE); priv = SOUP_SOCKET_GET_PRIVATE (sock); g_return_val_if_fail (priv->gsock == NULL, FALSE); - g_return_val_if_fail (priv->local_addr != NULL, FALSE); + if (!priv->listen_sock) + g_return_val_if_fail (priv->local_addr != NULL, FALSE); priv->is_server = TRUE; - /* @local_addr may have its port set to 0. So we intentionally - * don't store it in priv->local_addr, so that if the - * caller calls soup_socket_get_local_address() later, we'll - * have to make a new addr by calling getsockname(), which - * will have the right port number. - */ - addr = soup_address_get_gsockaddr (priv->local_addr); - g_return_val_if_fail (addr != NULL, FALSE); + if (priv->listen_sock) { + priv->gsock = priv->listen_sock; + g_object_ref(priv->gsock); + finish_socket_setup (priv); + } else { + /* @local_addr may have its port set to 0. So we intentionally + * don't store it in priv->local_addr, so that if the + * caller calls soup_socket_get_local_address() later, we'll + * have to make a new addr by calling getsockname(), which + * will have the right port number. + */ + addr = soup_address_get_gsockaddr (priv->local_addr); + g_return_val_if_fail (addr != NULL, FALSE); - priv->gsock = g_socket_new (g_socket_address_get_family (addr), - G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_DEFAULT, - NULL); - if (!priv->gsock) - goto cant_listen; - finish_socket_setup (priv); + priv->gsock = g_socket_new (g_socket_address_get_family (addr), + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + NULL); - /* Bind */ - if (!g_socket_bind (priv->gsock, addr, TRUE, NULL)) - goto cant_listen; - /* Force local_addr to be re-resolved now */ - g_object_unref (priv->local_addr); - priv->local_addr = NULL; + if (!priv->gsock) + goto cant_listen; + finish_socket_setup (priv); - /* Listen */ - if (!g_socket_listen (priv->gsock, NULL)) - goto cant_listen; + /* Bind */ + if (!g_socket_bind (priv->gsock, addr, TRUE, NULL)) + goto cant_listen; + + /* Listen */ + if (!g_socket_listen (priv->gsock, NULL)) + goto cant_listen; + } + + /* Force local_addr to be re-resolved now */ + if (priv->local_addr) { + g_object_unref (priv->local_addr); + priv->local_addr = NULL; + } priv->watch_src = soup_socket_create_watch (priv, G_IO_IN, listen_watch, sock, NULL); - g_object_unref (addr); + if (addr) + g_object_unref (addr); + return TRUE; cant_listen: if (priv->conn) disconnect_internal (sock, TRUE); - g_object_unref (addr); + if (addr) + g_object_unref (addr); return FALSE; } diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h index 5c1264f..a2a90dd 100644 --- a/libsoup/soup-socket.h +++ b/libsoup/soup-socket.h @@ -52,6 +52,7 @@ typedef struct { #define SOUP_SOCKET_TIMEOUT "timeout" #define SOUP_SOCKET_TLS_CERTIFICATE "tls-certificate" #define SOUP_SOCKET_TLS_ERRORS "tls-errors" +#define SOUP_SOCKET_LISTEN_SOCKET "listen-socket" typedef void (*SoupSocketCallback) (SoupSocket *sock, guint status, diff --git a/tests/Makefile.am b/tests/Makefile.am index a8b9d01..e8bc1e6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,6 +21,7 @@ test_programs = \ date \ forms-test \ header-parsing \ + listen-socket-test \ misc-test \ multipart-test \ no-ssl-test \ diff --git a/tests/listen-socket-test.c b/tests/listen-socket-test.c new file mode 100644 index 0000000..1a26dc1 --- /dev/null +++ b/tests/listen-socket-test.c @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright 2014 YouView TV Ltd + */ + +#include "test-utils.h" + +#include +#include + +static GSocket* create_listening_socket (void) +{ + gboolean bret; + GSocket* sock; + GInetAddress* inet_addr; + GSocketAddress* sock_addr; + + inet_addr = g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4); + sock_addr = g_inet_socket_address_new(inet_addr, 0); + + + sock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_TCP, NULL); + g_assert(sock); + + bret = g_socket_bind (sock, sock_addr, /*allow_reuse*/TRUE, NULL); + g_assert(bret); + + bret = g_socket_listen (sock, NULL); + g_assert(bret); + + g_object_unref(sock_addr); + g_object_unref(inet_addr); + + return sock; +} + +static void +do_listen_socket_low_level_test (void) +{ + GSocket* listen_sock; + SoupSocket* server_sock, *client_sock; + SoupAddress* server_addr; + gboolean bret; + guint uret; + + listen_sock = create_listening_socket (); + g_assert(listen_sock); + + server_sock = soup_socket_new (SOUP_SOCKET_LISTEN_SOCKET, listen_sock, NULL); + g_assert (server_sock); + + bret = soup_socket_listen (server_sock); + g_assert (bret); + + server_addr = soup_socket_get_local_address (server_sock); + g_assert (server_addr); + g_assert (g_socket_get_fd (listen_sock) == soup_socket_get_fd (server_sock)); + + client_sock = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, server_addr, NULL); + g_assert (client_sock); + + uret = soup_socket_connect_sync (client_sock, NULL); + g_assert_cmpuint (uret, ==, SOUP_STATUS_OK); + + g_object_unref (client_sock); + g_object_unref (server_sock); + g_object_unref (listen_sock); +} + +struct RequestContext +{ + GMainLoop* main_loop; + guint response_status; +}; + +static void +response_handler(SoupSession *session, SoupMessage *msg, gpointer user_data) +{ + struct RequestContext* ctx = user_data; + ctx->response_status = msg->status_code; + g_main_loop_quit (ctx->main_loop); +} + +static void +do_listen_socket_server_test (void) +{ + GSocket* listen_sock; + SoupServer* server; + SoupSocket* server_listener; + SoupSession* session; + SoupMessage* message; + char http_addr[100]; + guint server_port; + struct RequestContext ctx; + + ctx.main_loop = g_main_loop_new (NULL, FALSE); + ctx.response_status = 0; + g_assert (ctx.main_loop); + + listen_sock = create_listening_socket (); + g_assert (listen_sock); + + server = soup_server_new (SOUP_SERVER_LISTEN_SOCKET, listen_sock, NULL); + g_assert (server); + server_port = soup_server_get_port (server); + + server_listener = soup_server_get_listener (server); + g_assert(server_listener); + g_assert (g_socket_get_fd (listen_sock) == soup_socket_get_fd (server_listener)); + + session = soup_session_async_new (); + g_assert (session); + + g_snprintf (http_addr, sizeof(http_addr), "http://127.0.0.1:%u/", server_port); + message = soup_message_new ("GET", http_addr); + + soup_session_queue_message (session, message, &response_handler, &ctx); + + soup_server_run_async (server); + + g_main_loop_run (ctx.main_loop); + + g_object_unref (session); + g_object_unref (server); + g_object_unref (listen_sock); + g_main_loop_unref (ctx.main_loop); + + g_assert_cmpuint (ctx.response_status, ==, SOUP_STATUS_NOT_FOUND); +} + +int +main (int argc, char **argv) +{ + int ret; + test_init (argc, argv, NULL); + + g_test_add_func ("/listen-socket/low-level", do_listen_socket_low_level_test); + g_test_add_func ("/listen-socket/server", do_listen_socket_server_test); + + ret = g_test_run (); + + test_cleanup (); + return ret; +} -- 1.7.1 --------------080600010308030604030603-- From joseph.artsimovich@gmail.com Wed Apr 23 10:41:59 2014 Return-Path: X-Original-To: libsoup-list@gnome.org Delivered-To: libsoup-list@gnome.org Received: from localhost (localhost.localdomain [127.0.0.1]) by restaurant.gnome.org (Postfix) with ESMTP id 8F36F765C6 for ; Wed, 23 Apr 2014 10:41:59 +0000 (UTC) X-Virus-Scanned: by amavisd-new at gnome.org X-Spam-Flag: NO X-Spam-Score: -2.6 X-Spam-Level: X-Spam-Status: No, score=-2.6 tagged_above=-999 required=2 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001] autolearn=ham Received: from restaurant.gnome.org ([127.0.0.1]) by localhost (restaurant.gnome.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pscnGkc9Pf5K for ; Wed, 23 Apr 2014 10:41:57 +0000 (UTC) Received: from mail-we0-f171.google.com (mail-we0-f171.google.com [74.125.82.171]) by restaurant.gnome.org (Postfix) with ESMTP id 68552769FF for ; Wed, 23 Apr 2014 10:41:38 +0000 (UTC) Received: by mail-we0-f171.google.com with SMTP id t61so668957wes.16 for ; Wed, 23 Apr 2014 03:41:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=B7EmJFmygaeMtjYI/zyuhlBPtWC6iA6l28nE0dN4B7M=; b=ROXGbhxmq2t4ytJeoJ1bUuo1Fkk9Rciw0jT1/vbfSemqUX24YHHgIa52IOpQqIyU8r /mYtV4GOM58BwoAmLjaG1d7g5BwjZq1+yXtc90fwja6k7ZI+c2DogJMsy0GSiaejEySh RmxZbL5HIe6al17O9Kdqp2xk15hXnZ3gRyPZe9+jxQF5myYgjJvhGYrpfuajNpAHAdSv E5efpW5TaOrbFCrc1EHtsWsxLcZ+9Z1S7FCQvl8sEMFs1wb0+lhfLdSCGiHjH2qGIaeB CmqAvJDaxSDayFjxXZa0dXT0pXg5bu7WY/0KFE60bIvcztmZ+7L79l5OvPxx0PIzVNCg rBQw== X-Received: by 10.180.80.3 with SMTP id n3mr1242218wix.36.1398249696846; Wed, 23 Apr 2014 03:41:36 -0700 (PDT) Received: from [172.20.35.124] ([31.221.37.8]) by mx.google.com with ESMTPSA id h1sm946696wjy.7.2014.04.23.03.41.35 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 23 Apr 2014 03:41:36 -0700 (PDT) Sender: Joseph Artsimovich Message-ID: <535798DF.9050101@youview.com> Date: Wed, 23 Apr 2014 11:41:35 +0100 From: Joseph Artsimovich User-Agent: Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 MIME-Version: 1.0 To: libsoup-list@gnome.org Subject: Make SoupCookieJarDB robust against database file corruption Content-Type: multipart/mixed; boundary="------------010003050604060208080208" X-BeenThere: libsoup-list@gnome.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "discussion of libsoup, an HTTP library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 Apr 2014 10:41:59 -0000 This is a multi-part message in MIME format. --------------010003050604060208080208 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Hi, Please take a look at the attached patch. -- Joseph Artsimovich Software Engineer at YouView TV Ltd --------------010003050604060208080208 Content-Type: text/x-patch; name="0001-Make-SoupCookieJarDB-robust-to-database-file-corrupt.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-Make-SoupCookieJarDB-robust-to-database-file-corrupt.pa"; filename*1="tch" >From 4c785fc864e7b8cf9dddf8687736db81e9b00d08 Mon Sep 17 00:00:00 2001 From: Joseph Artsimovich Date: Wed, 23 Apr 2014 11:14:27 +0100 Subject: [PATCH 1/2] Make SoupCookieJarDB robust to database file corruption. SoupCookieJarDB stores cookies in a SQLite database. Until now, a corrupted database file resulted in warnings in a log and cookies not being stored to or loaded from the database. This change forces a database file to be deleted and re-created whenever the open operation or a query to the database fails. --- libsoup/soup-cookie-jar-db.c | 83 ++++++++++++++---- tests/Makefile.am | 1 + tests/cookiejar-db-test.c | 186 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+), 19 deletions(-) create mode 100644 tests/cookiejar-db-test.c diff --git a/libsoup/soup-cookie-jar-db.c b/libsoup/soup-cookie-jar-db.c index 8f21baa..2054c5c 100644 --- a/libsoup/soup-cookie-jar-db.c +++ b/libsoup/soup-cookie-jar-db.c @@ -13,6 +13,8 @@ #include +#include +#include #include #include "soup-cookie-jar-db.h" @@ -48,6 +50,7 @@ typedef struct { G_DEFINE_TYPE (SoupCookieJarDB, soup_cookie_jar_db, SOUP_TYPE_COOKIE_JAR) static void load (SoupCookieJar *jar); +static gboolean open_db (SoupCookieJar *jar, gboolean delete_db_file); static void soup_cookie_jar_db_init (SoupCookieJarDB *db) @@ -188,30 +191,54 @@ callback (void *data, int argc, char **argv, char **colname) } static void -try_create_table (sqlite3 *db) +try_create_table (SoupCookieJar *jar, gboolean delete_db_file) { char *error = NULL; + SoupCookieJarDBPrivate *priv = SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar); - if (sqlite3_exec (db, CREATE_TABLE, NULL, NULL, &error)) { - g_warning ("Failed to execute query: %s", error); - sqlite3_free (error); + if (delete_db_file) { + if (0 != open_db (jar, /*delete_db_file=*/TRUE)) { + /* open_db() prints errors by itself. */ + return; + } + } + + if (sqlite3_exec (priv->db, CREATE_TABLE, NULL, NULL, &error)) { + if (delete_db_file) { + g_warning ("Failed to execute query: %s", error); + sqlite3_free (error); + } else { + g_info ("Failed to create table. Deleting the database and retrying."); + sqlite3_free (error); + try_create_table(jar, /*delete_db_file=*/TRUE); + } } } static void -exec_query_with_try_create_table (sqlite3 *db, +exec_query_with_try_create_table (SoupCookieJar *jar, const char *sql, int (*callback)(void*,int,char**,char**), void *argument) { char *error = NULL; gboolean try_create = TRUE; + SoupCookieJarDBPrivate *priv = SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar); try_exec: - if (sqlite3_exec (db, sql, callback, argument, &error)) { + /* Note that try_create_table() below can leave us with + * priv->db == NULL, so this check needs to go below try_exec. */ + if (!priv->db) { + if (0 != open_db (jar, /*delete_db_file=*/TRUE)) { + /* open_db() prints errors by itself. */ + return; + } + } + + if (sqlite3_exec (priv->db, sql, callback, argument, &error)) { if (try_create) { try_create = FALSE; - try_create_table (db); + try_create_table (jar, /*delete_db_file=*/FALSE); sqlite3_free (error); error = NULL; goto try_exec; @@ -224,23 +251,41 @@ try_exec: /* Follows sqlite3 convention; returns TRUE on error */ static gboolean -open_db (SoupCookieJar *jar) +open_db (SoupCookieJar *jar, gboolean delete_db_file) { SoupCookieJarDBPrivate *priv = SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar); char *error = NULL; + if (delete_db_file) { + g_clear_pointer (&priv->db, sqlite3_close); + + if (0 != g_unlink (priv->filename)) { + g_warning("Unable to delete %s", priv->filename); + return TRUE; + } + } + if (sqlite3_open (priv->filename, &priv->db)) { - sqlite3_close (priv->db); - priv->db = NULL; - g_warning ("Can't open %s", priv->filename); - return TRUE; + g_clear_pointer (&priv->db, sqlite3_close); + if (delete_db_file) { + g_warning ("Can't open %s", priv->filename); + return TRUE; + } else { + return open_db (jar, /*delete_db_file=*/TRUE); + } } if (sqlite3_exec (priv->db, "PRAGMA synchronous = OFF; PRAGMA secure_delete = 1;", NULL, NULL, &error)) { - g_warning ("Failed to execute query: %s", error); - sqlite3_free (error); + if (delete_db_file) { + g_warning ("Failed to execute query: %s", error); + sqlite3_free (error); + return TRUE; + } else { + sqlite3_free (error); + return open_db (jar, /*delete_db_file=*/TRUE); + } } return FALSE; @@ -253,11 +298,11 @@ load (SoupCookieJar *jar) SOUP_COOKIE_JAR_DB_GET_PRIVATE (jar); if (priv->db == NULL) { - if (open_db (jar)) + if (open_db (jar, /*delete_db_file=*/FALSE)) return; } - exec_query_with_try_create_table (priv->db, QUERY_ALL, callback, jar); + exec_query_with_try_create_table (jar, QUERY_ALL, callback, jar); } static void @@ -270,7 +315,7 @@ soup_cookie_jar_db_changed (SoupCookieJar *jar, char *query; if (priv->db == NULL) { - if (open_db (jar)) + if (open_db (jar, /*delete_db_file=*/FALSE)) return; } @@ -278,7 +323,7 @@ soup_cookie_jar_db_changed (SoupCookieJar *jar, query = sqlite3_mprintf (QUERY_DELETE, old_cookie->name, old_cookie->domain); - exec_query_with_try_create_table (priv->db, query, NULL, NULL); + exec_query_with_try_create_table (jar, query, NULL, NULL); sqlite3_free (query); } @@ -294,7 +339,7 @@ soup_cookie_jar_db_changed (SoupCookieJar *jar, expires, new_cookie->secure, new_cookie->http_only); - exec_query_with_try_create_table (priv->db, query, NULL, NULL); + exec_query_with_try_create_table (jar, query, NULL, NULL); sqlite3_free (query); } } diff --git a/tests/Makefile.am b/tests/Makefile.am index a8b9d01..6a44cc3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,6 +18,7 @@ test_programs = \ context-test \ continue-test \ cookies-test \ + cookiejar-db-test \ date \ forms-test \ header-parsing \ diff --git a/tests/cookiejar-db-test.c b/tests/cookiejar-db-test.c new file mode 100644 index 0000000..b1663bb --- /dev/null +++ b/tests/cookiejar-db-test.c @@ -0,0 +1,186 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2014 YouView TV Ltd + */ + +#include "test-utils.h" + +#include +#include + +#include +#include +#include + +static void rmdir_recursive (const gchar *dir_path) +{ + GError* error; + GDir *dir; + const gchar *entry; + + dir = g_dir_open (dir_path, 0, &error); + if (!dir) { + g_warning ("Failed to delete directory \"%s\": %s", + dir_path, error->message); + g_error_free (error); + return; + } + + while ((entry = g_dir_read_name (dir))) { + gchar *entry_path = g_strdup_printf("%s/%s", dir_path, entry); + if (-1 == g_unlink (entry_path)) { + /* If unlinking failed, we assume it's a directory. */ + rmdir_recursive (entry_path); + } + g_free (entry_path); + } + + g_dir_close (dir); + if (-1 == g_rmdir (dir_path)) + { + g_warning ("Failed to delete directory \"%s\"", dir_path); + } +} + +static void +perform_basic_test (const gchar *db_file_path) +{ + SoupCookieJar *jar1, *jar2; + SoupCookie *cookie; + SoupURI *uri; + gchar *keyval; + + jar1 = soup_cookie_jar_db_new (db_file_path, FALSE); + g_test_queue_unref (jar1); + + /* Add a cookie to jar1. */ + cookie = soup_cookie_new ("testcookie", "value", "test.com", "/", + SOUP_COOKIE_MAX_AGE_ONE_DAY); + soup_cookie_jar_add_cookie (jar1, cookie); + + /* Open the same database file again, as jar2. */ + jar2 = soup_cookie_jar_db_new (db_file_path, FALSE); + g_test_queue_unref (jar2); + + uri = soup_uri_new("http://test.com/"); + g_test_queue_destroy ((GDestroyNotify)soup_uri_free, uri); + + /* Read the cookie back from jar2. */ + keyval = soup_cookie_jar_get_cookies (jar2, uri, TRUE); + if (0 != g_strcmp0 (keyval, "testcookie=value")) { + g_printerr ("Unexpected cookies retrieved: %s\n", keyval); + g_test_fail (); + return; + } +} + +static void +do_basic_test (void) +{ + gchar *temp_dir; + gchar *db_file_path; + + temp_dir = g_dir_make_tmp("soup-cookiejar-db-basic-test-XXXXXX", NULL); + g_test_queue_destroy ((GDestroyNotify)rmdir_recursive, temp_dir); + + db_file_path = g_strdup_printf ("%s/db.sqlite", temp_dir); + g_test_queue_free (db_file_path); + + perform_basic_test (db_file_path); +} + +static void +do_empty_file_recovery_test (void) +{ + gchar *temp_dir; + gchar *db_file_path; + + temp_dir = g_dir_make_tmp( + "soup-cookiejar-db-empty-file-recovery-XXXXXX", NULL); + g_test_queue_destroy ((GDestroyNotify)rmdir_recursive, temp_dir); + + db_file_path = g_strdup_printf ("%s/db.sqlite", temp_dir); + g_test_queue_free (db_file_path); + + /* Create an empty database file. */ + fclose(g_fopen(db_file_path, "w")); + + perform_basic_test (db_file_path); +} + +static void +do_broken_file_recovery_test (void) +{ + gchar *temp_dir; + gchar *db_file_path; + FILE *db_file; + char buf[2048]; + + temp_dir = g_dir_make_tmp( + "soup-cookiejar-db-broken-file-recovery-XXXXXX", NULL); + g_test_queue_destroy ((GDestroyNotify)rmdir_recursive, temp_dir); + + db_file_path = g_strdup_printf ("%s/db.sqlite", temp_dir); + g_test_queue_free (db_file_path); + + /* Fill buf with 0xff bytes and write that to db.sqlite file. */ + db_file = g_fopen(db_file_path, "w"); + memset(buf, 0xff, sizeof(buf)); + fwrite(buf, sizeof(buf), 1, db_file); + fclose(db_file); + + perform_basic_test (db_file_path); +} + +static void +do_broken_schema_recovery_test (void) +{ + gchar *temp_dir; + gchar *db_file_path; + sqlite3 *db = NULL; + char* errmsg = NULL; + const char *query = "CREATE TABLE moz_cookies(id INTEGER)"; + + temp_dir = g_dir_make_tmp("soup-cookiejar-db-schema-recovery-XXXXXX", NULL); + g_test_queue_destroy ((GDestroyNotify)rmdir_recursive, temp_dir); + + db_file_path = g_strdup_printf ("%s/db.sqlite", temp_dir); + g_test_queue_free (db_file_path); + + if (sqlite3_open (db_file_path, &db)) { + g_printerr ("Unable to open %s\n", db_file_path); + g_test_fail (); + return; + } + + if (sqlite3_exec(db, query, NULL, NULL, &errmsg)) { + g_printerr ("Error executing query: %s", errmsg); + sqlite3_free(errmsg); + return; + } + + sqlite3_close(db); + + perform_basic_test (db_file_path); +} + +int +main (int argc, char **argv) +{ + int ret; + + test_init (argc, argv, NULL); + + g_test_add_func ("/cookiejar-db/basic-test", do_basic_test); + g_test_add_func ("/cookiejar-db/recovery/empty-file", + do_empty_file_recovery_test); + g_test_add_func ("/cookiejar-db/recovery/broken-file", + do_broken_file_recovery_test); + g_test_add_func ("/cookiejar-db/recovery/broken-schema", + do_broken_schema_recovery_test); + + ret = g_test_run (); + + test_cleanup (); + return ret; +} -- 1.7.1 --------------010003050604060208080208--