[libsoup/carlosgc/status: 1/5] Remove non-HTTP SoupStatus values




commit 64d8b462723b4cee38a51ae044ed7de8dd5b8325
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Thu Nov 12 15:34:02 2020 +0100

    Remove non-HTTP SoupStatus values
    
    Stop using the message status for internal or transport errors and
    always use GError for those.

 docs/reference/libsoup-3.0-sections.txt |   5 -
 libsoup/auth/soup-auth-negotiate.c      |  70 ++++----
 libsoup/cache/soup-cache.c              |   2 +-
 libsoup/hsts/soup-hsts-enforcer.c       |   2 +-
 libsoup/server/soup-server-io.c         |   6 +-
 libsoup/server/soup-server.c            |   6 +-
 libsoup/soup-message-io.c               |  64 +++-----
 libsoup/soup-session.c                  | 279 +++++++++++++-------------------
 libsoup/soup-session.h                  |   9 +-
 libsoup/soup-status.c                   |  57 -------
 libsoup/soup-status.h                   |  25 ---
 tests/auth-test.c                       |  17 +-
 tests/cache-test.c                      |  13 +-
 tests/connection-test.c                 |   4 +-
 tests/continue-test.c                   |   2 +-
 tests/hsts-db-test.c                    |  10 +-
 tests/hsts-test.c                       |  12 +-
 tests/misc-test.c                       |  68 ++++----
 tests/no-ssl-test.c                     |   8 +-
 tests/range-test.c                      |   4 +-
 tests/redirect-test.c                   |  72 +++++----
 tests/request-body-test.c               |   2 +-
 tests/server-test.c                     |  16 +-
 tests/session-test.c                    |  40 ++---
 tests/sniffing-test.c                   |   6 +-
 tests/ssl-test.c                        |  23 ++-
 tests/streaming-test.c                  |   2 +-
 tests/test-utils.c                      |  44 +++--
 tests/test-utils.h                      |   3 +-
 tests/timeout-test.c                    |   4 +-
 30 files changed, 364 insertions(+), 511 deletions(-)
---
diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt
index f66f50fc..fb476edf 100644
--- a/docs/reference/libsoup-3.0-sections.txt
+++ b/docs/reference/libsoup-3.0-sections.txt
@@ -201,7 +201,6 @@ soup_message_body_get_type
 <SECTION>
 <FILE>soup-status</FILE>
 <TITLE>SoupStatus</TITLE>
-SOUP_STATUS_IS_TRANSPORT_ERROR
 SOUP_STATUS_IS_INFORMATIONAL
 SOUP_STATUS_IS_SUCCESSFUL
 SOUP_STATUS_IS_REDIRECTION
@@ -210,10 +209,6 @@ SOUP_STATUS_IS_SERVER_ERROR
 SoupStatus
 soup_status_get_phrase
 soup_status_proxify
-<SUBSECTION>
-SOUP_HTTP_ERROR
-<SUBSECTION Private>
-soup_http_error_quark
 </SECTION>
 
 <SECTION>
diff --git a/libsoup/auth/soup-auth-negotiate.c b/libsoup/auth/soup-auth-negotiate.c
index 41215690..7b05f9bb 100644
--- a/libsoup/auth/soup-auth-negotiate.c
+++ b/libsoup/auth/soup-auth-negotiate.c
@@ -95,12 +95,12 @@ G_DEFINE_TYPE_WITH_PRIVATE (SoupAuthNegotiate, soup_auth_negotiate, SOUP_TYPE_CO
 static gboolean check_auth_trusted_uri (SoupConnectionAuth *auth,
                                        SoupMessage *msg);
 static gboolean soup_gss_build_response (SoupNegotiateConnectionState *conn,
-                                        SoupAuth *auth, GError **err);
+                                        SoupAuth *auth, char **error_message);
 static void soup_gss_client_cleanup (SoupNegotiateConnectionState *conn);
 static gboolean soup_gss_client_init (SoupNegotiateConnectionState *conn,
-                                     const char *authority, GError **err);
+                                     const char *authority, char **error_message);
 static int soup_gss_client_step (SoupNegotiateConnectionState *conn,
-                                const char *host, GError **err);
+                                const char *host, char **error_message);
 
 static GSList *trusted_uris;
 static GSList *blacklisted_uris;
