Add "authenticate" and "reauthenticate" signals. (invalidate_auth): Remove
[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-marshal.h"
12 #include "soup-message.h"
13 #include "soup-message-private.h"
14 #include "soup-misc.h"
15 #include "soup-private.h"
16
17 #define PARENT_TYPE G_TYPE_OBJECT
18 static GObjectClass *parent_class;
19
20 enum {
21         WROTE_HEADERS,
22         WROTE_CHUNK,
23         WROTE_BODY,
24
25         GOT_HEADERS,
26         GOT_CHUNK,
27         GOT_BODY,
28
29         FINISHED,
30
31         LAST_SIGNAL
32 };
33
34 static guint signals[LAST_SIGNAL] = { 0 };
35
36 static void got_headers (SoupMessage *req);
37 static void got_chunk (SoupMessage *req);
38 static void got_body (SoupMessage *req);
39 static void finished (SoupMessage *req);
40 static void free_chunks (SoupMessage *msg);
41
42 static void
43 init (GObject *object)
44 {
45         SoupMessage *msg = SOUP_MESSAGE (object);
46
47         msg->priv = g_new0 (SoupMessagePrivate, 1);
48
49         msg->status  = SOUP_MESSAGE_STATUS_IDLE;
50
51         msg->request_headers = g_hash_table_new (soup_str_case_hash,
52                                                  soup_str_case_equal);
53
54         msg->response_headers = g_hash_table_new (soup_str_case_hash,
55                                                   soup_str_case_equal);
56
57         msg->priv->http_version = SOUP_HTTP_1_1;
58 }
59
60 static void
61 finalize (GObject *object)
62 {
63         SoupMessage *msg = SOUP_MESSAGE (object);
64
65         soup_message_io_cancel (msg);
66
67         if (msg->priv->uri)
68                 soup_uri_free (msg->priv->uri);
69
70         if (msg->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
71                 g_free (msg->request.body);
72         if (msg->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
73                 g_free (msg->response.body);
74         free_chunks (msg);
75
76         soup_message_clear_headers (msg->request_headers);
77         g_hash_table_destroy (msg->request_headers);
78
79         soup_message_clear_headers (msg->response_headers);
80         g_hash_table_destroy (msg->response_headers);
81
82         g_slist_foreach (msg->priv->content_handlers, (GFunc) g_free, NULL);
83         g_slist_free (msg->priv->content_handlers);
84
85         g_free ((char *) msg->reason_phrase);
86
87         g_free (msg->priv);
88
89         G_OBJECT_CLASS (parent_class)->finalize (object);
90 }
91
92 static void
93 class_init (GObjectClass *object_class)
94 {
95         SoupMessageClass *message_class = SOUP_MESSAGE_CLASS (object_class);
96
97         parent_class = g_type_class_ref (PARENT_TYPE);
98
99         /* virtual method definition */
100         message_class->got_headers  = got_headers;
101         message_class->got_chunk    = got_chunk;
102         message_class->got_body     = got_body;
103         message_class->finished     = finished;
104
105         /* virtual method override */
106         object_class->finalize = finalize;
107
108         /* signals */
109         signals[WROTE_HEADERS] =
110                 g_signal_new ("wrote_headers",
111                               G_OBJECT_CLASS_TYPE (object_class),
112                               G_SIGNAL_RUN_FIRST,
113                               G_STRUCT_OFFSET (SoupMessageClass, wrote_headers),
114                               NULL, NULL,
115                               soup_marshal_NONE__NONE,
116                               G_TYPE_NONE, 0);
117         signals[WROTE_CHUNK] =
118                 g_signal_new ("wrote_chunk",
119                               G_OBJECT_CLASS_TYPE (object_class),
120                               G_SIGNAL_RUN_FIRST,
121                               G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk),
122                               NULL, NULL,
123                               soup_marshal_NONE__NONE,
124                               G_TYPE_NONE, 0);
125         signals[WROTE_BODY] =
126                 g_signal_new ("wrote_body",
127                               G_OBJECT_CLASS_TYPE (object_class),
128                               G_SIGNAL_RUN_FIRST,
129                               G_STRUCT_OFFSET (SoupMessageClass, wrote_body),
130                               NULL, NULL,
131                               soup_marshal_NONE__NONE,
132                               G_TYPE_NONE, 0);
133
134         signals[GOT_HEADERS] =
135                 g_signal_new ("got_headers",
136                               G_OBJECT_CLASS_TYPE (object_class),
137                               G_SIGNAL_RUN_FIRST,
138                               G_STRUCT_OFFSET (SoupMessageClass, got_headers),
139                               NULL, NULL,
140                               soup_marshal_NONE__NONE,
141                               G_TYPE_NONE, 0);
142         signals[GOT_CHUNK] =
143                 g_signal_new ("got_chunk",
144                               G_OBJECT_CLASS_TYPE (object_class),
145                               G_SIGNAL_RUN_FIRST,
146                               G_STRUCT_OFFSET (SoupMessageClass, got_chunk),
147                               NULL, NULL,
148                               soup_marshal_NONE__NONE,
149                               G_TYPE_NONE, 0);
150         signals[GOT_BODY] =
151                 g_signal_new ("got_body",
152                               G_OBJECT_CLASS_TYPE (object_class),
153                               G_SIGNAL_RUN_FIRST,
154                               G_STRUCT_OFFSET (SoupMessageClass, got_body),
155                               NULL, NULL,
156                               soup_marshal_NONE__NONE,
157                               G_TYPE_NONE, 0);
158
159         signals[FINISHED] =
160                 g_signal_new ("finished",
161                               G_OBJECT_CLASS_TYPE (object_class),
162                               G_SIGNAL_RUN_FIRST,
163                               G_STRUCT_OFFSET (SoupMessageClass, finished),
164                               NULL, NULL,
165                               soup_marshal_NONE__NONE,
166                               G_TYPE_NONE, 0);
167 }
168
169 SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE)
170
171
172 /**
173  * soup_message_new:
174  * @method: the HTTP method for the created request
175  * @uri_string: the destination endpoint (as a string)
176  * 
177  * Creates a new empty #SoupMessage, which will connect to @uri
178  *
179  * Return value: the new #SoupMessage (or %NULL if @uri could not
180  * be parsed).
181  */
182 SoupMessage *
183 soup_message_new (const char *method, const char *uri_string)
184 {
185         SoupMessage *msg;
186         SoupUri *uri;
187
188         uri = soup_uri_new (uri_string);
189         if (!uri)
190                 return NULL;
191
192         msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
193         msg->method = method ? method : SOUP_METHOD_GET;
194         msg->priv->uri = uri;
195
196         return msg;
197 }
198
199 /**
200  * soup_message_new_from_uri:
201  * @method: the HTTP method for the created request
202  * @uri: the destination endpoint (as a #SoupUri)
203  * 
204  * Creates a new empty #SoupMessage, which will connect to @uri
205  *
206  * Return value: the new #SoupMessage
207  */
208 SoupMessage *
209 soup_message_new_from_uri (const char *method, const SoupUri *uri)
210 {
211         SoupMessage *msg;
212
213         msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
214         msg->method = method ? method : SOUP_METHOD_GET;
215         msg->priv->uri = soup_uri_copy (uri);
216
217         return msg;
218 }
219
220 /**
221  * soup_message_set_request:
222  * @msg: the message
223  * @content_type: MIME Content-Type of the body
224  * @req_owner: the #SoupOwnership of the passed data buffer.
225  * @req_body: a data buffer containing the body of the message request.
226  * @req_length: the byte length of @req_body.
227  * 
228  * Convenience function to set the request body of a #SoupMessage
229  */
230 void
231 soup_message_set_request (SoupMessage   *msg,
232                           const char    *content_type,
233                           SoupOwnership  req_owner,
234                           char          *req_body,
235                           gulong         req_length)
236 {
237         g_return_if_fail (SOUP_IS_MESSAGE (msg));
238         g_return_if_fail (content_type != NULL);
239         g_return_if_fail (req_body != NULL || req_length == 0);
240
241         soup_message_add_header (msg->request_headers,
242                                  "Content-Type", content_type);
243         msg->request.owner = req_owner;
244         msg->request.body = req_body;
245         msg->request.length = req_length;
246 }
247
248 /**
249  * soup_message_set_response:
250  * @msg: the message
251  * @content_type: MIME Content-Type of the body
252  * @req_owner: the #SoupOwnership of the passed data buffer.
253  * @req_body: a data buffer containing the body of the message response.
254  * @req_length: the byte length of @req_body.
255  * 
256  * Convenience function to set the response body of a #SoupMessage
257  */
258 void
259 soup_message_set_response (SoupMessage   *msg,
260                            const char    *content_type,
261                            SoupOwnership  resp_owner,
262                            char          *resp_body,
263                            gulong         resp_length)
264 {
265         g_return_if_fail (SOUP_IS_MESSAGE (msg));
266         g_return_if_fail (content_type != NULL);
267         g_return_if_fail (resp_body != NULL || resp_length == 0);
268
269         soup_message_add_header (msg->response_headers,
270                                  "Content-Type", content_type);
271         msg->response.owner = resp_owner;
272         msg->response.body = resp_body;
273         msg->response.length = resp_length;
274 }
275
276 void
277 soup_message_wrote_headers (SoupMessage *msg)
278 {
279         g_signal_emit (msg, signals[WROTE_HEADERS], 0);
280 }
281
282 void
283 soup_message_wrote_chunk (SoupMessage *msg)
284 {
285         g_signal_emit (msg, signals[WROTE_CHUNK], 0);
286 }
287
288 void
289 soup_message_wrote_body (SoupMessage *msg)
290 {
291         g_signal_emit (msg, signals[WROTE_BODY], 0);
292 }
293
294 static void
295 got_headers (SoupMessage *req)
296 {
297         g_object_ref (req);
298         soup_message_run_handlers (req, SOUP_HANDLER_PRE_BODY);
299         if (SOUP_MESSAGE_IS_STARTING (req))
300                 g_signal_stop_emission (req, signals[GOT_HEADERS], 0);
301         g_object_unref (req);
302 }
303
304 void
305 soup_message_got_headers (SoupMessage *msg)
306 {
307         g_signal_emit (msg, signals[GOT_HEADERS], 0);
308 }
309
310 static void
311 got_chunk (SoupMessage *req)
312 {
313         g_object_ref (req);
314         soup_message_run_handlers (req, SOUP_HANDLER_BODY_CHUNK);
315         if (SOUP_MESSAGE_IS_STARTING (req))
316                 g_signal_stop_emission (req, signals[GOT_CHUNK], 0);
317         g_object_unref (req);
318 }
319
320 void
321 soup_message_got_chunk (SoupMessage *msg)
322 {
323         g_signal_emit (msg, signals[GOT_CHUNK], 0);
324 }
325
326 static void
327 got_body (SoupMessage *req)
328 {
329         g_object_ref (req);
330         soup_message_run_handlers (req, SOUP_HANDLER_POST_BODY);
331         if (SOUP_MESSAGE_IS_STARTING (req))
332                 g_signal_stop_emission (req, signals[GOT_BODY], 0);
333         g_object_unref (req);
334 }
335
336 void
337 soup_message_got_body (SoupMessage *msg)
338 {
339         g_signal_emit (msg, signals[GOT_BODY], 0);
340 }
341
342 static void
343 finished (SoupMessage *req)
344 {
345         soup_message_io_cancel (req);
346 }
347
348 void
349 soup_message_finished (SoupMessage *msg)
350 {
351         g_signal_emit (msg, signals[FINISHED], 0);
352 }
353
354
355 /**
356  * soup_message_cancel:
357  * @msg: a #SoupMessage currently being processed.
358  * 
359  * Cancel a running message, and issue completion callback with an
360  * status code of %SOUP_STATUS_CANCELLED. If not requeued by the
361  * completion callback, the @msg will be destroyed.
362  */
363 void
364 soup_message_cancel (SoupMessage *msg)
365 {
366         soup_message_set_status (msg, SOUP_STATUS_CANCELLED);
367         soup_message_finished (msg);
368 }
369
370 static gboolean
371 free_header_list (gpointer name, gpointer vals, gpointer user_data)
372 {
373         g_free (name);
374         g_slist_foreach (vals, (GFunc) g_free, NULL);
375         g_slist_free (vals);
376
377         return TRUE;
378 }
379
380 void
381 soup_message_clear_headers (GHashTable *hash)
382 {
383         g_return_if_fail (hash != NULL);
384
385         g_hash_table_foreach_remove (hash, free_header_list, NULL);
386 }
387
388 void
389 soup_message_remove_header (GHashTable *hash, const char *name)
390 {
391         gpointer old_key, old_vals;
392
393         g_return_if_fail (hash != NULL);
394         g_return_if_fail (name != NULL || name[0] != '\0');
395
396         if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
397                 g_hash_table_remove (hash, name);
398                 free_header_list (old_key, old_vals, NULL);
399         }
400 }
401
402 void
403 soup_message_add_header (GHashTable *hash, const char *name, const char *value)
404 {
405         GSList *old_value;
406
407         g_return_if_fail (hash != NULL);
408         g_return_if_fail (name != NULL || name [0] != '\0');
409         g_return_if_fail (value != NULL);
410
411         old_value = g_hash_table_lookup (hash, name);
412
413         if (old_value)
414                 g_slist_append (old_value, g_strdup (value));
415         else {
416                 g_hash_table_insert (hash, g_strdup (name),
417                                      g_slist_append (NULL, g_strdup (value)));
418         }
419 }
420
421 /**
422  * soup_message_get_header:
423  * @hash: a header hash table
424  * @name: header name.
425  * 
426  * Lookup the first transport header in @hash with a key equal to
427  * @name.
428  * 
429  * Return value: the header's value or %NULL if not found.
430  */
431 const char *
432 soup_message_get_header (GHashTable *hash, const char *name)
433 {
434         GSList *vals;
435
436         g_return_val_if_fail (hash != NULL, NULL);
437         g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
438
439         vals = g_hash_table_lookup (hash, name);
440         if (vals)
441                 return vals->data;
442
443         return NULL;
444 }
445
446 /**
447  * soup_message_get_header_list:
448  * @hash: a header hash table
449  * @name: header name.
450  * 
451  * Lookup the all transport request headers in @hash with a key equal
452  * to @name.
453  * 
454  * Return value: a const pointer to a #GSList of header values or
455  * %NULL if not found.
456  */
457 const GSList *
458 soup_message_get_header_list (GHashTable *hash, const char *name)
459 {
460         g_return_val_if_fail (hash != NULL, NULL);
461         g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
462
463         return g_hash_table_lookup (hash, name);
464 }
465
466 typedef struct {
467         GHFunc   func;
468         gpointer user_data;
469 } SoupMessageForeachHeaderData;
470
471 static void
472 foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
473 {
474         GSList *vals = value;
475         SoupMessageForeachHeaderData *data = user_data;
476
477         while (vals) {
478                 (*data->func) (name, vals->data, data->user_data);
479                 vals = vals->next;
480         }
481 }
482
483 void
484 soup_message_foreach_header (GHashTable *hash, GHFunc func, gpointer user_data)
485 {
486         SoupMessageForeachHeaderData data;
487
488         g_return_if_fail (hash != NULL);
489         g_return_if_fail (func != NULL);
490
491         data.func = func;
492         data.user_data = user_data;
493         g_hash_table_foreach (hash, foreach_value_in_list, &data);
494 }
495
496 /**
497  * soup_message_prepare:
498  * @req: a message
499  *
500  * Prepares @req to be sent, by cleaning up its prior response state
501  **/
502 void
503 soup_message_prepare (SoupMessage *req)
504 {
505         soup_message_io_cancel (req);
506
507         if (req->status != SOUP_MESSAGE_STATUS_IDLE)
508                 req->status = SOUP_MESSAGE_STATUS_IDLE;
509
510         if (req->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
511                 g_free (req->response.body);
512
513         req->response.owner = 0;
514         req->response.body = NULL;
515         req->response.length = 0;
516
517         free_chunks (req);
518
519         soup_message_clear_headers (req->response_headers);
520
521         req->status_code = 0;
522         if (req->reason_phrase) {
523                 g_free ((char *) req->reason_phrase);
524                 req->reason_phrase = NULL;
525         }
526 }
527
528 void
529 soup_message_set_flags (SoupMessage *msg, guint flags)
530 {
531         g_return_if_fail (SOUP_IS_MESSAGE (msg));
532
533         msg->priv->msg_flags = flags;
534 }
535
536 guint
537 soup_message_get_flags (SoupMessage *msg)
538 {
539         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
540
541         return msg->priv->msg_flags;
542 }
543
544 void
545 soup_message_set_http_version  (SoupMessage *msg, SoupHttpVersion version)
546 {
547         g_return_if_fail (SOUP_IS_MESSAGE (msg));
548
549         msg->priv->http_version = version;
550 }
551
552 SoupHttpVersion
553 soup_message_get_http_version (SoupMessage *msg)
554 {
555         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
556
557         return msg->priv->http_version;
558 }
559
560 gboolean
561 soup_message_is_keepalive (SoupMessage *msg)
562 {
563         const char *c_conn, *s_conn;
564
565         c_conn = soup_message_get_header (msg->request_headers, "Connection");
566         s_conn = soup_message_get_header (msg->response_headers, "Connection");
567
568         if (msg->priv->http_version == SOUP_HTTP_1_0) {
569                 /* Only persistent if the client requested keepalive
570                  * and the server agreed.
571                  */
572
573                 if (!c_conn || !s_conn)
574                         return FALSE;
575                 if (g_strcasecmp (c_conn, "Keep-Alive") != 0 ||
576                     g_strcasecmp (s_conn, "Keep-Alive") != 0)
577                         return FALSE;
578
579                 return TRUE;
580         } else {
581                 /* Persistent unless either side requested otherwise */
582
583                 if (c_conn && g_strcasecmp (c_conn, "close") == 0)
584                         return FALSE;
585                 if (s_conn && g_strcasecmp (s_conn, "close") == 0)
586                         return FALSE;
587
588                 return TRUE;
589         }
590 }
591
592 void
593 soup_message_set_uri (SoupMessage *msg, const SoupUri *new_uri)
594 {
595         g_return_if_fail (SOUP_IS_MESSAGE (msg));
596
597         if (msg->priv->uri && new_uri) {
598                 if (strcmp (msg->priv->uri->host, new_uri->host) != 0)
599                         soup_message_io_cancel (msg);
600         } else if (!new_uri)
601                 soup_message_io_cancel (msg);
602
603         if (msg->priv->uri)
604                 soup_uri_free (msg->priv->uri);
605         msg->priv->uri = soup_uri_copy (new_uri);
606 }
607
608 const SoupUri *
609 soup_message_get_uri (SoupMessage *msg)
610 {
611         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
612
613         return msg->priv->uri;
614 }
615
616 void
617 soup_message_set_status (SoupMessage *msg, guint status_code)
618 {
619         g_return_if_fail (SOUP_IS_MESSAGE (msg));
620         g_return_if_fail (status_code != 0);
621
622         g_free ((char *) msg->reason_phrase);
623
624         msg->status_code = status_code;
625         msg->reason_phrase = g_strdup (soup_status_get_phrase (status_code));
626 }
627
628 void
629 soup_message_set_status_full (SoupMessage *msg,
630                               guint        status_code,
631                               const char  *reason_phrase)
632 {
633         g_return_if_fail (SOUP_IS_MESSAGE (msg));
634         g_return_if_fail (status_code != 0);
635         g_return_if_fail (reason_phrase != NULL);
636
637         g_free ((char *) msg->reason_phrase);
638
639         msg->status_code = status_code;
640         msg->reason_phrase = g_strdup (reason_phrase);
641 }
642
643
644 void
645 soup_message_add_chunk (SoupMessage   *msg,
646                         SoupOwnership  owner,
647                         const char    *body,
648                         guint          length)
649 {
650         SoupDataBuffer *chunk;
651
652         g_return_if_fail (SOUP_IS_MESSAGE (msg));
653         g_return_if_fail (body != NULL || length == 0);
654
655         chunk = g_new0 (SoupDataBuffer, 1);
656         if (owner == SOUP_BUFFER_USER_OWNED) {
657                 chunk->owner = SOUP_BUFFER_SYSTEM_OWNED;
658                 chunk->body = g_memdup (body, length);
659         } else {
660                 chunk->owner = owner;
661                 chunk->body = (char *)body;
662         }
663         chunk->length = length;
664
665         if (msg->priv->chunks) {
666                 g_slist_append (msg->priv->last_chunk, chunk);
667                 msg->priv->last_chunk = msg->priv->last_chunk->next;
668         } else {
669                 msg->priv->chunks = msg->priv->last_chunk =
670                         g_slist_append (NULL, chunk);
671         }
672 }
673
674 void
675 soup_message_add_final_chunk (SoupMessage *msg)
676 {
677         soup_message_add_chunk (msg, SOUP_BUFFER_STATIC, NULL, 0);
678 }
679
680 SoupDataBuffer *
681 soup_message_pop_chunk (SoupMessage *msg)
682 {
683         SoupDataBuffer *chunk;
684
685         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
686
687         if (!msg->priv->chunks)
688                 return NULL;
689
690         chunk = msg->priv->chunks->data;
691         msg->priv->chunks = g_slist_remove (msg->priv->chunks, chunk);
692         if (!msg->priv->chunks)
693                 msg->priv->last_chunk = NULL;
694
695         return chunk;
696 }
697
698 static void
699 free_chunks (SoupMessage *msg)
700 {
701         SoupDataBuffer *chunk;
702         GSList *ch;
703
704         for (ch = msg->priv->chunks; ch; ch = ch->next) {
705                 chunk = ch->data;
706
707                 if (chunk->owner == SOUP_BUFFER_SYSTEM_OWNED)
708                         g_free (chunk->body);
709                 g_free (chunk);
710         }
711
712         g_slist_free (msg->priv->chunks);
713         msg->priv->chunks = msg->priv->last_chunk = NULL;
714 }