[libsoup] SoupCache: add SoupContentProcessor support
- From: Sergio Villar Senin <svillar src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] SoupCache: add SoupContentProcessor support
- Date: Tue, 18 Dec 2012 15:49:45 +0000 (UTC)
commit 1fd0404b4c8fe5e6da8e04dfef44bf63a4af0a75
Author: Sergio Villar Senin <svillar igalia com>
Date: Thu Aug 23 17:55:05 2012 +0200
SoupCache: add SoupContentProcessor support
SoupCache now implements the SoupContentProcessor interface. This means that
soup-message-io will ask it to wrap a given base stream. By doing that the
cache will backup up every byte readed from that base stream into a local
file using a SoupCacheInputStream.
Apart from that, this removes all the old resource writing infrastructure
that was moved to the new SoupCacheInputStream. The SoupCache just needs
to pass a callback to the stream in order to be notified once the caching
operation finishes.
This also involves moving the caching decision from the "got-headers"
callback to the _wrap_input() implementation.
https://bugzilla.gnome.org/show_bug.cgi?id=682112
libsoup/soup-cache.c | 572 +++++++++++-------------------------
libsoup/soup-client-input-stream.c | 23 --
2 files changed, 178 insertions(+), 417 deletions(-)
---
diff --git a/libsoup/soup-cache.c b/libsoup/soup-cache.c
index 24a4b2c..da89ddf 100644
--- a/libsoup/soup-cache.c
+++ b/libsoup/soup-cache.c
@@ -32,12 +32,19 @@
#include <string.h>
#include "soup-cache.h"
+#include "soup-body-input-stream.h"
+#include "soup-cache-input-stream.h"
#include "soup-cache-private.h"
+#include "soup-content-processor.h"
+#include "soup-message-private.h"
#include "soup.h"
static SoupSessionFeatureInterface *soup_cache_default_feature_interface;
static void soup_cache_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
+static SoupContentProcessorInterface *soup_cache_default_content_processor_interface;
+static void soup_cache_content_processor_init (SoupContentProcessorInterface *interface, gpointer interface_data);
+
#define DEFAULT_MAX_SIZE 50 * 1024 * 1024
#define MAX_ENTRY_DATA_PERCENTAGE 10 /* Percentage of the total size
of the cache that can be
@@ -104,21 +111,6 @@ struct _SoupCachePrivate {
GList *lru_start;
};
-typedef struct {
- SoupCache *cache;
- SoupCacheEntry *entry;
- SoupMessage *msg;
- gulong content_sniffed_handler;
- gulong got_chunk_handler;
- gulong got_body_handler;
- gulong restarted_handler;
- GQueue *buffer_queue;
- gboolean got_body;
- SoupBuffer *current_writing_buffer;
- GError *error;
- GOutputStream *ostream;
-} SoupCacheWritingFixture;
-
enum {
PROP_0,
PROP_CACHE_DIR,
@@ -129,12 +121,13 @@ enum {
G_DEFINE_TYPE_WITH_CODE (SoupCache, soup_cache, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
- soup_cache_session_feature_init))
+ soup_cache_session_feature_init)
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_CONTENT_PROCESSOR,
+ soup_cache_content_processor_init))
static gboolean soup_cache_entry_remove (SoupCache *cache, SoupCacheEntry *entry, gboolean purge);
static void make_room_for_new_entry (SoupCache *cache, guint length_to_add);
static gboolean cache_accepts_entries_of_size (SoupCache *cache, guint length_to_add);
-static gboolean write_next_buffer (SoupCacheEntry *entry, SoupCacheWritingFixture *fixture);
static GFile *
get_file_from_entry (SoupCache *cache, SoupCacheEntry *entry)
@@ -489,232 +482,11 @@ soup_cache_entry_new (SoupCache *cache, SoupMessage *msg, time_t request_time, t
return entry;
}
-static void
-soup_cache_writing_fixture_free (SoupCacheWritingFixture *fixture)
-{
- /* Free fixture. And disconnect signals, we don't want to
- listen to more SoupMessage events as we're finished with
- this resource */
- if (g_signal_handler_is_connected (fixture->msg, fixture->content_sniffed_handler))
- g_signal_handler_disconnect (fixture->msg, fixture->content_sniffed_handler);
- if (g_signal_handler_is_connected (fixture->msg, fixture->got_chunk_handler))
- g_signal_handler_disconnect (fixture->msg, fixture->got_chunk_handler);
- if (g_signal_handler_is_connected (fixture->msg, fixture->got_body_handler))
- g_signal_handler_disconnect (fixture->msg, fixture->got_body_handler);
- if (g_signal_handler_is_connected (fixture->msg, fixture->restarted_handler))
- g_signal_handler_disconnect (fixture->msg, fixture->restarted_handler);
- g_clear_pointer (&fixture->current_writing_buffer, soup_buffer_free);
- g_clear_object (&fixture->ostream);
- g_clear_error (&fixture->error);
- g_queue_foreach (fixture->buffer_queue, (GFunc) soup_buffer_free, NULL);
- g_queue_free (fixture->buffer_queue);
- g_object_unref (fixture->msg);
- g_object_unref (fixture->cache);
- g_slice_free (SoupCacheWritingFixture, fixture);
-}
-
-static void
-msg_content_sniffed_cb (SoupMessage *msg, gchar *content_type, GHashTable *params, SoupCacheWritingFixture *fixture)
-{
- soup_message_headers_set_content_type (fixture->entry->headers, content_type, params);
-}
-
-static void
-close_ready_cb (GObject *source, GAsyncResult *result, SoupCacheWritingFixture *fixture)
-{
- SoupCacheEntry *entry = fixture->entry;
- SoupCache *cache = fixture->cache;
- GOutputStream *stream = G_OUTPUT_STREAM (source);
- goffset content_length;
-
- g_warn_if_fail (fixture->error == NULL);
-
- /* FIXME: what do we do on error ? */
-
- if (stream) {
- g_output_stream_close_finish (stream, result, NULL);
- g_object_unref (stream);
- }
- fixture->ostream = NULL;
-
- content_length = soup_message_headers_get_content_length (entry->headers);
-
- /* If the process was cancelled, then delete the entry from
- the cache. Do it also if the size of a chunked resource is
- too much for the cache */
- if (g_cancellable_is_cancelled (entry->cancellable)) {
- entry->dirty = FALSE;
- soup_cache_entry_remove (cache, entry, TRUE);
- entry = NULL;
- } else if ((soup_message_headers_get_encoding (entry->headers) == SOUP_ENCODING_CHUNKED) ||
- entry->length != (gsize) content_length) {
- /* Two options here:
- *
- * 1. "chunked" data, entry was temporarily added to
- * cache (as content-length is 0) and now that we have
- * the actual size we have to evaluate if we want it
- * in the cache or not
- *
- * 2. Content-Length has a different value than actual
- * length, means that the content was encoded for
- * transmission (typically compressed) and thus we
- * have to substract the content-length value that was
- * added to the cache and add the unencoded length
- */
- gint length_to_add = entry->length - content_length;
-
- /* Make room in cache if needed */
- if (cache_accepts_entries_of_size (cache, length_to_add)) {
- make_room_for_new_entry (cache, length_to_add);
-
- cache->priv->size += length_to_add;
- } else {
- entry->dirty = FALSE;
- soup_cache_entry_remove (cache, entry, TRUE);
- entry = NULL;
- }
- }
-
- if (entry) {
- entry->dirty = FALSE;
- fixture->got_body = FALSE;
-
- g_clear_pointer (&fixture->current_writing_buffer, soup_buffer_free);
- g_clear_object (&entry->cancellable);
- }
-
- cache->priv->n_pending--;
-
- /* Frees */
- soup_cache_writing_fixture_free (fixture);
-}
-
-static void
-write_ready_cb (GObject *source, GAsyncResult *result, SoupCacheWritingFixture *fixture)
-{
- GOutputStream *stream = G_OUTPUT_STREAM (source);
- gssize write_size;
- SoupCacheEntry *entry = fixture->entry;
-
- if (g_cancellable_is_cancelled (entry->cancellable)) {
- g_output_stream_close_async (stream,
- G_PRIORITY_LOW,
- entry->cancellable,
- (GAsyncReadyCallback)close_ready_cb,
- fixture);
- return;
- }
-
- write_size = g_output_stream_write_finish (stream, result, &fixture->error);
- if (write_size <= 0 || fixture->error) {
- g_output_stream_close_async (stream,
- G_PRIORITY_LOW,
- entry->cancellable,
- (GAsyncReadyCallback)close_ready_cb,
- fixture);
- /* FIXME: We should completely stop caching the
- resource at this point */
- } else {
- /* Are we still writing and is there new data to write
- already ? */
- if (fixture->buffer_queue->length > 0)
- write_next_buffer (entry, fixture);
- else {
- g_clear_pointer (&fixture->current_writing_buffer, soup_buffer_free);
-
- if (fixture->got_body) {
- /* If we already received 'got-body'
- and we have written all the data,
- we can close the stream */
- g_output_stream_close_async (fixture->ostream,
- G_PRIORITY_LOW,
- entry->cancellable,
- (GAsyncReadyCallback)close_ready_cb,
- fixture);
- }
- }
- }
-}
-
-static gboolean
-write_next_buffer (SoupCacheEntry *entry, SoupCacheWritingFixture *fixture)
-{
- SoupBuffer *buffer = g_queue_pop_head (fixture->buffer_queue);
-
- if (buffer == NULL)
- return FALSE;
-
- /* Free the old buffer */
- g_clear_pointer (&fixture->current_writing_buffer, soup_buffer_free);
- fixture->current_writing_buffer = buffer;
-
- g_output_stream_write_async (fixture->ostream, buffer->data, buffer->length,
- G_PRIORITY_LOW, entry->cancellable,
- (GAsyncReadyCallback) write_ready_cb,
- fixture);
- return TRUE;
-}
-
-static void
-msg_got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, SoupCacheWritingFixture *fixture)
-{
- SoupCacheEntry *entry = fixture->entry;
-
- /* Ignore this if the writing or appending was cancelled */
- if (!g_cancellable_is_cancelled (entry->cancellable)) {
- g_queue_push_tail (fixture->buffer_queue, soup_buffer_copy (chunk));
- entry->length += chunk->length;
-
- if (!cache_accepts_entries_of_size (fixture->cache, entry->length)) {
- /* Quickly cancel the caching of the resource */
- g_cancellable_cancel (entry->cancellable);
- }
- }
-
- /* FIXME: remove the error check when we cancel the caching at
- the first write error */
- /* Only write if the entry stream is ready */
- if (fixture->current_writing_buffer == NULL && fixture->error == NULL && fixture->ostream)
- write_next_buffer (entry, fixture);
-}
-
-static void
-msg_got_body_cb (SoupMessage *msg, SoupCacheWritingFixture *fixture)
-{
- SoupCacheEntry *entry = fixture->entry;
- g_return_if_fail (entry);
-
- fixture->got_body = TRUE;
-
- if (!fixture->ostream && fixture->buffer_queue->length > 0)
- /* The stream is not ready to be written but we still
- have data to write, we'll write it when the stream
- is opened for writing */
- return;
-
-
- if (fixture->buffer_queue->length > 0) {
- /* If we still have data to write, write it,
- write_ready_cb will close the stream */
- if (fixture->current_writing_buffer == NULL && fixture->error == NULL && fixture->ostream)
- write_next_buffer (entry, fixture);
- return;
- }
-
- if (fixture->ostream && fixture->current_writing_buffer == NULL)
- g_output_stream_close_async (fixture->ostream,
- G_PRIORITY_LOW,
- entry->cancellable,
- (GAsyncReadyCallback)close_ready_cb,
- fixture);
-}
-
static gboolean
soup_cache_entry_remove (SoupCache *cache, SoupCacheEntry *entry, gboolean purge)
{
GList *lru_item;
- /* if (entry->dirty && !g_cancellable_is_cancelled (entry->cancellable)) { */
if (entry->dirty) {
g_cancellable_cancel (entry->cancellable);
return FALSE;
@@ -819,7 +591,7 @@ soup_cache_entry_insert (SoupCache *cache,
/* Fill the key */
entry->key = get_cache_key_from_uri ((const char *) entry->uri);
- if (soup_message_headers_get_encoding (entry->headers) != SOUP_ENCODING_CHUNKED)
+ if (soup_message_headers_get_encoding (entry->headers) == SOUP_ENCODING_CONTENT_LENGTH)
length_to_add = soup_message_headers_get_content_length (entry->headers);
/* Check if we are going to store the resource depending on its size */
@@ -874,151 +646,12 @@ soup_cache_entry_lookup (SoupCache *cache,
return entry;
}
-static void
-msg_restarted_cb (SoupMessage *msg, SoupCacheEntry *entry)
-{
- /* FIXME: What should we do here exactly? */
-}
-
-static void
-replace_cb (GObject *source, GAsyncResult *result, SoupCacheWritingFixture *fixture)
-{
- SoupCacheEntry *entry = fixture->entry;
- GOutputStream *ostream = (GOutputStream *) g_file_replace_finish (G_FILE (source),
- result, &fixture->error);
-
- if (g_cancellable_is_cancelled (entry->cancellable) || fixture->error) {
- g_clear_object (&ostream);
- fixture->cache->priv->n_pending--;
- entry->dirty = FALSE;
- soup_cache_entry_remove (fixture->cache, entry, TRUE);
- soup_cache_writing_fixture_free (fixture);
- return;
- }
-
- fixture->ostream = ostream;
-
- /* If we already got all the data we have to initiate the
- * writing here, since we won't get more 'got-chunk'
- * signals
- */
- if (!fixture->got_body)
- return;
-
- /* It could happen that reading the data from server
- * was completed before this happens. In that case
- * there is no data
- */
- if (!write_next_buffer (entry, fixture))
- /* Could happen if the resource is empty */
- g_output_stream_close_async (ostream, G_PRIORITY_LOW, entry->cancellable,
- (GAsyncReadyCallback) close_ready_cb,
- fixture);
-}
-
-typedef struct {
- time_t request_time;
- SoupSessionFeature *feature;
- gulong got_headers_handler;
-} RequestHelper;
-
-static void
-msg_got_headers_cb (SoupMessage *msg, gpointer user_data)
-{
- SoupCache *cache;
- SoupCacheability cacheable;
- RequestHelper *helper;
- time_t request_time, response_time;
- SoupCacheEntry *entry;
-
- response_time = time (NULL);
-
- helper = (RequestHelper *)user_data;
- cache = SOUP_CACHE (helper->feature);
- request_time = helper->request_time;
- g_signal_handlers_disconnect_by_func (msg, msg_got_headers_cb, user_data);
- g_slice_free (RequestHelper, helper);
-
- cacheable = soup_cache_get_cacheability (cache, msg);
-
- if (cacheable & SOUP_CACHE_CACHEABLE) {
- GFile *file;
- SoupCacheWritingFixture *fixture;
-
- /* Check if we are already caching this resource */
- entry = soup_cache_entry_lookup (cache, msg);
-
- if (entry && (entry->dirty || entry->being_validated))
- return;
-
- /* Create a new entry, deleting any old one if present */
- if (entry)
- soup_cache_entry_remove (cache, entry, TRUE);
-
- entry = soup_cache_entry_new (cache, msg, request_time, response_time);
- entry->hits = 1;
-
- /* Do not continue if it can not be stored */
- if (!soup_cache_entry_insert (cache, entry, TRUE)) {
- soup_cache_entry_free (entry);
- return;
- }
-
- fixture = g_slice_new0 (SoupCacheWritingFixture);
- fixture->cache = g_object_ref (cache);
- fixture->entry = entry;
- fixture->msg = g_object_ref (msg);
- fixture->buffer_queue = g_queue_new ();
-
- /* We connect now to these signals and buffer the data
- if it comes before the file is ready for writing */
- fixture->content_sniffed_handler =
- g_signal_connect (msg, "content-sniffed", G_CALLBACK (msg_content_sniffed_cb), fixture);
- fixture->got_chunk_handler =
- g_signal_connect (msg, "got-chunk", G_CALLBACK (msg_got_chunk_cb), fixture);
- fixture->got_body_handler =
- g_signal_connect (msg, "got-body", G_CALLBACK (msg_got_body_cb), fixture);
- fixture->restarted_handler =
- g_signal_connect (msg, "restarted", G_CALLBACK (msg_restarted_cb), entry);
-
- /* Prepare entry */
- cache->priv->n_pending++;
-
- entry->dirty = TRUE;
- entry->cancellable = g_cancellable_new ();
- file = get_file_from_entry (cache, entry);
- g_file_replace_async (file, NULL, FALSE,
- G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION,
- G_PRIORITY_LOW, entry->cancellable,
- (GAsyncReadyCallback) replace_cb, fixture);
- g_object_unref (file);
- } else if (cacheable & SOUP_CACHE_INVALIDATES) {
- entry = soup_cache_entry_lookup (cache, msg);
-
- if (entry)
- soup_cache_entry_remove (cache, entry, TRUE);
- } else if (cacheable & SOUP_CACHE_VALIDATES) {
- entry = soup_cache_entry_lookup (cache, msg);
-
- /* It's possible to get a CACHE_VALIDATES with no
- * entry in the hash table. This could happen if for
- * example the soup client is the one creating the
- * conditional request.
- */
- if (entry) {
- entry->being_validated = FALSE;
- copy_end_to_end_headers (msg->response_headers, entry->headers);
- soup_cache_entry_set_freshness (entry, msg, cache);
- }
- }
-}
-
GInputStream *
soup_cache_send_response (SoupCache *cache, SoupMessage *msg)
{
SoupCacheEntry *entry;
char *current_age;
- GInputStream *stream = NULL;
+ GInputStream *file_stream, *body_stream, *cache_stream;
GFile *file;
g_return_val_if_fail (SOUP_IS_CACHE (cache), NULL);
@@ -1027,18 +660,19 @@ soup_cache_send_response (SoupCache *cache, SoupMessage *msg)
entry = soup_cache_entry_lookup (cache, msg);
g_return_val_if_fail (entry, NULL);
- /* TODO: the original idea was to save reads, but current code
- assumes that a stream is always returned. Need to reach
- some agreement here. Also we have to handle the situation
- were the file was no longer there (for example files
- removed without notifying the cache */
file = get_file_from_entry (cache, entry);
- stream = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
+ file_stream = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
g_object_unref (file);
/* Do not change the original message if there is no resource */
- if (stream == NULL)
- return stream;
+ if (!file_stream)
+ return NULL;
+
+ body_stream = soup_body_input_stream_new (file_stream, SOUP_ENCODING_CONTENT_LENGTH, entry->length);
+ g_object_unref (file_stream);
+
+ if (!body_stream)
+ return NULL;
/* If we are told to send a response from cache any validation
in course is over by now */
@@ -1057,19 +691,29 @@ soup_cache_send_response (SoupCache *cache, SoupMessage *msg)
current_age);
g_free (current_age);
- return stream;
+ /* Create the cache stream. */
+ soup_message_disable_feature (msg, SOUP_TYPE_CACHE);
+ cache_stream = soup_message_setup_body_istream (body_stream, msg,
+ cache->priv->session,
+ SOUP_STAGE_ENTITY_BODY);
+ g_object_unref (body_stream);
+
+ return cache_stream;
+}
+
+static void
+msg_got_headers_cb (SoupMessage *msg, gpointer user_data)
+{
+ g_object_set_data (G_OBJECT (msg), "response-time", GINT_TO_POINTER (time (NULL)));
+ g_signal_handlers_disconnect_by_func (msg, msg_got_headers_cb, user_data);
}
static void
request_started (SoupSessionFeature *feature, SoupSession *session,
SoupMessage *msg, SoupSocket *socket)
{
- RequestHelper *helper = g_slice_new0 (RequestHelper);
- helper->request_time = time (NULL);
- helper->feature = feature;
- helper->got_headers_handler = g_signal_connect (msg, "got-headers",
- G_CALLBACK (msg_got_headers_cb),
- helper);
+ g_object_set_data (G_OBJECT (msg), "request-time", GINT_TO_POINTER (time (NULL)));
+ g_signal_connect (msg, "got-headers", G_CALLBACK (msg_got_headers_cb), NULL);
}
static void
@@ -1092,6 +736,145 @@ soup_cache_session_feature_init (SoupSessionFeatureInterface *feature_interface,
feature_interface->request_started = request_started;
}
+typedef struct {
+ SoupCache *cache;
+ SoupCacheEntry *entry;
+} StreamHelper;
+
+static void
+istream_cache_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ SoupCacheInputStream *istream = SOUP_CACHE_INPUT_STREAM (source);
+ StreamHelper *helper = (StreamHelper *) user_data;
+ SoupCache *cache = helper->cache;
+ SoupCacheEntry *entry = helper->entry;
+ GError *error = NULL;
+
+ entry->dirty = FALSE;
+ g_clear_object (&entry->cancellable);
+ --cache->priv->n_pending;
+
+ entry->length = soup_cache_input_stream_cache_finish (istream, res, &error);
+
+ if (error) {
+ /* Update cache size */
+ if (soup_message_headers_get_encoding (entry->headers) == SOUP_ENCODING_CONTENT_LENGTH)
+ cache->priv->size -= soup_message_headers_get_content_length (entry->headers);
+
+ soup_cache_entry_remove (cache, entry, TRUE);
+ helper->entry = entry = NULL;
+ goto cleanup;
+ }
+
+ if (soup_message_headers_get_encoding (entry->headers) != SOUP_ENCODING_CONTENT_LENGTH) {
+
+ if (cache_accepts_entries_of_size (cache, entry->length)) {
+ make_room_for_new_entry (cache, entry->length);
+ cache->priv->size += entry->length;
+ } else {
+ soup_cache_entry_remove (cache, entry, TRUE);
+ helper->entry = entry = NULL;
+ }
+ }
+
+ cleanup:
+ g_object_unref (helper->cache);
+ g_slice_free (StreamHelper, helper);
+}
+
+
+static GInputStream*
+soup_cache_content_processor_wrap_input (SoupContentProcessor *processor,
+ GInputStream *base_stream,
+ SoupMessage *msg,
+ GError **error)
+{
+ SoupCache *cache = (SoupCache*) processor;
+ SoupCacheEntry *entry;
+ SoupCacheability cacheability;
+ GInputStream *istream;
+ GFile *file;
+ StreamHelper *helper;
+ time_t request_time, response_time;
+
+ /* First of all, check if we should cache the resource. */
+ cacheability = soup_cache_get_cacheability (cache, msg);
+ entry = soup_cache_entry_lookup (cache, msg);
+
+ if (cacheability & SOUP_CACHE_INVALIDATES) {
+ if (entry)
+ soup_cache_entry_remove (cache, entry, TRUE);
+ return NULL;
+ }
+
+ if (cacheability & SOUP_CACHE_VALIDATES) {
+ /* It's possible to get a CACHE_VALIDATES with no
+ * entry in the hash table. This could happen if for
+ * example the soup client is the one creating the
+ * conditional request.
+ */
+ if (entry) {
+ entry->being_validated = FALSE;
+ copy_end_to_end_headers (msg->response_headers, entry->headers);
+ soup_cache_entry_set_freshness (entry, msg, cache);
+ }
+ return NULL;
+ }
+
+ if (!(cacheability & SOUP_CACHE_CACHEABLE))
+ return NULL;
+
+ /* Check if we are already caching this resource */
+ if (entry && (entry->dirty || entry->being_validated))
+ return NULL;
+
+ /* Create a new entry, deleting any old one if present */
+ if (entry)
+ soup_cache_entry_remove (cache, entry, TRUE);
+
+ request_time = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (msg), "request-time"));
+ response_time = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (msg), "request-time"));
+ entry = soup_cache_entry_new (cache, msg, request_time, response_time);
+ entry->hits = 1;
+ entry->dirty = TRUE;
+
+ /* Do not continue if it can not be stored */
+ if (!soup_cache_entry_insert (cache, entry, TRUE)) {
+ soup_cache_entry_free (entry);
+ return NULL;
+ }
+
+ ++cache->priv->n_pending;
+
+ istream = soup_cache_input_stream_new (base_stream);
+
+ file = get_file_from_entry (cache, entry);
+ entry->cancellable = g_cancellable_new ();
+
+ helper = g_slice_new (StreamHelper);
+ helper->cache = g_object_ref (cache);
+ helper->entry = entry;
+
+ soup_cache_input_stream_cache (SOUP_CACHE_INPUT_STREAM (istream), file, entry->cancellable,
+ (GAsyncReadyCallback) istream_cache_cb, helper);
+ g_object_unref (file);
+
+ return istream;
+}
+
+static void
+soup_cache_content_processor_init (SoupContentProcessorInterface *processor_interface,
+ gpointer interface_data)
+{
+ soup_cache_default_content_processor_interface =
+ g_type_default_interface_peek (SOUP_TYPE_CONTENT_PROCESSOR);
+
+ processor_interface->processing_stage = SOUP_STAGE_ENTITY_BODY;
+ processor_interface->wrap_input = soup_cache_content_processor_wrap_input;
+}
+
static void
soup_cache_init (SoupCache *cache)
{
@@ -1565,6 +1348,7 @@ soup_cache_generate_conditional_request (SoupCache *cache, SoupMessage *original
/* Copy the data we need from the original message */
uri = soup_message_get_uri (original);
msg = soup_message_new_from_uri (original->method, uri);
+ soup_message_disable_feature (msg, SOUP_TYPE_CACHE);
soup_message_headers_foreach (original->request_headers,
(SoupMessageHeadersForeachFunc)copy_headers,
diff --git a/libsoup/soup-client-input-stream.c b/libsoup/soup-client-input-stream.c
index ddcabaa..78bc15f 100644
--- a/libsoup/soup-client-input-stream.c
+++ b/libsoup/soup-client-input-stream.c
@@ -88,17 +88,6 @@ soup_client_input_stream_get_property (GObject *object, guint prop_id,
}
}
-/* Temporary HACK to keep SoupCache working. See soup_client_input_stream_read_fn()
- * and soup_client_input_stream_read_nonblocking().
- */
-static void
-soup_client_input_stream_emit_got_chunk (SoupClientInputStream *stream, void *data, gssize nread)
-{
- SoupBuffer *buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY, data, nread);
- soup_message_got_chunk (stream->priv->msg, buffer);
- soup_buffer_free (buffer);
-}
-
static gssize
soup_client_input_stream_read_fn (GInputStream *stream,
void *buffer,
@@ -114,12 +103,6 @@ soup_client_input_stream_read_fn (GInputStream *stream,
if (nread == 0)
g_signal_emit (stream, signals[EOF], 0);
- /* Temporary HACK to keep SoupCache working */
- if (nread > 0) {
- soup_client_input_stream_emit_got_chunk (SOUP_CLIENT_INPUT_STREAM (stream),
- buffer, nread);
- }
-
return nread;
}
@@ -137,12 +120,6 @@ soup_client_input_stream_read_nonblocking (GPollableInputStream *stream,
if (nread == 0)
g_signal_emit (stream, signals[EOF], 0);
- /* Temporary HACK to keep SoupCache working */
- if (nread > 0) {
- soup_client_input_stream_emit_got_chunk (SOUP_CLIENT_INPUT_STREAM (stream),
- buffer, nread);
- }
-
return nread;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]