diff options
Diffstat (limited to 'libsoup')
-rw-r--r-- | libsoup/cache/soup-cache.c | 7 | ||||
-rw-r--r-- | libsoup/server/soup-server-io.c | 2 | ||||
-rw-r--r-- | libsoup/soup-body-output-stream.c | 18 | ||||
-rw-r--r-- | libsoup/soup-client-input-stream.c | 15 | ||||
-rw-r--r-- | libsoup/soup-filter-input-stream.c | 65 | ||||
-rw-r--r-- | libsoup/soup-logger.c | 17 | ||||
-rw-r--r-- | libsoup/soup-message-io-data.c | 10 | ||||
-rw-r--r-- | libsoup/soup-message-io-data.h | 1 | ||||
-rw-r--r-- | libsoup/soup-message-io.c | 55 | ||||
-rw-r--r-- | libsoup/soup-message-metrics-private.h | 9 | ||||
-rw-r--r-- | libsoup/soup-message-metrics.c | 119 | ||||
-rw-r--r-- | libsoup/soup-message-metrics.h | 18 |
12 files changed, 304 insertions, 32 deletions
diff --git a/libsoup/cache/soup-cache.c b/libsoup/cache/soup-cache.c index 969b3a4d..a33be803 100644 --- a/libsoup/cache/soup-cache.c +++ b/libsoup/cache/soup-cache.c @@ -40,7 +40,7 @@ #include "soup-content-processor.h" #include "soup-message-private.h" #include "soup.h" -#include "soup-message-private.h" +#include "soup-message-metrics-private.h" #include "soup-misc.h" #include "soup-session-private.h" #include "soup-session-feature-private.h" @@ -688,6 +688,7 @@ soup_cache_send_response (SoupCache *cache, SoupMessage *msg) SoupCacheEntry *entry; GInputStream *file_stream, *body_stream, *cache_stream, *client_stream; GFile *file; + SoupMessageMetrics *metrics; g_return_val_if_fail (SOUP_IS_CACHE (cache), NULL); g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL); @@ -711,6 +712,10 @@ soup_cache_send_response (SoupCache *cache, SoupMessage *msg) if (!body_stream) return NULL; + metrics = soup_message_get_metrics (msg); + if (metrics) + metrics->response_body_size = entry->length; + /* If we are told to send a response from cache any validation in course is over by now */ entry->being_validated = FALSE; diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c index 5cc240b1..a806d2f3 100644 --- a/libsoup/server/soup-server-io.c +++ b/libsoup/server/soup-server-io.c @@ -661,7 +661,7 @@ io_read (SoupServerMessage *msg, switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: - if (!soup_message_io_data_read_headers (io, FALSE, NULL, error)) { + if (!soup_message_io_data_read_headers (io, FALSE, NULL, NULL, error)) { if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT)) soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return FALSE; diff --git a/libsoup/soup-body-output-stream.c b/libsoup/soup-body-output-stream.c index 499e8e6f..c0aeb458 100644 --- a/libsoup/soup-body-output-stream.c +++ b/libsoup/soup-body-output-stream.c @@ -118,7 +118,15 @@ soup_body_output_stream_wrote_data (SoupBodyOutputStream *bostream, const void *buffer, gsize count) { - g_signal_emit (bostream, signals[WROTE_DATA], 0, buffer, count); + g_signal_emit (bostream, signals[WROTE_DATA], 0, buffer, count, FALSE); +} + +static void +soup_body_output_stream_wrote_metadata (SoupBodyOutputStream *bostream, + const void *buffer, + gsize count) +{ + g_signal_emit (bostream, signals[WROTE_DATA], 0, buffer, count, TRUE); } static gssize @@ -178,6 +186,9 @@ again: nwrote = g_pollable_stream_write (priv->base_stream, buf, len, blocking, cancellable, error); + if (nwrote > 0) + soup_body_output_stream_wrote_metadata (bostream, buf, nwrote); + if (nwrote < 0) return nwrote; memmove (buf, buf + nwrote, len + 1 - nwrote); @@ -341,9 +352,10 @@ soup_body_output_stream_class_init (SoupBodyOutputStreamClass *stream_class) 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, + G_TYPE_NONE, 3, G_TYPE_POINTER, - G_TYPE_UINT); + G_TYPE_UINT, + G_TYPE_BOOLEAN); g_object_class_install_property ( object_class, PROP_ENCODING, diff --git a/libsoup/soup-client-input-stream.c b/libsoup/soup-client-input-stream.c index bf4a866f..a95bfe41 100644 --- a/libsoup/soup-client-input-stream.c +++ b/libsoup/soup-client-input-stream.c @@ -12,6 +12,7 @@ #include "soup-client-input-stream.h" #include "soup.h" #include "soup-message-private.h" +#include "soup-message-metrics-private.h" #include "soup-misc.h" struct _SoupClientInputStream { @@ -20,6 +21,7 @@ struct _SoupClientInputStream { typedef struct { SoupMessage *msg; + SoupMessageMetrics *metrics; } SoupClientInputStreamPrivate; enum { @@ -69,6 +71,7 @@ soup_client_input_stream_set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_MESSAGE: priv->msg = g_value_dup_object (value); + priv->metrics = soup_message_get_metrics (priv->msg); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -100,11 +103,15 @@ soup_client_input_stream_read_fn (GInputStream *stream, GCancellable *cancellable, GError **error) { + SoupClientInputStreamPrivate *priv = soup_client_input_stream_get_instance_private (SOUP_CLIENT_INPUT_STREAM (stream)); gssize nread; nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)-> read_fn (stream, buffer, count, cancellable, error); + if (priv->metrics && nread > 0) + priv->metrics->response_body_size += nread; + if (nread == 0) g_signal_emit (stream, signals[SIGNAL_EOF], 0); @@ -117,11 +124,15 @@ soup_client_input_stream_skip (GInputStream *stream, GCancellable *cancellable, GError **error) { + SoupClientInputStreamPrivate *priv = soup_client_input_stream_get_instance_private (SOUP_CLIENT_INPUT_STREAM (stream)); gssize nread; nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)-> skip (stream, count, cancellable, error); + if (priv->metrics && nread > 0) + priv->metrics->response_body_size += nread; + if (nread == 0) g_signal_emit (stream, signals[SIGNAL_EOF], 0); @@ -134,11 +145,15 @@ soup_client_input_stream_read_nonblocking (GPollableInputStream *stream, gsize count, GError **error) { + SoupClientInputStreamPrivate *priv = soup_client_input_stream_get_instance_private (SOUP_CLIENT_INPUT_STREAM (stream)); gssize nread; nread = soup_client_input_stream_parent_pollable_interface-> read_nonblocking (stream, buffer, count, error); + if (priv->metrics && nread > 0) + priv->metrics->response_body_size += nread; + if (nread == 0) g_signal_emit (stream, signals[SIGNAL_EOF], 0); diff --git a/libsoup/soup-filter-input-stream.c b/libsoup/soup-filter-input-stream.c index 448b7c9f..6ef11a05 100644 --- a/libsoup/soup-filter-input-stream.c +++ b/libsoup/soup-filter-input-stream.c @@ -26,6 +26,14 @@ typedef struct { gboolean in_read_until; } SoupFilterInputStreamPrivate; +enum { + READ_DATA, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + static void soup_filter_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data); G_DEFINE_TYPE_WITH_CODE (SoupFilterInputStream, soup_filter_input_stream, G_TYPE_FILTER_INPUT_STREAM, @@ -81,17 +89,21 @@ soup_filter_input_stream_read_fn (GInputStream *stream, { SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream); SoupFilterInputStreamPrivate *priv = soup_filter_input_stream_get_instance_private (fstream); + gssize bytes_read; if (!priv->in_read_until) priv->need_more = FALSE; - if (priv->buf && !priv->in_read_until) { + if (priv->buf && !priv->in_read_until) return read_from_buf (fstream, buffer, count); - } else { - return g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream, - buffer, count, - TRUE, cancellable, error); - } + + bytes_read = g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream, + buffer, count, + TRUE, cancellable, error); + if (bytes_read > 0) + g_signal_emit (fstream, signals[READ_DATA], 0, bytes_read); + + return bytes_read; } static gssize @@ -102,16 +114,20 @@ soup_filter_input_stream_skip (GInputStream *stream, { SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream); SoupFilterInputStreamPrivate *priv = soup_filter_input_stream_get_instance_private (fstream); + gssize bytes_skipped; if (!priv->in_read_until) priv->need_more = FALSE; - if (priv->buf && !priv->in_read_until) { + if (priv->buf && !priv->in_read_until) return read_from_buf (fstream, NULL, count); - } else { - return g_input_stream_skip (G_FILTER_INPUT_STREAM (fstream)->base_stream, - count, cancellable, error); - } + + bytes_skipped = g_input_stream_skip (G_FILTER_INPUT_STREAM (fstream)->base_stream, + count, cancellable, error); + if (bytes_skipped > 0) + g_signal_emit (fstream, signals[READ_DATA], 0, bytes_skipped); + + return bytes_skipped; } static gboolean @@ -134,17 +150,21 @@ soup_filter_input_stream_read_nonblocking (GPollableInputStream *stream, { SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream); SoupFilterInputStreamPrivate *priv = soup_filter_input_stream_get_instance_private (fstream); + gssize bytes_read; if (!priv->in_read_until) priv->need_more = FALSE; - if (priv->buf && !priv->in_read_until) { + if (priv->buf && !priv->in_read_until) return read_from_buf (fstream, buffer, count); - } else { - return g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream, - buffer, count, - FALSE, NULL, error); - } + + bytes_read = g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream, + buffer, count, + FALSE, NULL, error); + if (bytes_read > 0) + g_signal_emit (fstream, signals[READ_DATA], 0, bytes_read); + + return bytes_read; } static GSource * @@ -178,6 +198,17 @@ soup_filter_input_stream_class_init (SoupFilterInputStreamClass *stream_class) input_stream_class->read_fn = soup_filter_input_stream_read_fn; input_stream_class->skip = soup_filter_input_stream_skip; + + signals[READ_DATA] = + g_signal_new ("read-data", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_UINT); + } static void diff --git a/libsoup/soup-logger.c b/libsoup/soup-logger.c index 3bb7dda3..c9899e22 100644 --- a/libsoup/soup-logger.c +++ b/libsoup/soup-logger.c @@ -815,13 +815,20 @@ got_body (SoupMessage *msg, gpointer user_data) } static void -body_stream_wrote_data_cb (GOutputStream *stream, const void *buffer, - guint count, SoupLogger *logger) +body_stream_wrote_data_cb (GOutputStream *stream, + const void *buffer, + guint count, + gboolean is_metadata, + SoupLogger *logger) { - SoupLoggerPrivate *priv = soup_logger_get_instance_private (logger); - SoupMessage *msg = g_hash_table_lookup (priv->request_messages, - stream); + SoupLoggerPrivate *priv; + SoupMessage *msg; + + if (is_metadata) + return; + priv = soup_logger_get_instance_private (logger); + msg = g_hash_table_lookup (priv->request_messages, stream); write_body (logger, buffer, count, msg, priv->request_bodies); } diff --git a/libsoup/soup-message-io-data.c b/libsoup/soup-message-io-data.c index 61ad83f4..04a9c255 100644 --- a/libsoup/soup-message-io-data.c +++ b/libsoup/soup-message-io-data.c @@ -50,6 +50,7 @@ gboolean soup_message_io_data_read_headers (SoupMessageIOData *io, gboolean blocking, GCancellable *cancellable, + gushort *extra_bytes, GError **error) { gssize nread, old_len; @@ -66,8 +67,11 @@ soup_message_io_data_read_headers (SoupMessageIOData *io, cancellable, error); io->read_header_buf->len = old_len + MAX (nread, 0); if (nread == 0) { - if (io->read_header_buf->len > 0) + if (io->read_header_buf->len > 0) { + if (extra_bytes) + *extra_bytes = 0; break; + } g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, @@ -82,12 +86,16 @@ soup_message_io_data_read_headers (SoupMessageIOData *io, io->read_header_buf->len - 2, "\n\n", 2)) { io->read_header_buf->len--; + if (extra_bytes) + *extra_bytes = 1; break; } else if (nread == 2 && old_len >= 3 && !strncmp ((char *)io->read_header_buf->data + io->read_header_buf->len - 3, "\n\r\n", 3)) { io->read_header_buf->len -= 2; + if (extra_bytes) + *extra_bytes = 2; break; } } diff --git a/libsoup/soup-message-io-data.h b/libsoup/soup-message-io-data.h index 868ae8d5..e3feae7a 100644 --- a/libsoup/soup-message-io-data.h +++ b/libsoup/soup-message-io-data.h @@ -80,6 +80,7 @@ void soup_message_io_data_cleanup (SoupMessageIOData *io); gboolean soup_message_io_data_read_headers (SoupMessageIOData *io, gboolean blocking, GCancellable *cancellable, + gushort *extra_bytes, GError **error); typedef gboolean (*SoupMessageIOSourceFunc) (GObject *msg, diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c index 9eab3ef2..68b437e5 100644 --- a/libsoup/soup-message-io.c +++ b/libsoup/soup-message-io.c @@ -25,6 +25,7 @@ #include "soup-filter-input-stream.h" #include "soup-logger-private.h" #include "soup-message-private.h" +#include "soup-message-metrics-private.h" #include "soup-message-queue-item.h" #include "soup-misc.h" #include "soup-uri-utils-private.h" @@ -34,6 +35,8 @@ struct _SoupClientMessageIOData { SoupMessageQueueItem *item; + SoupMessageMetrics *metrics; + #ifdef HAVE_SYSPROF gint64 begin_time_nsec; #endif @@ -164,9 +167,19 @@ soup_message_setup_body_istream (GInputStream *body_stream, static void request_body_stream_wrote_data_cb (SoupMessage *msg, const void *buffer, - guint count) + guint count, + gboolean is_metadata) { - soup_message_wrote_body_data (msg, count); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + + if (client_io->metrics) { + client_io->metrics->request_body_bytes_sent += count; + if (!is_metadata) + client_io->metrics->request_body_size += count; + } + + if (!is_metadata) + soup_message_wrote_body_data (msg, count); } static void @@ -345,6 +358,8 @@ io_write (SoupMessage *msg, gboolean blocking, if (nwrote == -1) return FALSE; io->written += nwrote; + if (client_io->metrics) + client_io->metrics->request_header_bytes_sent += nwrote; } io->written = 0; @@ -497,6 +512,18 @@ parse_headers (SoupMessage *msg, return TRUE; } +static void +response_network_stream_read_data_cb (SoupMessage *msg, + guint count) +{ + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + + if (client_io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY_START) + client_io->metrics->response_header_bytes_received += count; + else + client_io->metrics->response_body_bytes_received += count; +} + /* Attempts to push forward the reading side of @msg's I/O. Returns * %TRUE if it manages to make some progress, and it is likely that * further progress can be made. Returns %FALSE if it has reached a @@ -511,15 +538,27 @@ io_read (SoupMessage *msg, gboolean blocking, SoupMessageIOData *io = &client_io->base; gboolean succeeded; gboolean is_first_read; + gushort extra_bytes; switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: is_first_read = io->read_header_buf->len == 0 && soup_message_get_status (msg) == SOUP_STATUS_NONE; - if (!soup_message_io_data_read_headers (io, blocking, cancellable, error)) + if (!soup_message_io_data_read_headers (io, blocking, cancellable, &extra_bytes, error)) return FALSE; + if (client_io->metrics) { + /* Adjust the header and body bytes received, since we might + * have read part of the body already that is queued by the stream. + */ + if (client_io->metrics->response_header_bytes_received > io->read_header_buf->len + extra_bytes) { + client_io->metrics->response_body_bytes_received = + client_io->metrics->response_header_bytes_received - io->read_header_buf->len - extra_bytes; + client_io->metrics->response_header_bytes_received -= client_io->metrics->response_body_bytes_received; + } + } + if (is_first_read) soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_RESPONSE_START); @@ -642,6 +681,9 @@ io_read (SoupMessage *msg, gboolean blocking, if (nread == 0) io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE; + if (client_io->metrics) + client_io->metrics->response_body_size += nread; + break; } @@ -1000,6 +1042,13 @@ soup_message_send_request (SoupMessageQueueItem *item, io->base.read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; io->base.write_state = SOUP_MESSAGE_IO_STATE_HEADERS; + io->metrics = soup_message_get_metrics (io->item->msg); + if (io->metrics) { + g_signal_connect_object (io->base.istream, "read-data", + G_CALLBACK (response_network_stream_read_data_cb), + io->item->msg, G_CONNECT_SWAPPED); + } + #ifdef HAVE_SYSPROF io->begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME; #endif diff --git a/libsoup/soup-message-metrics-private.h b/libsoup/soup-message-metrics-private.h index 03d62ad1..6f0869e0 100644 --- a/libsoup/soup-message-metrics-private.h +++ b/libsoup/soup-message-metrics-private.h @@ -19,8 +19,15 @@ struct _SoupMessageMetrics { guint64 request_start; guint64 response_start; guint64 response_end; + + guint64 request_header_bytes_sent; + guint64 request_body_size; + guint64 request_body_bytes_sent; + guint64 response_header_bytes_received; + guint64 response_body_size; + guint64 response_body_bytes_received; }; -SoupMessageMetrics *soup_message_metrics_new (void); +SoupMessageMetrics *soup_message_metrics_new (void); G_END_DECLS diff --git a/libsoup/soup-message-metrics.c b/libsoup/soup-message-metrics.c index e3b642c3..41a9ef49 100644 --- a/libsoup/soup-message-metrics.c +++ b/libsoup/soup-message-metrics.c @@ -32,6 +32,10 @@ * fetch start event and finish with response end. All other events are optional. * An event can be 0 because it hasn't happened yet, because it's optional or * because the load failed before the event reached. + * + * Size metrics are expressed in bytes and aree updated while the #SoupMessage is + * being loaded. You can connect to different #SoupMessage signals to get the + * final result of every value. */ G_DEFINE_BOXED_TYPE (SoupMessageMetrics, soup_message_metrics, soup_message_metrics_copy, soup_message_metrics_free) @@ -243,3 +247,118 @@ soup_message_metrics_get_response_end (SoupMessageMetrics *metrics) return metrics->response_end; } + +/** + * soup_message_metrics_get_request_header_bytes_sent: + * @metrics: a #SoupMessageMetrics + * + * Get the number of bytes sent to the network for the request headers. + * This value is available right before #SoupMessage::wrote-headers signal + * is emitted, but you might get an intermediate value if called before. + * + * Returns: the request headers bytes sent + */ +guint64 +soup_message_metrics_get_request_header_bytes_sent (SoupMessageMetrics *metrics) +{ + g_return_val_if_fail (metrics != NULL, 0); + + return metrics->request_header_bytes_sent; +} + +/** + * soup_message_metrics_get_request_body_size: + * @metrics: a #SoupMessageMetrics + * + * Get the request body size in bytes. This is the size of the original body + * given to the request before any encoding is applied. This value is available + * right before #SoupMessage::wrote-body signal is emitted, but you might get + * an intermediate value if called before. + * + * Returns: the request body size + */ +guint64 +soup_message_metrics_get_request_body_size (SoupMessageMetrics *metrics) +{ + g_return_val_if_fail (metrics != NULL, 0); + + return metrics->request_body_size; +} + +/** + * soup_message_metrics_get_request_body_bytes_sent: + * @metrics: a #SoupMessageMetrics + * + * Get the number of bytes sent to the network for the request body. This is + * the size of the body sent, after encodings are applied, so it might be + * greater than the value returned by soup_message_metrics_get_request_body_size(). + * This value is available right before #SoupMessage::wrote-body signal is + * emitted, but you might get an intermediate value if called before. + * + * Returns: the request body bytes sent + */ +guint64 +soup_message_metrics_get_request_body_bytes_sent (SoupMessageMetrics *metrics) +{ + g_return_val_if_fail (metrics != NULL, 0); + + return metrics->request_body_bytes_sent; +} + +/** + * soup_message_metrics_get_response_header_bytes_received: + * @metrics: a #SoupMessageMetrics + * + * Get the number of bytes received from the network for the response headers. + * This value is available right before #SoupMessage::got-headers signal + * is emitted, but you might get an intermediate value if called before. + * For resources loaded from the disk cache this value is always 0. + * + * Returns: the response headers bytes received + */ +guint64 +soup_message_metrics_get_response_header_bytes_received (SoupMessageMetrics *metrics) +{ + g_return_val_if_fail (metrics != NULL, 0); + + return metrics->response_header_bytes_received; +} + +/** + * soup_message_metrics_get_response_body_size: + * @metrics: a #SoupMessageMetrics + * + * Get the response body size in bytes. This is the size of the body as given to the + * user after all encodings are applied, so it might be greater than the value + * returned by soup_message_metrics_get_response_body_bytes_received(). This value is + * available right before #SoupMessage::got-body signal is emitted, but you might get + * an intermediate value if called before. + * + * Returns: the response body size + */ +guint64 +soup_message_metrics_get_response_body_size (SoupMessageMetrics *metrics) +{ + g_return_val_if_fail (metrics != NULL, 0); + + return metrics->response_body_size; +} + +/** + * soup_message_metrics_get_response_body_bytes_received: + * @metrics: a #SoupMessageMetrics + * + * Get the number of bytes received from the network for the response body. This value is + * available right before #SoupMessage::got-body signal is emitted, but you might get + * an intermediate value if called before. + * For resources loaded from the disk cache this value is always 0. + * + * Returns: the response body bytes received + */ +guint64 +soup_message_metrics_get_response_body_bytes_received (SoupMessageMetrics *metrics) +{ + g_return_val_if_fail (metrics != NULL, 0); + + return metrics->response_body_bytes_received; +} diff --git a/libsoup/soup-message-metrics.h b/libsoup/soup-message-metrics.h index b5d3f9fb..1c12a62d 100644 --- a/libsoup/soup-message-metrics.h +++ b/libsoup/soup-message-metrics.h @@ -48,6 +48,24 @@ guint64 soup_message_metrics_get_response_start (SoupMessageMetrics SOUP_AVAILABLE_IN_ALL guint64 soup_message_metrics_get_response_end (SoupMessageMetrics *metrics); +SOUP_AVAILABLE_IN_ALL +guint64 soup_message_metrics_get_request_header_bytes_sent (SoupMessageMetrics *metrics); + +SOUP_AVAILABLE_IN_ALL +guint64 soup_message_metrics_get_request_body_size (SoupMessageMetrics *metrics); + +SOUP_AVAILABLE_IN_ALL +guint64 soup_message_metrics_get_request_body_bytes_sent (SoupMessageMetrics *metrics); + +SOUP_AVAILABLE_IN_ALL +guint64 soup_message_metrics_get_response_header_bytes_received (SoupMessageMetrics *metrics); + +SOUP_AVAILABLE_IN_ALL +guint64 soup_message_metrics_get_response_body_size (SoupMessageMetrics *metrics); + +SOUP_AVAILABLE_IN_ALL +guint64 soup_message_metrics_get_response_body_bytes_received (SoupMessageMetrics *metrics); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(SoupMessageMetrics, soup_message_metrics_free) G_END_DECLS |