diff options
author | Carlos Garcia Campos <cgarcia@igalia.com> | 2020-10-09 11:29:11 +0200 |
---|---|---|
committer | Carlos Garcia Campos <cgarcia@igalia.com> | 2020-10-19 14:02:25 +0200 |
commit | 99c19cc27ae837e665ace3c1f0e99cd1088e6c24 (patch) | |
tree | bbb7f7a7a9c9544801c66cf3e543ee3ea93291be | |
parent | d5cd7249b20beee01dc26c09ec80f270ef8962fd (diff) | |
download | libsoup-carlosgc/split-io.tar.gz |
Split SoupMessage into client and server partscarlosgc/split-io
Add SoupServerMessage and move there all the server only functionality.
63 files changed, 3121 insertions, 2372 deletions
diff --git a/docs/reference/libsoup-3.0-docs.xml b/docs/reference/libsoup-3.0-docs.xml index 479edf8c..adb0d12c 100644 --- a/docs/reference/libsoup-3.0-docs.xml +++ b/docs/reference/libsoup-3.0-docs.xml @@ -43,6 +43,12 @@ </chapter> <chapter> + <title>HTTP Server</title> + <xi:include href="xml/soup-server.xml"/> + <xi:include href="xml/soup-server-message.xml"/> + </chapter> + + <chapter> <title>Additional Features</title> <xi:include href="xml/soup-session-feature.xml"/> <xi:include href="xml/soup-content-decoder.xml"/> diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt index 4b1d56ac..64989b04 100644 --- a/docs/reference/libsoup-3.0-sections.txt +++ b/docs/reference/libsoup-3.0-sections.txt @@ -8,7 +8,6 @@ soup_message_new soup_message_new_from_uri soup_message_set_request_body soup_message_set_request_body_from_bytes -soup_message_set_response <SUBSECTION> SoupHTTPVersion soup_message_set_http_version @@ -18,7 +17,6 @@ soup_message_set_uri <SUBSECTION> soup_message_set_status soup_message_set_status_full -soup_message_set_redirect soup_message_is_keepalive soup_message_get_https_status <SUBSECTION> @@ -74,15 +72,12 @@ SOUP_IS_MESSAGE_CLASS SOUP_MESSAGE_GET_CLASS SoupMessageClass <SUBSECTION Private> -soup_message_wrote_informational soup_message_wrote_headers -soup_message_wrote_chunk soup_message_wrote_body_data soup_message_wrote_body soup_message_got_informational soup_message_got_headers soup_message_content_sniffed -soup_message_got_chunk soup_message_got_body soup_message_finished soup_message_restarted @@ -260,17 +255,6 @@ soup_server_add_websocket_handler soup_server_add_websocket_extension soup_server_remove_websocket_extension <SUBSECTION> -SoupClientContext -soup_client_context_get_local_address -soup_client_context_get_remote_address -soup_client_context_get_host -soup_client_context_get_auth_domain -soup_client_context_get_auth_user -soup_client_context_get_socket -soup_client_context_steal_connection -<SUBSECTION Private> -soup_client_context_get_soup_socket -<SUBSECTION> soup_server_add_auth_domain soup_server_remove_auth_domain <SUBSECTION> @@ -296,6 +280,35 @@ soup_client_context_get_type </SECTION> <SECTION> +<FILE>soup-server-message</FILE> +<TITLE>SoupServerMessage</TITLE> +SoupServerMessage +soup_server_message_get_request_headers +soup_server_message_get_response_headers +soup_server_message_get_request_body +soup_server_message_get_response_body +soup_server_message_get_method +soup_server_message_get_http_version +soup_server_message_set_http_version +soup_server_message_get_status +soup_server_message_set_status +soup_server_message_get_uri +soup_server_message_set_response +soup_server_message_set_redirect +soup_server_message_get_socket +soup_server_message_get_local_address +soup_server_message_get_remote_address +soup_server_message_get_remote_host +soup_server_message_steal_connection +<SUBSECTION Standard> +SOUP_SERVER_MESSAGE +SOUP_IS_SERVER_MESSAGE +SOUP_TYPE_SERVER_MESSAGE +<SUBSECTION Private> +soup_server_message_get_type +</SECTION> + +<SECTION> <FILE>soup-auth-domain</FILE> <TITLE>SoupAuthDomain</TITLE> SoupAuthDomain diff --git a/libsoup/meson.build b/libsoup/meson.build index c3a691d4..3a700870 100644 --- a/libsoup/meson.build +++ b/libsoup/meson.build @@ -44,6 +44,7 @@ soup_sources = [ 'server/soup-path-map.c', 'server/soup-server.c', 'server/soup-server-io.c', + 'server/soup-server-message.c', 'websocket/soup-websocket.c', 'websocket/soup-websocket-connection.c', @@ -67,6 +68,7 @@ soup_sources = [ 'soup-message-body.c', 'soup-message-headers.c', 'soup-message-io.c', + 'soup-message-io-data.c', 'soup-message-queue.c', 'soup-method.c', 'soup-misc.c', @@ -117,6 +119,7 @@ soup_introspection_headers = [ 'server/soup-auth-domain-basic.h', 'server/soup-auth-domain-digest.h', 'server/soup-server.h', + 'server/soup-server-message.h', 'websocket/soup-websocket.h', 'websocket/soup-websocket-connection.h', diff --git a/libsoup/server/soup-auth-domain-basic.c b/libsoup/server/soup-auth-domain-basic.c index 9a850050..0cba37d2 100644 --- a/libsoup/server/soup-auth-domain-basic.c +++ b/libsoup/server/soup-auth-domain-basic.c @@ -204,8 +204,9 @@ pw_free (char *pw) } static gboolean -parse_basic (SoupMessage *msg, const char *header, - char **username, char **password) +parse_basic (const char *header, + char **username, + char **password) { char *decoded, *colon; gsize len, plen; @@ -232,15 +233,16 @@ parse_basic (SoupMessage *msg, const char *header, } static char * -soup_auth_domain_basic_accepts (SoupAuthDomain *domain, SoupMessage *msg, - const char *header) +soup_auth_domain_basic_accepts (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *header) { SoupAuthDomainBasicPrivate *priv = soup_auth_domain_basic_get_instance_private (SOUP_AUTH_DOMAIN_BASIC (domain)); char *username, *password; gboolean ok = FALSE; - if (!parse_basic (msg, header, &username, &password)) + if (!parse_basic (header, &username, &password)) return NULL; if (priv->auth_callback) { @@ -262,7 +264,8 @@ soup_auth_domain_basic_accepts (SoupAuthDomain *domain, SoupMessage *msg, } static char * -soup_auth_domain_basic_challenge (SoupAuthDomain *domain, SoupMessage *msg) +soup_auth_domain_basic_challenge (SoupAuthDomain *domain, + SoupServerMessage *msg) { GString *challenge; @@ -272,18 +275,18 @@ soup_auth_domain_basic_challenge (SoupAuthDomain *domain, SoupMessage *msg) } static gboolean -soup_auth_domain_basic_check_password (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - const char *password) +soup_auth_domain_basic_check_password (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + const char *password) { const char *header; char *msg_username, *msg_password; gboolean ok; - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "Authorization"); - if (!parse_basic (msg, header, &msg_username, &msg_password)) + if (!parse_basic (header, &msg_username, &msg_password)) return FALSE; ok = (!strcmp (username, msg_username) && diff --git a/libsoup/server/soup-auth-domain-basic.h b/libsoup/server/soup-auth-domain-basic.h index a260e891..d0397051 100644 --- a/libsoup/server/soup-auth-domain-basic.h +++ b/libsoup/server/soup-auth-domain-basic.h @@ -20,11 +20,11 @@ SOUP_AVAILABLE_IN_2_4 SoupAuthDomain *soup_auth_domain_basic_new (const char *optname1, ...) G_GNUC_NULL_TERMINATED; -typedef gboolean (*SoupAuthDomainBasicAuthCallback) (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - const char *password, - gpointer user_data); +typedef gboolean (*SoupAuthDomainBasicAuthCallback) (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + const char *password, + gpointer user_data); SOUP_AVAILABLE_IN_2_4 void soup_auth_domain_basic_set_auth_callback (SoupAuthDomain *domain, diff --git a/libsoup/server/soup-auth-domain-digest.c b/libsoup/server/soup-auth-domain-digest.c index ae9fa266..1ad34a91 100644 --- a/libsoup/server/soup-auth-domain-digest.c +++ b/libsoup/server/soup-auth-domain-digest.c @@ -191,9 +191,11 @@ soup_auth_domain_digest_set_auth_callback (SoupAuthDomain *domain, } static gboolean -check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg, - GHashTable *params, const char *username, - const char *hex_urp) +check_hex_urp (SoupAuthDomain *domain, + SoupServerMessage *msg, + GHashTable *params, + const char *username, + const char *hex_urp) { const char *uri, *qop, *realm, *msg_username; const char *nonce, *nc, *cnonce, *response; @@ -210,7 +212,7 @@ check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg, if (!uri) return FALSE; - req_uri = soup_message_get_uri (msg); + req_uri = soup_server_message_get_uri (msg); dig_uri = soup_uri_new (uri); if (dig_uri) { if (!soup_uri_equal (dig_uri, req_uri)) { @@ -263,7 +265,8 @@ check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg, soup_auth_digest_compute_hex_a1 (hex_urp, SOUP_AUTH_DIGEST_ALGORITHM_MD5, nonce, cnonce, hex_a1); - soup_auth_digest_compute_response (msg->method, uri, + soup_auth_digest_compute_response (soup_server_message_get_method (msg), + uri, hex_a1, SOUP_AUTH_DIGEST_QOP_AUTH, nonce, cnonce, nonce_count, @@ -272,8 +275,9 @@ check_hex_urp (SoupAuthDomain *domain, SoupMessage *msg, } static char * -soup_auth_domain_digest_accepts (SoupAuthDomain *domain, SoupMessage *msg, - const char *header) +soup_auth_domain_digest_accepts (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *header) { SoupAuthDomainDigestPrivate *priv = soup_auth_domain_digest_get_instance_private (SOUP_AUTH_DOMAIN_DIGEST (domain)); @@ -317,7 +321,8 @@ soup_auth_domain_digest_accepts (SoupAuthDomain *domain, SoupMessage *msg, } static char * -soup_auth_domain_digest_challenge (SoupAuthDomain *domain, SoupMessage *msg) +soup_auth_domain_digest_challenge (SoupAuthDomain *domain, + SoupServerMessage *msg) { GString *str; @@ -366,10 +371,10 @@ soup_auth_domain_digest_encode_password (const char *username, } static gboolean -soup_auth_domain_digest_check_password (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - const char *password) +soup_auth_domain_digest_check_password (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + const char *password) { const char *header; GHashTable *params; @@ -377,7 +382,7 @@ soup_auth_domain_digest_check_password (SoupAuthDomain *domain, char hex_urp[33]; gboolean accept; - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "Authorization"); if (!header || (strncmp (header, "Digest ", 7) != 0)) return FALSE; diff --git a/libsoup/server/soup-auth-domain-digest.h b/libsoup/server/soup-auth-domain-digest.h index 523497ce..c5630470 100644 --- a/libsoup/server/soup-auth-domain-digest.h +++ b/libsoup/server/soup-auth-domain-digest.h @@ -20,10 +20,10 @@ SOUP_AVAILABLE_IN_2_4 SoupAuthDomain *soup_auth_domain_digest_new (const char *optname1, ...) G_GNUC_NULL_TERMINATED; -typedef char * (*SoupAuthDomainDigestAuthCallback) (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - gpointer user_data); +typedef char * (*SoupAuthDomainDigestAuthCallback) (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + gpointer user_data); SOUP_AVAILABLE_IN_2_4 void soup_auth_domain_digest_set_auth_callback (SoupAuthDomain *domain, diff --git a/libsoup/server/soup-auth-domain.c b/libsoup/server/soup-auth-domain.c index 8785c474..f22cd9ea 100644 --- a/libsoup/server/soup-auth-domain.c +++ b/libsoup/server/soup-auth-domain.c @@ -364,7 +364,7 @@ soup_auth_domain_remove_path (SoupAuthDomain *domain, const char *path) /** * SoupAuthDomainFilter: * @domain: a #SoupAuthDomain - * @msg: a #SoupMessage + * @msg: a #SoupServerMessage * @user_data: the data passed to soup_auth_domain_set_filter() * * The prototype for a #SoupAuthDomain filter; see @@ -444,7 +444,7 @@ soup_auth_domain_get_realm (SoupAuthDomain *domain) /** * SoupAuthDomainGenericAuthCallback: * @domain: a #SoupAuthDomain - * @msg: the #SoupMessage being authenticated + * @msg: the #SoupServerMessage being authenticated * @username: the username from @msg * @user_data: the data passed to * soup_auth_domain_set_generic_auth_callback() @@ -504,9 +504,9 @@ soup_auth_domain_set_generic_auth_callback (SoupAuthDomain *domain, } gboolean -soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username) +soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username) { SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain); @@ -519,7 +519,7 @@ soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain, /** * soup_auth_domain_check_password: * @domain: a #SoupAuthDomain - * @msg: a #SoupMessage + * @msg: a #SoupServerMessage * @username: a username * @password: a password * @@ -530,10 +530,10 @@ soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain, * Return value: whether or not the message is authenticated **/ gboolean -soup_auth_domain_check_password (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - const char *password) +soup_auth_domain_check_password (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + const char *password) { return SOUP_AUTH_DOMAIN_GET_CLASS (domain)->check_password (domain, msg, username, @@ -543,7 +543,7 @@ soup_auth_domain_check_password (SoupAuthDomain *domain, /** * soup_auth_domain_covers: * @domain: a #SoupAuthDomain - * @msg: a #SoupMessage + * @msg: a #SoupServerMessage * * Checks if @domain requires @msg to be authenticated (according to * its paths and filter function). This does not actually look at @@ -556,13 +556,14 @@ soup_auth_domain_check_password (SoupAuthDomain *domain, * Return value: %TRUE if @domain requires @msg to be authenticated **/ gboolean -soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg) +soup_auth_domain_covers (SoupAuthDomain *domain, + SoupServerMessage *msg) { SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain); const char *path; if (!priv->proxy) { - path = soup_message_get_uri (msg)->path; + path = soup_server_message_get_uri (msg)->path; if (!soup_path_map_lookup (priv->paths, path)) return FALSE; } @@ -576,7 +577,7 @@ soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg) /** * soup_auth_domain_accepts: * @domain: a #SoupAuthDomain - * @msg: a #SoupMessage + * @msg: a #SoupServerMessage * * Checks if @msg contains appropriate authorization for @domain to * accept it. Mirroring soup_auth_domain_covers(), this does not check @@ -590,12 +591,13 @@ soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg) * as, if in fact it has authenticated. %NULL otherwise. **/ char * -soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg) +soup_auth_domain_accepts (SoupAuthDomain *domain, + SoupServerMessage *msg) { SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain); const char *header; - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), priv->proxy ? "Proxy-Authorization" : "Authorization"); @@ -607,7 +609,7 @@ soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg) /** * soup_auth_domain_challenge: (virtual challenge) * @domain: a #SoupAuthDomain - * @msg: a #SoupMessage + * @msg: a #SoupServerMessage * * Adds a "WWW-Authenticate" or "Proxy-Authenticate" header to @msg, * requesting that the client authenticate, and sets @msg's status @@ -617,16 +619,18 @@ soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg) * anyone else. **/ void -soup_auth_domain_challenge (SoupAuthDomain *domain, SoupMessage *msg) +soup_auth_domain_challenge (SoupAuthDomain *domain, + SoupServerMessage *msg) { SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain); char *challenge; challenge = SOUP_AUTH_DOMAIN_GET_CLASS (domain)->challenge (domain, msg); - soup_message_set_status (msg, priv->proxy ? - SOUP_STATUS_PROXY_UNAUTHORIZED : - SOUP_STATUS_UNAUTHORIZED); - soup_message_headers_append (msg->response_headers, + soup_server_message_set_status (msg, priv->proxy ? + SOUP_STATUS_PROXY_UNAUTHORIZED : + SOUP_STATUS_UNAUTHORIZED, + NULL); + soup_message_headers_append (soup_server_message_get_response_headers (msg), priv->proxy ? "Proxy-Authenticate" : "WWW-Authenticate", diff --git a/libsoup/server/soup-auth-domain.h b/libsoup/server/soup-auth-domain.h index 397dc53b..c904d01b 100644 --- a/libsoup/server/soup-auth-domain.h +++ b/libsoup/server/soup-auth-domain.h @@ -16,15 +16,15 @@ G_DECLARE_DERIVABLE_TYPE (SoupAuthDomain, soup_auth_domain, SOUP, AUTH_DOMAIN, G struct _SoupAuthDomainClass { GObjectClass parent_class; - char * (*accepts) (SoupAuthDomain *domain, - SoupMessage *msg, - const char *header); - char * (*challenge) (SoupAuthDomain *domain, - SoupMessage *msg); - gboolean (*check_password) (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - const char *password); + char * (*accepts) (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *header); + char * (*challenge) (SoupAuthDomain *domain, + SoupServerMessage *msg); + gboolean (*check_password) (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + const char *password); gpointer padding[6]; }; @@ -37,14 +37,14 @@ struct _SoupAuthDomainClass { #define SOUP_AUTH_DOMAIN_GENERIC_AUTH_CALLBACK "generic-auth-callback" #define SOUP_AUTH_DOMAIN_GENERIC_AUTH_DATA "generic-auth-data" -typedef gboolean (*SoupAuthDomainFilter) (SoupAuthDomain *domain, - SoupMessage *msg, - gpointer user_data); +typedef gboolean (*SoupAuthDomainFilter) (SoupAuthDomain *domain, + SoupServerMessage *msg, + gpointer user_data); -typedef gboolean (*SoupAuthDomainGenericAuthCallback) (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username, - gpointer user_data); +typedef gboolean (*SoupAuthDomainGenericAuthCallback) (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username, + gpointer user_data); SOUP_AVAILABLE_IN_2_4 void soup_auth_domain_add_path (SoupAuthDomain *domain, @@ -69,24 +69,24 @@ void soup_auth_domain_set_generic_auth_callback (SoupAuthDomain *domain, GDestroyNotify dnotify); SOUP_AVAILABLE_IN_2_4 gboolean soup_auth_domain_check_password (SoupAuthDomain *domain, - SoupMessage *msg, + SoupServerMessage *msg, const char *username, const char *password); SOUP_AVAILABLE_IN_2_4 gboolean soup_auth_domain_covers (SoupAuthDomain *domain, - SoupMessage *msg); + SoupServerMessage *msg); SOUP_AVAILABLE_IN_2_4 char *soup_auth_domain_accepts (SoupAuthDomain *domain, - SoupMessage *msg); + SoupServerMessage *msg); SOUP_AVAILABLE_IN_2_4 void soup_auth_domain_challenge (SoupAuthDomain *domain, - SoupMessage *msg); + SoupServerMessage *msg); /* protected */ SOUP_AVAILABLE_IN_2_4 -gboolean soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain, - SoupMessage *msg, - const char *username); +gboolean soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain, + SoupServerMessage *msg, + const char *username); G_END_DECLS diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c index 4556635f..e94a366e 100644 --- a/libsoup/server/soup-server-io.c +++ b/libsoup/server/soup-server-io.c @@ -15,34 +15,115 @@ #include "soup-body-input-stream.h" #include "soup-body-output-stream.h" #include "soup-filter-input-stream.h" -#include "soup-message-private.h" +#include "soup-server-message-private.h" #include "soup-misc.h" #include "soup-socket-private.h" +struct _SoupServerMessageIOData { + SoupMessageIOData base; + + GBytes *write_chunk; + goffset write_body_offset; + + GSource *unpause_source; +}; + #define RESPONSE_BLOCK_SIZE 8192 #define HEADER_SIZE_LIMIT (64 * 1024) +void +soup_server_message_io_data_free (SoupServerMessageIOData *io) +{ + if (!io) + return; + + soup_message_io_data_cleanup (&io->base); + + if (io->unpause_source) { + g_source_destroy (io->unpause_source); + g_source_unref (io->unpause_source); + io->unpause_source = NULL; + } + + g_clear_pointer (&io->write_chunk, g_bytes_unref); + + g_slice_free (SoupServerMessageIOData, io); +} + +void +soup_server_message_io_finished (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io; + SoupMessageIOCompletionFn completion_cb; + gpointer completion_data; + SoupMessageIOCompletion completion; + + io = soup_server_message_get_io_data (msg); + if (!io) + return; + + completion_cb = io->base.completion_cb; + completion_data = io->base.completion_data; + + if ((io->base.read_state >= SOUP_MESSAGE_IO_STATE_FINISHING && + io->base.write_state >= SOUP_MESSAGE_IO_STATE_FINISHING)) + completion = SOUP_MESSAGE_IO_COMPLETE; + else + completion = SOUP_MESSAGE_IO_INTERRUPTED; + + g_object_ref (msg); + soup_server_message_set_io_data (msg, NULL); + if (completion_cb) + completion_cb (G_OBJECT (msg), completion, completion_data); + g_object_unref (msg); +} + +GIOStream * +soup_server_message_io_steal (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io; + SoupMessageIOCompletionFn completion_cb; + gpointer completion_data; + GIOStream *iostream; + + io = soup_server_message_get_io_data (msg); + if (!io || !io->base.iostream) + return NULL; + + iostream = g_object_ref (io->base.iostream); + completion_cb = io->base.completion_cb; + completion_data = io->base.completion_data; + + g_object_ref (msg); + soup_server_message_set_io_data (msg, NULL); + if (completion_cb) + completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data); + g_object_unref (msg); + + return iostream; +} + static void closed_async (GObject *source, GAsyncResult *result, gpointer user_data) { GOutputStream *body_ostream = G_OUTPUT_STREAM (source); - SoupMessage *msg = user_data; - SoupMessageIOData *io; + SoupServerMessage *msg = user_data; + SoupServerMessageIOData *io; GCancellable *async_wait; - io = soup_message_get_io_data (msg); - if (!io || !io->async_wait || io->body_ostream != body_ostream) { + io = soup_server_message_get_io_data (msg); + if (!io || !io->base.async_wait || io->base.body_ostream != body_ostream) { g_object_unref (msg); return; } - g_output_stream_close_finish (body_ostream, result, &io->async_error); - g_clear_object (&io->body_ostream); + g_output_stream_close_finish (body_ostream, result, &io->base.async_error); + g_clear_object (&io->base.body_ostream); - async_wait = io->async_wait; - io->async_wait = NULL; + async_wait = io->base.async_wait; + io->base.async_wait = NULL; g_cancellable_cancel (async_wait); g_object_unref (async_wait); @@ -76,12 +157,19 @@ closed_async (GObject *source, */ static void -handle_partial_get (SoupMessage *msg) +handle_partial_get (SoupServerMessage *msg) { SoupRange *ranges; int nranges; GBytes *full_response; guint status; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; + + request_headers = soup_server_message_get_request_headers (msg); + response_headers = soup_server_message_get_response_headers (msg); + response_body = soup_server_message_get_response_body (msg); /* Make sure the message is set up right for us to return a * partial response; it has to be a GET, the status must be @@ -89,50 +177,50 @@ handle_partial_get (SoupMessage *msg) * Content), and the SoupServer must have already filled in * the response body */ - if (msg->method != SOUP_METHOD_GET || - msg->status_code != SOUP_STATUS_OK || - soup_message_headers_get_encoding (msg->response_headers) != + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET || + soup_server_message_get_status (msg, NULL) != SOUP_STATUS_OK || + soup_message_headers_get_encoding (response_headers) != SOUP_ENCODING_CONTENT_LENGTH || - msg->response_body->length == 0 || - !soup_message_body_get_accumulate (msg->response_body)) + response_body->length == 0 || + !soup_message_body_get_accumulate (response_body)) return; /* Oh, and there has to have been a valid Range header on the * request, of course. */ - status = soup_message_headers_get_ranges_internal (msg->request_headers, - msg->response_body->length, + status = soup_message_headers_get_ranges_internal (request_headers, + response_body->length, TRUE, &ranges, &nranges); if (status == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE) { - soup_message_set_status (msg, status); - soup_message_body_truncate (msg->response_body); + soup_server_message_set_status (msg, status, NULL); + soup_message_body_truncate (response_body); return; } else if (status != SOUP_STATUS_PARTIAL_CONTENT) return; - full_response = soup_message_body_flatten (msg->response_body); + full_response = soup_message_body_flatten (response_body); if (!full_response) { - soup_message_headers_free_ranges (msg->request_headers, ranges); + soup_message_headers_free_ranges (request_headers, ranges); return; } - soup_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT); - soup_message_body_truncate (msg->response_body); + soup_server_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT, NULL); + soup_message_body_truncate (response_body); if (nranges == 1) { GBytes *range_buf; /* Single range, so just set Content-Range and fix the body. */ - soup_message_headers_set_content_range (msg->response_headers, + soup_message_headers_set_content_range (response_headers, ranges[0].start, ranges[0].end, g_bytes_get_size (full_response)); range_buf = g_bytes_new_from_bytes (full_response, ranges[0].start, ranges[0].end - ranges[0].start + 1); - soup_message_body_append_bytes (msg->response_body, range_buf); + soup_message_body_append_bytes (response_body, range_buf); g_bytes_unref (range_buf); } else { SoupMultipart *multipart; @@ -147,7 +235,7 @@ handle_partial_get (SoupMessage *msg) */ multipart = soup_multipart_new ("multipart/byteranges"); - content_type = soup_message_headers_get_one (msg->response_headers, + content_type = soup_message_headers_get_one (response_headers, "Content-Type"); for (i = 0; i < nranges; i++) { part_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART); @@ -169,52 +257,62 @@ handle_partial_get (SoupMessage *msg) g_bytes_unref (part_body); } - soup_multipart_to_message (multipart, msg->response_headers, &body); - soup_message_body_append_bytes (msg->response_body, body); + soup_multipart_to_message (multipart, response_headers, &body); + soup_message_body_append_bytes (response_body, body); g_bytes_unref (body); soup_multipart_free (multipart); } g_bytes_unref (full_response); - soup_message_headers_free_ranges (msg->request_headers, ranges); + soup_message_headers_free_ranges (request_headers, ranges); } static void -write_headers (SoupMessage *msg, - GString *headers, - SoupEncoding *encoding) +write_headers (SoupServerMessage *msg, + GString *headers, + SoupEncoding *encoding) { SoupEncoding claimed_encoding; SoupMessageHeadersIter iter; const char *name, *value; + guint status_code; + const char *reason_phrase; + const char *method; + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; - if (msg->status_code == 0) - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + if (soup_server_message_get_status (msg, NULL) == 0) + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, NULL); handle_partial_get (msg); + status_code = soup_server_message_get_status (msg, &reason_phrase); + g_string_append_printf (headers, "HTTP/1.%c %d %s\r\n", - soup_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1', - msg->status_code, msg->reason_phrase); - - claimed_encoding = soup_message_headers_get_encoding (msg->response_headers); - if ((msg->method == SOUP_METHOD_HEAD || - msg->status_code == SOUP_STATUS_NO_CONTENT || - msg->status_code == SOUP_STATUS_NOT_MODIFIED || - SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) || - (msg->method == SOUP_METHOD_CONNECT && - SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))) + soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1', + status_code, reason_phrase); + + method = soup_server_message_get_method (msg); + response_headers = soup_server_message_get_response_headers (msg); + claimed_encoding = soup_message_headers_get_encoding (response_headers); + if ((method == SOUP_METHOD_HEAD || + status_code == SOUP_STATUS_NO_CONTENT || + status_code == SOUP_STATUS_NOT_MODIFIED || + SOUP_STATUS_IS_INFORMATIONAL (status_code)) || + (method == SOUP_METHOD_CONNECT && + SOUP_STATUS_IS_SUCCESSFUL (status_code))) *encoding = SOUP_ENCODING_NONE; else *encoding = claimed_encoding; + response_body = soup_server_message_get_response_body (msg); if (claimed_encoding == SOUP_ENCODING_CONTENT_LENGTH && - !soup_message_headers_get_content_length (msg->response_headers)) { - soup_message_headers_set_content_length (msg->response_headers, - msg->response_body->length); + !soup_message_headers_get_content_length (response_headers)) { + soup_message_headers_set_content_length (response_headers, + response_body->length); } - soup_message_headers_iter_init (&iter, msg->response_headers); + soup_message_headers_iter_init (&iter, response_headers); while (soup_message_headers_iter_next (&iter, &name, &value)) g_string_append_printf (headers, "%s: %s\r\n", name, value); g_string_append (headers, "\r\n"); @@ -227,13 +325,15 @@ write_headers (SoupMessage *msg, * socket not writable, write is complete, etc). */ static gboolean -io_write (SoupMessage *msg, - GCancellable *cancellable, - GError **error) +io_write (SoupServerMessage *msg, + GCancellable *cancellable, + GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; GBytes *chunk; gssize nwrote; + guint status_code; if (io->async_error) { g_propagate_error (error, io->async_error); @@ -248,11 +348,12 @@ io_write (SoupMessage *msg, switch (io->write_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: - if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && msg->status_code == 0) { + status_code = soup_server_message_get_status (msg, NULL); + if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && status_code == 0) { /* Client requested "Expect: 100-continue", and * server did not set an error. */ - soup_message_set_status (msg, SOUP_STATUS_CONTINUE); + soup_server_message_set_status (msg, SOUP_STATUS_CONTINUE, NULL); } if (!io->write_buf->len) @@ -272,8 +373,9 @@ io_write (SoupMessage *msg, io->written = 0; g_string_truncate (io->write_buf, 0); - if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { - if (msg->status_code == SOUP_STATUS_CONTINUE) { + status_code = soup_server_message_get_status (msg, NULL); + if (SOUP_STATUS_IS_INFORMATIONAL (status_code)) { + if (status_code == SOUP_STATUS_CONTINUE) { /* Stop and wait for the body now */ io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING; @@ -288,20 +390,20 @@ io_write (SoupMessage *msg, */ } - soup_message_wrote_informational (msg); + soup_server_message_wrote_informational (msg); /* If this was "101 Switching Protocols", then * the server probably stole the connection... */ - if (io != soup_message_get_io_data (msg)) + if (server_io != soup_server_message_get_io_data (msg)) return FALSE; - soup_message_cleanup_response (msg); + soup_server_message_cleanup_response (msg); break; } if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) - io->write_length = soup_message_headers_get_content_length (msg->response_headers); + io->write_length = soup_message_headers_get_content_length (soup_server_message_get_response_headers (msg)); io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START; /* If the client was waiting for a Continue @@ -311,7 +413,7 @@ io_write (SoupMessage *msg, if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->read_state = SOUP_MESSAGE_IO_STATE_DONE; - soup_message_wrote_headers (msg); + soup_server_message_wrote_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: @@ -329,51 +431,53 @@ io_write (SoupMessage *msg, break; } - if (!io->write_chunk) { - io->write_chunk = soup_message_body_get_chunk (msg->response_body, io->write_body_offset); - if (!io->write_chunk) { - soup_message_io_pause (msg); + if (!server_io->write_chunk) { + server_io->write_chunk = soup_message_body_get_chunk (soup_server_message_get_response_body (msg), + server_io->write_body_offset); + if (!server_io->write_chunk) { + soup_server_message_io_pause (msg); return FALSE; } - if (!g_bytes_get_size (io->write_chunk)) { + if (!g_bytes_get_size (server_io->write_chunk)) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } } nwrote = g_pollable_stream_write (io->body_ostream, - (guchar*)g_bytes_get_data (io->write_chunk, NULL) + io->written, - g_bytes_get_size (io->write_chunk) - io->written, + (guchar*)g_bytes_get_data (server_io->write_chunk, NULL) + io->written, + g_bytes_get_size (server_io->write_chunk) - io->written, FALSE, cancellable, error); if (nwrote == -1) return FALSE; - chunk = g_bytes_new_from_bytes (io->write_chunk, io->written, nwrote); + chunk = g_bytes_new_from_bytes (server_io->write_chunk, io->written, nwrote); io->written += nwrote; if (io->write_length) io->write_length -= nwrote; - if (io->written == g_bytes_get_size (io->write_chunk)) + if (io->written == g_bytes_get_size (server_io->write_chunk)) io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DATA; - soup_message_wrote_body_data (msg, chunk); + soup_server_message_wrote_body_data (msg, g_bytes_get_size (chunk)); g_bytes_unref (chunk); break; case SOUP_MESSAGE_IO_STATE_BODY_DATA: io->written = 0; - if (g_bytes_get_size (io->write_chunk) == 0) { + if (g_bytes_get_size (server_io->write_chunk) == 0) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } - soup_message_body_wrote_chunk (msg->response_body, io->write_chunk); - io->write_body_offset += g_bytes_get_size (io->write_chunk); - g_clear_pointer (&io->write_chunk, g_bytes_unref); + soup_message_body_wrote_chunk (soup_server_message_get_response_body (msg), + server_io->write_chunk); + server_io->write_body_offset += g_bytes_get_size (server_io->write_chunk); + g_clear_pointer (&server_io->write_chunk, g_bytes_unref); io->write_state = SOUP_MESSAGE_IO_STATE_BODY; - soup_message_wrote_chunk (msg); + soup_server_message_wrote_chunk (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_FLUSH: @@ -397,7 +501,7 @@ io_write (SoupMessage *msg, case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; - soup_message_wrote_body (msg); + soup_server_message_wrote_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: @@ -435,55 +539,52 @@ parse_connect_authority (const char *req_path) } static guint -parse_headers (SoupMessage *msg, - char *headers, - guint headers_len, - SoupEncoding *encoding, - SoupSocket *sock, - GError **error) +parse_headers (SoupServerMessage *msg, + char *headers, + guint headers_len, + SoupEncoding *encoding, + GError **error) { char *req_method, *req_path, *url; SoupHTTPVersion version; + SoupSocket *sock; const char *req_host; guint status; SoupURI *uri; + SoupMessageHeaders *request_headers; + + request_headers = soup_server_message_get_request_headers (msg); status = soup_headers_parse_request (headers, headers_len, - msg->request_headers, + request_headers, &req_method, &req_path, &version); - if (!SOUP_STATUS_IS_SUCCESSFUL (status)) { - if (status == SOUP_STATUS_MALFORMED) { - g_set_error_literal (error, SOUP_REQUEST_ERROR, - SOUP_REQUEST_ERROR_PARSING, - _("Could not parse HTTP request")); - } + if (!SOUP_STATUS_IS_SUCCESSFUL (status)) return status; - } - g_object_set (G_OBJECT (msg), - SOUP_MESSAGE_METHOD, req_method, - SOUP_MESSAGE_HTTP_VERSION, version, - NULL); + soup_server_message_set_method (msg, req_method); + soup_server_message_set_http_version (msg, version); g_free (req_method); /* Handle request body encoding */ - *encoding = soup_message_headers_get_encoding (msg->request_headers); + *encoding = soup_message_headers_get_encoding (request_headers); if (*encoding == SOUP_ENCODING_UNRECOGNIZED) { - if (soup_message_headers_get_list (msg->request_headers, "Transfer-Encoding")) + if (soup_message_headers_get_list (request_headers, "Transfer-Encoding")) return SOUP_STATUS_NOT_IMPLEMENTED; else return SOUP_STATUS_BAD_REQUEST; } /* Generate correct context for request */ - req_host = soup_message_headers_get_one (msg->request_headers, "Host"); + req_host = soup_message_headers_get_one (request_headers, "Host"); if (req_host && strchr (req_host, '/')) { g_free (req_path); return SOUP_STATUS_BAD_REQUEST; } + sock = soup_server_message_get_soup_socket (msg); + if (!strcmp (req_path, "*") && req_host) { /* Eg, "OPTIONS * HTTP/1.1" */ url = g_strdup_printf ("%s://%s", @@ -493,7 +594,7 @@ parse_headers (SoupMessage *msg, if (uri) soup_uri_set_path (uri, "*"); g_free (url); - } else if (msg->method == SOUP_METHOD_CONNECT) { + } else if (soup_server_message_get_method (msg) == SOUP_METHOD_CONNECT) { /* Authority */ uri = parse_connect_authority (req_path); } else if (*req_path != '/') { @@ -505,7 +606,7 @@ parse_headers (SoupMessage *msg, req_host, req_path); uri = soup_uri_new (url); g_free (url); - } else if (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) { + } else if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) { /* No Host header, no AbsoluteUri */ GInetSocketAddress *addr = soup_socket_get_local_address (sock); GInetAddress *inet_addr = g_inet_socket_address_get_address (addr); @@ -530,7 +631,7 @@ parse_headers (SoupMessage *msg, return SOUP_STATUS_BAD_REQUEST; } - soup_message_set_uri (msg, uri); + soup_server_message_set_uri (msg, uri); soup_uri_free (uri); return SOUP_STATUS_OK; @@ -543,27 +644,33 @@ parse_headers (SoupMessage *msg, * socket not readable, read is complete, etc). */ static gboolean -io_read (SoupMessage *msg, - GCancellable *cancellable, - GError **error) +io_read (SoupServerMessage *msg, + GCancellable *cancellable, + GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; gssize nread; guint status; + SoupMessageHeaders *request_headers; switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: - if (!soup_message_io_read_headers (msg, io->istream, io->read_header_buf, FALSE, cancellable, error)) + if (!soup_message_io_data_read_headers (io, FALSE, cancellable, error)) { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT)) + soup_server_message_set_status (msg, SOUP_STATUS_MALFORMED, NULL); return FALSE; + } status = parse_headers (msg, (char *)io->read_header_buf->data, io->read_header_buf->len, &io->read_encoding, - io->sock, error); g_byte_array_set_size (io->read_header_buf, 0); + request_headers = soup_server_message_get_request_headers (msg); + if (status != SOUP_STATUS_OK) { /* Either we couldn't parse the headers, or they * indicated something that would mean we wouldn't @@ -572,14 +679,13 @@ io_read (SoupMessage *msg, * reading, and make sure the connection gets * closed when we're done. */ - soup_message_set_status (msg, status); - soup_message_headers_append (msg->request_headers, - "Connection", "close"); + soup_server_message_set_status (msg, status, NULL); + soup_message_headers_append (request_headers, "Connection", "close"); io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; break; } - if (soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) { + if (soup_message_headers_get_expectations (request_headers) & SOUP_EXPECTATION_CONTINUE) { /* We must return a status code and response * headers to the client; either an error to * be set by a got-headers handler below, or @@ -591,11 +697,11 @@ io_read (SoupMessage *msg, io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START; if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) - io->read_length = soup_message_headers_get_content_length (msg->request_headers); + io->read_length = soup_message_headers_get_content_length (request_headers); else io->read_length = -1; - soup_message_got_headers (msg); + soup_server_message_got_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: @@ -618,10 +724,13 @@ io_read (SoupMessage *msg, FALSE, cancellable, error); if (nread > 0) { - if (msg->request_body) { + SoupMessageBody *request_body; + + request_body = soup_server_message_get_request_body (msg); + if (request_body) { GBytes *bytes = g_bytes_new (buf, nread); - soup_message_body_got_chunk (msg->request_body, bytes); - soup_message_got_chunk (msg, bytes); + soup_message_body_got_chunk (request_body, bytes); + soup_server_message_got_chunk (msg, bytes); g_bytes_unref (bytes); } break; @@ -637,7 +746,7 @@ io_read (SoupMessage *msg, case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; - soup_message_got_body (msg); + soup_server_message_got_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: @@ -653,13 +762,14 @@ io_read (SoupMessage *msg, } static gboolean -io_run_until (SoupMessage *msg, +io_run_until (SoupServerMessage *msg, SoupMessageIOState read_state, SoupMessageIOState write_state, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; gboolean progress = TRUE, done; GError *my_error = NULL; @@ -674,7 +784,7 @@ io_run_until (SoupMessage *msg, g_object_ref (msg); - while (progress && soup_message_get_io_data (msg) == io && !io->paused && !io->async_wait && + while (progress && soup_server_message_get_io_data (msg) == server_io && !io->paused && !io->async_wait && (io->read_state < read_state || io->write_state < write_state)) { if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state)) @@ -689,7 +799,7 @@ io_run_until (SoupMessage *msg, g_propagate_error (error, my_error); g_object_unref (msg); return FALSE; - } else if (soup_message_get_io_data (msg) != io) { + } else if (soup_server_message_get_io_data (msg) != server_io) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled")); @@ -716,22 +826,22 @@ io_run_until (SoupMessage *msg, return done; } -static void io_run (SoupMessage *msg); +static void io_run (SoupServerMessage *msg); static gboolean -io_run_ready (SoupMessage *msg, - gpointer user_data) +io_run_ready (SoupServerMessage *msg, + gpointer user_data) { io_run (msg); return FALSE; } static void -io_run (SoupMessage *msg) +io_run (SoupServerMessage *msg) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; GError *error = NULL; - GCancellable *cancellable; if (io->io_source) { g_source_destroy (io->io_source); @@ -740,58 +850,109 @@ io_run (SoupMessage *msg) } g_object_ref (msg); - cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL; - if (io_run_until (msg, SOUP_MESSAGE_IO_STATE_DONE, SOUP_MESSAGE_IO_STATE_DONE, - cancellable, &error)) { - soup_message_io_finished (msg); + NULL, &error)) { + soup_server_message_io_finished (msg); } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_clear_error (&error); - io->io_source = soup_message_io_get_source (msg, NULL, io_run_ready, msg); + io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL, + (SoupMessageIOSourceFunc)io_run_ready, + NULL); g_source_attach (io->io_source, io->async_context); } else { - if (soup_message_get_io_data (msg) == io) { - if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code) && + if (soup_server_message_get_io_data (msg) == server_io) { + if (!SOUP_STATUS_IS_TRANSPORT_ERROR (soup_server_message_get_status (msg, NULL)) && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - soup_message_set_status (msg, SOUP_STATUS_IO_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, NULL); } - soup_message_io_finished (msg); + soup_server_message_io_finished (msg); } g_error_free (error); } - g_object_unref (msg); - g_clear_object (&cancellable); } void -soup_message_read_request (SoupMessage *msg, - SoupSocket *sock, - SoupMessageCompletionFn completion_cb, - gpointer user_data) +soup_server_message_read_request (SoupServerMessage *msg, + SoupMessageIOCompletionFn completion_cb, + gpointer user_data) { - SoupMessageIOData *io; + SoupServerMessageIOData *io; + SoupSocket *sock; - io = g_slice_new0 (SoupMessageIOData); - io->completion_cb = completion_cb; - io->completion_data = user_data; + io = g_slice_new0 (SoupServerMessageIOData); + io->base.completion_cb = completion_cb; + io->base.completion_data = user_data; - io->sock = sock; - io->iostream = g_object_ref (soup_socket_get_iostream (io->sock)); - io->istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->iostream)); - io->ostream = g_io_stream_get_output_stream (io->iostream); - io->async_context = g_main_context_ref_thread_default (); + sock = soup_server_message_get_soup_socket (msg); + io->base.iostream = g_object_ref (soup_socket_get_iostream (sock)); + io->base.istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->base.iostream)); + io->base.ostream = g_io_stream_get_output_stream (io->base.iostream); + io->base.async_context = g_main_context_ref_thread_default (); - io->read_header_buf = g_byte_array_new (); - io->write_buf = g_string_new (NULL); + io->base.read_header_buf = g_byte_array_new (); + io->base.write_buf = g_string_new (NULL); - io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; - io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; + io->base.read_state = SOUP_MESSAGE_IO_STATE_HEADERS; + io->base.write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; - soup_message_set_io_data (msg, io); + soup_server_message_set_io_data (msg, io); io_run (msg); } + +void +soup_server_message_io_pause (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + g_return_if_fail (io != NULL); + + if (io->unpause_source) { + g_source_destroy (io->unpause_source); + g_source_unref (io->unpause_source); + io->unpause_source = NULL; + } + + soup_message_io_data_pause (&io->base); +} + +static gboolean +io_unpause_internal (gpointer msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + g_return_val_if_fail (io != NULL, FALSE); + + g_clear_pointer (&io->unpause_source, g_source_unref); + soup_message_io_data_unpause (&io->base); + if (io->base.io_source) + return FALSE; + + io_run (msg); + return FALSE; +} + +void +soup_server_message_io_unpause (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + g_return_if_fail (io != NULL); + + if (!io->unpause_source) { + io->unpause_source = soup_add_completion_reffed (io->base.async_context, + io_unpause_internal, msg, NULL); + } +} + +gboolean +soup_server_message_is_io_paused (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + return io && io->base.paused; +} diff --git a/libsoup/server/soup-server-message-private.h b/libsoup/server/soup-server-message-private.h new file mode 100644 index 00000000..057b058d --- /dev/null +++ b/libsoup/server/soup-server-message-private.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Igalia S.L. + */ + +#ifndef __SOUP_SERVER_MESSAGE_PRIVATE_H__ +#define __SOUP_SERVER_MESSAGE_PRIVATE_H__ 1 + +#include "soup-server-message.h" +#include "soup-auth-domain.h" +#include "soup-message-io-data.h" +#include "soup-socket.h" + +SoupServerMessage *soup_server_message_new (SoupSocket *sock); +void soup_server_message_set_uri (SoupServerMessage *msg, + SoupURI *uri); +void soup_server_message_set_method (SoupServerMessage *msg, + const char *method); +SoupSocket *soup_server_message_get_soup_socket (SoupServerMessage *msg); +void soup_server_message_set_auth (SoupServerMessage *msg, + SoupAuthDomain *domain, + char *user); +gboolean soup_server_message_is_keepalive (SoupServerMessage *msg); +GIOStream *soup_server_message_io_steal (SoupServerMessage *msg); +void soup_server_message_io_pause (SoupServerMessage *msg); +void soup_server_message_io_unpause (SoupServerMessage *msg); +gboolean soup_server_message_is_io_paused (SoupServerMessage *msg); +void soup_server_message_io_finished (SoupServerMessage *msg); +void soup_server_message_cleanup_response (SoupServerMessage *msg); +void soup_server_message_wrote_informational (SoupServerMessage *msg); +void soup_server_message_wrote_headers (SoupServerMessage *msg); +void soup_server_message_wrote_chunk (SoupServerMessage *msg); +void soup_server_message_wrote_body_data (SoupServerMessage *msg, + gsize chunk_size); +void soup_server_message_wrote_body (SoupServerMessage *msg); +void soup_server_message_got_headers (SoupServerMessage *msg); +void soup_server_message_got_chunk (SoupServerMessage *msg, + GBytes *chunk); +void soup_server_message_got_body (SoupServerMessage *msg); +void soup_server_message_finished (SoupServerMessage *msg); +void soup_server_message_read_request (SoupServerMessage *msg, + SoupMessageIOCompletionFn completion_cb, + gpointer user_data); + +typedef struct _SoupServerMessageIOData SoupServerMessageIOData; +void soup_server_message_io_data_free (SoupServerMessageIOData *io); +void soup_server_message_set_io_data (SoupServerMessage *msg, + SoupServerMessageIOData *io); +SoupServerMessageIOData *soup_server_message_get_io_data (SoupServerMessage *msg); + +#endif /* __SOUP_SERVER_MESSAGE_PRIVATE_H__ */ diff --git a/libsoup/server/soup-server-message.c b/libsoup/server/soup-server-message.c new file mode 100644 index 00000000..1f2e8515 --- /dev/null +++ b/libsoup/server/soup-server-message.c @@ -0,0 +1,881 @@ +/* + * soup-server-message.c: HTTP server request/response + * + * Copyright (C) 2020 Igalia S.L. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#include "soup-server-message.h" +#include "soup.h" +#include "soup-connection.h" +#include "soup-server-message-private.h" +#include "soup-socket-private.h" + +/** + * SECTION:soup-server-message + * @short_description: An HTTP server request and response. + * @see_also: #SoupMessageHeaders, #SoupMessageBody + * + * A SoupServerMessage represents an HTTP message that is being sent or + * received on a #SoupServer + * + * #SoupServer will create #SoupServerMessage<!-- -->s automatically for + * incoming requests, which your application will receive via handlers. + * + * Note that libsoup's terminology here does not quite match the HTTP + * specification: in RFC 2616, an "HTTP-message" is + * <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a + * Response. In libsoup, a #SoupServerMessage combines both the request and + * the response. + **/ + +struct _SoupServerMessage { + GObject parent; + + SoupSocket *sock; + GSocket *gsock; + SoupAuthDomain *auth_domain; + char *auth_user; + + GSocketAddress *remote_addr; + char *remote_ip; + GSocketAddress *local_addr; + + const char *method; + SoupHTTPVersion http_version; + SoupHTTPVersion orig_http_version; + + guint status_code; + char *reason_phrase; + + SoupURI *uri; + + SoupMessageBody *request_body; + SoupMessageHeaders *request_headers; + + SoupMessageBody *response_body; + SoupMessageHeaders *response_headers; + + SoupServerMessageIOData *io_data; +}; + +struct _SoupServerMessageClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (SoupServerMessage, soup_server_message, G_TYPE_OBJECT) + +enum { + WROTE_INFORMATIONAL, + WROTE_HEADERS, + WROTE_CHUNK, + WROTE_BODY_DATA, + WROTE_BODY, + + GOT_HEADERS, + GOT_CHUNK, + GOT_BODY, + + DISCONNECTED, + FINISHED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +soup_server_message_init (SoupServerMessage *msg) +{ + msg->request_body = soup_message_body_new (); + msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); + msg->response_body = soup_message_body_new (); + msg->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE); + soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CONTENT_LENGTH); +} + +static void +soup_server_message_finalize (GObject *object) +{ + SoupServerMessage *msg = SOUP_SERVER_MESSAGE (object); + + soup_server_message_io_data_free (msg->io_data); + + g_clear_object (&msg->auth_domain); + g_clear_pointer (&msg->auth_user, g_free); + g_clear_object (&msg->remote_addr); + g_clear_object (&msg->local_addr); + + if (msg->sock) { + g_signal_handlers_disconnect_by_data (msg->sock, msg); + g_object_unref (msg->sock); + } + g_clear_object (&msg->gsock); + g_clear_pointer (&msg->remote_ip, g_free); + + g_clear_pointer (&msg->uri, soup_uri_free); + g_free (msg->reason_phrase); + + soup_message_body_free (msg->request_body); + soup_message_headers_free (msg->request_headers); + soup_message_body_free (msg->response_body); + soup_message_headers_free (msg->response_headers); + + G_OBJECT_CLASS (soup_server_message_parent_class)->finalize (object); +} + +static void +soup_server_message_class_init (SoupServerMessageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = soup_server_message_finalize; + + /** + * SoupServerMessage::wrote-informational: + * @msg: the message + * + * Emitted immediately after writing a 1xx (Informational) response. + */ + signals[WROTE_INFORMATIONAL] = + g_signal_new ("wrote-informational", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::wrote-headers: + * @msg: the message + * + * Emitted immediately after writing the response headers for a + * message. + */ + signals[WROTE_HEADERS] = + g_signal_new ("wrote-headers", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::wrote-chunk: + * @msg: the message + * + * Emitted immediately after writing a body chunk for a message. + * + * Note that this signal is not parallel to + * #SoupServerMessage::got-chunk; it is emitted only when a complete + * chunk (added with soup_message_body_append() or + * soup_message_body_append_bytes()) has been written. To get + * more useful continuous progress information, use + * #SoupServerMessage::wrote-body-data. + */ + signals[WROTE_CHUNK] = + g_signal_new ("wrote-chunk", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::wrote-body-data: + * @msg: the message + * @chunk_size: the number of bytes written + * + * Emitted immediately after writing a portion of the message + * body to the network. + */ + signals[WROTE_BODY_DATA] = + g_signal_new ("wrote-body-data", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_UINT); + + /** + * SoupServerMessage::wrote-body: + * @msg: the message + * + * Emitted immediately after writing the complete response body for a + * message. + */ + signals[WROTE_BODY] = + g_signal_new ("wrote-body", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::got-headers: + * @msg: the message + * + * Emitted after receiving the Request-Line and request headers. + */ + signals[GOT_HEADERS] = + g_signal_new ("got-headers", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::got-chunk: + * @msg: the message + * @chunk: the just-read chunk + * + * Emitted after receiving a chunk of a message body. Note + * that "chunk" in this context means any subpiece of the + * body, not necessarily the specific HTTP 1.1 chunks sent by + * the other side. + */ + signals[GOT_CHUNK] = + g_signal_new ("got-chunk", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_BYTES); + + /** + * SoupServerMessage::got-body: + * @msg: the message + * + * Emitted after receiving the complete request body. + */ + signals[GOT_BODY] = + g_signal_new ("got-body", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::finished: + * @msg: the message + * + * Emitted when all HTTP processing is finished for a message. + * (After #SoupServerMessage::wrote-body). + */ + signals[FINISHED] = + g_signal_new ("finished", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * SoupServerMessage::disconnected: + * @msg: the message + * + * Emitted when the @msg's socket is disconnected. + */ + signals[DISCONNECTED] = + g_signal_new ("disconnected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); +} + +static void +socket_disconnected (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[DISCONNECTED], 0); +} + +SoupServerMessage * +soup_server_message_new (SoupSocket *sock) +{ + SoupServerMessage *msg; + + msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + msg->sock = g_object_ref (sock); + msg->gsock = soup_socket_get_gsocket (sock); + if (msg->gsock) + g_object_ref (msg->gsock); + + g_signal_connect_object (sock, "disconnected", + G_CALLBACK (socket_disconnected), + msg, G_CONNECT_SWAPPED); + + return msg; +} + +void +soup_server_message_set_uri (SoupServerMessage *msg, + SoupURI *uri) +{ + if (msg->uri) + soup_uri_free (msg->uri); + msg->uri = soup_uri_copy (uri); +} + +SoupSocket * +soup_server_message_get_soup_socket (SoupServerMessage *msg) +{ + return msg->sock; +} + +void +soup_server_message_set_auth (SoupServerMessage *msg, + SoupAuthDomain *domain, + char *user) +{ + if (msg->auth_domain) + g_object_unref (msg->auth_domain); + msg->auth_domain = domain; + + if (msg->auth_user) + g_free (msg->auth_user); + msg->auth_user = user; +} + +gboolean +soup_server_message_is_keepalive (SoupServerMessage *msg) +{ + if (msg->status_code == SOUP_STATUS_OK && msg->method == SOUP_METHOD_CONNECT) + return TRUE; + + /* Not persistent if the server sent a terminate-by-EOF response */ + if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_EOF) + return FALSE; + + if (msg->http_version == SOUP_HTTP_1_0) { + /* In theory, HTTP/1.0 connections are only persistent + * if the client requests it, and the server agrees. + * But some servers do keep-alive even if the client + * doesn't request it. So ignore c_conn. + */ + + if (!soup_message_headers_header_contains (msg->response_headers, + "Connection", "Keep-Alive")) + return FALSE; + } else { + /* Normally persistent unless either side requested otherwise */ + if (soup_message_headers_header_contains (msg->request_headers, + "Connection", "close") || + soup_message_headers_header_contains (msg->response_headers, + "Connection", "close")) + return FALSE; + + return TRUE; + } + + return TRUE; +} + +void +soup_server_message_set_io_data (SoupServerMessage *msg, + SoupServerMessageIOData *io) +{ + soup_server_message_io_data_free (msg->io_data); + msg->io_data = io; +} + +SoupServerMessageIOData * +soup_server_message_get_io_data (SoupServerMessage *msg) +{ + return msg->io_data; +} + +void +soup_server_message_cleanup_response (SoupServerMessage *msg) +{ + soup_message_body_truncate (msg->response_body); + soup_message_headers_clear (msg->response_headers); + soup_message_headers_set_encoding (msg->response_headers, + SOUP_ENCODING_CONTENT_LENGTH); + msg->status_code = SOUP_STATUS_NONE; + g_clear_pointer (&msg->reason_phrase, g_free); + msg->http_version = msg->orig_http_version; +} + +void +soup_server_message_wrote_informational (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0); +} + +void +soup_server_message_wrote_headers (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[WROTE_HEADERS], 0); +} + +void +soup_server_message_wrote_chunk (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[WROTE_CHUNK], 0); +} + +void +soup_server_message_wrote_body_data (SoupServerMessage *msg, + gsize chunk_size) +{ + g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk_size); +} + +void +soup_server_message_wrote_body (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[WROTE_BODY], 0); +} + +void +soup_server_message_got_headers (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[GOT_HEADERS], 0); +} + +void +soup_server_message_got_chunk (SoupServerMessage *msg, + GBytes *chunk) +{ + g_signal_emit (msg, signals[GOT_CHUNK], 0, chunk); +} + +void +soup_server_message_got_body (SoupServerMessage *msg) +{ + if (soup_message_body_get_accumulate (msg->request_body)) + g_bytes_unref (soup_message_body_flatten (msg->request_body)); + g_signal_emit (msg, signals[GOT_BODY], 0); +} + +void +soup_server_message_finished (SoupServerMessage *msg) +{ + g_signal_emit (msg, signals[FINISHED], 0); +} + +/** + * soup_server_message_get_request_headers: + * @msg: a #SoupServerMessage + * + * Get the request headers of @msg. + * + * Returns: (transfer none): a #SoupMessageHeaders with the request headers. + */ +SoupMessageHeaders * +soup_server_message_get_request_headers (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->request_headers; +} + +/** + * soup_server_message_get_response_headers: + * @msg: a #SoupServerMessage + * + * Get the response headers of @msg. + * + * Returns: (transfer none): a #SoupMessageHeaders with the response headers. + */ +SoupMessageHeaders * +soup_server_message_get_response_headers (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->response_headers; +} + +/** + * soup_server_message_get_request_body: + * @msg: a #SoupServerMessage + * + * Get the request body of @msg. + * + * Returns: (transfer none): a #SoupMessageBody. + */ +SoupMessageBody * +soup_server_message_get_request_body (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->request_body; +} + +/** + * soup_server_message_get_response_body: + * @msg: a #SoupServerMessage + * + * Get the response body of @msg. + * + * Returns: (transfer none): a #SoupMessageBody. + */ +SoupMessageBody * +soup_server_message_get_response_body (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->response_body; +} + +/** + * soup_server_message_get_method: + * @msg: a #SoupServerMessage + * + * Get the HTTP method of @msg. + * + * Returns: the HTTP method. + */ +const char * +soup_server_message_get_method (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->method; +} + +void +soup_server_message_set_method (SoupServerMessage *msg, + const char *method) +{ + msg->method = g_intern_string (method); +} + +/** + * soup_server_message_get_http_version: + * @msg: a #SoupServerMessage + * + * Get the HTTP version of @msg. + * + * Returns: a #SoupHTTPVersion. + */ +SoupHTTPVersion +soup_server_message_get_http_version (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), SOUP_HTTP_1_1); + + return msg->http_version; +} + +/** + * soup_server_message_set_http_version: + * @msg: a #SoupServerMessage + * @version: a #SoupHTTPVersion + * + * Set the HTTP version of @msg. + */ +void +soup_server_message_set_http_version (SoupServerMessage *msg, + SoupHTTPVersion version) +{ + g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg)); + + msg->http_version = version; + if (msg->status_code == SOUP_STATUS_NONE) + msg->orig_http_version = version; +} + +/** + * soup_server_message_get_status: + * @msg: a #SoupServerMessage + * @reason_phrase: (out) (nullable) (transfer none): a location to store the reason phrase or %NULL + * + * Get the HTTP status code of @msg and optionally the reason phrase if @reason_phrase is not %NULL. + * + * Returns: the HTTP status code. + */ +guint +soup_server_message_get_status (SoupServerMessage *msg, + const char **reason_phrase) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), 0); + + if (reason_phrase) + *reason_phrase = msg->reason_phrase; + + return msg->status_code; +} + +/** + * soup_server_message_set_status: + * @msg: a #SoupServerMessage + * @status_code: an HTTP status code + * @reason_phrase: (nullable): a reason phrase + * + * Sets @msg's status code to @status_code. If @status_code is a + * known value and @reason_phrase is %NULL, the reason_phrase will + * be set automatically. + **/ +void +soup_server_message_set_status (SoupServerMessage *msg, + guint status_code, + const char *reason_phrase) +{ + g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg)); + g_return_if_fail (status_code != 0); + + g_free (msg->reason_phrase); + + msg->status_code = status_code; + msg->reason_phrase = g_strdup (reason_phrase ? reason_phrase : soup_status_get_phrase (status_code)); +} + +/** + * soup_server_message_get_uri: + * @msg: a #SoupServerMessage + * + * Get @msg's URI. + * + * Returns: (transfer none): a #SoupURI + */ +SoupURI * +soup_server_message_get_uri (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->uri; +} + +/** + * soup_server_message_set_response: + * @msg: the message + * @content_type: (allow-none): MIME Content-Type of the body + * @resp_use: a #SoupMemoryUse describing how to handle @resp_body + * @resp_body: (allow-none) (array length=resp_length) (element-type guint8): + * a data buffer containing the body of the message response. + * @resp_length: the byte length of @resp_body. + * + * Convenience function to set the response body of a #SoupServerMessage. If + * @content_type is %NULL, the response body must be empty as well. + */ +void +soup_server_message_set_response (SoupServerMessage *msg, + const char *content_type, + SoupMemoryUse resp_use, + const char *resp_body, + gsize resp_length) +{ + g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg)); + g_return_if_fail (content_type != NULL || resp_length == 0); + + if (content_type) { + g_warn_if_fail (strchr (content_type, '/') != NULL); + + soup_message_headers_replace (msg->response_headers, + "Content-Type", content_type); + soup_message_body_append (msg->response_body, resp_use, + resp_body, resp_length); + } else { + soup_message_headers_remove (msg->response_headers, + "Content-Type"); + soup_message_body_truncate (msg->response_body); + } +} + +/** + * soup_server_message_set_redirect: + * @msg: a #SoupServerMessage + * @status_code: a 3xx status code + * @redirect_uri: the URI to redirect @msg to + * + * Sets @msg's status_code to @status_code and adds a Location header + * pointing to @redirect_uri. Use this from a #SoupServer when you + * want to redirect the client to another URI. + * + * @redirect_uri can be a relative URI, in which case it is + * interpreted relative to @msg's current URI. In particular, if + * @redirect_uri is just a path, it will replace the path + * <emphasis>and query</emphasis> of @msg's URI. + */ +void +soup_server_message_set_redirect (SoupServerMessage *msg, + guint status_code, + const char *redirect_uri) +{ + SoupURI *location; + char *location_str; + + g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg)); + + location = soup_uri_new_with_base (soup_server_message_get_uri (msg), redirect_uri); + g_return_if_fail (location != NULL); + + soup_server_message_set_status (msg, status_code, NULL); + location_str = soup_uri_to_string (location, FALSE); + soup_message_headers_replace (msg->response_headers, "Location", + location_str); + g_free (location_str); + soup_uri_free (location); +} + +/** + * soup_server_message_get_socket: + * @msg: a #SoupServerMessage + * + * Retrieves the #GSocket that @msg is associated with. + * + * If you are using this method to observe when multiple requests are + * made on the same persistent HTTP connection (eg, as the ntlm-test + * test program does), you will need to pay attention to socket + * destruction as well (eg, by using weak references), so that you do + * not get fooled when the allocator reuses the memory address of a + * previously-destroyed socket to represent a new socket. + * + * Return value: (nullable) (transfer none): the #GSocket that @msg is + * associated with, %NULL if you used soup_server_accept_iostream(). + */ +GSocket * +soup_server_message_get_socket (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + return msg->gsock; +} + +/** + * soup_server_message_get_remote_address: + * @msg: a #SoupServerMessage + * + * Retrieves the #GSocketAddress associated with the remote end + * of a connection. + * + * Return value: (nullable) (transfer none): the #GSocketAddress + * associated with the remote end of a connection, it may be + * %NULL if you used soup_server_accept_iostream(). + */ +GSocketAddress * +soup_server_message_get_remote_address (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + if (msg->remote_addr) + return msg->remote_addr; + + msg->remote_addr = msg->gsock ? + g_socket_get_remote_address (msg->gsock, NULL) : + G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_remote_address (msg->sock))); + + return msg->remote_addr; +} + +/** + * soup_server_message_get_local_address: + * @msg: a #SoupServerMessage + * + * Retrieves the #GSocketAddress associated with the local end + * of a connection. + * + * Return value: (nullable) (transfer none): the #GSocketAddress + * associated with the local end of a connection, it may be + * %NULL if you used soup_server_accept_iostream(). + */ +GSocketAddress * +soup_server_message_get_local_address (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + if (msg->local_addr) + return msg->local_addr; + + msg->local_addr = msg->gsock ? + g_socket_get_local_address (msg->gsock, NULL) : + G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_local_address (msg->sock))); + + return msg->local_addr; +} + +/** + * soup_server_message_get_remote_host: + * @msg: a #SoupServerMessage + * + * Retrieves the IP address associated with the remote end of a + * connection. + * + * Return value: (nullable): the IP address associated with the remote + * end of a connection, it may be %NULL if you used + * soup_server_accept_iostream(). + */ +const char * +soup_server_message_get_remote_host (SoupServerMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL); + + if (msg->remote_ip) + return msg->remote_ip; + + if (msg->gsock) { + GSocketAddress *addr = soup_server_message_get_remote_address (msg); + GInetAddress *iaddr; + + if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr)) + return NULL; + iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)); + msg->remote_ip = g_inet_address_to_string (iaddr); + } else { + GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_socket_get_remote_address (msg->sock)); + GInetAddress *inet_addr = g_inet_socket_address_get_address (addr); + msg->remote_ip = g_inet_address_to_string (inet_addr); + } + + return msg->remote_ip; +} + +/** + * soup_server_message_steal_connection: + * @msg: a #SoupServerMessage + * + * "Steals" the HTTP connection associated with @msg from its + * #SoupServer. This happens immediately, regardless of the current + * state of the connection; if the response to @msg has not yet finished + * being sent, then it will be discarded; you can steal the connection from a + * #SoupServerMessage:wrote-informational or #SoupServerMessage:wrote-body signal + * handler if you need to wait for part or all of the response to be sent. + * + * Note that when calling this function from C, @msg will most + * likely be freed as a side effect. + * + * Return value: (transfer full): the #GIOStream formerly associated + * with @msg (or %NULL if @msg was no longer associated with a + * connection). No guarantees are made about what kind of #GIOStream + * is returned. + */ +GIOStream * +soup_server_message_steal_connection (SoupServerMessage *msg) +{ + GIOStream *stream; + + g_object_ref (msg); + stream = soup_server_message_io_steal (msg); + if (stream) { + g_object_set_data_full (G_OBJECT (stream), "GSocket", + soup_socket_steal_gsocket (msg->sock), + g_object_unref); + } + + socket_disconnected (msg); + g_object_unref (msg); + + return stream; +} diff --git a/libsoup/server/soup-server-message.h b/libsoup/server/soup-server-message.h new file mode 100644 index 00000000..5102648e --- /dev/null +++ b/libsoup/server/soup-server-message.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2020 Igalia S.L. + */ + +#ifndef __SOUP_SERVER_MESSAGE_H__ +#define __SOUP_SERVER_MESSAGE_H__ 1 + +#include "soup-types.h" +#include "soup-message-body.h" +#include "soup-message-headers.h" +#include "soup-method.h" + +G_BEGIN_DECLS + +#define SOUP_TYPE_SERVER_MESSAGE (soup_server_message_get_type ()) +SOUP_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (SoupServerMessage, soup_server_message, SOUP, SERVER_MESSAGE, GObject) + +SOUP_AVAILABLE_IN_ALL +SoupMessageHeaders *soup_server_message_get_request_headers (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +SoupMessageHeaders *soup_server_message_get_response_headers (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +SoupMessageBody *soup_server_message_get_request_body (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +SoupMessageBody *soup_server_message_get_response_body (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +const char *soup_server_message_get_method (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +SoupHTTPVersion soup_server_message_get_http_version (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +void soup_server_message_set_http_version (SoupServerMessage *msg, + SoupHTTPVersion version); + +SOUP_AVAILABLE_IN_ALL +guint soup_server_message_get_status (SoupServerMessage *msg, + const char **reason_phrase); +SOUP_AVAILABLE_IN_ALL +void soup_server_message_set_status (SoupServerMessage *msg, + guint status_code, + const char *reason_phrase); +SOUP_AVAILABLE_IN_ALL +SoupURI *soup_server_message_get_uri (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +void soup_server_message_set_response (SoupServerMessage *msg, + const char *content_type, + SoupMemoryUse resp_use, + const char *resp_body, + gsize resp_length); +SOUP_AVAILABLE_IN_ALL +void soup_server_message_set_redirect (SoupServerMessage *msg, + guint status_code, + const char *redirect_uri); + +SOUP_AVAILABLE_IN_ALL +GSocket *soup_server_message_get_socket (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +GSocketAddress *soup_server_message_get_local_address (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +GSocketAddress *soup_server_message_get_remote_address (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +const char *soup_server_message_get_remote_host (SoupServerMessage *msg); + +SOUP_AVAILABLE_IN_ALL +GIOStream *soup_server_message_steal_connection (SoupServerMessage *msg); + +G_END_DECLS + +#endif /* __SOUP_SERVER_MESSAGE_H__ */ diff --git a/libsoup/server/soup-server-private.h b/libsoup/server/soup-server-private.h deleted file mode 100644 index 15430e73..00000000 --- a/libsoup/server/soup-server-private.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020 Igalia S.L. - * - * This file is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#pragma once - -#include "soup-server.h" - -SoupSocket *soup_client_context_get_soup_socket (SoupClientContext *client); diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c index aa5f2203..2802f66a 100644 --- a/libsoup/server/soup-server.c +++ b/libsoup/server/soup-server.c @@ -13,9 +13,10 @@ #include <glib/gi18n-lib.h> -#include "soup-server-private.h" +#include "soup-server.h" +#include "soup-server-message-private.h" #include "soup.h" -#include "soup-message-private.h" +#include "soup-server-message-private.h" #include "soup-misc.h" #include "soup-path-map.h" #include "soup-socket-private.h" @@ -129,21 +130,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -struct _SoupClientContext { - SoupServer *server; - SoupSocket *sock; - GSocket *gsock; - SoupMessage *msg; - SoupAuthDomain *auth_domain; - char *auth_user; - - GSocketAddress *remote_addr; - char *remote_ip; - GSocketAddress *local_addr; - - int ref_count; -}; - typedef struct { char *path; @@ -207,9 +193,8 @@ enum { G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) -static SoupClientContext *soup_client_context_ref (SoupClientContext *client); -static void soup_client_context_unref (SoupClientContext *client); - +static void start_request (SoupServer *server, + SoupServerMessage *msg); static void free_handler (SoupServerHandler *handler) { @@ -398,7 +383,6 @@ soup_server_class_init (SoupServerClass *server_class) * SoupServer::request-started: * @server: the server * @message: the new message - * @client: the client context * * Emitted when the server has started reading a new request. * @message will be completely blank; not even the @@ -419,15 +403,13 @@ soup_server_class_init (SoupServerClass *server_class) G_STRUCT_OFFSET (SoupServerClass, request_started), NULL, NULL, NULL, - G_TYPE_NONE, 2, - SOUP_TYPE_MESSAGE, - SOUP_TYPE_CLIENT_CONTEXT); + G_TYPE_NONE, 1, + SOUP_TYPE_SERVER_MESSAGE); /** * SoupServer::request-read: * @server: the server * @message: the message - * @client: the client context * * Emitted when the server has successfully read a request. * @message will have all of its request-side information @@ -444,15 +426,13 @@ soup_server_class_init (SoupServerClass *server_class) G_STRUCT_OFFSET (SoupServerClass, request_read), NULL, NULL, NULL, - G_TYPE_NONE, 2, - SOUP_TYPE_MESSAGE, - SOUP_TYPE_CLIENT_CONTEXT); + G_TYPE_NONE, 1, + SOUP_TYPE_SERVER_MESSAGE); /** * SoupServer::request-finished: * @server: the server * @message: the message - * @client: the client context * * Emitted when the server has finished writing a response to * a request. @@ -464,15 +444,13 @@ soup_server_class_init (SoupServerClass *server_class) G_STRUCT_OFFSET (SoupServerClass, request_finished), NULL, NULL, NULL, - G_TYPE_NONE, 2, - SOUP_TYPE_MESSAGE, - SOUP_TYPE_CLIENT_CONTEXT); + G_TYPE_NONE, 1, + SOUP_TYPE_SERVER_MESSAGE); /** * SoupServer::request-aborted: * @server: the server * @message: the message - * @client: the client context * * Emitted when processing has failed for a message; this * could mean either that it could not be read (if @@ -493,9 +471,8 @@ soup_server_class_init (SoupServerClass *server_class) G_STRUCT_OFFSET (SoupServerClass, request_aborted), NULL, NULL, NULL, - G_TYPE_NONE, 2, - SOUP_TYPE_MESSAGE, - SOUP_TYPE_CLIENT_CONTEXT); + G_TYPE_NONE, 1, + SOUP_TYPE_SERVER_MESSAGE); /* properties */ /** @@ -818,97 +795,6 @@ soup_server_get_listeners (SoupServer *server) return listeners; } -static void start_request (SoupServer *, SoupClientContext *); -static void socket_disconnected (SoupSocket *sock, SoupClientContext *client); - -static SoupClientContext * -soup_client_context_new (SoupServer *server, SoupSocket *sock) -{ - SoupClientContext *client = g_slice_new0 (SoupClientContext); - - client->server = server; - client->sock = g_object_ref (sock); - client->gsock = soup_socket_get_gsocket (sock); - if (client->gsock) - g_object_ref (client->gsock); - g_signal_connect (sock, "disconnected", - G_CALLBACK (socket_disconnected), client); - client->ref_count = 1; - - return client; -} - -static void -soup_client_context_cleanup (SoupClientContext *client) -{ - g_clear_object (&client->auth_domain); - g_clear_pointer (&client->auth_user, g_free); - g_clear_object (&client->remote_addr); - g_clear_object (&client->local_addr); - - client->msg = NULL; -} - -static SoupClientContext * -soup_client_context_ref (SoupClientContext *client) -{ - g_atomic_int_inc (&client->ref_count); - return client; -} - -static void -soup_client_context_unref (SoupClientContext *client) -{ - if (!g_atomic_int_dec_and_test (&client->ref_count)) - return; - - soup_client_context_cleanup (client); - - g_signal_handlers_disconnect_by_func (client->sock, socket_disconnected, client); - g_object_unref (client->sock); - g_clear_object (&client->gsock); - g_clear_pointer (&client->remote_ip, g_free); - g_slice_free (SoupClientContext, client); -} - -static void -request_finished (SoupMessage *msg, SoupMessageIOCompletion completion, gpointer user_data) -{ - SoupClientContext *client = user_data; - SoupServer *server = client->server; - SoupServerPrivate *priv = soup_server_get_instance_private (server); - SoupSocket *sock = client->sock; - gboolean failed; - - if (completion == SOUP_MESSAGE_IO_STOLEN) { - soup_client_context_unref (client); - g_object_unref (msg); - return; - } - - /* Complete the message, assuming it actually really started. */ - if (msg->method) { - soup_message_finished (msg); - - failed = (completion == SOUP_MESSAGE_IO_INTERRUPTED || - msg->status_code == SOUP_STATUS_IO_ERROR); - g_signal_emit (server, - failed ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED], - 0, msg, client); - } - - if (completion == SOUP_MESSAGE_IO_COMPLETE && - soup_socket_is_connected (sock) && - soup_message_is_keepalive (msg) && - priv->listeners) { - start_request (server, client); - } else { - soup_socket_disconnect (client->sock); - soup_client_context_unref (client); - } - g_object_unref (msg); -} - /* "" was never documented as meaning the same thing as "/", but it * effectively was. We have to special case it now or otherwise it * would match "*" too. @@ -916,19 +802,21 @@ request_finished (SoupMessage *msg, SoupMessageIOCompletion completion, gpointer #define NORMALIZED_PATH(path) ((path) && *(path) ? (path) : "/") static SoupServerHandler * -get_handler (SoupServer *server, SoupMessage *msg) +get_handler (SoupServer *server, + SoupServerMessage *msg) { SoupServerPrivate *priv = soup_server_get_instance_private (server); SoupURI *uri; - uri = soup_message_get_uri (msg); + uri = soup_server_message_get_uri (msg); return soup_path_map_lookup (priv->handlers, NORMALIZED_PATH (uri->path)); } static void -call_handler (SoupServer *server, SoupServerHandler *handler, - SoupClientContext *client, SoupMessage *msg, - gboolean early) +call_handler (SoupServer *server, + SoupServerHandler *handler, + SoupServerMessage *msg, + gboolean early) { GHashTable *form_data_set; SoupURI *uri; @@ -938,10 +826,10 @@ call_handler (SoupServer *server, SoupServerHandler *handler, else if (!early && !handler->callback) return; - if (msg->status_code != 0) + if (soup_server_message_get_status (msg, NULL) != 0) return; - uri = soup_message_get_uri (msg); + uri = soup_server_message_get_uri (msg); if (uri->query) form_data_set = soup_form_decode (uri->query); else @@ -950,11 +838,11 @@ call_handler (SoupServer *server, SoupServerHandler *handler, if (early) { (*handler->early_callback) (server, msg, uri->path, form_data_set, - client, handler->early_user_data); + handler->early_user_data); } else { (*handler->callback) (server, msg, uri->path, form_data_set, - client, handler->user_data); + handler->user_data); } if (form_data_set) @@ -962,9 +850,9 @@ call_handler (SoupServer *server, SoupServerHandler *handler, } static void -got_headers (SoupMessage *msg, SoupClientContext *client) +got_headers (SoupServer *server, + SoupServerMessage *msg) { - SoupServer *server = client->server; SoupServerPrivate *priv = soup_server_get_instance_private (server); SoupServerHandler *handler; SoupURI *uri; @@ -974,22 +862,26 @@ got_headers (SoupMessage *msg, SoupClientContext *client) GSList *iter; gboolean rejected = FALSE; char *auth_user; + SoupMessageHeaders *headers; + SoupSocket *sock; /* Add required response headers */ + headers = soup_server_message_get_response_headers (msg); + date = g_date_time_new_now_utc (); date_string = soup_date_time_to_string (date, SOUP_DATE_HTTP); - soup_message_headers_replace (msg->response_headers, "Date", - date_string); + soup_message_headers_replace (headers, "Date", date_string); g_free (date_string); g_date_time_unref (date); - if (msg->status_code != 0) + if (soup_server_message_get_status (msg, NULL) != 0) return; - uri = soup_message_get_uri (msg); - if ((soup_socket_is_ssl (client->sock) && !soup_uri_is_https (uri, priv->https_aliases)) || - (!soup_socket_is_ssl (client->sock) && !soup_uri_is_http (uri, priv->http_aliases))) { - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + sock = soup_server_message_get_soup_socket (msg); + uri = soup_server_message_get_uri (msg); + if ((soup_socket_is_ssl (sock) && !soup_uri_is_https (uri, priv->https_aliases)) || + (!soup_socket_is_ssl (sock) && !soup_uri_is_http (uri, priv->http_aliases))) { + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return; } @@ -1010,7 +902,7 @@ got_headers (SoupMessage *msg, SoupClientContext *client) ) { /* Introducing new ".." segments is not allowed */ g_free (decoded_path); - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return; } @@ -1029,8 +921,7 @@ got_headers (SoupMessage *msg, SoupClientContext *client) if (soup_auth_domain_covers (domain, msg)) { auth_user = soup_auth_domain_accepts (domain, msg); if (auth_user) { - client->auth_domain = g_object_ref (domain); - client->auth_user = auth_user; + soup_server_message_set_auth (msg, g_object_ref (domain), auth_user); return; } @@ -1052,15 +943,14 @@ got_headers (SoupMessage *msg, SoupClientContext *client) /* Otherwise, call the early handlers. */ handler = get_handler (server, msg); if (handler) - call_handler (server, handler, client, msg, TRUE); + call_handler (server, handler, msg, TRUE); } static void -complete_websocket_upgrade (SoupMessage *msg, gpointer user_data) +complete_websocket_upgrade (SoupServer *server, + SoupServerMessage *msg) { - SoupClientContext *client = user_data; - SoupServer *server = client->server; - SoupURI *uri = soup_message_get_uri (msg); + SoupURI *uri = soup_server_message_get_uri (msg); SoupServerHandler *handler; GIOStream *stream; SoupWebsocketConnection *conn; @@ -1069,42 +959,41 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data) if (!handler || !handler->websocket_callback) return; - soup_client_context_ref (client); - stream = soup_client_context_steal_connection (client); + g_object_ref (msg); + stream = soup_server_message_steal_connection (msg); conn = soup_websocket_connection_new_with_extensions (stream, uri, SOUP_WEBSOCKET_CONNECTION_SERVER, - soup_message_headers_get_one (msg->request_headers, "Origin"), - soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), + soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "Origin"), + soup_message_headers_get_one (soup_server_message_get_response_headers (msg), "Sec-WebSocket-Protocol"), handler->websocket_extensions); handler->websocket_extensions = NULL; g_object_unref (stream); - soup_client_context_unref (client); - (*handler->websocket_callback) (server, conn, uri->path, client, + (*handler->websocket_callback) (server, msg, uri->path, conn, handler->websocket_user_data); g_object_unref (conn); - soup_client_context_unref (client); + g_object_unref (msg); } static void -got_body (SoupMessage *msg, SoupClientContext *client) +got_body (SoupServer *server, + SoupServerMessage *msg) { - SoupServer *server = client->server; SoupServerHandler *handler; - g_signal_emit (server, signals[REQUEST_READ], 0, msg, client); + g_signal_emit (server, signals[REQUEST_READ], 0, msg); - if (msg->status_code != 0) + if (soup_server_message_get_status (msg, NULL) != 0) return; handler = get_handler (server, msg); if (!handler) { - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL); return; } - call_handler (server, handler, client, msg, FALSE); - if (msg->status_code != 0) + call_handler (server, handler, msg, FALSE); + if (soup_server_message_get_status (msg, NULL) != 0) return; if (handler->websocket_callback) { @@ -1116,65 +1005,110 @@ got_body (SoupMessage *msg, SoupClientContext *client) handler->websocket_protocols, priv->websocket_extension_types, &handler->websocket_extensions)) { - g_signal_connect (msg, "wrote-informational", - G_CALLBACK (complete_websocket_upgrade), - soup_client_context_ref (client)); + g_signal_connect_object (msg, "wrote-informational", + G_CALLBACK (complete_websocket_upgrade), + server, G_CONNECT_SWAPPED); } } } static void -start_request (SoupServer *server, SoupClientContext *client) +client_disconnected (SoupServer *server, + SoupServerMessage *msg) { SoupServerPrivate *priv = soup_server_get_instance_private (server); - SoupMessage *msg; - - soup_client_context_cleanup (client); - /* Listen for another request on this connection */ - msg = g_object_new (SOUP_TYPE_MESSAGE, - SOUP_MESSAGE_SERVER_SIDE, TRUE, - NULL); - client->msg = msg; + priv->clients = g_slist_remove (priv->clients, msg); - if (priv->server_header) { - soup_message_headers_append (msg->response_headers, "Server", - priv->server_header); + if (soup_server_message_get_status (msg, NULL) != 0) { + soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, NULL); + soup_server_message_io_finished (msg); } +} - g_signal_connect (msg, "got_headers", G_CALLBACK (got_headers), client); - g_signal_connect (msg, "got_body", G_CALLBACK (got_body), client); - - g_signal_emit (server, signals[REQUEST_STARTED], 0, - msg, client); - - soup_message_read_request (msg, client->sock, - request_finished, client); +static void +soup_server_accept_socket (SoupServer *server, + SoupSocket *sock) +{ + SoupServerPrivate *priv = soup_server_get_instance_private (server); + SoupServerMessage *msg; + + msg = soup_server_message_new (sock); + g_signal_connect_object (msg, "disconnected", + G_CALLBACK (client_disconnected), + server, G_CONNECT_SWAPPED); + priv->clients = g_slist_prepend (priv->clients, msg); + start_request (server, msg); } static void -socket_disconnected (SoupSocket *sock, SoupClientContext *client) +request_finished (SoupServerMessage *msg, + SoupMessageIOCompletion completion, + SoupServer *server) { - SoupServerPrivate *priv = soup_server_get_instance_private (client->server); + SoupServerPrivate *priv = soup_server_get_instance_private (server); + SoupSocket *sock = soup_server_message_get_soup_socket (msg); + gboolean failed; + + if (completion == SOUP_MESSAGE_IO_STOLEN) { + g_object_unref (msg); + return; + } - priv->clients = g_slist_remove (priv->clients, client); + /* Complete the message, assuming it actually really started. */ + if (soup_server_message_get_method (msg)) { + soup_server_message_finished (msg); + + failed = (completion == SOUP_MESSAGE_IO_INTERRUPTED || + soup_server_message_get_status (msg, NULL) == SOUP_STATUS_IO_ERROR); + g_signal_emit (server, + failed ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED], + 0, msg); + } - if (client->msg) { - soup_message_set_status (client->msg, SOUP_STATUS_IO_ERROR); - soup_message_io_finished (client->msg); + if (completion == SOUP_MESSAGE_IO_COMPLETE && + soup_socket_is_connected (sock) && + soup_server_message_is_keepalive (msg) && + priv->listeners) { + g_object_ref (sock); + priv->clients = g_slist_remove (priv->clients, msg); + g_object_unref (msg); + + soup_server_accept_socket (server, sock); + g_object_unref (sock); + return; } + + soup_socket_disconnect (sock); + g_object_unref (msg); } static void -soup_server_accept_socket (SoupServer *server, - SoupSocket *sock) +start_request (SoupServer *server, + SoupServerMessage *msg) { SoupServerPrivate *priv = soup_server_get_instance_private (server); - SoupClientContext *client; - client = soup_client_context_new (server, sock); - priv->clients = g_slist_prepend (priv->clients, client); - start_request (server, client); + if (priv->server_header) { + SoupMessageHeaders *headers; + + headers = soup_server_message_get_response_headers (msg); + soup_message_headers_append (headers, "Server", + priv->server_header); + } + + g_signal_connect_object (msg, "got-headers", + G_CALLBACK (got_headers), + server, G_CONNECT_SWAPPED); + g_signal_connect_object (msg, "got-body", + G_CALLBACK (got_body), + server, G_CONNECT_SWAPPED); + + g_signal_emit (server, signals[REQUEST_STARTED], 0, msg); + + soup_server_message_read_request (msg, + (SoupMessageIOCompletionFn)request_finished, + server); } /** @@ -1194,11 +1128,11 @@ soup_server_accept_socket (SoupServer *server, * Since: 2.50 **/ gboolean -soup_server_accept_iostream (SoupServer *server, - GIOStream *stream, - GSocketAddress *local_addr, - GSocketAddress *remote_addr, - GError **error) +soup_server_accept_iostream (SoupServer *server, + GIOStream *stream, + GSocketAddress *local_addr, + GSocketAddress *remote_addr, + GError **error) { SoupSocket *sock; @@ -1244,7 +1178,6 @@ soup_server_disconnect (SoupServer *server) SoupServerPrivate *priv; GSList *listeners, *clients, *iter; SoupSocket *listener; - SoupClientContext *client; g_return_if_fail (SOUP_IS_SERVER (server)); priv = soup_server_get_instance_private (server); @@ -1255,8 +1188,9 @@ soup_server_disconnect (SoupServer *server) priv->listeners = NULL; for (iter = clients; iter; iter = iter->next) { - client = iter->data; - soup_socket_disconnect (client->sock); + SoupServerMessage *msg = iter->data; + + soup_socket_disconnect (soup_server_message_get_soup_socket (msg)); } g_slist_free (clients); @@ -1679,257 +1613,12 @@ soup_server_get_uris (SoupServer *server) } /** - * SoupClientContext: - * - * A #SoupClientContext provides additional information about the - * client making a particular request. In particular, you can use - * soup_client_context_get_auth_domain() and - * soup_client_context_get_auth_user() to determine if HTTP - * authentication was used successfully. - * - * soup_client_context_get_remote_address() and/or - * soup_client_context_get_host() can be used to get information for - * logging or debugging purposes. soup_client_context_get_socket() may - * also be of use in some situations (eg, tracking when multiple - * requests are made on the same connection). - **/ -G_DEFINE_BOXED_TYPE (SoupClientContext, soup_client_context, soup_client_context_ref, soup_client_context_unref) - -/** - * soup_client_context_get_soup_socket: - * @client: a #SoupClientContext - * - * Retrieves the #SoupSocket that @client is associated with. - * - * If you are using this method to observe when multiple requests are - * made on the same persistent HTTP connection (eg, as the ntlm-test - * test program does), you will need to pay attention to socket - * destruction as well (either by using weak references, or by - * connecting to the #SoupSocket::disconnected signal), so that you do - * not get fooled when the allocator reuses the memory address of a - * previously-destroyed socket to represent a new socket. - * - * Return value: (transfer none): the #SoupSocket that @client is - * associated with. - **/ -SoupSocket * -soup_client_context_get_soup_socket (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - return client->sock; -} - -/** - * soup_client_context_get_socket: - * @client: a #SoupClientContext - * - * Retrieves the #GSocket that @client is associated with. - * - * If you are using this method to observe when multiple requests are - * made on the same persistent HTTP connection (eg, as the ntlm-test - * test program does), you will need to pay attention to socket - * destruction as well (eg, by using weak references), so that you do - * not get fooled when the allocator reuses the memory address of a - * previously-destroyed socket to represent a new socket. - * - * Return value: (nullable) (transfer none): the #GSocket that @client is - * associated with, %NULL if you used soup_server_accept_iostream(). - * - * Since: 2.48 - **/ -GSocket * -soup_client_context_get_socket (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - return client->gsock; -} - -/** - * soup_client_context_get_remote_address: - * @client: a #SoupClientContext - * - * Retrieves the #GSocketAddress associated with the remote end - * of a connection. - * - * Return value: (nullable) (transfer none): the #GSocketAddress - * associated with the remote end of a connection, it may be - * %NULL if you used soup_server_accept_iostream(). - * - * Since: 2.48 - **/ -GSocketAddress * -soup_client_context_get_remote_address (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - if (client->remote_addr) - return client->remote_addr; - - client->remote_addr = client->gsock ? - g_socket_get_remote_address (client->gsock, NULL) : - G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_remote_address (client->sock))); - - return client->remote_addr; -} - -/** - * soup_client_context_get_local_address: - * @client: a #SoupClientContext - * - * Retrieves the #GSocketAddress associated with the local end - * of a connection. - * - * Return value: (nullable) (transfer none): the #GSocketAddress - * associated with the local end of a connection, it may be - * %NULL if you used soup_server_accept_iostream(). - * - * Since: 2.48 - **/ -GSocketAddress * -soup_client_context_get_local_address (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - if (client->local_addr) - return client->local_addr; - - client->local_addr = client->gsock ? - g_socket_get_local_address (client->gsock, NULL) : - G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_local_address (client->sock))); - - return client->local_addr; -} - -/** - * soup_client_context_get_host: - * @client: a #SoupClientContext - * - * Retrieves the IP address associated with the remote end of a - * connection. - * - * Return value: (nullable): the IP address associated with the remote - * end of a connection, it may be %NULL if you used - * soup_server_accept_iostream(). - **/ -const char * -soup_client_context_get_host (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - if (client->remote_ip) - return client->remote_ip; - - if (client->gsock) { - GSocketAddress *addr = soup_client_context_get_remote_address (client); - GInetAddress *iaddr; - - if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr)) - return NULL; - iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)); - client->remote_ip = g_inet_address_to_string (iaddr); - } else { - GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_socket_get_remote_address (client->sock)); - GInetAddress *inet_addr = g_inet_socket_address_get_address (addr); - client->remote_ip = g_inet_address_to_string (inet_addr); - } - - return client->remote_ip; -} - -/** - * soup_client_context_get_auth_domain: - * @client: a #SoupClientContext - * - * Checks whether the request associated with @client has been - * authenticated, and if so returns the #SoupAuthDomain that - * authenticated it. - * - * Return value: (transfer none) (nullable): a #SoupAuthDomain, or - * %NULL if the request was not authenticated. - **/ -SoupAuthDomain * -soup_client_context_get_auth_domain (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - return client->auth_domain; -} - -/** - * soup_client_context_get_auth_user: - * @client: a #SoupClientContext - * - * Checks whether the request associated with @client has been - * authenticated, and if so returns the username that the client - * authenticated as. - * - * Return value: (nullable): the authenticated-as user, or %NULL if - * the request was not authenticated. - **/ -const char * -soup_client_context_get_auth_user (SoupClientContext *client) -{ - g_return_val_if_fail (client != NULL, NULL); - - return client->auth_user; -} - -/** - * soup_client_context_steal_connection: - * @client: a #SoupClientContext - * - * "Steals" the HTTP connection associated with @client from its - * #SoupServer. This happens immediately, regardless of the current - * state of the connection; if the response to the current - * #SoupMessage has not yet finished being sent, then it will be - * discarded; you can steal the connection from a - * #SoupMessage::wrote-informational or #SoupMessage::wrote-body signal - * handler if you need to wait for part or all of the response to be - * sent. - * - * Note that when calling this function from C, @client will most - * likely be freed as a side effect. - * - * Return value: (transfer full): the #GIOStream formerly associated - * with @client (or %NULL if @client was no longer associated with a - * connection). No guarantees are made about what kind of #GIOStream - * is returned. - * - * Since: 2.50 - **/ -GIOStream * -soup_client_context_steal_connection (SoupClientContext *client) -{ - GIOStream *stream; - - g_return_val_if_fail (client != NULL, NULL); - - soup_client_context_ref (client); - - stream = soup_message_io_steal (client->msg); - if (stream) { - g_object_set_data_full (G_OBJECT (stream), "GSocket", - soup_socket_steal_gsocket (client->sock), - g_object_unref); - } - - socket_disconnected (client->sock, client); - soup_client_context_unref (client); - - return stream; -} - - -/** * SoupServerCallback: * @server: the #SoupServer * @msg: the message being processed * @path: the path component of @msg's Request-URI * @query: (element-type utf8 utf8) (allow-none): the parsed query * component of @msg's Request-URI - * @client: additional contextual information about the client * @user_data: the data passed to soup_server_add_handler() or * soup_server_add_early_handler(). * @@ -2108,7 +1797,7 @@ soup_server_add_early_handler (SoupServer *server, * @server: the #SoupServer * @path: the path component of @msg's Request-URI * @connection: the newly created WebSocket connection - * @client: additional contextual information about the client + * @msg: the #SoupServerMessage * @user_data: the data passed to @soup_server_add_handler * * A callback used to handle WebSocket requests to a #SoupServer. The @@ -2249,30 +1938,30 @@ soup_server_remove_auth_domain (SoupServer *server, SoupAuthDomain *auth_domain) /** * soup_server_pause_message: * @server: a #SoupServer - * @msg: a #SoupMessage associated with @server. + * @msg: a #SoupServerMessage associated with @server. * * Pauses I/O on @msg. This can be used when you need to return from * the server handler without having the full response ready yet. Use * soup_server_unpause_message() to resume I/O. * - * This must only be called on a #SoupMessage which was created by the + * This must only be called on a #SoupServerMessage which was created by the * #SoupServer and are currently doing I/O, such as those passed into a * #SoupServerCallback or emitted in a #SoupServer::request-read signal. **/ void -soup_server_pause_message (SoupServer *server, - SoupMessage *msg) +soup_server_pause_message (SoupServer *server, + SoupServerMessage *msg) { g_return_if_fail (SOUP_IS_SERVER (server)); - g_return_if_fail (SOUP_IS_MESSAGE (msg)); + g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg)); - soup_message_io_pause (msg); + soup_server_message_io_pause (msg); } /** * soup_server_unpause_message: * @server: a #SoupServer - * @msg: a #SoupMessage associated with @server. + * @msg: a #SoupServerMessage associated with @server. * * Resumes I/O on @msg. Use this to resume after calling * soup_server_pause_message(), or after adding a new chunk to a @@ -2280,18 +1969,18 @@ soup_server_pause_message (SoupServer *server, * * I/O won't actually resume until you return to the main loop. * - * This must only be called on a #SoupMessage which was created by the + * This must only be called on a #SoupServerMessage which was created by the * #SoupServer and are currently doing I/O, such as those passed into a * #SoupServerCallback or emitted in a #SoupServer::request-read signal. **/ void -soup_server_unpause_message (SoupServer *server, - SoupMessage *msg) +soup_server_unpause_message (SoupServer *server, + SoupServerMessage *msg) { g_return_if_fail (SOUP_IS_SERVER (server)); - g_return_if_fail (SOUP_IS_MESSAGE (msg)); + g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg)); - soup_message_io_unpause (msg); + soup_server_message_io_unpause (msg); } /** diff --git a/libsoup/server/soup-server.h b/libsoup/server/soup-server.h index eb9a13b7..b5225207 100644 --- a/libsoup/server/soup-server.h +++ b/libsoup/server/soup-server.h @@ -15,11 +15,6 @@ G_BEGIN_DECLS SOUP_AVAILABLE_IN_2_4 G_DECLARE_DERIVABLE_TYPE (SoupServer, soup_server, SOUP, SERVER, GObject) -typedef struct _SoupClientContext SoupClientContext; -SOUP_AVAILABLE_IN_2_4 -GType soup_client_context_get_type (void); -#define SOUP_TYPE_CLIENT_CONTEXT (soup_client_context_get_type ()) - typedef enum { SOUP_SERVER_LISTEN_HTTPS = (1 << 0), SOUP_SERVER_LISTEN_IPV4_ONLY = (1 << 1), @@ -30,14 +25,14 @@ struct _SoupServerClass { GObjectClass parent_class; /* signals */ - void (*request_started) (SoupServer *server, SoupMessage *msg, - SoupClientContext *client); - void (*request_read) (SoupServer *server, SoupMessage *msg, - SoupClientContext *client); - void (*request_finished) (SoupServer *server, SoupMessage *msg, - SoupClientContext *client); - void (*request_aborted) (SoupServer *server, SoupMessage *msg, - SoupClientContext *client); + void (*request_started) (SoupServer *server, + SoupServerMessage *msg); + void (*request_read) (SoupServer *server, + SoupServerMessage *msg); + void (*request_finished) (SoupServer *server, + SoupServerMessage *msg); + void (*request_aborted) (SoupServer *server, + SoupServerMessage *msg); gpointer padding[6]; }; @@ -98,10 +93,9 @@ gboolean soup_server_accept_iostream (SoupServer *server /* Handlers and auth */ typedef void (*SoupServerCallback) (SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, GHashTable *query, - SoupClientContext *client, gpointer user_data); SOUP_AVAILABLE_IN_2_4 @@ -121,9 +115,9 @@ void soup_server_add_early_handler (SoupServer *server, #define SOUP_SERVER_REMOVE_WEBSOCKET_EXTENSION "remove-websocket-extension" typedef void (*SoupServerWebsocketCallback) (SoupServer *server, - SoupWebsocketConnection *connection, + SoupServerMessage *msg, const char *path, - SoupClientContext *client, + SoupWebsocketConnection *connection, gpointer user_data); SOUP_AVAILABLE_IN_2_50 void soup_server_add_websocket_handler (SoupServer *server, @@ -153,28 +147,10 @@ void soup_server_remove_auth_domain (SoupServer *server, /* I/O */ SOUP_AVAILABLE_IN_2_4 -void soup_server_pause_message (SoupServer *server, - SoupMessage *msg); -SOUP_AVAILABLE_IN_2_4 -void soup_server_unpause_message (SoupServer *server, - SoupMessage *msg); - -/* Client context */ - -SOUP_AVAILABLE_IN_2_48 -GSocket *soup_client_context_get_socket (SoupClientContext *client); -SOUP_AVAILABLE_IN_2_48 -GSocketAddress *soup_client_context_get_local_address (SoupClientContext *client); -SOUP_AVAILABLE_IN_2_48 -GSocketAddress *soup_client_context_get_remote_address (SoupClientContext *client); -SOUP_AVAILABLE_IN_2_4 -const char *soup_client_context_get_host (SoupClientContext *client); +void soup_server_pause_message (SoupServer *server, + SoupServerMessage *msg); SOUP_AVAILABLE_IN_2_4 -SoupAuthDomain *soup_client_context_get_auth_domain (SoupClientContext *client); -SOUP_AVAILABLE_IN_2_4 -const char *soup_client_context_get_auth_user (SoupClientContext *client); - -SOUP_AVAILABLE_IN_2_50 -GIOStream *soup_client_context_steal_connection (SoupClientContext *client); +void soup_server_unpause_message (SoupServer *server, + SoupServerMessage *msg); G_END_DECLS diff --git a/libsoup/soup-client-input-stream.c b/libsoup/soup-client-input-stream.c index 16abb411..8fa28c0b 100644 --- a/libsoup/soup-client-input-stream.c +++ b/libsoup/soup-client-input-stream.c @@ -193,8 +193,9 @@ soup_client_input_stream_close_async (GInputStream *stream, g_task_set_priority (task, priority); if (close_async_ready (cistream->priv->msg, task) == G_SOURCE_CONTINUE) { - source = soup_message_io_get_source (cistream->priv->msg, - cancellable, NULL, NULL); + source = soup_message_io_data_get_source ((SoupMessageIOData *)soup_message_get_io_data (cistream->priv->msg), + G_OBJECT (cistream->priv->msg), + cancellable, NULL, NULL); g_task_attach_source (task, source, (GSourceFunc) close_async_ready); g_source_unref (source); diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c index df2cdb59..6e39bc7c 100644 --- a/libsoup/soup-connection.c +++ b/libsoup/soup-connection.c @@ -730,10 +730,10 @@ soup_connection_get_ever_used (SoupConnection *conn) } void -soup_connection_send_request (SoupConnection *conn, - SoupMessageQueueItem *item, - SoupMessageCompletionFn completion_cb, - gpointer user_data) +soup_connection_send_request (SoupConnection *conn, + SoupMessageQueueItem *item, + SoupMessageIOCompletionFn completion_cb, + gpointer user_data) { SoupConnectionPrivate *priv; diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h index 19888f1f..00c030cf 100644 --- a/libsoup/soup-connection.h +++ b/libsoup/soup-connection.h @@ -71,10 +71,10 @@ void soup_connection_set_state (SoupConnection *conn, gboolean soup_connection_get_ever_used (SoupConnection *conn); -void soup_connection_send_request (SoupConnection *conn, - SoupMessageQueueItem *item, - SoupMessageCompletionFn completion_cb, - gpointer user_data); +void soup_connection_send_request (SoupConnection *conn, + SoupMessageQueueItem *item, + SoupMessageIOCompletionFn completion_cb, + gpointer user_data); G_END_DECLS diff --git a/libsoup/soup-form.c b/libsoup/soup-form.c index 32e7de3c..e73cca93 100644 --- a/libsoup/soup-form.c +++ b/libsoup/soup-form.c @@ -112,13 +112,13 @@ soup_form_decode (const char *encoded_form) /** * soup_form_decode_multipart: - * @msg: a #SoupMessage containing a "multipart/form-data" request body + * @multipart: a #SoupMultipart * @file_control_name: (allow-none): the name of the HTML file upload control, or %NULL * @filename: (out) (allow-none): return location for the name of the uploaded file, or %NULL * @content_type: (out) (allow-none): return location for the MIME type of the uploaded file, or %NULL * @file: (out) (allow-none): return location for the uploaded file data, or %NULL * - * Decodes the "multipart/form-data" request in @msg; this is a + * Decodes the "multipart/form-data" request in @multipart; this is a * convenience method for the case when you have a single file upload * control in a form. (Or when you don't have any file upload * controls, but are still using "multipart/form-data" anyway.) Pass @@ -142,29 +142,21 @@ soup_form_decode (const char *encoded_form) * a hash table containing the name/value pairs (other than * @file_control_name) from @msg, which you can free with * g_hash_table_destroy(). On error, it will return %NULL. - * - * Since: 2.26 - **/ + */ GHashTable * -soup_form_decode_multipart (SoupMessage *msg, const char *file_control_name, - char **filename, char **content_type, - GBytes **file) +soup_form_decode_multipart (SoupMultipart *multipart, + const char *file_control_name, + char **filename, + char **content_type, + GBytes **file) { - SoupMultipart *multipart; GHashTable *form_data_set, *params; SoupMessageHeaders *part_headers; - GBytes *body; GBytes *part_body; char *disposition, *name; int i; - g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL); - - body = soup_message_body_flatten (msg->request_body); - multipart = soup_multipart_new_from_message (msg->request_headers, body); - g_bytes_unref (body); - if (!multipart) - return NULL; + g_return_val_if_fail (multipart != NULL, NULL); if (filename) *filename = NULL; diff --git a/libsoup/soup-form.h b/libsoup/soup-form.h index 4880e7be..27ca8aa1 100644 --- a/libsoup/soup-form.h +++ b/libsoup/soup-form.h @@ -17,11 +17,11 @@ G_BEGIN_DECLS SOUP_AVAILABLE_IN_2_4 GHashTable *soup_form_decode (const char *encoded_form); SOUP_AVAILABLE_IN_2_26 -GHashTable *soup_form_decode_multipart (SoupMessage *msg, - const char *file_control_name, - char **filename, - char **content_type, - GBytes **file); +GHashTable *soup_form_decode_multipart (SoupMultipart *multipart, + const char *file_control_name, + char **filename, + char **content_type, + GBytes **file); SOUP_AVAILABLE_IN_2_4 char *soup_form_encode (const char *first_field, diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c index fbe1e986..5a54b012 100644 --- a/libsoup/soup-headers.c +++ b/libsoup/soup-headers.c @@ -195,7 +195,7 @@ soup_headers_parse_request (const char *str, unsigned long major_version, minor_version; char *p; - g_return_val_if_fail (str != NULL, SOUP_STATUS_MALFORMED); + g_return_val_if_fail (str != NULL, SOUP_STATUS_BAD_REQUEST); /* RFC 2616 4.1 "servers SHOULD ignore any empty line(s) * received where a Request-Line is expected." diff --git a/libsoup/soup-logger.c b/libsoup/soup-logger.c index d76701a2..402f4f57 100644 --- a/libsoup/soup-logger.c +++ b/libsoup/soup-logger.c @@ -597,22 +597,6 @@ print_request (SoupLogger *logger, SoupMessage *msg, "%s: %s", name, value); } } - if (log_level == SOUP_LOGGER_LOG_HEADERS) - return; - - if (msg->request_body->length && - soup_message_body_get_accumulate (msg->request_body)) { - GBytes *request; - - request = soup_message_body_flatten (msg->request_body); - g_return_if_fail (request != NULL); - g_bytes_unref (request); - - if (soup_message_headers_get_expectations (msg->request_headers) != SOUP_EXPECTATION_CONTINUE) { - soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '>', - "\n%s", msg->request_body->data); - } - } } static void @@ -653,13 +637,6 @@ print_response (SoupLogger *logger, SoupMessage *msg) soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, '<', "%s: %s", name, value); } - if (log_level == SOUP_LOGGER_LOG_HEADERS) - return; - - if (msg->response_body->data) { - soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '<', - "\n%s", msg->response_body->data); - } } static void @@ -688,23 +665,9 @@ got_informational (SoupMessage *msg, gpointer user_data) print_response (logger, msg); soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', "\n"); - if (msg->status_code == SOUP_STATUS_CONTINUE && msg->request_body->data) { - SoupLoggerLogLevel log_level; - + if (msg->status_code == SOUP_STATUS_CONTINUE && msg->request_body_stream) { soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>', "[Now sending request body...]"); - - if (priv->request_filter) { - log_level = priv->request_filter (logger, msg, - priv->request_filter_data); - } else - log_level = priv->level; - - if (log_level == SOUP_LOGGER_LOG_BODY) { - soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '>', - "%s", msg->request_body->data); - } - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', "\n"); } diff --git a/libsoup/soup-message-io-data.c b/libsoup/soup-message-io-data.c new file mode 100644 index 00000000..8af99467 --- /dev/null +++ b/libsoup/soup-message-io-data.c @@ -0,0 +1,266 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * soup-message-io-data.c: HTTP message I/O data + * + * Copyright (C) 2000-2003, Ximian, Inc. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib/gi18n-lib.h> + +#include "soup-message-io-data.h" +#include "soup-message-private.h" +#include "soup-server-message-private.h" +#include "soup.h" + +#define RESPONSE_BLOCK_SIZE 8192 +#define HEADER_SIZE_LIMIT (64 * 1024) + +void +soup_message_io_data_cleanup (SoupMessageIOData *io) +{ + if (io->io_source) { + g_source_destroy (io->io_source); + g_source_unref (io->io_source); + io->io_source = NULL; + } + + if (io->iostream) + g_object_unref (io->iostream); + if (io->body_istream) + g_object_unref (io->body_istream); + if (io->body_ostream) + g_object_unref (io->body_ostream); + if (io->async_context) + g_main_context_unref (io->async_context); + + g_byte_array_free (io->read_header_buf, TRUE); + + g_string_free (io->write_buf, TRUE); + + if (io->async_wait) { + g_cancellable_cancel (io->async_wait); + g_clear_object (&io->async_wait); + } + g_clear_error (&io->async_error); +} + +gboolean +soup_message_io_data_read_headers (SoupMessageIOData *io, + gboolean blocking, + GCancellable *cancellable, + GError **error) +{ + gssize nread, old_len; + gboolean got_lf; + + while (1) { + old_len = io->read_header_buf->len; + g_byte_array_set_size (io->read_header_buf, old_len + RESPONSE_BLOCK_SIZE); + nread = soup_filter_input_stream_read_line (io->istream, + io->read_header_buf->data + old_len, + RESPONSE_BLOCK_SIZE, + blocking, + &got_lf, + cancellable, error); + io->read_header_buf->len = old_len + MAX (nread, 0); + if (nread == 0) { + if (io->read_header_buf->len > 0) + break; + + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + _("Connection terminated unexpectedly")); + } + if (nread <= 0) + return FALSE; + + if (got_lf) { + if (nread == 1 && old_len >= 2 && + !strncmp ((char *)io->read_header_buf->data + + io->read_header_buf->len - 2, + "\n\n", 2)) { + io->read_header_buf->len--; + break; + } else if (nread == 2 && old_len >= 3 && + !strncmp ((char *)io->read_header_buf->data + + io->read_header_buf->len - 3, + "\n\r\n", 3)) { + io->read_header_buf->len -= 2; + break; + } + } + + if (io->read_header_buf->len > HEADER_SIZE_LIMIT) { + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + _("Header too big")); + return FALSE; + } + } + + io->read_header_buf->data[io->read_header_buf->len] = '\0'; + return TRUE; +} + +static gboolean +message_io_is_paused (GObject *msg) +{ + if (SOUP_IS_MESSAGE (msg)) + return soup_message_is_io_paused (SOUP_MESSAGE (msg)); + + if (SOUP_IS_SERVER_MESSAGE (msg)) + return soup_server_message_is_io_paused (SOUP_SERVER_MESSAGE (msg)); + + return FALSE; +} + +typedef struct { + GSource source; + GObject *msg; + gboolean paused; +} SoupMessageIOSource; + +static gboolean +message_io_source_check (GSource *source) +{ + SoupMessageIOSource *message_source = (SoupMessageIOSource *)source; + + if (message_source->paused) { + if (message_io_is_paused (message_source->msg)) + return FALSE; + return TRUE; + } else + return FALSE; +} + +static gboolean +message_io_source_prepare (GSource *source, + gint *timeout) +{ + *timeout = -1; + return message_io_source_check (source); +} + +static gboolean +message_io_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + SoupMessageIOSourceFunc func = (SoupMessageIOSourceFunc)callback; + SoupMessageIOSource *message_source = (SoupMessageIOSource *)source; + + return (*func) (message_source->msg, user_data); +} + +static void +message_io_source_finalize (GSource *source) +{ + SoupMessageIOSource *message_source = (SoupMessageIOSource *)source; + + g_object_unref (message_source->msg); +} + +static gboolean +message_io_source_closure_callback (GObject *msg, + gpointer data) +{ + GClosure *closure = data; + GValue param = G_VALUE_INIT; + GValue result_value = G_VALUE_INIT; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶m, G_TYPE_OBJECT); + g_value_set_object (¶m, msg); + + g_closure_invoke (closure, &result_value, 1, ¶m, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶m); + + return result; +} + +static GSourceFuncs message_io_source_funcs = +{ + message_io_source_prepare, + message_io_source_check, + message_io_source_dispatch, + message_io_source_finalize, + (GSourceFunc)message_io_source_closure_callback, + (GSourceDummyMarshal)g_cclosure_marshal_generic, +}; + +GSource * +soup_message_io_data_get_source (SoupMessageIOData *io, + GObject *msg, + GCancellable *cancellable, + SoupMessageIOSourceFunc callback, + gpointer user_data) +{ + GSource *base_source, *source; + SoupMessageIOSource *message_source; + + if (!io) { + base_source = g_timeout_source_new (0); + } else if (io->paused) { + base_source = NULL; + } else if (io->async_wait) { + base_source = g_cancellable_source_new (io->async_wait); + } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) { + GPollableInputStream *istream; + + if (io->body_istream) + istream = G_POLLABLE_INPUT_STREAM (io->body_istream); + else + istream = G_POLLABLE_INPUT_STREAM (io->istream); + base_source = g_pollable_input_stream_create_source (istream, cancellable); + } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) { + GPollableOutputStream *ostream; + + if (io->body_ostream) + ostream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream); + else + ostream = G_POLLABLE_OUTPUT_STREAM (io->ostream); + base_source = g_pollable_output_stream_create_source (ostream, cancellable); + } else + base_source = g_timeout_source_new (0); + + source = g_source_new (&message_io_source_funcs, sizeof (SoupMessageIOSource)); + g_source_set_name (source, "SoupMessageIOSource"); + message_source = (SoupMessageIOSource *)source; + message_source->msg = g_object_ref (msg); + message_source->paused = io && io->paused; + + if (base_source) { + g_source_set_dummy_callback (base_source); + g_source_add_child_source (source, base_source); + g_source_unref (base_source); + } + g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL); + return source; +} + +void +soup_message_io_data_pause (SoupMessageIOData *io) +{ + if (io->io_source) { + g_source_destroy (io->io_source); + g_source_unref (io->io_source); + io->io_source = NULL; + } + + io->paused = TRUE; +} + +void +soup_message_io_data_unpause (SoupMessageIOData *io) +{ + io->paused = FALSE; +} diff --git a/libsoup/soup-message-io-data.h b/libsoup/soup-message-io-data.h new file mode 100644 index 00000000..0476a425 --- /dev/null +++ b/libsoup/soup-message-io-data.h @@ -0,0 +1,99 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2000-2003, Ximian, Inc. + */ + +#ifndef __SOUP_MESSAGE_IO_DATA_H__ +#define __SOUP_MESSAGE_IO_DATA_H__ 1 + +#include "soup-filter-input-stream.h" +#include "soup-message-headers.h" + +typedef enum { + SOUP_MESSAGE_IO_STATE_NOT_STARTED, + SOUP_MESSAGE_IO_STATE_ANY = SOUP_MESSAGE_IO_STATE_NOT_STARTED, + SOUP_MESSAGE_IO_STATE_HEADERS, + SOUP_MESSAGE_IO_STATE_BLOCKING, + SOUP_MESSAGE_IO_STATE_BODY_START, + SOUP_MESSAGE_IO_STATE_BODY, + SOUP_MESSAGE_IO_STATE_BODY_DATA, + SOUP_MESSAGE_IO_STATE_BODY_FLUSH, + SOUP_MESSAGE_IO_STATE_BODY_DONE, + SOUP_MESSAGE_IO_STATE_FINISHING, + SOUP_MESSAGE_IO_STATE_DONE +} SoupMessageIOState; + +#define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \ + (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \ + state != SOUP_MESSAGE_IO_STATE_BLOCKING && \ + state != SOUP_MESSAGE_IO_STATE_DONE) +#define SOUP_MESSAGE_IO_STATE_POLLABLE(state) \ + (SOUP_MESSAGE_IO_STATE_ACTIVE (state) && \ + state != SOUP_MESSAGE_IO_STATE_BODY_DONE) + +typedef enum { + SOUP_MESSAGE_IO_COMPLETE, + SOUP_MESSAGE_IO_INTERRUPTED, + SOUP_MESSAGE_IO_STOLEN +} SoupMessageIOCompletion; + +typedef void (*SoupMessageIOCompletionFn) (GObject *msg, + SoupMessageIOCompletion completion, + gpointer user_data); + +typedef struct { + GIOStream *iostream; + SoupFilterInputStream *istream; + GInputStream *body_istream; + GOutputStream *ostream; + GOutputStream *body_ostream; + GMainContext *async_context; + + SoupMessageIOState read_state; + SoupEncoding read_encoding; + GByteArray *read_header_buf; + goffset read_length; + + SoupMessageIOState write_state; + SoupEncoding write_encoding; + GString *write_buf; + GBytes *write_chunk; + goffset write_body_offset; + goffset write_length; + goffset written; + + GSource *io_source; + gboolean paused; + + GCancellable *async_wait; + GError *async_error; + + SoupMessageIOCompletionFn completion_cb; + gpointer completion_data; + +#ifdef HAVE_SYSPROF + gint64 begin_time_nsec; +#endif +} SoupMessageIOData; + +void soup_message_io_data_cleanup (SoupMessageIOData *io); + +gboolean soup_message_io_data_read_headers (SoupMessageIOData *io, + gboolean blocking, + GCancellable *cancellable, + GError **error); + +typedef gboolean (*SoupMessageIOSourceFunc) (GObject *msg, + gpointer user_data); + +GSource *soup_message_io_data_get_source (SoupMessageIOData *io, + GObject *msg, + GCancellable *cancellable, + SoupMessageIOSourceFunc callback, + gpointer user_data); + +void soup_message_io_data_pause (SoupMessageIOData *io); +void soup_message_io_data_unpause (SoupMessageIOData *io); + + +#endif /* __SOUP_MESSAGE_IO_DATA_H__ */ diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c index bfa14417..efa84ef6 100644 --- a/libsoup/soup-message-io.c +++ b/libsoup/soup-message-io.c @@ -28,60 +28,37 @@ #include "soup-misc.h" #include "soup-socket-private.h" +struct _SoupClientMessageIOData { + SoupMessageIOData base; + + SoupMessageQueueItem *item; + GCancellable *cancellable; + +#ifdef HAVE_SYSPROF + gint64 begin_time_nsec; +#endif +}; + #define RESPONSE_BLOCK_SIZE 8192 #define HEADER_SIZE_LIMIT (64 * 1024) void -soup_message_io_cleanup (SoupMessage *msg) +soup_client_message_io_data_free (SoupClientMessageIOData *io) { - SoupMessageIOData *io; - - io = soup_message_get_io_data (msg); if (!io) return; - if (io->io_source) { - g_source_destroy (io->io_source); - g_source_unref (io->io_source); - io->io_source = NULL; - } - - if (io->unpause_source) { - g_source_destroy (io->unpause_source); - g_source_unref (io->unpause_source); - io->unpause_source = NULL; - } + soup_message_io_data_cleanup (&io->base); + soup_message_queue_item_unref (io->item); - if (io->iostream) - g_object_unref (io->iostream); - if (io->body_istream) - g_object_unref (io->body_istream); - if (io->body_ostream) - g_object_unref (io->body_ostream); - if (io->async_context) - g_main_context_unref (io->async_context); - if (io->item) - soup_message_queue_item_unref (io->item); - - g_byte_array_free (io->read_header_buf, TRUE); - - g_string_free (io->write_buf, TRUE); - g_clear_pointer (&io->write_chunk, g_bytes_unref); - - if (io->async_wait) { - g_cancellable_cancel (io->async_wait); - g_clear_object (&io->async_wait); - } - g_clear_error (&io->async_error); - - g_slice_free (SoupMessageIOData, io); + g_slice_free (SoupClientMessageIOData, io); } void soup_message_io_finished (SoupMessage *msg) { - SoupMessageIOData *io; - SoupMessageCompletionFn completion_cb; + SoupClientMessageIOData *io; + SoupMessageIOCompletionFn completion_cb; gpointer completion_data; SoupMessageIOCompletion completion; @@ -89,11 +66,11 @@ soup_message_io_finished (SoupMessage *msg) if (!io) return; - completion_cb = io->completion_cb; - completion_data = io->completion_data; + completion_cb = io->base.completion_cb; + completion_data = io->base.completion_data; - if ((io->read_state >= SOUP_MESSAGE_IO_STATE_FINISHING && - io->write_state >= SOUP_MESSAGE_IO_STATE_FINISHING)) + if ((io->base.read_state >= SOUP_MESSAGE_IO_STATE_FINISHING && + io->base.write_state >= SOUP_MESSAGE_IO_STATE_FINISHING)) completion = SOUP_MESSAGE_IO_COMPLETE; else completion = SOUP_MESSAGE_IO_INTERRUPTED; @@ -101,96 +78,35 @@ soup_message_io_finished (SoupMessage *msg) g_object_ref (msg); soup_message_set_io_data (msg, NULL); if (completion_cb) - completion_cb (msg, completion, completion_data); + completion_cb (G_OBJECT (msg), completion, completion_data); g_object_unref (msg); } GIOStream * soup_message_io_steal (SoupMessage *msg) { - SoupMessageIOData *io; - SoupMessageCompletionFn completion_cb; + SoupClientMessageIOData *io; + SoupMessageIOCompletionFn completion_cb; gpointer completion_data; GIOStream *iostream; io = soup_message_get_io_data (msg); - if (!io || !io->iostream) + if (!io || !io->base.iostream) return NULL; - iostream = g_object_ref (io->iostream); - completion_cb = io->completion_cb; - completion_data = io->completion_data; + iostream = g_object_ref (io->base.iostream); + completion_cb = io->base.completion_cb; + completion_data = io->base.completion_data; g_object_ref (msg); soup_message_set_io_data (msg, NULL); if (completion_cb) - completion_cb (msg, SOUP_MESSAGE_IO_STOLEN, completion_data); + completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data); g_object_unref (msg); return iostream; } -gboolean -soup_message_io_read_headers (SoupMessage *msg, - SoupFilterInputStream *stream, - GByteArray *buffer, - gboolean blocking, - GCancellable *cancellable, - GError **error) -{ - gssize nread, old_len; - gboolean got_lf; - - while (1) { - old_len = buffer->len; - g_byte_array_set_size (buffer, old_len + RESPONSE_BLOCK_SIZE); - nread = soup_filter_input_stream_read_line (stream, - buffer->data + old_len, - RESPONSE_BLOCK_SIZE, - blocking, - &got_lf, - cancellable, error); - buffer->len = old_len + MAX (nread, 0); - if (nread == 0) { - if (buffer->len > 0) - break; - soup_message_set_status (msg, SOUP_STATUS_MALFORMED); - g_set_error_literal (error, G_IO_ERROR, - G_IO_ERROR_PARTIAL_INPUT, - _("Connection terminated unexpectedly")); - } - if (nread <= 0) - return FALSE; - - if (got_lf) { - if (nread == 1 && old_len >= 2 && - !strncmp ((char *)buffer->data + - buffer->len - 2, - "\n\n", 2)) { - buffer->len--; - break; - } else if (nread == 2 && old_len >= 3 && - !strncmp ((char *)buffer->data + - buffer->len - 3, - "\n\r\n", 3)) { - buffer->len -= 2; - break; - } - } - - if (buffer->len > HEADER_SIZE_LIMIT) { - soup_message_set_status (msg, SOUP_STATUS_MALFORMED); - g_set_error_literal (error, G_IO_ERROR, - G_IO_ERROR_PARTIAL_INPUT, - _("Header too big")); - return FALSE; - } - } - - buffer->data[buffer->len] = '\0'; - return TRUE; -} - static gint processing_stage_cmp (gconstpointer a, gconstpointer b) @@ -257,7 +173,7 @@ request_body_stream_wrote_cb (GOutputStream *ostream, GAsyncResult *result, SoupMessage *msg) { - SoupMessageIOData *io; + SoupClientMessageIOData *io; gssize nwrote; GCancellable *async_wait; GError *error = NULL; @@ -265,19 +181,19 @@ request_body_stream_wrote_cb (GOutputStream *ostream, nwrote = g_output_stream_splice_finish (ostream, result, &error); io = soup_message_get_io_data (msg); - if (!io || !io->async_wait || io->body_ostream != ostream) { + if (!io || !io->base.async_wait || io->base.body_ostream != ostream) { g_clear_error (&error); g_object_unref (msg); return; } if (nwrote != -1) - io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; + io->base.write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; if (error) - g_propagate_error (&io->async_error, error); - async_wait = io->async_wait; - io->async_wait = NULL; + g_propagate_error (&io->base.async_error, error); + async_wait = io->base.async_wait; + io->base.async_wait = NULL; g_cancellable_cancel (async_wait); g_object_unref (async_wait); @@ -291,20 +207,20 @@ closed_async (GObject *source, { GOutputStream *body_ostream = G_OUTPUT_STREAM (source); SoupMessage *msg = user_data; - SoupMessageIOData *io; + SoupClientMessageIOData *io; GCancellable *async_wait; io = soup_message_get_io_data (msg); - if (!io || !io->async_wait || io->body_ostream != body_ostream) { + if (!io || !io->base.async_wait || io->base.body_ostream != body_ostream) { g_object_unref (msg); return; } - g_output_stream_close_finish (body_ostream, result, &io->async_error); - g_clear_object (&io->body_ostream); + g_output_stream_close_finish (body_ostream, result, &io->base.async_error); + g_clear_object (&io->base.body_ostream); - async_wait = io->async_wait; - io->async_wait = NULL; + async_wait = io->base.async_wait; + io->base.async_wait = NULL; g_cancellable_cancel (async_wait); g_object_unref (async_wait); @@ -393,15 +309,6 @@ write_headers (SoupMessage *msg, g_free (uri_host); *encoding = soup_message_headers_get_encoding (msg->request_headers); - if ((*encoding == SOUP_ENCODING_CONTENT_LENGTH || - *encoding == SOUP_ENCODING_NONE) && - (msg->request_body->length > 0 || - soup_message_headers_get_one (msg->request_headers, "Content-Type")) && - !soup_message_headers_get_content_length (msg->request_headers)) { - *encoding = SOUP_ENCODING_CONTENT_LENGTH; - soup_message_headers_set_content_length (msg->request_headers, - msg->request_body->length); - } soup_message_headers_iter_init (&iter, msg->request_headers); while (soup_message_headers_iter_next (&iter, &name, &value)) @@ -419,7 +326,8 @@ static gboolean io_write (SoupMessage *msg, gboolean blocking, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + SoupMessageIOData *io = &client_io->base; gssize nwrote; if (io->async_error) { @@ -436,7 +344,7 @@ io_write (SoupMessage *msg, gboolean blocking, switch (io->write_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: if (!io->write_buf->len) - write_headers (msg, io->write_buf, io->item->conn, &io->write_encoding); + write_headers (msg, io->write_buf, client_io->item->conn, &io->write_encoding); while (io->written < io->write_buf->len) { nwrote = g_pollable_stream_write (io->ostream, @@ -607,13 +515,17 @@ static gboolean io_read (SoupMessage *msg, gboolean blocking, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + SoupMessageIOData *io = &client_io->base; guint status; switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: - if (!soup_message_io_read_headers (msg, io->istream, io->read_header_buf, blocking, cancellable, error)) + if (!soup_message_io_data_read_headers (io, blocking, cancellable, error)) { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT)) + soup_message_set_status (msg, SOUP_STATUS_MALFORMED); return FALSE; + } status = parse_headers (msg, (char *)io->read_header_buf->data, @@ -658,7 +570,7 @@ io_read (SoupMessage *msg, gboolean blocking, /* If this was "101 Switching Protocols", then * the session may have stolen the connection... */ - if (io != soup_message_get_io_data (msg)) + if (client_io != soup_message_get_io_data (msg)) return FALSE; soup_message_cleanup_response (msg); @@ -698,7 +610,7 @@ io_read (SoupMessage *msg, gboolean blocking, io->read_length); io->body_istream = soup_message_setup_body_istream (body_istream, msg, - io->item->session, + client_io->item->session, SOUP_STAGE_MESSAGE_BODY); g_object_unref (body_istream); } @@ -753,148 +665,18 @@ io_read (SoupMessage *msg, gboolean blocking, return TRUE; } -typedef struct { - GSource source; - SoupMessage *msg; - gboolean paused; -} SoupMessageSource; - -static gboolean -message_source_check (GSource *source) -{ - SoupMessageSource *message_source = (SoupMessageSource *)source; - - if (message_source->paused) { - SoupMessageIOData *io = soup_message_get_io_data (message_source->msg); - - if (io && io->paused) - return FALSE; - else - return TRUE; - } else - return FALSE; -} - -static gboolean -message_source_prepare (GSource *source, - gint *timeout) -{ - *timeout = -1; - return message_source_check (source); -} - -static gboolean -message_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - SoupMessageSourceFunc func = (SoupMessageSourceFunc)callback; - SoupMessageSource *message_source = (SoupMessageSource *)source; - - return (*func) (message_source->msg, user_data); -} - -static void -message_source_finalize (GSource *source) -{ - SoupMessageSource *message_source = (SoupMessageSource *)source; - - g_object_unref (message_source->msg); -} - -static gboolean -message_source_closure_callback (SoupMessage *msg, - gpointer data) -{ - GClosure *closure = data; - GValue param = G_VALUE_INIT; - GValue result_value = G_VALUE_INIT; - gboolean result; - - g_value_init (&result_value, G_TYPE_BOOLEAN); - - g_value_init (¶m, SOUP_TYPE_MESSAGE); - g_value_set_object (¶m, msg); - - g_closure_invoke (closure, &result_value, 1, ¶m, NULL); - - result = g_value_get_boolean (&result_value); - g_value_unset (&result_value); - g_value_unset (¶m); - - return result; -} - -static GSourceFuncs message_source_funcs = -{ - message_source_prepare, - message_source_check, - message_source_dispatch, - message_source_finalize, - (GSourceFunc)message_source_closure_callback, - (GSourceDummyMarshal)g_cclosure_marshal_generic, -}; - -GSource * -soup_message_io_get_source (SoupMessage *msg, GCancellable *cancellable, - SoupMessageSourceFunc callback, gpointer user_data) -{ - SoupMessageIOData *io = soup_message_get_io_data (msg); - GSource *base_source, *source; - SoupMessageSource *message_source; - - if (!io) { - base_source = g_timeout_source_new (0); - } else if (io->paused) { - base_source = NULL; - } else if (io->async_wait) { - base_source = g_cancellable_source_new (io->async_wait); - } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) { - GPollableInputStream *istream; - - if (io->body_istream) - istream = G_POLLABLE_INPUT_STREAM (io->body_istream); - else - istream = G_POLLABLE_INPUT_STREAM (io->istream); - base_source = g_pollable_input_stream_create_source (istream, cancellable); - } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) { - GPollableOutputStream *ostream; - - if (io->body_ostream) - ostream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream); - else - ostream = G_POLLABLE_OUTPUT_STREAM (io->ostream); - base_source = g_pollable_output_stream_create_source (ostream, cancellable); - } else - base_source = g_timeout_source_new (0); - - source = g_source_new (&message_source_funcs, - sizeof (SoupMessageSource)); - g_source_set_name (source, "SoupMessageSource"); - message_source = (SoupMessageSource *)source; - message_source->msg = g_object_ref (msg); - message_source->paused = io && io->paused; - - if (base_source) { - g_source_set_dummy_callback (base_source); - g_source_add_child_source (source, base_source); - g_source_unref (base_source); - } - g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL); - return source; -} - static gboolean request_is_restartable (SoupMessage *msg, GError *error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + SoupMessageIOData *io = &client_io->base; - if (!io) + if (!client_io) return FALSE; return (io->read_state <= SOUP_MESSAGE_IO_STATE_HEADERS && io->read_header_buf->len == 0 && - soup_connection_get_ever_used (io->item->conn) && + soup_connection_get_ever_used (client_io->item->conn) && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) && error->domain != G_TLS_ERROR && @@ -906,7 +688,8 @@ io_run_until (SoupMessage *msg, gboolean blocking, SoupMessageIOState read_state, SoupMessageIOState write_state, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + SoupMessageIOData *io = &client_io->base; gboolean progress = TRUE, done; GError *my_error = NULL; @@ -921,7 +704,7 @@ io_run_until (SoupMessage *msg, gboolean blocking, g_object_ref (msg); - while (progress && soup_message_get_io_data (msg) == io && !io->paused && !io->async_wait && + while (progress && soup_message_get_io_data (msg) == client_io && !io->paused && !io->async_wait && (io->read_state < read_state || io->write_state < write_state)) { if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state)) @@ -945,7 +728,7 @@ io_run_until (SoupMessage *msg, gboolean blocking, g_propagate_error (error, my_error); g_object_unref (msg); return FALSE; - } else if (soup_message_get_io_data (msg) != io) { + } else if (soup_message_get_io_data (msg) != client_io) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled")); @@ -979,7 +762,8 @@ io_run_until (SoupMessage *msg, gboolean blocking, /* FIXME: Expand and generalise sysprof support: * https://gitlab.gnome.org/GNOME/sysprof/-/issues/43 */ - sysprof_collector_mark_printf (io->begin_time_nsec, SYSPROF_CAPTURE_CURRENT_TIME - io->begin_time_nsec, + sysprof_collector_mark_printf (client_io->begin_time_nsec, + SYSPROF_CAPTURE_CURRENT_TIME - client_io->begin_time_nsec, "libsoup", "message", "%s request/response to %s: " "read %" G_GOFFSET_FORMAT "B, " @@ -1003,7 +787,7 @@ soup_message_io_update_status (SoupMessage *msg, GError *error) { if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); io->item->state = SOUP_MESSAGE_RESTARTING; } else if (error->domain == G_TLS_ERROR) { @@ -1029,7 +813,8 @@ void soup_message_io_run (SoupMessage *msg, gboolean blocking) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + SoupMessageIOData *io = &client_io->base; GError *error = NULL; GCancellable *cancellable; @@ -1040,7 +825,7 @@ soup_message_io_run (SoupMessage *msg, } g_object_ref (msg); - cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL; + cancellable = client_io->cancellable ? g_object_ref (client_io->cancellable) : NULL; if (io_run_until (msg, blocking, SOUP_MESSAGE_IO_STATE_DONE, @@ -1049,10 +834,12 @@ soup_message_io_run (SoupMessage *msg, soup_message_io_finished (msg); } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_clear_error (&error); - io->io_source = soup_message_io_get_source (msg, NULL, io_run_ready, msg); + io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL, + (SoupMessageIOSourceFunc)io_run_ready, + NULL); g_source_attach (io->io_source, io->async_context); } else { - if (soup_message_get_io_data (msg) == io) + if (soup_message_get_io_data (msg) == client_io) soup_message_io_update_status (msg, error); g_error_free (error); @@ -1067,7 +854,7 @@ soup_message_io_run_until_read (SoupMessage *msg, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); if (io_run_until (msg, TRUE, SOUP_MESSAGE_IO_STATE_BODY, @@ -1098,7 +885,8 @@ static void io_run_until_read_async (SoupMessage *msg, GTask *task) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *client_io = soup_message_get_io_data (msg); + SoupMessageIOData *io = &client_io->base; GError *error = NULL; if (io->io_source) { @@ -1119,12 +907,14 @@ io_run_until_read_async (SoupMessage *msg, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_error_free (error); - io->io_source = soup_message_io_get_source (msg, NULL, io_run_until_read_ready, task); + io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL, + (SoupMessageIOSourceFunc)io_run_until_read_ready, + task); g_source_attach (io->io_source, io->async_context); return; } - if (soup_message_get_io_data (msg) == io) + if (soup_message_get_io_data (msg) == client_io) soup_message_io_update_status (msg, error); g_task_return_error (task, error); @@ -1157,14 +947,14 @@ soup_message_io_run_until_finish (SoupMessage *msg, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); gboolean success; g_object_ref (msg); if (io) { - if (io->read_state < SOUP_MESSAGE_IO_STATE_BODY_DONE) - io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; + if (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY_DONE) + io->base.read_state = SOUP_MESSAGE_IO_STATE_FINISHING; } success = io_run_until (msg, blocking, @@ -1180,17 +970,17 @@ static void client_stream_eof (SoupClientInputStream *stream, gpointer user_data) { SoupMessage *msg = user_data; - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); - if (io && io->read_state == SOUP_MESSAGE_IO_STATE_BODY) - io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE; + if (io && io->base.read_state == SOUP_MESSAGE_IO_STATE_BODY) + io->base.read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE; } GInputStream * soup_message_io_get_response_istream (SoupMessage *msg, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); GInputStream *client_stream; if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) { @@ -1199,7 +989,7 @@ soup_message_io_get_response_istream (SoupMessage *msg, return NULL; } - client_stream = soup_client_input_stream_new (io->body_istream, msg); + client_stream = soup_client_input_stream_new (io->base.body_istream, msg); g_signal_connect (client_stream, "eof", G_CALLBACK (client_stream_eof), msg); @@ -1208,28 +998,28 @@ soup_message_io_get_response_istream (SoupMessage *msg, void soup_message_send_request (SoupMessageQueueItem *item, - SoupMessageCompletionFn completion_cb, + SoupMessageIOCompletionFn completion_cb, gpointer user_data) { - SoupMessageIOData *io; + SoupClientMessageIOData *io; - io = g_slice_new0 (SoupMessageIOData); - io->completion_cb = completion_cb; - io->completion_data = user_data; + io = g_slice_new0 (SoupClientMessageIOData); + io->base.completion_cb = completion_cb; + io->base.completion_data = user_data; io->item = item; soup_message_queue_item_ref (item); io->cancellable = io->item->cancellable; - io->iostream = g_object_ref (soup_socket_get_iostream (soup_connection_get_socket (io->item->conn))); - io->istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->iostream)); - io->ostream = g_io_stream_get_output_stream (io->iostream); - io->async_context = g_main_context_ref_thread_default (); + io->base.iostream = g_object_ref (soup_socket_get_iostream (soup_connection_get_socket (io->item->conn))); + io->base.istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->base.iostream)); + io->base.ostream = g_io_stream_get_output_stream (io->base.iostream); + io->base.async_context = g_main_context_ref_thread_default (); - io->read_header_buf = g_byte_array_new (); - io->write_buf = g_string_new (NULL); + io->base.read_header_buf = g_byte_array_new (); + io->base.write_buf = g_string_new (NULL); - io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; - io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; + io->base.read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; + io->base.write_state = SOUP_MESSAGE_IO_STATE_HEADERS; #ifdef HAVE_SYSPROF io->begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME; @@ -1238,65 +1028,25 @@ soup_message_send_request (SoupMessageQueueItem *item, soup_message_set_io_data (io->item->msg, io); } -void +void soup_message_io_pause (SoupMessage *msg) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); g_return_if_fail (io != NULL); + g_return_if_fail (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY); - if (io->item) - g_return_if_fail (io->read_state < SOUP_MESSAGE_IO_STATE_BODY); - - if (io->io_source) { - g_source_destroy (io->io_source); - g_source_unref (io->io_source); - io->io_source = NULL; - } - - if (io->unpause_source) { - g_source_destroy (io->unpause_source); - g_source_unref (io->unpause_source); - io->unpause_source = NULL; - } - - io->paused = TRUE; -} - -static gboolean -io_unpause_internal (gpointer msg) -{ - SoupMessageIOData *io = soup_message_get_io_data (msg); - - g_return_val_if_fail (io != NULL, FALSE); - - g_clear_pointer (&io->unpause_source, g_source_unref); - io->paused = FALSE; - - if (io->io_source) - return FALSE; - - soup_message_io_run (msg, FALSE); - return FALSE; + soup_message_io_data_pause (&io->base); } void soup_message_io_unpause (SoupMessage *msg) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupClientMessageIOData *io = soup_message_get_io_data (msg); g_return_if_fail (io != NULL); - - if (io->item) { - g_return_if_fail (io->read_state < SOUP_MESSAGE_IO_STATE_BODY); - io->paused = FALSE; - return; - } - - if (!io->unpause_source) { - io->unpause_source = soup_add_completion_reffed (io->async_context, - io_unpause_internal, msg, NULL); - } + g_return_if_fail (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY); + io->base.paused = FALSE; } /** @@ -1312,3 +1062,11 @@ soup_message_io_in_progress (SoupMessage *msg) { return soup_message_get_io_data (msg) != NULL; } + +gboolean +soup_message_is_io_paused (SoupMessage *msg) +{ + SoupClientMessageIOData *io = soup_message_get_io_data (msg); + + return io && io->base.paused; +} diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h index 1200adba..0ce07e8f 100644 --- a/libsoup/soup-message-private.h +++ b/libsoup/soup-message-private.h @@ -8,13 +8,17 @@ #include "soup-filter-input-stream.h" #include "soup-message.h" +#include "soup-message-io-data.h" #include "auth/soup-auth.h" #include "content-sniffer/soup-content-processor.h" #include "content-sniffer/soup-content-sniffer.h" #include "soup-session.h" +typedef struct _SoupClientMessageIOData SoupClientMessageIOData; +void soup_client_message_io_data_free (SoupClientMessageIOData *io); + typedef struct { - gpointer io_data; + SoupClientMessageIOData *io_data; guint msg_flags; gboolean server_side; @@ -46,12 +50,6 @@ typedef struct { void soup_message_cleanup_response (SoupMessage *msg); -typedef enum { - SOUP_MESSAGE_IO_COMPLETE, - SOUP_MESSAGE_IO_INTERRUPTED, - SOUP_MESSAGE_IO_STOLEN -} SoupMessageIOCompletion; - typedef void (*SoupMessageGetHeadersFn) (SoupMessage *msg, GString *headers, SoupEncoding *encoding, @@ -62,17 +60,9 @@ typedef guint (*SoupMessageParseHeadersFn)(SoupMessage *msg, SoupEncoding *encoding, gpointer user_data, GError **error); -typedef void (*SoupMessageCompletionFn) (SoupMessage *msg, - SoupMessageIOCompletion completion, - gpointer user_data); - void soup_message_send_request (SoupMessageQueueItem *item, - SoupMessageCompletionFn completion_cb, - gpointer user_data); -void soup_message_read_request (SoupMessage *msg, - SoupSocket *sock, - SoupMessageCompletionFn completion_cb, + SoupMessageIOCompletionFn completion_cb, gpointer user_data); /* Auth handling */ @@ -84,77 +74,13 @@ void soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *soup_message_get_proxy_auth (SoupMessage *msg); /* I/O */ -typedef enum { - SOUP_MESSAGE_IO_STATE_NOT_STARTED, - SOUP_MESSAGE_IO_STATE_ANY = SOUP_MESSAGE_IO_STATE_NOT_STARTED, - SOUP_MESSAGE_IO_STATE_HEADERS, - SOUP_MESSAGE_IO_STATE_BLOCKING, - SOUP_MESSAGE_IO_STATE_BODY_START, - SOUP_MESSAGE_IO_STATE_BODY, - SOUP_MESSAGE_IO_STATE_BODY_DATA, - SOUP_MESSAGE_IO_STATE_BODY_FLUSH, - SOUP_MESSAGE_IO_STATE_BODY_DONE, - SOUP_MESSAGE_IO_STATE_FINISHING, - SOUP_MESSAGE_IO_STATE_DONE -} SoupMessageIOState; - -#define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \ - (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \ - state != SOUP_MESSAGE_IO_STATE_BLOCKING && \ - state != SOUP_MESSAGE_IO_STATE_DONE) -#define SOUP_MESSAGE_IO_STATE_POLLABLE(state) \ - (SOUP_MESSAGE_IO_STATE_ACTIVE (state) && \ - state != SOUP_MESSAGE_IO_STATE_BODY_DONE) - -typedef struct { - /* Client only */ - SoupMessageQueueItem *item; - GCancellable *cancellable; - - /* Server only */ - SoupSocket *sock; - - GIOStream *iostream; - SoupFilterInputStream *istream; - GInputStream *body_istream; - GOutputStream *ostream; - GOutputStream *body_ostream; - GMainContext *async_context; - - SoupMessageIOState read_state; - SoupEncoding read_encoding; - GByteArray *read_header_buf; - goffset read_length; - - SoupMessageIOState write_state; - SoupEncoding write_encoding; - GString *write_buf; - GBytes *write_chunk; - goffset write_body_offset; - goffset write_length; - goffset written; - - GSource *io_source; - GSource *unpause_source; - gboolean paused; - - GCancellable *async_wait; - GError *async_error; - - SoupMessageCompletionFn completion_cb; - gpointer completion_data; - -#ifdef HAVE_SYSPROF - gint64 begin_time_nsec; -#endif -} SoupMessageIOData; - void soup_message_io_run (SoupMessage *msg, gboolean blocking); void soup_message_io_finished (SoupMessage *msg); void soup_message_io_cleanup (SoupMessage *msg); void soup_message_io_pause (SoupMessage *msg); void soup_message_io_unpause (SoupMessage *msg); +gboolean soup_message_is_io_paused (SoupMessage *msg); gboolean soup_message_io_in_progress (SoupMessage *msg); GIOStream *soup_message_io_steal (SoupMessage *msg); @@ -214,9 +140,9 @@ SoupConnection *soup_message_get_connection (SoupMessage *msg); void soup_message_set_connection (SoupMessage *msg, SoupConnection *conn); -gpointer soup_message_get_io_data (SoupMessage *msg); -void soup_message_set_io_data (SoupMessage *msg, - gpointer io); +SoupClientMessageIOData *soup_message_get_io_data (SoupMessage *msg); +void soup_message_set_io_data (SoupMessage *msg, + SoupClientMessageIOData *io); SoupContentSniffer *soup_message_get_content_sniffer (SoupMessage *msg); void soup_message_set_content_sniffer (SoupMessage *msg, @@ -224,7 +150,4 @@ void soup_message_set_content_sniffer (SoupMessage *msg void soup_message_set_bytes_for_sniffing (SoupMessage *msg, gsize bytes); -const char *soup_http_version_to_string (SoupHTTPVersion version); - - #endif /* __SOUP_MESSAGE_PRIVATE_H__ */ diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c index 5ead16d9..0a265dea 100644 --- a/libsoup/soup-message.c +++ b/libsoup/soup-message.c @@ -19,13 +19,13 @@ /** * SECTION:soup-message * @short_description: An HTTP request and response. - * @see_also: #SoupMessageHeaders, #SoupMessageBody + * @see_also: #SoupMessageHeaders * * A #SoupMessage represents an HTTP message that is being sent or * received. * - * For client-side usage, you would create a #SoupMessage with - * soup_message_new() or soup_message_new_from_uri(), set up its + * You would create a #SoupMessage with soup_message_new() or + * soup_message_new_from_uri(), set up its * fields appropriately, and send it. If you are using the newer * #SoupRequest API, you would create a request with * soup_session_request_http() or soup_session_request_http_uri(), and @@ -33,10 +33,6 @@ * #SoupMessage that you can retrieve via * soup_request_http_get_message(). * - * For server-side usage, #SoupServer will create #SoupMessage<!-- - * -->s automatically for incoming requests, which your application - * will receive via handlers. - * * Note that libsoup's terminology here does not quite match the HTTP * specification: in RFC 2616, an "HTTP-message" is * <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a @@ -49,9 +45,7 @@ * @method: the HTTP method * @status_code: the HTTP status code * @reason_phrase: the status phrase associated with @status_code - * @request_body: the request body * @request_headers: the request headers - * @response_body: the response body * @response_headers: the response headers * * Represents an HTTP message being sent or received. @@ -66,48 +60,17 @@ * messages. Rather, you should look at @status_code, and determine an * end-user-appropriate message based on that and on what you were * trying to do. - * - * As described in the #SoupMessageBody documentation, the - * @request_body and @response_body <literal>data</literal> fields - * will not necessarily be filled in at all times. When the body - * fields are filled in, they will be terminated with a '\0' byte - * (which is not included in the <literal>length</literal>), so you - * can use them as ordinary C strings (assuming that you know that the - * body doesn't have any other '\0' bytes). - * - * For a client-side #SoupMessage, @request_body's - * <literal>data</literal> is usually filled in right before libsoup - * writes the request to the network, but you should not count on - * this; use soup_message_body_flatten() if you want to ensure that - * <literal>data</literal> is filled in. If you are not using - * #SoupRequest to read the response, then @response_body's - * <literal>data</literal> will be filled in before - * #SoupMessage::finished is emitted. (If you are using #SoupRequest, - * then the message body is not accumulated by default, so - * @response_body's <literal>data</literal> will always be %NULL.) - * - * For a server-side #SoupMessage, @request_body's %data will be - * filled in before #SoupMessage::got_body is emitted. - * - * To prevent the %data field from being filled in at all (eg, if you - * are handling the data from a #SoupMessage::got_chunk, and so don't - * need to see it all at the end), call - * soup_message_body_set_accumulate() on @response_body or - * @request_body as appropriate, passing %FALSE. - **/ + */ G_DEFINE_TYPE_WITH_PRIVATE (SoupMessage, soup_message, G_TYPE_OBJECT) enum { - WROTE_INFORMATIONAL, WROTE_HEADERS, - WROTE_CHUNK, WROTE_BODY_DATA, WROTE_BODY, GOT_INFORMATIONAL, GOT_HEADERS, - GOT_CHUNK, GOT_BODY, CONTENT_SNIFFED, @@ -129,15 +92,10 @@ enum { PROP_URI, PROP_HTTP_VERSION, PROP_FLAGS, - PROP_SERVER_SIDE, PROP_STATUS_CODE, PROP_REASON_PHRASE, PROP_FIRST_PARTY, - PROP_REQUEST_BODY, - PROP_REQUEST_BODY_DATA, PROP_REQUEST_HEADERS, - PROP_RESPONSE_BODY, - PROP_RESPONSE_BODY_DATA, PROP_RESPONSE_HEADERS, PROP_TLS_CERTIFICATE, PROP_TLS_ERRORS, @@ -156,9 +114,7 @@ soup_message_init (SoupMessage *msg) priv->http_version = priv->orig_http_version = SOUP_HTTP_1_1; priv->priority = SOUP_MESSAGE_PRIORITY_NORMAL; - msg->request_body = soup_message_body_new (); msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); - msg->response_body = soup_message_body_new (); msg->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE); } @@ -168,7 +124,7 @@ soup_message_finalize (GObject *object) SoupMessage *msg = SOUP_MESSAGE (object); SoupMessagePrivate *priv = soup_message_get_instance_private (msg); - soup_message_io_cleanup (msg); + soup_client_message_io_data_free (priv->io_data); g_clear_pointer (&priv->uri, soup_uri_free); g_clear_pointer (&priv->first_party, soup_uri_free); @@ -181,11 +137,9 @@ soup_message_finalize (GObject *object) g_clear_object (&priv->tls_certificate); - soup_message_body_free (msg->request_body); soup_message_headers_free (msg->request_headers); - g_clear_object (&msg->request_body_stream); - soup_message_body_free (msg->response_body); soup_message_headers_free (msg->response_headers); + g_clear_object (&msg->request_body_stream); g_free (msg->reason_phrase); @@ -218,13 +172,6 @@ soup_message_set_property (GObject *object, guint prop_id, case PROP_FLAGS: soup_message_set_flags (msg, g_value_get_flags (value)); break; - case PROP_SERVER_SIDE: - priv->server_side = g_value_get_boolean (value); - if (priv->server_side) { - soup_message_headers_set_encoding (msg->response_headers, - SOUP_ENCODING_CONTENT_LENGTH); - } - break; case PROP_STATUS_CODE: soup_message_set_status (msg, g_value_get_uint (value)); break; @@ -266,7 +213,6 @@ soup_message_get_property (GObject *object, guint prop_id, { SoupMessage *msg = SOUP_MESSAGE (object); SoupMessagePrivate *priv = soup_message_get_instance_private (msg); - GBytes *buf; switch (prop_id) { case PROP_METHOD: @@ -287,9 +233,6 @@ soup_message_get_property (GObject *object, guint prop_id, case PROP_FLAGS: g_value_set_flags (value, priv->msg_flags); break; - case PROP_SERVER_SIDE: - g_value_set_boolean (value, priv->server_side); - break; case PROP_STATUS_CODE: g_value_set_uint (value, msg->status_code); break; @@ -299,23 +242,9 @@ soup_message_get_property (GObject *object, guint prop_id, case PROP_FIRST_PARTY: g_value_set_boxed (value, priv->first_party); break; - case PROP_REQUEST_BODY: - g_value_set_boxed (value, msg->request_body); - break; - case PROP_REQUEST_BODY_DATA: - buf = soup_message_body_flatten (msg->request_body); - g_value_take_boxed (value, buf); - break; case PROP_REQUEST_HEADERS: g_value_set_boxed (value, msg->request_headers); break; - case PROP_RESPONSE_BODY: - g_value_set_boxed (value, msg->response_body); - break; - case PROP_RESPONSE_BODY_DATA: - buf = soup_message_body_flatten (msg->response_body); - g_value_take_boxed (value, buf); - break; case PROP_RESPONSE_HEADERS: g_value_set_boxed (value, msg->response_headers); break; @@ -335,26 +264,10 @@ soup_message_get_property (GObject *object, guint prop_id, } static void -soup_message_real_got_body (SoupMessage *msg) -{ - SoupMessagePrivate *priv = soup_message_get_instance_private (msg); - SoupMessageBody *body; - - body = priv->server_side ? msg->request_body : msg->response_body; - if (soup_message_body_get_accumulate (body)) { - GBytes *buffer = soup_message_body_flatten (body); - g_bytes_unref (buffer); - } -} - -static void soup_message_class_init (SoupMessageClass *message_class) { GObjectClass *object_class = G_OBJECT_CLASS (message_class); - /* virtual method definition */ - message_class->got_body = soup_message_real_got_body; - /* virtual method override */ object_class->finalize = soup_message_finalize; object_class->set_property = soup_message_set_property; @@ -363,29 +276,11 @@ soup_message_class_init (SoupMessageClass *message_class) /* signals */ /** - * SoupMessage::wrote-informational: - * @msg: the message - * - * Emitted immediately after writing a 1xx (Informational) - * response for a (server-side) message. - **/ - signals[WROTE_INFORMATIONAL] = - g_signal_new ("wrote_informational", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SoupMessageClass, wrote_informational), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); - - /** * SoupMessage::wrote-headers: * @msg: the message * - * Emitted immediately after writing the headers for a - * message. (For a client-side message, this is after writing - * the request headers; for a server-side message, it is after - * writing the response headers.) + * Emitted immediately after writing the request headers for a + * message. **/ signals[WROTE_HEADERS] = g_signal_new ("wrote_headers", @@ -397,28 +292,6 @@ soup_message_class_init (SoupMessageClass *message_class) G_TYPE_NONE, 0); /** - * SoupMessage::wrote-chunk: - * @msg: the message - * - * Emitted immediately after writing a body chunk for a message. - * - * Note that this signal is not parallel to - * #SoupMessage::got_chunk; it is emitted only when a complete - * chunk (added with soup_message_body_append() or - * soup_message_body_append_bytes()) has been written. To get - * more useful continuous progress information, use - * #SoupMessage::wrote_body_data. - **/ - signals[WROTE_CHUNK] = - g_signal_new ("wrote_chunk", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); - - /** * SoupMessage::wrote-body-data: * @msg: the message * @chunk: the data written @@ -426,10 +299,6 @@ soup_message_class_init (SoupMessageClass *message_class) * Emitted immediately after writing a portion of the message * body to the network. * - * Unlike #SoupMessage::wrote_chunk, this is emitted after - * every successful write() call, not only after finishing a - * complete "chunk". - * * Since: 2.24 **/ signals[WROTE_BODY_DATA] = @@ -447,11 +316,7 @@ soup_message_class_init (SoupMessageClass *message_class) * @msg: the message * * Emitted immediately after writing the complete body for a - * message. (For a client-side message, this means that - * libsoup is done writing and is now waiting for the response - * from the server. For a server-side message, this means that - * libsoup has finished writing the response and is nearly - * done with the message.) + * message. **/ signals[WROTE_BODY] = g_signal_new ("wrote_body", @@ -489,11 +354,7 @@ soup_message_class_init (SoupMessageClass *message_class) * SoupMessage::got-headers: * @msg: the message * - * Emitted after receiving all message headers for a message. - * (For a client-side message, this is after receiving the - * Status-Line and response headers; for a server-side - * message, it is after receiving the Request-Line and request - * headers.) + * Emitted after receiving the Status-Line and response headers. * * See also soup_message_add_header_handler() and * soup_message_add_status_code_handler(), which can be used @@ -518,37 +379,10 @@ soup_message_class_init (SoupMessageClass *message_class) G_TYPE_NONE, 0); /** - * SoupMessage::got-chunk: - * @msg: the message - * @chunk: the just-read chunk - * - * Emitted after receiving a chunk of a message body. Note - * that "chunk" in this context means any subpiece of the - * body, not necessarily the specific HTTP 1.1 chunks sent by - * the other side. - * - * If you cancel or requeue @msg while processing this signal, - * then the current HTTP I/O will be stopped after this signal - * emission finished, and @msg's connection will be closed. - **/ - signals[GOT_CHUNK] = - g_signal_new ("got_chunk", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SoupMessageClass, got_chunk), - NULL, NULL, - NULL, - G_TYPE_NONE, 1, - G_TYPE_BYTES); - - /** * SoupMessage::got-body: * @msg: the message * - * Emitted after receiving the complete message body. (For a - * server-side message, this means it has received the request - * body. For a client-side message, this means it has received - * the response body and is nearly done with the message.) + * Emitted after receiving the complete message request body. * * See also soup_message_add_header_handler() and * soup_message_add_status_code_handler(), which can be used @@ -642,8 +476,7 @@ soup_message_class_init (SoupMessageClass *message_class) * @msg: the message * * Emitted when all HTTP processing is finished for a message. - * (After #SoupMessage::got_body for client-side messages, or - * after #SoupMessage::wrote_body for server-side messages.) + * (After #SoupMessage::got_body). **/ signals[FINISHED] = g_signal_new ("finished", @@ -746,20 +579,6 @@ soup_message_class_init (SoupMessageClass *message_class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * SOUP_MESSAGE_SERVER_SIDE: - * - * Alias for the #SoupMessage:server-side property. (%TRUE if - * the message was created by #SoupServer.) - **/ - g_object_class_install_property ( - object_class, PROP_SERVER_SIDE, - g_param_spec_boolean (SOUP_MESSAGE_SERVER_SIDE, - "Server-side", - "Whether or not the message is server-side rather than client-side", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** * SOUP_MESSAGE_STATUS_CODE: * * Alias for the #SoupMessage:status-code property. (The @@ -841,43 +660,6 @@ soup_message_class_init (SoupMessageClass *message_class) FALSE, G_PARAM_READWRITE)); /** - * SOUP_MESSAGE_REQUEST_BODY: - * - * Alias for the #SoupMessage:request-body property. (The - * message's HTTP request body.) - **/ - g_object_class_install_property ( - object_class, PROP_REQUEST_BODY, - g_param_spec_boxed (SOUP_MESSAGE_REQUEST_BODY, - "Request Body", - "The HTTP request content", - SOUP_TYPE_MESSAGE_BODY, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * SOUP_MESSAGE_REQUEST_BODY_DATA: - * - * Alias for the #SoupMessage:request-body-data property. (The - * message's HTTP request body, as a #GBytes.) - * - * Since: 2.46 - **/ - /** - * SoupMessage:request-body-data: - * - * The message's HTTP request body, as a #GBytes. - * - * Since: 2.46 - **/ - g_object_class_install_property ( - object_class, PROP_REQUEST_BODY_DATA, - g_param_spec_boxed (SOUP_MESSAGE_REQUEST_BODY_DATA, - "Request Body Data", - "The HTTP request body", - G_TYPE_BYTES, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** * SOUP_MESSAGE_REQUEST_HEADERS: * * Alias for the #SoupMessage:request-headers property. (The @@ -892,43 +674,6 @@ soup_message_class_init (SoupMessageClass *message_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** - * SOUP_MESSAGE_RESPONSE_BODY: - * - * Alias for the #SoupMessage:response-body property. (The - * message's HTTP response body.) - **/ - g_object_class_install_property ( - object_class, PROP_RESPONSE_BODY, - g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_BODY, - "Response Body", - "The HTTP response content", - SOUP_TYPE_MESSAGE_BODY, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * SOUP_MESSAGE_RESPONSE_BODY_DATA: - * - * Alias for the #SoupMessage:response-body-data property. (The - * message's HTTP response body, as a #GBytes.) - * - * Since: 2.46 - **/ - /** - * SoupMessage:response-body-data: - * - * The message's HTTP response body, as a #GBytes. - * - * Since: 2.46 - **/ - g_object_class_install_property ( - object_class, PROP_RESPONSE_BODY_DATA, - g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_BODY_DATA, - "Response Body Data", - "The HTTP response body", - G_TYPE_BYTES, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** * SOUP_MESSAGE_RESPONSE_HEADERS: * * Alias for the #SoupMessage:response-headers property. (The @@ -1059,42 +804,6 @@ soup_message_new_from_uri (const char *method, SoupURI *uri) } /** - * soup_message_set_response: - * @msg: the message - * @content_type: (allow-none): MIME Content-Type of the body - * @resp_use: a #SoupMemoryUse describing how to handle @resp_body - * @resp_body: (allow-none) (array length=resp_length) (element-type guint8): - * a data buffer containing the body of the message response. - * @resp_length: the byte length of @resp_body. - * - * Convenience function to set the response body of a #SoupMessage. If - * @content_type is %NULL, the response body must be empty as well. - */ -void -soup_message_set_response (SoupMessage *msg, - const char *content_type, - SoupMemoryUse resp_use, - const char *resp_body, - gsize resp_length) -{ - g_return_if_fail (SOUP_IS_MESSAGE (msg)); - g_return_if_fail (content_type != NULL || resp_length == 0); - - if (content_type) { - g_warn_if_fail (strchr (content_type, '/') != NULL); - - soup_message_headers_replace (msg->response_headers, - "Content-Type", content_type); - soup_message_body_append (msg->response_body, resp_use, - resp_body, resp_length); - } else { - soup_message_headers_remove (msg->response_headers, - "Content-Type"); - soup_message_body_truncate (msg->response_body); - } -} - -/** * soup_message_set_request_body: * @msg: the message * @content_type: (allow-none): MIME Content-Type of the body @@ -1165,24 +874,12 @@ soup_message_set_request_body_from_bytes (SoupMessage *msg, } void -soup_message_wrote_informational (SoupMessage *msg) -{ - g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0); -} - -void soup_message_wrote_headers (SoupMessage *msg) { g_signal_emit (msg, signals[WROTE_HEADERS], 0); } void -soup_message_wrote_chunk (SoupMessage *msg) -{ - g_signal_emit (msg, signals[WROTE_CHUNK], 0); -} - -void soup_message_wrote_body_data (SoupMessage *msg, GBytes *chunk) { g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk); @@ -1207,12 +904,6 @@ soup_message_got_headers (SoupMessage *msg) } void -soup_message_got_chunk (SoupMessage *msg, GBytes *chunk) -{ - g_signal_emit (msg, signals[GOT_CHUNK], 0, chunk); -} - -void soup_message_got_body (SoupMessage *msg) { g_signal_emit (msg, signals[GOT_BODY], 0); @@ -1233,11 +924,6 @@ soup_message_starting (SoupMessage *msg) void soup_message_restarted (SoupMessage *msg) { - SoupMessagePrivate *priv = soup_message_get_instance_private (msg); - - if (priv->msg_flags & SOUP_MESSAGE_CAN_REBUILD) - soup_message_body_truncate (msg->request_body); - g_clear_object (&msg->request_body_stream); g_signal_emit (msg, signals[RESTARTED], 0); @@ -1270,12 +956,9 @@ header_handler_metamarshal (GClosure *closure, GValue *return_value, gpointer invocation_hint, gpointer marshal_data) { SoupMessage *msg = g_value_get_object (¶m_values[0]); - SoupMessagePrivate *priv = soup_message_get_instance_private (msg); const char *header_name = marshal_data; - SoupMessageHeaders *hdrs; - hdrs = priv->server_side ? msg->request_headers : msg->response_headers; - if (soup_message_headers_get_one (hdrs, header_name)) { + if (soup_message_headers_get_one (msg->response_headers, header_name)) { closure->marshal (closure, return_value, n_param_values, param_values, invocation_hint, ((GCClosure *)closure)->callback); @@ -1292,9 +975,7 @@ header_handler_metamarshal (GClosure *closure, GValue *return_value, * * Adds a signal handler to @msg for @signal, as with * g_signal_connect(), but the @callback will only be run if @msg's - * incoming messages headers (that is, the - * <literal>request_headers</literal> for a client #SoupMessage, or - * the <literal>response_headers</literal> for a server #SoupMessage) + * incoming messages headers (that is, the <literal>request_headers</literal>) * contain a header named @header. * * Return value: the handler ID from g_signal_connect() @@ -1353,9 +1034,7 @@ status_handler_metamarshal (GClosure *closure, GValue *return_value, * the status @status_code. * * @signal must be a signal that will be emitted after @msg's status - * is set. For a client #SoupMessage, this means it can't be a "wrote" - * signal. For a server #SoupMessage, this means it can't be a "got" - * signal. + * is set (this means it can't be a "wrote" signal). * * Return value: the handler ID from g_signal_connect() **/ @@ -1379,7 +1058,6 @@ soup_message_add_status_code_handler (SoupMessage *msg, return g_signal_connect_closure (msg, signal, closure, FALSE); } - void soup_message_set_auth (SoupMessage *msg, SoupAuth *auth) { @@ -1470,12 +1148,7 @@ soup_message_cleanup_response (SoupMessage *msg) { SoupMessagePrivate *priv = soup_message_get_instance_private (msg); - soup_message_body_truncate (msg->response_body); soup_message_headers_clear (msg->response_headers); - if (priv->server_side) { - soup_message_headers_set_encoding (msg->response_headers, - SOUP_ENCODING_CONTENT_LENGTH); - } priv->msg_flags &= ~SOUP_MESSAGE_CONTENT_DECODED; @@ -1498,9 +1171,6 @@ soup_message_cleanup_response (SoupMessage *msg) * SoupMessageFlags: * @SOUP_MESSAGE_NO_REDIRECT: The session should not follow redirect * (3xx) responses received by this message. - * @SOUP_MESSAGE_CAN_REBUILD: The caller will rebuild the request - * body if the message is restarted; see - * soup_message_body_set_accumulate() for more details. * @SOUP_MESSAGE_CONTENT_DECODED: Set by #SoupContentDecoder to * indicate that it has removed the Content-Encoding on a message (and * so headers such as Content-Length may no longer accurately describe @@ -1575,14 +1245,6 @@ soup_message_get_flags (SoupMessage *msg) } /** - * SoupHTTPVersion: - * @SOUP_HTTP_1_0: HTTP 1.0 (RFC 1945) - * @SOUP_HTTP_1_1: HTTP 1.1 (RFC 2616) - * - * Indicates the HTTP protocol version being used. - **/ - -/** * soup_message_set_http_version: * @msg: a #SoupMessage * @version: the HTTP version @@ -2061,9 +1723,6 @@ soup_message_set_https_status (SoupMessage *msg, SoupConnection *conn) * showing what problems, if any, have been found with that * certificate. * - * <note><para>This is only meaningful with messages processed by a #SoupSession and is - * not useful for messages received by a #SoupServer</para></note> - * * Return value: %TRUE if @msg used/attempted https, %FALSE if not * * Since: 2.34 @@ -2086,41 +1745,6 @@ soup_message_get_https_status (SoupMessage *msg, return priv->tls_certificate != NULL; } -/** - * soup_message_set_redirect: - * @msg: a #SoupMessage - * @status_code: a 3xx status code - * @redirect_uri: the URI to redirect @msg to - * - * Sets @msg's status_code to @status_code and adds a Location header - * pointing to @redirect_uri. Use this from a #SoupServer when you - * want to redirect the client to another URI. - * - * @redirect_uri can be a relative URI, in which case it is - * interpreted relative to @msg's current URI. In particular, if - * @redirect_uri is just a path, it will replace the path - * <emphasis>and query</emphasis> of @msg's URI. - * - * Since: 2.38 - */ -void -soup_message_set_redirect (SoupMessage *msg, guint status_code, - const char *redirect_uri) -{ - SoupURI *location; - char *location_str; - - location = soup_uri_new_with_base (soup_message_get_uri (msg), redirect_uri); - g_return_if_fail (location != NULL); - - soup_message_set_status (msg, status_code); - location_str = soup_uri_to_string (location, FALSE); - soup_message_headers_replace (msg->response_headers, "Location", - location_str); - g_free (location_str); - soup_uri_free (location); -} - void soup_message_set_soup_request (SoupMessage *msg, SoupRequest *req) @@ -2223,7 +1847,7 @@ soup_message_get_priority (SoupMessage *msg) return priv->priority; } -gpointer +SoupClientMessageIOData * soup_message_get_io_data (SoupMessage *msg) { SoupMessagePrivate *priv = soup_message_get_instance_private (msg); @@ -2232,11 +1856,12 @@ soup_message_get_io_data (SoupMessage *msg) } void -soup_message_set_io_data (SoupMessage *msg, gpointer io) +soup_message_set_io_data (SoupMessage *msg, + SoupClientMessageIOData *io) { SoupMessagePrivate *priv = soup_message_get_instance_private (msg); - soup_message_io_cleanup (msg); + soup_client_message_io_data_free (priv->io_data); priv->io_data = io; } @@ -2266,17 +1891,3 @@ soup_message_set_bytes_for_sniffing (SoupMessage *msg, gsize bytes) priv->bytes_for_sniffing = bytes; } - -const char * -soup_http_version_to_string (SoupHTTPVersion version) -{ - switch (version) { - case SOUP_HTTP_1_0: - return "HTTP/1.0"; - case SOUP_HTTP_1_1: - return "HTTP/1.1"; - } - - g_assert_not_reached (); - return ""; -} diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h index 35560bf9..01664ab6 100644 --- a/libsoup/soup-message.h +++ b/libsoup/soup-message.h @@ -29,11 +29,8 @@ struct _SoupMessage { guint status_code; char *reason_phrase; - SoupMessageBody *request_body; GInputStream *request_body_stream; SoupMessageHeaders *request_headers; - - SoupMessageBody *response_body; SoupMessageHeaders *response_headers; }; @@ -41,13 +38,10 @@ typedef struct { GObjectClass parent_class; /* signals */ - void (*wrote_informational) (SoupMessage *msg); void (*wrote_headers) (SoupMessage *msg); - void (*wrote_chunk) (SoupMessage *msg); void (*wrote_body) (SoupMessage *msg); void (*got_informational) (SoupMessage *msg); void (*got_headers) (SoupMessage *msg); - void (*got_chunk) (SoupMessage *msg, GBytes *chunk); void (*got_body) (SoupMessage *msg); void (*restarted) (SoupMessage *msg); void (*finished) (SoupMessage *msg); @@ -89,12 +83,6 @@ SOUP_AVAILABLE_IN_2_4 SoupMessage *soup_message_new_from_uri (const char *method, SoupURI *uri); -SOUP_AVAILABLE_IN_2_4 -void soup_message_set_response (SoupMessage *msg, - const char *content_type, - SoupMemoryUse resp_use, - const char *resp_body, - gsize resp_length); SOUP_AVAILABLE_IN_ALL void soup_message_set_request_body (SoupMessage *msg, const char *content_type, @@ -105,11 +93,6 @@ void soup_message_set_request_body_from_bytes (SoupMessage *msg, const char *content_type, GBytes *bytes); -typedef enum { - SOUP_HTTP_1_0 = 0, /*< nick=http-1-0 >*/ - SOUP_HTTP_1_1 = 1 /*< nick=http-1-1 >*/ -} SoupHTTPVersion; - SOUP_AVAILABLE_IN_2_4 void soup_message_set_http_version (SoupMessage *msg, SoupHTTPVersion version); @@ -142,13 +125,12 @@ gboolean soup_message_get_is_top_level_navigation (SoupMessage *msg typedef enum { SOUP_MESSAGE_NO_REDIRECT = (1 << 1), - SOUP_MESSAGE_CAN_REBUILD = (1 << 2), - SOUP_MESSAGE_CONTENT_DECODED = (1 << 3), - SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 4), - SOUP_MESSAGE_NEW_CONNECTION = (1 << 5), - SOUP_MESSAGE_IDEMPOTENT = (1 << 6), - SOUP_MESSAGE_IGNORE_CONNECTION_LIMITS = (1 << 7), - SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE = (1 << 8) + SOUP_MESSAGE_CONTENT_DECODED = (1 << 2), + SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 3), + SOUP_MESSAGE_NEW_CONNECTION = (1 << 4), + SOUP_MESSAGE_IDEMPOTENT = (1 << 5), + SOUP_MESSAGE_IGNORE_CONNECTION_LIMITS = (1 << 6), + SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE = (1 << 7) } SoupMessageFlags; SOUP_AVAILABLE_IN_2_4 @@ -192,11 +174,6 @@ void soup_message_set_status_full (SoupMessage *msg, guint status_code, const char *reason_phrase); -SOUP_AVAILABLE_IN_2_38 -void soup_message_set_redirect (SoupMessage *msg, - guint status_code, - const char *redirect_uri); - SOUP_AVAILABLE_IN_2_28 void soup_message_disable_feature (SoupMessage *msg, GType feature_type); @@ -226,12 +203,8 @@ SOUP_AVAILABLE_IN_2_44 SoupMessagePriority soup_message_get_priority (SoupMessage *msg); SOUP_AVAILABLE_IN_2_4 -void soup_message_wrote_informational (SoupMessage *msg); -SOUP_AVAILABLE_IN_2_4 void soup_message_wrote_headers (SoupMessage *msg); SOUP_AVAILABLE_IN_2_4 -void soup_message_wrote_chunk (SoupMessage *msg); -SOUP_AVAILABLE_IN_2_4 void soup_message_wrote_body_data (SoupMessage *msg, GBytes *chunk); SOUP_AVAILABLE_IN_2_4 void soup_message_wrote_body (SoupMessage *msg); @@ -240,8 +213,6 @@ void soup_message_got_informational (SoupMessage *msg); SOUP_AVAILABLE_IN_2_4 void soup_message_got_headers (SoupMessage *msg); SOUP_AVAILABLE_IN_2_4 -void soup_message_got_chunk (SoupMessage *msg, GBytes *chunk); -SOUP_AVAILABLE_IN_2_4 void soup_message_got_body (SoupMessage *msg); SOUP_AVAILABLE_IN_2_4 void soup_message_content_sniffed (SoupMessage *msg, const char *content_type, GHashTable *params); diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c index ce7dc713..d336a62d 100644 --- a/libsoup/soup-session.c +++ b/libsoup/soup-session.c @@ -1013,7 +1013,7 @@ soup_session_append_queue_item (SoupSession *session, static void soup_session_send_queue_item (SoupSession *session, SoupMessageQueueItem *item, - SoupMessageCompletionFn completion_cb) + SoupMessageIOCompletionFn completion_cb) { SoupSessionPrivate *priv = soup_session_get_instance_private (session); @@ -1389,7 +1389,7 @@ tunnel_message_completed (SoupMessage *msg, SoupMessageIOCompletion completion, if (tunnel_item->conn) { tunnel_item->state = SOUP_MESSAGE_RUNNING; soup_session_send_queue_item (session, tunnel_item, - tunnel_message_completed); + (SoupMessageIOCompletionFn)tunnel_message_completed); soup_message_io_run (msg, !tunnel_item->async); return; } @@ -1443,7 +1443,7 @@ tunnel_connect (SoupMessageQueueItem *item) g_signal_emit (session, signals[TUNNELING], 0, tunnel_item->conn); soup_session_send_queue_item (session, tunnel_item, - tunnel_message_completed); + (SoupMessageIOCompletionFn)tunnel_message_completed); soup_message_io_run (msg, !item->async); g_object_unref (msg); } @@ -1709,7 +1709,8 @@ soup_session_process_queue_item (SoupSession *session, item->state = SOUP_MESSAGE_RUNNING; - soup_session_send_queue_item (session, item, message_completed); + soup_session_send_queue_item (session, item, + (SoupMessageIOCompletionFn)message_completed); if (item->async) async_send_request_running (session, item); diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c index d4ed5c41..5eb1f635 100644 --- a/libsoup/soup-status.c +++ b/libsoup/soup-status.c @@ -304,3 +304,11 @@ soup_status_proxify (guint status_code) } G_DEFINE_QUARK (soup-http-error-quark, soup_http_error) + +/** + * SoupHTTPVersion: + * @SOUP_HTTP_1_0: HTTP 1.0 (RFC 1945) + * @SOUP_HTTP_1_1: HTTP 1.1 (RFC 2616) + * + * Indicates the HTTP protocol version being used. + */ diff --git a/libsoup/soup-status.h b/libsoup/soup-status.h index 040a858c..cc7512f9 100644 --- a/libsoup/soup-status.h +++ b/libsoup/soup-status.h @@ -93,6 +93,11 @@ typedef enum { SOUP_STATUS_NOT_EXTENDED = 510 /* RFC 2774 */ } SoupStatus; +typedef enum { + SOUP_HTTP_1_0 = 0, /*< nick=http-1-0 >*/ + SOUP_HTTP_1_1 = 1 /*< nick=http-1-1 >*/ +} SoupHTTPVersion; + SOUP_AVAILABLE_IN_2_4 const char *soup_status_get_phrase (guint status_code); SOUP_AVAILABLE_IN_2_26 diff --git a/libsoup/soup-types.h b/libsoup/soup-types.h index abd7ea21..49a6c9c4 100644 --- a/libsoup/soup-types.h +++ b/libsoup/soup-types.h @@ -25,6 +25,7 @@ typedef struct _SoupMessage SoupMessage; typedef struct _SoupRequest SoupRequest; typedef struct _SoupRequestHTTP SoupRequestHTTP; typedef struct _SoupServer SoupServer; +typedef struct _SoupServerMessage SoupServerMessage; typedef struct _SoupSession SoupSession; typedef struct _SoupSessionFeature SoupSessionFeature; typedef struct _SoupSocket SoupSocket; diff --git a/libsoup/soup.h b/libsoup/soup.h index 36485dc2..bd95488e 100644 --- a/libsoup/soup.h +++ b/libsoup/soup.h @@ -45,6 +45,7 @@ extern "C" { #include "server/soup-auth-domain-basic.h" #include "server/soup-auth-domain-digest.h" #include "server/soup-server.h" +#include "server/soup-server-message.h" #include "soup-session.h" #include "soup-session-feature.h" #include "soup-socket.h" diff --git a/libsoup/websocket/soup-websocket.c b/libsoup/websocket/soup-websocket.c index e7f29f49..48f9a7bd 100644 --- a/libsoup/websocket/soup-websocket.c +++ b/libsoup/websocket/soup-websocket.c @@ -27,6 +27,7 @@ #include "soup-websocket.h" #include "soup-headers.h" #include "soup-message-private.h" +#include "soup-server-message.h" #include "soup-websocket-extension.h" #define FIXED_DIGEST_LEN 20 @@ -205,9 +206,9 @@ compute_accept_key (const char *key) } static gboolean -choose_subprotocol (SoupMessage *msg, - const char **server_protocols, - const char **chosen_protocol) +choose_subprotocol (SoupServerMessage *msg, + const char **server_protocols, + const char **chosen_protocol) { const char *client_protocols_str; char **client_protocols; @@ -219,8 +220,9 @@ choose_subprotocol (SoupMessage *msg, if (!server_protocols) return TRUE; - client_protocols_str = soup_message_headers_get_one (msg->request_headers, - "Sec-Websocket-Protocol"); + client_protocols_str = + soup_message_headers_get_one (soup_server_message_get_request_headers (msg), + "Sec-Websocket-Protocol"); if (!client_protocols_str) return TRUE; @@ -406,10 +408,10 @@ soup_websocket_client_prepare_handshake_with_extensions (SoupMessage *msg, * Since: 2.50 */ gboolean -soup_websocket_server_check_handshake (SoupMessage *msg, - const char *expected_origin, - char **protocols, - GError **error) +soup_websocket_server_check_handshake (SoupServerMessage *msg, + const char *expected_origin, + char **protocols, + GError **error) { return soup_websocket_server_check_handshake_with_extensions (msg, expected_origin, protocols, NULL, error); } @@ -460,15 +462,15 @@ extract_extension_names_from_request (SoupMessage *msg) } static gboolean -process_extensions (SoupMessage *msg, - const char *extensions, - gboolean is_server, +process_extensions (const char *extensions, + SoupMessage *msg, GPtrArray *supported_extensions, GList **accepted_extensions, GError **error) { GSList *extension_list, *l; GHashTable *requested_extensions = NULL; + gboolean is_server = msg == NULL; if (!supported_extensions || supported_extensions->len == 0) { if (is_server) @@ -608,7 +610,7 @@ process_extensions (SoupMessage *msg, /** * soup_websocket_server_check_handshake_with_extensions: - * @msg: #SoupMessage containing the client side of a WebSocket handshake + * @msg: #SoupServerMessage containing the client side of a WebSocket handshake * @origin: (nullable): expected Origin header * @protocols: (nullable) (array zero-terminated=1): allowed WebSocket * protocols. @@ -640,19 +642,20 @@ process_extensions (SoupMessage *msg, * Since: 2.68 */ gboolean -soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, - const char *expected_origin, - char **protocols, - GPtrArray *supported_extensions, - GError **error) +soup_websocket_server_check_handshake_with_extensions (SoupServerMessage *msg, + const char *expected_origin, + char **protocols, + GPtrArray *supported_extensions, + GError **error) { const char *origin; const char *key; const char *extensions; + SoupMessageHeaders *request_headers; - g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE); + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), FALSE); - if (msg->method != SOUP_METHOD_GET) { + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET, @@ -660,8 +663,9 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, return FALSE; } - if (!soup_message_headers_header_equals (msg->request_headers, "Upgrade", "websocket") || - !soup_message_headers_header_contains (msg->request_headers, "Connection", "upgrade")) { + request_headers = soup_server_message_get_request_headers (msg); + if (!soup_message_headers_header_equals (request_headers, "Upgrade", "websocket") || + !soup_message_headers_header_contains (request_headers, "Connection", "upgrade")) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET, @@ -669,7 +673,7 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, return FALSE; } - if (!soup_message_headers_header_equals (msg->request_headers, "Sec-WebSocket-Version", "13")) { + if (!soup_message_headers_header_equals (request_headers, "Sec-WebSocket-Version", "13")) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE, @@ -677,7 +681,7 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, return FALSE; } - key = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key"); + key = soup_message_headers_get_one (request_headers, "Sec-WebSocket-Key"); if (key == NULL || !validate_key (key)) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, @@ -687,7 +691,7 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, } if (expected_origin) { - origin = soup_message_headers_get_one (msg->request_headers, "Origin"); + origin = soup_message_headers_get_one (request_headers, "Origin"); if (!origin || g_ascii_strcasecmp (origin, expected_origin) != 0) { g_set_error (error, SOUP_WEBSOCKET_ERROR, @@ -705,9 +709,9 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, return FALSE; } - extensions = soup_message_headers_get_list (msg->request_headers, "Sec-WebSocket-Extensions"); + extensions = soup_message_headers_get_list (request_headers, "Sec-WebSocket-Extensions"); if (extensions && *extensions) { - if (!process_extensions (msg, extensions, TRUE, supported_extensions, NULL, error)) + if (!process_extensions (extensions, NULL, supported_extensions, NULL, error)) return FALSE; } @@ -718,32 +722,35 @@ soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, "<body>Received invalid WebSocket request</body></html>\r\n" static void -respond_handshake_forbidden (SoupMessage *msg) +respond_handshake_forbidden (SoupServerMessage *msg) { - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); - soup_message_headers_append (msg->response_headers, "Connection", "close"); - soup_message_set_response (msg, "text/html", SOUP_MEMORY_COPY, - RESPONSE_FORBIDDEN, strlen (RESPONSE_FORBIDDEN)); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, NULL); + soup_message_headers_append (soup_server_message_get_response_headers (msg), + "Connection", "close"); + soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_COPY, + RESPONSE_FORBIDDEN, strlen (RESPONSE_FORBIDDEN)); } #define RESPONSE_BAD "<html><head><title>400 Bad Request</title></head>\r\n" \ "<body>Received invalid WebSocket request: %s</body></html>\r\n" static void -respond_handshake_bad (SoupMessage *msg, const char *why) +respond_handshake_bad (SoupServerMessage *msg, + const char *why) { char *text; text = g_strdup_printf (RESPONSE_BAD, why); - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); - soup_message_headers_append (msg->response_headers, "Connection", "close"); - soup_message_set_response (msg, "text/html", SOUP_MEMORY_TAKE, - text, strlen (text)); + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); + soup_message_headers_append (soup_server_message_get_response_headers (msg), + "Connection", "close"); + soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_TAKE, + text, strlen (text)); } /** * soup_websocket_server_process_handshake: - * @msg: #SoupMessage containing the client side of a WebSocket handshake + * @msg: #SoupServerMessage containing the client side of a WebSocket handshake * @expected_origin: (allow-none): expected Origin header * @protocols: (allow-none) (array zero-terminated=1): allowed WebSocket * protocols. @@ -773,16 +780,16 @@ respond_handshake_bad (SoupMessage *msg, const char *why) * Since: 2.50 */ gboolean -soup_websocket_server_process_handshake (SoupMessage *msg, - const char *expected_origin, - char **protocols) +soup_websocket_server_process_handshake (SoupServerMessage *msg, + const char *expected_origin, + char **protocols) { return soup_websocket_server_process_handshake_with_extensions (msg, expected_origin, protocols, NULL, NULL); } /** * soup_websocket_server_process_handshake_with_extensions: - * @msg: #SoupMessage containing the client side of a WebSocket handshake + * @msg: #SoupServerMessage containing the client side of a WebSocket handshake * @expected_origin: (nullable): expected Origin header * @protocols: (nullable) (array zero-terminated=1): allowed WebSocket * protocols. @@ -813,18 +820,21 @@ soup_websocket_server_process_handshake (SoupMessage *msg, * Since: 2.68 */ gboolean -soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg, - const char *expected_origin, - char **protocols, - GPtrArray *supported_extensions, - GList **accepted_extensions) +soup_websocket_server_process_handshake_with_extensions (SoupServerMessage *msg, + const char *expected_origin, + char **protocols, + GPtrArray *supported_extensions, + GList **accepted_extensions) { const char *chosen_protocol = NULL; const char *key; const char *extensions; char *accept_key; GError *error = NULL; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), FALSE); g_return_val_if_fail (accepted_extensions == NULL || *accepted_extensions == NULL, FALSE); if (!soup_websocket_server_check_handshake_with_extensions (msg, expected_origin, protocols, supported_extensions, &error)) { @@ -838,25 +848,27 @@ soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg, return FALSE; } - soup_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS); - soup_message_headers_replace (msg->response_headers, "Upgrade", "websocket"); - soup_message_headers_append (msg->response_headers, "Connection", "Upgrade"); + soup_server_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS, NULL); + response_headers = soup_server_message_get_response_headers (msg); + soup_message_headers_replace (response_headers, "Upgrade", "websocket"); + soup_message_headers_append (response_headers, "Connection", "Upgrade"); - key = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key"); + request_headers = soup_server_message_get_request_headers (msg); + key = soup_message_headers_get_one (request_headers, "Sec-WebSocket-Key"); accept_key = compute_accept_key (key); - soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Accept", accept_key); + soup_message_headers_append (response_headers, "Sec-WebSocket-Accept", accept_key); g_free (accept_key); choose_subprotocol (msg, (const char **) protocols, &chosen_protocol); if (chosen_protocol) - soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Protocol", chosen_protocol); + soup_message_headers_append (response_headers, "Sec-WebSocket-Protocol", chosen_protocol); - extensions = soup_message_headers_get_list (msg->request_headers, "Sec-WebSocket-Extensions"); + extensions = soup_message_headers_get_list (request_headers, "Sec-WebSocket-Extensions"); if (extensions && *extensions) { GList *websocket_extensions = NULL; GList *l; - process_extensions (msg, extensions, TRUE, supported_extensions, &websocket_extensions, NULL); + process_extensions (extensions, NULL, supported_extensions, &websocket_extensions, NULL); if (websocket_extensions) { GString *response_extensions; @@ -878,11 +890,11 @@ soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg, } if (response_extensions->len > 0) { - soup_message_headers_replace (msg->response_headers, + soup_message_headers_replace (response_headers, "Sec-WebSocket-Extensions", response_extensions->str); } else { - soup_message_headers_remove (msg->response_headers, + soup_message_headers_remove (response_headers, "Sec-WebSocket-Extensions"); } g_string_free (response_extensions, TRUE); @@ -1009,7 +1021,7 @@ soup_websocket_client_verify_handshake_with_extensions (SoupMessage *msg, extensions = soup_message_headers_get_list (msg->response_headers, "Sec-WebSocket-Extensions"); if (extensions && *extensions) { - if (!process_extensions (msg, extensions, FALSE, supported_extensions, accepted_extensions, error)) + if (!process_extensions (extensions, msg, supported_extensions, accepted_extensions, error)) return FALSE; } diff --git a/libsoup/websocket/soup-websocket.h b/libsoup/websocket/soup-websocket.h index 9f265e0a..d347c213 100644 --- a/libsoup/websocket/soup-websocket.h +++ b/libsoup/websocket/soup-websocket.h @@ -87,28 +87,28 @@ gboolean soup_websocket_client_verify_handshake_with_extensions (SoupMessage *ms GError **error); SOUP_AVAILABLE_IN_2_50 -gboolean soup_websocket_server_check_handshake (SoupMessage *msg, - const char *origin, - char **protocols, - GError **error); +gboolean soup_websocket_server_check_handshake (SoupServerMessage *msg, + const char *origin, + char **protocols, + GError **error); SOUP_AVAILABLE_IN_2_68 gboolean -soup_websocket_server_check_handshake_with_extensions (SoupMessage *msg, - const char *origin, - char **protocols, - GPtrArray *supported_extensions, - GError **error); +soup_websocket_server_check_handshake_with_extensions (SoupServerMessage *msg, + const char *origin, + char **protocols, + GPtrArray *supported_extensions, + GError **error); SOUP_AVAILABLE_IN_2_50 -gboolean soup_websocket_server_process_handshake (SoupMessage *msg, - const char *expected_origin, - char **protocols); +gboolean soup_websocket_server_process_handshake (SoupServerMessage *msg, + const char *expected_origin, + char **protocols); SOUP_AVAILABLE_IN_2_68 gboolean -soup_websocket_server_process_handshake_with_extensions (SoupMessage *msg, - const char *expected_origin, - char **protocols, - GPtrArray *supported_extensions, - GList **accepted_extensions); +soup_websocket_server_process_handshake_with_extensions (SoupServerMessage *msg, + const char *expected_origin, + char **protocols, + GPtrArray *supported_extensions, + GList **accepted_extensions); G_END_DECLS diff --git a/tests/auth-test.c b/tests/auth-test.c index 9f7720ab..1f3ba064 100644 --- a/tests/auth-test.c +++ b/tests/auth-test.c @@ -838,19 +838,24 @@ select_auth_test_one (SoupURI *uri, } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "OK\r\n", 4); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "OK\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } static gboolean -server_basic_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, - const char *username, const char *password, gpointer data) +server_basic_auth_callback (SoupAuthDomain *auth_domain, + SoupServerMessage *msg, + const char *username, + const char *password, + gpointer data) { if (strcmp (username, "user") != 0) return FALSE; @@ -858,8 +863,10 @@ server_basic_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, } static char * -server_digest_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, - const char *username, gpointer data) +server_digest_auth_callback (SoupAuthDomain *auth_domain, + SoupServerMessage *msg, + const char *username, + gpointer data) { if (strcmp (username, "user") != 0) return NULL; @@ -974,19 +981,21 @@ do_select_auth_test (void) } static void -sneakily_close_connection (SoupMessage *msg, gpointer user_data) +sneakily_close_connection (SoupServerMessage *msg, + gpointer user_data) { /* Sneakily close the connection after the response, by * tricking soup-message-io into thinking that had been * the plan all along. */ - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (soup_server_message_get_response_headers (msg), "Connection", "close"); } static void -auth_close_request_started (SoupServer *server, SoupMessage *msg, - SoupClientContext *client, gpointer user_data) +auth_close_request_started (SoupServer *server, + SoupServerMessage *msg, + gpointer user_data) { g_signal_connect (msg, "wrote-headers", G_CALLBACK (sneakily_close_connection), NULL); @@ -1112,13 +1121,20 @@ do_infinite_auth_test (void) } static void -disappear_request_read (SoupServer *server, SoupMessage *msg, - SoupClientContext *context, gpointer user_data) +disappear_request_read (SoupServer *server, + SoupServerMessage *msg, + gpointer user_data) { + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + + request_headers = soup_server_message_get_request_headers (msg); + response_headers = soup_server_message_get_response_headers (msg); + /* Remove the WWW-Authenticate header if this was a failed attempt */ - if (soup_message_headers_get_one (msg->request_headers, "Authorization") && - msg->status_code == SOUP_STATUS_UNAUTHORIZED) - soup_message_headers_remove (msg->response_headers, "WWW-Authenticate"); + if (soup_message_headers_get_one (request_headers, "Authorization") && + soup_server_message_get_status (msg, NULL) == SOUP_STATUS_UNAUTHORIZED) + soup_message_headers_remove (response_headers, "WWW-Authenticate"); } static void diff --git a/tests/cache-test.c b/tests/cache-test.c index 34e26be8..a048db57 100644 --- a/tests/cache-test.c +++ b/tests/cache-test.c @@ -6,53 +6,62 @@ #include "test-utils.h" static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { const char *last_modified, *etag; const char *header; + const char *method; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; guint status = SOUP_STATUS_OK; - if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + method = soup_server_message_get_method (msg); + + if (method != SOUP_METHOD_GET && method != SOUP_METHOD_POST) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } - header = soup_message_headers_get_one (msg->request_headers, + request_headers = soup_server_message_get_request_headers (msg); + response_headers = soup_server_message_get_response_headers (msg); + header = soup_message_headers_get_one (request_headers, "Test-Set-Expires"); if (header) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Expires", header); } - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (request_headers, "Test-Set-Cache-Control"); if (header) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Cache-Control", header); } - last_modified = soup_message_headers_get_one (msg->request_headers, + last_modified = soup_message_headers_get_one (request_headers, "Test-Set-Last-Modified"); if (last_modified) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Last-Modified", last_modified); } - etag = soup_message_headers_get_one (msg->request_headers, + etag = soup_message_headers_get_one (request_headers, "Test-Set-ETag"); if (etag) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "ETag", etag); } - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (request_headers, "If-Modified-Since"); if (header && last_modified) { GDateTime *modified_date, *header_date; @@ -67,17 +76,17 @@ server_callback (SoupServer *server, SoupMessage *msg, g_date_time_unref (header_date); } - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (request_headers, "If-None-Match"); if (header && etag) { if (!strcmp (header, etag)) status = SOUP_STATUS_NOT_MODIFIED; } - header = soup_message_headers_get_one (msg->request_headers, + header = soup_message_headers_get_one (request_headers, "Test-Set-My-Header"); if (header) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "My-Header", header); } @@ -93,12 +102,12 @@ server_callback (SoupServer *server, SoupMessage *msg, if (etag) g_checksum_update (sum, (guchar *)etag, strlen (etag)); body = g_checksum_get_string (sum); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_COPY, - body, strlen (body) + 1); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_COPY, + body, strlen (body) + 1); g_checksum_free (sum); } - soup_message_set_status (msg, status); + soup_server_message_set_status (msg, status, NULL); } static gboolean diff --git a/tests/coding-test.c b/tests/coding-test.c index 696f46f5..75233351 100644 --- a/tests/coding-test.c +++ b/tests/coding-test.c @@ -10,26 +10,34 @@ SoupServer *server; SoupURI *base_uri; static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { const char *accept_encoding, *options; GSList *codings; GBytes *response = NULL; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; - options = soup_message_headers_get_one (msg->request_headers, + request_headers = soup_server_message_get_request_headers (msg); + options = soup_message_headers_get_one (request_headers, "X-Test-Options"); if (!options) options = ""; - accept_encoding = soup_message_headers_get_list (msg->request_headers, + accept_encoding = soup_message_headers_get_list (request_headers, "Accept-Encoding"); if (accept_encoding && !soup_header_contains (options, "force-encode")) codings = soup_header_parse_quality_list (accept_encoding, NULL); else codings = NULL; + response_headers = soup_server_message_get_response_headers (msg); + if (codings) { gboolean claim_deflate, claim_gzip; const char *extension = NULL, *encoding = NULL; @@ -58,7 +66,7 @@ server_callback (SoupServer *server, SoupMessage *msg, response = soup_test_load_resource (resource, NULL); if (response) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Encoding", encoding); } @@ -75,7 +83,7 @@ server_callback (SoupServer *server, SoupMessage *msg, * the error with "Content-Encoding: gzip" but there's * no body, so, eh. */ - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL); return; } @@ -86,34 +94,35 @@ server_callback (SoupServer *server, SoupMessage *msg, soup_header_contains (options, "prefer-deflate-raw")) encoding = "deflate"; - soup_message_headers_replace (msg->response_headers, + soup_message_headers_replace (response_headers, "Content-Encoding", encoding); } /* Content-Type matches the "real" format, not the sent format */ if (g_str_has_suffix (path, ".gz")) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "application/gzip"); } else { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "text/plain"); } - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CHUNKED); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_message_headers_set_encoding (response_headers, SOUP_ENCODING_CHUNKED); + response_body = soup_server_message_get_response_body (msg); if (!soup_header_contains (options, "empty")) - soup_message_body_append_bytes (msg->response_body, response); + soup_message_body_append_bytes (response_body, response); g_bytes_unref (response); if (soup_header_contains (options, "trailing-junk")) { - soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, + soup_message_body_append (response_body, SOUP_MEMORY_COPY, options, strlen (options)); } - soup_message_body_complete (msg->response_body); + soup_message_body_complete (response_body); } typedef struct { diff --git a/tests/connection-test.c b/tests/connection-test.c index d267c3ec..f694bf94 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -7,7 +7,7 @@ #include "soup-connection.h" #include "soup-socket-private.h" -#include "soup-server-private.h" +#include "soup-server-message-private.h" #include <gio/gnetworking.h> @@ -16,15 +16,17 @@ SoupURI *base_uri; GMutex server_mutex; static void -forget_close (SoupMessage *msg, gpointer user_data) +forget_close (SoupServerMessage *msg, + gpointer user_data) { - soup_message_headers_remove (msg->response_headers, "Connection"); + soup_message_headers_remove (soup_server_message_get_response_headers (msg), + "Connection"); } static void -close_socket (SoupMessage *msg, gpointer user_data) +close_socket (SoupServerMessage *msg, + SoupSocket *sock) { - SoupSocket *sock = user_data; GSocket *gsocket; int sockfd; @@ -42,7 +44,8 @@ close_socket (SoupMessage *msg, gpointer user_data) /* Then add the missing data to the message now, so SoupServer * can clean up after itself properly. */ - soup_message_body_append (msg->response_body, SOUP_MEMORY_STATIC, + soup_message_body_append (soup_server_message_get_response_body (msg), + SOUP_MEMORY_STATIC, "foo", 3); } @@ -53,8 +56,9 @@ timeout_socket (SoupSocket *sock, gpointer user_data) } static void -timeout_request_started (SoupServer *server, SoupMessage *msg, - SoupClientContext *client, gpointer user_data) +timeout_request_started (SoupServer *server, + SoupServerMessage *msg, + gpointer user_data) { SoupSocket *sock; GMainContext *context = g_main_context_get_thread_default (); @@ -62,7 +66,7 @@ timeout_request_started (SoupServer *server, SoupMessage *msg, g_signal_handlers_disconnect_by_func (server, timeout_request_started, NULL); - sock = soup_client_context_get_soup_socket (client); + sock = soup_server_message_get_soup_socket (msg); readable = g_signal_connect (sock, "readable", G_CALLBACK (timeout_socket), NULL); @@ -104,10 +108,14 @@ setup_timeout_persistent (SoupServer *server, SoupSocket *sock) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { + const char *method; + /* The way this gets used in the tests, we don't actually * need to hold it through the whole function, so it's simpler * to just release it right away. @@ -115,21 +123,25 @@ server_callback (SoupServer *server, SoupMessage *msg, g_mutex_lock (&server_mutex); g_mutex_unlock (&server_mutex); - if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + method = soup_server_message_get_method (msg); + if (method != SOUP_METHOD_GET && method != SOUP_METHOD_POST) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } if (g_str_has_prefix (path, "/content-length/")) { gboolean too_long = strcmp (path, "/content-length/long") == 0; gboolean no_close = strcmp (path, "/content-length/noclose") == 0; + SoupMessageHeaders *response_headers; + + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, "foobar", 6); - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, "foobar", 6); + response_headers = soup_server_message_get_response_headers (msg); if (too_long) - soup_message_headers_set_content_length (msg->response_headers, 9); - soup_message_headers_append (msg->response_headers, + soup_message_headers_set_content_length (response_headers, 9); + soup_message_headers_append (response_headers, "Connection", "close"); if (too_long) { @@ -140,7 +152,7 @@ server_callback (SoupServer *server, SoupMessage *msg, * the declared Content-Length. Instead, we * forcibly close the socket at that point. */ - sock = soup_client_context_get_soup_socket (context); + sock = soup_server_message_get_soup_socket (msg); g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock); } else if (no_close) { @@ -158,13 +170,13 @@ server_callback (SoupServer *server, SoupMessage *msg, if (!strcmp (path, "/timeout-persistent")) { SoupSocket *sock; - sock = soup_client_context_get_soup_socket (context); + sock = soup_server_message_get_soup_socket (msg); setup_timeout_persistent (server, sock); } - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, "index", 5); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, "index", 5); return; } diff --git a/tests/context-test.c b/tests/context-test.c index a47a3142..e8c55dc8 100644 --- a/tests/context-test.c +++ b/tests/context-test.c @@ -10,12 +10,13 @@ static char *base_uri; typedef struct { SoupServer *server; - SoupMessage *msg; + SoupServerMessage *msg; GSource *timeout; } SlowData; static void -request_finished (SoupMessage *msg, gpointer data) +request_finished (SoupServerMessage *msg, + gpointer data) { SlowData *sd = data; @@ -28,10 +29,12 @@ static gboolean add_body_chunk (gpointer data) { SlowData *sd = data; + SoupMessageBody *response_body; - soup_message_body_append (sd->msg->response_body, + response_body = soup_server_message_get_response_body (sd->msg); + soup_message_body_append (response_body, SOUP_MEMORY_STATIC, "OK\r\n", 4); - soup_message_body_complete (sd->msg->response_body); + soup_message_body_complete (response_body); soup_server_unpause_message (sd->server, sd->msg); g_object_unref (sd->msg); @@ -39,25 +42,29 @@ add_body_chunk (gpointer data) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { SlowData *sd; + SoupMessageHeaders *response_headers; - if (msg->method != SOUP_METHOD_GET) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); if (!strcmp (path, "/fast")) { - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, "OK\r\n", 4); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, "OK\r\n", 4); return; } - soup_message_headers_set_encoding (msg->response_headers, + response_headers = soup_server_message_get_response_headers (msg); + soup_message_headers_set_encoding (response_headers, SOUP_ENCODING_CHUNKED); g_object_ref (msg); soup_server_pause_message (server, msg); diff --git a/tests/continue-test.c b/tests/continue-test.c index 85d1a4e6..2b63b1b7 100644 --- a/tests/continue-test.c +++ b/tests/continue-test.c @@ -14,37 +14,65 @@ static SoupURI *base_uri; static GSList *events; static void -event (SoupMessage *msg, const char *side, const char *message) +client_event (SoupMessage *msg, + const char *message) { - char *data = g_strdup_printf ("%s-%s", side, message); + char *data = g_strdup_printf ("client-%s", message); + + debug_printf (2, " %s", data); + debug_printf (2, "\n"); + + events = g_slist_append (events, data); +} + +static void +server_event (SoupServerMessage *msg, + const char *message) +{ + char *data = g_strdup_printf ("server-%s", message); gboolean record_status = (!strcmp (data, "server-wrote_headers") || !strcmp (data, "server-wrote_informational")); + const char *reason_phrase; + guint status_code = soup_server_message_get_status (msg, &reason_phrase); debug_printf (2, " %s", data); if (record_status) - debug_printf (2, " (%s)", msg->reason_phrase); + debug_printf (2, " (%s)", reason_phrase); debug_printf (2, "\n"); events = g_slist_append (events, data); if (record_status) - events = g_slist_append (events, GUINT_TO_POINTER (msg->status_code)); + events = g_slist_append (events, GUINT_TO_POINTER (status_code)); } -#define EVENT_HANDLER(name) \ +#define CLIENT_EVENT_HANDLER(name) \ static void \ -name (SoupMessage *msg, gpointer side) \ +client_##name (SoupMessage *msg, gpointer side) \ { \ - event (msg, side, #name); \ + client_event (msg, #name); \ } -EVENT_HANDLER (got_informational) -EVENT_HANDLER (got_headers) -EVENT_HANDLER (got_body) -EVENT_HANDLER (wrote_informational) -EVENT_HANDLER (wrote_headers) -EVENT_HANDLER (wrote_body) -EVENT_HANDLER (finished) +#define SERVER_EVENT_HANDLER(name) \ +static void \ +server_##name (SoupServerMessage *msg, gpointer side) \ +{ \ + server_event (msg, #name); \ +} + +CLIENT_EVENT_HANDLER (got_informational) +CLIENT_EVENT_HANDLER (got_headers) +CLIENT_EVENT_HANDLER (got_body) +CLIENT_EVENT_HANDLER (wrote_headers) +CLIENT_EVENT_HANDLER (wrote_body) +CLIENT_EVENT_HANDLER (finished) + +SERVER_EVENT_HANDLER (got_headers) +SERVER_EVENT_HANDLER (got_body) +SERVER_EVENT_HANDLER (wrote_informational) +SERVER_EVENT_HANDLER (wrote_headers) +SERVER_EVENT_HANDLER (wrote_body) +SERVER_EVENT_HANDLER (finished) static void restarted (SoupMessage *msg, @@ -76,7 +104,6 @@ do_message (const char *path, gboolean long_body, } soup_uri_set_path (uri, path); msg = soup_message_new_from_uri ("POST", uri); - g_print ("DBG: soup_message_new_from_uri: %p\n", msg); soup_uri_free (uri); body = long_body ? LONG_BODY : SHORT_BODY; @@ -88,20 +115,18 @@ do_message (const char *path, gboolean long_body, SOUP_EXPECTATION_CONTINUE); } - g_signal_connect (msg, "got_informational", - G_CALLBACK (got_informational), "client"); - g_signal_connect (msg, "got_headers", - G_CALLBACK (got_headers), "client"); - g_signal_connect (msg, "got_body", - G_CALLBACK (got_body), "client"); - g_signal_connect (msg, "wrote_informational", - G_CALLBACK (wrote_informational), "client"); - g_signal_connect (msg, "wrote_headers", - G_CALLBACK (wrote_headers), "client"); - g_signal_connect (msg, "wrote_body", - G_CALLBACK (wrote_body), "client"); + g_signal_connect (msg, "got-informational", + G_CALLBACK (client_got_informational), NULL); + g_signal_connect (msg, "got-headers", + G_CALLBACK (client_got_headers), NULL); + g_signal_connect (msg, "got-body", + G_CALLBACK (client_got_body), NULL); + g_signal_connect (msg, "wrote-headers", + G_CALLBACK (client_wrote_headers), NULL); + g_signal_connect (msg, "wrote-body", + G_CALLBACK (client_wrote_body), NULL); g_signal_connect (msg, "finished", - G_CALLBACK (finished), "client"); + G_CALLBACK (client_finished), NULL); g_signal_connect (msg, "restarted", G_CALLBACK (restarted), request_body); @@ -401,47 +426,54 @@ do_test_auth_long_expect_pass (void) /* SERVER */ static void -server_got_headers (SoupMessage *msg, gpointer server) +_server_got_headers (SoupServerMessage *msg, + gpointer server) { + guint status_code; + SoupMessageHeaders *request_headers; + + status_code = soup_server_message_get_status (msg, NULL); /* FIXME */ - if (msg->status_code != SOUP_STATUS_CONTINUE && - msg->status_code != 0) + if (status_code != SOUP_STATUS_CONTINUE && status_code != 0) return; - if (soup_message_headers_get_expectations (msg->request_headers) & + request_headers = soup_server_message_get_request_headers (msg); + if (soup_message_headers_get_expectations (request_headers) & SOUP_EXPECTATION_CONTINUE) { const char *length; - length = soup_message_headers_get_one (msg->request_headers, + length = soup_message_headers_get_one (request_headers, "Content-Length"); if (length && atoi (length) > MAX_POST_LENGTH) { - soup_message_set_status (msg, SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE); - soup_message_headers_append (msg->response_headers, "Connection", "close"); + SoupMessageHeaders *response_headers; + + response_headers = soup_server_message_get_response_headers (msg); + soup_server_message_set_status (msg, SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE, NULL); + soup_message_headers_append (response_headers, "Connection", "close"); } } -} +} static void -request_started (SoupServer *server, SoupMessage *msg, - SoupClientContext *client, gpointer user_data) +request_started (SoupServer *server, + SoupServerMessage *msg, + gpointer user_data) { - g_signal_connect (msg, "got_headers", - G_CALLBACK (server_got_headers), server); - - g_signal_connect (msg, "got_informational", - G_CALLBACK (got_informational), "server"); - g_signal_connect (msg, "got_headers", - G_CALLBACK (got_headers), "server"); - g_signal_connect (msg, "got_body", - G_CALLBACK (got_body), "server"); - g_signal_connect (msg, "wrote_informational", - G_CALLBACK (wrote_informational), "server"); - g_signal_connect (msg, "wrote_headers", - G_CALLBACK (wrote_headers), "server"); - g_signal_connect (msg, "wrote_body", - G_CALLBACK (wrote_body), "server"); + g_signal_connect (msg, "got-headers", + G_CALLBACK (_server_got_headers), server); + + g_signal_connect (msg, "got-headers", + G_CALLBACK (server_got_headers), NULL); + g_signal_connect (msg, "got-body", + G_CALLBACK (server_got_body), NULL); + g_signal_connect (msg, "wrote-informational", + G_CALLBACK (server_wrote_informational), NULL); + g_signal_connect (msg, "wrote-headers", + G_CALLBACK (server_wrote_headers), NULL); + g_signal_connect (msg, "wrote-body", + G_CALLBACK (server_wrote_body), NULL); g_signal_connect (msg, "finished", - G_CALLBACK (finished), "server"); + G_CALLBACK (server_finished), NULL); } static gboolean @@ -452,18 +484,25 @@ auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - if (msg->method != SOUP_METHOD_POST) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); - soup_message_headers_append (msg->response_headers, "Connection", "close"); - } else if (msg->request_body->length > MAX_POST_LENGTH) { - soup_message_set_status (msg, SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE); - soup_message_headers_append (msg->response_headers, "Connection", "close"); + SoupMessageHeaders *response_headers; + SoupMessageBody *request_body; + + response_headers = soup_server_message_get_response_headers (msg); + request_body = soup_server_message_get_request_body (msg); + if (soup_server_message_get_method (msg) != SOUP_METHOD_POST) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); + soup_message_headers_append (response_headers, "Connection", "close"); + } else if (request_body->length > MAX_POST_LENGTH) { + soup_server_message_set_status (msg, SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE, NULL); + soup_message_headers_append (response_headers, "Connection", "close"); } else - soup_message_set_status (msg, SOUP_STATUS_CREATED); + soup_server_message_set_status (msg, SOUP_STATUS_CREATED, NULL); } static SoupServer * diff --git a/tests/cookies-test.c b/tests/cookies-test.c index 63c9e711..163f4f42 100644 --- a/tests/cookies-test.c +++ b/tests/cookies-test.c @@ -11,27 +11,34 @@ const char *first_party = "http://127.0.0.1/"; const char *third_party = "http://localhost/"; static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { + SoupMessageHeaders *response_headers; + SoupMessageHeaders *request_headers; + + response_headers = soup_server_message_get_response_headers (msg); + request_headers = soup_server_message_get_request_headers (msg); if (g_str_equal (path, "/index.html")) { - soup_message_headers_replace (msg->response_headers, + soup_message_headers_replace (response_headers, "Set-Cookie", "foo=bar"); } else if (g_str_equal (path, "/foo.jpg")) { - soup_message_headers_replace (msg->response_headers, + soup_message_headers_replace (response_headers, "Set-Cookie", "baz=qux"); - } else if (soup_message_headers_get_one (msg->request_headers, + } else if (soup_message_headers_get_one (request_headers, "Echo-Set-Cookie")) { - soup_message_headers_replace (msg->response_headers, + soup_message_headers_replace (response_headers, "Set-Cookie", - soup_message_headers_get_one (msg->request_headers, + soup_message_headers_get_one (request_headers, "Echo-Set-Cookie")); } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } typedef struct { diff --git a/tests/forms-test.c b/tests/forms-test.c index 1a07fa00..9d069a4c 100644 --- a/tests/forms-test.c +++ b/tests/forms-test.c @@ -250,16 +250,20 @@ do_form_decode_test (void) } static void -hello_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +hello_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { char *title, *name, *fmt; const char *content_type; GString *buf; + const char *method; - if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_HEAD) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + method = soup_server_message_get_method (msg); + if (method != SOUP_METHOD_GET && method != SOUP_METHOD_HEAD) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } @@ -296,17 +300,19 @@ hello_callback (SoupServer *server, SoupMessage *msg, } } - soup_message_set_response (msg, content_type, - SOUP_MEMORY_TAKE, - buf->str, buf->len); + soup_server_message_set_response (msg, content_type, + SOUP_MEMORY_TAKE, + buf->str, buf->len); g_string_free (buf, FALSE); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } static void -md5_get_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +md5_get_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { const char *file = NULL, *md5sum = NULL, *fmt; const char *content_type; @@ -340,17 +346,19 @@ md5_get_callback (SoupServer *server, SoupMessage *msg, g_string_append_printf (buf, "%s", md5sum); } - soup_message_set_response (msg, content_type, - SOUP_MEMORY_TAKE, - buf->str, buf->len); + soup_server_message_set_response (msg, content_type, + SOUP_MEMORY_TAKE, + buf->str, buf->len); g_string_free (buf, FALSE); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } static void -md5_post_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +md5_post_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { const char *content_type; GHashTable *params; @@ -358,17 +366,23 @@ md5_post_callback (SoupServer *server, SoupMessage *msg, char *filename, *md5sum, *redirect_uri; GBytes *file; SoupURI *uri; + SoupMultipart *multipart; + GBytes *body; + SoupMessageHeaders *request_headers; - content_type = soup_message_headers_get_content_type (msg->request_headers, NULL); + request_headers = soup_server_message_get_request_headers (msg); + content_type = soup_message_headers_get_content_type (request_headers, NULL); if (!content_type || strcmp (content_type, "multipart/form-data") != 0) { - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return; } - params = soup_form_decode_multipart (msg, "file", - &filename, NULL, &file); + body = soup_message_body_flatten (soup_server_message_get_request_body (msg)); + multipart = soup_multipart_new_from_message (request_headers, body); + g_bytes_unref (body); + params = multipart ? soup_form_decode_multipart (multipart, "file", &filename, NULL, &file) : NULL; if (!params) { - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return; } fmt = g_hash_table_lookup (params, "fmt"); @@ -376,7 +390,7 @@ md5_post_callback (SoupServer *server, SoupMessage *msg, md5sum = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, file); g_bytes_unref (file); - uri = soup_uri_copy (soup_message_get_uri (msg)); + uri = soup_uri_copy (soup_server_message_get_uri (msg)); soup_uri_set_query_from_fields (uri, "file", filename ? filename : "", "md5sum", md5sum, @@ -384,7 +398,7 @@ md5_post_callback (SoupServer *server, SoupMessage *msg, NULL); redirect_uri = soup_uri_to_string (uri, FALSE); - soup_message_set_redirect (msg, SOUP_STATUS_SEE_OTHER, redirect_uri); + soup_server_message_set_redirect (msg, SOUP_STATUS_SEE_OTHER, redirect_uri); g_free (redirect_uri); soup_uri_free (uri); @@ -394,16 +408,22 @@ md5_post_callback (SoupServer *server, SoupMessage *msg, } static void -md5_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +md5_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD) - md5_get_callback (server, msg, path, query, context, data); - else if (msg->method == SOUP_METHOD_POST) - md5_post_callback (server, msg, path, query, context, data); + const char *method; + + method = soup_server_message_get_method (msg); + + if (method == SOUP_METHOD_GET || method == SOUP_METHOD_HEAD) + md5_get_callback (server, msg, path, query, data); + else if (method == SOUP_METHOD_POST) + md5_post_callback (server, msg, path, query, data); else - soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); + soup_server_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED, NULL); } static gboolean run_tests = TRUE; diff --git a/tests/hsts-db-test.c b/tests/hsts-db-test.c index f45e355d..2adc05b7 100644 --- a/tests/hsts-db-test.c +++ b/tests/hsts-db-test.c @@ -13,42 +13,47 @@ SoupURI *https_uri; test the Soup HSTS feature. */ static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { + SoupMessageHeaders *response_headers; const char *server_protocol = data; + response_headers = soup_server_message_get_response_headers (msg); + if (strcmp (server_protocol, "http") == 0) { char *uri_string; SoupURI *uri = soup_uri_new ("https://localhost"); soup_uri_set_path (uri, path); uri_string = soup_uri_to_string (uri, FALSE); fprintf (stderr, "server is redirecting to HTTPS\n"); - soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, uri_string); + soup_server_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, uri_string); soup_uri_free (uri); g_free (uri_string); } else if (strcmp (server_protocol, "https") == 0) { - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); if (strcmp (path, "/long-lasting") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=31536000"); } else if (strcmp (path, "/two-seconds") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=2"); } else if (strcmp (path, "/delete") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=0"); } else if (strcmp (path, "/subdomains") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=31536000; includeSubDomains"); } else if (strcmp (path, "/very-long-lasting") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=631138519"); } diff --git a/tests/hsts-test.c b/tests/hsts-test.c index e8c7d877..9bb36edf 100644 --- a/tests/hsts-test.c +++ b/tests/hsts-test.c @@ -13,88 +13,93 @@ SoupURI *https_uri; test the Soup HSTS feature. */ static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { + SoupMessageHeaders *response_headers; const char *server_protocol = data; + response_headers = soup_server_message_get_response_headers (msg); + if (strcmp (server_protocol, "http") == 0) { if (strcmp (path, "/insecure") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=31536000"); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } else { char *uri_string; SoupURI *uri = soup_uri_new ("https://localhost"); soup_uri_set_path (uri, path); uri_string = soup_uri_to_string (uri, FALSE); - soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, uri_string); + soup_server_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, uri_string); soup_uri_free (uri); g_free (uri_string); } } else if (strcmp (server_protocol, "https") == 0) { - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); if (strcmp (path, "/long-lasting") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=31536000"); } else if (strcmp (path, "/two-seconds") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=2"); } else if (strcmp (path, "/three-seconds") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=3"); } else if (strcmp (path, "/delete") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=0"); } else if (strcmp (path, "/subdomains") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=31536000; includeSubDomains"); } else if (strcmp (path, "/no-sts-header") == 0) { /* Do not add anything */ } else if (strcmp (path, "/multiple-headers") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=31536000; includeSubDomains"); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=1; includeSubDomains"); } else if (strcmp (path, "/missing-values") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", ""); } else if (strcmp (path, "/invalid-values") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=foo"); } else if (strcmp (path, "/extra-values-0") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=3600; foo"); } else if (strcmp (path, "/extra-values-1") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", " max-age=3600; includeDomains; foo"); } else if (strcmp (path, "/duplicated-directives") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=3600; includeDomains; includeDomains"); } else if (strcmp (path, "/case-insensitive-header") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "STRICT-TRANSPORT-SECURITY", "max-age=3600"); } else if (strcmp (path, "/case-insensitive-directives") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "MAX-AGE=3600; includesubdomains"); } else if (strcmp (path, "/optional-quotations") == 0) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Strict-Transport-Security", "max-age=\"31536000\""); } diff --git a/tests/misc-test.c b/tests/misc-test.c index 759c2abf..beb586ba 100644 --- a/tests/misc-test.c +++ b/tests/misc-test.c @@ -27,29 +27,37 @@ timeout_finish_message (gpointer msg) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) -{ - SoupURI *uri = soup_message_get_uri (msg); +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) +{ + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + const char *method = soup_server_message_get_method (msg); + SoupURI *uri = soup_server_message_get_uri (msg); const char *server_protocol = data; - if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + if (method != SOUP_METHOD_GET && method != SOUP_METHOD_POST) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } if (!strcmp (path, "/redirect")) { - soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/"); + soup_server_message_set_redirect (msg, SOUP_STATUS_FOUND, "/"); return; } + request_headers = soup_server_message_get_request_headers (msg); + response_headers = soup_server_message_get_response_headers (msg); + if (!strcmp (path, "/alias-redirect")) { SoupURI *redirect_uri; char *redirect_string; const char *redirect_protocol; - redirect_protocol = soup_message_headers_get_one (msg->request_headers, "X-Redirect-Protocol"); + redirect_protocol = soup_message_headers_get_one (request_headers, "X-Redirect-Protocol"); redirect_uri = soup_uri_copy (uri); soup_uri_set_scheme (redirect_uri, "foo"); @@ -60,13 +68,13 @@ server_callback (SoupServer *server, SoupMessage *msg, soup_uri_set_path (redirect_uri, "/alias-redirected"); redirect_string = soup_uri_to_string (redirect_uri, FALSE); - soup_message_set_redirect (msg, SOUP_STATUS_FOUND, redirect_string); + soup_server_message_set_redirect (msg, SOUP_STATUS_FOUND, redirect_string); g_free (redirect_string); soup_uri_free (redirect_uri); return; } else if (!strcmp (path, "/alias-redirected")) { - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_headers_append (msg->response_headers, + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_message_headers_append (response_headers, "X-Redirected-Protocol", server_protocol); return; @@ -79,14 +87,14 @@ server_callback (SoupServer *server, SoupMessage *msg, 1000, timeout_finish_message, msg); } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); if (!strcmp (uri->host, "foo")) { - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, "foo-index", 9); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, "foo-index", 9); return; } else { - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, "index", 5); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, "index", 5); return; } } diff --git a/tests/multipart-test.c b/tests/multipart-test.c index c0c09dc8..d9a00ae1 100644 --- a/tests/multipart-test.c +++ b/tests/multipart-test.c @@ -58,26 +58,33 @@ const char *payload = \ "\r\n--cut-here--"; static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - if (msg->method != SOUP_METHOD_GET) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; + + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); - soup_message_headers_append (msg->response_headers, + response_headers = soup_server_message_get_response_headers (msg); + soup_message_headers_append (response_headers, "Content-Type", "multipart/x-mixed-replace; boundary=cut-here"); - soup_message_body_append (msg->response_body, + response_body = soup_server_message_get_response_body (msg); + soup_message_body_append (response_body, SOUP_MEMORY_STATIC, payload, strlen (payload)); - soup_message_body_complete (msg->response_body); + soup_message_body_complete (response_body); } static void diff --git a/tests/no-ssl-test.c b/tests/no-ssl-test.c index b92dd2c2..02bec973 100644 --- a/tests/no-ssl-test.c +++ b/tests/no-ssl-test.c @@ -38,16 +38,15 @@ do_ssl_tests (gconstpointer data) static void server_handler (SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, GHashTable *query, - SoupClientContext *client, gpointer user_data) { - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "ok\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "ok\r\n", 4); } int diff --git a/tests/ntlm-test.c b/tests/ntlm-test.c index 0a980f9b..c3d69c9b 100644 --- a/tests/ntlm-test.c +++ b/tests/ntlm-test.c @@ -55,19 +55,22 @@ clear_state (gpointer connections, GObject *ex_connection) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *client, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { TestServer *ts = data; GSocket *socket; const char *auth; + SoupMessageHeaders *request_headers; NTLMServerState state, required_user = 0; gboolean auth_required, not_found = FALSE; gboolean basic_allowed = TRUE, ntlm_allowed = TRUE; - if (msg->method != SOUP_METHOD_GET) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } @@ -86,10 +89,10 @@ server_callback (SoupServer *server, SoupMessage *msg, if (strstr (path, "/404")) not_found = TRUE; - socket = soup_client_context_get_socket (client); + socket = soup_server_message_get_socket (msg); state = GPOINTER_TO_INT (g_hash_table_lookup (ts->connections, socket)); - auth = soup_message_headers_get_one (msg->request_headers, - "Authorization"); + request_headers = soup_server_message_get_request_headers (msg); + auth = soup_message_headers_get_one (request_headers, "Authorization"); if (auth) { if (!strncmp (auth, "NTLM ", 5)) { @@ -126,33 +129,36 @@ server_callback (SoupServer *server, SoupMessage *msg, auth_required = FALSE; if (auth_required) { - soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED); + SoupMessageHeaders *response_headers; + soup_server_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED, NULL); + + response_headers = soup_server_message_get_response_headers (msg); if (basic_allowed && state != NTLM_RECEIVED_REQUEST) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "WWW-Authenticate", "Basic realm=\"ntlm-test\""); } if (ntlm_allowed && state == NTLM_RECEIVED_REQUEST) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "WWW-Authenticate", ts->ntlmssp ? ("NTLM " NTLMSSP_CHALLENGE) : ts->ntlmv2 ? ("NTLM " NTLMV2_CHALLENGE) : ("NTLM " NTLMV1_CHALLENGE)); state = NTLM_SENT_CHALLENGE; } else if (ntlm_allowed) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "WWW-Authenticate", "NTLM"); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Connection", "close"); } } else { if (not_found) - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL); else { - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "OK\r\n", 4); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "OK\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } } diff --git a/tests/proxy-test.c b/tests/proxy-test.c index a17671d4..03c79377 100644 --- a/tests/proxy-test.c +++ b/tests/proxy-test.c @@ -238,13 +238,15 @@ do_async_proxy_test (gconstpointer data) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - SoupURI *uri = soup_message_get_uri (msg); + SoupURI *uri = soup_server_message_get_uri (msg); - soup_message_set_status (msg, uri->fragment ? SOUP_STATUS_BAD_REQUEST : SOUP_STATUS_OK); + soup_server_message_set_status (msg, uri->fragment ? SOUP_STATUS_BAD_REQUEST : SOUP_STATUS_OK, NULL); } static void diff --git a/tests/pull-api-test.c b/tests/pull-api-test.c index f73d8cee..36d44a5e 100644 --- a/tests/pull-api-test.c +++ b/tests/pull-api-test.c @@ -52,8 +52,6 @@ typedef struct { } FullyAsyncData; static void fully_async_got_headers (SoupMessage *msg, gpointer user_data); -static void fully_async_got_chunk (SoupMessage *msg, GBytes *chunk, - gpointer user_data); static gboolean fully_async_request_chunk (gpointer user_data); static void @@ -99,12 +97,6 @@ do_fully_async_test (SoupSession *session, ad.read_so_far = 0; ad.expected_status = expected_status; - /* Since we aren't going to look at the final value of - * msg->response_body, we tell libsoup to not even bother - * generating it. - */ - soup_message_body_set_accumulate (msg->response_body, FALSE); - /* Connect to "got_headers", from which we'll decide where to * go next. */ @@ -187,45 +179,11 @@ fully_async_got_headers (SoupMessage *msg, gpointer user_data) * until one is requested. */ ad->chunks_ready = TRUE; - g_signal_connect (msg, "got_chunk", - G_CALLBACK (fully_async_got_chunk), ad); if (!ad->chunk_wanted) soup_session_pause_message (ad->session, msg); } static void -fully_async_got_chunk (SoupMessage *msg, GBytes *chunk, gpointer user_data) -{ - FullyAsyncData *ad = user_data; - - debug_printf (2, " got chunk from %lu - %lu\n", - (unsigned long) ad->read_so_far, - (unsigned long) ad->read_so_far + g_bytes_get_size (chunk)); - - /* We've got a chunk, let's process it. In the case of the - * test program, that means comparing it against - * correct_response to make sure that we got the right data. - */ - gsize chunk_length = g_bytes_get_size (chunk); - g_assert_cmpint (ad->read_so_far + chunk_length, <=, g_bytes_get_size (correct_response)); - soup_assert_cmpmem (g_bytes_get_data (chunk, NULL), chunk_length, - (guchar*)g_bytes_get_data (correct_response, NULL) + ad->read_so_far, - chunk_length); - ad->read_so_far += chunk_length; - - /* Now pause I/O, and prepare to read another chunk later. - * (Again, the timeout just abstractly represents the idea of - * the application requesting another chunk at some random - * point in the future. You wouldn't be using a timeout in a - * real program.) - */ - soup_session_pause_message (ad->session, msg); - ad->chunk_wanted = FALSE; - - ad->timeout = g_timeout_add (10, fully_async_request_chunk, ad); -} - -static void do_fast_async_test (gconstpointer data) { const char *base_uri = data; diff --git a/tests/range-test.c b/tests/range-test.c index ce8a744b..bf97f958 100644 --- a/tests/range-test.c +++ b/tests/range-test.c @@ -349,15 +349,14 @@ do_apache_range_test (void) static void server_handler (SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, GHashTable *query, - SoupClientContext *client, gpointer user_data) { - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_body_append_bytes (msg->response_body, - full_response); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_message_body_append_bytes (soup_server_message_get_response_body (msg), + full_response); } static void diff --git a/tests/redirect-test.c b/tests/redirect-test.c index d360065a..9ecc2e2d 100644 --- a/tests/redirect-test.c +++ b/tests/redirect-test.c @@ -287,72 +287,82 @@ do_async_req_api_test (gconstpointer test) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { char *remainder; guint status_code; + SoupMessageHeaders *response_headers; + const char *method; /* Make sure that a HTTP/1.0 redirect doesn't cause an * HTTP/1.0 re-request. (#521848) */ - if (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) { - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) { + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return; } + method = soup_server_message_get_method (msg); + response_headers = soup_server_message_get_response_headers (msg); + if (g_str_has_prefix (path, "/bad")) { if (!strcmp (path, "/bad")) { - soup_message_set_status (msg, SOUP_STATUS_FOUND); - soup_message_headers_replace (msg->response_headers, + soup_server_message_set_status (msg, SOUP_STATUS_FOUND, NULL); + soup_message_headers_replace (response_headers, "Location", "/bad with spaces"); } else if (!strcmp (path, "/bad-recursive")) { - soup_message_set_status (msg, SOUP_STATUS_FOUND); - soup_message_headers_replace (msg->response_headers, + soup_server_message_set_status (msg, SOUP_STATUS_FOUND, NULL); + soup_message_headers_replace (response_headers, "Location", "/bad-recursive"); } else if (!strcmp (path, "/bad-no-host")) { - soup_message_set_status (msg, SOUP_STATUS_FOUND); - soup_message_headers_replace (msg->response_headers, + soup_server_message_set_status (msg, SOUP_STATUS_FOUND, NULL); + soup_message_headers_replace (response_headers, "Location", "about:blank"); } else if (!strcmp (path, "/bad with spaces")) - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); else - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL); return; } else if (!strcmp (path, "/server2")) { - soup_message_set_status (msg, SOUP_STATUS_FOUND); - soup_message_headers_replace (msg->response_headers, + soup_server_message_set_status (msg, SOUP_STATUS_FOUND, NULL); + soup_message_headers_replace (response_headers, "Location", server2_uri); return; } else if (!strcmp (path, "/")) { - if (msg->method != SOUP_METHOD_GET && - msg->method != SOUP_METHOD_HEAD) { - soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); + SoupMessageBody *request_body; + + if (method != SOUP_METHOD_GET && + method != SOUP_METHOD_HEAD) { + soup_server_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED, NULL); return; } /* Make sure that redirecting a POST clears the body */ - if (msg->request_body->length) { - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + request_body = soup_server_message_get_request_body (msg); + if (request_body->length) { + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); /* FIXME: this is wrong, though it doesn't matter for * the purposes of this test, and to do the right * thing currently we'd have to set Content-Length by * hand. */ - if (msg->method != SOUP_METHOD_HEAD) { - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "OK\r\n", 4); + if (method != SOUP_METHOD_HEAD) { + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "OK\r\n", 4); } return; } @@ -360,7 +370,7 @@ server_callback (SoupServer *server, SoupMessage *msg, status_code = strtoul (path + 1, &remainder, 10); if (!SOUP_STATUS_IS_REDIRECTION (status_code) || (*remainder && *remainder != '/')) { - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL); return; } @@ -369,18 +379,20 @@ server_callback (SoupServer *server, SoupMessage *msg, * the rest of the time. */ if (*remainder == '/') - soup_message_set_http_version (msg, SOUP_HTTP_1_0); + soup_server_message_set_http_version (msg, SOUP_HTTP_1_0); - soup_message_set_redirect (msg, status_code, - *remainder ? remainder : "/"); + soup_server_message_set_redirect (msg, status_code, + *remainder ? remainder : "/"); } static void -server2_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server2_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } int diff --git a/tests/request-body-test.c b/tests/request-body-test.c index fb5cd31d..fad90c7f 100644 --- a/tests/request-body-test.c +++ b/tests/request-body-test.c @@ -138,30 +138,32 @@ do_request_test (gconstpointer data) } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { SoupMessageBody *md5_body; char *md5; if (g_str_has_prefix (path, "/redirect")) { - soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/"); + soup_server_message_set_redirect (msg, SOUP_STATUS_FOUND, "/"); return; } - if (msg->method == SOUP_METHOD_PUT) { - soup_message_set_status (msg, SOUP_STATUS_CREATED); - md5_body = msg->request_body; + if (soup_server_message_get_method (msg) == SOUP_METHOD_PUT) { + soup_server_message_set_status (msg, SOUP_STATUS_CREATED, NULL); + md5_body = soup_server_message_get_request_body (msg); } else { - soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); + soup_server_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED, NULL); return; } md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5, (guchar *)md5_body->data, md5_body->length); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (soup_server_message_get_response_headers (msg), "Content-MD5", md5); g_free (md5); } diff --git a/tests/server-auth-test.c b/tests/server-auth-test.c index dd92f1a6..54910967 100644 --- a/tests/server-auth-test.c +++ b/tests/server-auth-test.c @@ -227,15 +227,20 @@ do_server_auth_test (gconstpointer data) } static gboolean -basic_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, - const char *username, const char *password, gpointer data) +basic_auth_callback (SoupAuthDomain *auth_domain, + SoupServerMessage *msg, + const char *username, + const char *password, + gpointer data) { return !strcmp (username, "user") && !strcmp (password, "password"); } static char * -digest_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, - const char *username, gpointer data) +digest_auth_callback (SoupAuthDomain *auth_domain, + SoupServerMessage *msg, + const char *username, + gpointer data) { if (strcmp (username, "user") != 0) return NULL; @@ -251,27 +256,33 @@ digest_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_HEAD) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + const char *method; + + method = soup_server_message_get_method (msg); + if (method != SOUP_METHOD_GET && method != SOUP_METHOD_HEAD) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "OK\r\n", 4); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "OK\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } static void -got_headers_callback (SoupMessage *msg, gpointer data) +got_headers_callback (SoupServerMessage *msg, + gpointer data) { 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), "Authorization"); if (header) { if (strstr (header, "Basic ")) @@ -282,11 +293,12 @@ got_headers_callback (SoupMessage *msg, gpointer data) } static void -wrote_headers_callback (SoupMessage *msg, gpointer data) +wrote_headers_callback (SoupServerMessage *msg, + gpointer data) { const char *header; - header = soup_message_headers_get_list (msg->response_headers, + header = soup_message_headers_get_list (soup_server_message_get_response_headers (msg), "WWW-Authenticate"); if (header) { if (strstr (header, "Basic ")) @@ -297,12 +309,13 @@ wrote_headers_callback (SoupMessage *msg, gpointer data) } static void -request_started_callback (SoupServer *server, SoupMessage *msg, - SoupClientContext *client, gpointer data) +request_started_callback (SoupServer *server, + SoupServerMessage *msg, + gpointer data) { - g_signal_connect (msg, "got_headers", + g_signal_connect (msg, "got-headers", G_CALLBACK (got_headers_callback), NULL); - g_signal_connect (msg, "wrote_headers", + g_signal_connect (msg, "wrote-headers", G_CALLBACK (wrote_headers_callback), NULL); } diff --git a/tests/server-test.c b/tests/server-test.c index 3c5a1cab..8b18f8a7 100644 --- a/tests/server-test.c +++ b/tests/server-test.c @@ -14,27 +14,32 @@ typedef struct { } ServerData; static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - soup_message_headers_append (msg->response_headers, + const char *method; + + soup_message_headers_append (soup_server_message_get_response_headers (msg), "X-Handled-By", "server_callback"); if (!strcmp (path, "*")) { soup_test_assert (FALSE, "default server_callback got request for '*'"); - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, NULL); return; } - if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + method = soup_server_message_get_method (msg); + if (method != SOUP_METHOD_GET && method != SOUP_METHOD_POST) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, "index", 5); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, "index", 5); } static void @@ -90,25 +95,27 @@ server_teardown (ServerData *sd, gconstpointer test_data) } static void -server_star_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_star_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (soup_server_message_get_response_headers (msg), "X-Handled-By", "star_callback"); if (strcmp (path, "*") != 0) { soup_test_assert (FALSE, "server_star_callback got request for '%s'", path); - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, NULL); return; } - if (msg->method != SOUP_METHOD_OPTIONS) { - soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); + if (soup_server_message_get_method (msg) != SOUP_METHOD_OPTIONS) { + soup_server_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } /* Server handlers for "*" work but are separate from handlers for @@ -345,26 +352,28 @@ do_dot_dot_test (ServerData *sd, gconstpointer test_data) } static void -ipv6_server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +ipv6_server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { const char *host; GSocketAddress *addr; char expected_host[128]; - addr = soup_client_context_get_local_address (context); + addr = soup_server_message_get_local_address (msg); g_snprintf (expected_host, sizeof (expected_host), "[::1]:%d", g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr))); - host = soup_message_headers_get_one (msg->request_headers, "Host"); + host = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "Host"); g_assert_cmpstr (host, ==, expected_host); if (g_test_failed ()) - soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL); else - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } static void @@ -413,19 +422,21 @@ do_ipv6_test (ServerData *sd, gconstpointer test_data) } static void -multi_server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +multi_server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { GSocketAddress *addr; GInetSocketAddress *iaddr; SoupURI *uri; char *uristr, *addrstr; - addr = soup_client_context_get_local_address (context); + addr = soup_server_message_get_local_address (msg); iaddr = G_INET_SOCKET_ADDRESS (addr); - uri = soup_message_get_uri (msg); + uri = soup_server_message_get_uri (msg); uristr = soup_uri_to_string (uri, FALSE); addrstr = g_inet_address_to_string (g_inet_socket_address_get_address (iaddr)); @@ -436,9 +447,9 @@ multi_server_callback (SoupServer *server, SoupMessage *msg, /* FIXME ssl */ - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_TAKE, uristr, strlen (uristr)); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_TAKE, uristr, strlen (uristr)); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); } static void @@ -794,27 +805,29 @@ g_test_io_stream_new (GInputStream *input, GOutputStream *output) } static void -mem_server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +mem_server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { GSocketAddress *addr; GSocket *sock; const char *host; - addr = soup_client_context_get_local_address (context); + addr = soup_server_message_get_local_address (msg); g_assert_nonnull (addr); - addr = soup_client_context_get_remote_address (context); + addr = soup_server_message_get_remote_address (msg); g_assert_nonnull (addr); - sock = soup_client_context_get_socket (context); + sock = soup_server_message_get_socket (msg); g_assert_null (sock); - host = soup_client_context_get_host (context); + host = soup_server_message_get_remote_host (msg); g_assert_cmpstr (host, ==, "127.0.0.1"); - server_callback (server, msg, path, query, context, data); + server_callback (server, msg, path, query, data); } static void @@ -858,7 +871,7 @@ do_iostream_accept_test (void) typedef struct { SoupServer *server; - SoupMessage *smsg; + SoupServerMessage *smsg; gboolean handler_called; gboolean paused; } UnhandledServerData; @@ -873,15 +886,17 @@ idle_unpause_message (gpointer user_data) } static void -unhandled_server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +unhandled_server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { UnhandledServerData *usd = data; usd->handler_called = TRUE; - if (soup_message_headers_get_one (msg->request_headers, "X-Test-Server-Pause")) { + if (soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "X-Test-Server-Pause")) { usd->paused = TRUE; usd->server = server; usd->smsg = msg; @@ -946,7 +961,9 @@ do_fail_500_test (ServerData *sd, gconstpointer pause) } static void -stream_got_chunk (SoupMessage *msg, GBytes *chunk, gpointer user_data) +stream_got_chunk (SoupServerMessage *msg, + GBytes *chunk, + gpointer user_data) { GChecksum *checksum = user_data; @@ -954,26 +971,29 @@ stream_got_chunk (SoupMessage *msg, GBytes *chunk, gpointer user_data) } static void -stream_got_body (SoupMessage *msg, gpointer user_data) +stream_got_body (SoupServerMessage *msg, + gpointer user_data) { GChecksum *checksum = user_data; const char *md5 = g_checksum_get_string (checksum); - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY, - md5, strlen (md5)); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY, + md5, strlen (md5)); g_checksum_free (checksum); } static void -early_stream_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +early_stream_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { GChecksum *checksum; - if (msg->method != SOUP_METHOD_POST) { - soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); + if (soup_server_message_get_method (msg) != SOUP_METHOD_POST) { + soup_server_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED, NULL); return; } @@ -983,7 +1003,7 @@ early_stream_callback (SoupServer *server, SoupMessage *msg, g_signal_connect (msg, "got-body", G_CALLBACK (stream_got_body), checksum); - soup_message_body_set_accumulate (msg->request_body, TRUE); + soup_message_body_set_accumulate (soup_server_message_get_request_body (msg), TRUE); } static void @@ -1016,12 +1036,14 @@ do_early_stream_test (ServerData *sd, gconstpointer test_data) } static void -early_respond_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +early_respond_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { if (!strcmp (path, "/")) - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, NULL); } static void @@ -1040,7 +1062,6 @@ do_early_respond_test (ServerData *sd, gconstpointer test_data) msg = soup_message_new_from_uri ("GET", sd->base_uri); soup_test_session_send_message (session, msg); soup_test_assert_message_status (msg, SOUP_STATUS_FORBIDDEN); - g_assert_cmpint (msg->response_body->length, ==, 0); g_object_unref (msg); /* The early handler will ignore this one */ @@ -1057,11 +1078,13 @@ do_early_respond_test (ServerData *sd, gconstpointer test_data) } static void -early_multi_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +early_multi_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { - soup_message_headers_append (msg->response_headers, "X-Early", "yes"); + soup_message_headers_append (soup_server_message_get_response_headers (msg), "X-Early", "yes"); } static void @@ -1147,8 +1170,7 @@ typedef struct { typedef struct { SoupServer *self; - SoupMessage *msg; - SoupClientContext *context; + SoupServerMessage *msg; GCancellable *cancellable; TunnelEnd client, server; @@ -1272,11 +1294,12 @@ tunnel_read_cb (GObject *object, } static void -start_tunnel (SoupMessage *msg, gpointer user_data) +start_tunnel (SoupServerMessage *msg, + gpointer user_data) { Tunnel *tunnel = user_data; - tunnel->client.iostream = soup_client_context_steal_connection (tunnel->context); + tunnel->client.iostream = soup_server_message_steal_connection (msg); tunnel->client.istream = g_io_stream_get_input_stream (tunnel->client.iostream); tunnel->client.ostream = g_io_stream_get_output_stream (tunnel->client.iostream); g_clear_object (&tunnel->self); @@ -1309,10 +1332,10 @@ tunnel_connected_cb (GObject *object, tunnel->server.iostream = (GIOStream *) g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (object), result, &error); if (!tunnel->server.iostream) { - soup_message_set_status (tunnel->msg, SOUP_STATUS_BAD_GATEWAY); - soup_message_set_response (tunnel->msg, "text/plain", - SOUP_MEMORY_COPY, - error->message, strlen (error->message)); + soup_server_message_set_status (tunnel->msg, SOUP_STATUS_BAD_GATEWAY, NULL); + soup_server_message_set_response (tunnel->msg, "text/plain", + SOUP_MEMORY_COPY, + error->message, strlen (error->message)); g_error_free (error); soup_server_unpause_message (tunnel->self, tunnel->msg); tunnel_close (tunnel); @@ -1322,23 +1345,25 @@ tunnel_connected_cb (GObject *object, tunnel->server.istream = g_io_stream_get_input_stream (tunnel->server.iostream); tunnel->server.ostream = g_io_stream_get_output_stream (tunnel->server.iostream); - soup_message_set_status (tunnel->msg, SOUP_STATUS_OK); + soup_server_message_set_status (tunnel->msg, SOUP_STATUS_OK, NULL); soup_server_unpause_message (tunnel->self, tunnel->msg); g_signal_connect (tunnel->msg, "wrote-body", G_CALLBACK (start_tunnel), tunnel); } static void -proxy_server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +proxy_server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { GSocketClient *sclient; SoupURI *dest_uri; Tunnel *tunnel; - if (msg->method != SOUP_METHOD_CONNECT) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + if (soup_server_message_get_method (msg) != SOUP_METHOD_CONNECT) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } @@ -1347,9 +1372,8 @@ proxy_server_callback (SoupServer *server, SoupMessage *msg, tunnel = g_new0 (Tunnel, 1); tunnel->self = g_object_ref (server); tunnel->msg = g_object_ref (msg); - tunnel->context = context; - dest_uri = soup_message_get_uri (msg); + dest_uri = soup_server_message_get_uri (msg); sclient = g_socket_client_new (); g_socket_client_connect_to_host_async (sclient, dest_uri->host, dest_uri->port, NULL, tunnel_connected_cb, tunnel); diff --git a/tests/session-test.c b/tests/session-test.c index a3952f7d..be85d669 100644 --- a/tests/session-test.c +++ b/tests/session-test.c @@ -18,10 +18,9 @@ timeout_cb (gpointer user_data) static void server_handler (SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, GHashTable *query, - SoupClientContext *client, gpointer user_data) { if (!strcmp (path, "/request-timeout")) { @@ -35,10 +34,10 @@ server_handler (SoupServer *server, } else server_processed_message = TRUE; - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "ok\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "ok\r\n", 4); } static void diff --git a/tests/sniffing-test.c b/tests/sniffing-test.c index 98547a34..e81811b0 100644 --- a/tests/sniffing-test.c +++ b/tests/sniffing-test.c @@ -10,27 +10,32 @@ SoupURI *base_uri; SoupMessageBody *chunk_data; static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { GError *error = NULL; char *query_key; GBytes *response = NULL; gsize offset; + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; gboolean empty_response = FALSE; - if (msg->method != SOUP_METHOD_GET) { - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) { + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + response_headers = soup_server_message_get_response_headers (msg); if (query) { query_key = g_hash_table_lookup (query, "chunked"); if (query_key && g_str_equal (query_key, "yes")) { - soup_message_headers_set_encoding (msg->response_headers, + soup_message_headers_set_encoding (response_headers, SOUP_ENCODING_CHUNKED); } @@ -45,7 +50,7 @@ server_callback (SoupServer *server, SoupMessage *msg, g_assert_no_error (error); } - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "text/plain"); } @@ -56,10 +61,10 @@ server_callback (SoupServer *server, SoupMessage *msg, g_assert_no_error (error); g_free (base_name); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "X-Content-Type-Options", "nosniff"); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "no/sniffing-allowed"); } @@ -70,7 +75,7 @@ server_callback (SoupServer *server, SoupMessage *msg, g_assert_no_error (error); g_free (base_name); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "text/plain"); } @@ -81,7 +86,7 @@ server_callback (SoupServer *server, SoupMessage *msg, g_assert_no_error (error); g_free (base_name); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "UNKNOWN/unknown"); } @@ -99,7 +104,7 @@ server_callback (SoupServer *server, SoupMessage *msg, ptr = g_strrstr (components[2], "_"); *ptr = '/'; - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", components[2]); g_strfreev (components); } @@ -111,24 +116,25 @@ server_callback (SoupServer *server, SoupMessage *msg, g_assert_no_error (error); g_free (base_name); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "text/xml"); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (response_headers, "Content-Type", "text/plain"); } + response_body = soup_server_message_get_response_body (msg); if (response) { - gsize response_size = g_bytes_get_size (response); + gsize response_size = g_bytes_get_size (response); for (offset = 0; offset < response_size; offset += 500) { GBytes *chunk = g_bytes_new_from_bytes (response, offset, MIN (500, response_size - offset)); - soup_message_body_append_bytes (msg->response_body, chunk); + soup_message_body_append_bytes (response_body, chunk); g_bytes_unref (chunk); } g_bytes_unref (response); } - soup_message_body_complete (msg->response_body); + soup_message_body_complete (response_body); } static gboolean @@ -229,7 +235,9 @@ do_signals_test (gboolean should_content_sniff, soup_message_set_uri (msg, uri); +#if 0 soup_message_body_set_accumulate (msg->response_body, should_accumulate); +#endif g_object_connect (msg, "signal::got-headers", got_headers, GINT_TO_POINTER (should_pause), @@ -258,8 +266,10 @@ do_signals_test (gboolean should_content_sniff, if (!should_accumulate && chunk_data) body = soup_message_body_flatten (chunk_data); +#if 0 else if (msg->response_body) body = soup_message_body_flatten (msg->response_body); +#endif if (body) { //g_message ("|||body (%zu): %s", g_bytes_get_size (body), (char*)g_bytes_get_data (body, NULL)); diff --git a/tests/ssl-test.c b/tests/ssl-test.c index 1422834a..c314b2d7 100644 --- a/tests/ssl-test.c +++ b/tests/ssl-test.c @@ -238,16 +238,15 @@ do_tls_interaction_test (void) static void server_handler (SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, GHashTable *query, - SoupClientContext *client, gpointer user_data) { - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "ok\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "ok\r\n", 4); } int diff --git a/tests/streaming-test.c b/tests/streaming-test.c index b1a10d54..a9280cb8 100644 --- a/tests/streaming-test.c +++ b/tests/streaming-test.c @@ -11,16 +11,20 @@ GBytes *full_response; char *full_response_md5; static void -write_next_chunk (SoupMessage *msg, gpointer user_data) +write_next_chunk (SoupServerMessage *msg, + gpointer user_data) { gsize *offset = user_data; gsize chunk_length; + SoupMessageBody *response_body; + + response_body = soup_server_message_get_response_body (msg); chunk_length = MIN (RESPONSE_CHUNK_SIZE, g_bytes_get_size (full_response) - *offset); if (chunk_length > 0) { debug_printf (2, " writing chunk\n"); GBytes *chunk = g_bytes_new_from_bytes (full_response, *offset, chunk_length); - soup_message_body_append_bytes (msg->response_body, chunk); + soup_message_body_append_bytes (response_body, chunk); g_bytes_unref (chunk); *offset += chunk_length; } else { @@ -29,44 +33,49 @@ write_next_chunk (SoupMessage *msg, gpointer user_data) * cases, but it's harmless in the content-length * case. */ - soup_message_body_complete (msg->response_body); + soup_message_body_complete (response_body); } } static void -free_offset (SoupMessage *msg, gpointer offset) +free_offset (SoupServerMessage *msg, + gpointer offset) { g_free (offset); } static void -server_callback (SoupServer *server, SoupMessage *msg, - const char *path, GHashTable *query, - SoupClientContext *context, gpointer data) +server_callback (SoupServer *server, + SoupServerMessage *msg, + const char *path, + GHashTable *query, + gpointer data) { gsize *offset; + SoupMessageHeaders *response_headers; + response_headers = soup_server_message_get_response_headers (msg); if (!strcmp (path, "/chunked")) { - soup_message_headers_set_encoding (msg->response_headers, + soup_message_headers_set_encoding (response_headers, SOUP_ENCODING_CHUNKED); } else if (!strcmp (path, "/content-length")) { - soup_message_headers_set_encoding (msg->response_headers, + soup_message_headers_set_encoding (response_headers, SOUP_ENCODING_CONTENT_LENGTH); - soup_message_headers_set_content_length (msg->response_headers, + soup_message_headers_set_content_length (response_headers, g_bytes_get_size (full_response)); } else if (!strcmp (path, "/eof")) { - soup_message_headers_set_encoding (msg->response_headers, + soup_message_headers_set_encoding (response_headers, SOUP_ENCODING_EOF); } else { - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, NULL); return; } - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); offset = g_new0 (gsize, 1); - g_signal_connect (msg, "wrote_headers", + g_signal_connect (msg, "wrote-headers", G_CALLBACK (write_next_chunk), offset); - g_signal_connect (msg, "wrote_chunk", + g_signal_connect (msg, "wrote-chunk", G_CALLBACK (write_next_chunk), offset); g_signal_connect (msg, "finished", G_CALLBACK (free_offset), offset); diff --git a/tests/timeout-test.c b/tests/timeout-test.c index 17977434..b3325e42 100644 --- a/tests/timeout-test.c +++ b/tests/timeout-test.c @@ -287,16 +287,15 @@ timeout_finish_message (gpointer msg) static void server_handler (SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, GHashTable *query, - SoupClientContext *client, gpointer user_data) { - soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_response (msg, "text/plain", - SOUP_MEMORY_STATIC, - "ok\r\n", 4); + soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL); + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "ok\r\n", 4); if (!strcmp (path, "/slow")) { soup_server_pause_message (server, msg); diff --git a/tests/websocket-test.c b/tests/websocket-test.c index 5e40cf36..c3a401ce 100644 --- a/tests/websocket-test.c +++ b/tests/websocket-test.c @@ -19,7 +19,7 @@ */ #include "test-utils.h" - +#include "soup-server-message-private.h" #include <zlib.h> typedef struct { @@ -291,9 +291,9 @@ client_connect (Test *test, static void got_server_connection (SoupServer *server, - SoupWebsocketConnection *connection, + SoupServerMessage *msg, const char *path, - SoupClientContext *client, + SoupWebsocketConnection *connection, gpointer user_data) { Test *test = user_data; @@ -415,10 +415,12 @@ test_handshake (Test *test, } static void -websocket_server_request_started (SoupServer *server, SoupMessage *msg, - SoupClientContext *client, gpointer user_data) +websocket_server_request_started (SoupServer *server, + SoupServerMessage *msg, + gpointer user_data) { - soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Extensions", "x-foo"); + soup_message_headers_append (soup_server_message_get_response_headers (msg), + "Sec-WebSocket-Extensions", "x-foo"); } static void @@ -639,6 +641,11 @@ test_protocol_negotiate_direct (Test *test, gconstpointer unused) { SoupMessage *msg; + SoupServerMessage *server_msg; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageHeadersIter iter; + const char *name, *value; gboolean ok; const char *protocol; GError *error = NULL; @@ -647,16 +654,28 @@ test_protocol_negotiate_direct (Test *test, soup_websocket_client_prepare_handshake (msg, NULL, (char **) negotiate_client_protocols); - ok = soup_websocket_server_check_handshake (msg, NULL, + server_msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + soup_server_message_set_method (server_msg, msg->method); + soup_server_message_set_uri (server_msg, soup_message_get_uri (msg)); + request_headers = soup_server_message_get_request_headers (server_msg); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (request_headers, name, value); + ok = soup_websocket_server_check_handshake (server_msg, NULL, (char **) negotiate_server_protocols, &error); g_assert_no_error (error); g_assert_true (ok); - ok = soup_websocket_server_process_handshake (msg, NULL, + ok = soup_websocket_server_process_handshake (server_msg, NULL, (char **) negotiate_server_protocols); g_assert_true (ok); + msg->status_code = soup_server_message_get_status (server_msg, NULL); + response_headers = soup_server_message_get_response_headers (server_msg); + soup_message_headers_iter_init (&iter, response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (msg->response_headers, name, value); protocol = soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"); g_assert_cmpstr (protocol, ==, negotiated_protocol); @@ -665,6 +684,7 @@ test_protocol_negotiate_direct (Test *test, g_assert_true (ok); g_object_unref (msg); + g_object_unref (server_msg); } static void @@ -689,6 +709,11 @@ test_protocol_mismatch_direct (Test *test, gconstpointer unused) { SoupMessage *msg; + SoupServerMessage *server_msg; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageHeadersIter iter; + const char *name, *value; gboolean ok; const char *protocol; GError *error = NULL; @@ -697,18 +722,30 @@ test_protocol_mismatch_direct (Test *test, soup_websocket_client_prepare_handshake (msg, NULL, (char **) mismatch_client_protocols); - ok = soup_websocket_server_check_handshake (msg, NULL, + server_msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + soup_server_message_set_method (server_msg, msg->method); + soup_server_message_set_uri (server_msg, soup_message_get_uri (msg)); + request_headers = soup_server_message_get_request_headers (server_msg); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (request_headers, name, value); + ok = soup_websocket_server_check_handshake (server_msg, NULL, (char **) mismatch_server_protocols, &error); g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE); g_clear_error (&error); g_assert_false (ok); - ok = soup_websocket_server_process_handshake (msg, NULL, + ok = soup_websocket_server_process_handshake (server_msg, NULL, (char **) mismatch_server_protocols); g_assert_false (ok); + msg->status_code = soup_server_message_get_status (server_msg, NULL); soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST); + response_headers = soup_server_message_get_response_headers (server_msg); + soup_message_headers_iter_init (&iter, response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (msg->response_headers, name, value); protocol = soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"); g_assert_cmpstr (protocol, ==, NULL); @@ -718,6 +755,7 @@ test_protocol_mismatch_direct (Test *test, g_assert_false (ok); g_object_unref (msg); + g_object_unref (server_msg); } static void @@ -738,6 +776,11 @@ test_protocol_server_any_direct (Test *test, gconstpointer unused) { SoupMessage *msg; + SoupServerMessage *server_msg; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageHeadersIter iter; + const char *name, *value; gboolean ok; const char *protocol; GError *error = NULL; @@ -745,13 +788,25 @@ test_protocol_server_any_direct (Test *test, msg = soup_message_new ("GET", "http://127.0.0.1"); soup_websocket_client_prepare_handshake (msg, NULL, (char **) all_protocols); - ok = soup_websocket_server_check_handshake (msg, NULL, NULL, &error); + server_msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + soup_server_message_set_method (server_msg, msg->method); + soup_server_message_set_uri (server_msg, soup_message_get_uri (msg)); + request_headers = soup_server_message_get_request_headers (server_msg); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (request_headers, name, value); + ok = soup_websocket_server_check_handshake (server_msg, NULL, NULL, &error); g_assert_no_error (error); g_assert_true (ok); - ok = soup_websocket_server_process_handshake (msg, NULL, NULL); + ok = soup_websocket_server_process_handshake (server_msg, NULL, NULL); g_assert_true (ok); + msg->status_code = soup_server_message_get_status (server_msg, NULL); + response_headers = soup_server_message_get_response_headers (server_msg); + soup_message_headers_iter_init (&iter, response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (msg->response_headers, name, value); protocol = soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"); g_assert_cmpstr (protocol, ==, NULL); @@ -760,6 +815,7 @@ test_protocol_server_any_direct (Test *test, g_assert_true (ok); g_object_unref (msg); + g_object_unref (server_msg); } static void @@ -782,6 +838,11 @@ test_protocol_client_any_direct (Test *test, gconstpointer unused) { SoupMessage *msg; + SoupServerMessage *server_msg; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageHeadersIter iter; + const char *name, *value; gboolean ok; const char *protocol; GError *error = NULL; @@ -789,13 +850,25 @@ test_protocol_client_any_direct (Test *test, msg = soup_message_new ("GET", "http://127.0.0.1"); soup_websocket_client_prepare_handshake (msg, NULL, NULL); - ok = soup_websocket_server_check_handshake (msg, NULL, (char **) all_protocols, &error); + server_msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + soup_server_message_set_method (server_msg, msg->method); + soup_server_message_set_uri (server_msg, soup_message_get_uri (msg)); + request_headers = soup_server_message_get_request_headers (server_msg); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (request_headers, name, value); + ok = soup_websocket_server_check_handshake (server_msg, NULL, (char **) all_protocols, &error); g_assert_no_error (error); g_assert_true (ok); - ok = soup_websocket_server_process_handshake (msg, NULL, (char **) all_protocols); + ok = soup_websocket_server_process_handshake (server_msg, NULL, (char **) all_protocols); g_assert_true (ok); + msg->status_code = soup_server_message_get_status (server_msg, NULL); + response_headers = soup_server_message_get_response_headers (server_msg); + soup_message_headers_iter_init (&iter, response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (msg->response_headers, name, value); protocol = soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"); g_assert_cmpstr (protocol, ==, NULL); @@ -804,6 +877,7 @@ test_protocol_client_any_direct (Test *test, g_assert_true (ok); g_object_unref (msg); + g_object_unref (server_msg); } static void @@ -1431,9 +1505,9 @@ test_server_receive_unmasked_frame (Test *test, static void test_client_context_got_server_connection (SoupServer *server, - SoupWebsocketConnection *connection, + SoupServerMessage *msg, const char *path, - SoupClientContext *client, + SoupWebsocketConnection *connection, gpointer user_data) { Test *test = user_data; @@ -1442,7 +1516,7 @@ test_client_context_got_server_connection (SoupServer *server, char *str; const char *remote_ip; - addr = soup_client_context_get_local_address (client); + addr = soup_server_message_get_local_address (msg); iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)); str = g_inet_address_to_string (iaddr); if (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4) @@ -1451,7 +1525,7 @@ test_client_context_got_server_connection (SoupServer *server, g_assert_cmpstr (str, ==, "::1"); g_free (str); - addr = soup_client_context_get_remote_address (client); + addr = soup_server_message_get_remote_address (msg); iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)); str = g_inet_address_to_string (iaddr); if (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4) @@ -1459,7 +1533,7 @@ test_client_context_got_server_connection (SoupServer *server, else g_assert_cmpstr (str, ==, "::1"); - remote_ip = soup_client_context_get_host (client); + remote_ip = soup_server_message_get_remote_host (msg); g_assert_cmpstr (remote_ip, ==, str); g_free (str); @@ -1610,6 +1684,11 @@ test_deflate_negotiate_direct (Test *test, for (i = 0; i < G_N_ELEMENTS (deflate_negotiate_tests); i++) { SoupMessage *msg; + SoupServerMessage *server_msg; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageHeadersIter iter; + const char *name, *value; gboolean result; GList *accepted_extensions = NULL; GError *error = NULL; @@ -1618,7 +1697,15 @@ test_deflate_negotiate_direct (Test *test, soup_websocket_client_prepare_handshake (msg, NULL, NULL); soup_message_headers_append (msg->request_headers, "Sec-WebSocket-Extensions", deflate_negotiate_tests[i].client_extension); - result = soup_websocket_server_check_handshake_with_extensions (msg, NULL, NULL, + + server_msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + soup_server_message_set_method (server_msg, msg->method); + soup_server_message_set_uri (server_msg, soup_message_get_uri (msg)); + request_headers = soup_server_message_get_request_headers (server_msg); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (request_headers, name, value); + result = soup_websocket_server_check_handshake_with_extensions (server_msg, NULL, NULL, deflate_negotiate_tests[i].server_supports_extensions ? supported_extensions : NULL, &error); @@ -1630,11 +1717,17 @@ test_deflate_negotiate_direct (Test *test, g_clear_error (&error); } - result = soup_websocket_server_process_handshake_with_extensions (msg, NULL, NULL, + result = soup_websocket_server_process_handshake_with_extensions (server_msg, NULL, NULL, deflate_negotiate_tests[i].server_supports_extensions ? supported_extensions : NULL, &accepted_extensions); g_assert (result == deflate_negotiate_tests[i].expected_check_result); + + msg->status_code = soup_server_message_get_status (server_msg, NULL); + response_headers = soup_server_message_get_response_headers (server_msg); + soup_message_headers_iter_init (&iter, response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (msg->response_headers, name, value); if (deflate_negotiate_tests[i].expected_accepted_extension) { const char *extension; @@ -1668,6 +1761,7 @@ test_deflate_negotiate_direct (Test *test, } g_object_unref (msg); + g_object_unref (server_msg); } g_ptr_array_unref (supported_extensions); @@ -1678,6 +1772,11 @@ test_deflate_disabled_in_message_direct (Test *test, gconstpointer unused) { SoupMessage *msg; + SoupServerMessage *server_msg; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageHeadersIter iter; + const char *name, *value; GPtrArray *supported_extensions; GList *accepted_extensions = NULL; GError *error = NULL; @@ -1690,11 +1789,24 @@ test_deflate_disabled_in_message_direct (Test *test, soup_websocket_client_prepare_handshake_with_extensions (msg, NULL, NULL, supported_extensions); g_assert_cmpstr (soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Extensions"), ==, NULL); - g_assert_true (soup_websocket_server_check_handshake_with_extensions (msg, NULL, NULL, supported_extensions, &error)); + server_msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL); + soup_server_message_set_method (server_msg, msg->method); + soup_server_message_set_uri (server_msg, soup_message_get_uri (msg)); + request_headers = soup_server_message_get_request_headers (server_msg); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (request_headers, name, value); + + g_assert_true (soup_websocket_server_check_handshake_with_extensions (server_msg, NULL, NULL, supported_extensions, &error)); g_assert_no_error (error); - g_assert_true (soup_websocket_server_process_handshake_with_extensions (msg, NULL, NULL, supported_extensions, &accepted_extensions)); + g_assert_true (soup_websocket_server_process_handshake_with_extensions (server_msg, NULL, NULL, supported_extensions, &accepted_extensions)); g_assert_null (accepted_extensions); + msg->status_code = soup_server_message_get_status (server_msg, NULL); + response_headers = soup_server_message_get_response_headers (server_msg); + soup_message_headers_iter_init (&iter, response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + soup_message_headers_append (msg->response_headers, name, value); g_assert_cmpstr (soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Extensions"), ==, NULL); g_assert_true (soup_websocket_client_verify_handshake_with_extensions (msg, supported_extensions, &accepted_extensions, &error)); @@ -1702,6 +1814,7 @@ test_deflate_disabled_in_message_direct (Test *test, g_assert_null (accepted_extensions); g_object_unref (msg); + g_object_unref (server_msg); g_ptr_array_unref (supported_extensions); } @@ -1828,10 +1941,12 @@ test_cookies_in_request (Test *test, } static void -cookies_test_websocket_server_request_started (SoupServer *server, SoupMessage *msg, - SoupClientContext *client, gpointer user_data) +cookies_test_websocket_server_request_started (SoupServer *server, + SoupServerMessage *msg, + gpointer user_data) { - soup_message_headers_append (msg->response_headers, "Set-Cookie", "foo=bar; Path=/"); + soup_message_headers_append (soup_server_message_get_response_headers (msg), + "Set-Cookie", "foo=bar; Path=/"); } static void |