summaryrefslogtreecommitdiff
path: root/libsoup/server
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup/server')
-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
13 files changed, 1590 insertions, 765 deletions
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