@@ -194,23 +194,23 @@ soup_auth_negotiate_get_connection_authorization (SoupConnectionAuth *auth,
        char *header = NULL;
 
        if (conn->state == SOUP_NEGOTIATE_NEW) {
-               GError *err = NULL;
+               char *error_message = NULL;
 
                if (!check_auth_trusted_uri (auth, msg)) {
                        conn->state = SOUP_NEGOTIATE_FAILED;
                        return NULL;
                }
 
-               if (!soup_gss_build_response (conn, SOUP_AUTH (auth), &err)) {
-                        g_assert (err); /* Silence scan-build */
+               if (!soup_gss_build_response (conn, SOUP_AUTH (auth), &error_message)) {
+                       g_assert (error_message); /* Silence scan-build */
                        /* FIXME: report further upward via
                         * soup_message_get_error_message  */
                        if (conn->initialized)
-                               g_warning ("gssapi step failed: %s", err->message);
+                               g_warning ("gssapi step failed: %s", error_message);
                        else
-                               g_warning ("gssapi init failed: %s", err->message);
+                               g_warning ("gssapi init failed: %s", error_message);
                        conn->state = SOUP_NEGOTIATE_FAILED;
-                       g_clear_error (&err);
+                       g_clear_pointer (&error_message, g_free);
 
                        return NULL;
                }
@@ -243,7 +243,7 @@ soup_auth_negotiate_update_connection (SoupConnectionAuth *auth, SoupMessage *ms
 #ifdef LIBSOUP_HAVE_GSSAPI
        gboolean success = TRUE;
        SoupNegotiateConnectionState *conn = state;
-       GError *err = NULL;
+       char *error_message = NULL;
 
        if (!check_auth_trusted_uri (auth, msg)) {
                conn->state = SOUP_NEGOTIATE_FAILED;
@@ -260,7 +260,7 @@ soup_auth_negotiate_update_connection (SoupConnectionAuth *auth, SoupMessage *ms
                }
 
                conn->state = SOUP_NEGOTIATE_RECEIVED_CHALLENGE;
-               if (soup_gss_build_response (conn, SOUP_AUTH (auth), &err)) {
+               if (soup_gss_build_response (conn, SOUP_AUTH (auth), &error_message)) {
                        /* Connect the signal only once per message */
                        if (!g_object_get_data (G_OBJECT (msg), "negotiate-got-headers-connected")) {
                                /* Wait for the 2xx response to verify server response */
@@ -277,17 +277,17 @@ soup_auth_negotiate_update_connection (SoupConnectionAuth *auth, SoupMessage *ms
                        }
                        goto out;
                } else {
-                        g_assert (err); /* Silence scan-build */
+                        g_assert (error_message); /* Silence scan-build */
                        /* FIXME: report further upward via
                         * soup_message_get_error_message  */
                        if (conn->initialized)
-                               g_warning ("gssapi step failed: %s", err->message);
+                               g_warning ("gssapi step failed: %s", error_message);
                        else
-                               g_warning ("gssapi init failed: %s", err->message);
+                               g_warning ("gssapi init failed: %s", error_message);
                        success = FALSE;
                }
        } else if (!strncmp (header, "Negotiate ", 10)) {
-               if (soup_gss_client_step (conn, header + 10, &err) == AUTH_GSS_CONTINUE) {
+               if (soup_gss_client_step (conn, header + 10, &error_message) == AUTH_GSS_CONTINUE) {
                        conn->state = SOUP_NEGOTIATE_RECEIVED_CHALLENGE;
                        goto out;
                }
@@ -295,7 +295,7 @@ soup_auth_negotiate_update_connection (SoupConnectionAuth *auth, SoupMessage *ms
 
        conn->state = SOUP_NEGOTIATE_FAILED;
  out:
-       g_clear_error (&err);
+       g_clear_pointer (&error_message, g_free);
        return success;
 #else
        return FALSE;
@@ -343,7 +343,7 @@ check_server_response (SoupMessage *msg, gpointer auth)
 {
        gint ret;
        const char *auth_headers;
-       GError *err = NULL;
+       char *error_message = NULL;
        SoupAuthNegotiate *negotiate = auth;
        SoupAuthNegotiatePrivate *priv = soup_auth_negotiate_get_instance_private (negotiate);
        SoupNegotiateConnectionState *conn;
@@ -367,7 +367,7 @@ check_server_response (SoupMessage *msg, gpointer auth)
                goto out;
        }
 
-       ret = soup_gss_client_step (conn, auth_headers + 10, &err);
+       ret = soup_gss_client_step (conn, auth_headers + 10, &error_message);
 
        switch (ret) {
        case AUTH_GSS_COMPLETE:
@@ -377,8 +377,9 @@ check_server_response (SoupMessage *msg, gpointer auth)
                conn->state = SOUP_NEGOTIATE_RECEIVED_CHALLENGE;
                break;
        case AUTH_GSS_ERROR:
-               if (err)
-                       g_warning ("%s", err->message);
+               if (error_message)
+                       g_warning ("%s", error_message);
+
                /* Unfortunately, so many programs (curl, Firefox, ..) ignore
                 * the return token that is included in the response, so it is
                 * possible that there are servers that send back broken stuff.
@@ -394,7 +395,7 @@ check_server_response (SoupMessage *msg, gpointer auth)
                conn->state = SOUP_NEGOTIATE_FAILED;
        }
  out:
-       g_clear_error (&err);
+       g_clear_pointer (&error_message, g_free);
 }
 
 /* Check if scheme://host:port from message matches the given URI. */
@@ -471,20 +472,20 @@ check_auth_trusted_uri (SoupConnectionAuth *auth, SoupMessage *msg)
 }
 
 static gboolean
-soup_gss_build_response (SoupNegotiateConnectionState *conn, SoupAuth *auth, GError **err)
+soup_gss_build_response (SoupNegotiateConnectionState *conn, SoupAuth *auth, char **error_message)
 {
        if (!conn->initialized)
-               if (!soup_gss_client_init (conn, soup_auth_get_authority (auth), err))
+               if (!soup_gss_client_init (conn, soup_auth_get_authority (auth), error_message))
                        return FALSE;
 
-       if (soup_gss_client_step (conn, "", err) != AUTH_GSS_CONTINUE)
+       if (soup_gss_client_step (conn, "", error_message) != AUTH_GSS_CONTINUE)
                return FALSE;
 
        return TRUE;
 }
 
 static void
-soup_gss_error (OM_uint32 err_maj, OM_uint32 err_min, GError **err)
+soup_gss_error (OM_uint32 err_maj, OM_uint32 err_min, char **error_message)
 {
        OM_uint32 maj_stat, min_stat, msg_ctx = 0;
        gss_buffer_desc status;
@@ -514,14 +515,11 @@ soup_gss_error (OM_uint32 err_maj, OM_uint32 err_min, GError **err)
                        gss_release_buffer (&min_stat, &status);
                }
 
-               if (err && *err == NULL) {
-                       g_set_error (err,
-                                    SOUP_HTTP_ERROR,
-                                    SOUP_STATUS_UNAUTHORIZED,
-                                    "%s: %s",
-                                    buf_maj,
-                                    buf_min ? buf_min : "");
+               if (error_message && *error_message == NULL) {
+                       *error_message = g_strdup_printf ("%s: %s", buf_maj,
+                                                         buf_min ? buf_min : "");
                }
+
                g_free (buf_maj);
                g_free (buf_min);
                buf_min = buf_maj = NULL;
@@ -529,7 +527,7 @@ soup_gss_error (OM_uint32 err_maj, OM_uint32 err_min, GError **err)
 }
 
 static gboolean
-soup_gss_client_init (SoupNegotiateConnectionState *conn, const gchar *authority, GError **err)
+soup_gss_client_init (SoupNegotiateConnectionState *conn, const gchar *authority, char **error_message)
 {
        OM_uint32 maj_stat, min_stat;
        gchar *service = NULL;
@@ -553,7 +551,7 @@ soup_gss_client_init (SoupNegotiateConnectionState *conn, const gchar *authority
                                    &conn->server_name);
 
        if (GSS_ERROR (maj_stat)) {
-               soup_gss_error (maj_stat, min_stat, err);
+               soup_gss_error (maj_stat, min_stat, error_message);
                ret = FALSE;
                goto out;
        }
@@ -567,7 +565,7 @@ out:
 }
 
 static gint
-soup_gss_client_step (SoupNegotiateConnectionState *conn, const gchar *challenge, GError **err)
+soup_gss_client_step (SoupNegotiateConnectionState *conn, const gchar *challenge, char **error_message)
 {
        OM_uint32 maj_stat, min_stat;
        gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
@@ -597,7 +595,7 @@ soup_gss_client_step (SoupNegotiateConnectionState *conn, const gchar *challenge
                                         NULL);
 
        if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
-               soup_gss_error (maj_stat, min_stat, err);
+               soup_gss_error (maj_stat, min_stat, error_message);
                ret = AUTH_GSS_ERROR;
                goto out;
        }
diff --git a/libsoup/cache/soup-cache.c b/libsoup/cache/soup-cache.c
index cd0ab5de..68ba5f26 100644
--- a/libsoup/cache/soup-cache.c
+++ b/libsoup/cache/soup-cache.c
@@ -1425,7 +1425,7 @@ soup_cache_cancel_conditional_request (SoupCache   *cache,
        if (entry)
                entry->being_validated = FALSE;
 
-       soup_session_cancel_message (priv->session, msg, SOUP_STATUS_CANCELLED);
+       soup_session_cancel_message (priv->session, msg, SOUP_STATUS_NONE);
 }
 
 void
diff --git a/libsoup/hsts/soup-hsts-enforcer.c b/libsoup/hsts/soup-hsts-enforcer.c
index 8925f5ac..1889e98e 100644
--- a/libsoup/hsts/soup-hsts-enforcer.c
+++ b/libsoup/hsts/soup-hsts-enforcer.c
@@ -534,7 +534,7 @@ on_sts_known_host_message_starting (SoupMessage *msg, SoupHSTSEnforcer *hsts_enf
 
        errors = soup_message_get_tls_certificate_errors (msg);
        if (errors)
-               soup_session_cancel_message (priv->session, msg, SOUP_STATUS_CANCELLED);
+               soup_session_cancel_message (priv->session, msg, SOUP_STATUS_NONE);
 }
 
 static void
diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c
index ed467e9f..aaf7829f 100644
--- a/libsoup/server/soup-server-io.c
+++ b/libsoup/server/soup-server-io.c
@@ -659,7 +659,7 @@ io_read (SoupServerMessage *msg,
         case SOUP_MESSAGE_IO_STATE_HEADERS:
                 if (!soup_message_io_data_read_headers (io, FALSE, NULL, error)) {
                        if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT))
-                               soup_server_message_set_status (msg, SOUP_STATUS_MALFORMED, NULL);
+                               soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
                         return FALSE;
                }
 
@@ -851,9 +851,7 @@ io_run (SoupServerMessage *msg)
                                                                 NULL);
                 g_source_attach (io->io_source, io->async_context);
         } else if (soup_server_message_get_io_data (msg) == server_io) {
-               if (!SOUP_STATUS_IS_TRANSPORT_ERROR (soup_server_message_get_status (msg, NULL)))
-                       soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, error ? error->message : 
NULL);
-
+               soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, error ? 
error->message : NULL);
                soup_server_message_io_finished (msg);
        }
        g_object_unref (msg);
diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c
index c49127e1..58bbd9c9 100644
--- a/libsoup/server/soup-server.c
+++ b/libsoup/server/soup-server.c
@@ -966,10 +966,8 @@ client_disconnected (SoupServer        *server,
 
        priv->clients = g_slist_remove (priv->clients, msg);
 
-       if (soup_server_message_get_status (msg, NULL) != 0) {
-               soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, NULL);
+       if (soup_server_message_get_status (msg, NULL) != 0)
                soup_server_message_io_finished (msg);
-       }
 }
 
 static void
@@ -1006,7 +1004,7 @@ request_finished (SoupServerMessage      *msg,
                soup_server_message_finished (msg);
 
                failed = (completion == SOUP_MESSAGE_IO_INTERRUPTED ||
-                         soup_server_message_get_status (msg, NULL) == SOUP_STATUS_IO_ERROR);
+                         soup_server_message_get_status (msg, NULL) == SOUP_STATUS_INTERNAL_SERVER_ERROR);
                g_signal_emit (server,
                               failed ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED],
                               0, msg);
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 5bee9dc1..c247a9b6 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -460,7 +460,7 @@ io_write (SoupMessage *msg, gboolean blocking,
        return TRUE;
 }
 
-static guint
+static gboolean
 parse_headers (SoupMessage  *msg,
               char         *headers,
               guint         headers_len,
@@ -481,7 +481,7 @@ parse_headers (SoupMessage  *msg,
                g_set_error_literal (error, SOUP_SESSION_ERROR,
                                     SOUP_SESSION_ERROR_PARSING,
                                     _("Could not parse HTTP response"));
-               return SOUP_STATUS_MALFORMED;
+               return FALSE;
        }
 
         soup_message_set_status_full (msg, status, reason_phrase);
@@ -504,10 +504,10 @@ parse_headers (SoupMessage  *msg,
                g_set_error_literal (error, SOUP_SESSION_ERROR,
                                     SOUP_SESSION_ERROR_ENCODING,
                                     _("Unrecognized HTTP response encoding"));
-               return SOUP_STATUS_MALFORMED;
+               return FALSE;
        }
 
-       return SOUP_STATUS_OK;
+       return TRUE;
 }
 
 /* Attempts to push forward the reading side of @msg's I/O. Returns
@@ -522,24 +522,21 @@ io_read (SoupMessage *msg, gboolean blocking,
 {
        SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
-       guint status;
+       gboolean succeeded;
 
        switch (io->read_state) {
        case SOUP_MESSAGE_IO_STATE_HEADERS:
-               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);
+               if (!soup_message_io_data_read_headers (io, blocking, cancellable, error))
                        return FALSE;
-               }
 
-               status = parse_headers (msg,
-                                       (char *)io->read_header_buf->data,
-                                       io->read_header_buf->len,
-                                       &io->read_encoding,
-                                       error);
+               succeeded = parse_headers (msg,
+                                          (char *)io->read_header_buf->data,
+                                          io->read_header_buf->len,
+                                          &io->read_encoding,
+                                          error);
                g_byte_array_set_size (io->read_header_buf, 0);
 
-               if (status != SOUP_STATUS_OK) {
+               if (!succeeded) {
                        /* Either we couldn't parse the headers, or they
                         * indicated something that would mean we wouldn't
                         * be able to parse the body. (Eg, unknown
@@ -547,7 +544,6 @@ io_read (SoupMessage *msg, gboolean blocking,
                         * reading, and make sure the connection gets
                         * closed when we're done.
                         */
-                       soup_message_set_status (msg, status);
                        soup_message_headers_append (soup_message_get_request_headers (msg),
                                                     "Connection", "close");
                        io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
@@ -684,6 +680,7 @@ request_is_restartable (SoupMessage *msg, GError *error)
                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) &&
+               !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
                error->domain != G_TLS_ERROR &&
                SOUP_METHOD_IS_IDEMPOTENT (soup_message_get_method (msg)));
 }
@@ -721,15 +718,6 @@ io_run_until (SoupMessage *msg, gboolean blocking,
        }
 
        if (my_error) {
-               if (request_is_restartable (msg, my_error)) {
-                       /* Connection got closed, but we can safely try again */
-                       g_error_free (my_error);
-                       g_set_error_literal (error, SOUP_HTTP_ERROR,
-                                            SOUP_STATUS_TRY_AGAIN, "");
-                       g_object_unref (msg);
-                       return FALSE;
-               }
-
                g_propagate_error (error, my_error);
                g_object_unref (msg);
                return FALSE;
@@ -788,20 +776,14 @@ io_run_until (SoupMessage *msg, gboolean blocking,
 }
 
 static void
-soup_message_io_update_status (SoupMessage  *msg,
-                              GError       *error)
+soup_message_io_finish (SoupMessage  *msg,
+                       GError       *error)
 {
-       if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) {
+       if (request_is_restartable (msg, error)) {
                SoupClientMessageIOData *io = soup_message_get_io_data (msg);
 
+               /* Connection got closed, but we can safely try again. */
                io->item->state = SOUP_MESSAGE_RESTARTING;
-       } else if (error->domain == G_TLS_ERROR) {
-               soup_message_set_status_full (msg,
-                                             SOUP_STATUS_SSL_FAILED,
-                                             error->message);
-       } else if (!SOUP_STATUS_IS_TRANSPORT_ERROR (soup_message_get_status (msg)) &&
-                  !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
        }
 
        soup_message_io_finished (msg);
@@ -847,7 +829,7 @@ soup_message_io_run (SoupMessage *msg,
                g_source_attach (io->io_source, io->async_context);
        } else {
                if (soup_message_get_io_data (msg) == client_io)
-                       soup_message_io_update_status (msg, error);
+                       soup_message_io_finish (msg, error);
                g_error_free (error);
 
        }
@@ -870,7 +852,7 @@ soup_message_io_run_until_read (SoupMessage  *msg,
                return TRUE;
 
        if (soup_message_get_io_data (msg) == io)
-               soup_message_io_update_status (msg, *error);
+               soup_message_io_finish (msg, *error);
 
        return FALSE;
 }
@@ -923,7 +905,7 @@ io_run_until_read_async (SoupMessage *msg,
         }
 
         if (soup_message_get_io_data (msg) == client_io)
-                soup_message_io_update_status (msg, error);
+                soup_message_io_finish (msg, error);
 
         g_task_return_error (task, error);
         g_object_unref (task);
@@ -993,12 +975,6 @@ soup_message_io_get_response_istream (SoupMessage  *msg,
        SoupClientMessageIOData *io = soup_message_get_io_data (msg);
        GInputStream *client_stream;
 
-       if (SOUP_STATUS_IS_TRANSPORT_ERROR (soup_message_get_status (msg))) {
-               g_set_error_literal (error, SOUP_HTTP_ERROR,
-                                    soup_message_get_status (msg), soup_message_get_reason_phrase (msg));
-               return NULL;
-       }
-
        client_stream = soup_client_input_stream_new (io->base.body_istream, msg);
        g_signal_connect (client_stream, "eof",
                          G_CALLBACK (client_stream_eof), msg);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 604251fa..fa0ce46b 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -208,6 +208,14 @@ enum {
  *   be parsed
  * @SOUP_SESSION_ERROR_ENCODING: the server's response was in an
  *   unsupported format
+ * @SOUP_SESSION_ERROR_TOO_MANY_REDIRECTS: the message has been redirected
+ *   too many times
+ * @SOUP_SESSION_ERROR_TOO_MANY_RESTARTS: the message has been restarted
+ *   too many times
+ * @SOUP_SESSION_ERROR_REDIRECT_NO_LOCATION: failed to redirect message because
+ *   Location header was missing or empty in response
+ * @SOUP_SESSION_ERROR_REDIRECT_BAD_URI: failed to redirect message because
+ *   Location header contains an invalid URI
  *
  * A #SoupSession error.
  */
@@ -777,23 +785,39 @@ free_host (SoupSessionHost *host)
          soup_message_get_status (msg) == SOUP_STATUS_FOUND) && \
         SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)))
 
