summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2011-10-22 17:59:07 -0400
committerDan Winship <danw@gnome.org>2011-12-01 11:35:48 +0100
commit7f938c2334fbc55d7041a86bbf9ee9169d3c4c53 (patch)
tree31d0634026200739726405d4017ded3816263bcc
parent3b11e881fcf4cb7026604aac9d93b6497e48d0ed (diff)
downloadlibsoup-7f938c2334fbc55d7041a86bbf9ee9169d3c4c53.tar.gz
SoupRequestHTTP: don't complete send() until after sniffing
If the session has a SoupContentSniffer (and it's not disabled for this message), wait until content-sniffed is emitted before completing send()/send_async(). Remove the faked content-sniffed emissions from the cache codepaths, since they should no longer be needed. https://bugzilla.gnome.org/show_bug.cgi?id=663451
-rw-r--r--libsoup/soup-http-input-stream.c72
-rw-r--r--libsoup/soup-http-input-stream.h2
-rw-r--r--libsoup/soup-request-http.c23
3 files changed, 73 insertions, 24 deletions
diff --git a/libsoup/soup-http-input-stream.c b/libsoup/soup-http-input-stream.c
index 43c30a9c..45f181c9 100644
--- a/libsoup/soup-http-input-stream.c
+++ b/libsoup/soup-http-input-stream.c
@@ -27,6 +27,8 @@
#include <gio/gio.h>
#include "soup-http-input-stream.h"
+#include "soup-headers.h"
+#include "soup-content-sniffer.h"
#include "soup-session.h"
G_DEFINE_TYPE (SoupHTTPInputStream, soup_http_input_stream, G_TYPE_INPUT_STREAM)
@@ -53,6 +55,8 @@ typedef struct {
gsize caller_bufsize, caller_nread;
GAsyncReadyCallback outstanding_callback;
GSimpleAsyncResult *result;
+
+ char *sniffed_content_type;
} SoupHTTPInputStreamPrivate;
#define SOUP_HTTP_INPUT_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_HTTP_INPUT_STREAM, SoupHTTPInputStreamPrivate))
@@ -85,6 +89,7 @@ static gboolean soup_http_input_stream_close_finish (GInputStream *strea
GError **error);
static void soup_http_input_stream_got_headers (SoupMessage *msg, gpointer stream);
+static void soup_http_input_stream_content_sniffed (SoupMessage *msg, const char *content_type, GHashTable *params, gpointer stream);
static void soup_http_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer stream);
static void soup_http_input_stream_restarted (SoupMessage *msg, gpointer stream);
static void soup_http_input_stream_finished (SoupMessage *msg, gpointer stream);
@@ -98,6 +103,7 @@ soup_http_input_stream_finalize (GObject *object)
g_object_unref (priv->session);
g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_http_input_stream_got_headers), stream);
+ g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_http_input_stream_content_sniffed), stream);
g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_http_input_stream_got_chunk), stream);
g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_http_input_stream_restarted), stream);
g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_http_input_stream_finished), stream);
@@ -106,6 +112,8 @@ soup_http_input_stream_finalize (GObject *object)
g_queue_foreach (priv->leftover_queue, (GFunc) soup_buffer_free, NULL);
g_queue_free (priv->leftover_queue);
+ g_free (priv->sniffed_content_type);
+
if (G_OBJECT_CLASS (soup_http_input_stream_parent_class)->finalize)
(*G_OBJECT_CLASS (soup_http_input_stream_parent_class)->finalize)(object);
}
@@ -143,6 +151,20 @@ soup_http_input_stream_queue_message (SoupHTTPInputStream *stream)
priv->got_headers = priv->finished = FALSE;
+ if (soup_session_get_feature_for_message (priv->session, SOUP_TYPE_CONTENT_SNIFFER, priv->msg)) {
+ g_signal_connect (priv->msg, "content_sniffed",
+ G_CALLBACK (soup_http_input_stream_content_sniffed), stream);
+ } else {
+ g_signal_connect (priv->msg, "got_headers",
+ G_CALLBACK (soup_http_input_stream_got_headers), stream);
+ }
+ g_signal_connect (priv->msg, "got_chunk",
+ G_CALLBACK (soup_http_input_stream_got_chunk), stream);
+ g_signal_connect (priv->msg, "restarted",
+ G_CALLBACK (soup_http_input_stream_restarted), stream);
+ g_signal_connect (priv->msg, "finished",
+ G_CALLBACK (soup_http_input_stream_finished), stream);
+
/* Add an extra ref since soup_session_queue_message steals one */
g_object_ref (priv->msg);
soup_session_queue_message (priv->session, priv->msg, NULL, NULL);
@@ -189,16 +211,6 @@ soup_http_input_stream_new (SoupSession *session, SoupMessage *msg)
priv->async_context = soup_session_get_async_context (session);
priv->msg = g_object_ref (msg);
- g_signal_connect (msg, "got_headers",
- G_CALLBACK (soup_http_input_stream_got_headers), stream);
- g_signal_connect (msg, "got_chunk",
- G_CALLBACK (soup_http_input_stream_got_chunk), stream);
- g_signal_connect (msg, "restarted",
- G_CALLBACK (soup_http_input_stream_restarted), stream);
- g_signal_connect (msg, "finished",
- G_CALLBACK (soup_http_input_stream_finished), stream);
-
- soup_http_input_stream_queue_message (stream);
return (GInputStream *)stream;
}
@@ -227,6 +239,30 @@ soup_http_input_stream_got_headers (SoupMessage *msg, gpointer stream)
}
static void
+soup_http_input_stream_content_sniffed (SoupMessage *msg, const char *content_type,
+ GHashTable *params, gpointer stream)
+{
+ SoupHTTPInputStreamPrivate *priv = SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GString *sniffed_type;
+
+ sniffed_type = g_string_new (content_type);
+ if (params) {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, params);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ g_string_append (sniffed_type, "; ");
+ soup_header_g_string_append_param (sniffed_type, key, value);
+ }
+ }
+ g_free (priv->sniffed_content_type);
+ priv->sniffed_content_type = g_string_free (sniffed_type, FALSE);
+
+ soup_http_input_stream_got_headers (msg, stream);
+}
+
+static void
soup_http_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk_buffer,
gpointer stream)
{
@@ -439,6 +475,8 @@ soup_http_input_stream_send (SoupHTTPInputStream *httpstream,
g_return_val_if_fail (SOUP_IS_HTTP_INPUT_STREAM (httpstream), FALSE);
+ soup_http_input_stream_queue_message (httpstream);
+
if (!g_input_stream_set_pending (istream, error))
return FALSE;
@@ -586,6 +624,8 @@ soup_http_input_stream_send_async (SoupHTTPInputStream *httpstream,
g_return_if_fail (SOUP_IS_HTTP_INPUT_STREAM (httpstream));
+ soup_http_input_stream_queue_message (httpstream);
+
if (!g_input_stream_set_pending (istream, &error)) {
g_simple_async_report_take_gerror_in_idle (G_OBJECT (httpstream),
callback,
@@ -745,3 +785,15 @@ soup_http_input_stream_get_message (SoupHTTPInputStream *httpstream)
SoupHTTPInputStreamPrivate *priv = SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (httpstream);
return priv->msg ? g_object_ref (priv->msg) : NULL;
}
+
+const char *
+soup_http_input_stream_get_content_type (SoupHTTPInputStream *httpstream)
+{
+ SoupHTTPInputStreamPrivate *priv = SOUP_HTTP_INPUT_STREAM_GET_PRIVATE (httpstream);
+
+ if (priv->sniffed_content_type)
+ return priv->sniffed_content_type;
+ else
+ return soup_message_headers_get_content_type (priv->msg->response_headers, NULL);
+
+}
diff --git a/libsoup/soup-http-input-stream.h b/libsoup/soup-http-input-stream.h
index 940d0a1b..b6c598cb 100644
--- a/libsoup/soup-http-input-stream.h
+++ b/libsoup/soup-http-input-stream.h
@@ -72,6 +72,8 @@ gboolean soup_http_input_stream_send_finish (SoupHTTPInputStream *httpstre
SoupMessage *soup_http_input_stream_get_message (SoupHTTPInputStream *httpstream);
+const char *soup_http_input_stream_get_content_type (SoupHTTPInputStream *httpstream);
+
G_END_DECLS
#endif /* __SOUP_HTTP_INPUT_STREAM_H__ */
diff --git a/libsoup/soup-request-http.c b/libsoup/soup-request-http.c
index b58f970a..d4a2c201 100644
--- a/libsoup/soup-request-http.c
+++ b/libsoup/soup-request-http.c
@@ -32,7 +32,6 @@
#include "soup-request-http.h"
#include "soup-cache.h"
#include "soup-cache-private.h"
-#include "soup-content-sniffer.h"
#include "soup-http-input-stream.h"
#include "soup-message.h"
#include "soup-session.h"
@@ -42,6 +41,7 @@ G_DEFINE_TYPE (SoupRequestHTTP, soup_request_http, SOUP_TYPE_REQUEST)
struct _SoupRequestHTTPPrivate {
SoupMessage *msg;
+ char *content_type;
};
static void
@@ -89,6 +89,7 @@ soup_request_http_send (SoupRequest *request,
g_object_unref (httpstream);
return NULL;
}
+ http->priv->content_type = g_strdup (soup_http_input_stream_get_content_type (SOUP_HTTP_INPUT_STREAM (httpstream)));
return httpstream;
}
@@ -126,6 +127,7 @@ http_input_stream_ready_cb (GObject *source, GAsyncResult *result, gpointer user
GError *error = NULL;
if (soup_http_input_stream_send_finish (httpstream, result, &error)) {
+ sadata->http->priv->content_type = g_strdup (soup_http_input_stream_get_content_type (httpstream));
g_simple_async_result_set_op_res_gpointer (sadata->simple, httpstream, g_object_unref);
} else {
g_simple_async_result_take_error (sadata->simple, error);
@@ -151,11 +153,10 @@ conditional_get_ready_cb (SoupSession *session, SoupMessage *msg, gpointer user_
soup_message_got_headers (sadata->original);
- if (soup_session_get_feature_for_message (session, SOUP_TYPE_CONTENT_SNIFFER, sadata->original)) {
- const char *content_type =
- soup_message_headers_get_content_type (sadata->original->response_headers, NULL);
- soup_message_content_sniffed (sadata->original, content_type, NULL);
- }
+ /* FIXME: this is wrong; the cache won't have
+ * the sniffed type.
+ */
+ sadata->http->priv->content_type = g_strdup (soup_message_headers_get_content_type (sadata->original->response_headers, NULL));
g_simple_async_result_complete (sadata->simple);
@@ -177,9 +178,6 @@ static gboolean
idle_return_from_cache_cb (gpointer data)
{
SendAsyncData *sadata = data;
- SoupSession *session;
-
- session = soup_request_get_session (SOUP_REQUEST (sadata->http));
g_simple_async_result_set_op_res_gpointer (sadata->simple,
g_object_ref (sadata->stream), g_object_unref);
@@ -187,10 +185,7 @@ idle_return_from_cache_cb (gpointer data)
/* Issue signals */
soup_message_got_headers (sadata->http->priv->msg);
- if (soup_session_get_feature_for_message (session, SOUP_TYPE_CONTENT_SNIFFER, sadata->http->priv->msg)) {
- const char *content_type = soup_message_headers_get_content_type (sadata->http->priv->msg->response_headers, NULL);
- soup_message_content_sniffed (sadata->http->priv->msg, content_type, NULL);
- }
+ sadata->http->priv->content_type = g_strdup (soup_message_headers_get_content_type (sadata->http->priv->msg->response_headers, NULL));
g_simple_async_result_complete (sadata->simple);
@@ -288,7 +283,7 @@ soup_request_http_get_content_type (SoupRequest *request)
{
SoupRequestHTTP *http = SOUP_REQUEST_HTTP (request);
- return soup_message_headers_get_content_type (http->priv->msg->response_headers, NULL);
+ return http->priv->content_type;
}
static const char *http_schemes[] = { "http", "https", NULL };