Fixed all gtk-doc moans in soup-core documentation
[platform/upstream/libsoup.git] / libsoup / soup-message.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-message.c: Asyncronous Callback-based SOAP Request Queue.
4  *
5  * Authors:
6  *      Alex Graveley (alex@helixcode.com)
7  *
8  * Copyright (C) 2000, Helix Code, Inc.
9  */
10
11 #include "soup-message.h"
12 #include "soup-context.h"
13 #include "soup-private.h"
14
15 /**
16  * soup_message_new:
17  * @context: a %SoupContext for the destination endpoint.
18  * @action: a string which will be used as the SOAPAction header for the created
19  * request.
20  * 
21  * Creates a new empty %SoupMessage, which will connect to the URL represented
22  * by @context. The new message has a status of @SOUP_STATUS_IDLE.
23  *
24  * Return value: the new %SoupMessage.
25  */
26 SoupMessage *
27 soup_message_new (SoupContext *context, SoupAction action) 
28 {
29         SoupMessage *ret;
30         ret          = g_new0 (SoupMessage, 1);
31         ret->priv    = g_new0 (SoupMessagePrivate, 1);
32         ret->status  = SOUP_STATUS_IDLE;
33         ret->action  = g_strdup (action);
34         ret->context = context;
35
36         soup_context_ref (context);
37
38         return ret;
39 }
40
41 /**
42  * soup_message_new_full:
43  * @context: a %SoupContext for the destination endpoint.
44  * @action: a string which will be used as the SOAPAction header for the created
45  * request.
46  * @req_owner: the %SoupOwnership of the passed data buffer.
47  * @req_body: a data buffer containing the body of the message request.
48  * @req_length: the byte length of @req_body.
49  * 
50  * Creates a new %SoupMessage, which will connect to the URL represented by
51  * @context. The new message has a status of @SOUP_STATUS_IDLE. The request data
52  * buffer will be filled from @req_owner, @req_body, and @req_length
53  * respectively.
54  *
55  * Return value: the new %SoupMessage.
56  */
57 SoupMessage *
58 soup_message_new_full (SoupContext   *context,
59                        SoupAction     action,
60                        SoupOwnership  req_owner,
61                        gchar         *req_body,
62                        gulong         req_length)
63 {
64         SoupMessage *ret = soup_message_new (context, action);
65
66         ret->request.owner = req_owner;
67         ret->request.body = req_body;
68         ret->request.length = req_length;
69
70         return ret;
71 }
72
73 #define source_remove(_src) \
74         ({ if ((_src)) { g_source_remove ((_src)); (_src) = 0; }})
75
76 /**
77  * soup_message_cleanup:
78  * @req: a %SoupMessage.
79  * @action: a string which will be used as the SOAPAction header for the created
80  * request.
81  * 
82  * Frees any temporary resources created in the processing of @req. Request and
83  * response data buffers are left intact.
84  */
85 void 
86 soup_message_cleanup (SoupMessage *req)
87 {
88         g_return_if_fail (req != NULL);
89
90         source_remove (req->priv->read_tag);
91         source_remove (req->priv->write_tag);
92         source_remove (req->priv->error_tag);
93         source_remove (req->priv->timeout_tag);
94
95         if (req->priv->connect_tag) 
96                 soup_context_cancel_connect (req->priv->connect_tag);
97         if (req->priv->conn) 
98                 soup_connection_release (req->priv->conn);
99
100         req->priv->connect_tag = NULL;
101         req->priv->conn = NULL;
102         req->priv->write_len = 0;
103         req->priv->header_len = 0;
104         req->priv->content_length = 0;
105         req->priv->is_chunked = FALSE;
106
107         soup_active_requests = g_slist_remove (soup_active_requests, req);
108 }
109
110 static void
111 soup_message_remove_header (gchar *name, gchar *value, gpointer unused)
112 {
113         g_free (name);
114         g_free (value);
115 }
116
117 /**
118  * soup_message_free:
119  * @req: a %SoupMessage to destroy.
120  * 
121  * Destroys the %SoupMessage pointed to by @req. Request and response headers
122  * are freed. Request and response data buffers are also freed if their
123  * ownership is %SOUP_BUFFER_SYSTEM_OWNED. The message's destination context
124  * will be de-referenced.
125  */
126 void 
127 soup_message_free (SoupMessage *req)
128 {
129         g_return_if_fail (req != NULL);
130
131         soup_message_cleanup (req);
132
133         soup_context_unref (req->context);
134
135         if (req->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
136                 g_free (req->request.body);
137         if (req->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
138                 g_free (req->response.body);
139
140         if (req->priv->req_header) 
141                 g_string_free (req->priv->req_header, TRUE);
142
143         if (req->request_headers) {
144                 g_hash_table_foreach (req->request_headers,
145                                       (GHFunc) soup_message_remove_header,
146                                       NULL);
147                 g_hash_table_destroy (req->request_headers);
148         }
149
150         if (req->response_headers) {
151                 g_hash_table_foreach (req->response_headers,
152                                       (GHFunc) soup_message_remove_header,
153                                       NULL);
154                 g_hash_table_destroy (req->response_headers);
155         }
156
157         if (req->priv->recv_buf) 
158                 g_byte_array_free (req->priv->recv_buf, TRUE);
159
160         g_free (req->priv);
161         g_free (req->action);
162         g_free (req);
163 }
164
165 /**
166  * soup_message_issue_callback:
167  * @req: a %SoupMessage currently being processed.
168  * @error: a %SoupErrorCode to be passed to %req's completion callback.
169  * 
170  * Finalizes the message request, by first freeing any temporary resources, then
171  * issuing the callback function pointer passed in %soup_message_new or
172  * %soup_message_new_full. If, after returning from the callback, the message
173  * has not been requeued, @msg is destroyed using %soup_message_free.
174  */
175 void
176 soup_message_issue_callback (SoupMessage *req, SoupErrorCode error)
177 {
178         g_return_if_fail (req != NULL);
179
180         /* make sure we don't have some icky recursion if the callback 
181            runs the main loop, and the connection has some data or error 
182            which causes the callback to be run again */
183         soup_message_cleanup (req);
184
185         req->priv->errorcode = error;
186
187         if (req->priv->callback)
188                 (*req->priv->callback) (req, 
189                                         error, 
190                                         req->priv->user_data);
191
192         if (req->status != SOUP_STATUS_QUEUED) soup_message_free (req);
193 }
194
195 /**
196  * soup_message_cancel:
197  * @req: a %SoupMessage currently being processed.
198  * 
199  * Cancel a running message, and issue completion callback with a
200  * %SoupTransferStatus of %SOUP_ERROR_CANCELLED. If not requeued by the
201  * completion callback, the @msg will be destroyed.
202  */
203 void 
204 soup_message_cancel (SoupMessage *req) 
205 {
206         soup_message_issue_callback (req, SOUP_ERROR_CANCELLED);
207 }
208
209 static void 
210 soup_message_set_header (GHashTable  **hash,
211                          const gchar  *name,
212                          const gchar  *value) 
213 {
214         if (!*hash) 
215                 *hash = g_hash_table_new (soup_str_case_hash, 
216                                           soup_str_case_equal);
217
218         g_hash_table_insert (*hash, g_strdup (name), g_strdup (value));
219 }
220
221 /**
222  * soup_message_set_request_header:
223  * @req: a %SoupMessage.
224  * @name: header name.
225  * @value: header value.
226  * 
227  * Adds a new transport header to be sent on an outgoing request.
228  */
229 void
230 soup_message_set_request_header (SoupMessage *req,
231                                  const gchar *name,
232                                  const gchar *value) 
233 {
234         g_return_if_fail (req != NULL);
235         g_return_if_fail (name != NULL || name [0] != '\0');
236
237         if (req->priv->req_header) {
238                 g_string_free (req->priv->req_header, TRUE);
239                 req->priv->req_header = NULL;
240         }
241
242         soup_message_set_header (&req->request_headers, name, value);
243 }
244
245 /**
246  * soup_message_get_request_header:
247  * @req: a %SoupMessage.
248  * @name: header name.
249  * 
250  * Lookup the transport request header with a key equal to @name.
251  *
252  * Return value: the header's value or NULL if not found.
253  */
254 const gchar *
255 soup_message_get_request_header (SoupMessage *req,
256                                  const gchar *name) 
257 {
258         g_return_val_if_fail (req != NULL, NULL);
259         g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
260
261         return req->request_headers ? 
262                 g_hash_table_lookup (req->request_headers, name) : NULL;
263 }
264
265 /**
266  * soup_message_set_response_header:
267  * @req: a %SoupMessage.
268  * @name: header name.
269  * @value: header value.
270  * 
271  * Adds a new transport header to be sent on an outgoing response.
272  */
273 void
274 soup_message_set_response_header (SoupMessage *req,
275                                   const gchar *name,
276                                   const gchar *value) 
277 {
278         g_return_if_fail (req != NULL);
279         g_return_if_fail (name != NULL || name [0] != '\0');
280
281         soup_message_set_header (&req->response_headers, name, value);
282 }
283
284 /**
285  * soup_message_get_response_header:
286  * @req: a %SoupMessage.
287  * @name: header name.
288  * 
289  * Lookup the transport response header with a key equal to @name.
290  *
291  * Return value: the header's value or NULL if not found.
292  */
293 const gchar *
294 soup_message_get_response_header (SoupMessage *req,
295                                   const gchar *name) 
296 {
297         g_return_val_if_fail (req != NULL, NULL);
298         g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
299
300         return req->response_headers ? 
301                 g_hash_table_lookup (req->response_headers, name) : NULL;
302 }
303
304 /**
305  * soup_message_send:
306  * @msg: a %SoupMessage.
307  * 
308  * Syncronously send @msg. This call will not return until the transfer is
309  * finished successfully or there is an unrecoverable error. 
310  *
311  * Return value: the %SoupErrorCode of the error encountered while sending, or
312  * SOUP_ERROR_NONE.
313  */
314 SoupErrorCode 
315 soup_message_send (SoupMessage *msg)
316 {
317         soup_message_queue (msg, NULL, NULL);
318
319         while (1) {
320                 g_main_iteration (TRUE); 
321                 if (msg->status == SOUP_STATUS_FINISHED ||
322                     msg->priv->errorcode != SOUP_ERROR_NONE)
323                         return msg->priv->errorcode;
324         }
325
326         return SOUP_ERROR_NONE;
327 }
328
329 void
330 soup_message_set_flags (SoupMessage *msg, guint flags)
331 {
332         msg->priv->msg_flags = flags;
333 }
334
335 guint
336 soup_message_get_flags (SoupMessage *msg)
337 {
338         return msg->priv->msg_flags;
339 }