-static inline GUri *
-redirection_uri (SoupMessage *msg)
+static GUri *
+redirection_uri (SoupSession *session,
+                SoupMessage *msg,
+                GError     **error)
 {
+       SoupSessionPrivate *priv;
        const char *new_loc;
        GUri *new_uri;
 
        new_loc = soup_message_headers_get_one (soup_message_get_response_headers (msg),
                                                "Location");
-       if (!new_loc)
+       if (!new_loc || !*new_loc) {
+               g_set_error_literal (error,
+                                    SOUP_SESSION_ERROR,
+                                    SOUP_SESSION_ERROR_REDIRECT_NO_LOCATION,
+                                    _("Location header is missing or empty in response headers"));
                return NULL;
+       }
 
         new_uri = g_uri_parse_relative (soup_message_get_uri (msg), new_loc, SOUP_HTTP_URI_FLAGS, NULL);
        if (!new_uri)
                 return NULL;
-        
-        if (!g_uri_get_host (new_uri)) {
+
+       priv = soup_session_get_instance_private (session);
+       if (!g_uri_get_host (new_uri) || !*g_uri_get_host (new_uri) ||
+           (!soup_uri_is_http (new_uri, priv->http_aliases) &&
+            !soup_uri_is_https (new_uri, priv->https_aliases))) {
                g_uri_unref (new_uri);
+               g_set_error (error,
+                            SOUP_SESSION_ERROR,
+                            SOUP_SESSION_ERROR_REDIRECT_BAD_URI,
+                            _("Invalid URI “%s” in Location response header"),
+                            new_loc);
                return NULL;
        }
 
@@ -816,35 +840,58 @@ redirection_uri (SoupMessage *msg)
 gboolean
 soup_session_would_redirect (SoupSession *session, SoupMessage *msg)
 {
-       SoupSessionPrivate *priv = soup_session_get_instance_private (session);
        GUri *new_uri;
 
+       g_return_val_if_fail (SOUP_IS_SESSION (session), FALSE);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
+
        /* It must have an appropriate status code and method */
        if (!SOUP_SESSION_WOULD_REDIRECT_AS_GET (session, msg) &&
            !SOUP_SESSION_WOULD_REDIRECT_AS_SAFE (session, msg))
                return FALSE;
 
-       /* and a Location header that parses to an http URI */
-       if (!soup_message_headers_get_one (soup_message_get_response_headers (msg), "Location"))
-               return FALSE;
-       new_uri = redirection_uri (msg);
+       new_uri = redirection_uri (session, msg, NULL);
        if (!new_uri)
                return FALSE;
-       if (!g_uri_get_host (new_uri) || !*g_uri_get_host (new_uri) ||
-           (!soup_uri_is_http (new_uri, priv->http_aliases) &&
-            !soup_uri_is_https (new_uri, priv->https_aliases))) {
-               g_uri_unref (new_uri);
-               return FALSE;
-       }
 
        g_uri_unref (new_uri);
        return TRUE;
 }
 
+static gboolean
+soup_session_requeue_item (SoupSession          *session,
+                          SoupMessageQueueItem *item,
+                          GError              **error)
+{
+       gboolean retval;
+
+       if (item->resend_count >= SOUP_SESSION_MAX_RESEND_COUNT) {
+               if (SOUP_STATUS_IS_REDIRECTION (soup_message_get_status (item->msg))) {
+                       g_set_error_literal (error,
+                                            SOUP_SESSION_ERROR,
+                                            SOUP_SESSION_ERROR_TOO_MANY_REDIRECTS,
+                                            _("Too many redirects"));
+               } else {
+                       g_set_error_literal (error,
+                                            SOUP_SESSION_ERROR,
+                                            SOUP_SESSION_ERROR_TOO_MANY_RESTARTS,
+                                            _("Message was restarted too many times"));
+               }
+               retval = FALSE;
+       } else {
+               item->resend_count++;
+               item->state = SOUP_MESSAGE_RESTARTING;
+               retval = TRUE;
+       }
+
+       return retval;
+}
+
 /**
  * soup_session_redirect_message:
  * @session: the session
  * @msg: a #SoupMessage that has received a 3xx response
+ * @error: return location for a #GError, or %NULL
  *
  * Updates @msg's URI according to its status code and "Location"
  * header, and requeues it on @session. Use this when you have set
@@ -866,11 +913,20 @@ soup_session_would_redirect (SoupSession *session, SoupMessage *msg)
  * Since: 2.38
  */
 gboolean
-soup_session_redirect_message (SoupSession *session, SoupMessage *msg)
+soup_session_redirect_message (SoupSession *session,
+                              SoupMessage *msg,
+                              GError     **error)
 {
+       SoupSessionPrivate *priv;
        GUri *new_uri;
+       SoupMessageQueueItem *item;
+       gboolean retval;
 
-       new_uri = redirection_uri (msg);
+       g_return_val_if_fail (SOUP_IS_SESSION (session), FALSE);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
+       g_return_val_if_fail (!error || *error == NULL, FALSE);
+
+       new_uri = redirection_uri (session, msg, error);
        if (!new_uri)
                return FALSE;
 
@@ -888,8 +944,12 @@ soup_session_redirect_message (SoupSession *session, SoupMessage *msg)
        soup_message_set_uri (msg, new_uri);
        g_uri_unref (new_uri);
 
-       soup_session_requeue_message (session, msg);
-       return TRUE;
+       priv = soup_session_get_instance_private (session);
+       item = soup_message_queue_lookup (priv->queue, msg);
+       retval = soup_session_requeue_item (session, item, error);
+       soup_message_queue_item_unref (item);
+
+       return retval;
 }
 
 static void
@@ -899,8 +959,11 @@ redirect_handler (SoupMessage *msg,
        SoupMessageQueueItem *item = user_data;
        SoupSession *session = item->session;
 
-       if (soup_session_would_redirect (session, msg))
-               soup_session_redirect_message (session, msg);
+       if (!SOUP_SESSION_WOULD_REDIRECT_AS_GET (session, msg) &&
+           !SOUP_SESSION_WOULD_REDIRECT_AS_SAFE (session, msg))
+               return;
+
+       soup_session_redirect_message (session, msg, &item->error);
 }
 
 static void
@@ -1183,51 +1246,6 @@ soup_session_unqueue_item (SoupSession          *session,
        soup_message_queue_item_unref (item);
 }
 
-static void
-soup_session_set_item_status (SoupSession          *session,
-                             SoupMessageQueueItem *item,
-                             guint                 status_code,
-                             GError               *error)
-{
-       GUri *uri = NULL;
-
-       switch (status_code) {
-       case SOUP_STATUS_CANT_RESOLVE:
-       case SOUP_STATUS_CANT_CONNECT:
-               uri = soup_message_get_uri (item->msg);
-               break;
-
-       case SOUP_STATUS_CANT_RESOLVE_PROXY:
-       case SOUP_STATUS_CANT_CONNECT_PROXY:
-               if (item->conn)
-                       uri = soup_connection_get_proxy_uri (item->conn);
-               break;
-
-       case SOUP_STATUS_SSL_FAILED:
-               if (!g_tls_backend_supports_tls (g_tls_backend_get_default ())) {
-                       soup_message_set_status_full (item->msg, status_code,
-                                                     "TLS/SSL support not available; install 
glib-networking");
-                       return;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       if (error)
-               soup_message_set_status_full (item->msg, status_code, error->message);
-       else if (uri && g_uri_get_host (uri)) {
-               char *msg = g_strdup_printf ("%s (%s)",
-                                            soup_status_get_phrase (status_code),
-                                            g_uri_get_host (uri));
-               soup_message_set_status_full (item->msg, status_code, msg);
-               g_free (msg);
-       } else
-               soup_message_set_status (item->msg, status_code);
-}
-
-
 static void
 message_completed (SoupMessage *msg, SoupMessageIOCompletion completion, gpointer user_data)
 {
@@ -1250,41 +1268,6 @@ message_completed (SoupMessage *msg, SoupMessageIOCompletion completion, gpointe
        }
 }
 
-static guint
-status_from_connect_error (SoupMessageQueueItem *item, GError *error)
-{
-       guint status;
-
-       if (!error)
-               return SOUP_STATUS_OK;
-
-       if (error->domain == G_TLS_ERROR)
-               status = SOUP_STATUS_SSL_FAILED;
-       else if (error->domain == G_RESOLVER_ERROR)
-               status = SOUP_STATUS_CANT_RESOLVE;
-       else if (error->domain == G_IO_ERROR) {
-               if (error->code == G_IO_ERROR_CANCELLED)
-                       status = SOUP_STATUS_CANCELLED;
-               else if (error->code == G_IO_ERROR_HOST_UNREACHABLE ||
-                        error->code == G_IO_ERROR_NETWORK_UNREACHABLE ||
-                        error->code == G_IO_ERROR_CONNECTION_REFUSED)
-                       status = SOUP_STATUS_CANT_CONNECT;
-               else if (error->code == G_IO_ERROR_PROXY_FAILED ||
-                        error->code == G_IO_ERROR_PROXY_AUTH_FAILED ||
-                        error->code == G_IO_ERROR_PROXY_NEED_AUTH ||
-                        error->code == G_IO_ERROR_PROXY_NOT_ALLOWED)
-                       status = SOUP_STATUS_CANT_CONNECT_PROXY;
-               else
-                       status = SOUP_STATUS_IO_ERROR;
-       } else
-               status = SOUP_STATUS_IO_ERROR;
-
-       if (item->conn && soup_connection_is_via_proxy (item->conn))
-               return soup_status_proxify (status);
-       else
-               return status;
-}
-
 static void
 tunnel_complete (SoupMessageQueueItem *tunnel_item,
                 guint status, GError *error)
@@ -1297,18 +1280,17 @@ tunnel_complete (SoupMessageQueueItem *tunnel_item,
 
        if (soup_message_get_status (item->msg))
                item->state = SOUP_MESSAGE_FINISHING;
+       else if (item->state == SOUP_MESSAGE_TUNNELING)
+               item->state = SOUP_MESSAGE_READY;
 
        item->error = error;
-       if (!status)
-               status = status_from_connect_error (item, error);
-       if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+       if (!SOUP_STATUS_IS_SUCCESSFUL (status) || item->error) {
                soup_connection_disconnect (item->conn);
                soup_session_set_item_connection (session, item, NULL);
-               if (soup_message_get_status (item->msg) == 0)
-                       soup_session_set_item_status (session, item, status, error);
+               if (!error && soup_message_get_status (item->msg) == SOUP_STATUS_NONE)
+                       soup_message_set_status (item->msg, status);
        }
 
-       item->state = SOUP_MESSAGE_READY;
        if (item->async)
                soup_session_kick_queue (session);
        soup_message_queue_item_unref (item);
@@ -1322,7 +1304,7 @@ tunnel_handshake_complete (SoupConnection       *conn,
        GError *error = NULL;
 
        soup_connection_tunnel_handshake_finish (conn, result, &error);
-       tunnel_complete (tunnel_item, 0, error);
+       tunnel_complete (tunnel_item, SOUP_STATUS_OK, error);
 }
 
 static void
@@ -1344,14 +1326,14 @@ tunnel_message_completed (SoupMessage *msg, SoupMessageIOCompletion completion,
                        return;
                }
 
-               soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
+               item->state = SOUP_MESSAGE_RESTARTING;
        }
 
        tunnel_item->state = SOUP_MESSAGE_FINISHED;
        soup_session_unqueue_item (session, tunnel_item);
 
        status = soup_message_get_status (tunnel_item->msg);
-       if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+       if (!SOUP_STATUS_IS_SUCCESSFUL (status) || item->state == SOUP_MESSAGE_RESTARTING) {
                tunnel_complete (tunnel_item, status, NULL);
                return;
        }
@@ -1366,7 +1348,7 @@ tunnel_message_completed (SoupMessage *msg, SoupMessageIOCompletion completion,
                GError *error = NULL;
 
                soup_connection_tunnel_handshake (item->conn, item->cancellable, &error);
-               tunnel_complete (tunnel_item, 0, error);
+               tunnel_complete (tunnel_item, SOUP_STATUS_OK, error);
        }
 }
 
@@ -1403,7 +1385,6 @@ static void
 connect_complete (SoupMessageQueueItem *item, SoupConnection *conn, GError *error)
 {
        SoupSession *session = item->session;
-       guint status;
 
        if (!error) {
                item->state = SOUP_MESSAGE_CONNECTED;
@@ -1411,11 +1392,8 @@ connect_complete (SoupMessageQueueItem *item, SoupConnection *conn, GError *erro
        }
 
        item->error = error;
-       status = status_from_connect_error (item, error);
        soup_connection_disconnect (conn);
        if (item->state == SOUP_MESSAGE_CONNECTING) {
-               if (soup_message_get_status (item->msg) == 0)
-                       soup_session_set_item_status (session, item, status, error);
                soup_session_set_item_connection (session, item, NULL);
                item->state = SOUP_MESSAGE_READY;
        }
@@ -1621,12 +1599,8 @@ soup_session_process_queue_item (SoupSession          *session,
                                break;
                        }
 
-                       if (soup_message_get_status (item->msg)) {
-                               if (soup_message_get_status (item->msg) == SOUP_STATUS_TRY_AGAIN) {
-                                       soup_message_cleanup_response (item->msg);
-                                       item->state = SOUP_MESSAGE_STARTING;
-                               } else
-                                       item->state = SOUP_MESSAGE_FINISHING;
+                       if (item->error || soup_message_get_status (item->msg)) {
+                               item->state = SOUP_MESSAGE_FINISHING;
                                break;
                        }
 
@@ -1752,27 +1726,14 @@ idle_run_queue_dnotify (gpointer user_data)
  * again.
  **/
 void
-soup_session_requeue_message (SoupSession *session, SoupMessage *msg)
+soup_session_requeue_message (SoupSession *session,
+                             SoupMessage *msg)
 {
        SoupSessionPrivate *priv = soup_session_get_instance_private (session);
        SoupMessageQueueItem *item;
 
-       g_return_if_fail (SOUP_IS_SESSION (session));
-       g_return_if_fail (SOUP_IS_MESSAGE (msg));
-
        item = soup_message_queue_lookup (priv->queue, msg);
-       g_return_if_fail (item != NULL);
-
-       if (item->resend_count >= SOUP_SESSION_MAX_RESEND_COUNT) {
-               if (SOUP_STATUS_IS_REDIRECTION (soup_message_get_status (msg)))
-                       soup_message_set_status (msg, SOUP_STATUS_TOO_MANY_REDIRECTS);
-               else
-                       g_warning ("SoupMessage %p stuck in infinite loop?", msg);
-       } else {
-               item->resend_count++;
-               item->state = SOUP_MESSAGE_RESTARTING;
-       }
-
+       soup_session_requeue_item (session, item, &item->error);
        soup_message_queue_item_unref (item);
 }
 
@@ -1887,8 +1848,7 @@ soup_session_unpause_message (SoupSession *session,
  * soup_session_cancel_message:
  * @session: a #SoupSession
  * @msg: the message to cancel
- * @status_code: status code to set on @msg (generally
- * %SOUP_STATUS_CANCELLED)
+ * @status_code: status code to set on @msg
  *
  * Causes @session to immediately finish processing @msg (regardless
  * of its current state) with a final status_code of @status_code. You
@@ -1935,7 +1895,6 @@ soup_session_cancel_message (SoupSession *session, SoupMessage *msg, guint statu
                        soup_message_io_unpause (msg);
        }
 
-       soup_message_set_status (msg, status_code);
        g_cancellable_cancel (item->cancellable);
 
        soup_session_kick_queue (item->session);
@@ -1968,8 +1927,7 @@ soup_session_abort (SoupSession *session)
        for (item = soup_message_queue_first (priv->queue);
             item;
             item = soup_message_queue_next (priv->queue, item)) {
-               soup_session_cancel_message (session, item->msg,
-                                            SOUP_STATUS_CANCELLED);
+               soup_session_cancel_message (session, item->msg, SOUP_STATUS_NONE);
        }
 
        /* Close all idle connections */
@@ -2668,8 +2626,10 @@ expected_to_be_requeued (SoupSession *session, SoupMessage *msg)
                return !feature || !soup_message_disables_feature (msg, feature);
        }
 
-       if (!soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT))
-               return soup_session_would_redirect (session, msg);
+       if (!soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT)) {
+               return SOUP_SESSION_WOULD_REDIRECT_AS_GET (session, msg) ||
+                       SOUP_SESSION_WOULD_REDIRECT_AS_SAFE (session, msg);
+       }
 
        return FALSE;
 }
@@ -2696,13 +2656,6 @@ async_send_request_return_result (SoupMessageQueueItem *item,
                if (stream)
                        g_object_unref (stream);
                g_task_return_error (task, g_error_copy (item->error));
-       } else if (SOUP_STATUS_IS_TRANSPORT_ERROR (soup_message_get_status (item->msg))) {
-               if (stream)
-                       g_object_unref (stream);
-               g_task_return_new_error (task, SOUP_HTTP_ERROR,
-                                        soup_message_get_status (item->msg),
-                                        "%s",
-                                        soup_message_get_reason_phrase (item->msg));
        } else
                g_task_return_pointer (task, stream, g_object_unref);
        g_object_unref (task);
@@ -2831,8 +2784,11 @@ run_until_read_done (SoupMessage          *msg,
        GError *error = NULL;
 
        soup_message_io_run_until_read_finish (msg, result, &error);
-       if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN))
+       if (error && !item->io_started) {
+               /* Message was restarted, we'll try again. */
+               g_error_free (error);
                return;
+       }
 
        if (!error)
                stream = soup_message_io_get_response_istream (msg, &error);
@@ -2920,7 +2876,6 @@ cancel_cache_response (SoupMessageQueueItem *item)
 {
        item->paused = FALSE;
        item->state = SOUP_MESSAGE_FINISHING;
-       soup_message_set_status (item->msg, SOUP_STATUS_CANCELLED);
        soup_session_kick_queue (item->session);
 }
 
@@ -3096,15 +3051,6 @@ soup_session_send_async (SoupSession         *session,
        item->task = g_task_new (session, item->cancellable, callback, user_data);
        g_task_set_priority (item->task, io_priority);
        g_task_set_task_data (item->task, item, (GDestroyNotify) soup_message_queue_item_unref);
-
-       /* Do not check for cancellations as we do not want to
-        * overwrite custom error messages set during cancellations
-        * (for example SOUP_HTTP_ERROR is set for cancelled messages
-        * in async_send_request_return_result() (status_code==1
-        * means CANCEL and is considered a TRANSPORT_ERROR)).
-        */
-       g_task_set_check_cancellable (item->task, FALSE);
-
        if (async_respond_from_cache (session, item))
                item->state = SOUP_MESSAGE_CACHED;
        else
@@ -3215,7 +3161,8 @@ soup_session_send (SoupSession   *session,
 
                /* Send request, read headers */
                if (!soup_message_io_run_until_read (msg, item->cancellable, &my_error)) {
-                       if (g_error_matches (my_error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) {
+                       if (item->state == SOUP_MESSAGE_RESTARTING) {
+                               /* Message was restarted, we'll try again. */
                                g_clear_error (&my_error);
                                continue;
                        }
@@ -3267,10 +3214,6 @@ soup_session_send (SoupSession   *session,
                g_clear_object (&stream);
                if (error)
                        *error = g_error_copy (item->error);
-       } else if (SOUP_STATUS_IS_TRANSPORT_ERROR (soup_message_get_status (msg))) {
-               g_clear_object (&stream);
-               g_set_error_literal (error, SOUP_HTTP_ERROR, soup_message_get_status (msg),
-                                    soup_message_get_reason_phrase (msg));
        } else if (!stream)
                stream = g_memory_input_stream_new ();
 
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index 8b4e37f7..4da94903 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -23,7 +23,11 @@ typedef enum {
        SOUP_SESSION_ERROR_BAD_URI,
        SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME,
        SOUP_SESSION_ERROR_PARSING,
-       SOUP_SESSION_ERROR_ENCODING
+       SOUP_SESSION_ERROR_ENCODING,
+       SOUP_SESSION_ERROR_TOO_MANY_REDIRECTS,
+       SOUP_SESSION_ERROR_TOO_MANY_RESTARTS,
+       SOUP_SESSION_ERROR_REDIRECT_NO_LOCATION,
+       SOUP_SESSION_ERROR_REDIRECT_BAD_URI
 } SoupSessionError;
 
 SOUP_AVAILABLE_IN_2_42
@@ -62,7 +66,8 @@ gboolean        soup_session_would_redirect   (SoupSession           *session,
                                               SoupMessage           *msg);
 SOUP_AVAILABLE_IN_2_38
 gboolean        soup_session_redirect_message (SoupSession           *session,
-                                              SoupMessage           *msg);
+                                              SoupMessage           *msg,
+                                              GError               **error);
 
 SOUP_AVAILABLE_IN_2_24
 void                soup_session_add_feature            (SoupSession        *session,
diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c
index 87c6514e..58c5c4a4 100644
--- a/libsoup/soup-status.c
+++ b/libsoup/soup-status.c
@@ -20,14 +20,6 @@
  * HTTP (and libsoup) status codes.
  **/
 
-/**
- * SOUP_STATUS_IS_TRANSPORT_ERROR:
- * @status: a status code
- *
- * Tests if @status is a libsoup transport error.
- *
- * Return value: %TRUE or %FALSE
- **/
 /**
  * SOUP_STATUS_IS_INFORMATIONAL:
  * @status: an HTTP status code
@@ -73,18 +65,6 @@
  * SoupStatus:
  * @SOUP_STATUS_NONE: No status available. (Eg, the message has not
  * been sent yet)
- * @SOUP_STATUS_CANCELLED: Message was cancelled locally
- * @SOUP_STATUS_CANT_RESOLVE: Unable to resolve destination host name
- * @SOUP_STATUS_CANT_RESOLVE_PROXY: Unable to resolve proxy host name
- * @SOUP_STATUS_CANT_CONNECT: Unable to connect to remote host
- * @SOUP_STATUS_CANT_CONNECT_PROXY: Unable to connect to proxy
- * @SOUP_STATUS_SSL_FAILED: SSL/TLS negotiation failed
- * @SOUP_STATUS_IO_ERROR: A network error occurred, or the other end
- * closed the connection unexpectedly
- * @SOUP_STATUS_MALFORMED: Malformed data (usually a programmer error)
- * @SOUP_STATUS_TRY_AGAIN: Used internally
- * @SOUP_STATUS_TOO_MANY_REDIRECTS: There were too many redirections
- * @SOUP_STATUS_TLS_FAILED: Used internally
  * @SOUP_STATUS_CONTINUE: 100 Continue (HTTP)
  * @SOUP_STATUS_SWITCHING_PROTOCOLS: 101 Switching Protocols (HTTP)
  * @SOUP_STATUS_PROCESSING: 102 Processing (WebDAV)
@@ -175,17 +155,6 @@ static const struct {
        guint code;
        const char *phrase;
 } reason_phrases [] = {
-       /* Transport errors */
-       { SOUP_STATUS_CANCELLED,                  "Cancelled" },
-       { SOUP_STATUS_CANT_RESOLVE,               "Cannot resolve hostname" },
-       { SOUP_STATUS_CANT_RESOLVE_PROXY,         "Cannot resolve proxy hostname" },
-       { SOUP_STATUS_CANT_CONNECT,               "Cannot connect to destination" },
-       { SOUP_STATUS_CANT_CONNECT_PROXY,         "Cannot connect to proxy" },
-       { SOUP_STATUS_SSL_FAILED,                 "SSL handshake failed" },
-       { SOUP_STATUS_IO_ERROR,                   "Connection terminated unexpectedly" },
-       { SOUP_STATUS_MALFORMED,                  "Message Corrupt" },
-       { SOUP_STATUS_TOO_MANY_REDIRECTS,         "Too many redirects" },
-
        /* Informational */
        { SOUP_STATUS_CONTINUE,                   "Continue" },
        { SOUP_STATUS_SWITCHING_PROTOCOLS,        "Switching Protocols" },
@@ -280,32 +249,6 @@ soup_status_get_phrase (guint status_code)
        return "Unknown Error";
 }
 
-/**
- * soup_status_proxify:
- * @status_code: a status code
- *
- * Turns %SOUP_STATUS_CANT_RESOLVE into
- * %SOUP_STATUS_CANT_RESOLVE_PROXY and %SOUP_STATUS_CANT_CONNECT into
- * %SOUP_STATUS_CANT_CONNECT_PROXY. Other status codes are passed
- * through unchanged.
- *
- * Return value: the "proxified" equivalent of @status_code.
- *
- * Since: 2.26
- **/
-guint
-soup_status_proxify (guint status_code)
-{
-       if (status_code == SOUP_STATUS_CANT_RESOLVE)
-               return SOUP_STATUS_CANT_RESOLVE_PROXY;
-       else if (status_code == SOUP_STATUS_CANT_CONNECT)
-               return SOUP_STATUS_CANT_CONNECT_PROXY;
-       else
-               return status_code;
-}
-
-G_DEFINE_QUARK (soup-http-error-quark, soup_http_error)
-
 /**
  * SoupHTTPVersion:
  * @SOUP_HTTP_1_0: HTTP 1.0 (RFC 1945)
diff --git a/libsoup/soup-status.h b/libsoup/soup-status.h
index cc7512f9..4235b0f9 100644
--- a/libsoup/soup-status.h
+++ b/libsoup/soup-status.h
@@ -11,7 +11,6 @@
 
 G_BEGIN_DECLS
 
-#define SOUP_STATUS_IS_TRANSPORT_ERROR(status) ((status) >  0   && (status) < 100)
 #define SOUP_STATUS_IS_INFORMATIONAL(status)   ((status) >= 100 && (status) < 200)
 #define SOUP_STATUS_IS_SUCCESSFUL(status)      ((status) >= 200 && (status) < 300)
 #define SOUP_STATUS_IS_REDIRECTION(status)     ((status) >= 300 && (status) < 400)
@@ -21,20 +20,6 @@ G_BEGIN_DECLS
 typedef enum {
        SOUP_STATUS_NONE,
 
-       /* Transport Errors */
-       SOUP_STATUS_CANCELLED                       = 1,
-       SOUP_STATUS_CANT_RESOLVE,
-       SOUP_STATUS_CANT_RESOLVE_PROXY,
-       SOUP_STATUS_CANT_CONNECT,
-       SOUP_STATUS_CANT_CONNECT_PROXY,
-       SOUP_STATUS_SSL_FAILED,
-       SOUP_STATUS_IO_ERROR,
-       SOUP_STATUS_MALFORMED,
-       SOUP_STATUS_TRY_AGAIN,
-       SOUP_STATUS_TOO_MANY_REDIRECTS,
-       SOUP_STATUS_TLS_FAILED,
-
-       /* HTTP Status Codes */
        SOUP_STATUS_CONTINUE                        = 100,
        SOUP_STATUS_SWITCHING_PROTOCOLS             = 101,
        SOUP_STATUS_PROCESSING                      = 102, /* WebDAV */
@@ -103,14 +88,4 @@ const char *soup_status_get_phrase (guint status_code);
 SOUP_AVAILABLE_IN_2_26
 guint       soup_status_proxify    (guint status_code);
 
-/**
- * SOUP_HTTP_ERROR:
- *
- * A #GError domain representing an HTTP status. Use a #SoupStatus for
- * the <structfield>code</structfield> value.
- **/
-#define SOUP_HTTP_ERROR (soup_http_error_quark())
-SOUP_AVAILABLE_IN_2_4
-GQuark soup_http_error_quark (void);
-
 G_END_DECLS
diff --git a/tests/auth-test.c b/tests/auth-test.c
index a018ad3c..5b8d354f 100644
--- a/tests/auth-test.c
+++ b/tests/auth-test.c
@@ -1065,7 +1065,7 @@ do_auth_close_test (void)
        g_signal_connect (acd.msg, "authenticate",
                          G_CALLBACK (auth_close_authenticate), &acd);
        g_uri_unref (uri);
-       body = soup_test_session_async_send (acd.session, acd.msg);
+       body = soup_test_session_async_send (acd.session, acd.msg, NULL);
 
        soup_test_assert_message_status (acd.msg, SOUP_STATUS_OK);
 
@@ -1099,6 +1099,7 @@ do_infinite_auth_test (void)
        SoupMessage *msg;
        char *uri;
        int timeout;
+       GError *error = NULL;
 
        SOUP_TEST_SKIP_IF_NO_APACHE;
 
@@ -1110,17 +1111,13 @@ do_infinite_auth_test (void)
        g_free (uri);
 
        timeout = g_timeout_add (500, infinite_cancel, session);
-       g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
-                              "*stuck in infinite loop*");
-       soup_test_session_send_message (session, msg);
-       g_test_assert_expected_messages ();
-
-       soup_test_assert (soup_message_get_status (msg) != SOUP_STATUS_CANCELLED,
-                         "Got stuck in loop");
+       g_assert_null (soup_session_send (session, msg, NULL, &error));
+       g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_TOO_MANY_RESTARTS);
        soup_test_assert_message_status (msg, SOUP_STATUS_UNAUTHORIZED);
 
        g_source_remove (timeout);
        soup_test_session_abort_unref (session);
+       g_clear_error (&error);
        g_object_unref (msg);
 }
 
@@ -1192,7 +1189,7 @@ do_disappearing_auth_test (void)
        g_signal_connect (msg, "authenticate",
                          G_CALLBACK (disappear_authenticate), &counter);
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
 
        soup_test_assert (counter <= 2,
                          "Got stuck in loop");
@@ -1537,7 +1534,7 @@ cancel_after_retry_authenticate (SoupMessage          *msg,
                                  CancelAfterRetryData *data)
 {
         if (retrying) {
-                soup_session_cancel_message (data->session, msg, SOUP_STATUS_CANCELLED);
+                soup_session_cancel_message (data->session, msg, 0);
                 g_cancellable_cancel (data->cancellable);
 
                return FALSE;
diff --git a/tests/cache-test.c b/tests/cache-test.c
index 0a86ef87..0792753f 100644
--- a/tests/cache-test.c
+++ b/tests/cache-test.c
@@ -129,7 +129,6 @@ static char *do_request (SoupSession        *session,
 static gboolean last_request_hit_network;
 static gboolean last_request_validated;
 static gboolean last_request_unqueued;
-static guint cancelled_requests;
 
 static void
 copy_headers (const char         *name,
@@ -229,7 +228,6 @@ do_request_with_cancel (SoupSession          *session,
        GCancellable *cancellable;
 
        last_request_validated = last_request_hit_network = last_request_unqueued = FALSE;
-       cancelled_requests = 0;
 
        uri = g_uri_parse_relative (base_uri, path, SOUP_HTTP_URI_FLAGS, NULL);
        msg = soup_message_new_from_uri (method, uri);
@@ -241,8 +239,10 @@ do_request_with_cancel (SoupSession          *session,
                g_object_unref (stream);
                g_object_unref (msg);
                return;
-       } else
+       } else {
+               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
                g_clear_error (&error);
+       }
 
        g_clear_object (&cancellable);
        g_clear_object (&stream);
@@ -277,8 +277,6 @@ static void
 request_unqueued (SoupSession *session, SoupMessage *msg,
                  gpointer data)
 {
-       if (soup_message_get_status (msg) == SOUP_STATUS_CANCELLED)
-               cancelled_requests++;
        last_request_unqueued = TRUE;
 }
 
@@ -507,14 +505,12 @@ do_cancel_test (gconstpointer data)
        debug_printf (1, "  Cancel fresh resource with soup_session_message_cancel()\n");
        flags = SOUP_TEST_REQUEST_CANCEL_MESSAGE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
        do_request_with_cancel (session, base_uri, "GET", "/1", flags);
-       g_assert_cmpint (cancelled_requests, ==, 1);
        soup_test_assert (last_request_unqueued,
                          "Cancelled request /1 not unqueued");
 
        debug_printf (1, "  Cancel fresh resource with g_cancellable_cancel()\n");
        flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
        do_request_with_cancel (session, base_uri, "GET", "/1", flags);
-       g_assert_cmpint (cancelled_requests, ==, 1);
        soup_test_assert (last_request_unqueued,
                          "Cancelled request /1 not unqueued");
 
@@ -530,14 +526,12 @@ do_cancel_test (gconstpointer data)
        debug_printf (1, "  Cancel a revalidating resource with soup_session_message_cancel()\n");
        flags = SOUP_TEST_REQUEST_CANCEL_MESSAGE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
        do_request_with_cancel (session, base_uri, "GET", "/2", flags);
-       g_assert_cmpint (cancelled_requests, ==, 2);
        soup_test_assert (last_request_unqueued,
                          "Cancelled request /2 not unqueued");
 
        debug_printf (1, "  Cancel a revalidating resource with g_cancellable_cancel()\n");
        flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
        do_request_with_cancel (session, base_uri, "GET", "/2", flags);
-       g_assert_cmpint (cancelled_requests, ==, 2);
        soup_test_assert (last_request_unqueued,
                          "Cancelled request /2 not unqueued");
 
@@ -585,7 +579,6 @@ do_refcounting_test (gconstpointer data)
         soup_session_add_feature (session, SOUP_SESSION_FEATURE (cache));
 
        last_request_validated = last_request_hit_network = FALSE;
-       cancelled_requests = 0;
 
        uri = g_uri_parse_relative (base_uri, "/1", SOUP_HTTP_URI_FLAGS, NULL);
        msg = soup_message_new_from_uri ("GET", uri);
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 480b34c9..fea3aa38 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -504,7 +504,7 @@ do_max_conns_test_for_session (SoupSession *session)
                 * session" error.
                 */
                for (i = 0; i < TEST_CONNS; i++)
-                       soup_session_cancel_message (session, msgs[i], SOUP_STATUS_CANCELLED);
+                       soup_session_cancel_message (session, msgs[i], 0);
                g_main_loop_run (max_conns_loop);
        }
 
@@ -728,7 +728,7 @@ do_one_connection_state_test (SoupSession         *session,
        g_signal_connect (msg, "network-event",
                          G_CALLBACK (message_network_event),
                          state);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_bytes_unref (body);
        g_object_unref (msg);
diff --git a/tests/continue-test.c b/tests/continue-test.c
index 4fc662b2..4f0666cd 100644
--- a/tests/continue-test.c
+++ b/tests/continue-test.c
@@ -134,7 +134,7 @@ do_message (const char *path, gboolean long_body,
        events = NULL;
        session = soup_test_session_new (NULL);
         g_assert (SOUP_IS_MESSAGE (msg));
-       response_body = soup_test_session_async_send (session, msg);
+       response_body = soup_test_session_async_send (session, msg, NULL);
         g_assert (SOUP_IS_MESSAGE (msg));
        soup_test_session_abort_unref (session);
         g_assert (SOUP_IS_MESSAGE (msg));
diff --git a/tests/hsts-db-test.c b/tests/hsts-db-test.c
index 176ad029..e98914e2 100644
--- a/tests/hsts-db-test.c
+++ b/tests/hsts-db-test.c
@@ -63,11 +63,17 @@ session_get_uri (SoupSession *session, const char *uri, SoupStatus expected_stat
 {
        SoupMessage *msg;
         GBytes *body;
+        GError *error = NULL;
 
        msg = soup_message_new ("GET", uri);
        soup_message_add_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
-       body = soup_test_session_send (session, msg, NULL, NULL);
+       body = soup_test_session_send (session, msg, NULL, &error);
+       if (expected_status == SOUP_STATUS_NONE)
+               g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
+       else
+               g_assert_no_error (error);
        soup_test_assert_message_status (msg, expected_status);
+        g_clear_error (&error);
         g_bytes_unref (body);
        g_object_unref (msg);
 }
@@ -145,7 +151,7 @@ do_hsts_db_subdomains_test (void)
        soup_test_session_abort_unref (session);
 
        session = hsts_db_session_new ();
-       session_get_uri (session, "http://subdomain.localhost";, SOUP_STATUS_SSL_FAILED);
+       session_get_uri (session, "http://subdomain.localhost";, SOUP_STATUS_NONE);
        soup_test_session_abort_unref (session);
 
        g_remove (DB_FILE);
diff --git a/tests/hsts-test.c b/tests/hsts-test.c
index dad4dcf0..2d75d1bb 100644
--- a/tests/hsts-test.c
+++ b/tests/hsts-test.c
@@ -109,11 +109,17 @@ session_get_uri (SoupSession *session, const char *uri, SoupStatus expected_stat
 {
        SoupMessage *msg;
        GBytes *body;
+       GError *error = NULL;
 
        msg = soup_message_new ("GET", uri);
        soup_message_add_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
-       body = soup_test_session_send (session, msg, NULL, NULL);
+       body = soup_test_session_send (session, msg, NULL, &error);
+       if (expected_status == SOUP_STATUS_NONE)
+               g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
+       else
+               g_assert_no_error (error);
        soup_test_assert_message_status (msg, expected_status);
+       g_clear_error (&error);
        g_bytes_unref (body);
        g_object_unref (msg);
 }
@@ -289,7 +295,7 @@ do_hsts_subdomains_test (void)
        /* The enforcer should cause the request to ask for an HTTPS
           uri, which will fail with an SSL error as there's no server
           in subdomain.localhost. */
-       session_get_uri (session, "http://subdomain.localhost";, SOUP_STATUS_SSL_FAILED);
+       session_get_uri (session, "http://subdomain.localhost";, SOUP_STATUS_NONE);
        soup_test_session_abort_unref (session);
 }
 
@@ -422,7 +428,7 @@ do_hsts_utf8_address_test (void)
        /* The enforcer should cause the request to ask for an HTTPS
           uri, which will fail with an SSL error as there's no server
           in 食狮.中国.localhost. */
-       session_get_uri (session, "http://食狮.中国.localhost";, SOUP_STATUS_SSL_FAILED);
+       session_get_uri (session, "http://食狮.中国.localhost";, SOUP_STATUS_NONE);
        soup_test_session_abort_unref (session);
 }
 
diff --git a/tests/misc-test.c b/tests/misc-test.c
index a9df51ae..8f19aca2 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -178,7 +178,6 @@ cu_one_completed (SoupMessage *msg,
                  SoupSession *session)
 {
        debug_printf (2, "  Message 1 completed\n");
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANT_CONNECT);
        g_object_unref (session);
 }
 
@@ -194,7 +193,6 @@ cu_two_completed (SoupMessage *msg,
                  GMainLoop   *loop)
 {
        debug_printf (2, "  Message 2 completed\n");
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANT_CONNECT);
        g_idle_add (cu_idle_quit, loop); 
 }
 
@@ -309,14 +307,14 @@ do_msg_reuse_test (void)
        msg = soup_message_new_from_uri ("GET", base_uri);
        g_signal_connect (msg, "authenticate",
                           G_CALLBACK (reuse_test_authenticate), NULL);
-       soup_test_session_async_send (session, msg);
+       soup_test_session_async_send (session, msg, NULL);
        ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
 
        debug_printf (1, "  Redirect message\n");
        uri = g_uri_parse_relative (base_uri, "/redirect", SOUP_HTTP_URI_FLAGS, NULL);
        soup_message_set_uri (msg, uri);
        g_uri_unref (uri);
-       soup_test_session_async_send (session, msg);
+       soup_test_session_async_send (session, msg, NULL);
        g_assert_true (soup_uri_equal (soup_message_get_uri (msg), base_uri));
        ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
 
@@ -324,10 +322,10 @@ do_msg_reuse_test (void)
        uri = g_uri_parse_relative (base_uri, "/auth", SOUP_HTTP_URI_FLAGS, NULL);
        soup_message_set_uri (msg, uri);
        g_uri_unref (uri);
-       soup_test_session_async_send (session, msg);
+       soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        soup_message_set_uri (msg, base_uri);
-       soup_test_session_async_send (session, msg);
+       soup_test_session_async_send (session, msg, NULL);
        ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
 
        soup_test_session_abort_unref (session);
@@ -337,11 +335,16 @@ do_msg_reuse_test (void)
 
 /* Handle unexpectedly-early aborts. */
 static void
-ea_msg_completed_one (SoupMessage *msg,
-                     GMainLoop   *loop)
+ea_msg_completed_one (SoupSession  *session,
+                     GAsyncResult *result,
+                     GMainLoop    *loop)
 {
+       GError *error = NULL;
+
        debug_printf (2, "  Message 1 completed\n");
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
+       g_assert_null (soup_session_send_finish (session, result, &error));
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+       g_clear_error (&error);
        g_main_loop_quit (loop);
 }
 
@@ -370,7 +373,7 @@ ea_message_network_event (SoupMessage       *msg,
 static void
 ea_message_starting (SoupMessage *msg, SoupSession *session)
 {
-       soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
+       soup_session_cancel_message (session, msg, 0);
 }
 
 static void
@@ -378,9 +381,9 @@ do_early_abort_test (void)
 {
        SoupSession *session;
        SoupMessage *msg;
-       GBytes *body;
        GMainContext *context;
        GMainLoop *loop;
+       GError *error = NULL;
 
        g_test_bug ("596074");
        g_test_bug ("618641");
@@ -390,9 +393,9 @@ do_early_abort_test (void)
 
        context = g_main_context_default ();
        loop = g_main_loop_new (context, TRUE);
-       g_signal_connect (msg, "finished",
-                         G_CALLBACK (ea_msg_completed_one), loop);
-       soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
+       soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL,
+                                (GAsyncReadyCallback)ea_msg_completed_one,
+                                loop);
        g_object_unref (msg);
        g_main_context_iteration (context, FALSE);
 
@@ -408,11 +411,11 @@ do_early_abort_test (void)
        g_signal_connect (msg, "network-event",
                          G_CALLBACK (ea_message_network_event),
                          session);
-       body = soup_test_session_async_send (session, msg);
+       g_assert_null (soup_test_session_async_send (session, msg, &error));
        debug_printf (2, "  Message 2 completed\n");
 
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
-       g_bytes_unref (body);
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+       g_clear_error (&error);
        g_object_unref (msg);
 
        while (g_main_context_pending (context))
@@ -427,11 +430,11 @@ do_early_abort_test (void)
 
        g_signal_connect (msg, "starting",
                          G_CALLBACK (ea_message_starting), session);
-       body = soup_test_session_async_send (session, msg);
+       g_assert_null (soup_test_session_async_send (session, msg, &error));
        debug_printf (2, "  Message 3 completed\n");
 
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
-       g_bytes_unref (body);
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+       g_clear_error (&error);
        g_object_unref (msg);
 
        while (g_main_context_pending (context))
@@ -486,25 +489,18 @@ cancel_message_timeout (gpointer msg)
 {
        SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
 
-       soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
+       soup_session_cancel_message (session, msg, 0);
        g_object_unref (msg);
        g_object_unref (session);
        return FALSE;
 }
 
-static void
-set_done (SoupMessage *msg,
-         gboolean    *done)
-{
-       *done = TRUE;
-}
-
 static void
 do_cancel_while_reading_test_for_session (SoupSession *session)
 {
        SoupMessage *msg;
        GUri *uri;
-       gboolean done = FALSE;
+       GError *error = NULL;
 
        uri = g_uri_parse_relative (base_uri, "/slow", SOUP_HTTP_URI_FLAGS, NULL);
        msg = soup_message_new_from_uri ("GET", uri);
@@ -515,17 +511,9 @@ do_cancel_while_reading_test_for_session (SoupSession *session)
        g_object_ref (session);
        g_timeout_add (100, cancel_message_timeout, msg);
 
-       g_signal_connect (msg, "finished",
-                         G_CALLBACK (set_done), &done);
-       soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
-       while (!done)
-               g_main_context_iteration (NULL, TRUE);
-       /* We need one more iteration, because SoupMessage::finished is emitted
-        * right before the message is unqueued.
-        */
-       g_main_context_iteration (NULL, TRUE);
-
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
+       g_assert_null (soup_test_session_async_send (session, msg, &error));
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+       g_clear_error (&error);
        g_object_unref (msg);
 }
 
diff --git a/tests/no-ssl-test.c b/tests/no-ssl-test.c
index a5b9442d..009a254c 100644
--- a/tests/no-ssl-test.c
+++ b/tests/no-ssl-test.c
@@ -6,14 +6,16 @@ static void
 do_ssl_test_for_session (SoupSession *session, GUri *uri)
 {
        SoupMessage *msg;
+       GError *error;
 
        msg = soup_message_new_from_uri ("GET", uri);
-       soup_test_session_send_message (session, msg);
-       soup_test_assert_message_status (msg, SOUP_STATUS_SSL_FAILED);
-
+       soup_session_send (session, msg, NULL, &error);
+       g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_UNAVAILABLE);
+       g_assert_cmpuint (soup_message_get_status (msg), ==, SOUP_STATUS_NONE);
        g_assert_null (soup_message_get_tls_certificate (msg));
        g_assert_cmpuint (soup_message_get_tls_certificate_errors (msg), ==, 0);
 
+       g_error_free (error);
        g_object_unref (msg);
 }
 
diff --git a/tests/range-test.c b/tests/range-test.c
index cc050720..08ca88bc 100644
--- a/tests/range-test.c
+++ b/tests/range-test.c
@@ -69,7 +69,7 @@ do_single_range (SoupSession *session, SoupMessage *msg,
        debug_printf (1, "    Range: %s\n",
                      soup_message_headers_get_one (soup_message_get_request_headers (msg), "Range"));
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
 
        if (!succeed) {
                soup_test_assert_message_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
@@ -120,7 +120,7 @@ do_multi_range (SoupSession *session, SoupMessage *msg,
        debug_printf (1, "    Range: %s\n",
                      soup_message_headers_get_one (soup_message_get_request_headers (msg), "Range"));
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
 
        soup_test_assert_message_status (msg, SOUP_STATUS_PARTIAL_CONTENT);
 
diff --git a/tests/redirect-test.c b/tests/redirect-test.c
index 615da0fe..0e7e996f 100644
--- a/tests/redirect-test.c
+++ b/tests/redirect-test.c
@@ -19,6 +19,7 @@ typedef struct {
 typedef struct {
        TestRequest requests[3];
        guint final_status;
+       guint error_code;
        const char *bugref;
 } TestCase;
 
@@ -27,96 +28,99 @@ static TestCase tests[] = {
 
        { { { "GET", "/301", 301 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "GET", "/302", 302 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "GET", "/303", 303 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "GET", "/307", 307 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "GET", "/308", 308 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "HEAD", "/301", 301 },
            { "HEAD", "/", 200 },
-           { NULL } }, 200, "551190" },
+           { NULL } }, 200, 0, "551190" },
        { { { "HEAD", "/302", 302 },
            { "HEAD", "/", 200 },
-           { NULL } }, 200, "551190" },
+           { NULL } }, 200, 0, "551190" },
        /* 303 is a nonsensical response to HEAD, but some sites do
         * it anyway. :-/
         */
        { { { "HEAD", "/303", 303 },
            { "HEAD", "/", 200 },
-           { NULL } }, 200, "600830" },
+           { NULL } }, 200, 0, "600830" },
        { { { "HEAD", "/307", 307 },
            { "HEAD", "/", 200 },
-           { NULL } }, 200, "551190" },
+           { NULL } }, 200, 0, "551190" },
        { { { "HEAD", "/308", 308 },
            { "HEAD", "/", 200 },
-           { NULL } }, 200, "551190" },
+           { NULL } }, 200, 0, "551190" },
 
        /* A non-redirecty response to a GET or HEAD should not */
 
        { { { "GET", "/300", 300 },
-           { NULL } }, 300, NULL },
+           { NULL } }, 300, 0, NULL },
        { { { "GET", "/304", 304 },
-           { NULL } }, 304, NULL },
+           { NULL } }, 304, 0, NULL },
        { { { "GET", "/305", 305 },
-           { NULL } }, 305, NULL },
+           { NULL } }, 305, 0, NULL },
        { { { "GET", "/306", 306 },
-           { NULL } }, 306, NULL },
+           { NULL } }, 306, 0, NULL },
        { { { "HEAD", "/300", 300 },
-           { NULL } }, 300, "551190" },
+           { NULL } }, 300, 0, "551190" },
        { { { "HEAD", "/304", 304 },
-           { NULL } }, 304, "551190" },
+           { NULL } }, 304, 0, "551190" },
        { { { "HEAD", "/305", 305 },
-           { NULL } }, 305, "551190" },
+           { NULL } }, 305, 0, "551190" },
        { { { "HEAD", "/306", 306 },
-           { NULL } }, 306, "551190" },
+           { NULL } }, 306, 0, "551190" },
        
        /* Test double-redirect */
 
        { { { "GET", "/301/302", 301 },
            { "GET", "/302", 302 },
-           { "GET", "/", 200 } }, 200, NULL },
+           { "GET", "/", 200 } }, 200, 0, NULL },
        { { { "HEAD", "/301/302", 301 },
            { "HEAD", "/302", 302 },
-           { "HEAD", "/", 200 } }, 200, "551190" },
+           { "HEAD", "/", 200 } }, 200, 0, "551190" },
 
        /* POST should only automatically redirect on 301, 302 and 303 */
 
        { { { "POST", "/301", 301 },
            { "GET", "/", 200 },
-           { NULL } }, 200, "586692" },
+           { NULL } }, 200, 0, "586692" },
        { { { "POST", "/302", 302 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "POST", "/303", 303 },
            { "GET", "/", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
        { { { "POST", "/307", 307 },
-           { NULL } }, 307, NULL },
+           { NULL } }, 307, 0, NULL },
 
        /* Test behavior with recoverably-bad Location header */
        { { { "GET", "/bad", 302 },
            { "GET", "/bad%20with%20spaces", 200 },
-           { NULL } }, 200, "566530" },
+           { NULL } }, 200, 0, "566530" },
 
        { { { "GET", "/bad-no-host", 302 },
-           { NULL } }, 302, "528882" },
+           { NULL } }, 302, SOUP_SESSION_ERROR_REDIRECT_BAD_URI, "528882" },
+
+       { { { "GET", "/bad-no-location", 302 },
+           { NULL } }, 302, SOUP_SESSION_ERROR_REDIRECT_NO_LOCATION, NULL},
 
        /* Test infinite redirection */
        { { { "GET", "/bad-recursive", 302, TRUE },
-           { NULL } }, SOUP_STATUS_TOO_MANY_REDIRECTS, "604383" },
+           { NULL } }, 302, SOUP_SESSION_ERROR_TOO_MANY_REDIRECTS, "604383" },
 
        /* Test redirection to a different server */
        { { { "GET", "/server2", 302 },
            { "GET", "/on-server2", 200 },
-           { NULL } }, 200, NULL },
+           { NULL } }, 200, 0, NULL },
 };
 static const int n_tests = G_N_ELEMENTS (tests);
 
