1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-message.c: HTTP request/response
5 * Copyright (C) 2000-2003, Ximian, Inc.
10 #include "soup-auth.h"
11 #include "soup-error.h"
12 #include "soup-marshal.h"
13 #include "soup-message.h"
14 #include "soup-message-private.h"
15 #include "soup-misc.h"
16 #include "soup-context.h"
17 #include "soup-private.h"
18 #include "soup-queue.h"
20 #define PARENT_TYPE G_TYPE_OBJECT
21 static GObjectClass *parent_class;
23 guint soup_message_signals[LAST_SIGNAL] = { 0 };
25 static void cleanup_message (SoupMessage *req);
28 init (GObject *object)
30 SoupMessage *msg = SOUP_MESSAGE (object);
32 msg->priv = g_new0 (SoupMessagePrivate, 1);
34 msg->priv->status = SOUP_MESSAGE_STATUS_IDLE;
36 msg->request_headers = g_hash_table_new (soup_str_case_hash,
39 msg->response_headers = g_hash_table_new (soup_str_case_hash,
42 msg->priv->http_version = SOUP_HTTP_1_1;
46 finalize (GObject *object)
48 SoupMessage *msg = SOUP_MESSAGE (object);
50 cleanup_message (msg);
52 if (msg->priv->context)
53 g_object_unref (msg->priv->context);
55 if (msg->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
56 g_free (msg->request.body);
57 if (msg->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
58 g_free (msg->response.body);
60 soup_message_clear_headers (msg->request_headers);
61 g_hash_table_destroy (msg->request_headers);
63 soup_message_clear_headers (msg->response_headers);
64 g_hash_table_destroy (msg->response_headers);
66 g_slist_foreach (msg->priv->content_handlers, (GFunc) g_free, NULL);
67 g_slist_free (msg->priv->content_handlers);
69 g_free ((char *) msg->errorphrase);
73 G_OBJECT_CLASS (parent_class)->finalize (object);
77 class_init (GObjectClass *object_class)
79 parent_class = g_type_class_ref (PARENT_TYPE);
81 /* virtual method override */
82 object_class->finalize = finalize;
85 soup_message_signals[WROTE_HEADERS] =
86 g_signal_new ("wrote_headers",
87 G_OBJECT_CLASS_TYPE (object_class),
89 G_STRUCT_OFFSET (SoupMessageClass, wrote_headers),
91 soup_marshal_NONE__NONE,
93 soup_message_signals[WROTE_CHUNK] =
94 g_signal_new ("wrote_chunk",
95 G_OBJECT_CLASS_TYPE (object_class),
97 G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk),
99 soup_marshal_NONE__NONE,
101 soup_message_signals[WROTE_BODY] =
102 g_signal_new ("wrote_body",
103 G_OBJECT_CLASS_TYPE (object_class),
105 G_STRUCT_OFFSET (SoupMessageClass, wrote_body),
107 soup_marshal_NONE__NONE,
109 soup_message_signals[WRITE_ERROR] =
110 g_signal_new ("write_error",
111 G_OBJECT_CLASS_TYPE (object_class),
113 G_STRUCT_OFFSET (SoupMessageClass, write_error),
115 soup_marshal_NONE__NONE,
118 soup_message_signals[READ_HEADERS] =
119 g_signal_new ("read_headers",
120 G_OBJECT_CLASS_TYPE (object_class),
122 G_STRUCT_OFFSET (SoupMessageClass, read_headers),
124 soup_marshal_NONE__NONE,
126 soup_message_signals[READ_CHUNK] =
127 g_signal_new ("read_chunk",
128 G_OBJECT_CLASS_TYPE (object_class),
130 G_STRUCT_OFFSET (SoupMessageClass, read_chunk),
132 soup_marshal_NONE__POINTER,
135 soup_message_signals[READ_BODY] =
136 g_signal_new ("read_body",
137 G_OBJECT_CLASS_TYPE (object_class),
139 G_STRUCT_OFFSET (SoupMessageClass, read_body),
141 soup_marshal_NONE__NONE,
143 soup_message_signals[READ_ERROR] =
144 g_signal_new ("read_error",
145 G_OBJECT_CLASS_TYPE (object_class),
147 G_STRUCT_OFFSET (SoupMessageClass, read_error),
149 soup_marshal_NONE__NONE,
153 SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE)
158 * @method: the HTTP method for the created request
159 * @uri: the destination endpoint (as a string)
161 * Creates a new empty #SoupMessage, which will connect to @uri
163 * Return value: the new #SoupMessage (or %NULL if @uri could not
167 soup_message_new (const char *method, const char *uri)
172 ctx = soup_context_get (uri);
176 msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
177 msg->method = method ? method : SOUP_METHOD_GET;
178 msg->priv->context = ctx;
184 * soup_message_new_from_uri:
185 * @method: the HTTP method for the created request
186 * @uri: the destination endpoint (as a #SoupUri)
188 * Creates a new empty #SoupMessage, which will connect to @uri
190 * Return value: the new #SoupMessage (or %NULL if @uri is invalid)
193 soup_message_new_from_uri (const char *method, const SoupUri *uri)
198 ctx = soup_context_from_uri (uri);
202 msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
203 msg->method = method ? method : SOUP_METHOD_GET;
204 msg->priv->context = ctx;
210 * soup_message_set_request:
212 * @content_type: MIME Content-Type of the body
213 * @req_owner: the #SoupOwnership of the passed data buffer.
214 * @req_body: a data buffer containing the body of the message request.
215 * @req_length: the byte length of @req_body.
217 * Convenience function to set the request body of a #SoupMessage
220 soup_message_set_request (SoupMessage *msg,
221 const char *content_type,
222 SoupOwnership req_owner,
226 g_return_if_fail (SOUP_IS_MESSAGE (msg));
227 g_return_if_fail (content_type != NULL);
228 g_return_if_fail (req_body != NULL || req_length == 0);
230 soup_message_add_header (msg->request_headers,
231 "Content-Type", content_type);
232 msg->request.owner = req_owner;
233 msg->request.body = req_body;
234 msg->request.length = req_length;
238 * soup_message_set_response:
240 * @content_type: MIME Content-Type of the body
241 * @req_owner: the #SoupOwnership of the passed data buffer.
242 * @req_body: a data buffer containing the body of the message response.
243 * @req_length: the byte length of @req_body.
245 * Convenience function to set the response body of a #SoupMessage
248 soup_message_set_response (SoupMessage *msg,
249 const char *content_type,
250 SoupOwnership resp_owner,
254 g_return_if_fail (SOUP_IS_MESSAGE (msg));
255 g_return_if_fail (content_type != NULL);
256 g_return_if_fail (resp_body != NULL || resp_length == 0);
258 soup_message_add_header (msg->response_headers,
259 "Content-Type", content_type);
260 msg->response.owner = resp_owner;
261 msg->response.body = resp_body;
262 msg->response.length = resp_length;
266 cleanup_message (SoupMessage *req)
268 if (req->priv->read_state)
269 soup_message_read_cancel (req);
271 if (req->priv->write_state)
272 soup_message_write_cancel (req);
274 if (req->priv->connect_tag) {
275 soup_context_cancel_connect (req->priv->connect_tag);
276 req->priv->connect_tag = NULL;
279 soup_message_set_connection (req, NULL);
281 soup_queue_remove_request (req);
285 * soup_message_issue_callback:
286 * @req: a #SoupMessage currently being processed.
287 * @error: a #SoupErrorCode to be passed to @req's completion callback.
289 * Finalizes the message request, by first freeing any temporary
290 * resources, then issuing the callback function pointer passed in
291 * soup_message_new() or soup_message_new_full(). If, after returning
292 * from the callback, the message has not been requeued, @req will be
296 soup_message_issue_callback (SoupMessage *req)
298 g_return_if_fail (SOUP_IS_MESSAGE (req));
301 * Make sure we don't have some icky recursion if the callback
302 * runs the main loop, and the connection has some data or error
303 * which causes the callback to be run again.
305 cleanup_message (req);
307 if (req->priv->callback) {
308 (*req->priv->callback) (req, req->priv->user_data);
310 if (!SOUP_MESSAGE_IS_STARTING (req))
311 g_object_unref (req);
316 * soup_message_disconnect:
317 * @msg: a #SoupMessage
319 * Utility function to close and unref the connection associated with
320 * @msg if there was an error.
323 soup_message_disconnect (SoupMessage *msg)
325 if (msg->priv->connection) {
326 soup_connection_disconnect (msg->priv->connection);
327 soup_message_set_connection (msg, NULL);
332 * soup_message_cancel:
333 * @msg: a #SoupMessage currently being processed.
335 * Cancel a running message, and issue completion callback with an
336 * error code of %SOUP_ERROR_CANCELLED. If not requeued by the
337 * completion callback, the @msg will be destroyed.
340 soup_message_cancel (SoupMessage *msg)
342 soup_message_set_error (msg, SOUP_ERROR_CANCELLED);
343 soup_message_disconnect (msg);
344 soup_message_issue_callback (msg);
348 free_header_list (gpointer name, gpointer vals, gpointer user_data)
351 g_slist_foreach (vals, (GFunc) g_free, NULL);
358 soup_message_clear_headers (GHashTable *hash)
360 g_return_if_fail (hash != NULL);
362 g_hash_table_foreach_remove (hash, free_header_list, NULL);
366 soup_message_remove_header (GHashTable *hash, const char *name)
368 gpointer old_key, old_vals;
370 g_return_if_fail (hash != NULL);
371 g_return_if_fail (name != NULL || name[0] != '\0');
373 if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
374 g_hash_table_remove (hash, name);
375 free_header_list (old_key, old_vals, NULL);
380 soup_message_add_header (GHashTable *hash, const char *name, const char *value)
384 g_return_if_fail (hash != NULL);
385 g_return_if_fail (name != NULL || name [0] != '\0');
386 g_return_if_fail (value != NULL);
388 old_value = g_hash_table_lookup (hash, name);
391 g_slist_append (old_value, g_strdup (value));
393 g_hash_table_insert (hash, g_strdup (name),
394 g_slist_append (NULL, g_strdup (value)));
399 * soup_message_get_header:
400 * @hash: a header hash table
401 * @name: header name.
403 * Lookup the first transport header in @hash with a key equal to
406 * Return value: the header's value or %NULL if not found.
409 soup_message_get_header (GHashTable *hash, const char *name)
413 g_return_val_if_fail (hash != NULL, NULL);
414 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
416 vals = g_hash_table_lookup (hash, name);
424 * soup_message_get_header_list:
425 * @hash: a header hash table
426 * @name: header name.
428 * Lookup the all transport request headers in @hash with a key equal
431 * Return value: a const pointer to a #GSList of header values or
432 * %NULL if not found.
435 soup_message_get_header_list (GHashTable *hash, const char *name)
437 g_return_val_if_fail (hash != NULL, NULL);
438 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
440 return g_hash_table_lookup (hash, name);
446 } SoupMessageForeachHeaderData;
449 foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
451 GSList *vals = value;
452 SoupMessageForeachHeaderData *data = user_data;
455 (*data->func) (name, vals->data, data->user_data);
461 soup_message_foreach_header (GHashTable *hash, GHFunc func, gpointer user_data)
463 SoupMessageForeachHeaderData data;
465 g_return_if_fail (hash != NULL);
466 g_return_if_fail (func != NULL);
469 data.user_data = user_data;
470 g_hash_table_foreach (hash, foreach_value_in_list, &data);
474 queue_message (SoupMessage *req)
476 if (!req->priv->context) {
477 soup_message_set_error_full (req,
478 SOUP_ERROR_CANCELLED,
479 "Attempted to queue a message "
480 "with no destination context");
481 soup_message_issue_callback (req);
485 if (req->priv->status != SOUP_MESSAGE_STATUS_IDLE)
486 cleanup_message (req);
488 switch (req->response.owner) {
489 case SOUP_BUFFER_USER_OWNED:
490 soup_message_set_error_full (req,
491 SOUP_ERROR_CANCELLED,
492 "Attempted to queue a message "
493 "with a user owned response "
495 soup_message_issue_callback (req);
497 case SOUP_BUFFER_SYSTEM_OWNED:
498 g_free (req->response.body);
500 case SOUP_BUFFER_STATIC:
504 req->response.owner = 0;
505 req->response.body = NULL;
506 req->response.length = 0;
508 soup_message_clear_headers (req->response_headers);
513 if (req->errorphrase) {
514 g_free ((char *) req->errorphrase);
515 req->errorphrase = NULL;
518 soup_queue_message (req);
522 * soup_message_queue:
523 * @req: a #SoupMessage.
524 * @callback: a #SoupCallbackFn which will be called after the message
525 * completes or when an unrecoverable error occurs.
526 * @user_data: a pointer passed to @callback.
528 * Queues the message @req for sending. All messages are processed
529 * while the glib main loop runs. If this #SoupMessage has been
530 * processed before, any resources related to the time it was last
533 * If the response #SoupDataBuffer has an owner of
534 * %SOUP_BUFFER_USER_OWNED, the message will not be queued, and
535 * @callback will be called with a #SoupErrorCode of
536 * %SOUP_ERROR_CANCELLED.
538 * Upon message completetion, the callback specified in @callback will
539 * be invoked. If after returning from this callback the message has
540 * not been requeued using soup_message_queue(), @req will be unreffed.
543 soup_message_queue (SoupMessage *req,
544 SoupCallbackFn callback,
547 g_return_if_fail (SOUP_IS_MESSAGE (req));
549 req->priv->callback = callback;
550 req->priv->user_data = user_data;
556 requeue_read_error (SoupMessage *msg, gpointer user_data)
558 soup_message_disconnect (msg);
563 requeue_read_finished (SoupMessage *msg, gpointer user_data)
565 SoupConnection *conn = msg->priv->connection;
568 soup_message_set_connection (msg, NULL);
570 if (soup_connection_is_connected (conn)) {
571 soup_connection_mark_old (conn);
573 g_object_unref (conn);
578 soup_message_set_connection (msg, conn);
582 * soup_message_requeue:
583 * @req: a #SoupMessage
585 * This causes @req to be placed back on the queue to be attempted
589 soup_message_requeue (SoupMessage *req)
591 g_return_if_fail (SOUP_IS_MESSAGE (req));
593 if (req->priv->connection && req->priv->read_state) {
594 soup_message_read_set_callbacks (req, NULL, NULL,
595 requeue_read_finished,
596 requeue_read_error, NULL);
598 if (req->priv->write_state)
599 soup_message_write_cancel (req);
606 * @msg: a #SoupMessage.
608 * Synchronously send @msg. This call will not return until the
609 * transfer is finished successfully or there is an unrecoverable
612 * @msg is not freed upon return.
614 * Return value: the #SoupErrorClass of the error encountered while
615 * sending or reading the response.
618 soup_message_send (SoupMessage *msg)
620 soup_message_queue (msg, NULL, NULL);
623 g_main_iteration (TRUE);
625 if (msg->priv->status == SOUP_MESSAGE_STATUS_FINISHED ||
626 SOUP_ERROR_IS_TRANSPORT (msg->errorcode))
629 /* Quit if soup_shutdown has been called */
630 if (!soup_initialized)
631 return SOUP_ERROR_CANCELLED;
634 return msg->errorclass;
638 soup_message_set_flags (SoupMessage *msg, guint flags)
640 g_return_if_fail (SOUP_IS_MESSAGE (msg));
642 msg->priv->msg_flags = flags;
646 soup_message_get_flags (SoupMessage *msg)
648 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
650 return msg->priv->msg_flags;
654 soup_message_set_http_version (SoupMessage *msg, SoupHttpVersion version)
656 g_return_if_fail (SOUP_IS_MESSAGE (msg));
658 msg->priv->http_version = version;
662 soup_message_get_http_version (SoupMessage *msg)
664 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
666 return msg->priv->http_version;
670 soup_message_is_keepalive (SoupMessage *msg)
672 const char *c_conn, *s_conn;
674 c_conn = soup_message_get_header (msg->request_headers, "Connection");
675 s_conn = soup_message_get_header (msg->response_headers, "Connection");
677 if (msg->priv->http_version == SOUP_HTTP_1_0) {
678 /* Only persistent if the client requested keepalive
679 * and the server agreed.
682 if (!c_conn || !s_conn)
684 if (g_strcasecmp (c_conn, "Keep-Alive") != 0 ||
685 g_strcasecmp (s_conn, "Keep-Alive") != 0)
690 /* Persistent unless either side requested otherwise */
692 if (c_conn && g_strcasecmp (c_conn, "close") == 0)
694 if (s_conn && g_strcasecmp (s_conn, "close") == 0)
702 soup_message_set_context (SoupMessage *msg, SoupContext *new_ctx)
704 g_return_if_fail (SOUP_IS_MESSAGE (msg));
706 if (msg->priv->context && new_ctx) {
707 const SoupUri *old, *new;
709 old = soup_context_get_uri (msg->priv->context);
710 new = soup_context_get_uri (new_ctx);
711 if (strcmp (old->host, new->host) != 0)
712 cleanup_message (msg);
714 cleanup_message (msg);
717 g_object_ref (new_ctx);
718 if (msg->priv->context)
719 g_object_unref (msg->priv->context);
721 msg->priv->context = new_ctx;
725 soup_message_get_uri (SoupMessage *msg)
727 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
729 return soup_context_get_uri (msg->priv->context);
733 soup_message_set_connection (SoupMessage *msg, SoupConnection *conn)
736 soup_connection_set_in_use (conn, TRUE);
739 if (msg->priv->connection) {
740 soup_connection_set_in_use (msg->priv->connection, FALSE);
741 g_object_unref (msg->priv->connection);
744 msg->priv->connection = conn;
747 msg->priv->socket = soup_connection_get_socket (conn);
748 g_object_ref (msg->priv->socket);
749 } else if (msg->priv->socket) {
750 g_object_unref (msg->priv->socket);
751 msg->priv->socket = NULL;
756 soup_message_get_connection (SoupMessage *msg)
758 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
760 return msg->priv->connection;
764 soup_message_get_socket (SoupMessage *msg)
766 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
768 return msg->priv->socket;
772 soup_message_set_error (SoupMessage *msg, SoupKnownErrorCode errcode)
774 g_return_if_fail (SOUP_IS_MESSAGE (msg));
775 g_return_if_fail (errcode != 0);
777 g_free ((char *) msg->errorphrase);
779 msg->errorcode = errcode;
780 msg->errorclass = soup_error_get_class (errcode);
781 msg->errorphrase = g_strdup (soup_error_get_phrase (errcode));
785 soup_message_set_error_full (SoupMessage *msg,
787 const char *errphrase)
789 g_return_if_fail (SOUP_IS_MESSAGE (msg));
790 g_return_if_fail (errcode != 0);
791 g_return_if_fail (errphrase != NULL);
793 g_free ((char *) msg->errorphrase);
795 msg->errorcode = errcode;
796 msg->errorclass = soup_error_get_class (errcode);
797 msg->errorphrase = g_strdup (errphrase);