1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-connection.c: A single HTTP/HTTPS connection
5 * Copyright (C) 2000-2003, Ximian, Inc.
18 #include <sys/types.h>
20 #include "soup-address.h"
21 #include "soup-connection.h"
22 #include "soup-marshal.h"
23 #include "soup-message.h"
24 #include "soup-message-private.h"
25 #include "soup-misc.h"
26 #include "soup-socket.h"
31 SOUP_CONNECTION_MODE_DIRECT,
32 SOUP_CONNECTION_MODE_PROXY,
33 SOUP_CONNECTION_MODE_TUNNEL
39 /* proxy_addr is the address of the proxy server we are
40 * connected to, if any. server_addr is the address of the
41 * origin server. conn_addr is the uri of the host we are
42 * actually directly connected to, which will be proxy_addr if
43 * there's a proxy and server_addr if not.
45 SoupAddress *proxy_addr, *server_addr, *conn_addr;
48 SoupConnectionMode mode;
50 GMainContext *async_context;
54 gboolean connected, in_use;
55 guint io_timeout, idle_timeout;
56 GSource *idle_timeout_src;
57 } SoupConnectionPrivate;
58 #define SOUP_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CONNECTION, SoupConnectionPrivate))
60 G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
69 static guint signals[LAST_SIGNAL] = { 0 };
84 static void set_property (GObject *object, guint prop_id,
85 const GValue *value, GParamSpec *pspec);
86 static void get_property (GObject *object, guint prop_id,
87 GValue *value, GParamSpec *pspec);
89 static void stop_idle_timer (SoupConnectionPrivate *priv);
90 static void send_request (SoupConnection *conn, SoupMessage *req);
91 static void clear_current_request (SoupConnection *conn);
94 soup_connection_init (SoupConnection *conn)
100 finalize (GObject *object)
102 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
104 if (priv->proxy_addr)
105 g_object_unref (priv->proxy_addr);
106 if (priv->server_addr)
107 g_object_unref (priv->server_addr);
109 if (priv->async_context)
110 g_main_context_unref (priv->async_context);
112 G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
116 dispose (GObject *object)
118 SoupConnection *conn = SOUP_CONNECTION (object);
119 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
121 stop_idle_timer (priv);
122 /* Make sure clear_current_request doesn't re-establish the timeout */
123 priv->idle_timeout = 0;
125 clear_current_request (conn);
126 soup_connection_disconnect (conn);
128 G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
132 soup_connection_class_init (SoupConnectionClass *connection_class)
134 GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
136 g_type_class_add_private (connection_class, sizeof (SoupConnectionPrivate));
138 /* virtual method definition */
139 connection_class->send_request = send_request;
141 /* virtual method override */
142 object_class->dispose = dispose;
143 object_class->finalize = finalize;
144 object_class->set_property = set_property;
145 object_class->get_property = get_property;
149 signals[CONNECT_RESULT] =
150 g_signal_new ("connect_result",
151 G_OBJECT_CLASS_TYPE (object_class),
153 G_STRUCT_OFFSET (SoupConnectionClass, connect_result),
155 soup_marshal_NONE__INT,
158 signals[DISCONNECTED] =
159 g_signal_new ("disconnected",
160 G_OBJECT_CLASS_TYPE (object_class),
162 G_STRUCT_OFFSET (SoupConnectionClass, disconnected),
164 soup_marshal_NONE__NONE,
166 signals[REQUEST_STARTED] =
167 g_signal_new ("request-started",
168 G_OBJECT_CLASS_TYPE (object_class),
170 G_STRUCT_OFFSET (SoupConnectionClass, request_started),
172 soup_marshal_NONE__OBJECT,
177 g_object_class_install_property (
178 object_class, PROP_SERVER_ADDRESS,
179 g_param_spec_object (SOUP_CONNECTION_SERVER_ADDRESS,
181 "The address of the HTTP origin server for this connection",
183 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
184 g_object_class_install_property (
185 object_class, PROP_PROXY_ADDRESS,
186 g_param_spec_object (SOUP_CONNECTION_PROXY_ADDRESS,
188 "The address of the HTTP Proxy to use for this connection",
190 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
191 g_object_class_install_property (
192 object_class, PROP_SSL_CREDS,
193 g_param_spec_pointer (SOUP_CONNECTION_SSL_CREDENTIALS,
195 "Opaque SSL credentials for this connection",
196 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
197 g_object_class_install_property (
198 object_class, PROP_ASYNC_CONTEXT,
199 g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
200 "Async GMainContext",
201 "GMainContext to dispatch this connection's async I/O in",
202 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
203 g_object_class_install_property (
204 object_class, PROP_TIMEOUT,
205 g_param_spec_uint (SOUP_CONNECTION_TIMEOUT,
207 "Value in seconds to timeout a blocking I/O",
210 g_object_class_install_property (
211 object_class, PROP_IDLE_TIMEOUT,
212 g_param_spec_uint (SOUP_CONNECTION_IDLE_TIMEOUT,
214 "Connection lifetime when idle",
216 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
221 * soup_connection_new:
222 * @propname1: name of first property to set
223 * @...: value of @propname1, followed by additional property/value pairs
225 * Creates an HTTP connection. There are three possibilities:
227 * If you set %SOUP_CONNECTION_SERVER_ADDRESS and not
228 * %SOUP_CONNECTION_PROXY_ADDRESS, this will be a direct connection to
229 * the indicated origin server.
231 * If you set %SOUP_CONNECTION_PROXY_ADDRESS and not
232 * %SOUP_CONNECTION_SSL_CREDENTIALS, this will be a standard proxy
233 * connection, which can be used for requests to multiple origin
236 * If you set %SOUP_CONNECTION_SERVER_ADDRESS,
237 * %SOUP_CONNECTION_PROXY_ADDRESS, and
238 * %SOUP_CONNECTION_SSL_CREDENTIALS, this will be a tunnel through the
239 * proxy to the origin server.
241 * You must call soup_connection_connect_async() or
242 * soup_connection_connect_sync() to connect it after creating it.
244 * Return value: the new connection (not yet ready for use).
247 soup_connection_new (const char *propname1, ...)
249 SoupConnection *conn;
252 va_start (ap, propname1);
253 conn = (SoupConnection *)g_object_new_valist (SOUP_TYPE_CONNECTION,
261 set_property (GObject *object, guint prop_id,
262 const GValue *value, GParamSpec *pspec)
264 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
267 case PROP_SERVER_ADDRESS:
268 priv->server_addr = g_value_dup_object (value);
269 goto changed_connection;
271 case PROP_PROXY_ADDRESS:
272 priv->proxy_addr = g_value_dup_object (value);
273 goto changed_connection;
276 priv->ssl_creds = g_value_get_pointer (value);
277 goto changed_connection;
280 if (priv->proxy_addr) {
281 priv->conn_addr = priv->proxy_addr;
282 if (priv->server_addr && priv->ssl_creds)
283 priv->mode = SOUP_CONNECTION_MODE_TUNNEL;
285 priv->mode = SOUP_CONNECTION_MODE_PROXY;
287 priv->conn_addr = priv->server_addr;
288 priv->mode = SOUP_CONNECTION_MODE_DIRECT;
292 case PROP_ASYNC_CONTEXT:
293 priv->async_context = g_value_get_pointer (value);
294 if (priv->async_context)
295 g_main_context_ref (priv->async_context);
298 priv->io_timeout = g_value_get_uint (value);
300 case PROP_IDLE_TIMEOUT:
301 priv->idle_timeout = g_value_get_uint (value);
304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
310 get_property (GObject *object, guint prop_id,
311 GValue *value, GParamSpec *pspec)
313 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
316 case PROP_SERVER_ADDRESS:
317 g_value_set_object (value, priv->server_addr);
319 case PROP_PROXY_ADDRESS:
320 g_value_set_object (value, priv->proxy_addr);
323 g_value_set_pointer (value, priv->ssl_creds);
325 case PROP_ASYNC_CONTEXT:
326 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
329 g_value_set_uint (value, priv->io_timeout);
331 case PROP_IDLE_TIMEOUT:
332 g_value_set_uint (value, priv->idle_timeout);
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 idle_timeout (gpointer conn)
343 soup_connection_disconnect (conn);
348 start_idle_timer (SoupConnection *conn)
350 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
352 if (priv->idle_timeout > 0 && !priv->idle_timeout_src) {
353 priv->idle_timeout_src =
354 soup_add_timeout (priv->async_context,
355 priv->idle_timeout * 1000,
361 stop_idle_timer (SoupConnectionPrivate *priv)
363 if (priv->idle_timeout_src) {
364 g_source_destroy (priv->idle_timeout_src);
365 priv->idle_timeout_src = NULL;
370 set_current_request (SoupConnectionPrivate *priv, SoupMessage *req)
372 g_return_if_fail (priv->cur_req == NULL);
374 stop_idle_timer (priv);
376 soup_message_set_io_status (req, SOUP_MESSAGE_IO_STATUS_RUNNING);
379 g_object_add_weak_pointer (G_OBJECT (req), (gpointer)&priv->cur_req);
383 clear_current_request (SoupConnection *conn)
385 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
387 priv->in_use = FALSE;
388 start_idle_timer (conn);
390 SoupMessage *cur_req = priv->cur_req;
392 g_object_remove_weak_pointer (G_OBJECT (priv->cur_req),
393 (gpointer)&priv->cur_req);
394 priv->cur_req = NULL;
396 if (!soup_message_is_keepalive (cur_req))
397 soup_connection_disconnect (conn);
399 priv->last_used = time (NULL);
400 soup_message_io_stop (cur_req);
406 socket_disconnected (SoupSocket *sock, gpointer conn)
408 soup_connection_disconnect (conn);
412 proxified_status (SoupConnectionPrivate *priv, guint status)
414 if (!priv->proxy_addr)
417 if (status == SOUP_STATUS_CANT_RESOLVE)
418 return SOUP_STATUS_CANT_RESOLVE_PROXY;
419 else if (status == SOUP_STATUS_CANT_CONNECT)
420 return SOUP_STATUS_CANT_CONNECT_PROXY;
426 connect_message (SoupConnectionPrivate *priv)
431 uri = soup_uri_new (NULL);
432 soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS);
433 soup_uri_set_host (uri, soup_address_get_name (priv->server_addr));
434 soup_uri_set_port (uri, soup_address_get_port (priv->server_addr));
435 msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT, uri);
442 tunnel_connect_finished (SoupMessage *msg, gpointer user_data)
444 SoupConnection *conn = user_data;
445 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
446 guint status = msg->status_code;
448 clear_current_request (conn);
450 if (SOUP_STATUS_IS_SUCCESSFUL (status) && priv->ssl_creds) {
451 const char *server_name =
452 soup_address_get_name (priv->server_addr);
453 if (soup_socket_start_proxy_ssl (priv->socket, server_name,
455 priv->connected = TRUE;
457 status = SOUP_STATUS_SSL_FAILED;
458 } else if (SOUP_STATUS_IS_REDIRECTION (status)) {
459 /* Oops, the proxy thinks we're a web browser. */
460 status = SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED;
463 g_signal_emit (conn, signals[CONNECT_RESULT], 0,
464 proxified_status (priv, status));
465 g_object_unref (msg);
469 tunnel_connect_restarted (SoupMessage *msg, gpointer user_data)
471 SoupConnection *conn = user_data;
472 guint status = msg->status_code;
474 /* We only allow one restart: if another one happens, treat
477 g_signal_handlers_disconnect_by_func (msg, tunnel_connect_restarted, conn);
478 g_signal_connect (msg, "restarted",
479 G_CALLBACK (tunnel_connect_finished), conn);
481 if (status == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
482 /* Our parent session has handled the authentication
483 * and attempted to restart the message.
485 if (soup_message_is_keepalive (msg)) {
486 /* Connection is still open, so just send the
489 soup_connection_send_request (conn, msg);
491 /* Tell the session to try again. */
492 soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
493 soup_message_finished (msg);
496 soup_message_finished (msg);
500 socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
502 SoupConnection *conn = user_data;
503 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
505 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
508 if (priv->mode == SOUP_CONNECTION_MODE_DIRECT && priv->ssl_creds) {
509 if (!soup_socket_start_ssl (sock, NULL)) {
510 status = SOUP_STATUS_SSL_FAILED;
515 if (priv->mode == SOUP_CONNECTION_MODE_TUNNEL) {
516 SoupMessage *connect_msg = connect_message (priv);
518 g_signal_connect (connect_msg, "restarted",
519 G_CALLBACK (tunnel_connect_restarted), conn);
520 g_signal_connect (connect_msg, "finished",
521 G_CALLBACK (tunnel_connect_finished), conn);
523 soup_connection_send_request (conn, connect_msg);
527 priv->connected = TRUE;
528 start_idle_timer (conn);
531 g_signal_emit (conn, signals[CONNECT_RESULT], 0,
532 proxified_status (priv, status));
535 /* from soup-misc.c... will eventually go away */
536 guint soup_signal_connect_once (gpointer instance, const char *detailed_signal,
537 GCallback c_handler, gpointer data);
540 address_resolved (SoupAddress *addr, guint status, gpointer data)
542 SoupConnection *conn = data;
543 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
545 if (status != SOUP_STATUS_OK) {
546 socket_connect_result (NULL, status, conn);
551 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, addr,
552 SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
553 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
555 soup_socket_connect_async (priv->socket, NULL,
556 socket_connect_result, conn);
557 g_signal_connect (priv->socket, "disconnected",
558 G_CALLBACK (socket_disconnected), conn);
562 * soup_connection_connect_async:
563 * @conn: the connection
564 * @callback: callback to call when the connection succeeds or fails
565 * @user_data: data for @callback
567 * Asynchronously connects @conn.
570 soup_connection_connect_async (SoupConnection *conn,
571 SoupConnectionCallback callback,
574 SoupConnectionPrivate *priv;
576 g_return_if_fail (SOUP_IS_CONNECTION (conn));
577 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
578 g_return_if_fail (priv->socket == NULL);
581 soup_signal_connect_once (conn, "connect_result",
582 G_CALLBACK (callback), user_data);
585 soup_address_resolve_async (priv->conn_addr, priv->async_context, NULL,
586 address_resolved, conn);
590 * soup_connection_connect_sync:
591 * @conn: the connection
593 * Synchronously connects @conn.
595 * Return value: the soup status
598 soup_connection_connect_sync (SoupConnection *conn)
600 SoupConnectionPrivate *priv;
603 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
604 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
605 g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED);
607 status = soup_address_resolve_sync (priv->conn_addr, NULL);
608 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
612 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->conn_addr,
613 SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
614 SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
615 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
618 status = soup_socket_connect_sync (priv->socket, NULL);
620 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
623 g_signal_connect (priv->socket, "disconnected",
624 G_CALLBACK (socket_disconnected), conn);
626 if (priv->mode == SOUP_CONNECTION_MODE_DIRECT && priv->ssl_creds) {
627 if (!soup_socket_start_ssl (priv->socket, NULL)) {
628 status = SOUP_STATUS_SSL_FAILED;
633 if (priv->mode == SOUP_CONNECTION_MODE_TUNNEL) {
634 SoupMessage *connect_msg = connect_message (priv);
636 soup_connection_send_request (conn, connect_msg);
637 status = connect_msg->status_code;
639 if (status == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
640 SOUP_MESSAGE_IS_STARTING (connect_msg)) {
641 if (soup_message_is_keepalive (connect_msg)) {
643 soup_connection_send_request (conn, connect_msg);
644 status = connect_msg->status_code;
646 status = SOUP_STATUS_TRY_AGAIN;
649 g_object_unref (connect_msg);
651 if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
652 const char *server_name =
653 soup_address_get_name (priv->server_addr);
654 if (!soup_socket_start_proxy_ssl (priv->socket,
657 status = SOUP_STATUS_SSL_FAILED;
661 if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
662 priv->connected = TRUE;
663 start_idle_timer (conn);
667 g_object_unref (priv->socket);
672 status = proxified_status (priv, status);
673 g_signal_emit (conn, signals[CONNECT_RESULT], 0, status);
679 * soup_connection_disconnect:
680 * @conn: a connection
682 * Disconnects @conn's socket and emits a %disconnected signal.
683 * After calling this, @conn will be essentially useless.
686 soup_connection_disconnect (SoupConnection *conn)
688 SoupConnectionPrivate *priv;
690 g_return_if_fail (SOUP_IS_CONNECTION (conn));
691 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
696 g_signal_handlers_disconnect_by_func (priv->socket,
697 socket_disconnected, conn);
698 soup_socket_disconnect (priv->socket);
699 g_object_unref (priv->socket);
702 /* Don't emit "disconnected" if we aren't yet connected */
703 if (!priv->connected)
706 priv->connected = FALSE;
709 priv->cur_req->status_code == SOUP_STATUS_IO_ERROR &&
710 priv->last_used != 0) {
711 /* There was a message queued on this connection, but
712 * the socket was closed while it was being sent.
713 * Since last_used is not 0, then that means at least
714 * one message was successfully sent on this
715 * connection before, and so the most likely cause of
716 * the IO_ERROR is that the connection was idle for
717 * too long and the server timed out and closed it
718 * (and we didn't notice until after we started
719 * sending the message). So we want the message to get
720 * tried again on a new connection. The only code path
721 * that could have gotten us to this point is through
722 * the call to io_cleanup() in
723 * soup_message_io_finished(), and so all we need to
724 * do to get the message requeued in this case is to
727 soup_message_cleanup_response (priv->cur_req);
728 soup_message_set_io_status (priv->cur_req,
729 SOUP_MESSAGE_IO_STATUS_QUEUED);
732 /* If cur_req is non-NULL but priv->last_used is 0, then that
733 * means this was the first message to be sent on this
734 * connection, and it failed, so the error probably means that
735 * there's some network or server problem, so we let the
736 * IO_ERROR be returned to the caller.
738 * (Of course, it's also possible that the error in the
739 * last_used != 0 case was because of a network/server problem
740 * too. It's even possible that the message crashed the
741 * server. In this case, requeuing it was the wrong thing to
742 * do, but presumably, the next attempt will also get an
743 * error, and eventually the message will be requeued onto a
744 * fresh connection and get an error, at which point the error
745 * will finally be returned to the caller.)
748 /* NB: this might cause conn to be destroyed. */
749 g_signal_emit (conn, signals[DISCONNECTED], 0);
753 soup_connection_get_socket (SoupConnection *conn)
755 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
757 return SOUP_CONNECTION_GET_PRIVATE (conn)->socket;
761 * soup_connection_is_in_use:
762 * @conn: a connection
764 * Tests whether or not @conn is in use.
766 * Return value: %TRUE if there is currently a request being processed
770 soup_connection_is_in_use (SoupConnection *conn)
772 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
774 return SOUP_CONNECTION_GET_PRIVATE (conn)->in_use;
778 * soup_connection_last_used:
779 * @conn: a #SoupConnection.
781 * Returns the last time a response was received on @conn.
783 * Return value: the last time a response was received on @conn, or 0
784 * if @conn has not been used yet.
787 soup_connection_last_used (SoupConnection *conn)
789 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
791 return SOUP_CONNECTION_GET_PRIVATE (conn)->last_used;
795 send_request (SoupConnection *conn, SoupMessage *req)
797 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
799 if (req != priv->cur_req) {
800 set_current_request (priv, req);
801 g_signal_emit (conn, signals[REQUEST_STARTED], 0, req);
804 soup_message_send_request (req, priv->socket, conn,
805 priv->mode == SOUP_CONNECTION_MODE_PROXY);
809 * soup_connection_send_request:
810 * @conn: a #SoupConnection
811 * @req: a #SoupMessage
813 * Sends @req on @conn. This is a low-level function, intended for use
817 soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
819 g_return_if_fail (SOUP_IS_CONNECTION (conn));
820 g_return_if_fail (SOUP_IS_MESSAGE (req));
821 g_return_if_fail (SOUP_CONNECTION_GET_PRIVATE (conn)->socket != NULL);
823 SOUP_CONNECTION_GET_CLASS (conn)->send_request (conn, req);
827 * soup_connection_reserve:
828 * @conn: a #SoupConnection
830 * Marks @conn as "in use" despite not actually having a message on
831 * it. This is used by #SoupSession to keep it from accidentally
832 * trying to queue two messages on the same connection from different
833 * threads at the same time.
836 soup_connection_reserve (SoupConnection *conn)
838 g_return_if_fail (SOUP_IS_CONNECTION (conn));
840 SOUP_CONNECTION_GET_PRIVATE (conn)->in_use = TRUE;
844 * soup_connection_release:
845 * @conn: a #SoupConnection
847 * Marks @conn as not "in use". This can be used to cancel the effect
848 * of a soup_connection_reserve(). It is not necessary to call this
849 * after soup_connection_send_request().
852 soup_connection_release (SoupConnection *conn)
854 g_return_if_fail (SOUP_IS_CONNECTION (conn));
856 clear_current_request (conn);