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-connection.h"
12 #include "soup-error.h"
13 #include "soup-marshal.h"
14 #include "soup-message.h"
15 #include "soup-message-private.h"
16 #include "soup-misc.h"
17 #include "soup-context.h"
18 #include "soup-private.h"
19 #include "soup-queue.h"
21 #define PARENT_TYPE G_TYPE_OBJECT
22 static GObjectClass *parent_class;
24 guint soup_message_signals[LAST_SIGNAL] = { 0 };
26 static void cleanup_message (SoupMessage *req);
29 init (GObject *object)
31 SoupMessage *msg = SOUP_MESSAGE (object);
33 msg->priv = g_new0 (SoupMessagePrivate, 1);
35 msg->priv->status = SOUP_MESSAGE_STATUS_IDLE;
37 msg->request_headers = g_hash_table_new (soup_str_case_hash,
40 msg->response_headers = g_hash_table_new (soup_str_case_hash,
43 msg->priv->http_version = SOUP_HTTP_1_1;
47 finalize (GObject *object)
49 SoupMessage *msg = SOUP_MESSAGE (object);
51 cleanup_message (msg);
53 if (msg->priv->context)
54 g_object_unref (msg->priv->context);
56 if (msg->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
57 g_free (msg->request.body);
58 if (msg->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
59 g_free (msg->response.body);
61 soup_message_clear_headers (msg->request_headers);
62 g_hash_table_destroy (msg->request_headers);
64 soup_message_clear_headers (msg->response_headers);
65 g_hash_table_destroy (msg->response_headers);
67 g_slist_foreach (msg->priv->content_handlers, (GFunc) g_free, NULL);
68 g_slist_free (msg->priv->content_handlers);
70 g_free ((char *) msg->errorphrase);
74 G_OBJECT_CLASS (parent_class)->finalize (object);
78 class_init (GObjectClass *object_class)
80 parent_class = g_type_class_ref (PARENT_TYPE);
82 /* virtual method override */
83 object_class->finalize = finalize;
86 soup_message_signals[WROTE_HEADERS] =
87 g_signal_new ("wrote_headers",
88 G_OBJECT_CLASS_TYPE (object_class),
90 G_STRUCT_OFFSET (SoupMessageClass, wrote_headers),
92 soup_marshal_NONE__NONE,
94 soup_message_signals[WROTE_CHUNK] =
95 g_signal_new ("wrote_chunk",
96 G_OBJECT_CLASS_TYPE (object_class),
98 G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk),
100 soup_marshal_NONE__NONE,
102 soup_message_signals[WROTE_BODY] =
103 g_signal_new ("wrote_body",
104 G_OBJECT_CLASS_TYPE (object_class),
106 G_STRUCT_OFFSET (SoupMessageClass, wrote_body),
108 soup_marshal_NONE__NONE,
110 soup_message_signals[WRITE_ERROR] =
111 g_signal_new ("write_error",
112 G_OBJECT_CLASS_TYPE (object_class),
114 G_STRUCT_OFFSET (SoupMessageClass, write_error),
116 soup_marshal_NONE__NONE,
119 soup_message_signals[READ_HEADERS] =
120 g_signal_new ("read_headers",
121 G_OBJECT_CLASS_TYPE (object_class),
123 G_STRUCT_OFFSET (SoupMessageClass, read_headers),
125 soup_marshal_NONE__NONE,
127 soup_message_signals[READ_CHUNK] =
128 g_signal_new ("read_chunk",
129 G_OBJECT_CLASS_TYPE (object_class),
131 G_STRUCT_OFFSET (SoupMessageClass, read_chunk),
133 soup_marshal_NONE__POINTER,
136 soup_message_signals[READ_BODY] =
137 g_signal_new ("read_body",
138 G_OBJECT_CLASS_TYPE (object_class),
140 G_STRUCT_OFFSET (SoupMessageClass, read_body),
142 soup_marshal_NONE__NONE,
144 soup_message_signals[READ_ERROR] =
145 g_signal_new ("read_error",
146 G_OBJECT_CLASS_TYPE (object_class),
148 G_STRUCT_OFFSET (SoupMessageClass, read_error),
150 soup_marshal_NONE__NONE,
154 SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE)
159 * @method: the HTTP method for the created request
160 * @uri: the destination endpoint (as a string)
162 * Creates a new empty #SoupMessage, which will connect to @uri
164 * Return value: the new #SoupMessage (or %NULL if @uri could not
168 soup_message_new (const char *method, const char *uri)
173 ctx = soup_context_get (uri);
177 msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
178 msg->method = method ? method : SOUP_METHOD_GET;
179 msg->priv->context = ctx;
185 * soup_message_new_from_uri:
186 * @method: the HTTP method for the created request
187 * @uri: the destination endpoint (as a #SoupUri)
189 * Creates a new empty #SoupMessage, which will connect to @uri
191 * Return value: the new #SoupMessage (or %NULL if @uri is invalid)
194 soup_message_new_from_uri (const char *method, const SoupUri *uri)
199 ctx = soup_context_from_uri (uri);
203 msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
204 msg->method = method ? method : SOUP_METHOD_GET;
205 msg->priv->context = ctx;
211 * soup_message_set_request:
213 * @content_type: MIME Content-Type of the body
214 * @req_owner: the #SoupOwnership of the passed data buffer.
215 * @req_body: a data buffer containing the body of the message request.
216 * @req_length: the byte length of @req_body.
218 * Convenience function to set the request body of a #SoupMessage
221 soup_message_set_request (SoupMessage *msg,
222 const char *content_type,
223 SoupOwnership req_owner,
227 g_return_if_fail (SOUP_IS_MESSAGE (msg));
228 g_return_if_fail (content_type != NULL);
229 g_return_if_fail (req_body != NULL || req_length == 0);
231 soup_message_add_header (msg->request_headers,
232 "Content-Type", content_type);
233 msg->request.owner = req_owner;
234 msg->request.body = req_body;
235 msg->request.length = req_length;
239 * soup_message_set_response:
241 * @content_type: MIME Content-Type of the body
242 * @req_owner: the #SoupOwnership of the passed data buffer.
243 * @req_body: a data buffer containing the body of the message response.
244 * @req_length: the byte length of @req_body.
246 * Convenience function to set the response body of a #SoupMessage
249 soup_message_set_response (SoupMessage *msg,
250 const char *content_type,
251 SoupOwnership resp_owner,
255 g_return_if_fail (SOUP_IS_MESSAGE (msg));
256 g_return_if_fail (content_type != NULL);
257 g_return_if_fail (resp_body != NULL || resp_length == 0);
259 soup_message_add_header (msg->response_headers,
260 "Content-Type", content_type);
261 msg->response.owner = resp_owner;
262 msg->response.body = resp_body;
263 msg->response.length = resp_length;
267 cleanup_message (SoupMessage *req)
269 if (req->priv->read_state)
270 soup_message_read_cancel (req);
272 if (req->priv->write_state)
273 soup_message_write_cancel (req);
275 if (req->priv->connect_tag) {
276 soup_context_cancel_connect (req->priv->connect_tag);
277 req->priv->connect_tag = NULL;
280 soup_message_set_connection (req, NULL);
282 soup_queue_remove_request (req);
286 * soup_message_issue_callback:
287 * @req: a #SoupMessage currently being processed.
288 * @error: a #SoupErrorCode to be passed to @req's completion callback.
290 * Finalizes the message request, by first freeing any temporary
291 * resources, then issuing the callback function pointer passed in
292 * soup_message_new() or soup_message_new_full(). If, after returning
293 * from the callback, the message has not been requeued, @req will be
297 soup_message_issue_callback (SoupMessage *req)
299 g_return_if_fail (SOUP_IS_MESSAGE (req));
302 * Make sure we don't have some icky recursion if the callback
303 * runs the main loop, and the connection has some data or error
304 * which causes the callback to be run again.
306 cleanup_message (req);
308 if (req->priv->callback) {
309 (*req->priv->callback) (req, req->priv->user_data);
311 if (!SOUP_MESSAGE_IS_STARTING (req))
312 g_object_unref (req);
317 * soup_message_disconnect:
318 * @msg: a #SoupMessage
320 * Utility function to close and unref the connection associated with
321 * @msg if there was an error.
324 soup_message_disconnect (SoupMessage *msg)
326 if (msg->priv->connection) {
327 soup_connection_disconnect (msg->priv->connection);
328 soup_message_set_connection (msg, NULL);
333 * soup_message_cancel:
334 * @msg: a #SoupMessage currently being processed.
336 * Cancel a running message, and issue completion callback with an
337 * error code of %SOUP_ERROR_CANCELLED. If not requeued by the
338 * completion callback, the @msg will be destroyed.
341 soup_message_cancel (SoupMessage *msg)
343 soup_message_set_error (msg, SOUP_ERROR_CANCELLED);
344 soup_message_disconnect (msg);
345 soup_message_issue_callback (msg);
349 free_header_list (gpointer name, gpointer vals, gpointer user_data)
352 g_slist_foreach (vals, (GFunc) g_free, NULL);
359 soup_message_clear_headers (GHashTable *hash)
361 g_return_if_fail (hash != NULL);
363 g_hash_table_foreach_remove (hash, free_header_list, NULL);
367 soup_message_remove_header (GHashTable *hash, const char *name)
369 gpointer old_key, old_vals;
371 g_return_if_fail (hash != NULL);
372 g_return_if_fail (name != NULL || name[0] != '\0');
374 if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
375 g_hash_table_remove (hash, name);
376 free_header_list (old_key, old_vals, NULL);
381 soup_message_add_header (GHashTable *hash, const char *name, const char *value)
385 g_return_if_fail (hash != NULL);
386 g_return_if_fail (name != NULL || name [0] != '\0');
387 g_return_if_fail (value != NULL);
389 old_value = g_hash_table_lookup (hash, name);
392 g_slist_append (old_value, g_strdup (value));
394 g_hash_table_insert (hash, g_strdup (name),
395 g_slist_append (NULL, g_strdup (value)));
400 * soup_message_get_header:
401 * @hash: a header hash table
402 * @name: header name.
404 * Lookup the first transport header in @hash with a key equal to
407 * Return value: the header's value or %NULL if not found.
410 soup_message_get_header (GHashTable *hash, const char *name)
414 g_return_val_if_fail (hash != NULL, NULL);
415 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
417 vals = g_hash_table_lookup (hash, name);
425 * soup_message_get_header_list:
426 * @hash: a header hash table
427 * @name: header name.
429 * Lookup the all transport request headers in @hash with a key equal
432 * Return value: a const pointer to a #GSList of header values or
433 * %NULL if not found.
436 soup_message_get_header_list (GHashTable *hash, const char *name)
438 g_return_val_if_fail (hash != NULL, NULL);
439 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
441 return g_hash_table_lookup (hash, name);
447 } SoupMessageForeachHeaderData;
450 foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
452 GSList *vals = value;
453 SoupMessageForeachHeaderData *data = user_data;
456 (*data->func) (name, vals->data, data->user_data);
462 soup_message_foreach_header (GHashTable *hash, GHFunc func, gpointer user_data)
464 SoupMessageForeachHeaderData data;
466 g_return_if_fail (hash != NULL);
467 g_return_if_fail (func != NULL);
470 data.user_data = user_data;
471 g_hash_table_foreach (hash, foreach_value_in_list, &data);
475 queue_message (SoupMessage *req)
477 if (!req->priv->context) {
478 soup_message_set_error_full (req,
479 SOUP_ERROR_CANCELLED,
480 "Attempted to queue a message "
481 "with no destination context");
482 soup_message_issue_callback (req);
486 if (req->priv->status != SOUP_MESSAGE_STATUS_IDLE)
487 cleanup_message (req);
489 switch (req->response.owner) {
490 case SOUP_BUFFER_USER_OWNED:
491 soup_message_set_error_full (req,
492 SOUP_ERROR_CANCELLED,
493 "Attempted to queue a message "
494 "with a user owned response "
496 soup_message_issue_callback (req);
498 case SOUP_BUFFER_SYSTEM_OWNED:
499 g_free (req->response.body);
501 case SOUP_BUFFER_STATIC:
505 req->response.owner = 0;
506 req->response.body = NULL;
507 req->response.length = 0;
509 soup_message_clear_headers (req->response_headers);
514 if (req->errorphrase) {
515 g_free ((char *) req->errorphrase);
516 req->errorphrase = NULL;
519 soup_queue_message (req);
523 * soup_message_queue:
524 * @req: a #SoupMessage.
525 * @callback: a #SoupCallbackFn which will be called after the message
526 * completes or when an unrecoverable error occurs.
527 * @user_data: a pointer passed to @callback.
529 * Queues the message @req for sending. All messages are processed
530 * while the glib main loop runs. If this #SoupMessage has been
531 * processed before, any resources related to the time it was last
534 * If the response #SoupDataBuffer has an owner of
535 * %SOUP_BUFFER_USER_OWNED, the message will not be queued, and
536 * @callback will be called with a #SoupErrorCode of
537 * %SOUP_ERROR_CANCELLED.
539 * Upon message completetion, the callback specified in @callback will
540 * be invoked. If after returning from this callback the message has
541 * not been requeued using soup_message_queue(), @req will be unreffed.
544 soup_message_queue (SoupMessage *req,
545 SoupCallbackFn callback,
548 g_return_if_fail (SOUP_IS_MESSAGE (req));
550 req->priv->callback = callback;
551 req->priv->user_data = user_data;
557 requeue_read_error (SoupMessage *msg, gpointer user_data)
559 soup_message_disconnect (msg);
564 requeue_read_finished (SoupMessage *msg, gpointer user_data)
566 SoupConnection *conn = msg->priv->connection;
569 soup_message_set_connection (msg, NULL);
571 if (soup_connection_is_connected (conn)) {
572 soup_connection_mark_old (conn);
574 g_object_unref (conn);
579 soup_message_set_connection (msg, conn);
583 * soup_message_requeue:
584 * @req: a #SoupMessage
586 * This causes @req to be placed back on the queue to be attempted
590 soup_message_requeue (SoupMessage *req)
592 g_return_if_fail (SOUP_IS_MESSAGE (req));
594 if (req->priv->connection && req->priv->read_state) {
595 soup_message_read_set_callbacks (req, NULL, NULL,
596 requeue_read_finished,
597 requeue_read_error, NULL);
599 if (req->priv->write_state)
600 soup_message_write_cancel (req);
607 * @msg: a #SoupMessage.
609 * Synchronously send @msg. This call will not return until the
610 * transfer is finished successfully or there is an unrecoverable
613 * @msg is not freed upon return.
615 * Return value: the #SoupErrorClass of the error encountered while
616 * sending or reading the response.
619 soup_message_send (SoupMessage *msg)
621 soup_message_queue (msg, NULL, NULL);
624 g_main_iteration (TRUE);
626 if (msg->priv->status == SOUP_MESSAGE_STATUS_FINISHED ||
627 SOUP_ERROR_IS_TRANSPORT (msg->errorcode))
630 /* Quit if soup_shutdown has been called */
631 if (!soup_initialized)
632 return SOUP_ERROR_CANCELLED;
635 return msg->errorclass;
639 soup_message_set_flags (SoupMessage *msg, guint flags)
641 g_return_if_fail (SOUP_IS_MESSAGE (msg));
643 msg->priv->msg_flags = flags;
647 soup_message_get_flags (SoupMessage *msg)
649 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
651 return msg->priv->msg_flags;
655 soup_message_set_http_version (SoupMessage *msg, SoupHttpVersion version)
657 g_return_if_fail (SOUP_IS_MESSAGE (msg));
659 msg->priv->http_version = version;
663 soup_message_get_http_version (SoupMessage *msg)
665 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
667 return msg->priv->http_version;
671 soup_message_is_keepalive (SoupMessage *msg)
673 const char *c_conn, *s_conn;
675 c_conn = soup_message_get_header (msg->request_headers, "Connection");
676 s_conn = soup_message_get_header (msg->response_headers, "Connection");
678 if (msg->priv->http_version == SOUP_HTTP_1_0) {
679 /* Only persistent if the client requested keepalive
680 * and the server agreed.
683 if (!c_conn || !s_conn)
685 if (g_strcasecmp (c_conn, "Keep-Alive") != 0 ||
686 g_strcasecmp (s_conn, "Keep-Alive") != 0)
691 /* Persistent unless either side requested otherwise */
693 if (c_conn && g_strcasecmp (c_conn, "close") == 0)
695 if (s_conn && g_strcasecmp (s_conn, "close") == 0)
703 soup_message_set_context (SoupMessage *msg, SoupContext *new_ctx)
705 g_return_if_fail (SOUP_IS_MESSAGE (msg));
707 if (msg->priv->context && new_ctx) {
708 const SoupUri *old, *new;
710 old = soup_context_get_uri (msg->priv->context);
711 new = soup_context_get_uri (new_ctx);
712 if (strcmp (old->host, new->host) != 0)
713 cleanup_message (msg);
715 cleanup_message (msg);
718 g_object_ref (new_ctx);
719 if (msg->priv->context)
720 g_object_unref (msg->priv->context);
722 msg->priv->context = new_ctx;
726 soup_message_get_uri (SoupMessage *msg)
728 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
730 return soup_context_get_uri (msg->priv->context);
734 soup_message_set_connection (SoupMessage *msg, SoupConnection *conn)
737 soup_connection_set_in_use (conn, TRUE);
740 if (msg->priv->connection) {
741 soup_connection_set_in_use (msg->priv->connection, FALSE);
742 g_object_unref (msg->priv->connection);
745 msg->priv->connection = conn;
748 msg->priv->socket = soup_connection_get_socket (conn);
749 g_object_ref (msg->priv->socket);
750 } else if (msg->priv->socket) {
751 g_object_unref (msg->priv->socket);
752 msg->priv->socket = NULL;
757 soup_message_get_connection (SoupMessage *msg)
759 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
761 return msg->priv->connection;
765 soup_message_get_socket (SoupMessage *msg)
767 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
769 return msg->priv->socket;
773 soup_message_set_error (SoupMessage *msg, SoupKnownErrorCode errcode)
775 g_return_if_fail (SOUP_IS_MESSAGE (msg));
776 g_return_if_fail (errcode != 0);
778 g_free ((char *) msg->errorphrase);
780 msg->errorcode = errcode;
781 msg->errorclass = soup_error_get_class (errcode);
782 msg->errorphrase = g_strdup (soup_error_get_phrase (errcode));
786 soup_message_set_error_full (SoupMessage *msg,
788 const char *errphrase)
790 g_return_if_fail (SOUP_IS_MESSAGE (msg));
791 g_return_if_fail (errcode != 0);
792 g_return_if_fail (errphrase != NULL);
794 g_free ((char *) msg->errorphrase);
796 msg->errorcode = errcode;
797 msg->errorclass = soup_error_get_class (errcode);
798 msg->errorphrase = g_strdup (errphrase);