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@ximian.com)
8 * Copyright (C) 2000-2002, Ximian, 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_queue:
497 * @req: a %SoupMessage.
498 * @callback: a %SoupCallbackFn which will be called after the message completes
499 * or when an unrecoverable error occurs.
500 * @user_data: a pointer passed to @callback.
502 * Queues the message @req for sending. All messages are processed while the
503 * glib main loop runs. If this %SoupMessage has been processed before, any
504 * resources related to the time it was last sent are freed.
506 * If the response %SoupDataBuffer has an owner of %SOUP_BUFFER_USER_OWNED, the
507 * message will not be queued, and @callback will be called with a
508 * %SoupErrorCode of %SOUP_ERROR_CANCELLED.
510 * Upon message completetion, the callback specified in @callback will be
511 * invoked. If after returning from this callback the message has not been
512 * requeued using %soup_message_queue, %soup_message_free will be called on
516 soup_message_queue (SoupMessage *req,
517 SoupCallbackFn callback,
520 g_return_if_fail (req != NULL);
521 soup_queue_message (req, callback, user_data);
527 } RequeueConnectData;
530 requeue_connect_cb (SoupContext *ctx,
531 SoupConnectErrorCode err,
532 SoupConnection *conn,
535 RequeueConnectData *data = user_data;
537 if (conn && !conn->auth)
538 conn->auth = data->conn_auth;
540 soup_auth_free (data->conn_auth);
542 soup_queue_connect_cb (ctx, err, conn, data->msg);
543 if (data->msg->errorcode)
544 soup_message_issue_callback (data->msg);
550 requeue_read_error (gboolean body_started, gpointer user_data)
552 RequeueConnectData *data = user_data;
553 SoupMessage *msg = data->msg;
554 SoupContext *dest_ctx = msg->connection->context;
556 soup_context_ref (dest_ctx);
558 soup_connection_set_keep_alive (msg->connection, FALSE);
559 soup_connection_release (msg->connection);
560 msg->connection = NULL;
562 soup_queue_message (msg,
564 msg->priv->user_data);
566 msg->status = SOUP_STATUS_CONNECTING;
568 msg->priv->connect_tag =
569 soup_context_get_connection (dest_ctx,
573 soup_context_unref (dest_ctx);
577 requeue_read_finished (const SoupDataBuffer *buf,
580 RequeueConnectData *data = user_data;
581 SoupMessage *msg = data->msg;
582 SoupConnection *conn = msg->connection;
584 if (!soup_connection_is_keep_alive (msg->connection))
585 requeue_read_error (FALSE, data);
588 msg->connection = NULL;
590 soup_queue_message (msg,
592 msg->priv->user_data);
594 msg->connection = conn;
599 * soup_message_requeue:
600 * @req: a %SoupMessage
602 * This causes @req to be placed back on the queue to be attempted again.
605 soup_message_requeue (SoupMessage *req)
607 g_return_if_fail (req != NULL);
609 if (req->connection && req->connection->auth && req->priv->read_tag) {
610 RequeueConnectData *data = NULL;
612 data = g_new0 (RequeueConnectData, 1);
614 data->conn_auth = req->connection->auth;
616 soup_transfer_read_set_callbacks (req->priv->read_tag,
619 requeue_read_finished,
622 req->priv->read_tag = 0;
624 soup_queue_message (req,
626 req->priv->user_data);
631 * @msg: a %SoupMessage.
633 * Syncronously send @msg. This call will not return until the transfer is
634 * finished successfully or there is an unrecoverable error.
636 * @msg is not free'd upon return.
638 * Return value: the %SoupErrorClass of the error encountered while sending or
639 * reading the response.
642 soup_message_send (SoupMessage *msg)
644 soup_message_queue (msg, NULL, NULL);
647 g_main_iteration (TRUE);
649 if (msg->status == SOUP_STATUS_FINISHED ||
650 SOUP_ERROR_IS_TRANSPORT (msg->errorcode))
653 /* Quit if soup_shutdown has been called */
654 if (!soup_initialized)
655 return SOUP_ERROR_CANCELLED;
658 return msg->errorclass;
662 maybe_validate_auth (SoupMessage *msg, gpointer user_data)
664 gboolean proxy = GPOINTER_TO_INT (user_data);
670 ctx = soup_get_proxy ();
671 auth_failure = SOUP_ERROR_PROXY_UNAUTHORIZED; /* 407 */
675 auth_failure = SOUP_ERROR_UNAUTHORIZED; /* 401 */
678 auth = soup_auth_lookup (ctx);
682 if (msg->errorcode == auth_failure) {
685 else if (msg->errorclass == SOUP_ERROR_CLASS_SERVER_ERROR) {
687 * We have no way of knowing whether our auth is any good
688 * anymore, so just invalidate it and start from the
689 * beginning next time.
691 soup_auth_invalidate (auth, ctx);
694 auth->status = SOUP_AUTH_STATUS_SUCCESSFUL;
695 auth->controlling_msg = NULL;
697 } /* maybe_validate_auth */
700 authorize_handler (SoupMessage *msg, gboolean proxy)
707 if (msg->connection->auth &&
708 msg->connection->auth->status == SOUP_AUTH_STATUS_SUCCESSFUL)
709 goto THROW_CANT_AUTHENTICATE;
711 ctx = proxy ? soup_get_proxy () : msg->context;
712 uri = soup_context_get_uri (ctx);
714 vals = soup_message_get_header_list (msg->response_headers,
716 "Proxy-Authenticate" :
718 if (!vals) goto THROW_CANT_AUTHENTICATE;
720 auth = soup_auth_lookup (ctx);
722 g_assert (auth->status != SOUP_AUTH_STATUS_INVALID);
724 if (auth->status == SOUP_AUTH_STATUS_PENDING) {
725 if (auth->controlling_msg == msg) {
726 auth->status = SOUP_AUTH_STATUS_FAILED;
727 goto THROW_CANT_AUTHENTICATE;
730 soup_message_requeue (msg);
734 else if (auth->status == SOUP_AUTH_STATUS_FAILED ||
735 auth->status == SOUP_AUTH_STATUS_SUCCESSFUL) {
737 * We've failed previously, but we'll give it
738 * another go, or we've been successful
739 * previously, but it's not working anymore.
741 * Invalidate the auth, so it's removed from the
742 * hash and try it again as if we never had it
743 * in the first place.
745 soup_auth_invalidate (auth, ctx);
746 soup_message_requeue (msg);
752 auth = soup_auth_new_from_header_list (uri, vals);
755 soup_message_set_error_full (
758 SOUP_ERROR_CANT_AUTHENTICATE_PROXY :
759 SOUP_ERROR_CANT_AUTHENTICATE,
761 "Unknown authentication scheme "
762 "required by proxy" :
763 "Unknown authentication scheme "
768 auth->status = SOUP_AUTH_STATUS_PENDING;
769 auth->controlling_msg = msg;
770 soup_message_add_handler (msg, SOUP_HANDLER_PRE_BODY,
772 GINT_TO_POINTER (proxy));
776 * Call registered authenticate handler
778 if (!uri->user && soup_auth_fn)
779 (*soup_auth_fn) (auth->type,
782 soup_auth_fn_user_data);
785 soup_auth_free (auth);
786 goto THROW_CANT_AUTHENTICATE;
790 * Initialize with auth data (possibly returned from
793 soup_auth_initialize (auth, uri);
795 if (auth->type == SOUP_AUTH_TYPE_NTLM) {
796 SoupAuth *old_auth = msg->connection->auth;
799 soup_auth_free (old_auth);
800 msg->connection->auth = auth;
802 soup_auth_set_context (auth, ctx);
804 soup_message_requeue (msg);
808 THROW_CANT_AUTHENTICATE:
809 soup_message_set_error (msg,
811 SOUP_ERROR_CANT_AUTHENTICATE_PROXY :
812 SOUP_ERROR_CANT_AUTHENTICATE);
816 redirect_handler (SoupMessage *msg, gpointer user_data)
818 const gchar *new_loc;
820 if (msg->errorclass != SOUP_ERROR_CLASS_REDIRECT ||
821 msg->priv->msg_flags & SOUP_MESSAGE_NO_REDIRECT) return;
823 new_loc = soup_message_get_header (msg->response_headers, "Location");
826 const SoupUri *old_uri;
828 SoupContext *new_ctx;
830 old_uri = soup_context_get_uri (msg->context);
832 new_uri = soup_uri_new (new_loc);
834 goto INVALID_REDIRECT;
837 * Copy auth info from original URI.
839 if (old_uri->user && !new_uri->user)
840 soup_uri_set_auth (new_uri,
845 new_ctx = soup_context_from_uri (new_uri);
847 soup_uri_free (new_uri);
850 goto INVALID_REDIRECT;
852 soup_message_set_context (msg, new_ctx);
853 soup_context_unref (new_ctx);
855 soup_message_requeue (msg);
861 soup_message_set_error_full (msg,
862 SOUP_ERROR_MALFORMED,
863 "Invalid Redirect URL");
867 RESPONSE_HEADER_HANDLER = 1,
868 RESPONSE_ERROR_CODE_HANDLER,
869 RESPONSE_ERROR_CLASS_HANDLER
873 SoupHandlerType type;
874 SoupCallbackFn handler_cb;
877 SoupHandlerKind kind;
880 SoupErrorClass errorclass;
885 static SoupHandlerData global_handlers [] = {
887 * Handle redirect response codes 300, 301, 302, 303, and 305.
890 SOUP_HANDLER_PRE_BODY,
893 RESPONSE_HEADER_HANDLER,
894 { (guint) "Location" }
897 * Handle authorization.
900 SOUP_HANDLER_PRE_BODY,
901 (SoupCallbackFn) authorize_handler,
902 GINT_TO_POINTER (FALSE),
903 RESPONSE_ERROR_CODE_HANDLER,
907 * Handle proxy authorization.
910 SOUP_HANDLER_PRE_BODY,
911 (SoupCallbackFn) authorize_handler,
912 GINT_TO_POINTER (TRUE),
913 RESPONSE_ERROR_CODE_HANDLER,
920 run_handler (SoupMessage *msg,
921 SoupHandlerType invoke_type,
922 SoupHandlerData *data)
924 if (data->type != invoke_type) return;
926 switch (data->kind) {
927 case RESPONSE_HEADER_HANDLER:
928 if (!soup_message_get_header (msg->response_headers,
932 case RESPONSE_ERROR_CODE_HANDLER:
933 if (msg->errorcode != data->data.errorcode) return;
935 case RESPONSE_ERROR_CLASS_HANDLER:
936 if (msg->errorclass != data->data.errorclass) return;
942 (*data->handler_cb) (msg, data->user_data);
946 * Run each handler with matching criteria (first per-message then global
947 * handlers). If a handler requeues a message, we stop processing and terminate
948 * the current request.
950 * After running all handlers, if there is an error set or the invoke type was
951 * post_body, issue the final callback.
953 * FIXME: If the errorcode is changed by a handler, we should restart the
957 soup_message_run_handlers (SoupMessage *msg, SoupHandlerType invoke_type)
960 SoupHandlerData *data;
962 g_return_val_if_fail (msg != NULL, FALSE);
964 for (list = msg->priv->content_handlers; list; list = list->next) {
967 run_handler (msg, invoke_type, data);
969 if (msg->status == SOUP_STATUS_QUEUED ||
970 msg->status == SOUP_STATUS_CONNECTING) return TRUE;
973 for (data = global_handlers; data->type; data++) {
974 run_handler (msg, invoke_type, data);
976 if (msg->status == SOUP_STATUS_QUEUED ||
977 msg->status == SOUP_STATUS_CONNECTING) return TRUE;
981 * Issue final callback if the invoke_type is POST_BODY and the error
982 * class is not INFORMATIONAL.
984 if (invoke_type == SOUP_HANDLER_POST_BODY &&
985 msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL) {
986 soup_message_issue_callback (msg);
994 add_handler (SoupMessage *msg,
995 SoupHandlerType type,
996 SoupCallbackFn handler_cb,
998 SoupHandlerKind kind,
1003 SoupHandlerData *data;
1005 data = g_new0 (SoupHandlerData, 1);
1007 data->handler_cb = handler_cb;
1008 data->user_data = user_data;
1012 case RESPONSE_HEADER_HANDLER:
1013 data->data.header = header;
1015 case RESPONSE_ERROR_CODE_HANDLER:
1016 data->data.errorcode = errorcode;
1018 case RESPONSE_ERROR_CLASS_HANDLER:
1019 data->data.errorclass = errorclass;
1025 msg->priv->content_handlers =
1026 g_slist_append (msg->priv->content_handlers, data);
1030 soup_message_add_header_handler (SoupMessage *msg,
1031 const gchar *header,
1032 SoupHandlerType type,
1033 SoupCallbackFn handler_cb,
1036 g_return_if_fail (msg != NULL);
1037 g_return_if_fail (header != NULL);
1038 g_return_if_fail (handler_cb != NULL);
1044 RESPONSE_HEADER_HANDLER,
1051 soup_message_add_error_code_handler (SoupMessage *msg,
1053 SoupHandlerType type,
1054 SoupCallbackFn handler_cb,
1057 g_return_if_fail (msg != NULL);
1058 g_return_if_fail (errorcode != 0);
1059 g_return_if_fail (handler_cb != NULL);
1065 RESPONSE_ERROR_CODE_HANDLER,
1072 soup_message_add_error_class_handler (SoupMessage *msg,
1073 SoupErrorClass errorclass,
1074 SoupHandlerType type,
1075 SoupCallbackFn handler_cb,
1078 g_return_if_fail (msg != NULL);
1079 g_return_if_fail (errorclass != 0);
1080 g_return_if_fail (handler_cb != NULL);
1086 RESPONSE_ERROR_CLASS_HANDLER,
1093 soup_message_add_handler (SoupMessage *msg,
1094 SoupHandlerType type,
1095 SoupCallbackFn handler_cb,
1098 g_return_if_fail (msg != NULL);
1099 g_return_if_fail (handler_cb != NULL);
1112 soup_message_remove_handler (SoupMessage *msg,
1113 SoupHandlerType type,
1114 SoupCallbackFn handler_cb,
1117 GSList *iter = msg->priv->content_handlers;
1120 SoupHandlerData *data = iter->data;
1122 if (data->handler_cb == handler_cb &&
1123 data->user_data == user_data &&
1124 data->type == type) {
1125 msg->priv->content_handlers =
1126 g_slist_remove_link (
1127 msg->priv->content_handlers,
1137 static inline gboolean
1138 ADDED_FLAG (SoupMessage *msg, guint newflags, SoupMessageFlags find)
1140 return ((newflags & find) && !(msg->priv->msg_flags & find));
1143 static inline gboolean
1144 REMOVED_FLAG (SoupMessage *msg, guint newflags, SoupMessageFlags find)
1146 return (!(newflags & find) && (msg->priv->msg_flags & find));
1150 soup_message_set_flags (SoupMessage *msg, guint flags)
1152 g_return_if_fail (msg != NULL);
1154 msg->priv->msg_flags = flags;
1158 soup_message_get_flags (SoupMessage *msg)
1160 g_return_val_if_fail (msg != NULL, 0);
1162 return msg->priv->msg_flags;
1166 soup_message_set_http_version (SoupMessage *msg, SoupHttpVersion version)
1168 g_return_if_fail (msg != NULL);
1170 msg->priv->http_version = version;
1174 soup_message_get_http_version (SoupMessage *msg)
1176 g_return_val_if_fail (msg != NULL, SOUP_HTTP_1_0);
1178 return msg->priv->http_version;
1182 soup_message_set_context (SoupMessage *msg,
1183 SoupContext *new_ctx)
1185 g_return_if_fail (msg != NULL);
1188 if (msg->connection &&
1189 (!new_ctx || (msg->context->server != new_ctx->server)))
1190 soup_message_cleanup (msg);
1191 soup_context_unref (msg->context);
1195 soup_context_ref (new_ctx);
1197 msg->context = new_ctx;
1201 soup_message_get_context (SoupMessage *msg)
1203 g_return_val_if_fail (msg != NULL, NULL);
1206 soup_context_ref (msg->context);
1208 return msg->context;
1212 soup_message_set_error (SoupMessage *msg, SoupKnownErrorCode errcode)
1214 g_return_if_fail (msg != NULL);
1215 g_return_if_fail (errcode != 0);
1217 g_free ((gchar *) msg->errorphrase);
1219 msg->errorcode = errcode;
1220 msg->errorclass = soup_error_get_class (errcode);
1221 msg->errorphrase = g_strdup (soup_error_get_phrase (errcode));
1225 soup_message_set_error_full (SoupMessage *msg,
1227 const gchar *errphrase)
1229 g_return_if_fail (msg != NULL);
1230 g_return_if_fail (errcode != 0);
1231 g_return_if_fail (errphrase != NULL);
1233 g_free ((gchar *) msg->errorphrase);
1235 msg->errorcode = errcode;
1236 msg->errorclass = soup_error_get_class (errcode);
1237 msg->errorphrase = g_strdup (errphrase);
1241 soup_message_set_handler_error (SoupMessage *msg,
1243 const gchar *errphrase)
1245 g_return_if_fail (msg != NULL);
1246 g_return_if_fail (errcode != 0);
1247 g_return_if_fail (errphrase != NULL);
1249 g_free ((gchar *) msg->errorphrase);
1251 msg->errorcode = errcode;
1252 msg->errorclass = SOUP_ERROR_CLASS_HANDLER;
1253 msg->errorphrase = g_strdup (errphrase);