@@ -164,6 +168,7 @@ do_message_api_test (SoupSession *session, TestCase *test)
        SoupMessage *msg;
        GBytes *body;
        TestRequest *treq;
+       GError *error = NULL;
 
        if (test->bugref)
                g_test_bug (test->bugref);
@@ -186,10 +191,15 @@ do_message_api_test (SoupSession *session, TestCase *test)
        g_signal_connect (msg, "restarted",
                          G_CALLBACK (restarted), &treq);
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, &error);
 
        soup_test_assert_message_status (msg, test->final_status);
+       if (test->error_code)
+               g_assert_error (error, SOUP_SESSION_ERROR, test->error_code);
+       else
+               g_assert_no_error (error);
 
+       g_clear_error (&error);
        g_bytes_unref (body);
        g_object_unref (msg);
 }
@@ -239,6 +249,10 @@ server_callback (SoupServer        *server,
                        soup_message_headers_replace (response_headers,
                                                      "Location",
                                                      "about:blank");
+               } else if (!strcmp (path, "/bad-no-location")) {
+                       soup_server_message_set_status (msg, SOUP_STATUS_FOUND, NULL);
+                       soup_message_headers_replace (response_headers,
+                                                     "Location", "");
                } else if (!strcmp (path, "/bad with spaces"))
                        soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
                else
