[libgdata] core: Return G_IO_ERROR_CLOSED if stream close methods are called again
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata] core: Return G_IO_ERROR_CLOSED if stream close methods are called again
- Date: Mon, 20 Dec 2010 13:50:19 +0000 (UTC)
commit 063845eaabfdf0703914c3d59b63a7945250ce4d
Author: Philip Withnall <philip tecnocode co uk>
Date: Mon Dec 20 10:09:21 2010 +0000
core: Return G_IO_ERROR_CLOSED if stream close methods are called again
While g_[input|output]_stream_close() prevents the close method implementation
from being called multiple times, other methods in GIO (such as
g_output_stream_splice()) call the close method implementation directly, so
gdata_[upload|download]_stream_close() need to be safe to call multiple
times.
gdata/gdata-download-stream.c | 16 +++++++++++++---
gdata/gdata-upload-stream.c | 16 +++++++++++++---
2 files changed, 26 insertions(+), 6 deletions(-)
---
diff --git a/gdata/gdata-download-stream.c b/gdata/gdata-download-stream.c
index ce11a5f..493eefe 100644
--- a/gdata/gdata-download-stream.c
+++ b/gdata/gdata-download-stream.c
@@ -39,6 +39,7 @@
#include <config.h>
#include <glib.h>
+#include <glib/gi18n-lib.h>
#include "gdata-download-stream.h"
#include "gdata-buffer.h"
@@ -476,9 +477,9 @@ close_cancelled_cb (GCancellable *cancellable, CancelledData *data)
g_static_mutex_unlock (&(priv->finished_mutex));
}
-/* If g_input_stream_close() has already been called once on this stream, g_input_stream_is_closed() is set to %TRUE, and all future calls to
- * g_input_stream_close() will immediately return, i.e. gdata_download_stream_close() is guaranteed to only ever run once (even if the first call was
- * cancelled or returned an error).
+/* Even though calling g_input_stream_close() multiple times on this stream is guaranteed to call gdata_download_stream_close() at most once, other
+ * GIO methods (notably g_output_stream_splice()) can call gdata_download_stream_close() directly. Consequently, we need to be careful to be idempotent
+ * after the first call.
*
* If the network thread hasn't yet been started (i.e. gdata_download_stream_read() hasn't been called at all yet), %TRUE will be returned immediately.
*
@@ -503,6 +504,15 @@ gdata_download_stream_close (GInputStream *stream, GCancellable *cancellable, GE
if (priv->network_thread == NULL)
return TRUE;
+ /* If we've already closed the stream, return G_IO_ERROR_CLOSED */
+ g_static_mutex_lock (&(priv->finished_mutex));
+ if (priv->finished == FALSE) {
+ g_static_mutex_unlock (&(priv->finished_mutex));
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, _("Stream is already closed"));
+ return FALSE;
+ }
+ g_static_mutex_unlock (&(priv->finished_mutex));
+
/* Allow cancellation */
data.download_stream = GDATA_DOWNLOAD_STREAM (stream);
data.cancelled = &cancelled;
diff --git a/gdata/gdata-upload-stream.c b/gdata/gdata-upload-stream.c
index 6405349..8f40c0b 100644
--- a/gdata/gdata-upload-stream.c
+++ b/gdata/gdata-upload-stream.c
@@ -59,6 +59,7 @@
#include <config.h>
#include <glib.h>
+#include <glib/gi18n-lib.h>
#include <string.h>
#include "gdata-upload-stream.h"
@@ -614,9 +615,9 @@ close_cancelled_cb (GCancellable *cancellable, CancelledData *data)
/* It's guaranteed that we have set ->response_status and ->response_error and are done with *all* network activity before this returns, unless it's
* cancelled. This means that it's safe to call gdata_upload_stream_get_response() once a call to close() has returned without being cancelled.
*
- * If g_output_stream_close() has already been called once on this stream, g_output_stream_is_closed() is set to %TRUE, and all future calls to
- * g_output_stream_close() will immediately return, i.e. gdata_upload_stream_close() is guaranteed to only ever run once (even if the first call was
- * cancelled or returned an error).
+ * Even though calling g_output_stream_close() multiple times on this stream is guaranteed to call gdata_upload_stream_close() at most once, other
+ * GIO methods (notably g_output_stream_splice()) can call gdata_upload_stream_close() directly. Consequently, we need to be careful to be idempotent
+ * after the first call.
*
* If the network thread hasn't yet been started (i.e. gdata_upload_stream_write() hasn't been called at all yet), %TRUE will be returned immediately.
*
@@ -642,6 +643,15 @@ gdata_upload_stream_close (GOutputStream *stream, GCancellable *cancellable, GEr
if (priv->network_thread == NULL)
return TRUE;
+ /* If we've already closed the stream, return G_IO_ERROR_CLOSED */
+ g_static_mutex_lock (&(priv->response_mutex));
+ if (priv->response_status != SOUP_STATUS_NONE) {
+ g_static_mutex_unlock (&(priv->response_mutex));
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, _("Stream is already closed"));
+ return FALSE;
+ }
+ g_static_mutex_unlock (&(priv->response_mutex));
+
/* Allow cancellation */
data.upload_stream = GDATA_UPLOAD_STREAM (stream);
data.cancelled = &cancelled;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]