source: trunk/third/libsoup/libsoup/soup-message.c @ 21108

Revision 21108, 23.2 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21107, which included commits to RCS files with non-trunk default branches.
Line 
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-uri.h"
16
17#define PARENT_TYPE G_TYPE_OBJECT
18static GObjectClass *parent_class;
19
20enum {
21        WROTE_INFORMATIONAL,
22        WROTE_HEADERS,
23        WROTE_CHUNK,
24        WROTE_BODY,
25
26        GOT_INFORMATIONAL,
27        GOT_HEADERS,
28        GOT_CHUNK,
29        GOT_BODY,
30
31        RESTARTED,
32        FINISHED,
33
34        LAST_SIGNAL
35};
36
37static guint signals[LAST_SIGNAL] = { 0 };
38
39static void wrote_body (SoupMessage *req);
40static void got_headers (SoupMessage *req);
41static void got_chunk (SoupMessage *req);
42static void got_body (SoupMessage *req);
43static void restarted (SoupMessage *req);
44static void finished (SoupMessage *req);
45static void free_chunks (SoupMessage *msg);
46
47static void
48init (GObject *object)
49{
50        SoupMessage *msg = SOUP_MESSAGE (object);
51
52        msg->priv = g_new0 (SoupMessagePrivate, 1);
53
54        msg->status  = SOUP_MESSAGE_STATUS_IDLE;
55
56        msg->request_headers = g_hash_table_new (soup_str_case_hash,
57                                                 soup_str_case_equal);
58
59        msg->response_headers = g_hash_table_new (soup_str_case_hash,
60                                                  soup_str_case_equal);
61
62        msg->priv->http_version = SOUP_HTTP_1_1;
63}
64
65static void
66finalize (GObject *object)
67{
68        SoupMessage *msg = SOUP_MESSAGE (object);
69
70        soup_message_io_stop (msg);
71
72        if (msg->priv->uri)
73                soup_uri_free (msg->priv->uri);
74
75        if (msg->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
76                g_free (msg->request.body);
77        if (msg->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
78                g_free (msg->response.body);
79        free_chunks (msg);
80
81        soup_message_clear_headers (msg->request_headers);
82        g_hash_table_destroy (msg->request_headers);
83
84        soup_message_clear_headers (msg->response_headers);
85        g_hash_table_destroy (msg->response_headers);
86
87        g_slist_foreach (msg->priv->content_handlers, (GFunc) g_free, NULL);
88        g_slist_free (msg->priv->content_handlers);
89
90        g_free ((char *) msg->reason_phrase);
91
92        g_free (msg->priv);
93
94        G_OBJECT_CLASS (parent_class)->finalize (object);
95}
96
97static void
98class_init (GObjectClass *object_class)
99{
100        SoupMessageClass *message_class = SOUP_MESSAGE_CLASS (object_class);
101
102        parent_class = g_type_class_ref (PARENT_TYPE);
103
104        /* virtual method definition */
105        message_class->wrote_body   = wrote_body;
106        message_class->got_headers  = got_headers;
107        message_class->got_chunk    = got_chunk;
108        message_class->got_body     = got_body;
109        message_class->restarted    = restarted;
110        message_class->finished     = finished;
111
112        /* virtual method override */
113        object_class->finalize = finalize;
114
115        /* signals */
116        signals[WROTE_INFORMATIONAL] =
117                g_signal_new ("wrote_informational",
118                              G_OBJECT_CLASS_TYPE (object_class),
119                              G_SIGNAL_RUN_FIRST,
120                              G_STRUCT_OFFSET (SoupMessageClass, wrote_informational),
121                              NULL, NULL,
122                              soup_marshal_NONE__NONE,
123                              G_TYPE_NONE, 0);
124        signals[WROTE_HEADERS] =
125                g_signal_new ("wrote_headers",
126                              G_OBJECT_CLASS_TYPE (object_class),
127                              G_SIGNAL_RUN_FIRST,
128                              G_STRUCT_OFFSET (SoupMessageClass, wrote_headers),
129                              NULL, NULL,
130                              soup_marshal_NONE__NONE,
131                              G_TYPE_NONE, 0);
132        signals[WROTE_CHUNK] =
133                g_signal_new ("wrote_chunk",
134                              G_OBJECT_CLASS_TYPE (object_class),
135                              G_SIGNAL_RUN_FIRST,
136                              G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk),
137                              NULL, NULL,
138                              soup_marshal_NONE__NONE,
139                              G_TYPE_NONE, 0);
140        signals[WROTE_BODY] =
141                g_signal_new ("wrote_body",
142                              G_OBJECT_CLASS_TYPE (object_class),
143                              G_SIGNAL_RUN_FIRST,
144                              G_STRUCT_OFFSET (SoupMessageClass, wrote_body),
145                              NULL, NULL,
146                              soup_marshal_NONE__NONE,
147                              G_TYPE_NONE, 0);
148
149        signals[GOT_INFORMATIONAL] =
150                g_signal_new ("got_informational",
151                              G_OBJECT_CLASS_TYPE (object_class),
152                              G_SIGNAL_RUN_FIRST,
153                              G_STRUCT_OFFSET (SoupMessageClass, got_informational),
154                              NULL, NULL,
155                              soup_marshal_NONE__NONE,
156                              G_TYPE_NONE, 0);
157        signals[GOT_HEADERS] =
158                g_signal_new ("got_headers",
159                              G_OBJECT_CLASS_TYPE (object_class),
160                              G_SIGNAL_RUN_FIRST,
161                              G_STRUCT_OFFSET (SoupMessageClass, got_headers),
162                              NULL, NULL,
163                              soup_marshal_NONE__NONE,
164                              G_TYPE_NONE, 0);
165        signals[GOT_CHUNK] =
166                g_signal_new ("got_chunk",
167                              G_OBJECT_CLASS_TYPE (object_class),
168                              G_SIGNAL_RUN_FIRST,
169                              G_STRUCT_OFFSET (SoupMessageClass, got_chunk),
170                              NULL, NULL,
171                              soup_marshal_NONE__NONE,
172                              G_TYPE_NONE, 0);
173        signals[GOT_BODY] =
174                g_signal_new ("got_body",
175                              G_OBJECT_CLASS_TYPE (object_class),
176                              G_SIGNAL_RUN_FIRST,
177                              G_STRUCT_OFFSET (SoupMessageClass, got_body),
178                              NULL, NULL,
179                              soup_marshal_NONE__NONE,
180                              G_TYPE_NONE, 0);
181
182        signals[RESTARTED] =
183                g_signal_new ("restarted",
184                              G_OBJECT_CLASS_TYPE (object_class),
185                              G_SIGNAL_RUN_FIRST,
186                              G_STRUCT_OFFSET (SoupMessageClass, restarted),
187                              NULL, NULL,
188                              soup_marshal_NONE__NONE,
189                              G_TYPE_NONE, 0);
190        signals[FINISHED] =
191                g_signal_new ("finished",
192                              G_OBJECT_CLASS_TYPE (object_class),
193                              G_SIGNAL_RUN_FIRST,
194                              G_STRUCT_OFFSET (SoupMessageClass, finished),
195                              NULL, NULL,
196                              soup_marshal_NONE__NONE,
197                              G_TYPE_NONE, 0);
198}
199
200SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE)
201
202
203/**
204 * soup_message_new:
205 * @method: the HTTP method for the created request
206 * @uri_string: the destination endpoint (as a string)
207 *
208 * Creates a new empty #SoupMessage, which will connect to @uri
209 *
210 * Return value: the new #SoupMessage (or %NULL if @uri could not
211 * be parsed).
212 */
213SoupMessage *
214soup_message_new (const char *method, const char *uri_string)
215{
216        SoupMessage *msg;
217        SoupUri *uri;
218
219        uri = soup_uri_new (uri_string);
220        if (!uri)
221                return NULL;
222
223        if (!uri->host) {
224                soup_uri_free (uri);
225                return NULL;
226        }
227
228        msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
229        msg->method = method ? method : SOUP_METHOD_GET;
230        msg->priv->uri = uri;
231
232        return msg;
233}
234
235/**
236 * soup_message_new_from_uri:
237 * @method: the HTTP method for the created request
238 * @uri: the destination endpoint (as a #SoupUri)
239 *
240 * Creates a new empty #SoupMessage, which will connect to @uri
241 *
242 * Return value: the new #SoupMessage
243 */
244SoupMessage *
245soup_message_new_from_uri (const char *method, const SoupUri *uri)
246{
247        SoupMessage *msg;
248
249        msg = g_object_new (SOUP_TYPE_MESSAGE, NULL);
250        msg->method = method ? method : SOUP_METHOD_GET;
251        msg->priv->uri = soup_uri_copy (uri);
252
253        return msg;
254}
255
256/**
257 * soup_message_set_request:
258 * @msg: the message
259 * @content_type: MIME Content-Type of the body
260 * @req_owner: the #SoupOwnership of the passed data buffer.
261 * @req_body: a data buffer containing the body of the message request.
262 * @req_length: the byte length of @req_body.
263 *
264 * Convenience function to set the request body of a #SoupMessage
265 */
266void
267soup_message_set_request (SoupMessage   *msg,
268                          const char    *content_type,
269                          SoupOwnership  req_owner,
270                          char          *req_body,
271                          gulong         req_length)
272{
273        g_return_if_fail (SOUP_IS_MESSAGE (msg));
274        g_return_if_fail (content_type != NULL);
275        g_return_if_fail (req_body != NULL || req_length == 0);
276
277        soup_message_add_header (msg->request_headers,
278                                 "Content-Type", content_type);
279        msg->request.owner = req_owner;
280        msg->request.body = req_body;
281        msg->request.length = req_length;
282}
283
284/**
285 * soup_message_set_response:
286 * @msg: the message
287 * @content_type: MIME Content-Type of the body
288 * @resp_owner: the #SoupOwnership of the passed data buffer.
289 * @resp_body: a data buffer containing the body of the message response.
290 * @resp_length: the byte length of @resp_body.
291 *
292 * Convenience function to set the response body of a #SoupMessage
293 */
294void
295soup_message_set_response (SoupMessage   *msg,
296                           const char    *content_type,
297                           SoupOwnership  resp_owner,
298                           char          *resp_body,
299                           gulong         resp_length)
300{
301        g_return_if_fail (SOUP_IS_MESSAGE (msg));
302        g_return_if_fail (content_type != NULL);
303        g_return_if_fail (resp_body != NULL || resp_length == 0);
304
305        soup_message_add_header (msg->response_headers,
306                                 "Content-Type", content_type);
307        msg->response.owner = resp_owner;
308        msg->response.body = resp_body;
309        msg->response.length = resp_length;
310}
311
312/**
313 * soup_message_wrote_informational:
314 * @msg: a #SoupMessage
315 *
316 * Emits the %wrote_informational signal, indicating that the IO layer
317 * finished writing an informational (1xx) response for @msg.
318 **/
319void
320soup_message_wrote_informational (SoupMessage *msg)
321{
322        g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0);
323}
324
325/**
326 * soup_message_wrote_headers:
327 * @msg: a #SoupMessage
328 *
329 * Emits the %wrote_headers signal, indicating that the IO layer
330 * finished writing the (non-informational) headers for @msg.
331 **/
332void
333soup_message_wrote_headers (SoupMessage *msg)
334{
335        g_signal_emit (msg, signals[WROTE_HEADERS], 0);
336}
337
338/**
339 * soup_message_wrote_chunk:
340 * @msg: a #SoupMessage
341 *
342 * Emits the %wrote_chunk signal, indicating that the IO layer
343 * finished writing a chunk of @msg's body.
344 **/
345void
346soup_message_wrote_chunk (SoupMessage *msg)
347{
348        g_signal_emit (msg, signals[WROTE_CHUNK], 0);
349}
350
351static void
352wrote_body (SoupMessage *req)
353{
354        g_object_ref (req);
355        soup_message_run_handlers (req, SOUP_HANDLER_POST_REQUEST);
356        g_object_unref (req);
357}
358
359/**
360 * soup_message_wrote_body:
361 * @msg: a #SoupMessage
362 *
363 * Emits the %wrote_body signal, indicating that the IO layer finished
364 * writing the body for @msg.
365 **/
366void
367soup_message_wrote_body (SoupMessage *msg)
368{
369        g_signal_emit (msg, signals[WROTE_BODY], 0);
370}
371
372/**
373 * soup_message_got_informational:
374 * @msg: a #SoupMessage
375 *
376 * Emits the %got_informational signal, indicating that the IO layer
377 * read a complete informational (1xx) response for @msg.
378 **/
379void
380soup_message_got_informational (SoupMessage *msg)
381{
382        g_signal_emit (msg, signals[GOT_INFORMATIONAL], 0);
383}
384
385static void
386got_headers (SoupMessage *req)
387{
388        g_object_ref (req);
389        soup_message_run_handlers (req, SOUP_HANDLER_PRE_BODY);
390        if (SOUP_MESSAGE_IS_STARTING (req))
391                g_signal_stop_emission (req, signals[GOT_HEADERS], 0);
392        g_object_unref (req);
393}
394
395/**
396 * soup_message_got_headers:
397 * @msg: a #SoupMessage
398 *
399 * Emits the %got_headers signal, indicating that the IO layer
400 * finished reading the (non-informational) headers for @msg.
401 **/
402void
403soup_message_got_headers (SoupMessage *msg)
404{
405        g_signal_emit (msg, signals[GOT_HEADERS], 0);
406}
407
408static void
409got_chunk (SoupMessage *req)
410{
411        g_object_ref (req);
412        soup_message_run_handlers (req, SOUP_HANDLER_BODY_CHUNK);
413        if (SOUP_MESSAGE_IS_STARTING (req))
414                g_signal_stop_emission (req, signals[GOT_CHUNK], 0);
415        g_object_unref (req);
416}
417
418/**
419 * soup_message_got_chunk:
420 * @msg: a #SoupMessage
421 *
422 * Emits the %got_chunk signal, indicating that the IO layer finished
423 * reading a chunk of @msg's body.
424 **/
425void
426soup_message_got_chunk (SoupMessage *msg)
427{
428        g_signal_emit (msg, signals[GOT_CHUNK], 0);
429}
430
431static void
432got_body (SoupMessage *req)
433{
434        g_object_ref (req);
435        soup_message_run_handlers (req, SOUP_HANDLER_POST_BODY);
436        if (SOUP_MESSAGE_IS_STARTING (req))
437                g_signal_stop_emission (req, signals[GOT_BODY], 0);
438        g_object_unref (req);
439}
440
441/**
442 * soup_message_got_body:
443 * @msg: a #SoupMessage
444 *
445 * Emits the %got_body signal, indicating that the IO layer finished
446 * reading the body for @msg.
447 **/
448void
449soup_message_got_body (SoupMessage *msg)
450{
451        g_signal_emit (msg, signals[GOT_BODY], 0);
452}
453
454static void
455restarted (SoupMessage *req)
456{
457        soup_message_io_stop (req);
458}
459
460/**
461 * soup_message_restarted:
462 * @msg: a #SoupMessage
463 *
464 * Emits the %restarted signal, indicating that @msg should be
465 * requeued.
466 **/
467void
468soup_message_restarted (SoupMessage *msg)
469{
470        g_signal_emit (msg, signals[RESTARTED], 0);
471}
472
473static void
474finished (SoupMessage *req)
475{
476        soup_message_io_stop (req);
477        req->status = SOUP_MESSAGE_STATUS_FINISHED;
478}
479
480/**
481 * soup_message_finished:
482 * @msg: a #SoupMessage
483 *
484 * Emits the %finished signal, indicating that @msg has been completely
485 * processed.
486 **/
487void
488soup_message_finished (SoupMessage *msg)
489{
490        g_signal_emit (msg, signals[FINISHED], 0);
491}
492
493static gboolean
494free_header_list (gpointer name, gpointer vals, gpointer user_data)
495{
496        g_free (name);
497        g_slist_foreach (vals, (GFunc) g_free, NULL);
498        g_slist_free (vals);
499
500        return TRUE;
501}
502
503/**
504 * soup_message_clear_headers:
505 * @hash: a header table (the %request_headers or %response_headers
506 * field of a #SoupMessage)
507 *
508 * Clears @hash.
509 **/
510void
511soup_message_clear_headers (GHashTable *hash)
512{
513        g_return_if_fail (hash != NULL);
514
515        g_hash_table_foreach_remove (hash, free_header_list, NULL);
516}
517
518/**
519 * soup_message_remove_header:
520 * @hash: a header table (the %request_headers or %response_headers
521 * field of a #SoupMessage)
522 * @name: the header name to remove
523 *
524 * Removes @name from @hash. If there are multiple values for @name,
525 * they are all removed.
526 **/
527void
528soup_message_remove_header (GHashTable *hash, const char *name)
529{
530        gpointer old_key, old_vals;
531
532        g_return_if_fail (hash != NULL);
533        g_return_if_fail (name != NULL || name[0] != '\0');
534
535        if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
536                g_hash_table_remove (hash, name);
537                free_header_list (old_key, old_vals, NULL);
538        }
539}
540
541/**
542 * soup_message_add_header:
543 * @hash: a header table (the %request_headers or %response_headers
544 * field of a #SoupMessage)
545 * @name: the header name to add
546 * @value: the value of the new header
547 *
548 * Adds a header with name @name and value @value to @hash. If there
549 * was already a header with name @name, this one does not replace it,
550 * it is merely added to it.
551 **/
552void
553soup_message_add_header (GHashTable *hash, const char *name, const char *value)
554{
555        GSList *old_value;
556
557        g_return_if_fail (hash != NULL);
558        g_return_if_fail (name != NULL || name [0] != '\0');
559        g_return_if_fail (value != NULL);
560
561        old_value = g_hash_table_lookup (hash, name);
562
563        if (old_value)
564                g_slist_append (old_value, g_strdup (value));
565        else {
566                g_hash_table_insert (hash, g_strdup (name),
567                                     g_slist_append (NULL, g_strdup (value)));
568        }
569}
570
571/**
572 * soup_message_get_header:
573 * @hash: a header table (the %request_headers or %response_headers
574 * field of a #SoupMessage)
575 * @name: header name.
576 *
577 * Finds the first header in @hash with name @name.
578 *
579 * Return value: the header's value or %NULL if not found.
580 **/
581const char *
582soup_message_get_header (GHashTable *hash, const char *name)
583{
584        GSList *vals;
585
586        g_return_val_if_fail (hash != NULL, NULL);
587        g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
588
589        vals = g_hash_table_lookup (hash, name);
590        if (vals)
591                return vals->data;
592
593        return NULL;
594}
595
596/**
597 * soup_message_get_header_list:
598 * @hash: a header table (the %request_headers or %response_headers
599 * field of a #SoupMessage)
600 * @name: header name.
601 *
602 * Finds all headers in @hash with name @name.
603 *
604 * Return value: a (possibly empty) list of values of headers with
605 * name @name. The caller should not modify or free this list.
606 **/
607const GSList *
608soup_message_get_header_list (GHashTable *hash, const char *name)
609{
610        g_return_val_if_fail (hash != NULL, NULL);
611        g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
612
613        return g_hash_table_lookup (hash, name);
614}
615
616typedef struct {
617        GHFunc   func;
618        gpointer user_data;
619} SoupMessageForeachHeaderData;
620
621static void
622foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
623{
624        GSList *vals = value;
625        SoupMessageForeachHeaderData *data = user_data;
626
627        while (vals) {
628                (*data->func) (name, vals->data, data->user_data);
629                vals = vals->next;
630        }
631}
632
633/**
634 * soup_message_foreach_header:
635 * @hash: a header table (the %request_headers or %response_headers
636 * field of a #SoupMessage)
637 * @func: callback function to run for each header
638 * @user_data: data to pass to @func
639 *
640 * Calls @func once for each header value in @hash. (If there are
641 * headers will multiple values, @func will be called once on each
642 * value.)
643 **/
644void
645soup_message_foreach_header (GHashTable *hash, GHFunc func, gpointer user_data)
646{
647        SoupMessageForeachHeaderData data;
648
649        g_return_if_fail (hash != NULL);
650        g_return_if_fail (func != NULL);
651
652        data.func = func;
653        data.user_data = user_data;
654        g_hash_table_foreach (hash, foreach_value_in_list, &data);
655}
656
657/**
658 * soup_message_cleanup_response:
659 * @req: a #SoupMessage
660 *
661 * Cleans up all response data on @req, so that the request can be sent
662 * again and receive a new response. (Eg, as a result of a redirect or
663 * authorization request.)
664 **/
665void
666soup_message_cleanup_response (SoupMessage *req)
667{
668        if (req->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
669                g_free (req->response.body);
670
671        req->response.owner = 0;
672        req->response.body = NULL;
673        req->response.length = 0;
674
675        free_chunks (req);
676
677        soup_message_clear_headers (req->response_headers);
678
679        req->status_code = SOUP_STATUS_NONE;
680        if (req->reason_phrase) {
681                g_free ((char *) req->reason_phrase);
682                req->reason_phrase = NULL;
683        }
684}
685
686/**
687 * soup_message_set_flags:
688 * @msg: a #SoupMessage
689 * @flags: a set of #SoupMessageFlags values
690 *
691 * Sets the specified flags on @msg.
692 **/
693void
694soup_message_set_flags (SoupMessage *msg, guint flags)
695{
696        g_return_if_fail (SOUP_IS_MESSAGE (msg));
697
698        msg->priv->msg_flags = flags;
699}
700
701/**
702 * soup_message_get_flags:
703 * @msg: a #SoupMessage
704 *
705 * Gets the flags on @msg
706 *
707 * Return value: the flags
708 **/
709guint
710soup_message_get_flags (SoupMessage *msg)
711{
712        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
713
714        return msg->priv->msg_flags;
715}
716
717/**
718 * soup_message_set_http_version:
719 * @msg: a #SoupMessage
720 * @version: the HTTP version
721 *
722 * Sets the HTTP version on @msg. The default version is
723 * %SOUP_HTTP_1_1. Setting it to %SOUP_HTTP_1_0 will prevent certain
724 * functionality from being used.
725 **/
726void
727soup_message_set_http_version (SoupMessage *msg, SoupHttpVersion version)
728{
729        g_return_if_fail (SOUP_IS_MESSAGE (msg));
730
731        msg->priv->http_version = version;
732}
733
734/**
735 * soup_message_get_http_version:
736 * @msg: a #SoupMessage
737 *
738 * Gets the HTTP version of @msg. This is the minimum of the
739 * version from the request and the version from the response.
740 *
741 * Return value: the HTTP version
742 **/
743SoupHttpVersion
744soup_message_get_http_version (SoupMessage *msg)
745{
746        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
747
748        return msg->priv->http_version;
749}
750
751/**
752 * soup_message_is_keepalive:
753 * @msg: a #SoupMessage
754 *
755 * Determines whether or not @msg's connection can be kept alive for
756 * further requests after processing @msg.
757 *
758 * Return value: %TRUE or %FALSE.
759 **/
760gboolean
761soup_message_is_keepalive (SoupMessage *msg)
762{
763        const char *c_conn, *s_conn;
764
765        c_conn = soup_message_get_header (msg->request_headers, "Connection");
766        s_conn = soup_message_get_header (msg->response_headers, "Connection");
767
768        if (msg->status_code == SOUP_STATUS_OK &&
769            soup_method_get_id (msg->method) == SOUP_METHOD_ID_CONNECT)
770                return TRUE;
771
772        if (msg->priv->http_version == SOUP_HTTP_1_0) {
773                /* Only persistent if the client requested keepalive
774                 * and the server agreed.
775                 */
776
777                if (!c_conn || !s_conn)
778                        return FALSE;
779                if (g_strcasecmp (c_conn, "Keep-Alive") != 0 ||
780                    g_strcasecmp (s_conn, "Keep-Alive") != 0)
781                        return FALSE;
782
783                return TRUE;
784        } else {
785                /* Persistent unless either side requested otherwise */
786
787                if (c_conn && g_strcasecmp (c_conn, "close") == 0)
788                        return FALSE;
789                if (s_conn && g_strcasecmp (s_conn, "close") == 0)
790                        return FALSE;
791
792                return TRUE;
793        }
794}
795
796/**
797 * soup_message_set_uri:
798 * @msg: a #SoupMessage
799 * @new_uri: the new #SoupUri
800 *
801 * Changes the URI that @msg is directed to (generally as a result
802 * of a redirect).
803 **/
804void
805soup_message_set_uri (SoupMessage *msg, const SoupUri *new_uri)
806{
807        g_return_if_fail (SOUP_IS_MESSAGE (msg));
808
809        if (msg->priv->uri && new_uri) {
810                if (strcmp (msg->priv->uri->host, new_uri->host) != 0)
811                        soup_message_io_stop (msg);
812        } else if (!new_uri)
813                soup_message_io_stop (msg);
814
815        if (msg->priv->uri)
816                soup_uri_free (msg->priv->uri);
817        msg->priv->uri = soup_uri_copy (new_uri);
818}
819
820/**
821 * soup_message_get_uri:
822 * @msg: a #SoupMessage
823 *
824 * Gets @msg's URI
825 *
826 * Return value: the URI @msg is targeted for.
827 **/
828const SoupUri *
829soup_message_get_uri (SoupMessage *msg)
830{
831        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
832
833        return msg->priv->uri;
834}
835
836/**
837 * soup_message_set_status:
838 * @msg: a #SoupMessage
839 * @status_code: an HTTP status code
840 *
841 * Sets @msg's status code to @status_code. If @status_code is a
842 * known value, it will also set @msg's reason_phrase.
843 **/
844void
845soup_message_set_status (SoupMessage *msg, guint status_code)
846{
847        g_return_if_fail (SOUP_IS_MESSAGE (msg));
848        g_return_if_fail (status_code != 0);
849
850        g_free ((char *) msg->reason_phrase);
851
852        msg->status_code = status_code;
853        msg->reason_phrase = g_strdup (soup_status_get_phrase (status_code));
854}
855
856/**
857 * soup_message_set_status_full:
858 * @msg: a #SoupMessage
859 * @status_code: an HTTP status code
860 * @reason_phrase: a description of the status
861 *
862 * Sets @msg's status code and reason phrase.
863 **/
864void
865soup_message_set_status_full (SoupMessage *msg,
866                              guint        status_code,
867                              const char  *reason_phrase)
868{
869        g_return_if_fail (SOUP_IS_MESSAGE (msg));
870        g_return_if_fail (status_code != 0);
871        g_return_if_fail (reason_phrase != NULL);
872
873        g_free ((char *) msg->reason_phrase);
874
875        msg->status_code = status_code;
876        msg->reason_phrase = g_strdup (reason_phrase);
877}
878
879
880/**
881 * soup_message_add_chunk:
882 * @msg: a #SoupMessage
883 * @owner: the ownership of @body
884 * @body: body data
885 * @length: length of @body
886 *
887 * Adds a chunk of response data to @body. (Note that currently
888 * there is no way to send a request using chunked encoding.)
889 **/
890void
891soup_message_add_chunk (SoupMessage   *msg,
892                        SoupOwnership  owner,
893                        const char    *body,
894                        guint          length)
895{
896        SoupDataBuffer *chunk;
897
898        g_return_if_fail (SOUP_IS_MESSAGE (msg));
899        g_return_if_fail (body != NULL || length == 0);
900
901        chunk = g_new0 (SoupDataBuffer, 1);
902        if (owner == SOUP_BUFFER_USER_OWNED) {
903                chunk->owner = SOUP_BUFFER_SYSTEM_OWNED;
904                chunk->body = g_memdup (body, length);
905        } else {
906                chunk->owner = owner;
907                chunk->body = (char *)body;
908        }
909        chunk->length = length;
910
911        if (msg->priv->chunks) {
912                g_slist_append (msg->priv->last_chunk, chunk);
913                msg->priv->last_chunk = msg->priv->last_chunk->next;
914        } else {
915                msg->priv->chunks = msg->priv->last_chunk =
916                        g_slist_append (NULL, chunk);
917        }
918}
919
920/**
921 * soup_message_add_final_chunk:
922 * @msg: a #SoupMessage
923 *
924 * Adds a final, empty chunk of response data to @body. This must
925 * be called after adding the last real chunk, to indicate that
926 * there is no more data.
927 **/
928void
929soup_message_add_final_chunk (SoupMessage *msg)
930{
931        soup_message_add_chunk (msg, SOUP_BUFFER_STATIC, NULL, 0);
932}
933
934/**
935 * soup_message_pop_chunk:
936 * @msg: a #SoupMessage
937 *
938 * Pops a chunk of response data from @msg's chunk list. The caller
939 * must free @chunk itself, and must handle the data in @chunk
940 * according to its %ownership.
941 *
942 * Return value: the chunk, or %NULL if there are no chunks left.
943 **/
944SoupDataBuffer *
945soup_message_pop_chunk (SoupMessage *msg)
946{
947        SoupDataBuffer *chunk;
948
949        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
950
951        if (!msg->priv->chunks)
952                return NULL;
953
954        chunk = msg->priv->chunks->data;
955        msg->priv->chunks = g_slist_remove (msg->priv->chunks, chunk);
956        if (!msg->priv->chunks)
957                msg->priv->last_chunk = NULL;
958
959        return chunk;
960}
961
962static void
963free_chunks (SoupMessage *msg)
964{
965        SoupDataBuffer *chunk;
966        GSList *ch;
967
968        for (ch = msg->priv->chunks; ch; ch = ch->next) {
969                chunk = ch->data;
970
971                if (chunk->owner == SOUP_BUFFER_SYSTEM_OWNED)
972                        g_free (chunk->body);
973                g_free (chunk);
974        }
975
976        g_slist_free (msg->priv->chunks);
977        msg->priv->chunks = msg->priv->last_chunk = NULL;
978}
Note: See TracBrowser for help on using the repository browser.