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-message-queue.h"
26 #include "soup-misc.h"
27 #include "soup-misc-private.h"
28 #include "soup-socket.h"
31 #include "soup-enum-types.h"
36 SoupAddress *remote_addr, *tunnel_addr;
40 gboolean ssl_fallback;
42 GMainContext *async_context;
44 SoupMessageQueueItem *cur_item;
45 SoupConnectionState state;
46 time_t unused_timeout;
47 guint io_timeout, idle_timeout;
48 GSource *idle_timeout_src;
49 } SoupConnectionPrivate;
50 #define SOUP_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CONNECTION, SoupConnectionPrivate))
52 G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
59 static guint signals[LAST_SIGNAL] = { 0 };
79 static void set_property (GObject *object, guint prop_id,
80 const GValue *value, GParamSpec *pspec);
81 static void get_property (GObject *object, guint prop_id,
82 GValue *value, GParamSpec *pspec);
84 static void stop_idle_timer (SoupConnectionPrivate *priv);
85 static void clear_current_item (SoupConnection *conn);
87 /* Number of seconds after which we close a connection that hasn't yet
90 #define SOUP_CONNECTION_UNUSED_TIMEOUT 3
93 soup_connection_init (SoupConnection *conn)
99 finalize (GObject *object)
101 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
103 if (priv->remote_addr)
104 g_object_unref (priv->remote_addr);
105 if (priv->tunnel_addr)
106 g_object_unref (priv->tunnel_addr);
108 soup_uri_free (priv->proxy_uri);
110 if (priv->async_context)
111 g_main_context_unref (priv->async_context);
113 G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
117 dispose (GObject *object)
119 SoupConnection *conn = SOUP_CONNECTION (object);
120 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
122 stop_idle_timer (priv);
123 /* Make sure clear_current_item doesn't re-establish the timeout */
124 priv->idle_timeout = 0;
126 if (priv->cur_item) {
127 g_warning ("Disposing connection with cur_item set");
128 clear_current_item (conn);
131 g_warning ("Disposing connection while connected");
132 soup_connection_disconnect (conn);
135 G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
139 soup_connection_class_init (SoupConnectionClass *connection_class)
141 GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
143 g_type_class_add_private (connection_class, sizeof (SoupConnectionPrivate));
145 /* virtual method override */
146 object_class->dispose = dispose;
147 object_class->finalize = finalize;
148 object_class->set_property = set_property;
149 object_class->get_property = get_property;
152 signals[DISCONNECTED] =
153 g_signal_new ("disconnected",
154 G_OBJECT_CLASS_TYPE (object_class),
156 G_STRUCT_OFFSET (SoupConnectionClass, disconnected),
158 soup_marshal_NONE__NONE,
162 g_object_class_install_property (
163 object_class, PROP_REMOTE_ADDRESS,
164 g_param_spec_object (SOUP_CONNECTION_REMOTE_ADDRESS,
166 "The address of the HTTP or proxy server",
168 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
169 g_object_class_install_property (
170 object_class, PROP_TUNNEL_ADDRESS,
171 g_param_spec_object (SOUP_CONNECTION_TUNNEL_ADDRESS,
173 "The address of the HTTPS server this tunnel connects to",
175 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
176 g_object_class_install_property (
177 object_class, PROP_PROXY_URI,
178 g_param_spec_boxed (SOUP_CONNECTION_PROXY_URI,
180 "URI of the HTTP proxy this connection connects to",
183 g_object_class_install_property (
184 object_class, PROP_SSL_CREDS,
185 g_param_spec_pointer (SOUP_CONNECTION_SSL_CREDENTIALS,
187 "Opaque SSL credentials for this connection",
188 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
189 g_object_class_install_property (
190 object_class, PROP_SSL_STRICT,
191 g_param_spec_boolean (SOUP_CONNECTION_SSL_STRICT,
192 "Strictly validate SSL certificates",
193 "Whether certificate errors should be considered a connection error",
195 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
196 g_object_class_install_property (
197 object_class, PROP_SSL_FALLBACK,
198 g_param_spec_boolean (SOUP_CONNECTION_SSL_FALLBACK,
200 "Use SSLv3 instead of TLS",
202 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
203 g_object_class_install_property (
204 object_class, PROP_ASYNC_CONTEXT,
205 g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
206 "Async GMainContext",
207 "GMainContext to dispatch this connection's async I/O in",
208 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
209 g_object_class_install_property (
210 object_class, PROP_TIMEOUT,
211 g_param_spec_uint (SOUP_CONNECTION_TIMEOUT,
213 "Value in seconds to timeout a blocking I/O",
216 g_object_class_install_property (
217 object_class, PROP_IDLE_TIMEOUT,
218 g_param_spec_uint (SOUP_CONNECTION_IDLE_TIMEOUT,
220 "Connection lifetime when idle",
222 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
223 g_object_class_install_property (
224 object_class, PROP_STATE,
225 g_param_spec_enum (SOUP_CONNECTION_STATE,
227 "Current state of connection",
228 SOUP_TYPE_CONNECTION_STATE, SOUP_CONNECTION_NEW,
230 g_object_class_install_property (
231 object_class, PROP_MESSAGE,
232 g_param_spec_object (SOUP_CONNECTION_MESSAGE,
234 "Message being processed",
241 soup_connection_new (const char *propname1, ...)
243 SoupConnection *conn;
246 va_start (ap, propname1);
247 conn = (SoupConnection *)g_object_new_valist (SOUP_TYPE_CONNECTION,
255 set_property (GObject *object, guint prop_id,
256 const GValue *value, GParamSpec *pspec)
258 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
261 case PROP_REMOTE_ADDRESS:
262 priv->remote_addr = g_value_dup_object (value);
264 case PROP_TUNNEL_ADDRESS:
265 priv->tunnel_addr = g_value_dup_object (value);
269 soup_uri_free (priv->proxy_uri);
270 priv->proxy_uri = g_value_dup_boxed (value);
273 priv->ssl_creds = g_value_get_pointer (value);
275 case PROP_SSL_STRICT:
276 priv->ssl_strict = g_value_get_boolean (value);
278 case PROP_SSL_FALLBACK:
279 priv->ssl_fallback = g_value_get_boolean (value);
281 case PROP_ASYNC_CONTEXT:
282 priv->async_context = g_value_get_pointer (value);
283 if (priv->async_context)
284 g_main_context_ref (priv->async_context);
287 priv->io_timeout = g_value_get_uint (value);
289 case PROP_IDLE_TIMEOUT:
290 priv->idle_timeout = g_value_get_uint (value);
293 soup_connection_set_state (SOUP_CONNECTION (object), g_value_get_uint (value));
296 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
302 get_property (GObject *object, guint prop_id,
303 GValue *value, GParamSpec *pspec)
305 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
308 case PROP_REMOTE_ADDRESS:
309 g_value_set_object (value, priv->remote_addr);
311 case PROP_TUNNEL_ADDRESS:
312 g_value_set_object (value, priv->tunnel_addr);
315 g_value_set_boxed (value, priv->proxy_uri);
318 g_value_set_pointer (value, priv->ssl_creds);
320 case PROP_SSL_STRICT:
321 g_value_set_boolean (value, priv->ssl_strict);
323 case PROP_SSL_FALLBACK:
324 g_value_set_boolean (value, priv->ssl_fallback);
326 case PROP_ASYNC_CONTEXT:
327 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
330 g_value_set_uint (value, priv->io_timeout);
332 case PROP_IDLE_TIMEOUT:
333 g_value_set_uint (value, priv->idle_timeout);
336 g_value_set_enum (value, priv->state);
340 g_value_set_object (value, priv->cur_item->msg);
342 g_value_set_object (value, NULL);
345 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
351 idle_timeout (gpointer conn)
353 soup_connection_disconnect (conn);
358 start_idle_timer (SoupConnection *conn)
360 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
362 if (priv->idle_timeout > 0 && !priv->idle_timeout_src) {
363 priv->idle_timeout_src =
364 soup_add_timeout (priv->async_context,
365 priv->idle_timeout * 1000,
371 stop_idle_timer (SoupConnectionPrivate *priv)
373 if (priv->idle_timeout_src) {
374 g_source_destroy (priv->idle_timeout_src);
375 priv->idle_timeout_src = NULL;
380 set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
382 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
384 g_return_if_fail (priv->cur_item == NULL);
386 g_object_freeze_notify (G_OBJECT (conn));
388 stop_idle_timer (priv);
390 item->state = SOUP_MESSAGE_RUNNING;
391 priv->cur_item = item;
392 g_object_notify (G_OBJECT (conn), "message");
394 if (priv->state == SOUP_CONNECTION_IDLE ||
395 item->msg->method != SOUP_METHOD_CONNECT)
396 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
398 g_object_thaw_notify (G_OBJECT (conn));
402 clear_current_item (SoupConnection *conn)
404 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
406 g_object_freeze_notify (G_OBJECT (conn));
408 priv->unused_timeout = 0;
409 start_idle_timer (conn);
411 if (priv->cur_item) {
412 SoupMessageQueueItem *item;
414 item = priv->cur_item;
415 priv->cur_item = NULL;
416 g_object_notify (G_OBJECT (conn), "message");
418 if (item->msg->method == SOUP_METHOD_CONNECT &&
419 SOUP_STATUS_IS_SUCCESSFUL (item->msg->status_code)) {
420 /* We're now effectively no longer proxying */
421 soup_uri_free (priv->proxy_uri);
422 priv->proxy_uri = NULL;
425 if (!soup_message_is_keepalive (item->msg))
426 soup_connection_disconnect (conn);
429 g_object_thaw_notify (G_OBJECT (conn));
433 socket_disconnected (SoupSocket *sock, gpointer conn)
435 soup_connection_disconnect (conn);
439 SoupConnection *conn;
440 SoupConnectionCallback callback;
441 gpointer callback_data;
442 GCancellable *cancellable;
443 } SoupConnectionAsyncConnectData;
446 socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
448 SoupConnectionAsyncConnectData *data = user_data;
449 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
451 if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
452 g_signal_connect (priv->socket, "disconnected",
453 G_CALLBACK (socket_disconnected), data->conn);
455 soup_connection_set_state (data->conn, SOUP_CONNECTION_IN_USE);
456 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
457 start_idle_timer (data->conn);
458 } else if (status == SOUP_STATUS_TLS_FAILED) {
459 priv->ssl_fallback = TRUE;
460 status = SOUP_STATUS_TRY_AGAIN;
463 if (data->callback) {
464 if (priv->proxy_uri != NULL)
465 status = soup_status_proxify (status);
466 data->callback (data->conn, status, data->callback_data);
468 g_object_unref (data->conn);
469 if (data->cancellable)
470 g_object_unref (data->cancellable);
471 g_slice_free (SoupConnectionAsyncConnectData, data);
475 socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
477 SoupConnectionAsyncConnectData *data = user_data;
478 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
480 if (SOUP_STATUS_IS_SUCCESSFUL (status) &&
481 priv->ssl_creds && !priv->tunnel_addr) {
482 if (soup_socket_start_ssl (sock, data->cancellable)) {
483 soup_socket_handshake_async (sock, data->cancellable,
484 socket_connect_finished, data);
488 status = SOUP_STATUS_SSL_FAILED;
491 socket_connect_finished (sock, status, data);
495 soup_connection_connect_async (SoupConnection *conn,
496 GCancellable *cancellable,
497 SoupConnectionCallback callback,
500 SoupConnectionAsyncConnectData *data;
501 SoupConnectionPrivate *priv;
503 g_return_if_fail (SOUP_IS_CONNECTION (conn));
504 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
505 g_return_if_fail (priv->socket == NULL);
507 soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
509 data = g_slice_new (SoupConnectionAsyncConnectData);
510 data->conn = g_object_ref (conn);
511 data->callback = callback;
512 data->callback_data = user_data;
513 data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
516 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
517 SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
518 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
519 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
520 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
521 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
522 "clean-dispose", TRUE,
524 soup_socket_connect_async (priv->socket, cancellable,
525 socket_connect_result, data);
529 soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
531 SoupConnectionPrivate *priv;
534 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
535 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
536 g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED);
538 soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
541 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
542 SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
543 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
544 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
545 SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
546 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
547 "clean-dispose", TRUE,
550 status = soup_socket_connect_sync (priv->socket, cancellable);
552 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
555 if (priv->ssl_creds && !priv->tunnel_addr) {
556 if (!soup_socket_start_ssl (priv->socket, cancellable))
557 status = SOUP_STATUS_SSL_FAILED;
559 status = soup_socket_handshake_sync (priv->socket, cancellable);
560 if (status == SOUP_STATUS_TLS_FAILED) {
561 priv->ssl_fallback = TRUE;
562 status = SOUP_STATUS_TRY_AGAIN;
567 if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
568 g_signal_connect (priv->socket, "disconnected",
569 G_CALLBACK (socket_disconnected), conn);
571 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
572 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
573 start_idle_timer (conn);
577 soup_socket_disconnect (priv->socket);
578 g_object_unref (priv->socket);
583 if (priv->proxy_uri != NULL)
584 status = soup_status_proxify (status);
589 soup_connection_get_tunnel_addr (SoupConnection *conn)
591 SoupConnectionPrivate *priv;
593 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
594 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
596 return priv->tunnel_addr;
600 soup_connection_start_ssl_sync (SoupConnection *conn,
601 GCancellable *cancellable)
603 SoupConnectionPrivate *priv;
604 const char *server_name;
607 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
608 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
610 server_name = soup_address_get_name (priv->tunnel_addr ?
613 if (!soup_socket_start_proxy_ssl (priv->socket, server_name,
615 return SOUP_STATUS_SSL_FAILED;
617 status = soup_socket_handshake_sync (priv->socket, cancellable);
618 if (status == SOUP_STATUS_TLS_FAILED) {
619 priv->ssl_fallback = TRUE;
620 status = SOUP_STATUS_TRY_AGAIN;
627 start_ssl_completed (SoupSocket *socket, guint status, gpointer user_data)
629 SoupConnectionAsyncConnectData *data = user_data;
630 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
632 if (status == SOUP_STATUS_TLS_FAILED) {
633 priv->ssl_fallback = TRUE;
634 status = SOUP_STATUS_TRY_AGAIN;
637 data->callback (data->conn, status, data->callback_data);
638 g_object_unref (data->conn);
639 g_slice_free (SoupConnectionAsyncConnectData, data);
643 idle_start_ssl_completed (gpointer user_data)
645 SoupConnectionAsyncConnectData *data = user_data;
647 start_ssl_completed (NULL, SOUP_STATUS_SSL_FAILED, data);
652 soup_connection_start_ssl_async (SoupConnection *conn,
653 GCancellable *cancellable,
654 SoupConnectionCallback callback,
657 SoupConnectionPrivate *priv;
658 const char *server_name;
659 SoupConnectionAsyncConnectData *data;
661 g_return_if_fail (SOUP_IS_CONNECTION (conn));
662 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
664 data = g_slice_new (SoupConnectionAsyncConnectData);
665 data->conn = g_object_ref (conn);
666 data->callback = callback;
667 data->callback_data = user_data;
669 server_name = soup_address_get_name (priv->tunnel_addr ?
672 if (!soup_socket_start_proxy_ssl (priv->socket, server_name,
674 soup_add_completion (priv->async_context,
675 idle_start_ssl_completed, data);
679 soup_socket_handshake_async (priv->socket, cancellable,
680 start_ssl_completed, data);
684 * soup_connection_disconnect:
685 * @conn: a connection
687 * Disconnects @conn's socket and emits a %disconnected signal.
688 * After calling this, @conn will be essentially useless.
691 soup_connection_disconnect (SoupConnection *conn)
693 SoupConnectionPrivate *priv;
694 SoupConnectionState old_state;
696 g_return_if_fail (SOUP_IS_CONNECTION (conn));
697 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
699 old_state = priv->state;
700 if (old_state != SOUP_CONNECTION_DISCONNECTED)
701 soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
704 g_signal_handlers_disconnect_by_func (priv->socket,
705 socket_disconnected, conn);
706 soup_socket_disconnect (priv->socket);
707 g_object_unref (priv->socket);
711 if (old_state != SOUP_CONNECTION_DISCONNECTED)
712 g_signal_emit (conn, signals[DISCONNECTED], 0);
716 soup_connection_get_socket (SoupConnection *conn)
718 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
720 return SOUP_CONNECTION_GET_PRIVATE (conn)->socket;
724 soup_connection_get_proxy_uri (SoupConnection *conn)
726 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
728 return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri;
732 soup_connection_is_via_proxy (SoupConnection *conn)
734 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
736 return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri != NULL;
740 soup_connection_get_state (SoupConnection *conn)
742 SoupConnectionPrivate *priv;
744 g_return_val_if_fail (SOUP_IS_CONNECTION (conn),
745 SOUP_CONNECTION_DISCONNECTED);
746 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
749 if (priv->state == SOUP_CONNECTION_IDLE) {
752 pfd.fd = soup_socket_get_fd (priv->socket);
753 pfd.events = G_IO_IN;
755 if (g_poll (&pfd, 1, 0) == 1)
756 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
759 if (priv->state == SOUP_CONNECTION_IDLE &&
760 priv->unused_timeout && priv->unused_timeout < time (NULL))
761 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
767 soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
769 SoupConnectionPrivate *priv;
770 SoupConnectionState old_state;
772 g_return_if_fail (SOUP_IS_CONNECTION (conn));
773 g_return_if_fail (state >= SOUP_CONNECTION_NEW &&
774 state <= SOUP_CONNECTION_DISCONNECTED);
776 g_object_freeze_notify (G_OBJECT (conn));
778 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
779 old_state = priv->state;
781 if ((state == SOUP_CONNECTION_IDLE ||
782 state == SOUP_CONNECTION_DISCONNECTED) &&
783 old_state == SOUP_CONNECTION_IN_USE)
784 clear_current_item (conn);
786 g_object_notify (G_OBJECT (conn), "state");
787 g_object_thaw_notify (G_OBJECT (conn));
791 soup_connection_get_ever_used (SoupConnection *conn)
793 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
795 return SOUP_CONNECTION_GET_PRIVATE (conn)->unused_timeout == 0;
799 soup_connection_get_ssl_fallback (SoupConnection *conn)
801 return SOUP_CONNECTION_GET_PRIVATE (conn)->ssl_fallback;
805 soup_connection_send_request (SoupConnection *conn,
806 SoupMessageQueueItem *item,
807 SoupMessageCompletionFn completion_cb,
810 SoupConnectionPrivate *priv;
812 g_return_if_fail (SOUP_IS_CONNECTION (conn));
813 g_return_if_fail (item != NULL);
814 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
815 g_return_if_fail (priv->state != SOUP_CONNECTION_NEW && priv->state != SOUP_CONNECTION_DISCONNECTED);
817 if (item != priv->cur_item)
818 set_current_item (conn, item);
819 soup_message_send_request (item, completion_cb, user_data);