diff --git a/tests/request-body-test.c b/tests/request-body-test.c
index b2b6335b..c6227f00 100644
--- a/tests/request-body-test.c
+++ b/tests/request-body-test.c
@@ -119,7 +119,7 @@ do_request_test (gconstpointer data)
                           G_CALLBACK (wrote_body_data), &ptd);
 
         if (flags & ASYNC)
-                soup_test_session_async_send (session, msg);
+                soup_test_session_async_send (session, msg, NULL);
         else
                 soup_test_session_send_message (session, msg);
         soup_test_assert_message_status (msg, SOUP_STATUS_CREATED);
diff --git a/tests/server-test.c b/tests/server-test.c
index 36edb5a0..94fa142b 100644
--- a/tests/server-test.c
+++ b/tests/server-test.c
@@ -409,7 +409,7 @@ do_ipv6_test (ServerData *sd, gconstpointer test_data)
 
        debug_printf (1, "  HTTP/1.1\n");
        msg = soup_message_new_from_uri ("GET", sd->base_uri);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_bytes_unref (body);
        g_object_unref (msg);
@@ -417,7 +417,7 @@ do_ipv6_test (ServerData *sd, gconstpointer test_data)
        debug_printf (1, "  HTTP/1.0\n");
        msg = soup_message_new_from_uri ("GET", sd->base_uri);
        soup_message_set_http_version (msg, SOUP_HTTP_1_0);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_bytes_unref (body);
        g_object_unref (msg);
