09846973477efd120aeddfb05d5aa056576e00b6
[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: HTTP request/response
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #include <string.h>
9
10 #include "soup-auth.h"
11 #include "soup-error.h"
12 #include "soup-message.h"
13 #include "soup-message-private.h"
14 #include "soup-misc.h"
15 #include "soup-context.h"
16 #include "soup-private.h"
17 #include "soup-queue.h"
18
19 #define PARENT_TYPE G_TYPE_OBJECT
20 static GObjectClass *parent_class;
21
22 static void cleanup_message (SoupMessage *req);
23
24 static void
25 init (GObject *object)
26 {
27         SoupMessage *msg = SOUP_MESSAGE (object);
28
29         msg->priv = g_new0 (SoupMessagePrivate, 1);
30
31         msg->priv->status  = SOUP_MESSAGE_STATUS_IDLE;
32
33         msg->request_headers = g_hash_table_new (soup_str_case_hash,
34                                                  soup_str_case_equal);
35
36         msg->response_headers = g_hash_table_new (soup_str_case_hash,
37                                                   soup_str_case_equal);
38
39         msg->priv->http_version = SOUP_HTTP_1_1;
40 }
41
42 static void
43 finalize (GObject *object)
44 {
45         SoupMessage *msg = SOUP_MESSAGE (object);
46
47         cleanup_message (msg);
48
49         if (msg->priv->context)
50                 g_object_unref (msg->priv->context);
51
52         if (msg->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
53                 g_free (msg->request.body);
54         if (msg->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
55                 g_free (msg->response.body);
56
57         soup_message_clear_headers (msg->request_headers);
58         g_hash_table_destroy (msg->request_headers);
59
60         soup_message_clear_headers (msg->response_headers);
61         g_hash_table_destroy (msg->response_headers);
62
63         g_slist_foreach (msg->priv->content_handlers, (GFunc) g_free, NULL);
64         g_slist_free (msg->priv->content_handlers);
65
66         g_free ((char *) msg->errorphrase);
67
68         g_free (msg->priv);
69
70         G_OBJECT_CLASS (parent_class)->finalize (object);
71 }
72
73 static void
74 class_init (GObjectClass *object_class)
75 {
76         parent_class = g_type_class_ref (PARENT_TYPE);
77
78         /* virtual method override */
79         object_class->finalize = finalize;
80 }
81
82 SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE)
83
84
85 /**
86  * soup_message_new:
87  * @method: the HTTP method for the created request
88  * @uri: the destination endpoint (as a string)
89  * 
90  * Creates a new empty #SoupMessage, which will connect to @uri
91  *
92  * Return value: the new #SoupMessage (or %NULL if @uri could not
93  * be parsed).
94  */
95 SoupMessage *
96 soup_message_new (const char *method, const char *uri)
97 {
98         SoupMessage *msg;
99         SoupContext *ctx;
100
101         ctx = soup_context_get (uri);
102         if (!ctx)
103                 return NULL;
104
105         msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
106         msg->method = method ? method : SOUP_METHOD_GET;
107         msg->priv->context = ctx;
108
109         return msg;
110 }
111
112 /**
113  * soup_message_new_from_uri:
114  * @method: the HTTP method for the created request
115  * @uri: the destination endpoint (as a #SoupUri)
116  * 
117  * Creates a new empty #SoupMessage, which will connect to @uri
118  *
119  * Return value: the new #SoupMessage (or %NULL if @uri is invalid)
120  */
121 SoupMessage *
122 soup_message_new_from_uri (const char *method, const SoupUri *uri)
123 {
124         SoupMessage *msg;
125         SoupContext *ctx;
126
127         ctx = soup_context_from_uri (uri);
128         if (!ctx)
129                 return NULL;
130
131         msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
132         msg->method = method ? method : SOUP_METHOD_GET;
133         msg->priv->context = ctx;
134
135         return msg;
136 }
137
138 /**
139  * soup_message_set_request:
140  * @msg: the message
141  * @content_type: MIME Content-Type of the body
142  * @req_owner: the #SoupOwnership of the passed data buffer.
143  * @req_body: a data buffer containing the body of the message request.
144  * @req_length: the byte length of @req_body.
145  * 
146  * Convenience function to set the request body of a #SoupMessage
147  */
148 void
149 soup_message_set_request (SoupMessage   *msg,
150                           const char    *content_type,
151                           SoupOwnership  req_owner,
152                           char          *req_body,
153                           gulong         req_length)
154 {
155         g_return_if_fail (SOUP_IS_MESSAGE (msg));
156         g_return_if_fail (content_type != NULL);
157         g_return_if_fail (req_body != NULL || req_length == 0);
158
159         soup_message_add_header (msg->request_headers,
160                                  "Content-Type", content_type);
161         msg->request.owner = req_owner;
162         msg->request.body = req_body;
163         msg->request.length = req_length;
164 }
165
166 /**
167  * soup_message_set_response:
168  * @msg: the message
169  * @content_type: MIME Content-Type of the body
170  * @req_owner: the #SoupOwnership of the passed data buffer.
171  * @req_body: a data buffer containing the body of the message response.
172  * @req_length: the byte length of @req_body.
173  * 
174  * Convenience function to set the response body of a #SoupMessage
175  */
176 void
177 soup_message_set_response (SoupMessage   *msg,
178                            const char    *content_type,
179                            SoupOwnership  resp_owner,
180                            char          *resp_body,
181                            gulong         resp_length)
182 {
183         g_return_if_fail (SOUP_IS_MESSAGE (msg));
184         g_return_if_fail (content_type != NULL);
185         g_return_if_fail (resp_body != NULL || resp_length == 0);
186
187         soup_message_add_header (msg->response_headers,
188                                  "Content-Type", content_type);
189         msg->response.owner = resp_owner;
190         msg->response.body = resp_body;
191         msg->response.length = resp_length;
192 }
193
194 static void
195 cleanup_message (SoupMessage *req)
196 {
197         if (req->priv->read_state)
198                 soup_message_read_cancel (req);
199
200         if (req->priv->write_state)
201                 soup_message_write_cancel (req);
202
203         if (req->priv->connect_tag) {
204                 soup_context_cancel_connect (req->priv->connect_tag);
205                 req->priv->connect_tag = NULL;
206         }
207
208         soup_message_set_connection (req, NULL);
209
210         soup_queue_remove_request (req);
211 }
212
213 /**
214  * soup_message_issue_callback:
215  * @req: a #SoupMessage currently being processed.
216  * @error: a #SoupErrorCode to be passed to @req's completion callback.
217  * 
218  * Finalizes the message request, by first freeing any temporary
219  * resources, then issuing the callback function pointer passed in
220  * soup_message_new() or soup_message_new_full(). If, after returning
221  * from the callback, the message has not been requeued, @req will be
222  * unreffed.
223  */
224 void
225 soup_message_issue_callback (SoupMessage *req)
226 {
227         g_return_if_fail (SOUP_IS_MESSAGE (req));
228
229         /*
230          * Make sure we don't have some icky recursion if the callback
231          * runs the main loop, and the connection has some data or error
232          * which causes the callback to be run again.
233          */
234         cleanup_message (req);
235
236         if (req->priv->callback) {
237                 (*req->priv->callback) (req, req->priv->user_data);
238
239                 if (!SOUP_MESSAGE_IS_STARTING (req))
240                         g_object_unref (req);
241         }
242 }
243
244 /**
245  * soup_message_disconnect:
246  * @msg: a #SoupMessage
247  *
248  * Utility function to close and unref the connection associated with
249  * @msg if there was an error.
250  **/
251 void
252 soup_message_disconnect (SoupMessage *msg)
253 {
254         if (msg->priv->connection) {
255                 soup_connection_disconnect (msg->priv->connection);
256                 soup_message_set_connection (msg, NULL);
257         }
258 }
259
260 /**
261  * soup_message_cancel:
262  * @msg: a #SoupMessage currently being processed.
263  * 
264  * Cancel a running message, and issue completion callback with an
265  * error code of %SOUP_ERROR_CANCELLED. If not requeued by the
266  * completion callback, the @msg will be destroyed.
267  */
268 void
269 soup_message_cancel (SoupMessage *msg)
270 {
271         soup_message_set_error (msg, SOUP_ERROR_CANCELLED);
272         soup_message_disconnect (msg);
273         soup_message_issue_callback (msg);
274 }
275
276 static gboolean
277 free_header_list (gpointer name, gpointer vals, gpointer user_data)
278 {
279         g_free (name);
280         g_slist_foreach (vals, (GFunc) g_free, NULL);
281         g_slist_free (vals);
282
283         return TRUE;
284 }
285
286 void
287 soup_message_clear_headers (GHashTable *hash)
288 {
289         g_return_if_fail (hash != NULL);
290
291         g_hash_table_foreach_remove (hash, free_header_list, NULL);
292 }
293
294 void
295 soup_message_remove_header (GHashTable *hash, const char *name)
296 {
297         gpointer old_key, old_vals;
298
299         g_return_if_fail (hash != NULL);
300         g_return_if_fail (name != NULL || name[0] != '\0');
301
302         if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
303                 g_hash_table_remove (hash, name);
304                 free_header_list (old_key, old_vals, NULL);
305         }
306 }
307
308 void
309 soup_message_add_header (GHashTable *hash, const char *name, const char *value)
310 {
311         GSList *old_value;
312
313         g_return_if_fail (hash != NULL);
314         g_return_if_fail (name != NULL || name [0] != '\0');
315         g_return_if_fail (value != NULL);
316
317         old_value = g_hash_table_lookup (hash, name);
318
319         if (old_value)
320                 g_slist_append (old_value, g_strdup (value));
321         else {
322                 g_hash_table_insert (hash, g_strdup (name),
323                                      g_slist_append (NULL, g_strdup (value)));
324         }
325 }
326
327 /**
328  * soup_message_get_header:
329  * @hash: a header hash table
330  * @name: header name.
331  * 
332  * Lookup the first transport header in @hash with a key equal to
333  * @name.
334  * 
335  * Return value: the header's value or %NULL if not found.
336  */
337 const char *
338 soup_message_get_header (GHashTable *hash, const char *name)
339 {
340         GSList *vals;
341
342         g_return_val_if_fail (hash != NULL, NULL);
343         g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
344
345         vals = g_hash_table_lookup (hash, name);
346         if (vals)
347                 return vals->data;
348
349         return NULL;
350 }
351
352 /**
353  * soup_message_get_header_list:
354  * @hash: a header hash table
355  * @name: header name.
356  * 
357  * Lookup the all transport request headers in @hash with a key equal
358  * to @name.
359  * 
360  * Return value: a const pointer to a #GSList of header values or
361  * %NULL if not found.
362  */
363 const GSList *
364 soup_message_get_header_list (GHashTable *hash, const char *name)
365 {
366         g_return_val_if_fail (hash != NULL, NULL);
367         g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
368
369         return g_hash_table_lookup (hash, name);
370 }
371
372 typedef struct {
373         GHFunc   func;
374         gpointer user_data;
375 } SoupMessageForeachHeaderData;
376
377 static void
378 foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
379 {
380         GSList *vals = value;
381         SoupMessageForeachHeaderData *data = user_data;
382
383         while (vals) {
384                 (*data->func) (name, vals->data, data->user_data);
385                 vals = vals->next;
386         }
387 }
388
389 void
390 soup_message_foreach_header (GHashTable *hash, GHFunc func, gpointer user_data)
391 {
392         SoupMessageForeachHeaderData data;
393
394         g_return_if_fail (hash != NULL);
395         g_return_if_fail (func != NULL);
396
397         data.func = func;
398         data.user_data = user_data;
399         g_hash_table_foreach (hash, foreach_value_in_list, &data);
400 }
401
402 static void
403 queue_message (SoupMessage *req)
404 {
405         if (!req->priv->context) {
406                 soup_message_set_error_full (req, 
407                                              SOUP_ERROR_CANCELLED,
408                                              "Attempted to queue a message "
409                                              "with no destination context");
410                 soup_message_issue_callback (req);
411                 return;
412         }
413
414         if (req->priv->status != SOUP_MESSAGE_STATUS_IDLE)
415                 cleanup_message (req);
416
417         switch (req->response.owner) {
418         case SOUP_BUFFER_USER_OWNED:
419                 soup_message_set_error_full (req, 
420                                              SOUP_ERROR_CANCELLED,
421                                              "Attempted to queue a message "
422                                              "with a user owned response "
423                                              "buffer.");
424                 soup_message_issue_callback (req);
425                 return;
426         case SOUP_BUFFER_SYSTEM_OWNED:
427                 g_free (req->response.body);
428                 break;
429         case SOUP_BUFFER_STATIC:
430                 break;
431         }
432
433         req->response.owner = 0;
434         req->response.body = NULL;
435         req->response.length = 0;
436
437         soup_message_clear_headers (req->response_headers);
438
439         req->errorcode = 0;
440         req->errorclass = 0;
441
442         if (req->errorphrase) {
443                 g_free ((char *) req->errorphrase);
444                 req->errorphrase = NULL;
445         }
446
447         soup_queue_message (req);
448 }
449
450 /**
451  * soup_message_queue:
452  * @req: a #SoupMessage.
453  * @callback: a #SoupCallbackFn which will be called after the message
454  * completes or when an unrecoverable error occurs.
455  * @user_data: a pointer passed to @callback.
456  * 
457  * Queues the message @req for sending. All messages are processed
458  * while the glib main loop runs. If this #SoupMessage has been
459  * processed before, any resources related to the time it was last
460  * sent are freed.
461  *
462  * If the response #SoupDataBuffer has an owner of
463  * %SOUP_BUFFER_USER_OWNED, the message will not be queued, and
464  * @callback will be called with a #SoupErrorCode of
465  * %SOUP_ERROR_CANCELLED.
466  *
467  * Upon message completetion, the callback specified in @callback will
468  * be invoked. If after returning from this callback the message has
469  * not been requeued using soup_message_queue(), @req will be unreffed.
470  */
471 void
472 soup_message_queue (SoupMessage    *req,
473                     SoupCallbackFn  callback,
474                     gpointer        user_data)
475 {
476         g_return_if_fail (SOUP_IS_MESSAGE (req));
477
478         req->priv->callback = callback;
479         req->priv->user_data = user_data;
480
481         queue_message (req);
482 }
483
484 static void
485 requeue_read_error (SoupMessage *msg)
486 {
487         soup_message_disconnect (msg);
488         queue_message (msg);
489 }
490
491 static void
492 requeue_read_finished (SoupMessage *msg, char *body, guint len)
493 {
494         SoupConnection *conn = msg->priv->connection;
495
496         g_free (body);
497
498         g_object_ref (conn);
499         soup_message_set_connection (msg, NULL);
500
501         if (soup_connection_is_connected (conn)) {
502                 soup_connection_mark_old (conn);
503         } else {
504                 g_object_unref (conn);
505                 conn = NULL;
506         }
507
508         queue_message (msg);
509         soup_message_set_connection (msg, conn);
510 }
511
512 /**
513  * soup_message_requeue:
514  * @req: a #SoupMessage
515  *
516  * This causes @req to be placed back on the queue to be attempted
517  * again.
518  **/
519 void
520 soup_message_requeue (SoupMessage *req)
521 {
522         g_return_if_fail (SOUP_IS_MESSAGE (req));
523
524         if (req->priv->connection && req->priv->read_state) {
525                 soup_message_read_set_callbacks (req, NULL, NULL,
526                                                  requeue_read_finished,
527                                                  requeue_read_error);
528
529                 if (req->priv->write_state)
530                         soup_message_write_cancel (req);
531         } else
532                 queue_message (req);
533 }
534
535 /**
536  * soup_message_send:
537  * @msg: a #SoupMessage.
538  * 
539  * Synchronously send @msg. This call will not return until the
540  * transfer is finished successfully or there is an unrecoverable
541  * error.
542  *
543  * @msg is not freed upon return.
544  *
545  * Return value: the #SoupErrorClass of the error encountered while
546  * sending or reading the response.
547  */
548 SoupErrorClass
549 soup_message_send (SoupMessage *msg)
550 {
551         soup_message_queue (msg, NULL, NULL);
552
553         while (1) {
554                 g_main_iteration (TRUE);
555
556                 if (msg->priv->status == SOUP_MESSAGE_STATUS_FINISHED ||
557                     SOUP_ERROR_IS_TRANSPORT (msg->errorcode))
558                         break;
559
560                 /* Quit if soup_shutdown has been called */
561                 if (!soup_initialized)
562                         return SOUP_ERROR_CANCELLED;
563         }
564
565         return msg->errorclass;
566 }
567
568 void
569 soup_message_set_flags (SoupMessage *msg, guint flags)
570 {
571         g_return_if_fail (SOUP_IS_MESSAGE (msg));
572
573         msg->priv->msg_flags = flags;
574 }
575
576 guint
577 soup_message_get_flags (SoupMessage *msg)
578 {
579         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
580
581         return msg->priv->msg_flags;
582 }
583
584 void
585 soup_message_set_http_version  (SoupMessage *msg, SoupHttpVersion version)
586 {
587         g_return_if_fail (SOUP_IS_MESSAGE (msg));
588
589         msg->priv->http_version = version;
590 }
591
592 SoupHttpVersion
593 soup_message_get_http_version (SoupMessage *msg)
594 {
595         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
596
597         return msg->priv->http_version;
598 }
599
600 gboolean
601 soup_message_is_keepalive (SoupMessage *msg)
602 {
603         const char *c_conn, *s_conn;
604
605         c_conn = soup_message_get_header (msg->request_headers, "Connection");
606         s_conn = soup_message_get_header (msg->response_headers, "Connection");
607
608         if (msg->priv->http_version == SOUP_HTTP_1_0) {
609                 /* Only persistent if the client requested keepalive
610                  * and the server agreed.
611                  */
612
613                 if (!c_conn || !s_conn)
614                         return FALSE;
615                 if (g_strcasecmp (c_conn, "Keep-Alive") != 0 ||
616                     g_strcasecmp (s_conn, "Keep-Alive") != 0)
617                         return FALSE;
618
619                 return TRUE;
620         } else {
621                 /* Persistent unless either side requested otherwise */
622
623                 if (c_conn && g_strcasecmp (c_conn, "close") == 0)
624                         return FALSE;
625                 if (s_conn && g_strcasecmp (s_conn, "close") == 0)
626                         return FALSE;
627
628                 return TRUE;
629         }
630 }
631
632 void
633 soup_message_set_context (SoupMessage *msg, SoupContext *new_ctx)
634 {
635         g_return_if_fail (SOUP_IS_MESSAGE (msg));
636
637         if (msg->priv->context && new_ctx) {
638                 const SoupUri *old, *new;
639
640                 old = soup_context_get_uri (msg->priv->context);
641                 new = soup_context_get_uri (new_ctx);
642                 if (strcmp (old->host, new->host) != 0)
643                         cleanup_message (msg);
644         } else if (!new_ctx)
645                 cleanup_message (msg);
646
647         if (new_ctx)
648                 g_object_ref (new_ctx);
649         if (msg->priv->context)
650                 g_object_unref (msg->priv->context);
651
652         msg->priv->context = new_ctx;
653 }
654
655 const SoupUri *
656 soup_message_get_uri (SoupMessage *msg)
657 {
658         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
659
660         return soup_context_get_uri (msg->priv->context);
661 }
662
663 void
664 soup_message_set_connection (SoupMessage *msg, SoupConnection *conn)
665 {
666         if (conn) {
667                 soup_connection_set_in_use (conn, TRUE);
668                 g_object_ref (conn);
669         }
670         if (msg->priv->connection) {
671                 soup_connection_set_in_use (msg->priv->connection, FALSE);
672                 g_object_unref (msg->priv->connection);
673         }
674
675         msg->priv->connection = conn;
676
677         if (conn) {
678                 msg->priv->socket = soup_connection_get_socket (conn);
679                 g_object_ref (msg->priv->socket);
680         } else if (msg->priv->socket) {
681                 g_object_unref (msg->priv->socket);
682                 msg->priv->socket = NULL;
683         }
684 }
685
686 SoupConnection *
687 soup_message_get_connection (SoupMessage *msg)
688 {
689         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
690
691         return msg->priv->connection;
692 }
693
694 SoupSocket *
695 soup_message_get_socket (SoupMessage *msg)
696 {
697         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
698
699         return msg->priv->socket;
700 }
701
702 void
703 soup_message_set_error (SoupMessage *msg, SoupKnownErrorCode errcode)
704 {
705         g_return_if_fail (SOUP_IS_MESSAGE (msg));
706         g_return_if_fail (errcode != 0);
707
708         g_free ((char *) msg->errorphrase);
709
710         msg->errorcode = errcode;
711         msg->errorclass = soup_error_get_class (errcode);
712         msg->errorphrase = g_strdup (soup_error_get_phrase (errcode));
713 }
714
715 void
716 soup_message_set_error_full (SoupMessage *msg,
717                              guint        errcode,
718                              const char  *errphrase)
719 {
720         g_return_if_fail (SOUP_IS_MESSAGE (msg));
721         g_return_if_fail (errcode != 0);
722         g_return_if_fail (errphrase != NULL);
723
724         g_free ((char *) msg->errorphrase);
725
726         msg->errorcode = errcode;
727         msg->errorclass = soup_error_get_class (errcode);
728         msg->errorphrase = g_strdup (errphrase);
729 }