[libgdata] [core] Fix premature termination of request body on buffer underflow
- From: Philip Withnall <pwithnall src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libgdata] [core] Fix premature termination of request body on buffer underflow
- Date: Wed, 5 Aug 2009 21:55:27 +0000 (UTC)
commit ef78512a717eb47533ff45c0f6222cef0691fbe3
Author: Philip Withnall <philip tecnocode co uk>
Date: Wed Aug 5 22:53:31 2009 +0100
[core] Fix premature termination of request body on buffer underflow
EOF and buffer underflow returns from gdata_buffer_pop_data() were getting
confused and, if data wasn't pushed to a GDataUploadStream fast enough, would
result in premature termination of the request body.
gdata/gdata-buffer.c | 23 ++++++++++++++++++-----
gdata/gdata-buffer.h | 4 ++--
gdata/gdata-download-stream.c | 2 +-
gdata/gdata-upload-stream.c | 8 ++++----
4 files changed, 25 insertions(+), 12 deletions(-)
---
diff --git a/gdata/gdata-buffer.c b/gdata/gdata-buffer.c
index 8bb1e2f..3da67b4 100644
--- a/gdata/gdata-buffer.c
+++ b/gdata/gdata-buffer.c
@@ -167,6 +167,7 @@ pop_cancelled_cb (GCancellable *cancellable, CancelledData *data)
* @self: a #GDataBuffer
* @data: return location for the popped data
* @length_requested: the number of bytes of data requested
+ * @reached_eof: return location for a value which is %TRUE when we've reached EOF, %FALSE otherwise, or %NULL
* @cancellable: a #GCancellable, or %NULL
*
* Pops up to @length_requested bytes off the head of the buffer and copies them to @data, which must be allocated by
@@ -188,7 +189,7 @@ pop_cancelled_cb (GCancellable *cancellable, CancelledData *data)
* Since: 0.5.0
**/
gsize
-gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested, GCancellable *cancellable)
+gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested, gboolean *reached_eof, GCancellable *cancellable)
{
GDataBufferChunk *chunk;
gsize return_length = 0, length_remaining;
@@ -204,6 +205,10 @@ gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested,
g_static_mutex_lock (&(self->mutex));
+ /* Set reached_eof */
+ if (reached_eof != NULL)
+ *reached_eof = self->reached_eof;
+
if (self->reached_eof == TRUE && length_requested > self->total_length) {
/* Return data up to the EOF */
return_length = self->total_length;
@@ -294,18 +299,26 @@ gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested,
* gdata_buffer_pop_all_data:
* @self: a #GDataBuffer
* @data: return location for the popped data
+ * @maximum_length: the maximum number of bytes to return
+ * @reached_eof: return location for a value which is %TRUE when we've reached EOF, %FALSE otherwise, or %NULL
*
* Pops as much data as possible off the #GDataBuffer, up to a limit of @maxium_length bytes. If fewer bytes exist
* in the buffer, fewer bytes will be returned. If more bytes exist in the buffer, @maximum_length bytes will be returned.
*
- * This function will never block.
+ * If %0 bytes exist in the buffer, this function will block until data is available. Otherwise, it will never block.
*
- * Return value: the number of bytes returned in @data
+ * Return value: the number of bytes returned in @data (guaranteed to be more than %0 and at most @maximum_length)
*
* Since: 0.5.0
**/
gsize
-gdata_buffer_pop_data_limited (GDataBuffer *self, guint8 *data, gsize maximum_length)
+gdata_buffer_pop_data_limited (GDataBuffer *self, guint8 *data, gsize maximum_length, gboolean *reached_eof)
{
- return gdata_buffer_pop_data (self, data, MIN (maximum_length, self->total_length), NULL);
+ /* If there's no data in the buffer, block until some is available */
+ g_static_mutex_lock (&(self->mutex));
+ if (self->total_length == 0 && self->reached_eof == FALSE)
+ g_cond_wait (self->cond, g_static_mutex_get_mutex (&(self->mutex)));
+ g_static_mutex_unlock (&(self->mutex));
+
+ return gdata_buffer_pop_data (self, data, MIN (maximum_length, self->total_length), reached_eof, NULL);
}
diff --git a/gdata/gdata-buffer.h b/gdata/gdata-buffer.h
index be0c622..9591dc1 100644
--- a/gdata/gdata-buffer.h
+++ b/gdata/gdata-buffer.h
@@ -51,8 +51,8 @@ GDataBuffer *gdata_buffer_new (void) G_GNUC_WARN_UNUSED_RESULT;
void gdata_buffer_free (GDataBuffer *self);
gboolean gdata_buffer_push_data (GDataBuffer *self, const guint8 *data, gsize length);
-gsize gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested, GCancellable *cancellable);
-gsize gdata_buffer_pop_data_limited (GDataBuffer *self, guint8 *data, gsize maximum_length);
+gsize gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested, gboolean *reached_eof, GCancellable *cancellable);
+gsize gdata_buffer_pop_data_limited (GDataBuffer *self, guint8 *data, gsize maximum_length, gboolean *reached_eof);
G_END_DECLS
diff --git a/gdata/gdata-download-stream.c b/gdata/gdata-download-stream.c
index bfd3b58..4891f2c 100644
--- a/gdata/gdata-download-stream.c
+++ b/gdata/gdata-download-stream.c
@@ -272,7 +272,7 @@ gdata_download_stream_read (GInputStream *stream, void *buffer, gsize count, GCa
}
/* Read the data off the buffer */
- length_read = (gssize) gdata_buffer_pop_data (priv->buffer, buffer, count, cancellable);
+ length_read = (gssize) gdata_buffer_pop_data (priv->buffer, buffer, count, NULL, cancellable);
if (g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE) {
/* Handle cancellation */
diff --git a/gdata/gdata-upload-stream.c b/gdata/gdata-upload-stream.c
index bbc0a7d..c83a86f 100644
--- a/gdata/gdata-upload-stream.c
+++ b/gdata/gdata-upload-stream.c
@@ -454,8 +454,7 @@ gdata_upload_stream_close (GOutputStream *stream, GCancellable *cancellable, GEr
* If we don't return from this signal handler, the message is never paused, and thus
* Bad Things don't happen (due to the bug, messages can be paused, but not unpaused).
* Obviously this means that our memory usage will increase, and we'll eventually end
- * up storing the entire request body in memory, but that's unavoidable at this point.
- * The additions to work around the bug are commented as "bgo#522147". */
+ * up storing the entire request body in memory, but that's unavoidable at this point. */
static void
wrote_chunk_cb (SoupMessage *message, GDataUploadStream *self)
{
@@ -463,6 +462,7 @@ wrote_chunk_cb (SoupMessage *message, GDataUploadStream *self)
GDataUploadStreamPrivate *priv = self->priv;
gsize length;
+ gboolean reached_eof = FALSE;
guint8 buffer[CHUNK_SIZE];
/* Signal the main thread that the chunk has been written */
@@ -476,8 +476,8 @@ wrote_chunk_cb (SoupMessage *message, GDataUploadStream *self)
* we could deadlock if we block on getting CHUNK_SIZE bytes at the end of the stream. write() could
* easily be called with fewer bytes, but has no way to notify us that we've reached the end of the
* stream, so we'd happily block on receiving more bytes which weren't forthcoming. */
- length = gdata_buffer_pop_data_limited (priv->buffer, buffer, CHUNK_SIZE);
- if (length == 0) {
+ length = gdata_buffer_pop_data_limited (priv->buffer, buffer, CHUNK_SIZE, &reached_eof);
+ if (reached_eof == TRUE) {
/* We've reached the end of the stream, so append the footer (if appropriate) and stop */
if (priv->entry != NULL) {
const gchar *footer = "\n--" BOUNDARY_STRING "--";
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]