@@ -470,7 +470,7 @@ do_multi_test (ServerData *sd, GUri *uri1, GUri *uri2)
 
        uristr = g_uri_to_string (uri1);
        msg = soup_message_new ("GET", uristr);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_assert_cmpmem (uristr, strlen (uristr), g_bytes_get_data (body, NULL), g_bytes_get_size (body));
        g_bytes_unref (body);
@@ -479,7 +479,7 @@ do_multi_test (ServerData *sd, GUri *uri1, GUri *uri2)
 
        uristr = g_uri_to_string (uri2);
        msg = soup_message_new ("GET", uristr);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_assert_cmpmem (uristr, strlen (uristr), g_bytes_get_data (body, NULL), g_bytes_get_size (body));
        g_bytes_unref (body);
@@ -650,7 +650,7 @@ do_gsocket_import_test (void)
 
        session = soup_test_session_new (NULL);
        msg = soup_message_new_from_uri ("GET", uri);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_bytes_unref (body);
        g_object_unref (msg);
@@ -716,7 +716,7 @@ do_fd_import_test (void)
 
        session = soup_test_session_new (NULL);
        msg = soup_message_new_from_uri ("GET", uri);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_bytes_unref (body);
        g_object_unref (msg);
@@ -923,7 +923,7 @@ do_fail_404_test (ServerData *sd, gconstpointer test_data)
 
        session = soup_test_session_new (NULL);
        msg = soup_message_new_from_uri ("GET", sd->base_uri);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_NOT_FOUND);
        g_bytes_unref (body);
        g_object_unref (msg);
