summaryrefslogtreecommitdiff
path: root/libsoup
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup')
-rw-r--r--libsoup/meson.build3
-rw-r--r--libsoup/server/soup-auth-domain-basic.c27
-rw-r--r--libsoup/server/soup-auth-domain-basic.h10
-rw-r--r--libsoup/server/soup-auth-domain-digest.c31
-rw-r--r--libsoup/server/soup-auth-domain-digest.h8
-rw-r--r--libsoup/server/soup-auth-domain.c48
-rw-r--r--libsoup/server/soup-auth-domain.h46
-rw-r--r--libsoup/server/soup-server-io.c473
-rw-r--r--libsoup/server/soup-server-message-private.h50
-rw-r--r--libsoup/server/soup-server-message.c881
-rw-r--r--libsoup/server/soup-server-message.h79
-rw-r--r--libsoup/server/soup-server-private.h23
-rw-r--r--libsoup/server/soup-server.c625
-rw-r--r--libsoup/server/soup-server.h54
-rw-r--r--libsoup/soup-client-input-stream.c5
-rw-r--r--libsoup/soup-connection.c8
-rw-r--r--libsoup/soup-connection.h8
-rw-r--r--libsoup/soup-form.c26
-rw-r--r--libsoup/soup-form.h10
-rw-r--r--libsoup/soup-headers.c2
-rw-r--r--libsoup/soup-logger.c39
-rw-r--r--libsoup/soup-message-io-data.c266
-rw-r--r--libsoup/soup-message-io-data.h99
-rw-r--r--libsoup/soup-message-io.c468
-rw-r--r--libsoup/soup-message-private.h97
-rw-r--r--libsoup/soup-message.c427
-rw-r--r--libsoup/soup-message.h41
-rw-r--r--libsoup/soup-session.c9
-rw-r--r--libsoup/soup-status.c8
-rw-r--r--libsoup/soup-status.h5
-rw-r--r--libsoup/soup-types.h1
-rw-r--r--libsoup/soup.h1
-rw-r--r--libsoup/websocket/soup-websocket.c128
-rw-r--r--libsoup/websocket/soup-websocket.h34
34 files changed, 2240 insertions, 1800 deletions
diff --git a/libsoup/meson.build b/libsoup/meson.build
index c3a691d4..3a700870 100644
--- a/libsoup/meson.build
+++ b/libsoup/meson.build
@@ -44,6 +44,7 @@ soup_sources = [
'server/soup-path-map.c',
'server/soup-server.c',
'server/soup-server-io.c',
+ 'server/soup-server-message.c',
'websocket/soup-websocket.c',
'websocket/soup-websocket-connection.c',
@@ -67,6 +68,7 @@ soup_sources = [
'soup-message-body.c',
'soup-message-headers.c',
'soup-message-io.c',
+ 'soup-message-io-data.c',
'soup-message-queue.c',
'soup-method.c',
'soup-misc.c',
@@ -117,6 +119,7 @@ soup_introspection_headers = [
'server/soup-auth-domain-basic.h',
'server/soup-auth-domain-digest.h',
'server/soup-server.h',
+ 'server/soup-server-message.h',
'websocket/soup-websocket.h',
'websocket/soup-websocket-connection.h',
diff --git a/libsoup/server/soup-auth-domain-basic.c b/libsoup/server/soup-auth-domain-basic.c
index 9a850050..0cba37d2 100644
--- a/libsoup/server/soup-auth-domain-basic.c
+++ b/libsoup/server/soup-auth-domain-basic.c
@@ -204,8 +204,9 @@ pw_free (char *pw)
}
static gboolean
-parse_basic (SoupMessage *msg, const char *header,
- char **username, char **password)
+parse_basic (const char *header,
+ char **username,
+ char **password)
{
char *decoded, *colon;
gsize len, plen;
@@ -232,15 +233,16 @@ parse_basic (SoupMessage *msg, const char *header,
}
static char *
-soup_auth_domain_basic_accepts (SoupAuthDomain *domain, SoupMessage *msg,
- const char *header)
+soup_auth_domain_basic_accepts (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *header)
{
SoupAuthDomainBasicPrivate *priv =
soup_auth_domain_basic_get_instance_private (SOUP_AUTH_DOMAIN_BASIC (domain));
char *username, *password;
gboolean ok = FALSE;
- if (!parse_basic (msg, header, &username, &password))
+ if (!parse_basic (header, &username, &password))
return NULL;
if (priv->auth_callback) {
@@ -262,7 +264,8 @@ soup_auth_domain_basic_accepts (SoupAuthDomain *domain, SoupMessage *msg,
}
static char *
-soup_auth_domain_basic_challenge (SoupAuthDomain *domain, SoupMessage *msg)
+soup_auth_domain_basic_challenge (SoupAuthDomain *domain,
+ SoupServerMessage *msg)
{
GString *challenge;
@@ -272,18 +275,18 @@ soup_auth_domain_basic_challenge (SoupAuthDomain *domain, SoupMessage *msg)
}
static gboolean
-soup_auth_domain_basic_check_password (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- const char *password)
+soup_auth_domain_basic_check_password (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ const char *password)
{
const char *header;
char *msg_username, *msg_password;
gboolean ok;
- header = soup_message_headers_get_one (msg->request_headers,
+ header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg),
"Authorization");
- if (!parse_basic (msg, header, &msg_username, &msg_password))
+ if (!parse_basic (header, &msg_username, &msg_password))
return FALSE;
ok = (!strcmp (username, msg_username) &&
diff --git a/libsoup/server/soup-auth-domain-basic.h b/libsoup/server/soup-auth-domain-basic.h
index a260e891..d0397051 100644
--- a/libsoup/server/soup-auth-domain-basic.h
+++ b/libsoup/server/soup-auth-domain-basic.h
@@ -20,11 +20,11 @@ SOUP_AVAILABLE_IN_2_4
SoupAuthDomain *soup_auth_domain_basic_new (const char *optname1,
...) G_GNUC_NULL_TERMINATED;
-typedef gboolean (*SoupAuthDomainBasicAuthCallback) (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- const char *password,
- gpointer user_data);
+typedef gboolean (*SoupAuthDomainBasicAuthCallback) (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ const char *password,
+ gpointer user_data);
SOUP_AVAILABLE_IN_2_4
void soup_auth_domain_basic_set_auth_callback (SoupAuthDomain *domain,
diff --git a/libsoup/server/soup-auth-domain-digest.c b/libsoup/server/soup-auth-domain-digest.c
index ae9fa266..1ad34a91 100644
--- a/libsoup/server/soup-auth-domain-digest.c
+++ b/libsoup/server/soup-auth-domain-digest.c
@@ -191,9 +191,11 @@ soup_auth_domain_digest_set_auth_callback (SoupAuthDomain *domain,
}
static gboolean
-check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg,
- GHashTable *params, const char *username,
- const char *hex_urp)
+check_hex_urp (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ GHashTable *params,
+ const char *username,
+ const char *hex_urp)
{
const char *uri, *qop, *realm, *msg_username;
const char *nonce, *nc, *cnonce, *response;
@@ -210,7 +212,7 @@ check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg,
if (!uri)
return FALSE;
- req_uri = soup_message_get_uri (msg);
+ req_uri = soup_server_message_get_uri (msg);
dig_uri = soup_uri_new (uri);
if (dig_uri) {
if (!soup_uri_equal (dig_uri, req_uri)) {
@@ -263,7 +265,8 @@ check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg,
soup_auth_digest_compute_hex_a1 (hex_urp,
SOUP_AUTH_DIGEST_ALGORITHM_MD5,
nonce, cnonce, hex_a1);
- soup_auth_digest_compute_response (msg->method, uri,
+ soup_auth_digest_compute_response (soup_server_message_get_method (msg),
+ uri,
hex_a1,
SOUP_AUTH_DIGEST_QOP_AUTH,
nonce, cnonce, nonce_count,
@@ -272,8 +275,9 @@ check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg,
}
static char *
-soup_auth_domain_digest_accepts (SoupAuthDomain *domain, SoupMessage *msg,
- const char *header)
+soup_auth_domain_digest_accepts (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *header)
{
SoupAuthDomainDigestPrivate *priv =
soup_auth_domain_digest_get_instance_private (SOUP_AUTH_DOMAIN_DIGEST (domain));
@@ -317,7 +321,8 @@ soup_auth_domain_digest_accepts (SoupAuthDomain *domain, SoupMessage *msg,
}
static char *
-soup_auth_domain_digest_challenge (SoupAuthDomain *domain, SoupMessage *msg)
+soup_auth_domain_digest_challenge (SoupAuthDomain *domain,
+ SoupServerMessage *msg)
{
GString *str;
@@ -366,10 +371,10 @@ soup_auth_domain_digest_encode_password (const char *username,
}
static gboolean
-soup_auth_domain_digest_check_password (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- const char *password)
+soup_auth_domain_digest_check_password (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ const char *password)
{
const char *header;
GHashTable *params;
@@ -377,7 +382,7 @@ soup_auth_domain_digest_check_password (SoupAuthDomain *domain,
char hex_urp[33];
gboolean accept;
- header = soup_message_headers_get_one (msg->request_headers,
+ header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg),
"Authorization");
if (!header || (strncmp (header, "Digest ", 7) != 0))
return FALSE;
diff --git a/libsoup/server/soup-auth-domain-digest.h b/libsoup/server/soup-auth-domain-digest.h
index 523497ce..c5630470 100644
--- a/libsoup/server/soup-auth-domain-digest.h
+++ b/libsoup/server/soup-auth-domain-digest.h
@@ -20,10 +20,10 @@ SOUP_AVAILABLE_IN_2_4
SoupAuthDomain *soup_auth_domain_digest_new (const char *optname1,
...) G_GNUC_NULL_TERMINATED;
-typedef char * (*SoupAuthDomainDigestAuthCallback) (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- gpointer user_data);
+typedef char * (*SoupAuthDomainDigestAuthCallback) (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ gpointer user_data);
SOUP_AVAILABLE_IN_2_4
void soup_auth_domain_digest_set_auth_callback (SoupAuthDomain *domain,
diff --git a/libsoup/server/soup-auth-domain.c b/libsoup/server/soup-auth-domain.c
index 8785c474..f22cd9ea 100644
--- a/libsoup/server/soup-auth-domain.c
+++ b/libsoup/server/soup-auth-domain.c
@@ -364,7 +364,7 @@ soup_auth_domain_remove_path (SoupAuthDomain *domain, const char *path)
/**
* SoupAuthDomainFilter:
* @domain: a #SoupAuthDomain
- * @msg: a #SoupMessage
+ * @msg: a #SoupServerMessage
* @user_data: the data passed to soup_auth_domain_set_filter()
*
* The prototype for a #SoupAuthDomain filter; see
@@ -444,7 +444,7 @@ soup_auth_domain_get_realm (SoupAuthDomain *domain)
/**
* SoupAuthDomainGenericAuthCallback:
* @domain: a #SoupAuthDomain
- * @msg: the #SoupMessage being authenticated
+ * @msg: the #SoupServerMessage being authenticated
* @username: the username from @msg
* @user_data: the data passed to
* soup_auth_domain_set_generic_auth_callback()
@@ -504,9 +504,9 @@ soup_auth_domain_set_generic_auth_callback (SoupAuthDomain *domain,
}
gboolean
-soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username)
+soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username)
{
SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
@@ -519,7 +519,7 @@ soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
/**
* soup_auth_domain_check_password:
* @domain: a #SoupAuthDomain
- * @msg: a #SoupMessage
+ * @msg: a #SoupServerMessage
* @username: a username
* @password: a password
*
@@ -530,10 +530,10 @@ soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
* Return value: whether or not the message is authenticated
**/
gboolean
-soup_auth_domain_check_password (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- const char *password)
+soup_auth_domain_check_password (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ const char *password)
{
return SOUP_AUTH_DOMAIN_GET_CLASS (domain)->check_password (domain, msg,
username,
@@ -543,7 +543,7 @@ soup_auth_domain_check_password (SoupAuthDomain *domain,
/**
* soup_auth_domain_covers:
* @domain: a #SoupAuthDomain
- * @msg: a #SoupMessage
+ * @msg: a #SoupServerMessage
*
* Checks if @domain requires @msg to be authenticated (according to
* its paths and filter function). This does not actually look at
@@ -556,13 +556,14 @@ soup_auth_domain_check_password (SoupAuthDomain *domain,
* Return value: %TRUE if @domain requires @msg to be authenticated
**/
gboolean
-soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg)
+soup_auth_domain_covers (SoupAuthDomain *domain,
+ SoupServerMessage *msg)
{
SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
const char *path;
if (!priv->proxy) {
- path = soup_message_get_uri (msg)->path;
+ path = soup_server_message_get_uri (msg)->path;
if (!soup_path_map_lookup (priv->paths, path))
return FALSE;
}
@@ -576,7 +577,7 @@ soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg)
/**
* soup_auth_domain_accepts:
* @domain: a #SoupAuthDomain
- * @msg: a #SoupMessage
+ * @msg: a #SoupServerMessage
*
* Checks if @msg contains appropriate authorization for @domain to
* accept it. Mirroring soup_auth_domain_covers(), this does not check
@@ -590,12 +591,13 @@ soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg)
* as, if in fact it has authenticated. %NULL otherwise.
**/
char *
-soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg)
+soup_auth_domain_accepts (SoupAuthDomain *domain,
+ SoupServerMessage *msg)
{
SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
const char *header;
- header = soup_message_headers_get_one (msg->request_headers,
+ header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg),
priv->proxy ?
"Proxy-Authorization" :
"Authorization");
@@ -607,7 +609,7 @@ soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg)
/**
* soup_auth_domain_challenge: (virtual challenge)
* @domain: a #SoupAuthDomain
- * @msg: a #SoupMessage
+ * @msg: a #SoupServerMessage
*
* Adds a "WWW-Authenticate" or "Proxy-Authenticate" header to @msg,
* requesting that the client authenticate, and sets @msg's status
@@ -617,16 +619,18 @@ soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg)
* anyone else.
**/
void
-soup_auth_domain_challenge (SoupAuthDomain *domain, SoupMessage *msg)
+soup_auth_domain_challenge (SoupAuthDomain *domain,
+ SoupServerMessage *msg)
{
SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
char *challenge;
challenge = SOUP_AUTH_DOMAIN_GET_CLASS (domain)->challenge (domain, msg);
- soup_message_set_status (msg, priv->proxy ?
- SOUP_STATUS_PROXY_UNAUTHORIZED :
- SOUP_STATUS_UNAUTHORIZED);
- soup_message_headers_append (msg->response_headers,
+ soup_server_message_set_status (msg, priv->proxy ?
+ SOUP_STATUS_PROXY_UNAUTHORIZED :
+ SOUP_STATUS_UNAUTHORIZED,
+ NULL);
+ soup_message_headers_append (soup_server_message_get_response_headers (msg),
priv->proxy ?
"Proxy-Authenticate" :
"WWW-Authenticate",
diff --git a/libsoup/server/soup-auth-domain.h b/libsoup/server/soup-auth-domain.h
index 397dc53b..c904d01b 100644
--- a/libsoup/server/soup-auth-domain.h
+++ b/libsoup/server/soup-auth-domain.h
@@ -16,15 +16,15 @@ G_DECLARE_DERIVABLE_TYPE (SoupAuthDomain, soup_auth_domain, SOUP, AUTH_DOMAIN, G
struct _SoupAuthDomainClass {
GObjectClass parent_class;
- char * (*accepts) (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *header);
- char * (*challenge) (SoupAuthDomain *domain,
- SoupMessage *msg);
- gboolean (*check_password) (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- const char *password);
+ char * (*accepts) (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *header);
+ char * (*challenge) (SoupAuthDomain *domain,
+ SoupServerMessage *msg);
+ gboolean (*check_password) (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ const char *password);
gpointer padding[6];
};
@@ -37,14 +37,14 @@ struct _SoupAuthDomainClass {
#define SOUP_AUTH_DOMAIN_GENERIC_AUTH_CALLBACK "generic-auth-callback"
#define SOUP_AUTH_DOMAIN_GENERIC_AUTH_DATA "generic-auth-data"
-typedef gboolean (*SoupAuthDomainFilter) (SoupAuthDomain *domain,
- SoupMessage *msg,
- gpointer user_data);
+typedef gboolean (*SoupAuthDomainFilter) (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ gpointer user_data);
-typedef gboolean (*SoupAuthDomainGenericAuthCallback) (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username,
- gpointer user_data);
+typedef gboolean (*SoupAuthDomainGenericAuthCallback) (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username,
+ gpointer user_data);
SOUP_AVAILABLE_IN_2_4
void soup_auth_domain_add_path (SoupAuthDomain *domain,
@@ -69,24 +69,24 @@ void soup_auth_domain_set_generic_auth_callback (SoupAuthDomain *domain,
GDestroyNotify dnotify);
SOUP_AVAILABLE_IN_2_4
gboolean soup_auth_domain_check_password (SoupAuthDomain *domain,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *username,
const char *password);
SOUP_AVAILABLE_IN_2_4
gboolean soup_auth_domain_covers (SoupAuthDomain *domain,
- SoupMessage *msg);
+ SoupServerMessage *msg);
SOUP_AVAILABLE_IN_2_4
char *soup_auth_domain_accepts (SoupAuthDomain *domain,
- SoupMessage *msg);
+ SoupServerMessage *msg);
SOUP_AVAILABLE_IN_2_4
void soup_auth_domain_challenge (SoupAuthDomain *domain,
- SoupMessage *msg);
+ SoupServerMessage *msg);
/* protected */
SOUP_AVAILABLE_IN_2_4
-gboolean soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
- SoupMessage *msg,
- const char *username);
+gboolean soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
+ SoupServerMessage *msg,
+ const char *username);
G_END_DECLS
diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c
index 4556635f..e94a366e 100644
--- a/libsoup/server/soup-server-io.c
+++ b/libsoup/server/soup-server-io.c
@@ -15,34 +15,115 @@
#include "soup-body-input-stream.h"
#include "soup-body-output-stream.h"
#include "soup-filter-input-stream.h"
-#include "soup-message-private.h"
+#include "soup-server-message-private.h"
#include "soup-misc.h"
#include "soup-socket-private.h"
+struct _SoupServerMessageIOData {
+ SoupMessageIOData base;
+
+ GBytes *write_chunk;
+ goffset write_body_offset;
+
+ GSource *unpause_source;
+};
+
#define RESPONSE_BLOCK_SIZE 8192
#define HEADER_SIZE_LIMIT (64 * 1024)
+void
+soup_server_message_io_data_free (SoupServerMessageIOData *io)
+{
+ if (!io)
+ return;
+
+ soup_message_io_data_cleanup (&io->base);
+
+ if (io->unpause_source) {
+ g_source_destroy (io->unpause_source);
+ g_source_unref (io->unpause_source);
+ io->unpause_source = NULL;
+ }
+
+ g_clear_pointer (&io->write_chunk, g_bytes_unref);
+
+ g_slice_free (SoupServerMessageIOData, io);
+}
+
+void
+soup_server_message_io_finished (SoupServerMessage *msg)
+{
+ SoupServerMessageIOData *io;
+ SoupMessageIOCompletionFn completion_cb;
+ gpointer completion_data;
+ SoupMessageIOCompletion completion;
+
+ io = soup_server_message_get_io_data (msg);
+ if (!io)
+ return;
+
+ completion_cb = io->base.completion_cb;
+ completion_data = io->base.completion_data;
+
+ if ((io->base.read_state >= SOUP_MESSAGE_IO_STATE_FINISHING &&
+ io->base.write_state >= SOUP_MESSAGE_IO_STATE_FINISHING))
+ completion = SOUP_MESSAGE_IO_COMPLETE;
+ else
+ completion = SOUP_MESSAGE_IO_INTERRUPTED;
+
+ g_object_ref (msg);
+ soup_server_message_set_io_data (msg, NULL);
+ if (completion_cb)
+ completion_cb (G_OBJECT (msg), completion, completion_data);
+ g_object_unref (msg);
+}
+
+GIOStream *
+soup_server_message_io_steal (SoupServerMessage *msg)
+{
+ SoupServerMessageIOData *io;
+ SoupMessageIOCompletionFn completion_cb;
+ gpointer completion_data;
+ GIOStream *iostream;
+
+ io = soup_server_message_get_io_data (msg);
+ if (!io || !io->base.iostream)
+ return NULL;
+
+ iostream = g_object_ref (io->base.iostream);
+ completion_cb = io->base.completion_cb;
+ completion_data = io->base.completion_data;
+
+ g_object_ref (msg);
+ soup_server_message_set_io_data (msg, NULL);
+ if (completion_cb)
+ completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data);
+ g_object_unref (msg);
+
+ return iostream;
+}
+
static void
closed_async (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GOutputStream *body_ostream = G_OUTPUT_STREAM (source);
- SoupMessage *msg = user_data;
- SoupMessageIOData *io;
+ SoupServerMessage *msg = user_data;
+ SoupServerMessageIOData *io;
GCancellable *async_wait;
- io = soup_message_get_io_data (msg);
- if (!io || !io->async_wait || io->body_ostream != body_ostream) {
+ io = soup_server_message_get_io_data (msg);
+ if (!io || !io->base.async_wait || io->base.body_ostream != body_ostream) {
g_object_unref (msg);
return;
}
- g_output_stream_close_finish (body_ostream, result, &io->async_error);
- g_clear_object (&io->body_ostream);
+ g_output_stream_close_finish (body_ostream, result, &io->base.async_error);
+ g_clear_object (&io->base.body_ostream);
- async_wait = io->async_wait;
- io->async_wait = NULL;
+ async_wait = io->base.async_wait;
+ io->base.async_wait = NULL;
g_cancellable_cancel (async_wait);
g_object_unref (async_wait);
@@ -76,12 +157,19 @@ closed_async (GObject *source,
*/
static void
-handle_partial_get (SoupMessage *msg)
+handle_partial_get (SoupServerMessage *msg)
{
SoupRange *ranges;
int nranges;
GBytes *full_response;
guint status;
+ SoupMessageHeaders *request_headers;
+ SoupMessageHeaders *response_headers;
+ SoupMessageBody *response_body;
+
+ request_headers = soup_server_message_get_request_headers (msg);
+ response_headers = soup_server_message_get_response_headers (msg);
+ response_body = soup_server_message_get_response_body (msg);
/* Make sure the message is set up right for us to return a
* partial response; it has to be a GET, the status must be
@@ -89,50 +177,50 @@ handle_partial_get (SoupMessage *msg)
* Content), and the SoupServer must have already filled in
* the response body
*/
- if (msg->method != SOUP_METHOD_GET ||
- msg->status_code != SOUP_STATUS_OK ||
- soup_message_headers_get_encoding (msg->response_headers) !=
+ if (soup_server_message_get_method (msg) != SOUP_METHOD_GET ||
+ soup_server_message_get_status (msg, NULL) != SOUP_STATUS_OK ||
+ soup_message_headers_get_encoding (response_headers) !=
SOUP_ENCODING_CONTENT_LENGTH ||
- msg->response_body->length == 0 ||
- !soup_message_body_get_accumulate (msg->response_body))
+ response_body->length == 0 ||
+ !soup_message_body_get_accumulate (response_body))
return;
/* Oh, and there has to have been a valid Range header on the
* request, of course.
*/
- status = soup_message_headers_get_ranges_internal (msg->request_headers,
- msg->response_body->length,
+ status = soup_message_headers_get_ranges_internal (request_headers,
+ response_body->length,
TRUE,
&ranges, &nranges);
if (status == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE) {
- soup_message_set_status (msg, status);
- soup_message_body_truncate (msg->response_body);
+ soup_server_message_set_status (msg, status, NULL);
+ soup_message_body_truncate (response_body);
return;
} else if (status != SOUP_STATUS_PARTIAL_CONTENT)
return;
- full_response = soup_message_body_flatten (msg->response_body);
+ full_response = soup_message_body_flatten (response_body);
if (!full_response) {
- soup_message_headers_free_ranges (msg->request_headers, ranges);
+ soup_message_headers_free_ranges (request_headers, ranges);
return;
}
- soup_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT);
- soup_message_body_truncate (msg->response_body);
+ soup_server_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT, NULL);
+ soup_message_body_truncate (response_body);
if (nranges == 1) {
GBytes *range_buf;
/* Single range, so just set Content-Range and fix the body. */
- soup_message_headers_set_content_range (msg->response_headers,
+ soup_message_headers_set_content_range (response_headers,
ranges[0].start,
ranges[0].end,
g_bytes_get_size (full_response));
range_buf = g_bytes_new_from_bytes (full_response,
ranges[0].start,
ranges[0].end - ranges[0].start + 1);
- soup_message_body_append_bytes (msg->response_body, range_buf);
+ soup_message_body_append_bytes (response_body, range_buf);
g_bytes_unref (range_buf);
} else {
SoupMultipart *multipart;
@@ -147,7 +235,7 @@ handle_partial_get (SoupMessage *msg)
*/
multipart = soup_multipart_new ("multipart/byteranges");
- content_type = soup_message_headers_get_one (msg->response_headers,
+ content_type = soup_message_headers_get_one (response_headers,
"Content-Type");
for (i = 0; i < nranges; i++) {
part_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
@@ -169,52 +257,62 @@ handle_partial_get (SoupMessage *msg)
g_bytes_unref (part_body);
}
- soup_multipart_to_message (multipart, msg->response_headers, &body);
- soup_message_body_append_bytes (msg->response_body, body);
+ soup_multipart_to_message (multipart, response_headers, &body);
+ soup_message_body_append_bytes (response_body, body);
g_bytes_unref (body);
soup_multipart_free (multipart);
}
g_bytes_unref (full_response);
- soup_message_headers_free_ranges (msg->request_headers, ranges);
+ soup_message_headers_free_ranges (request_headers, ranges);
}
static void
-write_headers (SoupMessage *msg,
- GString *headers,
- SoupEncoding *encoding)
+write_headers (SoupServerMessage *msg,
+ GString *headers,
+ SoupEncoding *encoding)
{
SoupEncoding claimed_encoding;
SoupMessageHeadersIter iter;
const char *name, *value;
+ guint status_code;
+ const char *reason_phrase;
+ const char *method;
+ SoupMessageHeaders *response_headers;
+ SoupMessageBody *response_body;
- if (msg->status_code == 0)
- soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ if (soup_server_message_get_status (msg, NULL) == 0)
+ soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, NULL);
handle_partial_get (msg);
+ status_code = soup_server_message_get_status (msg, &reason_phrase);
+
g_string_append_printf (headers, "HTTP/1.%c %d %s\r\n",
- soup_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1',
- msg->status_code, msg->reason_phrase);
-
- claimed_encoding = soup_message_headers_get_encoding (msg->response_headers);
- if ((msg->method == SOUP_METHOD_HEAD ||
- msg->status_code == SOUP_STATUS_NO_CONTENT ||
- msg->status_code == SOUP_STATUS_NOT_MODIFIED ||
- SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) ||
- (msg->method == SOUP_METHOD_CONNECT &&
- SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)))
+ soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1',
+ status_code, reason_phrase);
+
+ method = soup_server_message_get_method (msg);
+ response_headers = soup_server_message_get_response_headers (msg);
+ claimed_encoding = soup_message_headers_get_encoding (response_headers);
+ if ((method == SOUP_METHOD_HEAD ||
+ status_code == SOUP_STATUS_NO_CONTENT ||
+ status_code == SOUP_STATUS_NOT_MODIFIED ||
+ SOUP_STATUS_IS_INFORMATIONAL (status_code)) ||
+ (method == SOUP_METHOD_CONNECT &&
+ SOUP_STATUS_IS_SUCCESSFUL (status_code)))
*encoding = SOUP_ENCODING_NONE;
else
*encoding = claimed_encoding;
+ response_body = soup_server_message_get_response_body (msg);
if (claimed_encoding == SOUP_ENCODING_CONTENT_LENGTH &&
- !soup_message_headers_get_content_length (msg->response_headers)) {
- soup_message_headers_set_content_length (msg->response_headers,
- msg->response_body->length);
+ !soup_message_headers_get_content_length (response_headers)) {
+ soup_message_headers_set_content_length (response_headers,
+ response_body->length);
}
- soup_message_headers_iter_init (&iter, msg->response_headers);
+ soup_message_headers_iter_init (&iter, response_headers);
while (soup_message_headers_iter_next (&iter, &name, &value))
g_string_append_printf (headers, "%s: %s\r\n", name, value);
g_string_append (headers, "\r\n");
@@ -227,13 +325,15 @@ write_headers (SoupMessage *msg,
* socket not writable, write is complete, etc).
*/
static gboolean
-io_write (SoupMessage *msg,
- GCancellable *cancellable,
- GError **error)
+io_write (SoupServerMessage *msg,
+ GCancellable *cancellable,
+ GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg);
+ SoupMessageIOData *io = &server_io->base;
GBytes *chunk;
gssize nwrote;
+ guint status_code;
if (io->async_error) {
g_propagate_error (error, io->async_error);
@@ -248,11 +348,12 @@ io_write (SoupMessage *msg,
switch (io->write_state) {
case SOUP_MESSAGE_IO_STATE_HEADERS:
- if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && msg->status_code == 0) {
+ status_code = soup_server_message_get_status (msg, NULL);
+ if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && status_code == 0) {
/* Client requested "Expect: 100-continue", and
* server did not set an error.
*/
- soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
+ soup_server_message_set_status (msg, SOUP_STATUS_CONTINUE, NULL);
}
if (!io->write_buf->len)
@@ -272,8 +373,9 @@ io_write (SoupMessage *msg,
io->written = 0;
g_string_truncate (io->write_buf, 0);
- if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
- if (msg->status_code == SOUP_STATUS_CONTINUE) {
+ status_code = soup_server_message_get_status (msg, NULL);
+ if (SOUP_STATUS_IS_INFORMATIONAL (status_code)) {
+ if (status_code == SOUP_STATUS_CONTINUE) {
/* Stop and wait for the body now */
io->write_state =
SOUP_MESSAGE_IO_STATE_BLOCKING;
@@ -288,20 +390,20 @@ io_write (SoupMessage *msg,
*/
}
- soup_message_wrote_informational (msg);
+ soup_server_message_wrote_informational (msg);
/* If this was "101 Switching Protocols", then
* the server probably stole the connection...
*/
- if (io != soup_message_get_io_data (msg))
+ if (server_io != soup_server_message_get_io_data (msg))
return FALSE;
- soup_message_cleanup_response (msg);
+ soup_server_message_cleanup_response (msg);
break;
}
if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH)
- io->write_length = soup_message_headers_get_content_length (msg->response_headers);
+ io->write_length = soup_message_headers_get_content_length (soup_server_message_get_response_headers (msg));
io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START;
/* If the client was waiting for a Continue
@@ -311,7 +413,7 @@ io_write (SoupMessage *msg,
if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
- soup_message_wrote_headers (msg);
+ soup_server_message_wrote_headers (msg);
break;
case SOUP_MESSAGE_IO_STATE_BODY_START:
@@ -329,51 +431,53 @@ io_write (SoupMessage *msg,
break;
}
- if (!io->write_chunk) {
- io->write_chunk = soup_message_body_get_chunk (msg->response_body, io->write_body_offset);
- if (!io->write_chunk) {
- soup_message_io_pause (msg);
+ if (!server_io->write_chunk) {
+ server_io->write_chunk = soup_message_body_get_chunk (soup_server_message_get_response_body (msg),
+ server_io->write_body_offset);
+ if (!server_io->write_chunk) {
+ soup_server_message_io_pause (msg);
return FALSE;
}
- if (!g_bytes_get_size (io->write_chunk)) {
+ if (!g_bytes_get_size (server_io->write_chunk)) {
io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
break;
}
}
nwrote = g_pollable_stream_write (io->body_ostream,
- (guchar*)g_bytes_get_data (io->write_chunk, NULL) + io->written,
- g_bytes_get_size (io->write_chunk) - io->written,
+ (guchar*)g_bytes_get_data (server_io->write_chunk, NULL) + io->written,
+ g_bytes_get_size (server_io->write_chunk) - io->written,
FALSE,
cancellable, error);
if (nwrote == -1)
return FALSE;
- chunk = g_bytes_new_from_bytes (io->write_chunk, io->written, nwrote);
+ chunk = g_bytes_new_from_bytes (server_io->write_chunk, io->written, nwrote);
io->written += nwrote;
if (io->write_length)
io->write_length -= nwrote;
- if (io->written == g_bytes_get_size (io->write_chunk))
+ if (io->written == g_bytes_get_size (server_io->write_chunk))
io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DATA;
- soup_message_wrote_body_data (msg, chunk);
+ soup_server_message_wrote_body_data (msg, g_bytes_get_size (chunk));
g_bytes_unref (chunk);
break;
case SOUP_MESSAGE_IO_STATE_BODY_DATA:
io->written = 0;
- if (g_bytes_get_size (io->write_chunk) == 0) {
+ if (g_bytes_get_size (server_io->write_chunk) == 0) {
io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
break;
}
- soup_message_body_wrote_chunk (msg->response_body, io->write_chunk);
- io->write_body_offset += g_bytes_get_size (io->write_chunk);
- g_clear_pointer (&io->write_chunk, g_bytes_unref);
+ soup_message_body_wrote_chunk (soup_server_message_get_response_body (msg),
+ server_io->write_chunk);
+ server_io->write_body_offset += g_bytes_get_size (server_io->write_chunk);
+ g_clear_pointer (&server_io->write_chunk, g_bytes_unref);
io->write_state = SOUP_MESSAGE_IO_STATE_BODY;
- soup_message_wrote_chunk (msg);
+ soup_server_message_wrote_chunk (msg);
break;
case SOUP_MESSAGE_IO_STATE_BODY_FLUSH:
@@ -397,7 +501,7 @@ io_write (SoupMessage *msg,
case SOUP_MESSAGE_IO_STATE_BODY_DONE:
io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
- soup_message_wrote_body (msg);
+ soup_server_message_wrote_body (msg);
break;
case SOUP_MESSAGE_IO_STATE_FINISHING:
@@ -435,55 +539,52 @@ parse_connect_authority (const char *req_path)
}
static guint
-parse_headers (SoupMessage *msg,
- char *headers,
- guint headers_len,
- SoupEncoding *encoding,
- SoupSocket *sock,
- GError **error)
+parse_headers (SoupServerMessage *msg,
+ char *headers,
+ guint headers_len,
+ SoupEncoding *encoding,
+ GError **error)
{
char *req_method, *req_path, *url;
SoupHTTPVersion version;
+ SoupSocket *sock;
const char *req_host;
guint status;
SoupURI *uri;
+ SoupMessageHeaders *request_headers;
+
+ request_headers = soup_server_message_get_request_headers (msg);
status = soup_headers_parse_request (headers, headers_len,
- msg->request_headers,
+ request_headers,
&req_method,
&req_path,
&version);
- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- if (status == SOUP_STATUS_MALFORMED) {
- g_set_error_literal (error, SOUP_REQUEST_ERROR,
- SOUP_REQUEST_ERROR_PARSING,
- _("Could not parse HTTP request"));
- }
+ if (!SOUP_STATUS_IS_SUCCESSFUL (status))
return status;
- }
- g_object_set (G_OBJECT (msg),
- SOUP_MESSAGE_METHOD, req_method,
- SOUP_MESSAGE_HTTP_VERSION, version,
- NULL);
+ soup_server_message_set_method (msg, req_method);
+ soup_server_message_set_http_version (msg, version);
g_free (req_method);
/* Handle request body encoding */
- *encoding = soup_message_headers_get_encoding (msg->request_headers);
+ *encoding = soup_message_headers_get_encoding (request_headers);
if (*encoding == SOUP_ENCODING_UNRECOGNIZED) {
- if (soup_message_headers_get_list (msg->request_headers, "Transfer-Encoding"))
+ if (soup_message_headers_get_list (request_headers, "Transfer-Encoding"))
return SOUP_STATUS_NOT_IMPLEMENTED;
else
return SOUP_STATUS_BAD_REQUEST;
}
/* Generate correct context for request */
- req_host = soup_message_headers_get_one (msg->request_headers, "Host");
+ req_host = soup_message_headers_get_one (request_headers, "Host");
if (req_host && strchr (req_host, '/')) {
g_free (req_path);
return SOUP_STATUS_BAD_REQUEST;
}
+ sock = soup_server_message_get_soup_socket (msg);
+
if (!strcmp (req_path, "*") && req_host) {
/* Eg, "OPTIONS * HTTP/1.1" */
url = g_strdup_printf ("%s://%s",
@@ -493,7 +594,7 @@ parse_headers (SoupMessage *msg,
if (uri)
soup_uri_set_path (uri, "*");
g_free (url);
- } else if (msg->method == SOUP_METHOD_CONNECT) {
+ } else if (soup_server_message_get_method (msg) == SOUP_METHOD_CONNECT) {
/* Authority */
uri = parse_connect_authority (req_path);
} else if (*req_path != '/') {
@@ -505,7 +606,7 @@ parse_headers (SoupMessage *msg,
req_host, req_path);
uri = soup_uri_new (url);
g_free (url);
- } else if (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) {
+ } else if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) {
/* No Host header, no AbsoluteUri */
GInetSocketAddress *addr = soup_socket_get_local_address (sock);
GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
@@ -530,7 +631,7 @@ parse_headers (SoupMessage *msg,
return SOUP_STATUS_BAD_REQUEST;
}
- soup_message_set_uri (msg, uri);
+ soup_server_message_set_uri (msg, uri);
soup_uri_free (uri);
return SOUP_STATUS_OK;
@@ -543,27 +644,33 @@ parse_headers (SoupMessage *msg,
* socket not readable, read is complete, etc).
*/
static gboolean
-io_read (SoupMessage *msg,
- GCancellable *cancellable,
- GError **error)
+io_read (SoupServerMessage *msg,
+ GCancellable *cancellable,
+ GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg);
+ SoupMessageIOData *io = &server_io->base;
gssize nread;
guint status;
+ SoupMessageHeaders *request_headers;
switch (io->read_state) {
case SOUP_MESSAGE_IO_STATE_HEADERS:
- if (!soup_message_io_read_headers (msg, io->istream, io->read_header_buf, FALSE, cancellable, error))
+ if (!soup_message_io_data_read_headers (io, FALSE, cancellable, error)) {
+ if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT))
+ soup_server_message_set_status (msg, SOUP_STATUS_MALFORMED, NULL);
return FALSE;
+ }
status = parse_headers (msg,
(char *)io->read_header_buf->data,
io->read_header_buf->len,
&io->read_encoding,
- io->sock,
error);
g_byte_array_set_size (io->read_header_buf, 0);
+ request_headers = soup_server_message_get_request_headers (msg);
+
if (status != SOUP_STATUS_OK) {
/* Either we couldn't parse the headers, or they
* indicated something that would mean we wouldn't
@@ -572,14 +679,13 @@ io_read (SoupMessage *msg,
* reading, and make sure the connection gets
* closed when we're done.
*/
- soup_message_set_status (msg, status);
- soup_message_headers_append (msg->request_headers,
- "Connection", "close");
+ soup_server_message_set_status (msg, status, NULL);
+ soup_message_headers_append (request_headers, "Connection", "close");
io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
break;
}
- if (soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
+ if (soup_message_headers_get_expectations (request_headers) & SOUP_EXPECTATION_CONTINUE) {
/* We must return a status code and response
* headers to the client; either an error to
* be set by a got-headers handler below, or
@@ -591,11 +697,11 @@ io_read (SoupMessage *msg,
io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START;
if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH)
- io->read_length = soup_message_headers_get_content_length (msg->request_headers);
+ io->read_length = soup_message_headers_get_content_length (request_headers);
else
io->read_length = -1;
- soup_message_got_headers (msg);
+ soup_server_message_got_headers (msg);
break;
case SOUP_MESSAGE_IO_STATE_BODY_START:
@@ -618,10 +724,13 @@ io_read (SoupMessage *msg,
FALSE,
cancellable, error);
if (nread > 0) {
- if (msg->request_body) {
+ SoupMessageBody *request_body;
+
+ request_body = soup_server_message_get_request_body (msg);
+ if (request_body) {
GBytes *bytes = g_bytes_new (buf, nread);
- soup_message_body_got_chunk (msg->request_body, bytes);
- soup_message_got_chunk (msg, bytes);
+ soup_message_body_got_chunk (request_body, bytes);
+ soup_server_message_got_chunk (msg, bytes);
g_bytes_unref (bytes);
}
break;
@@ -637,7 +746,7 @@ io_read (SoupMessage *msg,
case SOUP_MESSAGE_IO_STATE_BODY_DONE:
io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
- soup_message_got_body (msg);
+ soup_server_message_got_body (msg);
break;
case SOUP_MESSAGE_IO_STATE_FINISHING:
@@ -653,13 +762,14 @@ io_read (SoupMessage *msg,
}
static gboolean
-io_run_until (SoupMessage *msg,
+io_run_until (SoupServerMessage *msg,
SoupMessageIOState read_state,
SoupMessageIOState write_state,
GCancellable *cancellable,
GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg);
+ SoupMessageIOData *io = &server_io->base;
gboolean progress = TRUE, done;
GError *my_error = NULL;
@@ -674,7 +784,7 @@ io_run_until (SoupMessage *msg,
g_object_ref (msg);
- while (progress && soup_message_get_io_data (msg) == io && !io->paused && !io->async_wait &&
+ while (progress && soup_server_message_get_io_data (msg) == server_io && !io->paused && !io->async_wait &&
(io->read_state < read_state || io->write_state < write_state)) {
if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
@@ -689,7 +799,7 @@ io_run_until (SoupMessage *msg,
g_propagate_error (error, my_error);
g_object_unref (msg);
return FALSE;
- } else if (soup_message_get_io_data (msg) != io) {
+ } else if (soup_server_message_get_io_data (msg) != server_io) {
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_CANCELLED,
_("Operation was cancelled"));
@@ -716,22 +826,22 @@ io_run_until (SoupMessage *msg,
return done;
}
-static void io_run (SoupMessage *msg);
+static void io_run (SoupServerMessage *msg);
static gboolean
-io_run_ready (SoupMessage *msg,
- gpointer user_data)
+io_run_ready (SoupServerMessage *msg,
+ gpointer user_data)
{
io_run (msg);
return FALSE;
}
static void
-io_run (SoupMessage *msg)
+io_run (SoupServerMessage *msg)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg);
+ SoupMessageIOData *io = &server_io->base;
GError *error = NULL;
- GCancellable *cancellable;
if (io->io_source) {
g_source_destroy (io->io_source);
@@ -740,58 +850,109 @@ io_run (SoupMessage *msg)
}
g_object_ref (msg);
- cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL;
-
if (io_run_until (msg,
SOUP_MESSAGE_IO_STATE_DONE,
SOUP_MESSAGE_IO_STATE_DONE,
- cancellable, &error)) {
- soup_message_io_finished (msg);
+ NULL, &error)) {
+ soup_server_message_io_finished (msg);
} else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
g_clear_error (&error);
- io->io_source = soup_message_io_get_source (msg, NULL, io_run_ready, msg);
+ io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL,
+ (SoupMessageIOSourceFunc)io_run_ready,
+ NULL);
g_source_attach (io->io_source, io->async_context);
} else {
- if (soup_message_get_io_data (msg) == io) {
- if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code) &&
+ if (soup_server_message_get_io_data (msg) == server_io) {
+ if (!SOUP_STATUS_IS_TRANSPORT_ERROR (soup_server_message_get_status (msg, NULL)) &&
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
+ soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, NULL);
}
- soup_message_io_finished (msg);
+ soup_server_message_io_finished (msg);
}
g_error_free (error);
}
-
g_object_unref (msg);
- g_clear_object (&cancellable);
}
void
-soup_message_read_request (SoupMessage *msg,
- SoupSocket *sock,
- SoupMessageCompletionFn completion_cb,
- gpointer user_data)
+soup_server_message_read_request (SoupServerMessage *msg,
+ SoupMessageIOCompletionFn completion_cb,
+ gpointer user_data)
{
- SoupMessageIOData *io;
+ SoupServerMessageIOData *io;
+ SoupSocket *sock;
- io = g_slice_new0 (SoupMessageIOData);
- io->completion_cb = completion_cb;
- io->completion_data = user_data;
+ io = g_slice_new0 (SoupServerMessageIOData);
+ io->base.completion_cb = completion_cb;
+ io->base.completion_data = user_data;
- io->sock = sock;
- io->iostream = g_object_ref (soup_socket_get_iostream (io->sock));
- io->istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->iostream));
- io->ostream = g_io_stream_get_output_stream (io->iostream);
- io->async_context = g_main_context_ref_thread_default ();
+ sock = soup_server_message_get_soup_socket (msg);
+ io->base.iostream = g_object_ref (soup_socket_get_iostream (sock));
+ io->base.istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->base.iostream));
+ io->base.ostream = g_io_stream_get_output_stream (io->base.iostream);
+ io->base.async_context = g_main_context_ref_thread_default ();
- io->read_header_buf = g_byte_array_new ();
- io->write_buf = g_string_new (NULL);
+ io->base.read_header_buf = g_byte_array_new ();
+ io->base.write_buf = g_string_new (NULL);
- io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
- io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
+ io->base.read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
+ io->base.write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
- soup_message_set_io_data (msg, io);
+ soup_server_message_set_io_data (msg, io);
io_run (msg);
}
+
+void
+soup_server_message_io_pause (SoupServerMessage *msg)
+{
+ SoupServerMessageIOData *io = soup_server_message_get_io_data (msg);
+
+ g_return_if_fail (io != NULL);
+
+ if (io->unpause_source) {
+ g_source_destroy (io->unpause_source);
+ g_source_unref (io->unpause_source);
+ io->unpause_source = NULL;
+ }
+
+ soup_message_io_data_pause (&io->base);
+}
+
+static gboolean
+io_unpause_internal (gpointer msg)
+{
+ SoupServerMessageIOData *io = soup_server_message_get_io_data (msg);
+
+ g_return_val_if_fail (io != NULL, FALSE);
+
+ g_clear_pointer (&io->unpause_source, g_source_unref);
+ soup_message_io_data_unpause (&io->base);
+ if (io->base.io_source)
+ return FALSE;
+
+ io_run (msg);
+ return FALSE;
+}
+
+void
+soup_server_message_io_unpause (SoupServerMessage *msg)
+{
+ SoupServerMessageIOData *io = soup_server_message_get_io_data (msg);
+
+ g_return_if_fail (io != NULL);
+
+ if (!io->unpause_source) {
+ io->unpause_source = soup_add_completion_reffed (io->base.async_context,
+ io_unpause_internal, msg, NULL);
+ }
+}
+
+gboolean
+soup_server_message_is_io_paused (SoupServerMessage *msg)
+{
+ SoupServerMessageIOData *io = soup_server_message_get_io_data (msg);
+
+ return io && io->base.paused;
+}
diff --git a/libsoup/server/soup-server-message-private.h b/libsoup/server/soup-server-message-private.h
new file mode 100644
index 00000000..057b058d
--- /dev/null
+++ b/libsoup/server/soup-server-message-private.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 Igalia S.L.
+ */
+
+#ifndef __SOUP_SERVER_MESSAGE_PRIVATE_H__
+#define __SOUP_SERVER_MESSAGE_PRIVATE_H__ 1
+
+#include "soup-server-message.h"
+#include "soup-auth-domain.h"
+#include "soup-message-io-data.h"
+#include "soup-socket.h"
+
+SoupServerMessage *soup_server_message_new (SoupSocket *sock);
+void soup_server_message_set_uri (SoupServerMessage *msg,
+ SoupURI *uri);
+void soup_server_message_set_method (SoupServerMessage *msg,
+ const char *method);
+SoupSocket *soup_server_message_get_soup_socket (SoupServerMessage *msg);
+void soup_server_message_set_auth (SoupServerMessage *msg,
+ SoupAuthDomain *domain,
+ char *user);
+gboolean soup_server_message_is_keepalive (SoupServerMessage *msg);
+GIOStream *soup_server_message_io_steal (SoupServerMessage *msg);
+void soup_server_message_io_pause (SoupServerMessage *msg);
+void soup_server_message_io_unpause (SoupServerMessage *msg);
+gboolean soup_server_message_is_io_paused (SoupServerMessage *msg);
+void soup_server_message_io_finished (SoupServerMessage *msg);
+void soup_server_message_cleanup_response (SoupServerMessage *msg);
+void soup_server_message_wrote_informational (SoupServerMessage *msg);
+void soup_server_message_wrote_headers (SoupServerMessage *msg);
+void soup_server_message_wrote_chunk (SoupServerMessage *msg);
+void soup_server_message_wrote_body_data (SoupServerMessage *msg,
+ gsize chunk_size);
+void soup_server_message_wrote_body (SoupServerMessage *msg);
+void soup_server_message_got_headers (SoupServerMessage *msg);
+void soup_server_message_got_chunk (SoupServerMessage *msg,
+ GBytes *chunk);
+void soup_server_message_got_body (SoupServerMessage *msg);
+void soup_server_message_finished (SoupServerMessage *msg);
+void soup_server_message_read_request (SoupServerMessage *msg,
+ SoupMessageIOCompletionFn completion_cb,
+ gpointer user_data);
+
+typedef struct _SoupServerMessageIOData SoupServerMessageIOData;
+void soup_server_message_io_data_free (SoupServerMessageIOData *io);
+void soup_server_message_set_io_data (SoupServerMessage *msg,
+ SoupServerMessageIOData *io);
+SoupServerMessageIOData *soup_server_message_get_io_data (SoupServerMessage *msg);
+
+#endif /* __SOUP_SERVER_MESSAGE_PRIVATE_H__ */
diff --git a/libsoup/server/soup-server-message.c b/libsoup/server/soup-server-message.c
new file mode 100644
index 00000000..1f2e8515
--- /dev/null
+++ b/libsoup/server/soup-server-message.c
@@ -0,0 +1,881 @@
+/*
+ * soup-server-message.c: HTTP server request/response
+ *
+ * Copyright (C) 2020 Igalia S.L.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "soup-server-message.h"
+#include "soup.h"
+#include "soup-connection.h"
+#include "soup-server-message-private.h"
+#include "soup-socket-private.h"
+
+/**
+ * SECTION:soup-server-message
+ * @short_description: An HTTP server request and response.
+ * @see_also: #SoupMessageHeaders, #SoupMessageBody
+ *
+ * A SoupServerMessage represents an HTTP message that is being sent or
+ * received on a #SoupServer
+ *
+ * #SoupServer will create #SoupServerMessage<!-- -->s automatically for
+ * incoming requests, which your application will receive via handlers.
+ *
+ * Note that libsoup's terminology here does not quite match the HTTP
+ * specification: in RFC 2616, an "HTTP-message" is
+ * <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a
+ * Response. In libsoup, a #SoupServerMessage combines both the request and
+ * the response.
+ **/
+
+struct _SoupServerMessage {
+ GObject parent;
+
+ SoupSocket *sock;
+ GSocket *gsock;
+ SoupAuthDomain *auth_domain;
+ char *auth_user;
+
+ GSocketAddress *remote_addr;
+ char *remote_ip;
+ GSocketAddress *local_addr;
+
+ const char *method;
+ SoupHTTPVersion http_version;
+ SoupHTTPVersion orig_http_version;
+
+ guint status_code;
+ char *reason_phrase;
+
+ SoupURI *uri;
+
+ SoupMessageBody *request_body;
+ SoupMessageHeaders *request_headers;
+
+ SoupMessageBody *response_body;
+ SoupMessageHeaders *response_headers;
+
+ SoupServerMessageIOData *io_data;
+};
+
+struct _SoupServerMessageClass {
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (SoupServerMessage, soup_server_message, G_TYPE_OBJECT)
+
+enum {
+ WROTE_INFORMATIONAL,
+ WROTE_HEADERS,
+ WROTE_CHUNK,
+ WROTE_BODY_DATA,
+ WROTE_BODY,
+
+ GOT_HEADERS,
+ GOT_CHUNK,
+ GOT_BODY,
+
+ DISCONNECTED,
+ FINISHED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+soup_server_message_init (SoupServerMessage *msg)
+{
+ msg->request_body = soup_message_body_new ();
+ msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
+ msg->response_body = soup_message_body_new ();
+ msg->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
+ soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CONTENT_LENGTH);
+}
+
+static void
+soup_server_message_finalize (GObject *object)
+{
+ SoupServerMessage *msg = SOUP_SERVER_MESSAGE (object);
+
+ soup_server_message_io_data_free (msg->io_data);
+
+ g_clear_object (&msg->auth_domain);
+ g_clear_pointer (&msg->auth_user, g_free);
+ g_clear_object (&msg->remote_addr);
+ g_clear_object (&msg->local_addr);
+
+ if (msg->sock) {
+ g_signal_handlers_disconnect_by_data (msg->sock, msg);
+ g_object_unref (msg->sock);
+ }
+ g_clear_object (&msg->gsock);
+ g_clear_pointer (&msg->remote_ip, g_free);
+
+ g_clear_pointer (&msg->uri, soup_uri_free);
+ g_free (msg->reason_phrase);
+
+ soup_message_body_free (msg->request_body);
+ soup_message_headers_free (msg->request_headers);
+ soup_message_body_free (msg->response_body);
+ soup_message_headers_free (msg->response_headers);
+
+ G_OBJECT_CLASS (soup_server_message_parent_class)->finalize (object);
+}
+
+static void
+soup_server_message_class_init (SoupServerMessageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = soup_server_message_finalize;
+
+ /**
+ * SoupServerMessage::wrote-informational:
+ * @msg: the message
+ *
+ * Emitted immediately after writing a 1xx (Informational) response.
+ */
+ signals[WROTE_INFORMATIONAL] =
+ g_signal_new ("wrote-informational",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::wrote-headers:
+ * @msg: the message
+ *
+ * Emitted immediately after writing the response headers for a
+ * message.
+ */
+ signals[WROTE_HEADERS] =
+ g_signal_new ("wrote-headers",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::wrote-chunk:
+ * @msg: the message
+ *
+ * Emitted immediately after writing a body chunk for a message.
+ *
+ * Note that this signal is not parallel to
+ * #SoupServerMessage::got-chunk; it is emitted only when a complete
+ * chunk (added with soup_message_body_append() or
+ * soup_message_body_append_bytes()) has been written. To get
+ * more useful continuous progress information, use
+ * #SoupServerMessage::wrote-body-data.
+ */
+ signals[WROTE_CHUNK] =
+ g_signal_new ("wrote-chunk",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::wrote-body-data:
+ * @msg: the message
+ * @chunk_size: the number of bytes written
+ *
+ * Emitted immediately after writing a portion of the message
+ * body to the network.
+ */
+ signals[WROTE_BODY_DATA] =
+ g_signal_new ("wrote-body-data",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_UINT);
+
+ /**
+ * SoupServerMessage::wrote-body:
+ * @msg: the message
+ *
+ * Emitted immediately after writing the complete response body for a
+ * message.
+ */
+ signals[WROTE_BODY] =
+ g_signal_new ("wrote-body",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::got-headers:
+ * @msg: the message
+ *
+ * Emitted after receiving the Request-Line and request headers.
+ */
+ signals[GOT_HEADERS] =
+ g_signal_new ("got-headers",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::got-chunk:
+ * @msg: the message
+ * @chunk: the just-read chunk
+ *
+ * Emitted after receiving a chunk of a message body. Note
+ * that "chunk" in this context means any subpiece of the
+ * body, not necessarily the specific HTTP 1.1 chunks sent by
+ * the other side.
+ */
+ signals[GOT_CHUNK] =
+ g_signal_new ("got-chunk",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_BYTES);
+
+ /**
+ * SoupServerMessage::got-body:
+ * @msg: the message
+ *
+ * Emitted after receiving the complete request body.
+ */
+ signals[GOT_BODY] =
+ g_signal_new ("got-body",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::finished:
+ * @msg: the message
+ *
+ * Emitted when all HTTP processing is finished for a message.
+ * (After #SoupServerMessage::wrote-body).
+ */
+ signals[FINISHED] =
+ g_signal_new ("finished",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * SoupServerMessage::disconnected:
+ * @msg: the message
+ *
+ * Emitted when the @msg's socket is disconnected.
+ */
+ signals[DISCONNECTED] =
+ g_signal_new ("disconnected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+socket_disconnected (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[DISCONNECTED], 0);
+}
+
+SoupServerMessage *
+soup_server_message_new (SoupSocket *sock)
+{
+ SoupServerMessage *msg;
+
+ msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL);
+ msg->sock = g_object_ref (sock);
+ msg->gsock = soup_socket_get_gsocket (sock);
+ if (msg->gsock)
+ g_object_ref (msg->gsock);
+
+ g_signal_connect_object (sock, "disconnected",
+ G_CALLBACK (socket_disconnected),
+ msg, G_CONNECT_SWAPPED);
+
+ return msg;
+}
+
+void
+soup_server_message_set_uri (SoupServerMessage *msg,
+ SoupURI *uri)
+{
+ if (msg->uri)
+ soup_uri_free (msg->uri);
+ msg->uri = soup_uri_copy (uri);
+}
+
+SoupSocket *
+soup_server_message_get_soup_socket (SoupServerMessage *msg)
+{
+ return msg->sock;
+}
+
+void
+soup_server_message_set_auth (SoupServerMessage *msg,
+ SoupAuthDomain *domain,
+ char *user)
+{
+ if (msg->auth_domain)
+ g_object_unref (msg->auth_domain);
+ msg->auth_domain = domain;
+
+ if (msg->auth_user)
+ g_free (msg->auth_user);
+ msg->auth_user = user;
+}
+
+gboolean
+soup_server_message_is_keepalive (SoupServerMessage *msg)
+{
+ if (msg->status_code == SOUP_STATUS_OK && msg->method == SOUP_METHOD_CONNECT)
+ return TRUE;
+
+ /* Not persistent if the server sent a terminate-by-EOF response */
+ if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_EOF)
+ return FALSE;
+
+ if (msg->http_version == SOUP_HTTP_1_0) {
+ /* In theory, HTTP/1.0 connections are only persistent
+ * if the client requests it, and the server agrees.
+ * But some servers do keep-alive even if the client
+ * doesn't request it. So ignore c_conn.
+ */
+
+ if (!soup_message_headers_header_contains (msg->response_headers,
+ "Connection", "Keep-Alive"))
+ return FALSE;
+ } else {
+ /* Normally persistent unless either side requested otherwise */
+ if (soup_message_headers_header_contains (msg->request_headers,
+ "Connection", "close") ||
+ soup_message_headers_header_contains (msg->response_headers,
+ "Connection", "close"))
+ return FALSE;
+
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+void
+soup_server_message_set_io_data (SoupServerMessage *msg,
+ SoupServerMessageIOData *io)
+{
+ soup_server_message_io_data_free (msg->io_data);
+ msg->io_data = io;
+}
+
+SoupServerMessageIOData *
+soup_server_message_get_io_data (SoupServerMessage *msg)
+{
+ return msg->io_data;
+}
+
+void
+soup_server_message_cleanup_response (SoupServerMessage *msg)
+{
+ soup_message_body_truncate (msg->response_body);
+ soup_message_headers_clear (msg->response_headers);
+ soup_message_headers_set_encoding (msg->response_headers,
+ SOUP_ENCODING_CONTENT_LENGTH);
+ msg->status_code = SOUP_STATUS_NONE;
+ g_clear_pointer (&msg->reason_phrase, g_free);
+ msg->http_version = msg->orig_http_version;
+}
+
+void
+soup_server_message_wrote_informational (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0);
+}
+
+void
+soup_server_message_wrote_headers (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[WROTE_HEADERS], 0);
+}
+
+void
+soup_server_message_wrote_chunk (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[WROTE_CHUNK], 0);
+}
+
+void
+soup_server_message_wrote_body_data (SoupServerMessage *msg,
+ gsize chunk_size)
+{
+ g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk_size);
+}
+
+void
+soup_server_message_wrote_body (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[WROTE_BODY], 0);
+}
+
+void
+soup_server_message_got_headers (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[GOT_HEADERS], 0);
+}
+
+void
+soup_server_message_got_chunk (SoupServerMessage *msg,
+ GBytes *chunk)
+{
+ g_signal_emit (msg, signals[GOT_CHUNK], 0, chunk);
+}
+
+void
+soup_server_message_got_body (SoupServerMessage *msg)
+{
+ if (soup_message_body_get_accumulate (msg->request_body))
+ g_bytes_unref (soup_message_body_flatten (msg->request_body));
+ g_signal_emit (msg, signals[GOT_BODY], 0);
+}
+
+void
+soup_server_message_finished (SoupServerMessage *msg)
+{
+ g_signal_emit (msg, signals[FINISHED], 0);
+}
+
+/**
+ * soup_server_message_get_request_headers:
+ * @msg: a #SoupServerMessage
+ *
+ * Get the request headers of @msg.
+ *
+ * Returns: (transfer none): a #SoupMessageHeaders with the request headers.
+ */
+SoupMessageHeaders *
+soup_server_message_get_request_headers (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->request_headers;
+}
+
+/**
+ * soup_server_message_get_response_headers:
+ * @msg: a #SoupServerMessage
+ *
+ * Get the response headers of @msg.
+ *
+ * Returns: (transfer none): a #SoupMessageHeaders with the response headers.
+ */
+SoupMessageHeaders *
+soup_server_message_get_response_headers (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->response_headers;
+}
+
+/**
+ * soup_server_message_get_request_body:
+ * @msg: a #SoupServerMessage
+ *
+ * Get the request body of @msg.
+ *
+ * Returns: (transfer none): a #SoupMessageBody.
+ */
+SoupMessageBody *
+soup_server_message_get_request_body (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->request_body;
+}
+
+/**
+ * soup_server_message_get_response_body:
+ * @msg: a #SoupServerMessage
+ *
+ * Get the response body of @msg.
+ *
+ * Returns: (transfer none): a #SoupMessageBody.
+ */
+SoupMessageBody *
+soup_server_message_get_response_body (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->response_body;
+}
+
+/**
+ * soup_server_message_get_method:
+ * @msg: a #SoupServerMessage
+ *
+ * Get the HTTP method of @msg.
+ *
+ * Returns: the HTTP method.
+ */
+const char *
+soup_server_message_get_method (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->method;
+}
+
+void
+soup_server_message_set_method (SoupServerMessage *msg,
+ const char *method)
+{
+ msg->method = g_intern_string (method);
+}
+
+/**
+ * soup_server_message_get_http_version:
+ * @msg: a #SoupServerMessage
+ *
+ * Get the HTTP version of @msg.
+ *
+ * Returns: a #SoupHTTPVersion.
+ */
+SoupHTTPVersion
+soup_server_message_get_http_version (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), SOUP_HTTP_1_1);
+
+ return msg->http_version;
+}
+
+/**
+ * soup_server_message_set_http_version:
+ * @msg: a #SoupServerMessage
+ * @version: a #SoupHTTPVersion
+ *
+ * Set the HTTP version of @msg.
+ */
+void
+soup_server_message_set_http_version (SoupServerMessage *msg,
+ SoupHTTPVersion version)
+{
+ g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
+
+ msg->http_version = version;
+ if (msg->status_code == SOUP_STATUS_NONE)
+ msg->orig_http_version = version;
+}
+
+/**
+ * soup_server_message_get_status:
+ * @msg: a #SoupServerMessage
+ * @reason_phrase: (out) (nullable) (transfer none): a location to store the reason phrase or %NULL
+ *
+ * Get the HTTP status code of @msg and optionally the reason phrase if @reason_phrase is not %NULL.
+ *
+ * Returns: the HTTP status code.
+ */
+guint
+soup_server_message_get_status (SoupServerMessage *msg,
+ const char **reason_phrase)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), 0);
+
+ if (reason_phrase)
+ *reason_phrase = msg->reason_phrase;
+
+ return msg->status_code;
+}
+
+/**
+ * soup_server_message_set_status:
+ * @msg: a #SoupServerMessage
+ * @status_code: an HTTP status code
+ * @reason_phrase: (nullable): a reason phrase
+ *
+ * Sets @msg's status code to @status_code. If @status_code is a
+ * known value and @reason_phrase is %NULL, the reason_phrase will
+ * be set automatically.
+ **/
+void
+soup_server_message_set_status (SoupServerMessage *msg,
+ guint status_code,
+ const char *reason_phrase)
+{
+ g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
+ g_return_if_fail (status_code != 0);
+
+ g_free (msg->reason_phrase);
+
+ msg->status_code = status_code;
+ msg->reason_phrase = g_strdup (reason_phrase ? reason_phrase : soup_status_get_phrase (status_code));
+}
+
+/**
+ * soup_server_message_get_uri:
+ * @msg: a #SoupServerMessage
+ *
+ * Get @msg's URI.
+ *
+ * Returns: (transfer none): a #SoupURI
+ */
+SoupURI *
+soup_server_message_get_uri (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->uri;
+}
+
+/**
+ * soup_server_message_set_response:
+ * @msg: the message
+ * @content_type: (allow-none): MIME Content-Type of the body
+ * @resp_use: a #SoupMemoryUse describing how to handle @resp_body
+ * @resp_body: (allow-none) (array length=resp_length) (element-type guint8):
+ * a data buffer containing the body of the message response.
+ * @resp_length: the byte length of @resp_body.
+ *
+ * Convenience function to set the response body of a #SoupServerMessage. If
+ * @content_type is %NULL, the response body must be empty as well.
+ */
+void
+soup_server_message_set_response (SoupServerMessage *msg,
+ const char *content_type,
+ SoupMemoryUse resp_use,
+ const char *resp_body,
+ gsize resp_length)
+{
+ g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
+ g_return_if_fail (content_type != NULL || resp_length == 0);
+
+ if (content_type) {
+ g_warn_if_fail (strchr (content_type, '/') != NULL);
+
+ soup_message_headers_replace (msg->response_headers,
+ "Content-Type", content_type);
+ soup_message_body_append (msg->response_body, resp_use,
+ resp_body, resp_length);
+ } else {
+ soup_message_headers_remove (msg->response_headers,
+ "Content-Type");
+ soup_message_body_truncate (msg->response_body);
+ }
+}
+
+/**
+ * soup_server_message_set_redirect:
+ * @msg: a #SoupServerMessage
+ * @status_code: a 3xx status code
+ * @redirect_uri: the URI to redirect @msg to
+ *
+ * Sets @msg's status_code to @status_code and adds a Location header
+ * pointing to @redirect_uri. Use this from a #SoupServer when you
+ * want to redirect the client to another URI.
+ *
+ * @redirect_uri can be a relative URI, in which case it is
+ * interpreted relative to @msg's current URI. In particular, if
+ * @redirect_uri is just a path, it will replace the path
+ * <emphasis>and query</emphasis> of @msg's URI.
+ */
+void
+soup_server_message_set_redirect (SoupServerMessage *msg,
+ guint status_code,
+ const char *redirect_uri)
+{
+ SoupURI *location;
+ char *location_str;
+
+ g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
+
+ location = soup_uri_new_with_base (soup_server_message_get_uri (msg), redirect_uri);
+ g_return_if_fail (location != NULL);
+
+ soup_server_message_set_status (msg, status_code, NULL);
+ location_str = soup_uri_to_string (location, FALSE);
+ soup_message_headers_replace (msg->response_headers, "Location",
+ location_str);
+ g_free (location_str);
+ soup_uri_free (location);
+}
+
+/**
+ * soup_server_message_get_socket:
+ * @msg: a #SoupServerMessage
+ *
+ * Retrieves the #GSocket that @msg is associated with.
+ *
+ * If you are using this method to observe when multiple requests are
+ * made on the same persistent HTTP connection (eg, as the ntlm-test
+ * test program does), you will need to pay attention to socket
+ * destruction as well (eg, by using weak references), so that you do
+ * not get fooled when the allocator reuses the memory address of a
+ * previously-destroyed socket to represent a new socket.
+ *
+ * Return value: (nullable) (transfer none): the #GSocket that @msg is
+ * associated with, %NULL if you used soup_server_accept_iostream().
+ */
+GSocket *
+soup_server_message_get_socket (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ return msg->gsock;
+}
+
+/**
+ * soup_server_message_get_remote_address:
+ * @msg: a #SoupServerMessage
+ *
+ * Retrieves the #GSocketAddress associated with the remote end
+ * of a connection.
+ *
+ * Return value: (nullable) (transfer none): the #GSocketAddress
+ * associated with the remote end of a connection, it may be
+ * %NULL if you used soup_server_accept_iostream().
+ */
+GSocketAddress *
+soup_server_message_get_remote_address (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ if (msg->remote_addr)
+ return msg->remote_addr;
+
+ msg->remote_addr = msg->gsock ?
+ g_socket_get_remote_address (msg->gsock, NULL) :
+ G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_remote_address (msg->sock)));
+
+ return msg->remote_addr;
+}
+
+/**
+ * soup_server_message_get_local_address:
+ * @msg: a #SoupServerMessage
+ *
+ * Retrieves the #GSocketAddress associated with the local end
+ * of a connection.
+ *
+ * Return value: (nullable) (transfer none): the #GSocketAddress
+ * associated with the local end of a connection, it may be
+ * %NULL if you used soup_server_accept_iostream().
+ */
+GSocketAddress *
+soup_server_message_get_local_address (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ if (msg->local_addr)
+ return msg->local_addr;
+
+ msg->local_addr = msg->gsock ?
+ g_socket_get_local_address (msg->gsock, NULL) :
+ G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_local_address (msg->sock)));
+
+ return msg->local_addr;
+}
+
+/**
+ * soup_server_message_get_remote_host:
+ * @msg: a #SoupServerMessage
+ *
+ * Retrieves the IP address associated with the remote end of a
+ * connection.
+ *
+ * Return value: (nullable): the IP address associated with the remote
+ * end of a connection, it may be %NULL if you used
+ * soup_server_accept_iostream().
+ */
+const char *
+soup_server_message_get_remote_host (SoupServerMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
+
+ if (msg->remote_ip)
+ return msg->remote_ip;
+
+ if (msg->gsock) {
+ GSocketAddress *addr = soup_server_message_get_remote_address (msg);
+ GInetAddress *iaddr;
+
+ if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr))
+ return NULL;
+ iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
+ msg->remote_ip = g_inet_address_to_string (iaddr);
+ } else {
+ GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_socket_get_remote_address (msg->sock));
+ GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
+ msg->remote_ip = g_inet_address_to_string (inet_addr);
+ }
+
+ return msg->remote_ip;
+}
+
+/**
+ * soup_server_message_steal_connection:
+ * @msg: a #SoupServerMessage
+ *
+ * "Steals" the HTTP connection associated with @msg from its
+ * #SoupServer. This happens immediately, regardless of the current
+ * state of the connection; if the response to @msg has not yet finished
+ * being sent, then it will be discarded; you can steal the connection from a
+ * #SoupServerMessage:wrote-informational or #SoupServerMessage:wrote-body signal
+ * handler if you need to wait for part or all of the response to be sent.
+ *
+ * Note that when calling this function from C, @msg will most
+ * likely be freed as a side effect.
+ *
+ * Return value: (transfer full): the #GIOStream formerly associated
+ * with @msg (or %NULL if @msg was no longer associated with a
+ * connection). No guarantees are made about what kind of #GIOStream
+ * is returned.
+ */
+GIOStream *
+soup_server_message_steal_connection (SoupServerMessage *msg)
+{
+ GIOStream *stream;
+
+ g_object_ref (msg);
+ stream = soup_server_message_io_steal (msg);
+ if (stream) {
+ g_object_set_data_full (G_OBJECT (stream), "GSocket",
+ soup_socket_steal_gsocket (msg->sock),
+ g_object_unref);
+ }
+
+ socket_disconnected (msg);
+ g_object_unref (msg);
+
+ return stream;
+}
diff --git a/libsoup/server/soup-server-message.h b/libsoup/server/soup-server-message.h
new file mode 100644
index 00000000..5102648e
--- /dev/null
+++ b/libsoup/server/soup-server-message.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 Igalia S.L.
+ */
+
+#ifndef __SOUP_SERVER_MESSAGE_H__
+#define __SOUP_SERVER_MESSAGE_H__ 1
+
+#include "soup-types.h"
+#include "soup-message-body.h"
+#include "soup-message-headers.h"
+#include "soup-method.h"
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_SERVER_MESSAGE (soup_server_message_get_type ())
+SOUP_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (SoupServerMessage, soup_server_message, SOUP, SERVER_MESSAGE, GObject)
+
+SOUP_AVAILABLE_IN_ALL
+SoupMessageHeaders *soup_server_message_get_request_headers (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+SoupMessageHeaders *soup_server_message_get_response_headers (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+SoupMessageBody *soup_server_message_get_request_body (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+SoupMessageBody *soup_server_message_get_response_body (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+const char *soup_server_message_get_method (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+SoupHTTPVersion soup_server_message_get_http_version (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+void soup_server_message_set_http_version (SoupServerMessage *msg,
+ SoupHTTPVersion version);
+
+SOUP_AVAILABLE_IN_ALL
+guint soup_server_message_get_status (SoupServerMessage *msg,
+ const char **reason_phrase);
+SOUP_AVAILABLE_IN_ALL
+void soup_server_message_set_status (SoupServerMessage *msg,
+ guint status_code,
+ const char *reason_phrase);
+SOUP_AVAILABLE_IN_ALL
+SoupURI *soup_server_message_get_uri (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+void soup_server_message_set_response (SoupServerMessage *msg,
+ const char *content_type,
+ SoupMemoryUse resp_use,
+ const char *resp_body,
+ gsize resp_length);
+SOUP_AVAILABLE_IN_ALL
+void soup_server_message_set_redirect (SoupServerMessage *msg,
+ guint status_code,
+ const char *redirect_uri);
+
+SOUP_AVAILABLE_IN_ALL
+GSocket *soup_server_message_get_socket (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+GSocketAddress *soup_server_message_get_local_address (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+GSocketAddress *soup_server_message_get_remote_address (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+const char *soup_server_message_get_remote_host (SoupServerMessage *msg);
+
+SOUP_AVAILABLE_IN_ALL
+GIOStream *soup_server_message_steal_connection (SoupServerMessage *msg);
+
+G_END_DECLS
+
+#endif /* __SOUP_SERVER_MESSAGE_H__ */
diff --git a/libsoup/server/soup-server-private.h b/libsoup/server/soup-server-private.h
deleted file mode 100644
index 15430e73..00000000
--- a/libsoup/server/soup-server-private.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2020 Igalia S.L.
- *
- * This file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#pragma once
-
-#include "soup-server.h"
-
-SoupSocket *soup_client_context_get_soup_socket (SoupClientContext *client);
diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c
index aa5f2203..2802f66a 100644
--- a/libsoup/server/soup-server.c
+++ b/libsoup/server/soup-server.c
@@ -13,9 +13,10 @@
#include <glib/gi18n-lib.h>
-#include "soup-server-private.h"
+#include "soup-server.h"
+#include "soup-server-message-private.h"
#include "soup.h"
-#include "soup-message-private.h"
+#include "soup-server-message-private.h"
#include "soup-misc.h"
#include "soup-path-map.h"
#include "soup-socket-private.h"
@@ -129,21 +130,6 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
-struct _SoupClientContext {
- SoupServer *server;
- SoupSocket *sock;
- GSocket *gsock;
- SoupMessage *msg;
- SoupAuthDomain *auth_domain;
- char *auth_user;
-
- GSocketAddress *remote_addr;
- char *remote_ip;
- GSocketAddress *local_addr;
-
- int ref_count;
-};
-
typedef struct {
char *path;
@@ -207,9 +193,8 @@ enum {
G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT)
-static SoupClientContext *soup_client_context_ref (SoupClientContext *client);
-static void soup_client_context_unref (SoupClientContext *client);
-
+static void start_request (SoupServer *server,
+ SoupServerMessage *msg);
static void
free_handler (SoupServerHandler *handler)
{
@@ -398,7 +383,6 @@ soup_server_class_init (SoupServerClass *server_class)
* SoupServer::request-started:
* @server: the server
* @message: the new message
- * @client: the client context
*
* Emitted when the server has started reading a new request.
* @message will be completely blank; not even the
@@ -419,15 +403,13 @@ soup_server_class_init (SoupServerClass *server_class)
G_STRUCT_OFFSET (SoupServerClass, request_started),
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
- SOUP_TYPE_MESSAGE,
- SOUP_TYPE_CLIENT_CONTEXT);
+ G_TYPE_NONE, 1,
+ SOUP_TYPE_SERVER_MESSAGE);
/**
* SoupServer::request-read:
* @server: the server
* @message: the message
- * @client: the client context
*
* Emitted when the server has successfully read a request.
* @message will have all of its request-side information
@@ -444,15 +426,13 @@ soup_server_class_init (SoupServerClass *server_class)
G_STRUCT_OFFSET (SoupServerClass, request_read),
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
- SOUP_TYPE_MESSAGE,
- SOUP_TYPE_CLIENT_CONTEXT);
+ G_TYPE_NONE, 1,
+ SOUP_TYPE_SERVER_MESSAGE);
/**
* SoupServer::request-finished:
* @server: the server
* @message: the message
- * @client: the client context
*
* Emitted when the server has finished writing a response to
* a request.
@@ -464,15 +444,13 @@ soup_server_class_init (SoupServerClass *server_class)
G_STRUCT_OFFSET (SoupServerClass, request_finished),
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
- SOUP_TYPE_MESSAGE,
- SOUP_TYPE_CLIENT_CONTEXT);
+ G_TYPE_NONE, 1,
+ SOUP_TYPE_SERVER_MESSAGE);
/**
* SoupServer::request-aborted:
* @server: the server
* @message: the message
- * @client: the client context
*
* Emitted when processing has failed for a message; this
* could mean either that it could not be read (if
@@ -493,9 +471,8 @@ soup_server_class_init (SoupServerClass *server_class)
G_STRUCT_OFFSET (SoupServerClass, request_aborted),
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
- SOUP_TYPE_MESSAGE,
- SOUP_TYPE_CLIENT_CONTEXT);
+ G_TYPE_NONE, 1,
+ SOUP_TYPE_SERVER_MESSAGE);
/* properties */
/**
@@ -818,97 +795,6 @@ soup_server_get_listeners (SoupServer *server)
return listeners;
}
-static void start_request (SoupServer *, SoupClientContext *);
-static void socket_disconnected (SoupSocket *sock, SoupClientContext *client);
-
-static SoupClientContext *
-soup_client_context_new (SoupServer *server, SoupSocket *sock)
-{
- SoupClientContext *client = g_slice_new0 (SoupClientContext);
-
- client->server = server;
- client->sock = g_object_ref (sock);
- client->gsock = soup_socket_get_gsocket (sock);
- if (client->gsock)
- g_object_ref (client->gsock);
- g_signal_connect (sock, "disconnected",
- G_CALLBACK (socket_disconnected), client);
- client->ref_count = 1;
-
- return client;
-}
-
-static void
-soup_client_context_cleanup (SoupClientContext *client)
-{
- g_clear_object (&client->auth_domain);
- g_clear_pointer (&client->auth_user, g_free);
- g_clear_object (&client->remote_addr);
- g_clear_object (&client->local_addr);
-
- client->msg = NULL;
-}
-
-static SoupClientContext *
-soup_client_context_ref (SoupClientContext *client)
-{
- g_atomic_int_inc (&client->ref_count);
- return client;
-}
-
-static void
-soup_client_context_unref (SoupClientContext *client)
-{
- if (!g_atomic_int_dec_and_test (&client->ref_count))
- return;
-
- soup_client_context_cleanup (client);
-
- g_signal_handlers_disconnect_by_func (client->sock, socket_disconnected, client);
- g_object_unref (client->sock);
- g_clear_object (&client->gsock);
- g_clear_pointer (&client->remote_ip, g_free);
- g_slice_free (SoupClientContext, client);
-}
-
-static void
-request_finished (SoupMessage *msg, SoupMessageIOCompletion completion, gpointer user_data)
-{
- SoupClientContext *client = user_data;
- SoupServer *server = client->server;
- SoupServerPrivate *priv = soup_server_get_instance_private (server);
- SoupSocket *sock = client->sock;
- gboolean failed;
-
- if (completion == SOUP_MESSAGE_IO_STOLEN) {
- soup_client_context_unref (client);
- g_object_unref (msg);
- return;
- }
-
- /* Complete the message, assuming it actually really started. */
- if (msg->method) {
- soup_message_finished (msg);
-
- failed = (completion == SOUP_MESSAGE_IO_INTERRUPTED ||
- msg->status_code == SOUP_STATUS_IO_ERROR);
- g_signal_emit (server,
- failed ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED],
- 0, msg, client);
- }
-
- if (completion == SOUP_MESSAGE_IO_COMPLETE &&
- soup_socket_is_connected (sock) &&
- soup_message_is_keepalive (msg) &&
- priv->listeners) {
- start_request (server, client);
- } else {
- soup_socket_disconnect (client->sock);
- soup_client_context_unref (client);
- }
- g_object_unref (msg);
-}
-
/* "" was never documented as meaning the same thing as "/", but it
* effectively was. We have to special case it now or otherwise it
* would match "*" too.
@@ -916,19 +802,21 @@ request_finished (SoupMessage *msg, SoupMessageIOCompletion completion, gpointer
#define NORMALIZED_PATH(path) ((path) && *(path) ? (path) : "/")
static SoupServerHandler *
-get_handler (SoupServer *server, SoupMessage *msg)
+get_handler (SoupServer *server,
+ SoupServerMessage *msg)
{
SoupServerPrivate *priv = soup_server_get_instance_private (server);
SoupURI *uri;
- uri = soup_message_get_uri (msg);
+ uri = soup_server_message_get_uri (msg);
return soup_path_map_lookup (priv->handlers, NORMALIZED_PATH (uri->path));
}
static void
-call_handler (SoupServer *server, SoupServerHandler *handler,
- SoupClientContext *client, SoupMessage *msg,
- gboolean early)
+call_handler (SoupServer *server,
+ SoupServerHandler *handler,
+ SoupServerMessage *msg,
+ gboolean early)
{
GHashTable *form_data_set;
SoupURI *uri;
@@ -938,10 +826,10 @@ call_handler (SoupServer *server, SoupServerHandler *handler,
else if (!early && !handler->callback)
return;
- if (msg->status_code != 0)
+ if (soup_server_message_get_status (msg, NULL) != 0)
return;
- uri = soup_message_get_uri (msg);
+ uri = soup_server_message_get_uri (msg);
if (uri->query)
form_data_set = soup_form_decode (uri->query);
else
@@ -950,11 +838,11 @@ call_handler (SoupServer *server, SoupServerHandler *handler,
if (early) {
(*handler->early_callback) (server, msg,
uri->path, form_data_set,
- client, handler->early_user_data);
+ handler->early_user_data);
} else {
(*handler->callback) (server, msg,
uri->path, form_data_set,
- client, handler->user_data);
+ handler->user_data);
}
if (form_data_set)
@@ -962,9 +850,9 @@ call_handler (SoupServer *server, SoupServerHandler *handler,
}
static void
-got_headers (SoupMessage *msg, SoupClientContext *client)
+got_headers (SoupServer *server,
+ SoupServerMessage *msg)
{
- SoupServer *server = client->server;
SoupServerPrivate *priv = soup_server_get_instance_private (server);
SoupServerHandler *handler;
SoupURI *uri;
@@ -974,22 +862,26 @@ got_headers (SoupMessage *msg, SoupClientContext *client)
GSList *iter;
gboolean rejected = FALSE;
char *auth_user;
+ SoupMessageHeaders *headers;
+ SoupSocket *sock;
/* Add required response headers */
+ headers = soup_server_message_get_response_headers (msg);
+
date = g_date_time_new_now_utc ();
date_string = soup_date_time_to_string (date, SOUP_DATE_HTTP);
- soup_message_headers_replace (msg->response_headers, "Date",
- date_string);
+ soup_message_headers_replace (headers, "Date", date_string);
g_free (date_string);
g_date_time_unref (date);
- if (msg->status_code != 0)
+ if (soup_server_message_get_status (msg, NULL) != 0)
return;
- uri = soup_message_get_uri (msg);
- if ((soup_socket_is_ssl (client->sock) && !soup_uri_is_https (uri, priv->https_aliases)) ||
- (!soup_socket_is_ssl (client->sock) && !soup_uri_is_http (uri, priv->http_aliases))) {
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ sock = soup_server_message_get_soup_socket (msg);
+ uri = soup_server_message_get_uri (msg);
+ if ((soup_socket_is_ssl (sock) && !soup_uri_is_https (uri, priv->https_aliases)) ||
+ (!soup_socket_is_ssl (sock) && !soup_uri_is_http (uri, priv->http_aliases))) {
+ soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
return;
}
@@ -1010,7 +902,7 @@ got_headers (SoupMessage *msg, SoupClientContext *client)
) {
/* Introducing new ".." segments is not allowed */
g_free (decoded_path);
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
return;
}
@@ -1029,8 +921,7 @@ got_headers (SoupMessage *msg, SoupClientContext *client)
if (soup_auth_domain_covers (domain, msg)) {
auth_user = soup_auth_domain_accepts (domain, msg);
if (auth_user) {
- client->auth_domain = g_object_ref (domain);
- client->auth_user = auth_user;
+ soup_server_message_set_auth (msg, g_object_ref (domain), auth_user);
return;
}
@@ -1052,15 +943,14 @@ got_headers (SoupMessage *msg, SoupClientContext *client)
/* Otherwise, call the early handlers. */
handler = get_handler (server, msg);
if (handler)
- call_handler (server, handler, client, msg, TRUE);
+ call_handler (server, handler, msg, TRUE);
}
static void
-complete_websocket_upgrade (SoupMessage *msg, gpointer user_data)
+complete_websocket_upgrade (SoupServer *server,
+ SoupServerMessage *msg)
{
- SoupClientContext *client = user_data;
- SoupServer *server = client->server;
- SoupURI *uri = soup_message_get_uri (msg);
+ SoupURI *uri = soup_server_message_get_uri (msg);
SoupServerHandler *handler;
GIOStream *stream;
SoupWebsocketConnection *conn;
@@ -1069,42 +959,41 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data)
if (!handler || !handler->websocket_callback)
return;
- soup_client_context_ref (client);
- stream = soup_client_context_steal_connection (client);
+ g_object_ref (msg);
+ stream = soup_server_message_steal_connection (msg);
conn = soup_websocket_connection_new_with_extensions (stream, uri,
SOUP_WEBSOCKET_CONNECTION_SERVER,
- soup_message_headers_get_one (msg->request_headers, "Origin"),
- soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"),
+ soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "Origin"),
+ soup_message_headers_get_one (soup_server_message_get_response_headers (msg), "Sec-WebSocket-Protocol"),
handler->websocket_extensions);
handler->websocket_extensions = NULL;
g_object_unref (stream);
- soup_client_context_unref (client);
- (*handler->websocket_callback) (server, conn, uri->path, client,
+ (*handler->websocket_callback) (server, msg, uri->path, conn,
handler->websocket_user_data);
g_object_unref (conn);
- soup_client_context_unref (client);
+ g_object_unref (msg);
}
static void
-got_body (SoupMessage *msg, SoupClientContext *client)
+got_body (SoupServer *server,
+ SoupServerMessage *msg)
{
- SoupServer *server = client->server;
SoupServerHandler *handler;
- g_signal_emit (server, signals[REQUEST_READ], 0, msg, client);
+ g_signal_emit (server, signals[REQUEST_READ], 0, msg);
- if (msg->status_code != 0)
+ if (soup_server_message_get_status (msg, NULL) != 0)
return;
handler = get_handler (server, msg);
if (!handler) {
- soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
+ soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL);
return;
}
- call_handler (server, handler, client, msg, FALSE);
- if (msg->status_code != 0)
+ call_handler (server, handler, msg, FALSE);
+ if (soup_server_message_get_status (msg, NULL) != 0)
return;
if (handler->websocket_callback) {
@@ -1116,65 +1005,110 @@ got_body (SoupMessage *msg, SoupClientContext *client)
handler->websocket_protocols,
priv->websocket_extension_types,
&handler->websocket_extensions)) {
- g_signal_connect (msg, "wrote-informational",
- G_CALLBACK (complete_websocket_upgrade),
- soup_client_context_ref (client));
+ g_signal_connect_object (msg, "wrote-informational",
+ G_CALLBACK (complete_websocket_upgrade),
+ server, G_CONNECT_SWAPPED);
}
}
}
static void
-start_request (SoupServer *server, SoupClientContext *client)
+client_disconnected (SoupServer *server,
+ SoupServerMessage *msg)
{
SoupServerPrivate *priv = soup_server_get_instance_private (server);
- SoupMessage *msg;
-
- soup_client_context_cleanup (client);
- /* Listen for another request on this connection */
- msg = g_object_new (SOUP_TYPE_MESSAGE,
- SOUP_MESSAGE_SERVER_SIDE, TRUE,
- NULL);
- client->msg = msg;
+ priv->clients = g_slist_remove (priv->clients, msg);
- if (priv->server_header) {
- soup_message_headers_append (msg->response_headers, "Server",
- priv->server_header);
+ if (soup_server_message_get_status (msg, NULL) != 0) {
+ soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, NULL);
+ soup_server_message_io_finished (msg);
}
+}
- g_signal_connect (msg, "got_headers", G_CALLBACK (got_headers), client);
- g_signal_connect (msg, "got_body", G_CALLBACK (got_body), client);
-
- g_signal_emit (server, signals[REQUEST_STARTED], 0,
- msg, client);
-
- soup_message_read_request (msg, client->sock,
- request_finished, client);
+static void
+soup_server_accept_socket (SoupServer *server,
+ SoupSocket *sock)
+{
+ SoupServerPrivate *priv = soup_server_get_instance_private (server);
+ SoupServerMessage *msg;
+
+ msg = soup_server_message_new (sock);
+ g_signal_connect_object (msg, "disconnected",
+ G_CALLBACK (client_disconnected),
+ server, G_CONNECT_SWAPPED);
+ priv->clients = g_slist_prepend (priv->clients, msg);
+ start_request (server, msg);
}
static void
-socket_disconnected (SoupSocket *sock, SoupClientContext *client)
+request_finished (SoupServerMessage *msg,
+ SoupMessageIOCompletion completion,
+ SoupServer *server)
{
- SoupServerPrivate *priv = soup_server_get_instance_private (client->server);
+ SoupServerPrivate *priv = soup_server_get_instance_private (server);
+ SoupSocket *sock = soup_server_message_get_soup_socket (msg);
+ gboolean failed;
+
+ if (completion == SOUP_MESSAGE_IO_STOLEN) {
+ g_object_unref (msg);
+ return;
+ }
- priv->clients = g_slist_remove (priv->clients, client);
+ /* Complete the message, assuming it actually really started. */
+ if (soup_server_message_get_method (msg)) {
+ soup_server_message_finished (msg);
+
+ failed = (completion == SOUP_MESSAGE_IO_INTERRUPTED ||
+ soup_server_message_get_status (msg, NULL) == SOUP_STATUS_IO_ERROR);
+ g_signal_emit (server,
+ failed ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED],
+ 0, msg);
+ }
- if (client->msg) {
- soup_message_set_status (client->msg, SOUP_STATUS_IO_ERROR);
- soup_message_io_finished (client->msg);
+ if (completion == SOUP_MESSAGE_IO_COMPLETE &&
+ soup_socket_is_connected (sock) &&
+ soup_server_message_is_keepalive (msg) &&
+ priv->listeners) {
+ g_object_ref (sock);
+ priv->clients = g_slist_remove (priv->clients, msg);
+ g_object_unref (msg);
+
+ soup_server_accept_socket (server, sock);
+ g_object_unref (sock);
+ return;
}
+
+ soup_socket_disconnect (sock);
+ g_object_unref (msg);
}
static void
-soup_server_accept_socket (SoupServer *server,
- SoupSocket *sock)
+start_request (SoupServer *server,
+ SoupServerMessage *msg)
{
SoupServerPrivate *priv = soup_server_get_instance_private (server);
- SoupClientContext *client;
- client = soup_client_context_new (server, sock);
- priv->clients = g_slist_prepend (priv->clients, client);
- start_request (server, client);
+ if (priv->server_header) {
+ SoupMessageHeaders *headers;
+
+ headers = soup_server_message_get_response_headers (msg);
+ soup_message_headers_append (headers, "Server",
+ priv->server_header);
+ }
+
+ g_signal_connect_object (msg, "got-headers",
+ G_CALLBACK (got_headers),
+ server, G_CONNECT_SWAPPED);
+ g_signal_connect_object (msg, "got-body",
+ G_CALLBACK (got_body),
+ server, G_CONNECT_SWAPPED);
+
+ g_signal_emit (server, signals[REQUEST_STARTED], 0, msg);
+
+ soup_server_message_read_request (msg,
+ (SoupMessageIOCompletionFn)request_finished,
+ server);
}
/**
@@ -1194,11 +1128,11 @@ soup_server_accept_socket (SoupServer *server,
* Since: 2.50
**/
gboolean
-soup_server_accept_iostream (SoupServer *server,
- GIOStream *stream,
- GSocketAddress *local_addr,
- GSocketAddress *remote_addr,
- GError **error)
+soup_server_accept_iostream (SoupServer *server,
+ GIOStream *stream,
+ GSocketAddress *local_addr,
+ GSocketAddress *remote_addr,
+ GError **error)
{
SoupSocket *sock;
@@ -1244,7 +1178,6 @@ soup_server_disconnect (SoupServer *server)
SoupServerPrivate *priv;
GSList *listeners, *clients, *iter;
SoupSocket *listener;
- SoupClientContext *client;
g_return_if_fail (SOUP_IS_SERVER (server));
priv = soup_server_get_instance_private (server);
@@ -1255,8 +1188,9 @@ soup_server_disconnect (SoupServer *server)
priv->listeners = NULL;
for (iter = clients; iter; iter = iter->next) {
- client = iter->data;
- soup_socket_disconnect (client->sock);
+ SoupServerMessage *msg = iter->data;
+
+ soup_socket_disconnect (soup_server_message_get_soup_socket (msg));
}
g_slist_free (clients);
@@ -1679,257 +1613,12 @@ soup_server_get_uris (SoupServer *server)
}
/**
- * SoupClientContext:
- *
- * A #SoupClientContext provides additional information about the
- * client making a particular request. In particular, you can use
- * soup_client_context_get_auth_domain() and
- * soup_client_context_get_auth_user() to determine if HTTP
- * authentication was used successfully.
- *
- * soup_client_context_get_remote_address() and/or
- * soup_client_context_get_host() can be used to get information for
- * logging or debugging purposes. soup_client_context_get_socket() may
- * also be of use in some situations (eg, tracking when multiple
- * requests are made on the same connection).
- **/
-G_DEFINE_BOXED_TYPE (SoupClientContext, soup_client_context, soup_client_context_ref, soup_client_context_unref)
-
-/**
- * soup_client_context_get_soup_socket:
- * @client: a #SoupClientContext
- *
- * Retrieves the #SoupSocket that @client is associated with.
- *
- * If you are using this method to observe when multiple requests are
- * made on the same persistent HTTP connection (eg, as the ntlm-test
- * test program does), you will need to pay attention to socket
- * destruction as well (either by using weak references, or by
- * connecting to the #SoupSocket::disconnected signal), so that you do
- * not get fooled when the allocator reuses the memory address of a
- * previously-destroyed socket to represent a new socket.
- *
- * Return value: (transfer none): the #SoupSocket that @client is
- * associated with.
- **/
-SoupSocket *
-soup_client_context_get_soup_socket (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- return client->sock;
-}
-
-/**
- * soup_client_context_get_socket:
- * @client: a #SoupClientContext
- *
- * Retrieves the #GSocket that @client is associated with.
- *
- * If you are using this method to observe when multiple requests are
- * made on the same persistent HTTP connection (eg, as the ntlm-test
- * test program does), you will need to pay attention to socket
- * destruction as well (eg, by using weak references), so that you do
- * not get fooled when the allocator reuses the memory address of a
- * previously-destroyed socket to represent a new socket.
- *
- * Return value: (nullable) (transfer none): the #GSocket that @client is
- * associated with, %NULL if you used soup_server_accept_iostream().
- *
- * Since: 2.48
- **/
-GSocket *
-soup_client_context_get_socket (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- return client->gsock;
-}
-
-/**
- * soup_client_context_get_remote_address:
- * @client: a #SoupClientContext
- *
- * Retrieves the #GSocketAddress associated with the remote end
- * of a connection.
- *
- * Return value: (nullable) (transfer none): the #GSocketAddress
- * associated with the remote end of a connection, it may be
- * %NULL if you used soup_server_accept_iostream().
- *
- * Since: 2.48
- **/
-GSocketAddress *
-soup_client_context_get_remote_address (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- if (client->remote_addr)
- return client->remote_addr;
-
- client->remote_addr = client->gsock ?
- g_socket_get_remote_address (client->gsock, NULL) :
- G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_remote_address (client->sock)));
-
- return client->remote_addr;
-}
-
-/**
- * soup_client_context_get_local_address:
- * @client: a #SoupClientContext
- *
- * Retrieves the #GSocketAddress associated with the local end
- * of a connection.
- *
- * Return value: (nullable) (transfer none): the #GSocketAddress
- * associated with the local end of a connection, it may be
- * %NULL if you used soup_server_accept_iostream().
- *
- * Since: 2.48
- **/
-GSocketAddress *
-soup_client_context_get_local_address (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- if (client->local_addr)
- return client->local_addr;
-
- client->local_addr = client->gsock ?
- g_socket_get_local_address (client->gsock, NULL) :
- G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_local_address (client->sock)));
-
- return client->local_addr;
-}
-
-/**
- * soup_client_context_get_host:
- * @client: a #SoupClientContext
- *
- * Retrieves the IP address associated with the remote end of a
- * connection.
- *
- * Return value: (nullable): the IP address associated with the remote
- * end of a connection, it may be %NULL if you used
- * soup_server_accept_iostream().
- **/
-const char *
-soup_client_context_get_host (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- if (client->remote_ip)
- return client->remote_ip;
-
- if (client->gsock) {
- GSocketAddress *addr = soup_client_context_get_remote_address (client);
- GInetAddress *iaddr;
-
- if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr))
- return NULL;
- iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
- client->remote_ip = g_inet_address_to_string (iaddr);
- } else {
- GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_socket_get_remote_address (client->sock));
- GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
- client->remote_ip = g_inet_address_to_string (inet_addr);
- }
-
- return client->remote_ip;
-}
-
-/**
- * soup_client_context_get_auth_domain:
- * @client: a #SoupClientContext
- *
- * Checks whether the request associated with @client has been
- * authenticated, and if so returns the #SoupAuthDomain that
- * authenticated it.
- *
- * Return value: (transfer none) (nullable): a #SoupAuthDomain, or
- * %NULL if the request was not authenticated.
- **/
-SoupAuthDomain *
-soup_client_context_get_auth_domain (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- return client->auth_domain;
-}
-
-/**
- * soup_client_context_get_auth_user:
- * @client: a #SoupClientContext
- *
- * Checks whether the request associated with @client has been
- * authenticated, and if so returns the username that the client
- * authenticated as.
- *
- * Return value: (nullable): the authenticated-as user, or %NULL if
- * the request was not authenticated.
- **/
-const char *
-soup_client_context_get_auth_user (SoupClientContext *client)
-{
- g_return_val_if_fail (client != NULL, NULL);
-
- return client->auth_user;
-}
-
-/**
- * soup_client_context_steal_connection:
- * @client: a #SoupClientContext
- *
- * "Steals" the HTTP connection associated with @client from its
- * #SoupServer. This happens immediately, regardless of the current
- * state of the connection; if the response to the current
- * #SoupMessage has not yet finished being sent, then it will be
- * discarded; you can steal the connection from a
- * #SoupMessage::wrote-informational or #SoupMessage::wrote-body signal
- * handler if you need to wait for part or all of the response to be
- * sent.
- *
- * Note that when calling this function from C, @client will most
- * likely be freed as a side effect.
- *
- * Return value: (transfer full): the #GIOStream formerly associated
- * with @client (or %NULL if @client was no longer associated with a
- * connection). No guarantees are made about what kind of #GIOStream
- * is returned.
- *
- * Since: 2.50
- **/
-GIOStream *
-soup_client_context_steal_connection (SoupClientContext *client)
-{
- GIOStream *stream;
-
- g_return_val_if_fail (client != NULL, NULL);
-
- soup_client_context_ref (client);
-
- stream = soup_message_io_steal (client->msg);
- if (stream) {
- g_object_set_data_full (G_OBJECT (stream), "GSocket",
- soup_socket_steal_gsocket (client->sock),
- g_object_unref);
- }
-
- socket_disconnected (client->sock, client);
- soup_client_context_unref (client);
-
- return stream;
-}
-
-
-/**
* SoupServerCallback:
* @server: the #SoupServer
* @msg: the message being processed
* @path: the path component of @msg's Request-URI
* @query: (element-type utf8 utf8) (allow-none): the parsed query
* component of @msg's Request-URI
- * @client: additional contextual information about the client
* @user_data: the data passed to soup_server_add_handler() or
* soup_server_add_early_handler().
*
@@ -2108,7 +1797,7 @@ soup_server_add_early_handler (SoupServer *server,
* @server: the #SoupServer
* @path: the path component of @msg's Request-URI
* @connection: the newly created WebSocket connection
- * @client: additional contextual information about the client
+ * @msg: the #SoupServerMessage
* @user_data: the data passed to @soup_server_add_handler
*
* A callback used to handle WebSocket requests to a #SoupServer. The
@@ -2249,30 +1938,30 @@ soup_server_remove_auth_domain (SoupServer *server, SoupAuthDomain *auth_domain)
/**
* soup_server_pause_message:
* @server: a #SoupServer
- * @msg: a #SoupMessage associated with @server.
+ * @msg: a #SoupServerMessage associated with @server.
*
* Pauses I/O on @msg. This can be used when you need to return from
* the server handler without having the full response ready yet. Use
* soup_server_unpause_message() to resume I/O.
*
- * This must only be called on a #SoupMessage which was created by the
+ * This must only be called on a #SoupServerMessage which was created by the
* #SoupServer and are currently doing I/O, such as those passed into a
* #SoupServerCallback or emitted in a #SoupServer::request-read signal.
**/
void
-soup_server_pause_message (SoupServer *server,
- SoupMessage *msg)
+soup_server_pause_message (SoupServer *server,
+ SoupServerMessage *msg)
{
g_return_if_fail (SOUP_IS_SERVER (server));
- g_return_if_fail (SOUP_IS_MESSAGE (msg));
+ g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
- soup_message_io_pause (msg);
+ soup_server_message_io_pause (msg);
}
/**
* soup_server_unpause_message:
* @server: a #SoupServer
- * @msg: a #SoupMessage associated with @server.
+ * @msg: a #SoupServerMessage associated with @server.
*
* Resumes I/O on @msg. Use this to resume after calling
* soup_server_pause_message(), or after adding a new chunk to a
@@ -2280,18 +1969,18 @@ soup_server_pause_message (SoupServer *server,
*
* I/O won't actually resume until you return to the main loop.
*
- * This must only be called on a #SoupMessage which was created by the
+ * This must only be called on a #SoupServerMessage which was created by the
* #SoupServer and are currently doing I/O, such as those passed into a
* #SoupServerCallback or emitted in a #SoupServer::request-read signal.
**/
void
-soup_server_unpause_message (SoupServer *server,
- SoupMessage *msg)
+soup_server_unpause_message (SoupServer *server,
+ SoupServerMessage *msg)
{
g_return_if_fail (SOUP_IS_SERVER (server));
- g_return_if_fail (SOUP_IS_MESSAGE (msg));
+ g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
- soup_message_io_unpause (msg);
+ soup_server_message_io_unpause (msg);
}
/**
diff --git a/libsoup/server/soup-server.h b/libsoup/server/soup-server.h
index eb9a13b7..b5225207 100644
--- a/libsoup/server/soup-server.h
+++ b/libsoup/server/soup-server.h
@@ -15,11 +15,6 @@ G_BEGIN_DECLS
SOUP_AVAILABLE_IN_2_4
G_DECLARE_DERIVABLE_TYPE (SoupServer, soup_server, SOUP, SERVER, GObject)
-typedef struct _SoupClientContext SoupClientContext;
-SOUP_AVAILABLE_IN_2_4
-GType soup_client_context_get_type (void);
-#define SOUP_TYPE_CLIENT_CONTEXT (soup_client_context_get_type ())
-
typedef enum {
SOUP_SERVER_LISTEN_HTTPS = (1 << 0),
SOUP_SERVER_LISTEN_IPV4_ONLY = (1 << 1),
@@ -30,14 +25,14 @@ struct _SoupServerClass {
GObjectClass parent_class;
/* signals */
- void (*request_started) (SoupServer *server, SoupMessage *msg,
- SoupClientContext *client);
- void (*request_read) (SoupServer *server, SoupMessage *msg,
- SoupClientContext *client);
- void (*request_finished) (SoupServer *server, SoupMessage *msg,
- SoupClientContext *client);
- void (*request_aborted) (SoupServer *server, SoupMessage *msg,
- SoupClientContext *client);
+ void (*request_started) (SoupServer *server,
+ SoupServerMessage *msg);
+ void (*request_read) (SoupServer *server,
+ SoupServerMessage *msg);
+ void (*request_finished) (SoupServer *server,
+ SoupServerMessage *msg);
+ void (*request_aborted) (SoupServer *server,
+ SoupServerMessage *msg);
gpointer padding[6];
};
@@ -98,10 +93,9 @@ gboolean soup_server_accept_iostream (SoupServer *server
/* Handlers and auth */
typedef void (*SoupServerCallback) (SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *path,
GHashTable *query,
- SoupClientContext *client,
gpointer user_data);
SOUP_AVAILABLE_IN_2_4
@@ -121,9 +115,9 @@ void soup_server_add_early_handler (SoupServer *server,
#define SOUP_SERVER_REMOVE_WEBSOCKET_EXTENSION "remove-websocket-extension"
typedef void (*SoupServerWebsocketCallback) (SoupServer *server,
- SoupWebsocketConnection *connection,
+ SoupServerMessage *msg,
const char *path,
- SoupClientContext *client,
+ SoupWebsocketConnection *connection,
gpointer user_data);
SOUP_AVAILABLE_IN_2_50
void soup_server_add_websocket_handler (SoupServer *server,
@@ -153,28 +147,10 @@ void soup_server_remove_auth_domain (SoupServer *server,
/* I/O */
SOUP_AVAILABLE_IN_2_4
-void soup_server_pause_message (SoupServer *server,
- SoupMessage *msg);
-SOUP_AVAILABLE_IN_2_4
-void soup_server_unpause_message (SoupServer *server,
- SoupMessage *msg);
-
-/* Client context */
-
-SOUP_AVAILABLE_IN_2_48
-GSocket *soup_client_context_get_socket (SoupClientContext *client);
-SOUP_AVAILABLE_IN_2_48
-GSocketAddress *soup_client_context_get_local_address (SoupClientContext *client);
-SOUP_AVAILABLE_IN_2_48
-GSocketAddress *soup_client_context_get_remote_address (SoupClientContext *client);
-SOUP_AVAILABLE_IN_2_4
-const char *soup_client_context_get_host (SoupClientContext *client);
+void soup_server_pause_message (SoupServer *server,
+ SoupServerMessage *msg);
SOUP_AVAILABLE_IN_2_4
-SoupAuthDomain *soup_client_context_get_auth_domain (SoupClientContext *client);
-SOUP_AVAILABLE_IN_2_4
-const char *soup_client_context_get_auth_user (SoupClientContext *client);
-
-SOUP_AVAILABLE_IN_2_50
-GIOStream *soup_client_context_steal_connection (SoupClientContext *client);
+void soup_server_unpause_message (SoupServer *server,
+ SoupServerMessage *msg);
G_END_DECLS
diff --git a/libsoup/soup-client-input-stream.c b/libsoup/soup-client-input-stream.c
index 16abb411..8fa28c0b 100644
--- a/libsoup/soup-client-input-stream.c
+++ b/libsoup/soup-client-input-stream.c
@@ -193,8 +193,9 @@ soup_client_input_stream_close_async (GInputStream *stream,
g_task_set_priority (task, priority);
if (close_async_ready (cistream->priv->msg, task) == G_SOURCE_CONTINUE) {
- source = soup_message_io_get_source (cistream->priv->msg,
- cancellable, NULL, NULL);
+ source = soup_message_io_data_get_source ((SoupMessageIOData *)soup_message_get_io_data (cistream->priv->msg),
+ G_OBJECT (cistream->priv->msg),
+ cancellable, NULL, NULL);
g_task_attach_source (task, source, (GSourceFunc) close_async_ready);
g_source_unref (source);
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index df2cdb59..6e39bc7c 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -730,10 +730,10 @@ soup_connection_get_ever_used (SoupConnection *conn)
}
void
-soup_connection_send_request (SoupConnection *conn,
- SoupMessageQueueItem *item,
- SoupMessageCompletionFn completion_cb,
- gpointer user_data)
+soup_connection_send_request (SoupConnection *conn,
+ SoupMessageQueueItem *item,
+ SoupMessageIOCompletionFn completion_cb,
+ gpointer user_data)
{
SoupConnectionPrivate *priv;
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 19888f1f..00c030cf 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -71,10 +71,10 @@ void soup_connection_set_state (SoupConnection *conn,
gboolean soup_connection_get_ever_used (SoupConnection *conn);
-void soup_connection_send_request (SoupConnection *conn,
- SoupMessageQueueItem *item,
- SoupMessageCompletionFn completion_cb,
- gpointer user_data);
+void soup_connection_send_request (SoupConnection *conn,
+ SoupMessageQueueItem *item,
+ SoupMessageIOCompletionFn completion_cb,
+ gpointer user_data);
G_END_DECLS
diff --git a/libsoup/soup-form.c b/libsoup/soup-form.c
index 32e7de3c..e73cca93 100644
--- a/libsoup/soup-form.c
+++ b/libsoup/soup-form.c
@@ -112,13 +112,13 @@ soup_form_decode (const char *encoded_form)
/**
* soup_form_decode_multipart:
- * @msg: a #SoupMessage containing a "multipart/form-data" request body
+ * @multipart: a #SoupMultipart
* @file_control_name: (allow-none): the name of the HTML file upload control, or %NULL
* @filename: (out) (allow-none): return location for the name of the uploaded file, or %NULL
* @content_type: (out) (allow-none): return location for the MIME type of the uploaded file, or %NULL
* @file: (out) (allow-none): return location for the uploaded file data, or %NULL
*
- * Decodes the "multipart/form-data" request in @msg; this is a
+ * Decodes the "multipart/form-data" request in @multipart; this is a
* convenience method for the case when you have a single file upload
* control in a form. (Or when you don't have any file upload
* controls, but are still using "multipart/form-data" anyway.) Pass
@@ -142,29 +142,21 @@ soup_form_decode (const char *encoded_form)
* a hash table containing the name/value pairs (other than
* @file_control_name) from @msg, which you can free with
* g_hash_table_destroy(). On error, it will return %NULL.
- *
- * Since: 2.26
- **/
+ */
GHashTable *
-soup_form_decode_multipart (SoupMessage *msg, const char *file_control_name,
- char **filename, char **content_type,
- GBytes **file)
+soup_form_decode_multipart (SoupMultipart *multipart,
+ const char *file_control_name,
+ char **filename,
+ char **content_type,
+ GBytes **file)
{
- SoupMultipart *multipart;
GHashTable *form_data_set, *params;
SoupMessageHeaders *part_headers;
- GBytes *body;
GBytes *part_body;
char *disposition, *name;
int i;
- g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
-
- body = soup_message_body_flatten (msg->request_body);
- multipart = soup_multipart_new_from_message (msg->request_headers, body);
- g_bytes_unref (body);
- if (!multipart)
- return NULL;
+ g_return_val_if_fail (multipart != NULL, NULL);
if (filename)
*filename = NULL;
diff --git a/libsoup/soup-form.h b/libsoup/soup-form.h
index 4880e7be..27ca8aa1 100644
--- a/libsoup/soup-form.h
+++ b/libsoup/soup-form.h
@@ -17,11 +17,11 @@ G_BEGIN_DECLS
SOUP_AVAILABLE_IN_2_4
GHashTable *soup_form_decode (const char *encoded_form);
SOUP_AVAILABLE_IN_2_26
-GHashTable *soup_form_decode_multipart (SoupMessage *msg,
- const char *file_control_name,
- char **filename,
- char **content_type,
- GBytes **file);
+GHashTable *soup_form_decode_multipart (SoupMultipart *multipart,
+ const char *file_control_name,
+ char **filename,
+ char **content_type,
+ GBytes **file);
SOUP_AVAILABLE_IN_2_4
char *soup_form_encode (const char *first_field,
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
index fbe1e986..5a54b012 100644
--- a/libsoup/soup-headers.c
+++ b/libsoup/soup-headers.c
@@ -195,7 +195,7 @@ soup_headers_parse_request (const char *str,
unsigned long major_version, minor_version;
char *p;
- g_return_val_if_fail (str != NULL, SOUP_STATUS_MALFORMED);
+ g_return_val_if_fail (str != NULL, SOUP_STATUS_BAD_REQUEST);
/* RFC 2616 4.1 "servers SHOULD ignore any empty line(s)
* received where a Request-Line is expected."
diff --git a/libsoup/soup-logger.c b/libsoup/soup-logger.c
index d76701a2..402f4f57 100644
--- a/libsoup/soup-logger.c
+++ b/libsoup/soup-logger.c
@@ -597,22 +597,6 @@ print_request (SoupLogger *logger, SoupMessage *msg,
"%s: %s", name, value);
}
}
- if (log_level == SOUP_LOGGER_LOG_HEADERS)
- return;
-
- if (msg->request_body->length &&
- soup_message_body_get_accumulate (msg->request_body)) {
- GBytes *request;
-
- request = soup_message_body_flatten (msg->request_body);
- g_return_if_fail (request != NULL);
- g_bytes_unref (request);
-
- if (soup_message_headers_get_expectations (msg->request_headers) != SOUP_EXPECTATION_CONTINUE) {
- soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '>',
- "\n%s", msg->request_body->data);
- }
- }
}
static void
@@ -653,13 +637,6 @@ print_response (SoupLogger *logger, SoupMessage *msg)
soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, '<',
"%s: %s", name, value);
}
- if (log_level == SOUP_LOGGER_LOG_HEADERS)
- return;
-
- if (msg->response_body->data) {
- soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '<',
- "\n%s", msg->response_body->data);
- }
}
static void
@@ -688,23 +665,9 @@ got_informational (SoupMessage *msg, gpointer user_data)
print_response (logger, msg);
soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', "\n");
- if (msg->status_code == SOUP_STATUS_CONTINUE && msg->request_body->data) {
- SoupLoggerLogLevel log_level;
-
+ if (msg->status_code == SOUP_STATUS_CONTINUE && msg->request_body_stream) {
soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>',
"[Now sending request body...]");
-
- if (priv->request_filter) {
- log_level = priv->request_filter (logger, msg,
- priv->request_filter_data);
- } else
- log_level = priv->level;
-
- if (log_level == SOUP_LOGGER_LOG_BODY) {
- soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '>',
- "%s", msg->request_body->data);
- }
-
soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', "\n");
}
diff --git a/libsoup/soup-message-io-data.c b/libsoup/soup-message-io-data.c
new file mode 100644
index 00000000..8af99467
--- /dev/null
+++ b/libsoup/soup-message-io-data.c
@@ -0,0 +1,266 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-message-io-data.c: HTTP message I/O data
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include "soup-message-io-data.h"
+#include "soup-message-private.h"
+#include "soup-server-message-private.h"
+#include "soup.h"
+
+#define RESPONSE_BLOCK_SIZE 8192
+#define HEADER_SIZE_LIMIT (64 * 1024)
+
+void
+soup_message_io_data_cleanup (SoupMessageIOData *io)
+{
+ if (io->io_source) {
+ g_source_destroy (io->io_source);
+ g_source_unref (io->io_source);
+ io->io_source = NULL;
+ }
+
+ if (io->iostream)
+ g_object_unref (io->iostream);
+ if (io->body_istream)
+ g_object_unref (io->body_istream);
+ if (io->body_ostream)
+ g_object_unref (io->body_ostream);
+ if (io->async_context)
+ g_main_context_unref (io->async_context);
+
+ g_byte_array_free (io->read_header_buf, TRUE);
+
+ g_string_free (io->write_buf, TRUE);
+
+ if (io->async_wait) {
+ g_cancellable_cancel (io->async_wait);
+ g_clear_object (&io->async_wait);
+ }
+ g_clear_error (&io->async_error);
+}
+
+gboolean
+soup_message_io_data_read_headers (SoupMessageIOData *io,
+ gboolean blocking,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gssize nread, old_len;
+ gboolean got_lf;
+
+ while (1) {
+ old_len = io->read_header_buf->len;
+ g_byte_array_set_size (io->read_header_buf, old_len + RESPONSE_BLOCK_SIZE);
+ nread = soup_filter_input_stream_read_line (io->istream,
+ io->read_header_buf->data + old_len,
+ RESPONSE_BLOCK_SIZE,
+ blocking,
+ &got_lf,
+ cancellable, error);
+ io->read_header_buf->len = old_len + MAX (nread, 0);
+ if (nread == 0) {
+ if (io->read_header_buf->len > 0)
+ break;
+
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_PARTIAL_INPUT,
+ _("Connection terminated unexpectedly"));
+ }
+ if (nread <= 0)
+ return FALSE;
+
+ if (got_lf) {
+ if (nread == 1 && old_len >= 2 &&
+ !strncmp ((char *)io->read_header_buf->data +
+ io->read_header_buf->len - 2,
+ "\n\n", 2)) {
+ io->read_header_buf->len--;
+ 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;
+ break;
+ }
+ }
+
+ if (io->read_header_buf->len > HEADER_SIZE_LIMIT) {
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_PARTIAL_INPUT,
+ _("Header too big"));
+ return FALSE;
+ }
+ }
+
+ io->read_header_buf->data[io->read_header_buf->len] = '\0';
+ return TRUE;
+}
+
+static gboolean
+message_io_is_paused (GObject *msg)
+{
+ if (SOUP_IS_MESSAGE (msg))
+ return soup_message_is_io_paused (SOUP_MESSAGE (msg));
+
+ if (SOUP_IS_SERVER_MESSAGE (msg))
+ return soup_server_message_is_io_paused (SOUP_SERVER_MESSAGE (msg));
+
+ return FALSE;
+}
+
+typedef struct {
+ GSource source;
+ GObject *msg;
+ gboolean paused;
+} SoupMessageIOSource;
+
+static gboolean
+message_io_source_check (GSource *source)
+{
+ SoupMessageIOSource *message_source = (SoupMessageIOSource *)source;
+
+ if (message_source->paused) {
+ if (message_io_is_paused (message_source->msg))
+ return FALSE;
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+static gboolean
+message_io_source_prepare (GSource *source,
+ gint *timeout)
+{
+ *timeout = -1;
+ return message_io_source_check (source);
+}
+
+static gboolean
+message_io_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ SoupMessageIOSourceFunc func = (SoupMessageIOSourceFunc)callback;
+ SoupMessageIOSource *message_source = (SoupMessageIOSource *)source;
+
+ return (*func) (message_source->msg, user_data);
+}
+
+static void
+message_io_source_finalize (GSource *source)
+{
+ SoupMessageIOSource *message_source = (SoupMessageIOSource *)source;
+
+ g_object_unref (message_source->msg);
+}
+
+static gboolean
+message_io_source_closure_callback (GObject *msg,
+ gpointer data)
+{
+ GClosure *closure = data;
+ GValue param = G_VALUE_INIT;
+ GValue result_value = G_VALUE_INIT;
+ gboolean result;
+
+ g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+ g_value_init (&param, G_TYPE_OBJECT);
+ g_value_set_object (&param, msg);
+
+ g_closure_invoke (closure, &result_value, 1, &param, NULL);
+
+ result = g_value_get_boolean (&result_value);
+ g_value_unset (&result_value);
+ g_value_unset (&param);
+
+ return result;
+}
+
+static GSourceFuncs message_io_source_funcs =
+{
+ message_io_source_prepare,
+ message_io_source_check,
+ message_io_source_dispatch,
+ message_io_source_finalize,
+ (GSourceFunc)message_io_source_closure_callback,
+ (GSourceDummyMarshal)g_cclosure_marshal_generic,
+};
+
+GSource *
+soup_message_io_data_get_source (SoupMessageIOData *io,
+ GObject *msg,
+ GCancellable *cancellable,
+ SoupMessageIOSourceFunc callback,
+ gpointer user_data)
+{
+ GSource *base_source, *source;
+ SoupMessageIOSource *message_source;
+
+ if (!io) {
+ base_source = g_timeout_source_new (0);
+ } else if (io->paused) {
+ base_source = NULL;
+ } else if (io->async_wait) {
+ base_source = g_cancellable_source_new (io->async_wait);
+ } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) {
+ GPollableInputStream *istream;
+
+ if (io->body_istream)
+ istream = G_POLLABLE_INPUT_STREAM (io->body_istream);
+ else
+ istream = G_POLLABLE_INPUT_STREAM (io->istream);
+ base_source = g_pollable_input_stream_create_source (istream, cancellable);
+ } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) {
+ GPollableOutputStream *ostream;
+
+ if (io->body_ostream)
+ ostream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream);
+ else
+ ostream = G_POLLABLE_OUTPUT_STREAM (io->ostream);
+ base_source = g_pollable_output_stream_create_source (ostream, cancellable);
+ } else
+ base_source = g_timeout_source_new (0);
+
+ source = g_source_new (&message_io_source_funcs, sizeof (SoupMessageIOSource));
+ g_source_set_name (source, "SoupMessageIOSource");
+ message_source = (SoupMessageIOSource *)source;
+ message_source->msg = g_object_ref (msg);
+ message_source->paused = io && io->paused;
+
+ if (base_source) {
+ g_source_set_dummy_callback (base_source);
+ g_source_add_child_source (source, base_source);
+ g_source_unref (base_source);
+ }
+ g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL);
+ return source;
+}
+
+void
+soup_message_io_data_pause (SoupMessageIOData *io)
+{
+ if (io->io_source) {
+ g_source_destroy (io->io_source);
+ g_source_unref (io->io_source);
+ io->io_source = NULL;
+ }
+
+ io->paused = TRUE;
+}
+
+void
+soup_message_io_data_unpause (SoupMessageIOData *io)
+{
+ io->paused = FALSE;
+}
diff --git a/libsoup/soup-message-io-data.h b/libsoup/soup-message-io-data.h
new file mode 100644
index 00000000..0476a425
--- /dev/null
+++ b/libsoup/soup-message-io-data.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifndef __SOUP_MESSAGE_IO_DATA_H__
+#define __SOUP_MESSAGE_IO_DATA_H__ 1
+
+#include "soup-filter-input-stream.h"
+#include "soup-message-headers.h"
+
+typedef enum {
+ SOUP_MESSAGE_IO_STATE_NOT_STARTED,
+ SOUP_MESSAGE_IO_STATE_ANY = SOUP_MESSAGE_IO_STATE_NOT_STARTED,
+ SOUP_MESSAGE_IO_STATE_HEADERS,
+ SOUP_MESSAGE_IO_STATE_BLOCKING,
+ SOUP_MESSAGE_IO_STATE_BODY_START,
+ SOUP_MESSAGE_IO_STATE_BODY,
+ SOUP_MESSAGE_IO_STATE_BODY_DATA,
+ SOUP_MESSAGE_IO_STATE_BODY_FLUSH,
+ SOUP_MESSAGE_IO_STATE_BODY_DONE,
+ SOUP_MESSAGE_IO_STATE_FINISHING,
+ SOUP_MESSAGE_IO_STATE_DONE
+} SoupMessageIOState;
+
+#define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \
+ (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \
+ state != SOUP_MESSAGE_IO_STATE_BLOCKING && \
+ state != SOUP_MESSAGE_IO_STATE_DONE)
+#define SOUP_MESSAGE_IO_STATE_POLLABLE(state) \
+ (SOUP_MESSAGE_IO_STATE_ACTIVE (state) && \
+ state != SOUP_MESSAGE_IO_STATE_BODY_DONE)
+
+typedef enum {
+ SOUP_MESSAGE_IO_COMPLETE,
+ SOUP_MESSAGE_IO_INTERRUPTED,
+ SOUP_MESSAGE_IO_STOLEN
+} SoupMessageIOCompletion;
+
+typedef void (*SoupMessageIOCompletionFn) (GObject *msg,
+ SoupMessageIOCompletion completion,
+ gpointer user_data);
+
+typedef struct {
+ GIOStream *iostream;
+ SoupFilterInputStream *istream;
+ GInputStream *body_istream;
+ GOutputStream *ostream;
+ GOutputStream *body_ostream;
+ GMainContext *async_context;
+
+ SoupMessageIOState read_state;
+ SoupEncoding read_encoding;
+ GByteArray *read_header_buf;
+ goffset read_length;
+
+ SoupMessageIOState write_state;
+ SoupEncoding write_encoding;
+ GString *write_buf;
+ GBytes *write_chunk;
+ goffset write_body_offset;
+ goffset write_length;
+ goffset written;
+
+ GSource *io_source;
+ gboolean paused;
+
+ GCancellable *async_wait;
+ GError *async_error;
+
+ SoupMessageIOCompletionFn completion_cb;
+ gpointer completion_data;
+
+#ifdef HAVE_SYSPROF
+ gint64 begin_time_nsec;
+#endif
+} SoupMessageIOData;
+
+void soup_message_io_data_cleanup (SoupMessageIOData *io);
+
+gboolean soup_message_io_data_read_headers (SoupMessageIOData *io,
+ gboolean blocking,
+ GCancellable *cancellable,
+ GError **error);
+
+typedef gboolean (*SoupMessageIOSourceFunc) (GObject *msg,
+ gpointer user_data);
+
+GSource *soup_message_io_data_get_source (SoupMessageIOData *io,
+ GObject *msg,
+ GCancellable *cancellable,
+ SoupMessageIOSourceFunc callback,
+ gpointer user_data);
+
+void soup_message_io_data_pause (SoupMessageIOData *io);
+void soup_message_io_data_unpause (SoupMessageIOData *io);
+
+
+#endif /* __SOUP_MESSAGE_IO_DATA_H__ */
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index bfa14417..efa84ef6 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -28,60 +28,37 @@
#include "soup-misc.h"
#include "soup-socket-private.h"
+struct _SoupClientMessageIOData {
+ SoupMessageIOData base;
+
+ SoupMessageQueueItem *item;
+ GCancellable *cancellable;
+
+#ifdef HAVE_SYSPROF
+ gint64 begin_time_nsec;
+#endif
+};
+
#define RESPONSE_BLOCK_SIZE 8192
#define HEADER_SIZE_LIMIT (64 * 1024)
void
-soup_message_io_cleanup (SoupMessage *msg)
+soup_client_message_io_data_free (SoupClientMessageIOData *io)
{
- SoupMessageIOData *io;
-
- io = soup_message_get_io_data (msg);
if (!io)
return;
- if (io->io_source) {
- g_source_destroy (io->io_source);
- g_source_unref (io->io_source);
- io->io_source = NULL;
- }
-
- if (io->unpause_source) {
- g_source_destroy (io->unpause_source);
- g_source_unref (io->unpause_source);
- io->unpause_source = NULL;
- }
+ soup_message_io_data_cleanup (&io->base);
+ soup_message_queue_item_unref (io->item);
- if (io->iostream)
- g_object_unref (io->iostream);
- if (io->body_istream)
- g_object_unref (io->body_istream);
- if (io->body_ostream)
- g_object_unref (io->body_ostream);
- if (io->async_context)
- g_main_context_unref (io->async_context);
- if (io->item)
- soup_message_queue_item_unref (io->item);
-
- g_byte_array_free (io->read_header_buf, TRUE);
-
- g_string_free (io->write_buf, TRUE);
- g_clear_pointer (&io->write_chunk, g_bytes_unref);
-
- if (io->async_wait) {
- g_cancellable_cancel (io->async_wait);
- g_clear_object (&io->async_wait);
- }
- g_clear_error (&io->async_error);
-
- g_slice_free (SoupMessageIOData, io);
+ g_slice_free (SoupClientMessageIOData, io);
}
void
soup_message_io_finished (SoupMessage *msg)
{
- SoupMessageIOData *io;
- SoupMessageCompletionFn completion_cb;
+ SoupClientMessageIOData *io;
+ SoupMessageIOCompletionFn completion_cb;
gpointer completion_data;
SoupMessageIOCompletion completion;
@@ -89,11 +66,11 @@ soup_message_io_finished (SoupMessage *msg)
if (!io)
return;
- completion_cb = io->completion_cb;
- completion_data = io->completion_data;
+ completion_cb = io->base.completion_cb;
+ completion_data = io->base.completion_data;
- if ((io->read_state >= SOUP_MESSAGE_IO_STATE_FINISHING &&
- io->write_state >= SOUP_MESSAGE_IO_STATE_FINISHING))
+ if ((io->base.read_state >= SOUP_MESSAGE_IO_STATE_FINISHING &&
+ io->base.write_state >= SOUP_MESSAGE_IO_STATE_FINISHING))
completion = SOUP_MESSAGE_IO_COMPLETE;
else
completion = SOUP_MESSAGE_IO_INTERRUPTED;
@@ -101,96 +78,35 @@ soup_message_io_finished (SoupMessage *msg)
g_object_ref (msg);
soup_message_set_io_data (msg, NULL);
if (completion_cb)
- completion_cb (msg, completion, completion_data);
+ completion_cb (G_OBJECT (msg), completion, completion_data);
g_object_unref (msg);
}
GIOStream *
soup_message_io_steal (SoupMessage *msg)
{
- SoupMessageIOData *io;
- SoupMessageCompletionFn completion_cb;
+ SoupClientMessageIOData *io;
+ SoupMessageIOCompletionFn completion_cb;
gpointer completion_data;
GIOStream *iostream;
io = soup_message_get_io_data (msg);
- if (!io || !io->iostream)
+ if (!io || !io->base.iostream)
return NULL;
- iostream = g_object_ref (io->iostream);
- completion_cb = io->completion_cb;
- completion_data = io->completion_data;
+ iostream = g_object_ref (io->base.iostream);
+ completion_cb = io->base.completion_cb;
+ completion_data = io->base.completion_data;
g_object_ref (msg);
soup_message_set_io_data (msg, NULL);
if (completion_cb)
- completion_cb (msg, SOUP_MESSAGE_IO_STOLEN, completion_data);
+ completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data);
g_object_unref (msg);
return iostream;
}
-gboolean
-soup_message_io_read_headers (SoupMessage *msg,
- SoupFilterInputStream *stream,
- GByteArray *buffer,
- gboolean blocking,
- GCancellable *cancellable,
- GError **error)
-{
- gssize nread, old_len;
- gboolean got_lf;
-
- while (1) {
- old_len = buffer->len;
- g_byte_array_set_size (buffer, old_len + RESPONSE_BLOCK_SIZE);
- nread = soup_filter_input_stream_read_line (stream,
- buffer->data + old_len,
- RESPONSE_BLOCK_SIZE,
- blocking,
- &got_lf,
- cancellable, error);
- buffer->len = old_len + MAX (nread, 0);
- if (nread == 0) {
- if (buffer->len > 0)
- break;
- soup_message_set_status (msg, SOUP_STATUS_MALFORMED);
- g_set_error_literal (error, G_IO_ERROR,
- G_IO_ERROR_PARTIAL_INPUT,
- _("Connection terminated unexpectedly"));
- }
- if (nread <= 0)
- return FALSE;
-
- if (got_lf) {
- if (nread == 1 && old_len >= 2 &&
- !strncmp ((char *)buffer->data +
- buffer->len - 2,
- "\n\n", 2)) {
- buffer->len--;
- break;
- } else if (nread == 2 && old_len >= 3 &&
- !strncmp ((char *)buffer->data +
- buffer->len - 3,
- "\n\r\n", 3)) {
- buffer->len -= 2;
- break;
- }
- }
-
- if (buffer->len > HEADER_SIZE_LIMIT) {
- soup_message_set_status (msg, SOUP_STATUS_MALFORMED);
- g_set_error_literal (error, G_IO_ERROR,
- G_IO_ERROR_PARTIAL_INPUT,
- _("Header too big"));
- return FALSE;
- }
- }
-
- buffer->data[buffer->len] = '\0';
- return TRUE;
-}
-
static gint
processing_stage_cmp (gconstpointer a,
gconstpointer b)
@@ -257,7 +173,7 @@ request_body_stream_wrote_cb (GOutputStream *ostream,
GAsyncResult *result,
SoupMessage *msg)
{
- SoupMessageIOData *io;
+ SoupClientMessageIOData *io;
gssize nwrote;
GCancellable *async_wait;
GError *error = NULL;
@@ -265,19 +181,19 @@ request_body_stream_wrote_cb (GOutputStream *ostream,
nwrote = g_output_stream_splice_finish (ostream, result, &error);
io = soup_message_get_io_data (msg);
- if (!io || !io->async_wait || io->body_ostream != ostream) {
+ if (!io || !io->base.async_wait || io->base.body_ostream != ostream) {
g_clear_error (&error);
g_object_unref (msg);
return;
}
if (nwrote != -1)
- io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
+ io->base.write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
if (error)
- g_propagate_error (&io->async_error, error);
- async_wait = io->async_wait;
- io->async_wait = NULL;
+ g_propagate_error (&io->base.async_error, error);
+ async_wait = io->base.async_wait;
+ io->base.async_wait = NULL;
g_cancellable_cancel (async_wait);
g_object_unref (async_wait);
@@ -291,20 +207,20 @@ closed_async (GObject *source,
{
GOutputStream *body_ostream = G_OUTPUT_STREAM (source);
SoupMessage *msg = user_data;
- SoupMessageIOData *io;
+ SoupClientMessageIOData *io;
GCancellable *async_wait;
io = soup_message_get_io_data (msg);
- if (!io || !io->async_wait || io->body_ostream != body_ostream) {
+ if (!io || !io->base.async_wait || io->base.body_ostream != body_ostream) {
g_object_unref (msg);
return;
}
- g_output_stream_close_finish (body_ostream, result, &io->async_error);
- g_clear_object (&io->body_ostream);
+ g_output_stream_close_finish (body_ostream, result, &io->base.async_error);
+ g_clear_object (&io->base.body_ostream);
- async_wait = io->async_wait;
- io->async_wait = NULL;
+ async_wait = io->base.async_wait;
+ io->base.async_wait = NULL;
g_cancellable_cancel (async_wait);
g_object_unref (async_wait);
@@ -393,15 +309,6 @@ write_headers (SoupMessage *msg,
g_free (uri_host);
*encoding = soup_message_headers_get_encoding (msg->request_headers);
- if ((*encoding == SOUP_ENCODING_CONTENT_LENGTH ||
- *encoding == SOUP_ENCODING_NONE) &&
- (msg->request_body->length > 0 ||
- soup_message_headers_get_one (msg->request_headers, "Content-Type")) &&
- !soup_message_headers_get_content_length (msg->request_headers)) {
- *encoding = SOUP_ENCODING_CONTENT_LENGTH;
- soup_message_headers_set_content_length (msg->request_headers,
- msg->request_body->length);
- }
soup_message_headers_iter_init (&iter, msg->request_headers);
while (soup_message_headers_iter_next (&iter, &name, &value))
@@ -419,7 +326,8 @@ static gboolean
io_write (SoupMessage *msg, gboolean blocking,
GCancellable *cancellable, GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+ SoupMessageIOData *io = &client_io->base;
gssize nwrote;
if (io->async_error) {
@@ -436,7 +344,7 @@ io_write (SoupMessage *msg, gboolean blocking,
switch (io->write_state) {
case SOUP_MESSAGE_IO_STATE_HEADERS:
if (!io->write_buf->len)
- write_headers (msg, io->write_buf, io->item->conn, &io->write_encoding);
+ write_headers (msg, io->write_buf, client_io->item->conn, &io->write_encoding);
while (io->written < io->write_buf->len) {
nwrote = g_pollable_stream_write (io->ostream,
@@ -607,13 +515,17 @@ static gboolean
io_read (SoupMessage *msg, gboolean blocking,
GCancellable *cancellable, GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+ SoupMessageIOData *io = &client_io->base;
guint status;
switch (io->read_state) {
case SOUP_MESSAGE_IO_STATE_HEADERS:
- if (!soup_message_io_read_headers (msg, io->istream, io->read_header_buf, blocking, cancellable, error))
+ if (!soup_message_io_data_read_headers (io, blocking, cancellable, error)) {
+ if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT))
+ soup_message_set_status (msg, SOUP_STATUS_MALFORMED);
return FALSE;
+ }
status = parse_headers (msg,
(char *)io->read_header_buf->data,
@@ -658,7 +570,7 @@ io_read (SoupMessage *msg, gboolean blocking,
/* If this was "101 Switching Protocols", then
* the session may have stolen the connection...
*/
- if (io != soup_message_get_io_data (msg))
+ if (client_io != soup_message_get_io_data (msg))
return FALSE;
soup_message_cleanup_response (msg);
@@ -698,7 +610,7 @@ io_read (SoupMessage *msg, gboolean blocking,
io->read_length);
io->body_istream = soup_message_setup_body_istream (body_istream, msg,
- io->item->session,
+ client_io->item->session,
SOUP_STAGE_MESSAGE_BODY);
g_object_unref (body_istream);
}
@@ -753,148 +665,18 @@ io_read (SoupMessage *msg, gboolean blocking,
return TRUE;
}
-typedef struct {
- GSource source;
- SoupMessage *msg;
- gboolean paused;
-} SoupMessageSource;
-
-static gboolean
-message_source_check (GSource *source)
-{
- SoupMessageSource *message_source = (SoupMessageSource *)source;
-
- if (message_source->paused) {
- SoupMessageIOData *io = soup_message_get_io_data (message_source->msg);
-
- if (io && io->paused)
- return FALSE;
- else
- return TRUE;
- } else
- return FALSE;
-}
-
-static gboolean
-message_source_prepare (GSource *source,
- gint *timeout)
-{
- *timeout = -1;
- return message_source_check (source);
-}
-
-static gboolean
-message_source_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
-{
- SoupMessageSourceFunc func = (SoupMessageSourceFunc)callback;
- SoupMessageSource *message_source = (SoupMessageSource *)source;
-
- return (*func) (message_source->msg, user_data);
-}
-
-static void
-message_source_finalize (GSource *source)
-{
- SoupMessageSource *message_source = (SoupMessageSource *)source;
-
- g_object_unref (message_source->msg);
-}
-
-static gboolean
-message_source_closure_callback (SoupMessage *msg,
- gpointer data)
-{
- GClosure *closure = data;
- GValue param = G_VALUE_INIT;
- GValue result_value = G_VALUE_INIT;
- gboolean result;
-
- g_value_init (&result_value, G_TYPE_BOOLEAN);
-
- g_value_init (&param, SOUP_TYPE_MESSAGE);
- g_value_set_object (&param, msg);
-
- g_closure_invoke (closure, &result_value, 1, &param, NULL);
-
- result = g_value_get_boolean (&result_value);
- g_value_unset (&result_value);
- g_value_unset (&param);
-
- return result;
-}
-
-static GSourceFuncs message_source_funcs =
-{
- message_source_prepare,
- message_source_check,
- message_source_dispatch,
- message_source_finalize,
- (GSourceFunc)message_source_closure_callback,
- (GSourceDummyMarshal)g_cclosure_marshal_generic,
-};
-
-GSource *
-soup_message_io_get_source (SoupMessage *msg, GCancellable *cancellable,
- SoupMessageSourceFunc callback, gpointer user_data)
-{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
- GSource *base_source, *source;
- SoupMessageSource *message_source;
-
- if (!io) {
- base_source = g_timeout_source_new (0);
- } else if (io->paused) {
- base_source = NULL;
- } else if (io->async_wait) {
- base_source = g_cancellable_source_new (io->async_wait);
- } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) {
- GPollableInputStream *istream;
-
- if (io->body_istream)
- istream = G_POLLABLE_INPUT_STREAM (io->body_istream);
- else
- istream = G_POLLABLE_INPUT_STREAM (io->istream);
- base_source = g_pollable_input_stream_create_source (istream, cancellable);
- } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) {
- GPollableOutputStream *ostream;
-
- if (io->body_ostream)
- ostream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream);
- else
- ostream = G_POLLABLE_OUTPUT_STREAM (io->ostream);
- base_source = g_pollable_output_stream_create_source (ostream, cancellable);
- } else
- base_source = g_timeout_source_new (0);
-
- source = g_source_new (&message_source_funcs,
- sizeof (SoupMessageSource));
- g_source_set_name (source, "SoupMessageSource");
- message_source = (SoupMessageSource *)source;
- message_source->msg = g_object_ref (msg);
- message_source->paused = io && io->paused;
-
- if (base_source) {
- g_source_set_dummy_callback (base_source);
- g_source_add_child_source (source, base_source);
- g_source_unref (base_source);
- }
- g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL);
- return source;
-}
-
static gboolean
request_is_restartable (SoupMessage *msg, GError *error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+ SoupMessageIOData *io = &client_io->base;
- if (!io)
+ if (!client_io)
return FALSE;
return (io->read_state <= SOUP_MESSAGE_IO_STATE_HEADERS &&
io->read_header_buf->len == 0 &&
- soup_connection_get_ever_used (io->item->conn) &&
+ soup_connection_get_ever_used (client_io->item->conn) &&
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) &&
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) &&
error->domain != G_TLS_ERROR &&
@@ -906,7 +688,8 @@ io_run_until (SoupMessage *msg, gboolean blocking,
SoupMessageIOState read_state, SoupMessageIOState write_state,
GCancellable *cancellable, GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+ SoupMessageIOData *io = &client_io->base;
gboolean progress = TRUE, done;
GError *my_error = NULL;
@@ -921,7 +704,7 @@ io_run_until (SoupMessage *msg, gboolean blocking,
g_object_ref (msg);
- while (progress && soup_message_get_io_data (msg) == io && !io->paused && !io->async_wait &&
+ while (progress && soup_message_get_io_data (msg) == client_io && !io->paused && !io->async_wait &&
(io->read_state < read_state || io->write_state < write_state)) {
if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
@@ -945,7 +728,7 @@ io_run_until (SoupMessage *msg, gboolean blocking,
g_propagate_error (error, my_error);
g_object_unref (msg);
return FALSE;
- } else if (soup_message_get_io_data (msg) != io) {
+ } else if (soup_message_get_io_data (msg) != client_io) {
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_CANCELLED,
_("Operation was cancelled"));
@@ -979,7 +762,8 @@ io_run_until (SoupMessage *msg, gboolean blocking,
/* FIXME: Expand and generalise sysprof support:
* https://gitlab.gnome.org/GNOME/sysprof/-/issues/43 */
- sysprof_collector_mark_printf (io->begin_time_nsec, SYSPROF_CAPTURE_CURRENT_TIME - io->begin_time_nsec,
+ sysprof_collector_mark_printf (client_io->begin_time_nsec,
+ SYSPROF_CAPTURE_CURRENT_TIME - client_io->begin_time_nsec,
"libsoup", "message",
"%s request/response to %s: "
"read %" G_GOFFSET_FORMAT "B, "
@@ -1003,7 +787,7 @@ soup_message_io_update_status (SoupMessage *msg,
GError *error)
{
if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) {
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
io->item->state = SOUP_MESSAGE_RESTARTING;
} else if (error->domain == G_TLS_ERROR) {
@@ -1029,7 +813,8 @@ void
soup_message_io_run (SoupMessage *msg,
gboolean blocking)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+ SoupMessageIOData *io = &client_io->base;
GError *error = NULL;
GCancellable *cancellable;
@@ -1040,7 +825,7 @@ soup_message_io_run (SoupMessage *msg,
}
g_object_ref (msg);
- cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL;
+ cancellable = client_io->cancellable ? g_object_ref (client_io->cancellable) : NULL;
if (io_run_until (msg, blocking,
SOUP_MESSAGE_IO_STATE_DONE,
@@ -1049,10 +834,12 @@ soup_message_io_run (SoupMessage *msg,
soup_message_io_finished (msg);
} else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
g_clear_error (&error);
- io->io_source = soup_message_io_get_source (msg, NULL, io_run_ready, msg);
+ io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL,
+ (SoupMessageIOSourceFunc)io_run_ready,
+ NULL);
g_source_attach (io->io_source, io->async_context);
} else {
- if (soup_message_get_io_data (msg) == io)
+ if (soup_message_get_io_data (msg) == client_io)
soup_message_io_update_status (msg, error);
g_error_free (error);
@@ -1067,7 +854,7 @@ soup_message_io_run_until_read (SoupMessage *msg,
GCancellable *cancellable,
GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
if (io_run_until (msg, TRUE,
SOUP_MESSAGE_IO_STATE_BODY,
@@ -1098,7 +885,8 @@ static void
io_run_until_read_async (SoupMessage *msg,
GTask *task)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+ SoupMessageIOData *io = &client_io->base;
GError *error = NULL;
if (io->io_source) {
@@ -1119,12 +907,14 @@ io_run_until_read_async (SoupMessage *msg,
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
g_error_free (error);
- io->io_source = soup_message_io_get_source (msg, NULL, io_run_until_read_ready, task);
+ io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL,
+ (SoupMessageIOSourceFunc)io_run_until_read_ready,
+ task);
g_source_attach (io->io_source, io->async_context);
return;
}
- if (soup_message_get_io_data (msg) == io)
+ if (soup_message_get_io_data (msg) == client_io)
soup_message_io_update_status (msg, error);
g_task_return_error (task, error);
@@ -1157,14 +947,14 @@ soup_message_io_run_until_finish (SoupMessage *msg,
GCancellable *cancellable,
GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
gboolean success;
g_object_ref (msg);
if (io) {
- if (io->read_state < SOUP_MESSAGE_IO_STATE_BODY_DONE)
- io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
+ if (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY_DONE)
+ io->base.read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
}
success = io_run_until (msg, blocking,
@@ -1180,17 +970,17 @@ static void
client_stream_eof (SoupClientInputStream *stream, gpointer user_data)
{
SoupMessage *msg = user_data;
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
- if (io && io->read_state == SOUP_MESSAGE_IO_STATE_BODY)
- io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
+ if (io && io->base.read_state == SOUP_MESSAGE_IO_STATE_BODY)
+ io->base.read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
}
GInputStream *
soup_message_io_get_response_istream (SoupMessage *msg,
GError **error)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
GInputStream *client_stream;
if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
@@ -1199,7 +989,7 @@ soup_message_io_get_response_istream (SoupMessage *msg,
return NULL;
}
- client_stream = soup_client_input_stream_new (io->body_istream, msg);
+ client_stream = soup_client_input_stream_new (io->base.body_istream, msg);
g_signal_connect (client_stream, "eof",
G_CALLBACK (client_stream_eof), msg);
@@ -1208,28 +998,28 @@ soup_message_io_get_response_istream (SoupMessage *msg,
void
soup_message_send_request (SoupMessageQueueItem *item,
- SoupMessageCompletionFn completion_cb,
+ SoupMessageIOCompletionFn completion_cb,
gpointer user_data)
{
- SoupMessageIOData *io;
+ SoupClientMessageIOData *io;
- io = g_slice_new0 (SoupMessageIOData);
- io->completion_cb = completion_cb;
- io->completion_data = user_data;
+ io = g_slice_new0 (SoupClientMessageIOData);
+ io->base.completion_cb = completion_cb;
+ io->base.completion_data = user_data;
io->item = item;
soup_message_queue_item_ref (item);
io->cancellable = io->item->cancellable;
- io->iostream = g_object_ref (soup_socket_get_iostream (soup_connection_get_socket (io->item->conn)));
- io->istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->iostream));
- io->ostream = g_io_stream_get_output_stream (io->iostream);
- io->async_context = g_main_context_ref_thread_default ();
+ io->base.iostream = g_object_ref (soup_socket_get_iostream (soup_connection_get_socket (io->item->conn)));
+ io->base.istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->base.iostream));
+ io->base.ostream = g_io_stream_get_output_stream (io->base.iostream);
+ io->base.async_context = g_main_context_ref_thread_default ();
- io->read_header_buf = g_byte_array_new ();
- io->write_buf = g_string_new (NULL);
+ io->base.read_header_buf = g_byte_array_new ();
+ io->base.write_buf = g_string_new (NULL);
- io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
- io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
+ io->base.read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
+ io->base.write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
#ifdef HAVE_SYSPROF
io->begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
@@ -1238,65 +1028,25 @@ soup_message_send_request (SoupMessageQueueItem *item,
soup_message_set_io_data (io->item->msg, io);
}
-void
+void
soup_message_io_pause (SoupMessage *msg)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
g_return_if_fail (io != NULL);
+ g_return_if_fail (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY);
- if (io->item)
- g_return_if_fail (io->read_state < SOUP_MESSAGE_IO_STATE_BODY);
-
- if (io->io_source) {
- g_source_destroy (io->io_source);
- g_source_unref (io->io_source);
- io->io_source = NULL;
- }
-
- if (io->unpause_source) {
- g_source_destroy (io->unpause_source);
- g_source_unref (io->unpause_source);
- io->unpause_source = NULL;
- }
-
- io->paused = TRUE;
-}
-
-static gboolean
-io_unpause_internal (gpointer msg)
-{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
-
- g_return_val_if_fail (io != NULL, FALSE);
-
- g_clear_pointer (&io->unpause_source, g_source_unref);
- io->paused = FALSE;
-
- if (io->io_source)
- return FALSE;
-
- soup_message_io_run (msg, FALSE);
- return FALSE;
+ soup_message_io_data_pause (&io->base);
}
void
soup_message_io_unpause (SoupMessage *msg)
{
- SoupMessageIOData *io = soup_message_get_io_data (msg);
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
g_return_if_fail (io != NULL);
-
- if (io->item) {
- g_return_if_fail (io->read_state < SOUP_MESSAGE_IO_STATE_BODY);
- io->paused = FALSE;
- return;
- }
-
- if (!io->unpause_source) {
- io->unpause_source = soup_add_completion_reffed (io->async_context,
- io_unpause_internal, msg, NULL);
- }
+ g_return_if_fail (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY);
+ io->base.paused = FALSE;
}
/**
@@ -1312,3 +1062,11 @@ soup_message_io_in_progress (SoupMessage *msg)
{
return soup_message_get_io_data (msg) != NULL;
}
+
+gboolean
+soup_message_is_io_paused (SoupMessage *msg)
+{
+ SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+
+ return io && io->base.paused;
+}
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index 1200adba..0ce07e8f 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -8,13 +8,17 @@
#include "soup-filter-input-stream.h"
#include "soup-message.h"
+#include "soup-message-io-data.h"
#include "auth/soup-auth.h"
#include "content-sniffer/soup-content-processor.h"
#include "content-sniffer/soup-content-sniffer.h"
#include "soup-session.h"
+typedef struct _SoupClientMessageIOData SoupClientMessageIOData;
+void soup_client_message_io_data_free (SoupClientMessageIOData *io);
+
typedef struct {
- gpointer io_data;
+ SoupClientMessageIOData *io_data;
guint msg_flags;
gboolean server_side;
@@ -46,12 +50,6 @@ typedef struct {
void soup_message_cleanup_response (SoupMessage *msg);
-typedef enum {
- SOUP_MESSAGE_IO_COMPLETE,
- SOUP_MESSAGE_IO_INTERRUPTED,
- SOUP_MESSAGE_IO_STOLEN
-} SoupMessageIOCompletion;
-
typedef void (*SoupMessageGetHeadersFn) (SoupMessage *msg,
GString *headers,
SoupEncoding *encoding,
@@ -62,17 +60,9 @@ typedef guint (*SoupMessageParseHeadersFn)(SoupMessage *msg,
SoupEncoding *encoding,
gpointer user_data,
GError **error);
-typedef void (*SoupMessageCompletionFn) (SoupMessage *msg,
- SoupMessageIOCompletion completion,
- gpointer user_data);
-
void soup_message_send_request (SoupMessageQueueItem *item,
- SoupMessageCompletionFn completion_cb,
- gpointer user_data);
-void soup_message_read_request (SoupMessage *msg,
- SoupSocket *sock,
- SoupMessageCompletionFn completion_cb,
+ SoupMessageIOCompletionFn completion_cb,
gpointer user_data);
/* Auth handling */
@@ -84,77 +74,13 @@ void soup_message_set_proxy_auth (SoupMessage *msg,
SoupAuth *soup_message_get_proxy_auth (SoupMessage *msg);
/* I/O */
-typedef enum {
- SOUP_MESSAGE_IO_STATE_NOT_STARTED,
- SOUP_MESSAGE_IO_STATE_ANY = SOUP_MESSAGE_IO_STATE_NOT_STARTED,
- SOUP_MESSAGE_IO_STATE_HEADERS,
- SOUP_MESSAGE_IO_STATE_BLOCKING,
- SOUP_MESSAGE_IO_STATE_BODY_START,
- SOUP_MESSAGE_IO_STATE_BODY,
- SOUP_MESSAGE_IO_STATE_BODY_DATA,
- SOUP_MESSAGE_IO_STATE_BODY_FLUSH,
- SOUP_MESSAGE_IO_STATE_BODY_DONE,
- SOUP_MESSAGE_IO_STATE_FINISHING,
- SOUP_MESSAGE_IO_STATE_DONE
-} SoupMessageIOState;
-
-#define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \
- (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \
- state != SOUP_MESSAGE_IO_STATE_BLOCKING && \
- state != SOUP_MESSAGE_IO_STATE_DONE)
-#define SOUP_MESSAGE_IO_STATE_POLLABLE(state) \
- (SOUP_MESSAGE_IO_STATE_ACTIVE (state) && \
- state != SOUP_MESSAGE_IO_STATE_BODY_DONE)
-
-typedef struct {
- /* Client only */
- SoupMessageQueueItem *item;
- GCancellable *cancellable;
-
- /* Server only */
- SoupSocket *sock;
-
- GIOStream *iostream;
- SoupFilterInputStream *istream;
- GInputStream *body_istream;
- GOutputStream *ostream;
- GOutputStream *body_ostream;
- GMainContext *async_context;
-
- SoupMessageIOState read_state;
- SoupEncoding read_encoding;
- GByteArray *read_header_buf;
- goffset read_length;
-
- SoupMessageIOState write_state;
- SoupEncoding write_encoding;
- GString *write_buf;
- GBytes *write_chunk;
- goffset write_body_offset;
- goffset write_length;
- goffset written;
-
- GSource *io_source;
- GSource *unpause_source;
- gboolean paused;
-
- GCancellable *async_wait;
- GError *async_error;
-
- SoupMessageCompletionFn completion_cb;
- gpointer completion_data;
-
-#ifdef HAVE_SYSPROF
- gint64 begin_time_nsec;
-#endif
-} SoupMessageIOData;
-
void soup_message_io_run (SoupMessage *msg,
gboolean blocking);
void soup_message_io_finished (SoupMessage *msg);
void soup_message_io_cleanup (SoupMessage *msg);
void soup_message_io_pause (SoupMessage *msg);
void soup_message_io_unpause (SoupMessage *msg);
+gboolean soup_message_is_io_paused (SoupMessage *msg);
gboolean soup_message_io_in_progress (SoupMessage *msg);
GIOStream *soup_message_io_steal (SoupMessage *msg);
@@ -214,9 +140,9 @@ SoupConnection *soup_message_get_connection (SoupMessage *msg);
void soup_message_set_connection (SoupMessage *msg,
SoupConnection *conn);
-gpointer soup_message_get_io_data (SoupMessage *msg);
-void soup_message_set_io_data (SoupMessage *msg,
- gpointer io);
+SoupClientMessageIOData *soup_message_get_io_data (SoupMessage *msg);
+void soup_message_set_io_data (SoupMessage *msg,
+ SoupClientMessageIOData *io);
SoupContentSniffer *soup_message_get_content_sniffer (SoupMessage *msg);
void soup_message_set_content_sniffer (SoupMessage *msg,
@@ -224,7 +150,4 @@ void soup_message_set_content_sniffer (SoupMessage *msg
void soup_message_set_bytes_for_sniffing (SoupMessage *msg,
gsize bytes);
-const char *soup_http_version_to_string (SoupHTTPVersion version);
-
-
#endif /* __SOUP_MESSAGE_PRIVATE_H__ */
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 5ead16d9..0a265dea 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -19,13 +19,13 @@
/**
* SECTION:soup-message
* @short_description: An HTTP request and response.
- * @see_also: #SoupMessageHeaders, #SoupMessageBody
+ * @see_also: #SoupMessageHeaders
*
* A #SoupMessage represents an HTTP message that is being sent or
* received.
*
- * For client-side usage, you would create a #SoupMessage with
- * soup_message_new() or soup_message_new_from_uri(), set up its
+ * You would create a #SoupMessage with soup_message_new() or
+ * soup_message_new_from_uri(), set up its
* fields appropriately, and send it. If you are using the newer
* #SoupRequest API, you would create a request with
* soup_session_request_http() or soup_session_request_http_uri(), and
@@ -33,10 +33,6 @@
* #SoupMessage that you can retrieve via
* soup_request_http_get_message().
*
- * For server-side usage, #SoupServer will create #SoupMessage<!--
- * -->s automatically for incoming requests, which your application
- * will receive via handlers.
- *
* Note that libsoup's terminology here does not quite match the HTTP
* specification: in RFC 2616, an "HTTP-message" is
* <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a
@@ -49,9 +45,7 @@
* @method: the HTTP method
* @status_code: the HTTP status code
* @reason_phrase: the status phrase associated with @status_code
- * @request_body: the request body
* @request_headers: the request headers
- * @response_body: the response body
* @response_headers: the response headers
*
* Represents an HTTP message being sent or received.
@@ -66,48 +60,17 @@
* messages. Rather, you should look at @status_code, and determine an
* end-user-appropriate message based on that and on what you were
* trying to do.
- *
- * As described in the #SoupMessageBody documentation, the
- * @request_body and @response_body <literal>data</literal> fields
- * will not necessarily be filled in at all times. When the body
- * fields are filled in, they will be terminated with a '\0' byte
- * (which is not included in the <literal>length</literal>), so you
- * can use them as ordinary C strings (assuming that you know that the
- * body doesn't have any other '\0' bytes).
- *
- * For a client-side #SoupMessage, @request_body's
- * <literal>data</literal> is usually 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
- * <literal>data</literal> is filled in. If you are not using
- * #SoupRequest to read the response, then @response_body's
- * <literal>data</literal> will be filled in before
- * #SoupMessage::finished is emitted. (If you are using #SoupRequest,
- * then the message body is not accumulated by default, so
- * @response_body's <literal>data</literal> will always be %NULL.)
- *
- * 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_WITH_PRIVATE (SoupMessage, soup_message, G_TYPE_OBJECT)
enum {
- WROTE_INFORMATIONAL,
WROTE_HEADERS,
- WROTE_CHUNK,
WROTE_BODY_DATA,
WROTE_BODY,
GOT_INFORMATIONAL,
GOT_HEADERS,
- GOT_CHUNK,
GOT_BODY,
CONTENT_SNIFFED,
@@ -129,15 +92,10 @@ enum {
PROP_URI,
PROP_HTTP_VERSION,
PROP_FLAGS,
- PROP_SERVER_SIDE,
PROP_STATUS_CODE,
PROP_REASON_PHRASE,
PROP_FIRST_PARTY,
- PROP_REQUEST_BODY,
- PROP_REQUEST_BODY_DATA,
PROP_REQUEST_HEADERS,
- PROP_RESPONSE_BODY,
- PROP_RESPONSE_BODY_DATA,
PROP_RESPONSE_HEADERS,
PROP_TLS_CERTIFICATE,
PROP_TLS_ERRORS,
@@ -156,9 +114,7 @@ soup_message_init (SoupMessage *msg)
priv->http_version = priv->orig_http_version = SOUP_HTTP_1_1;
priv->priority = SOUP_MESSAGE_PRIORITY_NORMAL;
- msg->request_body = soup_message_body_new ();
msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
- msg->response_body = soup_message_body_new ();
msg->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
}
@@ -168,7 +124,7 @@ soup_message_finalize (GObject *object)
SoupMessage *msg = SOUP_MESSAGE (object);
SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
- soup_message_io_cleanup (msg);
+ soup_client_message_io_data_free (priv->io_data);
g_clear_pointer (&priv->uri, soup_uri_free);
g_clear_pointer (&priv->first_party, soup_uri_free);
@@ -181,11 +137,9 @@ soup_message_finalize (GObject *object)
g_clear_object (&priv->tls_certificate);
- soup_message_body_free (msg->request_body);
soup_message_headers_free (msg->request_headers);
- g_clear_object (&msg->request_body_stream);
- soup_message_body_free (msg->response_body);
soup_message_headers_free (msg->response_headers);
+ g_clear_object (&msg->request_body_stream);
g_free (msg->reason_phrase);
@@ -218,13 +172,6 @@ soup_message_set_property (GObject *object, guint prop_id,
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);
- if (priv->server_side) {
- soup_message_headers_set_encoding (msg->response_headers,
- SOUP_ENCODING_CONTENT_LENGTH);
- }
- break;
case PROP_STATUS_CODE:
soup_message_set_status (msg, g_value_get_uint (value));
break;
@@ -266,7 +213,6 @@ soup_message_get_property (GObject *object, guint prop_id,
{
SoupMessage *msg = SOUP_MESSAGE (object);
SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
- GBytes *buf;
switch (prop_id) {
case PROP_METHOD:
@@ -287,9 +233,6 @@ soup_message_get_property (GObject *object, guint prop_id,
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;
@@ -299,23 +242,9 @@ soup_message_get_property (GObject *object, guint prop_id,
case PROP_FIRST_PARTY:
g_value_set_boxed (value, priv->first_party);
break;
- case PROP_REQUEST_BODY:
- g_value_set_boxed (value, msg->request_body);
- break;
- case PROP_REQUEST_BODY_DATA:
- buf = soup_message_body_flatten (msg->request_body);
- g_value_take_boxed (value, buf);
- break;
case PROP_REQUEST_HEADERS:
g_value_set_boxed (value, msg->request_headers);
break;
- case PROP_RESPONSE_BODY:
- g_value_set_boxed (value, msg->response_body);
- break;
- case PROP_RESPONSE_BODY_DATA:
- buf = soup_message_body_flatten (msg->response_body);
- g_value_take_boxed (value, buf);
- break;
case PROP_RESPONSE_HEADERS:
g_value_set_boxed (value, msg->response_headers);
break;
@@ -335,26 +264,10 @@ soup_message_get_property (GObject *object, guint prop_id,
}
static void
-soup_message_real_got_body (SoupMessage *msg)
-{
- SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
- SoupMessageBody *body;
-
- body = priv->server_side ? msg->request_body : msg->response_body;
- if (soup_message_body_get_accumulate (body)) {
- GBytes *buffer = soup_message_body_flatten (body);
- g_bytes_unref (buffer);
- }
-}
-
-static void
soup_message_class_init (SoupMessageClass *message_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (message_class);
- /* virtual method definition */
- message_class->got_body = soup_message_real_got_body;
-
/* virtual method override */
object_class->finalize = soup_message_finalize;
object_class->set_property = soup_message_set_property;
@@ -363,29 +276,11 @@ soup_message_class_init (SoupMessageClass *message_class)
/* signals */
/**
- * SoupMessage::wrote-informational:
- * @msg: the message
- *
- * Emitted immediately after writing a 1xx (Informational)
- * response for a (server-side) message.
- **/
- signals[WROTE_INFORMATIONAL] =
- g_signal_new ("wrote_informational",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SoupMessageClass, wrote_informational),
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 0);
-
- /**
* SoupMessage::wrote-headers:
* @msg: the message
*
- * Emitted immediately after writing the headers for a
- * message. (For a client-side message, this is after writing
- * the request headers; for a server-side message, it is after
- * writing the response headers.)
+ * Emitted immediately after writing the request headers for a
+ * message.
**/
signals[WROTE_HEADERS] =
g_signal_new ("wrote_headers",
@@ -397,28 +292,6 @@ soup_message_class_init (SoupMessageClass *message_class)
G_TYPE_NONE, 0);
/**
- * SoupMessage::wrote-chunk:
- * @msg: the message
- *
- * Emitted immediately after writing a body chunk for a message.
- *
- * Note that this signal is not parallel to
- * #SoupMessage::got_chunk; it is emitted only when a complete
- * chunk (added with soup_message_body_append() or
- * soup_message_body_append_bytes()) has been written. To get
- * more useful continuous progress information, use
- * #SoupMessage::wrote_body_data.
- **/
- signals[WROTE_CHUNK] =
- g_signal_new ("wrote_chunk",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk),
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 0);
-
- /**
* SoupMessage::wrote-body-data:
* @msg: the message
* @chunk: the data written
@@ -426,10 +299,6 @@ soup_message_class_init (SoupMessageClass *message_class)
* Emitted immediately after writing a portion of the message
* body to the network.
*
- * Unlike #SoupMessage::wrote_chunk, this is emitted after
- * every successful write() call, not only after finishing a
- * complete "chunk".
- *
* Since: 2.24
**/
signals[WROTE_BODY_DATA] =
@@ -447,11 +316,7 @@ soup_message_class_init (SoupMessageClass *message_class)
* @msg: the message
*
* Emitted immediately after writing the complete body for a
- * message. (For a client-side message, this means that
- * libsoup is done writing and is now waiting for the response
- * from the server. For a server-side message, this means that
- * libsoup has finished writing the response and is nearly
- * done with the message.)
+ * message.
**/
signals[WROTE_BODY] =
g_signal_new ("wrote_body",
@@ -489,11 +354,7 @@ soup_message_class_init (SoupMessageClass *message_class)
* SoupMessage::got-headers:
* @msg: the message
*
- * Emitted after receiving all message headers for a message.
- * (For a client-side message, this is after receiving the
- * Status-Line and response headers; for a server-side
- * message, it is after receiving the Request-Line and request
- * headers.)
+ * Emitted after receiving the Status-Line and response headers.
*
* See also soup_message_add_header_handler() and
* soup_message_add_status_code_handler(), which can be used
@@ -518,37 +379,10 @@ soup_message_class_init (SoupMessageClass *message_class)
G_TYPE_NONE, 0);
/**
- * SoupMessage::got-chunk:
- * @msg: the message
- * @chunk: the just-read chunk
- *
- * Emitted after receiving a chunk of a message body. Note
- * that "chunk" in this context means any subpiece of the
- * body, not necessarily the specific HTTP 1.1 chunks sent by
- * the other side.
- *
- * If you cancel or requeue @msg while processing this signal,
- * then the current HTTP I/O will be stopped after this signal
- * emission finished, and @msg's connection will be closed.
- **/
- signals[GOT_CHUNK] =
- g_signal_new ("got_chunk",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SoupMessageClass, got_chunk),
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 1,
- G_TYPE_BYTES);
-
- /**
* SoupMessage::got-body:
* @msg: the message
*
- * Emitted after receiving the complete message body. (For a
- * server-side message, this means it has received the request
- * body. For a client-side message, this means it has received
- * the response body and is nearly done with the message.)
+ * Emitted after receiving the complete message request body.
*
* See also soup_message_add_header_handler() and
* soup_message_add_status_code_handler(), which can be used
@@ -642,8 +476,7 @@ soup_message_class_init (SoupMessageClass *message_class)
* @msg: the message
*
* Emitted when all HTTP processing is finished for a message.
- * (After #SoupMessage::got_body for client-side messages, or
- * after #SoupMessage::wrote_body for server-side messages.)
+ * (After #SoupMessage::got_body).
**/
signals[FINISHED] =
g_signal_new ("finished",
@@ -746,20 +579,6 @@ soup_message_class_init (SoupMessageClass *message_class)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
- * SOUP_MESSAGE_SERVER_SIDE:
- *
- * Alias for the #SoupMessage:server-side property. (%TRUE if
- * the message was created by #SoupServer.)
- **/
- 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_PARAM_STATIC_STRINGS));
- /**
* SOUP_MESSAGE_STATUS_CODE:
*
* Alias for the #SoupMessage:status-code property. (The
@@ -841,43 +660,6 @@ soup_message_class_init (SoupMessageClass *message_class)
FALSE,
G_PARAM_READWRITE));
/**
- * SOUP_MESSAGE_REQUEST_BODY:
- *
- * Alias for the #SoupMessage:request-body property. (The
- * message's HTTP request body.)
- **/
- g_object_class_install_property (
- object_class, PROP_REQUEST_BODY,
- g_param_spec_boxed (SOUP_MESSAGE_REQUEST_BODY,
- "Request Body",
- "The HTTP request content",
- SOUP_TYPE_MESSAGE_BODY,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
- /**
- * SOUP_MESSAGE_REQUEST_BODY_DATA:
- *
- * Alias for the #SoupMessage:request-body-data property. (The
- * message's HTTP request body, as a #GBytes.)
- *
- * Since: 2.46
- **/
- /**
- * SoupMessage:request-body-data:
- *
- * The message's HTTP request body, as a #GBytes.
- *
- * Since: 2.46
- **/
- g_object_class_install_property (
- object_class, PROP_REQUEST_BODY_DATA,
- g_param_spec_boxed (SOUP_MESSAGE_REQUEST_BODY_DATA,
- "Request Body Data",
- "The HTTP request body",
- G_TYPE_BYTES,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
- /**
* SOUP_MESSAGE_REQUEST_HEADERS:
*
* Alias for the #SoupMessage:request-headers property. (The
@@ -892,43 +674,6 @@ soup_message_class_init (SoupMessageClass *message_class)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
- * SOUP_MESSAGE_RESPONSE_BODY:
- *
- * Alias for the #SoupMessage:response-body property. (The
- * message's HTTP response body.)
- **/
- g_object_class_install_property (
- object_class, PROP_RESPONSE_BODY,
- g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_BODY,
- "Response Body",
- "The HTTP response content",
- SOUP_TYPE_MESSAGE_BODY,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
- /**
- * SOUP_MESSAGE_RESPONSE_BODY_DATA:
- *
- * Alias for the #SoupMessage:response-body-data property. (The
- * message's HTTP response body, as a #GBytes.)
- *
- * Since: 2.46
- **/
- /**
- * SoupMessage:response-body-data:
- *
- * The message's HTTP response body, as a #GBytes.
- *
- * Since: 2.46
- **/
- g_object_class_install_property (
- object_class, PROP_RESPONSE_BODY_DATA,
- g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_BODY_DATA,
- "Response Body Data",
- "The HTTP response body",
- G_TYPE_BYTES,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
- /**
* SOUP_MESSAGE_RESPONSE_HEADERS:
*
* Alias for the #SoupMessage:response-headers property. (The
@@ -1059,42 +804,6 @@ soup_message_new_from_uri (const char *method, SoupURI *uri)
}
/**
- * soup_message_set_response:
- * @msg: the message
- * @content_type: (allow-none): MIME Content-Type of the body
- * @resp_use: a #SoupMemoryUse describing how to handle @resp_body
- * @resp_body: (allow-none) (array length=resp_length) (element-type guint8):
- * a data buffer containing the body of the message response.
- * @resp_length: the byte length of @resp_body.
- *
- * Convenience function to set the response body of a #SoupMessage. If
- * @content_type is %NULL, the response body must be empty as well.
- */
-void
-soup_message_set_response (SoupMessage *msg,
- const char *content_type,
- SoupMemoryUse resp_use,
- const char *resp_body,
- gsize resp_length)
-{
- g_return_if_fail (SOUP_IS_MESSAGE (msg));
- g_return_if_fail (content_type != NULL || resp_length == 0);
-
- if (content_type) {
- g_warn_if_fail (strchr (content_type, '/') != NULL);
-
- soup_message_headers_replace (msg->response_headers,
- "Content-Type", content_type);
- soup_message_body_append (msg->response_body, resp_use,
- resp_body, resp_length);
- } else {
- soup_message_headers_remove (msg->response_headers,
- "Content-Type");
- soup_message_body_truncate (msg->response_body);
- }
-}
-
-/**
* soup_message_set_request_body:
* @msg: the message
* @content_type: (allow-none): MIME Content-Type of the body
@@ -1165,24 +874,12 @@ soup_message_set_request_body_from_bytes (SoupMessage *msg,
}
void
-soup_message_wrote_informational (SoupMessage *msg)
-{
- g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0);
-}
-
-void
soup_message_wrote_headers (SoupMessage *msg)
{
g_signal_emit (msg, signals[WROTE_HEADERS], 0);
}
void
-soup_message_wrote_chunk (SoupMessage *msg)
-{
- g_signal_emit (msg, signals[WROTE_CHUNK], 0);
-}
-
-void
soup_message_wrote_body_data (SoupMessage *msg, GBytes *chunk)
{
g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk);
@@ -1207,12 +904,6 @@ soup_message_got_headers (SoupMessage *msg)
}
void
-soup_message_got_chunk (SoupMessage *msg, GBytes *chunk)
-{
- g_signal_emit (msg, signals[GOT_CHUNK], 0, chunk);
-}
-
-void
soup_message_got_body (SoupMessage *msg)
{
g_signal_emit (msg, signals[GOT_BODY], 0);
@@ -1233,11 +924,6 @@ soup_message_starting (SoupMessage *msg)
void
soup_message_restarted (SoupMessage *msg)
{
- SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
-
- if (priv->msg_flags & SOUP_MESSAGE_CAN_REBUILD)
- soup_message_body_truncate (msg->request_body);
-
g_clear_object (&msg->request_body_stream);
g_signal_emit (msg, signals[RESTARTED], 0);
@@ -1270,12 +956,9 @@ header_handler_metamarshal (GClosure *closure, GValue *return_value,
gpointer invocation_hint, gpointer marshal_data)
{
SoupMessage *msg = g_value_get_object (&param_values[0]);
- SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
const char *header_name = marshal_data;
- SoupMessageHeaders *hdrs;
- hdrs = priv->server_side ? msg->request_headers : msg->response_headers;
- if (soup_message_headers_get_one (hdrs, header_name)) {
+ if (soup_message_headers_get_one (msg->response_headers, header_name)) {
closure->marshal (closure, return_value, n_param_values,
param_values, invocation_hint,
((GCClosure *)closure)->callback);
@@ -1292,9 +975,7 @@ header_handler_metamarshal (GClosure *closure, GValue *return_value,
*
* Adds a signal handler to @msg for @signal, as with
* g_signal_connect(), but the @callback will only be run if @msg's
- * incoming messages headers (that is, the
- * <literal>request_headers</literal> for a client #SoupMessage, or
- * the <literal>response_headers</literal> for a server #SoupMessage)
+ * incoming messages headers (that is, the <literal>request_headers</literal>)
* contain a header named @header.
*
* Return value: the handler ID from g_signal_connect()
@@ -1353,9 +1034,7 @@ status_handler_metamarshal (GClosure *closure, GValue *return_value,
* the status @status_code.
*
* @signal must be a signal that will be emitted after @msg's status
- * is set. For a client #SoupMessage, this means it can't be a "wrote"
- * signal. For a server #SoupMessage, this means it can't be a "got"
- * signal.
+ * is set (this means it can't be a "wrote" signal).
*
* Return value: the handler ID from g_signal_connect()
**/
@@ -1379,7 +1058,6 @@ soup_message_add_status_code_handler (SoupMessage *msg,
return g_signal_connect_closure (msg, signal, closure, FALSE);
}
-
void
soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
{
@@ -1470,12 +1148,7 @@ soup_message_cleanup_response (SoupMessage *msg)
{
SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
- soup_message_body_truncate (msg->response_body);
soup_message_headers_clear (msg->response_headers);
- if (priv->server_side) {
- soup_message_headers_set_encoding (msg->response_headers,
- SOUP_ENCODING_CONTENT_LENGTH);
- }
priv->msg_flags &= ~SOUP_MESSAGE_CONTENT_DECODED;
@@ -1498,9 +1171,6 @@ soup_message_cleanup_response (SoupMessage *msg)
* SoupMessageFlags:
* @SOUP_MESSAGE_NO_REDIRECT: The session should not follow redirect
* (3xx) responses received by this message.
- * @SOUP_MESSAGE_CAN_REBUILD: The caller will rebuild the request
- * body if the message is restarted; see
- * soup_message_body_set_accumulate() for more details.
* @SOUP_MESSAGE_CONTENT_DECODED: Set by #SoupContentDecoder to
* indicate that it has removed the Content-Encoding on a message (and
* so headers such as Content-Length may no longer accurately describe
@@ -1575,14 +1245,6 @@ soup_message_get_flags (SoupMessage *msg)
}
/**
- * SoupHTTPVersion:
- * @SOUP_HTTP_1_0: HTTP 1.0 (RFC 1945)
- * @SOUP_HTTP_1_1: HTTP 1.1 (RFC 2616)
- *
- * Indicates the HTTP protocol version being used.
- **/
-
-/**
* soup_message_set_http_version:
* @msg: a #SoupMessage
* @version: the HTTP version
@@ -2061,9 +1723,6 @@ soup_message_set_https_status (SoupMessage *msg, SoupConnection *conn)
* showing what problems, if any, have been found with that
* certificate.
*
- * <note><para>This is only meaningful with messages processed by a #SoupSession and is
- * not useful for messages received by a #SoupServer</para></note>
- *
* Return value: %TRUE if @msg used/attempted https, %FALSE if not
*
* Since: 2.34
@@ -2086,41 +1745,6 @@ soup_message_get_https_status (SoupMessage *msg,
return priv->tls_certificate != NULL;
}
-/**
- * soup_message_set_redirect:
- * @msg: a #SoupMessage
- * @status_code: a 3xx status code
- * @redirect_uri: the URI to redirect @msg to
- *
- * Sets @msg's status_code to @status_code and adds a Location header
- * pointing to @redirect_uri. Use this from a #SoupServer when you
- * want to redirect the client to another URI.
- *
- * @redirect_uri can be a relative URI, in which case it is
- * interpreted relative to @msg's current URI. In particular, if
- * @redirect_uri is just a path, it will replace the path
- * <emphasis>and query</emphasis> of @msg's URI.
- *
- * Since: 2.38
- */
-void
-soup_message_set_redirect (SoupMessage *msg, guint status_code,
- const char *redirect_uri)
-{
- SoupURI *location;
- char *location_str;
-
- location = soup_uri_new_with_base (soup_message_get_uri (msg), redirect_uri);
- g_return_if_fail (location != NULL);
-
- soup_message_set_status (msg, status_code);
- location_str = soup_uri_to_string (location, FALSE);
- soup_message_headers_replace (msg->response_headers, "Location",
- location_str);
- g_free (location_str);
- soup_uri_free (location);
-}
-
void
soup_message_set_soup_request (SoupMessage *msg,
SoupRequest *req)
@@ -2223,7 +1847,7 @@ soup_message_get_priority (SoupMessage *msg)
return priv->priority;
}
-gpointer
+SoupClientMessageIOData *
soup_message_get_io_data (SoupMessage *msg)
{
SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
@@ -2232,11 +1856,12 @@ soup_message_get_io_data (SoupMessage *msg)
}
void
-soup_message_set_io_data (SoupMessage *msg, gpointer io)
+soup_message_set_io_data (SoupMessage *msg,
+ SoupClientMessageIOData *io)
{
SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
- soup_message_io_cleanup (msg);
+ soup_client_message_io_data_free (priv->io_data);
priv->io_data = io;
}
@@ -2266,17 +1891,3 @@ soup_message_set_bytes_for_sniffing (SoupMessage *msg, gsize bytes)
priv->bytes_for_sniffing = bytes;
}
-
-const char *
-soup_http_version_to_string (SoupHTTPVersion version)
-{
- switch (version) {
- case SOUP_HTTP_1_0:
- return "HTTP/1.0";
- case SOUP_HTTP_1_1:
- return "HTTP/1.1";
- }
-
- g_assert_not_reached ();
- return "";
-}
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index 35560bf9..01664ab6 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -29,11 +29,8 @@ struct _SoupMessage {
guint status_code;
char *reason_phrase;
- SoupMessageBody *request_body;
GInputStream *request_body_stream;
SoupMessageHeaders *request_headers;
-
- SoupMessageBody *response_body;
SoupMessageHeaders *response_headers;
};
@@ -41,13 +38,10 @@ typedef struct {
GObjectClass parent_class;
/* signals */
- void (*wrote_informational) (SoupMessage *msg);
void (*wrote_headers) (SoupMessage *msg);
- void (*wrote_chunk) (SoupMessage *msg);
void (*wrote_body) (SoupMessage *msg);
void (*got_informational) (SoupMessage *msg);
void (*got_headers) (SoupMessage *msg);
- void (*got_chunk) (SoupMessage *msg, GBytes *chunk);
void (*got_body) (SoupMessage *msg);
void (*restarted) (SoupMessage *msg);
void (*finished) (SoupMessage *msg);
@@ -89,12 +83,6 @@ SOUP_AVAILABLE_IN_2_4
SoupMessage *soup_message_new_from_uri (const char *method,
SoupURI *uri);
-SOUP_AVAILABLE_IN_2_4
-void soup_message_set_response (SoupMessage *msg,
- const char *content_type,
- SoupMemoryUse resp_use,
- const char *resp_body,
- gsize resp_length);
SOUP_AVAILABLE_IN_ALL
void soup_message_set_request_body (SoupMessage *msg,
const char *content_type,
@@ -105,11 +93,6 @@ void soup_message_set_request_body_from_bytes (SoupMessage *msg,
const char *content_type,
GBytes *bytes);
-typedef enum {
- SOUP_HTTP_1_0 = 0, /*< nick=http-1-0 >*/
- SOUP_HTTP_1_1 = 1 /*< nick=http-1-1 >*/
-} SoupHTTPVersion;
-
SOUP_AVAILABLE_IN_2_4
void soup_message_set_http_version (SoupMessage *msg,
SoupHTTPVersion version);
@@ -142,13 +125,12 @@ gboolean soup_message_get_is_top_level_navigation (SoupMessage *msg
typedef enum {
SOUP_MESSAGE_NO_REDIRECT = (1 << 1),
- SOUP_MESSAGE_CAN_REBUILD = (1 << 2),
- SOUP_MESSAGE_CONTENT_DECODED = (1 << 3),
- SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 4),
- SOUP_MESSAGE_NEW_CONNECTION = (1 << 5),
- SOUP_MESSAGE_IDEMPOTENT = (1 << 6),
- SOUP_MESSAGE_IGNORE_CONNECTION_LIMITS = (1 << 7),
- SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE = (1 << 8)
+ SOUP_MESSAGE_CONTENT_DECODED = (1 << 2),
+ SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 3),
+ SOUP_MESSAGE_NEW_CONNECTION = (1 << 4),
+ SOUP_MESSAGE_IDEMPOTENT = (1 << 5),
+ SOUP_MESSAGE_IGNORE_CONNECTION_LIMITS = (1 << 6),
+ SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE = (1 << 7)
} SoupMessageFlags;
SOUP_AVAILABLE_IN_2_4
@@ -192,11 +174,6 @@ void soup_message_set_status_full (SoupMessage *msg,
guint status_code,
const char *reason_phrase);
-SOUP_AVAILABLE_IN_2_38
-void soup_message_set_redirect (SoupMessage *msg,
- guint status_code,
- const char *redirect_uri);
-
SOUP_AVAILABLE_IN_2_28
void soup_message_disable_feature (SoupMessage *msg,
GType feature_type);
@@ -226,12 +203,8 @@ SOUP_AVAILABLE_IN_2_44
SoupMessagePriority soup_message_get_priority (SoupMessage *msg);
SOUP_AVAILABLE_IN_2_4
-void soup_message_wrote_informational (SoupMessage *msg);
-SOUP_AVAILABLE_IN_2_4
void soup_message_wrote_headers (SoupMessage *msg);
SOUP_AVAILABLE_IN_2_4
-void soup_message_wrote_chunk (SoupMessage *msg);
-SOUP_AVAILABLE_IN_2_4
void soup_message_wrote_body_data (SoupMessage *msg, GBytes *chunk);
SOUP_AVAILABLE_IN_2_4
void soup_message_wrote_body (SoupMessage *msg);
@@ -240,8 +213,6 @@ void soup_message_got_informational (SoupMessage *msg);
SOUP_AVAILABLE_IN_2_4
void soup_message_got_headers (SoupMessage *msg);
SOUP_AVAILABLE_IN_2_4
-void soup_message_got_chunk (SoupMessage *msg, GBytes *chunk);
-SOUP_AVAILABLE_IN_2_4
void soup_message_got_body (SoupMessage *msg);
SOUP_AVAILABLE_IN_2_4
void soup_message_content_sniffed (SoupMessage *msg, const char *content_type, GHashTable *params);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index ce7dc713..d336a62d 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1013,7 +1013,7 @@ soup_session_append_queue_item (SoupSession *session,
static void
soup_session_send_queue_item (SoupSession *session,
SoupMessageQueueItem *item,
- SoupMessageCompletionFn completion_cb)
+ SoupMessageIOCompletionFn completion_cb)
{
SoupSessionPrivate *priv = soup_session_get_instance_private (session);
@@ -1389,7 +1389,7 @@ tunnel_message_completed (SoupMessage *msg, SoupMessageIOCompletion completion,
if (tunnel_item->conn) {
tunnel_item->state = SOUP_MESSAGE_RUNNING;
soup_session_send_queue_item (session, tunnel_item,
- tunnel_message_completed);
+ (SoupMessageIOCompletionFn)tunnel_message_completed);
soup_message_io_run (msg, !tunnel_item->async);
return;
}
@@ -1443,7 +1443,7 @@ tunnel_connect (SoupMessageQueueItem *item)
g_signal_emit (session, signals[TUNNELING], 0, tunnel_item->conn);
soup_session_send_queue_item (session, tunnel_item,
- tunnel_message_completed);
+ (SoupMessageIOCompletionFn)tunnel_message_completed);
soup_message_io_run (msg, !item->async);
g_object_unref (msg);
}
@@ -1709,7 +1709,8 @@ soup_session_process_queue_item (SoupSession *session,
item->state = SOUP_MESSAGE_RUNNING;
- soup_session_send_queue_item (session, item, message_completed);
+ soup_session_send_queue_item (session, item,
+ (SoupMessageIOCompletionFn)message_completed);
if (item->async)
async_send_request_running (session, item);
diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c
index d4ed5c41..5eb1f635 100644
--- a/libsoup/soup-status.c
+++ b/libsoup/soup-status.c
@@ -304,3 +304,11 @@ soup_status_proxify (guint status_code)
}
G_DEFINE_QUARK (soup-http-error-quark, soup_http_error)
+
+/**
+ * SoupHTTPVersion:
+ * @SOUP_HTTP_1_0: HTTP 1.0 (RFC 1945)
+ * @SOUP_HTTP_1_1: HTTP 1.1 (RFC 2616)
+ *
+ * Indicates the HTTP protocol version being used.
+ */
diff --git a/libsoup/soup-status.h b/libsoup/soup-status.h
index 040a858c..cc7512f9 100644
--- a/libsoup/soup-status.h
+++ b/libsoup/soup-status.h
@@ -93,6 +93,11 @@ typedef enum {
SOUP_STATUS_NOT_EXTENDED = 510 /* RFC 2774 */
} SoupStatus;
+typedef enum {
+ SOUP_HTTP_1_0 = 0, /*< nick=http-1-0 >*/
+ SOUP_HTTP_1_1 = 1 /*< nick=http-1-1 >*/
+} SoupHTTPVersion;
+
SOUP_AVAILABLE_IN_2_4
const char *soup_status_get_phrase (guint status_code);
SOUP_AVAILABLE_IN_2_26
diff --git a/libsoup/soup-types.h b/libsoup/soup-types.h
index abd7ea21..49a6c9c4 100644
--- a/libsoup/soup-types.h
+++ b/libsoup/soup-types.h
@@ -25,6 +25,7 @@ typedef struct _SoupMessage SoupMessage;
typedef struct _SoupRequest SoupRequest;
typedef struct _SoupRequestHTTP SoupRequestHTTP;
typedef struct _SoupServer SoupServer;
+typedef struct _SoupServerMessage SoupServerMessage;
typedef struct _SoupSession SoupSession;
typedef struct _SoupSessionFeature SoupSessionFeature;
typedef struct _SoupSocket SoupSocket;
diff --git a/libsoup/soup.h b/libsoup/soup.h
index 36485dc2..bd95488e 100644
--- a/libsoup/soup.h
+++ b/libsoup/soup.h
@@ -45,6 +45,7 @@ extern "C" {
#include "server/soup-auth-domain-basic.h"
#include "server/soup-auth-domain-digest.h"
#include "server/soup-server.h"
+#include "server/soup-server-message.h"
#include "soup-session.h"
#include "soup-session-feature.h"
#include "soup-socket.h"
diff --git a/libsoup/websocket/soup-websocket.c b/libsoup/websocket/soup-websocket.c
index e7f29f49..48f9a7bd 100644
--- a/libsoup/websocket/soup-websocket.c
+++ b/libsoup/websocket/soup-websocket.c
@@ -27,6 +27,7 @@
#include "soup-websocket.h"
#include "soup-headers.h"
#include "soup-message-private.h"
+#include "soup-server-message.h"
#include "soup-websocket-extension.h"
#define FIXED_DIGEST_LEN 20
@@ -205,9 +206,9 @@ compute_accept_key (const char *key)
}
static gboolean
-choose_subprotocol (SoupMessage *msg,
- const char **server_protocols,
- const char **chosen_protocol)
+choose_subprotocol (SoupServerMessage *msg,
+ const char **server_protocols,
+ const char **chosen_protocol)
{
const char *client_protocols_str;
char **client_protocols;
@@ -219,8 +220,9 @@ choose_subprotocol (SoupMessage *msg,
if (!server_protocols)
return TRUE;
- client_protocols_str = soup_message_headers_get_one (msg->request_headers,
- "Sec-Websocket-Protocol");
+ client_protocols_str =
+ soup_message_headers_get_one (soup_server_message_get_request_headers (msg),
+ "Sec-Websocket-Protocol");
if (!client_protocols_str)
return TRUE;
@@ -406,10 +408,10 @@ soup_websocket_client_prepare_handshake_with_extensions (SoupMessage *msg,
* Since: 2.50
*/
gboolean
-soup_websocket_server_check_handshake (SoupMessage *msg,
- const char *expected_origin,
- char **protocols,
- GError **error)
+soup_websocket_server_check_handshake (SoupServerMessage *msg,
+ const char *expected_origin,
+ char **protocols,
+ GError **error)
{
return soup_websocket_server_check_handshake_with_extensions (msg, expected_origin, protocols, NULL, error);
}
@@ -460,15 +462,15 @@ extract_extension_names_from_request (SoupMessage *msg)
}
static gboolean
-process_extensions (SoupMessage *msg,
- const char *extensions,
- gboolean is_server,
+process_extensions (const char *extensions,
+ SoupMessage *msg,
GPtrArray *supported_extensions,
GList **accepted_extensions,
GError **error)
{
GSList *extension_list, *l;
GHashTable *requested_extensions = NULL;
+ gboolean is_server = msg == NULL;
if (!supported_extensions || supported_extensions->len == 0) {
if (is_server)
@@ -608,7 +610,7 @@ process_extensions (SoupMessage *msg,
/**
* soup_websocket_server_check_handshake_with_extensions:
- * @msg: #SoupMessage containing the client side of a WebSocket handshake
+ * @msg: #SoupServerMessage containing the client side of a WebSocket handshake
* @origin: (nullable): expected Origin header
* @protocols: (nullable) (array zero-terminated=1): allowed WebSocket
* protocols.
@@ -640,19 +642,20 @@ process_extensions (SoupMessage *msg,
* Since: 2.68
*/
gboolean
-soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
- const char *expected_origin,
- char **protocols,
- GPtrArray *supported_extensions,
- GError **error)
+soup_websocket_server_check_handshake_with_extensions (SoupServerMessage *msg,
+ const char *expected_origin,
+ char **protocols,
+ GPtrArray *supported_extensions,
+ GError **error)
{
const char *origin;
const char *key;
const char *extensions;
+ SoupMessageHeaders *request_headers;
- g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), FALSE);
- if (msg->method != SOUP_METHOD_GET) {
+ if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) {
g_set_error_literal (error,
SOUP_WEBSOCKET_ERROR,
SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET,
@@ -660,8 +663,9 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
return FALSE;
}
- if (!soup_message_headers_header_equals (msg->request_headers, "Upgrade", "websocket") ||
- !soup_message_headers_header_contains (msg->request_headers, "Connection", "upgrade")) {
+ request_headers = soup_server_message_get_request_headers (msg);
+ if (!soup_message_headers_header_equals (request_headers, "Upgrade", "websocket") ||
+ !soup_message_headers_header_contains (request_headers, "Connection", "upgrade")) {
g_set_error_literal (error,
SOUP_WEBSOCKET_ERROR,
SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET,
@@ -669,7 +673,7 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
return FALSE;
}
- if (!soup_message_headers_header_equals (msg->request_headers, "Sec-WebSocket-Version", "13")) {
+ if (!soup_message_headers_header_equals (request_headers, "Sec-WebSocket-Version", "13")) {
g_set_error_literal (error,
SOUP_WEBSOCKET_ERROR,
SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE,
@@ -677,7 +681,7 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
return FALSE;
}
- key = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key");
+ key = soup_message_headers_get_one (request_headers, "Sec-WebSocket-Key");
if (key == NULL || !validate_key (key)) {
g_set_error_literal (error,
SOUP_WEBSOCKET_ERROR,
@@ -687,7 +691,7 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
}
if (expected_origin) {
- origin = soup_message_headers_get_one (msg->request_headers, "Origin");
+ origin = soup_message_headers_get_one (request_headers, "Origin");
if (!origin || g_ascii_strcasecmp (origin, expected_origin) != 0) {
g_set_error (error,
SOUP_WEBSOCKET_ERROR,
@@ -705,9 +709,9 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
return FALSE;
}
- extensions = soup_message_headers_get_list (msg->request_headers, "Sec-WebSocket-Extensions");
+ extensions = soup_message_headers_get_list (request_headers, "Sec-WebSocket-Extensions");
if (extensions && *extensions) {
- if (!process_extensions (msg, extensions, TRUE, supported_extensions, NULL, error))
+ if (!process_extensions (extensions, NULL, supported_extensions, NULL, error))
return FALSE;
}
@@ -718,32 +722,35 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
"<body>Received invalid WebSocket request</body></html>\r\n"
static void
-respond_handshake_forbidden (SoupMessage *msg)
+respond_handshake_forbidden (SoupServerMessage *msg)
{
- soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
- soup_message_headers_append (msg->response_headers, "Connection", "close");
- soup_message_set_response (msg, "text/html", SOUP_MEMORY_COPY,
- RESPONSE_FORBIDDEN, strlen (RESPONSE_FORBIDDEN));
+ soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, NULL);
+ soup_message_headers_append (soup_server_message_get_response_headers (msg),
+ "Connection", "close");
+ soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_COPY,
+ RESPONSE_FORBIDDEN, strlen (RESPONSE_FORBIDDEN));
}
#define RESPONSE_BAD "<html><head><title>400 Bad Request</title></head>\r\n" \
"<body>Received invalid WebSocket request: %s</body></html>\r\n"
static void
-respond_handshake_bad (SoupMessage *msg, const char *why)
+respond_handshake_bad (SoupServerMessage *msg,
+ const char *why)
{
char *text;
text = g_strdup_printf (RESPONSE_BAD, why);
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
- soup_message_headers_append (msg->response_headers, "Connection", "close");
- soup_message_set_response (msg, "text/html", SOUP_MEMORY_TAKE,
- text, strlen (text));
+ soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
+ soup_message_headers_append (soup_server_message_get_response_headers (msg),
+ "Connection", "close");
+ soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_TAKE,
+ text, strlen (text));
}
/**
* soup_websocket_server_process_handshake:
- * @msg: #SoupMessage containing the client side of a WebSocket handshake
+ * @msg: #SoupServerMessage containing the client side of a WebSocket handshake
* @expected_origin: (allow-none): expected Origin header
* @protocols: (allow-none) (array zero-terminated=1): allowed WebSocket
* protocols.
@@ -773,16 +780,16 @@ respond_handshake_bad (SoupMessage *msg, const char *why)
* Since: 2.50
*/
gboolean
-soup_websocket_server_process_handshake (SoupMessage *msg,
- const char *expected_origin,
- char **protocols)
+soup_websocket_server_process_handshake (SoupServerMessage *msg,
+ const char *expected_origin,
+ char **protocols)
{
return soup_websocket_server_process_handshake_with_extensions (msg, expected_origin, protocols, NULL, NULL);
}
/**
* soup_websocket_server_process_handshake_with_extensions:
- * @msg: #SoupMessage containing the client side of a WebSocket handshake
+ * @msg: #SoupServerMessage containing the client side of a WebSocket handshake
* @expected_origin: (nullable): expected Origin header
* @protocols: (nullable) (array zero-terminated=1): allowed WebSocket
* protocols.
@@ -813,18 +820,21 @@ soup_websocket_server_process_handshake (SoupMessage *msg,
* Since: 2.68
*/
gboolean
-soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg,
- const char *expected_origin,
- char **protocols,
- GPtrArray *supported_extensions,
- GList **accepted_extensions)
+soup_websocket_server_process_handshake_with_extensions (SoupServerMessage *msg,
+ const char *expected_origin,
+ char **protocols,
+ GPtrArray *supported_extensions,
+ GList **accepted_extensions)
{
const char *chosen_protocol = NULL;
const char *key;
const char *extensions;
char *accept_key;
GError *error = NULL;
+ SoupMessageHeaders *request_headers;
+ SoupMessageHeaders *response_headers;
+ g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), FALSE);
g_return_val_if_fail (accepted_extensions == NULL || *accepted_extensions == NULL, FALSE);
if (!soup_websocket_server_check_handshake_with_extensions (msg, expected_origin, protocols, supported_extensions, &error)) {
@@ -838,25 +848,27 @@ soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg,
return FALSE;
}
- soup_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS);
- soup_message_headers_replace (msg->response_headers, "Upgrade", "websocket");
- soup_message_headers_append (msg->response_headers, "Connection", "Upgrade");
+ soup_server_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS, NULL);
+ response_headers = soup_server_message_get_response_headers (msg);
+ soup_message_headers_replace (response_headers, "Upgrade", "websocket");
+ soup_message_headers_append (response_headers, "Connection", "Upgrade");
- key = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key");
+ request_headers = soup_server_message_get_request_headers (msg);
+ key = soup_message_headers_get_one (request_headers, "Sec-WebSocket-Key");
accept_key = compute_accept_key (key);
- soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Accept", accept_key);
+ soup_message_headers_append (response_headers, "Sec-WebSocket-Accept", accept_key);
g_free (accept_key);
choose_subprotocol (msg, (const char **) protocols, &chosen_protocol);
if (chosen_protocol)
- soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Protocol", chosen_protocol);
+ soup_message_headers_append (response_headers, "Sec-WebSocket-Protocol", chosen_protocol);
- extensions = soup_message_headers_get_list (msg->request_headers, "Sec-WebSocket-Extensions");
+ extensions = soup_message_headers_get_list (request_headers, "Sec-WebSocket-Extensions");
if (extensions && *extensions) {
GList *websocket_extensions = NULL;
GList *l;
- process_extensions (msg, extensions, TRUE, supported_extensions, &websocket_extensions, NULL);
+ process_extensions (extensions, NULL, supported_extensions, &websocket_extensions, NULL);
if (websocket_extensions) {
GString *response_extensions;
@@ -878,11 +890,11 @@ soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg,
}
if (response_extensions->len > 0) {
- soup_message_headers_replace (msg->response_headers,
+ soup_message_headers_replace (response_headers,
"Sec-WebSocket-Extensions",
response_extensions->str);
} else {
- soup_message_headers_remove (msg->response_headers,
+ soup_message_headers_remove (response_headers,
"Sec-WebSocket-Extensions");
}
g_string_free (response_extensions, TRUE);
@@ -1009,7 +1021,7 @@ soup_websocket_client_verify_handshake_with_extensions (SoupMessage *msg,
extensions = soup_message_headers_get_list (msg->response_headers, "Sec-WebSocket-Extensions");
if (extensions && *extensions) {
- if (!process_extensions (msg, extensions, FALSE, supported_extensions, accepted_extensions, error))
+ if (!process_extensions (extensions, msg, supported_extensions, accepted_extensions, error))
return FALSE;
}
diff --git a/libsoup/websocket/soup-websocket.h b/libsoup/websocket/soup-websocket.h
index 9f265e0a..d347c213 100644
--- a/libsoup/websocket/soup-websocket.h
+++ b/libsoup/websocket/soup-websocket.h
@@ -87,28 +87,28 @@ gboolean soup_websocket_client_verify_handshake_with_extensions (SoupMessage *ms
GError **error);
SOUP_AVAILABLE_IN_2_50
-gboolean soup_websocket_server_check_handshake (SoupMessage *msg,
- const char *origin,
- char **protocols,
- GError **error);
+gboolean soup_websocket_server_check_handshake (SoupServerMessage *msg,
+ const char *origin,
+ char **protocols,
+ GError **error);
SOUP_AVAILABLE_IN_2_68
gboolean
-soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg,
- const char *origin,
- char **protocols,
- GPtrArray *supported_extensions,
- GError **error);
+soup_websocket_server_check_handshake_with_extensions (SoupServerMessage *msg,
+ const char *origin,
+ char **protocols,
+ GPtrArray *supported_extensions,
+ GError **error);
SOUP_AVAILABLE_IN_2_50
-gboolean soup_websocket_server_process_handshake (SoupMessage *msg,
- const char *expected_origin,
- char **protocols);
+gboolean soup_websocket_server_process_handshake (SoupServerMessage *msg,
+ const char *expected_origin,
+ char **protocols);
SOUP_AVAILABLE_IN_2_68
gboolean
-soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg,
- const char *expected_origin,
- char **protocols,
- GPtrArray *supported_extensions,
- GList **accepted_extensions);
+soup_websocket_server_process_handshake_with_extensions (SoupServerMessage *msg,
+ const char *expected_origin,
+ char **protocols,
+ GPtrArray *supported_extensions,
+ GList **accepted_extensions);
G_END_DECLS