diff options
author | Dan Winship <danw@gnome.org> | 2012-11-26 17:24:36 -0500 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2012-12-12 10:54:00 +0100 |
commit | 6c539304a552f3bc52cab0770fb34ab966f55480 (patch) | |
tree | 95864fac2d8a08eb5ada57d845c8927de04ae1e9 | |
parent | b62854f057dc6fba9d4cab976157231427a26a79 (diff) | |
download | libsoup-6c539304a552f3bc52cab0770fb34ab966f55480.tar.gz |
soup-body-output-stream: fix non-blocking writing
Since soup_body_output_stream_write_chunked() sometimes loops and does
multiple writes, it's not enough to just check is_writable() first and
then do a blocking write. Implement write_nonblocking() to fix this.
Noticed by Milan Plzik.
https://bugzilla.gnome.org/show_bug.cgi?id=688974
-rw-r--r-- | libsoup/soup-body-output-stream.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/libsoup/soup-body-output-stream.c b/libsoup/soup-body-output-stream.c index 86f131ab..a1419754 100644 --- a/libsoup/soup-body-output-stream.c +++ b/libsoup/soup-body-output-stream.c @@ -104,6 +104,7 @@ static gssize soup_body_output_stream_write_raw (SoupBodyOutputStream *bostream, const void *buffer, gsize count, + gboolean blocking, GCancellable *cancellable, GError **error) { @@ -122,9 +123,9 @@ soup_body_output_stream_write_raw (SoupBodyOutputStream *bostream, } else my_count = count; - nwrote = g_output_stream_write (bostream->priv->base_stream, - buffer, my_count, - cancellable, error); + nwrote = g_pollable_stream_write (bostream->priv->base_stream, + buffer, my_count, + blocking, cancellable, error); if (nwrote > 0 && bostream->priv->write_length) bostream->priv->written += nwrote; @@ -139,6 +140,7 @@ static gssize soup_body_output_stream_write_chunked (SoupBodyOutputStream *bostream, const void *buffer, gsize count, + gboolean blocking, GCancellable *cancellable, GError **error) { @@ -148,8 +150,9 @@ soup_body_output_stream_write_chunked (SoupBodyOutputStream *bostream, again: len = strlen (buf); if (len) { - nwrote = g_output_stream_write (bostream->priv->base_stream, - buf, len, cancellable, error); + nwrote = g_pollable_stream_write (bostream->priv->base_stream, + buf, len, blocking, + cancellable, error); if (nwrote < 0) return nwrote; memmove (buf, buf + nwrote, len + 1 - nwrote); @@ -169,8 +172,9 @@ again: break; case SOUP_BODY_OUTPUT_STREAM_STATE_CHUNK: - nwrote = g_output_stream_write (bostream->priv->base_stream, - buffer, count, cancellable, error); + nwrote = g_pollable_stream_write (bostream->priv->base_stream, + buffer, count, blocking, + cancellable, error); if (nwrote < (gssize)count) return nwrote; @@ -212,11 +216,11 @@ soup_body_output_stream_write_fn (GOutputStream *stream, switch (bostream->priv->encoding) { case SOUP_ENCODING_CHUNKED: return soup_body_output_stream_write_chunked (bostream, buffer, count, - cancellable, error); + TRUE, cancellable, error); default: return soup_body_output_stream_write_raw (bostream, buffer, count, - cancellable, error); + TRUE, cancellable, error); } } @@ -228,7 +232,7 @@ soup_body_output_stream_close_fn (GOutputStream *stream, SoupBodyOutputStream *bostream = SOUP_BODY_OUTPUT_STREAM (stream); if (bostream->priv->encoding == SOUP_ENCODING_CHUNKED) { - if (soup_body_output_stream_write_chunked (bostream, NULL, 0, cancellable, error) == -1) + if (soup_body_output_stream_write_chunked (bostream, NULL, 0, TRUE, cancellable, error) == -1) return FALSE; } @@ -244,6 +248,28 @@ soup_body_output_stream_is_writable (GPollableOutputStream *stream) g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (bostream->priv->base_stream)); } +static gssize +soup_body_output_stream_write_nonblocking (GPollableOutputStream *stream, + const void *buffer, + gsize count, + GError **error) +{ + SoupBodyOutputStream *bostream = SOUP_BODY_OUTPUT_STREAM (stream); + + if (bostream->priv->eof) + return count; + + switch (bostream->priv->encoding) { + case SOUP_ENCODING_CHUNKED: + return soup_body_output_stream_write_chunked (bostream, buffer, count, + FALSE, NULL, error); + + default: + return soup_body_output_stream_write_raw (bostream, buffer, count, + FALSE, NULL, error); + } +} + static GSource * soup_body_output_stream_create_source (GPollableOutputStream *stream, GCancellable *cancellable) @@ -301,6 +327,7 @@ soup_body_output_stream_pollable_init (GPollableOutputStreamInterface *pollable_ gpointer interface_data) { pollable_interface->is_writable = soup_body_output_stream_is_writable; + pollable_interface->write_nonblocking = soup_body_output_stream_write_nonblocking; pollable_interface->create_source = soup_body_output_stream_create_source; } |