@@ -950,7 +950,7 @@ do_fail_500_test (ServerData *sd, gconstpointer pause)
        msg = soup_message_new_from_uri ("GET", sd->base_uri);
        if (pause)
                soup_message_headers_append (soup_message_get_request_headers (msg), "X-Test-Server-Pause", 
"true");
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
        g_bytes_unref (body);
        g_object_unref (msg);
diff --git a/tests/session-test.c b/tests/session-test.c
index 1ae68b5f..34a0f539 100644
--- a/tests/session-test.c
+++ b/tests/session-test.c
@@ -59,21 +59,29 @@ finished_cb (SoupMessage *msg,
 static void
 cancel_message_cb (SoupMessage *msg, gpointer session)
 {
-       soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
+       soup_session_cancel_message (session, msg, 0);
+}
+
+static void
+cancel_message_send_done (SoupSession  *session,
+                         GAsyncResult *result,
+                         GError      **error)
+{
+       g_assert_null (soup_session_send_finish (session, result, error));
        g_main_loop_quit (loop);
 }
 
 static void
 do_test_for_session (SoupSession *session,
                     gboolean queue_is_async,
-                    gboolean send_is_blocking,
-                    gboolean cancel_is_immediate)
+                    gboolean send_is_blocking)
 {
        SoupMessage *msg;
        gboolean finished, local_timeout;
        guint timeout_id;
        GUri *timeout_uri;
        GBytes *body;
+       GError *error = NULL;
 
        debug_printf (1, "  queue_message\n");
        debug_printf (2, "    requesting timeout\n");
@@ -133,33 +141,19 @@ do_test_for_session (SoupSession *session,
 
        debug_printf (1, "  cancel_message\n");
        msg = soup_message_new_from_uri ("GET", base_uri);
-       finished = FALSE;
-       g_signal_connect (msg, "finished",
-                         G_CALLBACK (finished_cb), &finished);
-       soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
+       soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL,
+                                (GAsyncReadyCallback)cancel_message_send_done,
+                                &error);
        g_signal_connect (msg, "wrote-headers",
                          G_CALLBACK (cancel_message_cb), session);
 
        loop = g_main_loop_new (NULL, FALSE);
        g_main_loop_run (loop);
 
-       if (cancel_is_immediate)
-               g_assert_true (finished);
-       else
-               g_assert_false (finished);
+       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
 
-       if (!finished) {
-               debug_printf (2, "    waiting for finished\n");
-               while (!finished)
-                       g_main_context_iteration (NULL, TRUE);
-               /* We need one iteration more because finished is emitted
-                * right before the item is unqueued.
-                */
-               g_main_context_iteration (NULL, TRUE);
-       }
        g_main_loop_unref (loop);
-
-       soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
+       g_clear_error (&error);
        g_object_unref (msg);
 }
 
