1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-message.c: Asyncronous Callback-based HTTP Request Queue.
6 * Alex Graveley (alex@helixcode.com)
8 * Copyright (C) 2000, Helix Code, Inc.
11 #include "soup-auth.h"
12 #include "soup-error.h"
13 #include "soup-message.h"
14 #include "soup-misc.h"
15 #include "soup-context.h"
16 #include "soup-private.h"
17 #include "soup-queue.h"
18 #include "soup-transfer.h"
22 * @context: a %SoupContext for the destination endpoint.
23 * @method: a string which will be used as the HTTP method for the created
24 * request, if NULL a GET request will be made.
26 * Creates a new empty %SoupMessage, which will connect to the URL represented
27 * by @context. A reference will be added to @context.
29 * The new message has a status of @SOUP_STATUS_IDLE.
31 * Return value: the new %SoupMessage.
34 soup_message_new (SoupContext *context, const gchar *method)
38 ret = g_new0 (SoupMessage, 1);
39 ret->priv = g_new0 (SoupMessagePrivate, 1);
40 ret->status = SOUP_STATUS_IDLE;
41 ret->method = method ? method : SOUP_METHOD_GET;
43 ret->request_headers = g_hash_table_new (soup_str_case_hash,
46 ret->response_headers = g_hash_table_new (soup_str_case_hash,
49 ret->priv->http_version = SOUP_HTTP_1_1;
51 soup_message_set_context (ret, context);
57 * soup_message_new_full:
58 * @context: a %SoupContext for the destination endpoint.
59 * @method: a string which will be used as the HTTP method for the created
60 * request, if NULL a GET request will be made..
61 * @req_owner: the %SoupOwnership of the passed data buffer.
62 * @req_body: a data buffer containing the body of the message request.
63 * @req_length: the byte length of @req_body.
65 * Creates a new %SoupMessage, which will connect to the URL represented by
66 * @context. A reference is added to @context. The request data
67 * buffer will be filled from @req_owner, @req_body, and @req_length
70 * The new message has a status of @SOUP_STATUS_IDLE.
72 * Return value: the new %SoupMessage.
75 soup_message_new_full (SoupContext *context,
77 SoupOwnership req_owner,
81 SoupMessage *ret = soup_message_new (context, method);
83 ret->request.owner = req_owner;
84 ret->request.body = req_body;
85 ret->request.length = req_length;
91 copy_header (gchar *key, gchar *value, GHashTable *dest_hash)
93 soup_message_add_header (dest_hash, key, value);
97 * Copy context, method, error, request buffer, response buffer, request
98 * headers, response headers, message flags, http version.
100 * Callback function, content handlers, message status, server, server socket,
101 * and server message are NOT copied.
104 soup_message_copy (SoupMessage *req)
108 cpy = soup_message_new (req->context, req->method);
110 cpy->errorcode = req->errorcode;
111 cpy->errorclass = req->errorclass;
112 cpy->errorphrase = req->errorphrase;
114 cpy->request.owner = SOUP_BUFFER_SYSTEM_OWNED;
115 cpy->request.length = cpy->request.length;
116 cpy->request.body = g_memdup (req->request.body,
117 req->request.length);
119 cpy->response.owner = SOUP_BUFFER_SYSTEM_OWNED;
120 cpy->response.length = cpy->response.length;
121 cpy->response.body = g_memdup (req->response.body,
122 req->response.length);
124 soup_message_foreach_header (req->request_headers,
125 (GHFunc) copy_header,
126 cpy->request_headers);
128 soup_message_foreach_header (req->response_headers,
129 (GHFunc) copy_header,
130 cpy->response_headers);
132 cpy->priv->msg_flags = req->priv->msg_flags;
135 * Note: We don't copy content handlers or callback function as this is
136 * a nightmare double free situation.
139 cpy->priv->http_version = req->priv->http_version;
145 release_connection (const SoupDataBuffer *data,
148 SoupConnection *conn = user_data;
149 soup_connection_release (conn);
153 release_and_close_connection (gboolean headers_done, gpointer user_data)
155 SoupConnection *conn = user_data;
156 soup_connection_set_keep_alive (conn, FALSE);
157 soup_connection_release (conn);
161 * soup_message_cleanup:
162 * @req: a %SoupMessage.
164 * Frees any temporary resources created in the processing of @req. Also
165 * releases the active connection, if one exists. Request and response data
166 * buffers are left intact.
169 soup_message_cleanup (SoupMessage *req)
171 g_return_if_fail (req != NULL);
173 if (req->connection &&
174 req->priv->read_tag &&
175 req->status == SOUP_STATUS_READING_RESPONSE) {
176 soup_transfer_read_set_callbacks (req->priv->read_tag,
180 release_and_close_connection,
182 req->priv->read_tag = 0;
183 req->connection = NULL;
185 * The buffer doesn't belong to us until the message is
188 req->response.owner = SOUP_BUFFER_STATIC;
191 if (req->priv->read_tag) {
192 soup_transfer_read_cancel (req->priv->read_tag);
193 req->priv->read_tag = 0;
196 if (req->priv->write_tag) {
197 soup_transfer_write_cancel (req->priv->write_tag);
198 req->priv->write_tag = 0;
201 if (req->priv->connect_tag) {
202 soup_context_cancel_connect (req->priv->connect_tag);
203 req->priv->connect_tag = NULL;
206 if (req->connection) {
207 soup_connection_release (req->connection);
208 req->connection = NULL;
211 soup_queue_remove_request (req);
215 finalize_message (SoupMessage *req)
218 soup_context_unref (req->context);
220 if (req->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
221 g_free (req->request.body);
222 if (req->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
223 g_free (req->response.body);
225 soup_message_clear_headers (req->request_headers);
226 g_hash_table_destroy (req->request_headers);
228 soup_message_clear_headers (req->response_headers);
229 g_hash_table_destroy (req->response_headers);
231 g_slist_foreach (req->priv->content_handlers, (GFunc) g_free, NULL);
232 g_slist_free (req->priv->content_handlers);
234 g_free ((gchar *) req->errorphrase);
241 * @req: a %SoupMessage to destroy.
243 * Destroys the %SoupMessage pointed to by @req. Request and response headers
244 * are freed. Request and response data buffers are also freed if their
245 * ownership is %SOUP_BUFFER_SYSTEM_OWNED. The message's destination context
246 * will be de-referenced.
249 soup_message_free (SoupMessage *req)
251 g_return_if_fail (req != NULL);
253 soup_message_cleanup (req);
255 finalize_message (req);
259 * soup_message_issue_callback:
260 * @req: a %SoupMessage currently being processed.
261 * @error: a %SoupErrorCode to be passed to %req's completion callback.
263 * Finalizes the message request, by first freeing any temporary resources, then
264 * issuing the callback function pointer passed in %soup_message_new or
265 * %soup_message_new_full. If, after returning from the callback, the message
266 * has not been requeued, @msg is destroyed using %soup_message_free.
269 soup_message_issue_callback (SoupMessage *req)
271 g_return_if_fail (req != NULL);
274 * Make sure we don't have some icky recursion if the callback
275 * runs the main loop, and the connection has some data or error
276 * which causes the callback to be run again.
278 soup_message_cleanup (req);
280 if (req->priv->callback) {
281 (*req->priv->callback) (req, req->priv->user_data);
283 if (req->status != SOUP_STATUS_QUEUED)
284 finalize_message (req);
289 * soup_message_cancel:
290 * @req: a %SoupMessage currently being processed.
292 * Cancel a running message, and issue completion callback with a
293 * %SoupTransferStatus of %SOUP_ERROR_CANCELLED. If not requeued by the
294 * completion callback, the @msg will be destroyed.
297 soup_message_cancel (SoupMessage *msg)
299 soup_message_set_error (msg, SOUP_ERROR_CANCELLED);
301 /* Kill the connection as a safety measure */
303 soup_connection_set_keep_alive (msg->connection, FALSE);
305 soup_message_issue_callback (msg);
309 foreach_free_header_list (gchar *name, GSList *vals, gpointer notused)
312 g_slist_foreach (vals, (GFunc) g_free, NULL);
319 soup_message_clear_headers (GHashTable *hash)
321 g_return_if_fail (hash != NULL);
323 g_hash_table_foreach_remove (hash,
324 (GHRFunc) foreach_free_header_list,
329 soup_message_remove_header (GHashTable *hash,
335 g_return_if_fail (hash != NULL);
336 g_return_if_fail (name != NULL || name [0] != '\0');
338 if (g_hash_table_lookup_extended (hash,
340 (gpointer *) &stored_key,
341 (gpointer *) &vals)) {
342 g_hash_table_remove (hash, name);
343 foreach_free_header_list (stored_key, vals, NULL);
348 soup_message_add_header (GHashTable *hash,
354 g_return_if_fail (hash != NULL);
355 g_return_if_fail (name != NULL || name [0] != '\0');
356 g_return_if_fail (value != NULL);
358 old_value = g_hash_table_lookup (hash, name);
361 g_slist_append (old_value, g_strdup (value));
363 g_hash_table_insert (hash,
365 g_slist_append (NULL,
370 * soup_message_get_header:
371 * @req: a %SoupMessage.
372 * @name: header name.
374 * Lookup the first transport header with a key equal to @name.
376 * Return value: the header's value or NULL if not found.
379 soup_message_get_header (GHashTable *hash,
384 g_return_val_if_fail (hash != NULL, NULL);
385 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
387 vals = g_hash_table_lookup (hash, name);
395 * soup_message_get_header_list:
396 * @req: a %SoupMessage.
397 * @name: header name.
399 * Lookup the all transport request headers with a key equal to @name.
401 * Return value: a const pointer to a GSList of header values or NULL if not
405 soup_message_get_header_list (GHashTable *hash,
408 g_return_val_if_fail (hash != NULL, NULL);
409 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
411 return g_hash_table_lookup (hash, name);
420 foreach_value_in_list (gchar *name, GSList *vals, ForeachData *data)
423 gchar *v = vals->data;
425 (*data->func) (name, v, data->user_data);
432 soup_message_foreach_header (GHashTable *hash,
436 ForeachData data = { func, user_data };
438 g_return_if_fail (hash != NULL);
439 g_return_if_fail (func != NULL);
441 g_hash_table_foreach (hash, (GHFunc) foreach_value_in_list, &data);
450 foreach_remove_value_in_list (gchar *name,
452 ForeachRemoveData *data)
457 gchar *v = iter->data;
458 gboolean ret = FALSE;
460 ret = (*data->func) (name, v, data->user_data);
462 GSList *next = iter->next;
464 vals = g_slist_remove (vals, v);
481 soup_message_foreach_remove_header (GHashTable *hash,
485 ForeachRemoveData data = { func, user_data };
487 g_return_if_fail (hash != NULL);
488 g_return_if_fail (func != NULL);
490 g_hash_table_foreach_remove (hash,
491 (GHRFunc) foreach_remove_value_in_list,
496 * soup_message_set_request_header:
497 * @req: a %SoupMessage.
498 * @name: header name.
499 * @value: header value.
503 * Adds a new transport header to be sent on an outgoing request. Passing a NULL
504 * @value will remove all headers with a name equal to @name.
507 soup_message_set_request_header (SoupMessage *req,
511 g_return_if_fail (req != NULL);
512 g_return_if_fail (name != NULL || name [0] != '\0');
514 g_warning ("soup_message_set_request_header is DEPRECATED. Use "
515 "soup_message_add_header, with msg->request_headers as "
516 "the first argument.\n");
518 soup_message_add_header (req->request_headers, name, value);
522 * soup_message_get_request_header:
523 * @req: a %SoupMessage.
524 * @name: header name.
528 * Lookup the first transport request header with a key equal to @name.
530 * Return value: the header's value or NULL if not found.
533 soup_message_get_request_header (SoupMessage *req,
537 g_return_val_if_fail (req != NULL, NULL);
538 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
540 g_warning ("soup_message_get_request_header is DEPRECATED. Use "
541 "soup_message_get_header, with msg->request_headers as "
542 "the first argument.\n");
544 if (req->request_headers) {
545 vals = g_hash_table_lookup (req->request_headers, name);
554 * soup_message_set_response_header:
555 * @req: a %SoupMessage.
556 * @name: header name.
557 * @value: header value.
561 * Adds a new transport header to be sent on an outgoing response. Passing a
562 * NULL @value will remove all headers with a name equal to @name.
565 soup_message_set_response_header (SoupMessage *req,
569 g_return_if_fail (req != NULL);
570 g_return_if_fail (name != NULL || name [0] != '\0');
572 g_warning ("soup_message_set_response_header is DEPRECATED. Use "
573 "soup_message_add_header, with msg->response_headers as "
574 "the first argument.\n");
576 soup_message_add_header (req->response_headers, name, value);
580 * soup_message_get_response_header:
581 * @req: a %SoupMessage.
582 * @name: header name.
586 * Lookup the transport response header with a key equal to @name.
588 * Return value: the header's value or NULL if not found.
591 soup_message_get_response_header (SoupMessage *req,
595 g_return_val_if_fail (req != NULL, NULL);
596 g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
598 g_warning ("soup_message_get_response_header is DEPRECATED. Use "
599 "soup_message_get_header, with msg->response_headers as "
600 "the first argument.\n");
602 if (req->response_headers) {
603 vals = g_hash_table_lookup (req->response_headers, name);
612 * soup_message_queue:
613 * @req: a %SoupMessage.
614 * @callback: a %SoupCallbackFn which will be called after the message completes
615 * or when an unrecoverable error occurs.
616 * @user_data: a pointer passed to @callback.
618 * Queues the message @req for sending. All messages are processed while the
619 * glib main loop runs. If this %SoupMessage has been processed before, any
620 * resources related to the time it was last sent are freed.
622 * If the response %SoupDataBuffer has an owner of %SOUP_BUFFER_USER_OWNED, the
623 * message will not be queued, and @callback will be called with a
624 * %SoupErrorCode of %SOUP_ERROR_CANCELLED.
626 * Upon message completetion, the callback specified in @callback will be
627 * invoked. If after returning from this callback the message has not been
628 * requeued using %soup_message_queue, %soup_message_free will be called on
632 soup_message_queue (SoupMessage *req,
633 SoupCallbackFn callback,
636 g_return_if_fail (req != NULL);
637 soup_queue_message (req, callback, user_data);
643 } RequeueConnectData;
646 requeue_connect_cb (SoupContext *ctx,
647 SoupConnectErrorCode err,
648 SoupConnection *conn,
651 RequeueConnectData *data = user_data;
653 if (conn && !conn->auth)
654 conn->auth = data->conn_auth;
656 soup_auth_free (data->conn_auth);
658 soup_queue_connect_cb (ctx, err, conn, data->msg);
659 if (data->msg->errorcode)
660 soup_message_issue_callback (data->msg);
666 requeue_read_error (gboolean body_started, gpointer user_data)
668 RequeueConnectData *data = user_data;
669 SoupMessage *msg = data->msg;
670 SoupContext *dest_ctx = msg->connection->context;
672 soup_context_ref (dest_ctx);
674 soup_connection_set_keep_alive (msg->connection, FALSE);
675 soup_connection_release (msg->connection);
676 msg->connection = NULL;
678 soup_queue_message (msg,
680 msg->priv->user_data);
682 msg->status = SOUP_STATUS_CONNECTING;
684 msg->priv->connect_tag =
685 soup_context_get_connection (dest_ctx,
689 soup_context_unref (dest_ctx);
693 requeue_read_finished (const SoupDataBuffer *buf,
696 RequeueConnectData *data = user_data;
697 SoupMessage *msg = data->msg;
698 SoupConnection *conn = msg->connection;
700 if (!soup_connection_is_keep_alive (msg->connection))
701 requeue_read_error (FALSE, data);
704 msg->connection = NULL;
706 soup_queue_message (msg,
708 msg->priv->user_data);
710 msg->connection = conn;
715 * soup_message_requeue:
716 * @req: a %SoupMessage
718 * This causes @req to be placed back on the queue to be attempted again.
721 soup_message_requeue (SoupMessage *req)
723 g_return_if_fail (req != NULL);
725 if (req->connection && req->connection->auth && req->priv->read_tag) {
726 RequeueConnectData *data = NULL;
728 data = g_new0 (RequeueConnectData, 1);
730 data->conn_auth = req->connection->auth;
732 soup_transfer_read_set_callbacks (req->priv->read_tag,
735 requeue_read_finished,
738 req->priv->read_tag = 0;
740 soup_queue_message (req,
742 req->priv->user_data);
747 * @msg: a %SoupMessage.
749 * Syncronously send @msg. This call will not return until the transfer is
750 * finished successfully or there is an unrecoverable error.
752 * @msg is not free'd upon return.
754 * Return value: the %SoupErrorClass of the error encountered while sending or
755 * reading the response.
758 soup_message_send (SoupMessage *msg)
760 soup_message_queue (msg, NULL, NULL);
763 g_main_iteration (TRUE);
765 if (msg->status == SOUP_STATUS_FINISHED ||
766 SOUP_ERROR_IS_TRANSPORT (msg->errorcode))
769 /* Quit if soup_shutdown has been called */
770 if (!soup_initialized)
771 return SOUP_ERROR_CANCELLED;
774 return msg->errorclass;
778 maybe_validate_auth (SoupMessage *msg, gpointer user_data)
780 gboolean proxy = GPOINTER_TO_INT (user_data);
786 ctx = soup_get_proxy ();
787 auth_failure = SOUP_ERROR_PROXY_UNAUTHORIZED; /* 407 */
791 auth_failure = SOUP_ERROR_UNAUTHORIZED; /* 401 */
794 auth = soup_auth_lookup (ctx);
798 if (msg->errorcode == auth_failure) {
801 else if (msg->errorclass == SOUP_ERROR_CLASS_SERVER_ERROR) {
803 * We have no way of knowing whether our auth is any good
804 * anymore, so just invalidate it and start from the
805 * beginning next time.
807 soup_auth_invalidate (auth, ctx);
810 auth->status = SOUP_AUTH_STATUS_SUCCESSFUL;
811 auth->controlling_msg = NULL;
813 } /* maybe_validate_auth */
816 authorize_handler (SoupMessage *msg, gboolean proxy)
823 if (msg->connection->auth &&
824 msg->connection->auth->status == SOUP_AUTH_STATUS_SUCCESSFUL)
825 goto THROW_CANT_AUTHENTICATE;
827 ctx = proxy ? soup_get_proxy () : msg->context;
828 uri = soup_context_get_uri (ctx);
830 vals = soup_message_get_header_list (msg->response_headers,
832 "Proxy-Authenticate" :
834 if (!vals) goto THROW_CANT_AUTHENTICATE;
836 auth = soup_auth_lookup (ctx);
838 g_assert (auth->status != SOUP_AUTH_STATUS_INVALID);
840 if (auth->status == SOUP_AUTH_STATUS_PENDING) {
841 if (auth->controlling_msg == msg) {
842 auth->status = SOUP_AUTH_STATUS_FAILED;
843 goto THROW_CANT_AUTHENTICATE;
846 soup_message_requeue (msg);
850 else if (auth->status == SOUP_AUTH_STATUS_FAILED ||
851 auth->status == SOUP_AUTH_STATUS_SUCCESSFUL) {
853 * We've failed previously, but we'll give it
854 * another go, or we've been successful
855 * previously, but it's not working anymore.
857 * Invalidate the auth, so it's removed from the
858 * hash and try it again as if we never had it
859 * in the first place.
861 soup_auth_invalidate (auth, ctx);
862 soup_message_requeue (msg);
868 auth = soup_auth_new_from_header_list (uri, vals);
871 soup_message_set_error_full (
874 SOUP_ERROR_CANT_AUTHENTICATE_PROXY :
875 SOUP_ERROR_CANT_AUTHENTICATE,
877 "Unknown authentication scheme "
878 "required by proxy" :
879 "Unknown authentication scheme "
884 auth->status = SOUP_AUTH_STATUS_PENDING;
885 auth->controlling_msg = msg;
886 soup_message_add_handler (msg, SOUP_HANDLER_PRE_BODY,
888 GINT_TO_POINTER (proxy));
892 * Call registered authenticate handler
894 if (!uri->user && soup_auth_fn)
895 (*soup_auth_fn) (auth->type,
898 soup_auth_fn_user_data);
901 soup_auth_free (auth);
902 goto THROW_CANT_AUTHENTICATE;
906 * Initialize with auth data (possibly returned from
909 soup_auth_initialize (auth, uri);
911 if (auth->type == SOUP_AUTH_TYPE_NTLM) {
912 SoupAuth *old_auth = msg->connection->auth;
915 soup_auth_free (old_auth);
916 msg->connection->auth = auth;
918 soup_auth_set_context (auth, ctx);
920 soup_message_requeue (msg);
924 THROW_CANT_AUTHENTICATE:
925 soup_message_set_error (msg,
927 SOUP_ERROR_CANT_AUTHENTICATE_PROXY :
928 SOUP_ERROR_CANT_AUTHENTICATE);
932 redirect_handler (SoupMessage *msg, gpointer user_data)
934 const gchar *new_loc;
936 if (msg->errorclass != SOUP_ERROR_CLASS_REDIRECT ||
937 msg->priv->msg_flags & SOUP_MESSAGE_NO_REDIRECT) return;
939 new_loc = soup_message_get_header (msg->response_headers, "Location");
942 const SoupUri *old_uri;
944 SoupContext *new_ctx;
946 old_uri = soup_context_get_uri (msg->context);
948 new_uri = soup_uri_new (new_loc);
950 goto INVALID_REDIRECT;
953 * Copy auth info from original URI.
955 if (old_uri->user && !new_uri->user)
956 soup_uri_set_auth (new_uri,
961 new_ctx = soup_context_from_uri (new_uri);
963 soup_uri_free (new_uri);
966 goto INVALID_REDIRECT;
968 soup_message_set_context (msg, new_ctx);
969 soup_context_unref (new_ctx);
971 soup_message_requeue (msg);
977 soup_message_set_error_full (msg,
978 SOUP_ERROR_MALFORMED,
979 "Invalid Redirect URL");
983 RESPONSE_HEADER_HANDLER = 1,
984 RESPONSE_ERROR_CODE_HANDLER,
985 RESPONSE_ERROR_CLASS_HANDLER
989 SoupHandlerType type;
990 SoupCallbackFn handler_cb;
993 SoupHandlerKind kind;
996 SoupErrorClass errorclass;
1001 static SoupHandlerData global_handlers [] = {
1003 * Handle redirect response codes 300, 301, 302, 303, and 305.
1006 SOUP_HANDLER_PRE_BODY,
1009 RESPONSE_HEADER_HANDLER,
1010 { (guint) "Location" }
1013 * Handle authorization.
1016 SOUP_HANDLER_PRE_BODY,
1017 (SoupCallbackFn) authorize_handler,
1018 GINT_TO_POINTER (FALSE),
1019 RESPONSE_ERROR_CODE_HANDLER,
1023 * Handle proxy authorization.
1026 SOUP_HANDLER_PRE_BODY,
1027 (SoupCallbackFn) authorize_handler,
1028 GINT_TO_POINTER (TRUE),
1029 RESPONSE_ERROR_CODE_HANDLER,
1036 run_handler (SoupMessage *msg,
1037 SoupHandlerType invoke_type,
1038 SoupHandlerData *data)
1040 if (data->type != invoke_type) return;
1042 switch (data->kind) {
1043 case RESPONSE_HEADER_HANDLER:
1044 if (!soup_message_get_header (msg->response_headers,
1048 case RESPONSE_ERROR_CODE_HANDLER:
1049 if (msg->errorcode != data->data.errorcode) return;
1051 case RESPONSE_ERROR_CLASS_HANDLER:
1052 if (msg->errorclass != data->data.errorclass) return;
1058 (*data->handler_cb) (msg, data->user_data);
1062 * Run each handler with matching criteria (first per-message then global
1063 * handlers). If a handler requeues a message, we stop processing and terminate
1064 * the current request.
1066 * After running all handlers, if there is an error set or the invoke type was
1067 * post_body, issue the final callback.
1069 * FIXME: If the errorcode is changed by a handler, we should restart the
1073 soup_message_run_handlers (SoupMessage *msg, SoupHandlerType invoke_type)
1076 SoupHandlerData *data;
1078 g_return_val_if_fail (msg != NULL, FALSE);
1080 for (list = msg->priv->content_handlers; list; list = list->next) {
1083 run_handler (msg, invoke_type, data);
1085 if (msg->status == SOUP_STATUS_QUEUED ||
1086 msg->status == SOUP_STATUS_CONNECTING) return TRUE;
1089 for (data = global_handlers; data->type; data++) {
1090 run_handler (msg, invoke_type, data);
1092 if (msg->status == SOUP_STATUS_QUEUED ||
1093 msg->status == SOUP_STATUS_CONNECTING) return TRUE;
1097 * Issue final callback if the invoke_type is POST_BODY and the error
1098 * class is not INFORMATIONAL.
1100 if (invoke_type == SOUP_HANDLER_POST_BODY &&
1101 msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL) {
1102 soup_message_issue_callback (msg);
1110 add_handler (SoupMessage *msg,
1111 SoupHandlerType type,
1112 SoupCallbackFn handler_cb,
1114 SoupHandlerKind kind,
1115 const gchar *header,
1119 SoupHandlerData *data;
1121 data = g_new0 (SoupHandlerData, 1);
1123 data->handler_cb = handler_cb;
1124 data->user_data = user_data;
1128 case RESPONSE_HEADER_HANDLER:
1129 data->data.header = header;
1131 case RESPONSE_ERROR_CODE_HANDLER:
1132 data->data.errorcode = errorcode;
1134 case RESPONSE_ERROR_CLASS_HANDLER:
1135 data->data.errorclass = errorclass;
1141 msg->priv->content_handlers =
1142 g_slist_append (msg->priv->content_handlers, data);
1146 soup_message_add_header_handler (SoupMessage *msg,
1147 const gchar *header,
1148 SoupHandlerType type,
1149 SoupCallbackFn handler_cb,
1152 g_return_if_fail (msg != NULL);
1153 g_return_if_fail (header != NULL);
1154 g_return_if_fail (handler_cb != NULL);
1160 RESPONSE_HEADER_HANDLER,
1167 soup_message_add_error_code_handler (SoupMessage *msg,
1169 SoupHandlerType type,
1170 SoupCallbackFn handler_cb,
1173 g_return_if_fail (msg != NULL);
1174 g_return_if_fail (errorcode != 0);
1175 g_return_if_fail (handler_cb != NULL);
1181 RESPONSE_ERROR_CODE_HANDLER,
1188 soup_message_add_error_class_handler (SoupMessage *msg,
1189 SoupErrorClass errorclass,
1190 SoupHandlerType type,
1191 SoupCallbackFn handler_cb,
1194 g_return_if_fail (msg != NULL);
1195 g_return_if_fail (errorclass != 0);
1196 g_return_if_fail (handler_cb != NULL);
1202 RESPONSE_ERROR_CLASS_HANDLER,
1209 soup_message_add_handler (SoupMessage *msg,
1210 SoupHandlerType type,
1211 SoupCallbackFn handler_cb,
1214 g_return_if_fail (msg != NULL);
1215 g_return_if_fail (handler_cb != NULL);
1228 soup_message_remove_handler (SoupMessage *msg,
1229 SoupHandlerType type,
1230 SoupCallbackFn handler_cb,
1233 GSList *iter = msg->priv->content_handlers;
1236 SoupHandlerData *data = iter->data;
1238 if (data->handler_cb == handler_cb &&
1239 data->user_data == user_data &&
1240 data->type == type) {
1241 msg->priv->content_handlers =
1242 g_slist_remove_link (
1243 msg->priv->content_handlers,
1253 static inline gboolean
1254 ADDED_FLAG (SoupMessage *msg, guint newflags, SoupMessageFlags find)
1256 return ((newflags & find) && !(msg->priv->msg_flags & find));
1259 static inline gboolean
1260 REMOVED_FLAG (SoupMessage *msg, guint newflags, SoupMessageFlags find)
1262 return (!(newflags & find) && (msg->priv->msg_flags & find));
1266 soup_message_set_flags (SoupMessage *msg, guint flags)
1268 g_return_if_fail (msg != NULL);
1270 msg->priv->msg_flags = flags;
1274 soup_message_get_flags (SoupMessage *msg)
1276 g_return_val_if_fail (msg != NULL, 0);
1278 return msg->priv->msg_flags;
1282 soup_message_set_http_version (SoupMessage *msg, SoupHttpVersion version)
1284 g_return_if_fail (msg != NULL);
1286 msg->priv->http_version = version;
1290 soup_message_get_http_version (SoupMessage *msg)
1292 g_return_val_if_fail (msg != NULL, SOUP_HTTP_1_0);
1294 return msg->priv->http_version;
1298 soup_message_set_context (SoupMessage *msg,
1299 SoupContext *new_ctx)
1301 g_return_if_fail (msg != NULL);
1304 soup_context_unref (msg->context);
1307 soup_context_ref (new_ctx);
1309 msg->context = new_ctx;
1313 soup_message_get_context (SoupMessage *msg)
1315 g_return_val_if_fail (msg != NULL, NULL);
1318 soup_context_ref (msg->context);
1320 return msg->context;
1324 soup_message_set_error (SoupMessage *msg, SoupKnownErrorCode errcode)
1326 g_return_if_fail (msg != NULL);
1327 g_return_if_fail (errcode != 0);
1329 g_free ((gchar *) msg->errorphrase);
1331 msg->errorcode = errcode;
1332 msg->errorclass = soup_error_get_class (errcode);
1333 msg->errorphrase = g_strdup (soup_error_get_phrase (errcode));
1337 soup_message_set_error_full (SoupMessage *msg,
1339 const gchar *errphrase)
1341 g_return_if_fail (msg != NULL);
1342 g_return_if_fail (errcode != 0);
1343 g_return_if_fail (errphrase != NULL);
1345 g_free ((gchar *) msg->errorphrase);
1347 msg->errorcode = errcode;
1348 msg->errorclass = soup_error_get_class (errcode);
1349 msg->errorphrase = g_strdup (errphrase);
1353 soup_message_set_handler_error (SoupMessage *msg,
1355 const gchar *errphrase)
1357 g_return_if_fail (msg != NULL);
1358 g_return_if_fail (errcode != 0);
1359 g_return_if_fail (errphrase != NULL);
1361 g_free ((gchar *) msg->errorphrase);
1363 msg->errorcode = errcode;
1364 msg->errorclass = SOUP_ERROR_CLASS_HANDLER;
1365 msg->errorphrase = g_strdup (errphrase);