libsoup r1126 - in trunk: . libsoup tests
- From: danw svn gnome org
- To: svn-commits-list gnome org
- Subject: libsoup r1126 - in trunk: . libsoup tests
- Date: Sat, 5 Apr 2008 20:35:35 +0100 (BST)
Author: danw
Date: Sat Apr 5 20:35:35 2008
New Revision: 1126
URL: http://svn.gnome.org/viewvc/libsoup?rev=1126&view=rev
Log:
* libsoup/soup-message-body.c (soup_message_body_set_accumulate)
(soup_message_body_get_accumulate): New, replaces
SOUP_MESSAGE_OVERWRITE_CHUNKS, but can be set on either the
incoming or outgoing message body.
(soup_message_body_get_chunk): update to still dtrt if !accumulate
(soup_message_body_got_chunk, soup_message_body_wrote_chunk): New
methods to handle accumulating/discarding chunks.
* libsoup/soup-message-io.c (read_body_chunk): Use
soup_message_body_got_chunk.
(io_write): Use soup_message_body_wrote_chunk, to discard unneeded
chunks after writing them. Fixes most of #522146.
* libsoup/soup-message.c (soup_message_class_init): add a new
flag, "server-side", to indicate whether the message is
client-side or server-side, and update several methods to use it.
(got_body): Update for accumulate
(soup_message_set_flags): If the caller changes OVERWRITE_CHUNKS,
update the corresponding accumulate flag.
* libsoup/soup-message.h (SOUP_MESSAGE_OVERWRITE_CHUNKS):
deprecated now
* tests/chunk-test.c (do_request_test): Use
soup_message_body_set_accumulate() now, and verify that the chunks
are being discarded appropriately.
(do_response_test): Use
soup_message_body_set_accumulate() instead of OVERWRITE_CHUNKS.
* tests/pull-api.c (do_fully_async_test)
(do_synchronously_async_test): Use
soup_message_body_set_accumulate().
Modified:
trunk/ChangeLog
trunk/libsoup/soup-message-body.c
trunk/libsoup/soup-message-body.h
trunk/libsoup/soup-message-io.c
trunk/libsoup/soup-message-private.h
trunk/libsoup/soup-message.c
trunk/libsoup/soup-message.h
trunk/libsoup/soup-server.c
trunk/tests/chunk-test.c
trunk/tests/pull-api.c
Modified: trunk/libsoup/soup-message-body.c
==============================================================================
--- trunk/libsoup/soup-message-body.c (original)
+++ trunk/libsoup/soup-message-body.c Sat Apr 5 20:35:35 2008
@@ -304,6 +304,8 @@
SoupMessageBody body;
GSList *chunks, *last;
SoupBuffer *flattened;
+ gboolean accumulate;
+ goffset base_offset;
int ref_count;
} SoupMessageBodyPrivate;
@@ -321,11 +323,63 @@
SoupMessageBodyPrivate *priv;
priv = g_slice_new0 (SoupMessageBodyPrivate);
+ priv->accumulate = TRUE;
priv->ref_count = 1;
return (SoupMessageBody *)priv;
}
+/**
+ * soup_message_body_set_accumulate:
+ * @body: a #SoupMessageBody
+ * @accumulate: whether or not to accumulate body chunks in @body
+ *
+ * Sets or clears the accumulate flag on @body. (The default value
+ * is %TRUE.)
+ *
+ * If you set this flag to %FALSE on an "incoming" message body (that
+ * is, the %response_body of a client-side message, or %request_body
+ * of a server-side message), this will cause each chunk of the body
+ * to be discarded after its corresponding #SoupMessage::got_chunk
+ * signal is emitted. (This is equivalent to setting the deprecated
+ * %SOUP_MESSAGE_OVERWRITE_CHUNKS flag on the message.)
+ *
+ * If you set this flag to %FALSE on an "outgoing" message body (the
+ * %request_body of a client-side message, or %response_body of a
+ * server-side message), it will cause each chunk of the body to be
+ * discarded after its corresponding #SoupMessage::wrote_chunk signal
+ * is emitted.
+ *
+ * In either case, @body's %data field will not be filled in after the
+ * body is fully sent/received, since the body data will no longer be
+ * available
+ **/
+void
+soup_message_body_set_accumulate (SoupMessageBody *body,
+ gboolean accumulate)
+{
+ SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
+
+ priv->accumulate = accumulate;
+}
+
+/**
+ * soup_message_body_get_accumulate:
+ * @body: a #SoupMessageBody
+ *
+ * Gets the accumulate flag on @body; see
+ * soup_message_body_set_accumulate() for details.
+ *
+ * Return value: the accumulate flag for @body.
+ **/
+gboolean
+soup_message_body_get_accumulate (SoupMessageBody *body)
+{
+ SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
+
+ return priv->accumulate;
+}
+
static void
append_buffer (SoupMessageBody *body, SoupBuffer *buffer)
{
@@ -438,6 +492,8 @@
GSList *iter;
SoupBuffer *chunk;
+ g_return_val_if_fail (priv->accumulate == TRUE, NULL);
+
if (!priv->flattened) {
#if GLIB_SIZEOF_SIZE_T < 8
g_return_val_if_fail (body->length < G_MAXSIZE, NULL);
@@ -489,6 +545,7 @@
GSList *iter;
SoupBuffer *chunk = NULL;
+ offset -= priv->base_offset;
for (iter = priv->chunks; iter; iter = iter->next) {
chunk = iter->data;
@@ -509,6 +566,63 @@
}
}
+/**
+ * soup_message_body_got_chunk:
+ * @body: a #SoupMessageBody
+ * @chunk: a #SoupBuffer received from the network
+ *
+ * Handles the #SoupMessageBody part of receiving a chunk of data from
+ * the network. Normally this means appending @chunk to @body, exactly
+ * as with soup_message_body_append_buffer(), but if you have set
+ * @body's accumulate flag to %FALSE, then that will not happen.
+ *
+ * This is a low-level method which you should not normally need to
+ * use.
+ **/
+void
+soup_message_body_got_chunk (SoupMessageBody *body, SoupBuffer *chunk)
+{
+ SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
+
+ if (!priv->accumulate)
+ return;
+
+ soup_message_body_append_buffer (body, chunk);
+}
+
+/**
+ * soup_message_body_wrote_chunk:
+ * @body: a #SoupMessageBody
+ * @chunk: a #SoupBuffer received from the network
+ *
+ * Handles the #SoupMessageBody part of writing a chunk of data to the
+ * network. Normally this is a no-op, but if you have set @body's
+ * accumulate flag to %FALSE, then this will cause @chunk (and any
+ * chunks preceding it in @body) to be discarded to free up memory.
+ *
+ * This is a low-level method which you should not normally need to
+ * use.
+ **/
+void
+soup_message_body_wrote_chunk (SoupMessageBody *body, SoupBuffer *chunk)
+{
+ SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
+ SoupBuffer *chunk2;
+
+ if (priv->accumulate)
+ return;
+
+ do {
+ chunk2 = priv->chunks->data;
+ priv->chunks = g_slist_remove (priv->chunks, chunk2);
+ priv->base_offset += chunk2->length;
+ soup_buffer_free (chunk2);
+ } while (priv->chunks && chunk2 != chunk);
+
+ if (!priv->chunks)
+ priv->last = NULL;
+}
+
static SoupMessageBody *
soup_message_body_copy (SoupMessageBody *body)
{
Modified: trunk/libsoup/soup-message-body.h
==============================================================================
--- trunk/libsoup/soup-message-body.h (original)
+++ trunk/libsoup/soup-message-body.h Sat Apr 5 20:35:35 2008
@@ -51,6 +51,10 @@
SoupMessageBody *soup_message_body_new (void);
+void soup_message_body_set_accumulate(SoupMessageBody *body,
+ gboolean accumulate);
+gboolean soup_message_body_get_accumulate(SoupMessageBody *body);
+
void soup_message_body_append (SoupMessageBody *body,
SoupMemoryUse use,
gconstpointer data,
@@ -65,6 +69,11 @@
SoupBuffer *soup_message_body_get_chunk (SoupMessageBody *body,
goffset offset);
+void soup_message_body_got_chunk (SoupMessageBody *body,
+ SoupBuffer *chunk);
+void soup_message_body_wrote_chunk (SoupMessageBody *body,
+ SoupBuffer *chunk);
+
void soup_message_body_free (SoupMessageBody *body);
G_END_DECLS
Modified: trunk/libsoup/soup-message-io.c
==============================================================================
--- trunk/libsoup/soup-message-io.c (original)
+++ trunk/libsoup/soup-message-io.c Sat Apr 5 20:35:35 2008
@@ -261,8 +261,7 @@
/* Reads as much message body data as is available on io->sock (but no
* further than the end of the current message body or chunk). On a
* successful read, emits "got_chunk" (possibly multiple times), and
- * if %SOUP_MESSAGE_OVERWRITE_CHUNKS wasn't set, appends the chunk
- * to io->read_body.
+ * (unless told not to) appends the chunk to io->read_body.
*
* See the note at read_metadata() for an explanation of the return
* value.
@@ -306,8 +305,7 @@
if (status == SOUP_SOCKET_OK && nread) {
buffer->length = nread;
- if (!(priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
- soup_message_body_append_buffer (io->read_body, buffer);
+ soup_message_body_got_chunk (io->read_body, buffer);
io->read_length -= nread;
@@ -549,6 +547,7 @@
io->write_chunk->length, TRUE))
return;
+ soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
soup_buffer_free (io->write_chunk);
io->write_body_offset += io->write_chunk->length;
io->write_chunk = NULL;
@@ -591,6 +590,7 @@
io->write_chunk->length, TRUE))
return;
+ soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
soup_buffer_free (io->write_chunk);
io->write_chunk = NULL;
Modified: trunk/libsoup/soup-message-private.h
==============================================================================
--- trunk/libsoup/soup-message-private.h (original)
+++ trunk/libsoup/soup-message-private.h Sat Apr 5 20:35:35 2008
@@ -27,6 +27,7 @@
GDestroyNotify chunk_allocator_dnotify;
guint msg_flags;
+ gboolean server_side;
SoupHTTPVersion http_version, orig_http_version;
Modified: trunk/libsoup/soup-message.c
==============================================================================
--- trunk/libsoup/soup-message.c (original)
+++ trunk/libsoup/soup-message.c Sat Apr 5 20:35:35 2008
@@ -62,11 +62,16 @@
* filled in right before libsoup writes the request to the network,
* but you should not count on this; use soup_message_body_flatten()
* if you want to ensure that %data is filled in. @response_body's
- * %data will be filled in before #SoupMessage::finished is emitted,
- * unless you set the %SOUP_MESSAGE_OVERWRITE_CHUNKS flag.
+ * %data will be filled in before #SoupMessage::finished is emitted.
*
* For a server-side #SoupMessage, @request_body's %data will be
* filled in before #SoupMessage::got_body is emitted.
+ *
+ * To prevent the %data field from being filled in at all (eg, if you
+ * are handling the data from a #SoupMessage::got_chunk, and so don't
+ * need to see it all at the end), call
+ * soup_message_body_set_accumulate() on @response_body or
+ * @request_body as appropriate, passing %FALSE.
**/
G_DEFINE_TYPE (SoupMessage, soup_message, G_TYPE_OBJECT)
@@ -98,6 +103,7 @@
PROP_URI,
PROP_HTTP_VERSION,
PROP_FLAGS,
+ PROP_SERVER_SIDE,
PROP_STATUS_CODE,
PROP_REASON_PHRASE,
@@ -446,6 +452,13 @@
0,
G_PARAM_READWRITE));
g_object_class_install_property (
+ object_class, PROP_SERVER_SIDE,
+ g_param_spec_boolean (SOUP_MESSAGE_SERVER_SIDE,
+ "Server-side",
+ "Whether or not the message is server-side rather than client-side",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (
object_class, PROP_STATUS_CODE,
g_param_spec_uint (SOUP_MESSAGE_STATUS_CODE,
"Status code",
@@ -466,6 +479,7 @@
const GValue *value, GParamSpec *pspec)
{
SoupMessage *msg = SOUP_MESSAGE (object);
+ SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
switch (prop_id) {
case PROP_METHOD:
@@ -480,6 +494,9 @@
case PROP_FLAGS:
soup_message_set_flags (msg, g_value_get_flags (value));
break;
+ case PROP_SERVER_SIDE:
+ priv->server_side = g_value_get_boolean (value);
+ break;
case PROP_STATUS_CODE:
soup_message_set_status (msg, g_value_get_uint (value));
break;
@@ -513,6 +530,9 @@
case PROP_FLAGS:
g_value_set_flags (value, priv->msg_flags);
break;
+ case PROP_SERVER_SIDE:
+ g_value_set_boolean (value, priv->server_side);
+ break;
case PROP_STATUS_CODE:
g_value_set_uint (value, msg->status_code);
break;
@@ -752,15 +772,13 @@
got_body (SoupMessage *req)
{
SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (req);
+ SoupMessageBody *body;
- if (!(priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS)) {
+ body = priv->server_side ? req->request_body : req->response_body;
+ if (soup_message_body_get_accumulate (body)) {
SoupBuffer *buffer;
- /* Figure out *which* body we read, and flatten it. */
- if (req->status_code == 0)
- buffer = soup_message_body_flatten (req->request_body);
- else
- buffer = soup_message_body_flatten (req->response_body);
+ buffer = soup_message_body_flatten (body);
soup_buffer_free (buffer);
}
}
@@ -838,13 +856,7 @@
if (priv->io_status != SOUP_MESSAGE_IO_STATUS_RUNNING)
return;
- /* If status_code is SOUP_STATUS_NONE, we're still processing
- * the request side; if it's not, we're processing the
- * response side.
- */
- hdrs = (msg->status_code == SOUP_STATUS_NONE) ?
- msg->request_headers : msg->response_headers;
-
+ hdrs = priv->server_side ? msg->request_headers : msg->response_headers;
if (soup_message_headers_get (hdrs, header_name)) {
closure->marshal (closure, return_value, n_param_values,
param_values, invocation_hint,
@@ -1103,11 +1115,9 @@
* SoupMessageFlags:
* @SOUP_MESSAGE_NO_REDIRECT: The session should not follow redirect
* (3xx) responses received by this message.
- * @SOUP_MESSAGE_OVERWRITE_CHUNKS: Each chunk of the response will be
- * freed after its corresponding %got_chunk signal is emitted, meaning
- * %response will still be empty after the message is complete. You
- * can use this to save memory if you expect the response to be large
- * and you are able to process it a chunk at a time.
+ * @SOUP_MESSAGE_OVERWRITE_CHUNKS: Deprecated: equivalent to calling
+ * soup_message_body_set_accumulate() on the incoming message body
+ * (ie, %response_body for a client-side request), passing %FALSE.
*
* Various flags that can be set on a #SoupMessage to alter its
* behavior.
@@ -1123,9 +1133,18 @@
void
soup_message_set_flags (SoupMessage *msg, SoupMessageFlags flags)
{
+ SoupMessagePrivate *priv;
+
g_return_if_fail (SOUP_IS_MESSAGE (msg));
+ priv = SOUP_MESSAGE_GET_PRIVATE (msg);
+
+ if ((priv->msg_flags ^ flags) & SOUP_MESSAGE_OVERWRITE_CHUNKS) {
+ soup_message_body_set_accumulate (
+ priv->server_side ? msg->request_body : msg->response_body,
+ !(flags & SOUP_MESSAGE_OVERWRITE_CHUNKS));
+ }
- SOUP_MESSAGE_GET_PRIVATE (msg)->msg_flags = flags;
+ priv->msg_flags = flags;
g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_FLAGS);
}
@@ -1387,23 +1406,22 @@
* %length to indicate how much data it read.
*
* Generally, a custom chunk allocator would be used in conjunction
- * with %SOUP_MESSAGE_OVERWRITE_CHUNKS and #SoupMessage::got_chunk, as
- * part of a strategy to avoid unnecessary copying of data. However,
- * you cannot assume that every call to the allocator will be followed
- * by a call to your %got_chunk handler; if an I/O error occurs, then
- * the buffer will be unreffed without ever having been used. If your
- * buffer-allocation strategy requires special cleanup, use
- * soup_buffer_new_with_owner() rather than doing the cleanup from the
- * %got_chunk handler.
- *
- * The other thing to remember when using
- * %SOUP_MESSAGE_OVERWRITE_CHUNKS is that the buffer passed to the
- * %got_chunk handler will be unreffed after the handler returns, just
- * as it would be in the non-custom-allocated case. If you want to
- * hand the chunk data off to some other part of your program to use
- * later, you'll need to ref the #SoupBuffer (or its owner, in the
- * soup_buffer_new_with_owner() case) to ensure that the data remains
- * valid.
+ * with soup_message_body_set_accumulate() %FALSE and
+ * #SoupMessage::got_chunk, as part of a strategy to avoid unnecessary
+ * copying of data. However, you cannot assume that every call to the
+ * allocator will be followed by a call to your %got_chunk handler; if
+ * an I/O error occurs, then the buffer will be unreffed without ever
+ * having been used. If your buffer-allocation strategy requires
+ * special cleanup, use soup_buffer_new_with_owner() rather than doing
+ * the cleanup from the %got_chunk handler.
+ *
+ * The other thing to remember when using non-accumulating message
+ * bodies is that the buffer passed to the %got_chunk handler will be
+ * unreffed after the handler returns, just as it would be in the
+ * non-custom-allocated case. If you want to hand the chunk data off
+ * to some other part of your program to use later, you'll need to ref
+ * the #SoupBuffer (or its owner, in the soup_buffer_new_with_owner()
+ * case) to ensure that the data remains valid.
**/
void
soup_message_set_chunk_allocator (SoupMessage *msg,
Modified: trunk/libsoup/soup-message.h
==============================================================================
--- trunk/libsoup/soup-message.h (original)
+++ trunk/libsoup/soup-message.h Sat Apr 5 20:35:35 2008
@@ -64,6 +64,7 @@
#define SOUP_MESSAGE_URI "uri"
#define SOUP_MESSAGE_HTTP_VERSION "http-version"
#define SOUP_MESSAGE_FLAGS "flags"
+#define SOUP_MESSAGE_SERVER_SIDE "server-side"
#define SOUP_MESSAGE_STATUS_CODE "status-code"
#define SOUP_MESSAGE_REASON_PHRASE "reason-phrase"
@@ -100,7 +101,9 @@
typedef enum {
SOUP_MESSAGE_NO_REDIRECT = (1 << 1),
+#ifndef LIBSOUP_DISABLE_DEPRECATED
SOUP_MESSAGE_OVERWRITE_CHUNKS = (1 << 3),
+#endif
} SoupMessageFlags;
void soup_message_set_flags (SoupMessage *msg,
Modified: trunk/libsoup/soup-server.c
==============================================================================
--- trunk/libsoup/soup-server.c (original)
+++ trunk/libsoup/soup-server.c Sat Apr 5 20:35:35 2008
@@ -807,7 +807,9 @@
soup_client_context_cleanup (client);
/* Listen for another request on this connection */
- msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
+ msg = g_object_new (SOUP_TYPE_MESSAGE,
+ SOUP_MESSAGE_SERVER_SIDE, TRUE,
+ NULL);
soup_message_headers_set_encoding (msg->response_headers,
SOUP_ENCODING_CONTENT_LENGTH);
if (priv->server_header) {
Modified: trunk/tests/chunk-test.c
==============================================================================
--- trunk/tests/chunk-test.c (original)
+++ trunk/tests/chunk-test.c Sat Apr 5 20:35:35 2008
@@ -36,12 +36,10 @@
debug_printf (2, " writing chunk\n");
-#ifdef IMPLEMENTED_OVERWRITE_CHUNKS_FOR_REQUESTS
if (ptd->next > 0 && ptd->chunks[ptd->next - 1]) {
debug_printf (1, " error: next chunk requested before last one freed!\n");
errors++;
}
-#endif
if (ptd->next < G_N_ELEMENTS (ptd->chunks)) {
soup_message_body_append_buffer (msg->request_body,
@@ -117,6 +115,7 @@
msg = soup_message_new_from_uri ("PUT", base_uri);
soup_message_headers_set_encoding (msg->request_headers, SOUP_ENCODING_CHUNKED);
+ soup_message_body_set_accumulate (msg->request_body, FALSE);
soup_message_set_chunk_allocator (msg, error_chunk_allocator, NULL, NULL);
g_signal_connect (msg, "wrote_headers",
G_CALLBACK (write_next_chunk), &ptd);
@@ -206,7 +205,7 @@
gtd.check = g_checksum_new (G_CHECKSUM_MD5);
msg = soup_message_new_from_uri ("GET", base_uri);
- soup_message_set_flags (msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
+ soup_message_body_set_accumulate (msg->response_body, FALSE);
soup_message_set_chunk_allocator (msg, chunk_allocator, >d, NULL);
g_signal_connect (msg, "got_chunk",
G_CALLBACK (got_chunk), >d);
Modified: trunk/tests/pull-api.c
==============================================================================
--- trunk/tests/pull-api.c (original)
+++ trunk/tests/pull-api.c Sat Apr 5 20:35:35 2008
@@ -98,10 +98,10 @@
ad.expected_status = expected_status;
/* Since we aren't going to look at the final value of
- * msg->response, we set OVERWRITE_CHUNKS, to tell libsoup to
- * not even bother generating it.
+ * msg->response_body, we tell libsoup to not even bother
+ * generating it.
*/
- soup_message_set_flags (msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
+ soup_message_body_set_accumulate (msg->response_body, FALSE);
/* Connect to "got_headers", from which we'll decide where to
* go next.
@@ -289,10 +289,10 @@
msg = soup_message_new (SOUP_METHOD_GET, uri);
g_free (uri);
- /* As in the fully-async case, we set OVERWRITE_CHUNKS as an
+ /* As in the fully-async case, we turn off accumulate, as an
* optimization.
*/
- soup_message_set_flags (msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
+ soup_message_body_set_accumulate (msg->response_body, FALSE);
/* Send the message, get back headers */
sync_async_send (session, msg);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]