@@ -169,7 +163,7 @@ do_plain_tests (void)
        SoupSession *session;
 
        session = soup_test_session_new (NULL);
-       do_test_for_session (session, TRUE, TRUE, FALSE);
+       do_test_for_session (session, TRUE, TRUE);
        soup_test_session_abort_unref (session);
 }
 
diff --git a/tests/sniffing-test.c b/tests/sniffing-test.c
index 0bcc3bea..19f23f1c 100644
--- a/tests/sniffing-test.c
+++ b/tests/sniffing-test.c
@@ -211,7 +211,7 @@ do_signals_test (gboolean should_content_sniff,
                          "signal::content_sniffed", content_sniffed, NULL,
                          NULL);
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
 
        if (should_content_sniff) {
                soup_test_assert (g_object_get_data (G_OBJECT (msg), "content-sniffed") != NULL,
@@ -300,7 +300,7 @@ test_sniffing (const char *path, const char *expected_type)
        g_signal_connect (msg, "content-sniffed",
                          G_CALLBACK (sniffing_content_sniffed), &sniffed_type);
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        g_assert_cmpstr (sniffed_type, ==, expected_type);
        g_free (sniffed_type);
        g_bytes_unref (body);
@@ -352,7 +352,7 @@ test_disabled (gconstpointer data)
        g_signal_connect (msg, "content-sniffed",
                          G_CALLBACK (sniffing_content_sniffed), &sniffed_type);
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
 
        g_assert_null (sniffed_type);
        g_bytes_unref (body);
diff --git a/tests/ssl-test.c b/tests/ssl-test.c
index 53b3441a..ed018488 100644
--- a/tests/ssl-test.c
+++ b/tests/ssl-test.c
@@ -15,7 +15,7 @@ static const StrictnessTest strictness_tests[] = {
        { "/ssl/strictness/strict/with-ca",
          TRUE, TRUE, SOUP_STATUS_OK },
        { "/ssl/strictness/strict/without-ca",
-         TRUE, FALSE, SOUP_STATUS_SSL_FAILED },
+         TRUE, FALSE, SOUP_STATUS_NONE },
        { "/ssl/strictness/non-strict/with-ca",
          FALSE, TRUE, SOUP_STATUS_OK },
        { "/ssl/strictness/non-strict/without-ca",
@@ -36,7 +36,9 @@ do_strictness_test (gconstpointer data)
        const StrictnessTest *test = data;
        SoupSession *session;
        SoupMessage *msg;
+       GBytes *body;
        GTlsCertificateFlags flags = 0;
+       GError *error = NULL;
 
        SOUP_TEST_SKIP_IF_NO_TLS;
 
@@ -52,23 +54,27 @@ do_strictness_test (gconstpointer data)
                g_signal_connect (msg, "accept-certificate",
                                  G_CALLBACK (accept_certificate), NULL);
        }
-       soup_test_session_send_message (session, msg);
+       body = soup_test_session_send (session, msg, NULL, &error);
        soup_test_assert_message_status (msg, test->expected_status);
+       if (test->expected_status != SOUP_STATUS_OK)
+               g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
 
        g_test_bug ("690176");
        g_assert_nonnull (soup_message_get_tls_certificate (msg));
        flags = soup_message_get_tls_certificate_errors (msg);
 
        g_test_bug ("665182");
-       if (test->with_ca_list && SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
+       if (test->with_ca_list && !error)
                g_assert_cmpuint (flags, ==, 0);
        else
                g_assert_cmpuint (flags, !=, 0);
 
-       if (soup_message_get_status (msg) == SOUP_STATUS_SSL_FAILED &&
-           test->expected_status != SOUP_STATUS_SSL_FAILED)
+       if (soup_message_get_status (msg) == SOUP_STATUS_NONE &&
+           test->expected_status != SOUP_STATUS_NONE)
                debug_printf (1, "              tls error flags: 0x%x\n", flags);
 
+       g_clear_pointer (&body, g_bytes_unref);
+       g_clear_error (&error);
        g_object_unref (msg);
 
        soup_test_session_abort_unref (session);
@@ -218,8 +224,9 @@ do_tls_interaction_test (void)
 
        /* Without a GTlsInteraction */
        msg = soup_message_new_from_uri ("GET", test_uri);
-       body = soup_test_session_async_send (session, msg);
-       soup_test_assert_message_status (msg, SOUP_STATUS_SSL_FAILED);
+       body = soup_test_session_async_send (session, msg, &error);
+       g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
+       g_clear_error (&error);
        g_bytes_unref (body);
        g_object_unref (msg);
 
@@ -231,7 +238,7 @@ do_tls_interaction_test (void)
 
        /* With a GTlsInteraction */
        msg = soup_message_new_from_uri ("GET", test_uri);
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_assert_nonnull (soup_message_get_tls_certificate (msg));
        g_bytes_unref (body);
diff --git a/tests/streaming-test.c b/tests/streaming-test.c
index cfec948b..7c2ff1e4 100644
--- a/tests/streaming-test.c
+++ b/tests/streaming-test.c
@@ -93,7 +93,7 @@ do_request (SoupSession *session, GUri *base_uri, char *path)
        msg = soup_message_new_from_uri ("GET", uri);
        g_uri_unref (uri);
 
-       body = soup_test_session_async_send (session, msg);
+       body = soup_test_session_async_send (session, msg, NULL);
 
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_assert_cmpint (g_bytes_get_size (body), ==, g_bytes_get_size (full_response));
diff --git a/tests/test-utils.c b/tests/test-utils.c
index a057e0ed..9627d892 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -301,15 +301,22 @@ soup_test_session_abort_unref (SoupSession *session)
        g_object_unref (session);
 }
 
+typedef struct {
+       GBytes *body;
+       GError *error;
+       gboolean done;
+} SendAsyncData;
+
 static void
-send_async_ready_cb (SoupSession  *session,
-                    GAsyncResult *result,
-                    GBytes      **body)
+send_async_ready_cb (SoupSession   *session,
+                    GAsyncResult  *result,
+                    SendAsyncData *data)
 {
        GInputStream *istream;
        GOutputStream *ostream;
 
-       istream = soup_session_send_finish (session, result, NULL);
+       data->done = TRUE;
+       istream = soup_session_send_finish (session, result, &data->error);
        if (!istream)
                return;
 
@@ -318,40 +325,46 @@ send_async_ready_cb (SoupSession  *session,
                                istream,
                                G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
                                G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
-                               NULL, NULL);
-       *body = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (ostream));
+                               NULL,
+                               &data->error);
+       data->body = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (ostream));
        g_object_unref (ostream);
        g_object_unref (istream);
 }
 
 static void
 on_message_finished (SoupMessage *msg,
-                    gboolean    *message_finished)
+                    gboolean    *message_finished)
 {
         *message_finished = TRUE;
 }
 
 GBytes *
 soup_test_session_async_send (SoupSession *session,
-                             SoupMessage *msg)
+                             SoupMessage *msg,
+                             GError     **error)
 {
-        gboolean message_finished = FALSE;
+       gboolean message_finished = FALSE;
        GMainContext *async_context = g_main_context_ref_thread_default ();
        gulong signal_id;
-       GBytes *body = NULL;
+       SendAsyncData data = { NULL, NULL, FALSE };
 
        signal_id = g_signal_connect (msg, "finished",
-                                     G_CALLBACK (on_message_finished), &message_finished);
+                                     G_CALLBACK (on_message_finished), &message_finished);
+
        soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL,
-                                (GAsyncReadyCallback)send_async_ready_cb, &body);
+                                (GAsyncReadyCallback)send_async_ready_cb, &data);
 
-       while (!message_finished)
+       while (!data.done || !message_finished)
                g_main_context_iteration (async_context, TRUE);
 
        g_signal_handler_disconnect (msg, signal_id);
 
+       if (data.error)
+               g_propagate_error (error, data.error);
+
         g_main_context_unref (async_context);
-       return body;
+       return data.body;
 }
 
 guint
@@ -681,8 +694,7 @@ cancel_message_or_cancellable (CancelData *cancel_data)
        if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_MESSAGE) {
                SoupMessage *msg = cancel_data->msg;
 
-               soup_session_cancel_message (cancel_data->session, msg,
-                                            SOUP_STATUS_CANCELLED);
+               soup_session_cancel_message (cancel_data->session, msg, 0);
                g_object_unref (msg);
        } else if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_CANCELLABLE) {
                g_cancellable_cancel (cancel_data->cancellable);
diff --git a/tests/test-utils.h b/tests/test-utils.h
index 20b0b98d..0447f73f 100644
--- a/tests/test-utils.h
+++ b/tests/test-utils.h
@@ -54,7 +54,8 @@ typedef enum {
 SoupSession *soup_test_session_new                (const char *propname, ...);
 void         soup_test_session_abort_unref        (SoupSession *session);
 GBytes      *soup_test_session_async_send         (SoupSession *session,
-                                                  SoupMessage *msg);
+                                                  SoupMessage *msg,
+                                                  GError     **error);
 guint        soup_test_session_send_message       (SoupSession *session,
                                                   SoupMessage *msg);
 
diff --git a/tests/timeout-test.c b/tests/timeout-test.c
index 3d713757..0cbfd5b5 100644
--- a/tests/timeout-test.c
+++ b/tests/timeout-test.c
@@ -37,7 +37,7 @@ do_message_to_session (SoupSession *session, GUri *uri,
        g_signal_connect (msg, "finished",
                          G_CALLBACK (message_finished), &finished);
 #if 0
-       soup_test_session_async_send_message (session, msg);
+       soup_test_session_async_send_message (session, msg, NULL);
 #endif
 
        soup_test_assert_message_status (msg, expected_status);
@@ -76,7 +76,9 @@ do_msg_tests_for_session (SoupSession *timeout_session,
        }
 
        do_message_to_session (timeout_session, fast_uri, "fast to timeout", SOUP_STATUS_OK);
+#if 0
        do_message_to_session (timeout_session, slow_uri, "slow to timeout", SOUP_STATUS_IO_ERROR);
+#endif
 
        if (idle_session) {
                do_message_to_session (idle_session, fast_uri, "fast to idle", SOUP_STATUS_OK);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]