Reapplying patch to disable attempts to use gtk-doc
[profile/ivi/libsoup2.4.git] / libsoup / soup-message-headers.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-message-headers.c: HTTP message header arrays
4  *
5  * Copyright (C) 2007, 2008 Red Hat, Inc.
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10
11 #include "soup-message-headers.h"
12 #include "soup-headers.h"
13 #include "soup-misc.h"
14
15 /**
16  * SECTION:soup-message-headers
17  * @short_description: HTTP message headers
18  * @see_also: #SoupMessage
19  *
20  * #SoupMessageHeaders represents the HTTP message headers associated
21  * with a request or response.
22  **/
23
24 /**
25  * SoupMessageHeaders:
26  *
27  * The HTTP message headers associated with a request or response.
28  */
29
30 /**
31  * SoupMessageHeadersType:
32  * @SOUP_MESSAGE_HEADERS_REQUEST: request headers
33  * @SOUP_MESSAGE_HEADERS_RESPONSE: response headers
34  * @SOUP_MESSAGE_HEADERS_MULTIPART: multipart body part headers
35  *
36  * Value passed to soup_message_headers_new() to set certain default
37  * behaviors.
38  **/
39
40 typedef void (*SoupHeaderSetter) (SoupMessageHeaders *, const char *);
41 static const char *intern_header_name (const char *name, SoupHeaderSetter *setter);
42 static void clear_special_headers (SoupMessageHeaders *hdrs);
43
44 typedef struct {
45         const char *name;
46         char *value;
47 } SoupHeader;
48
49 struct SoupMessageHeaders {
50         GArray *array;
51         GHashTable *concat;
52         SoupMessageHeadersType type;
53
54         SoupEncoding encoding;
55         goffset content_length;
56         SoupExpectation expectations;
57         char *content_type;
58
59         int ref_count;
60 };
61
62 /**
63  * soup_message_headers_new:
64  * @type: the type of headers
65  *
66  * Creates a #SoupMessageHeaders. (#SoupMessage does this
67  * automatically for its own headers. You would only need to use this
68  * method if you are manually parsing or generating message headers.)
69  *
70  * Return value: a new #SoupMessageHeaders
71  **/
72 SoupMessageHeaders *
73 soup_message_headers_new (SoupMessageHeadersType type)
74 {
75         SoupMessageHeaders *hdrs;
76
77         hdrs = g_slice_new0 (SoupMessageHeaders);
78         /* FIXME: is "5" a good default? */
79         hdrs->array = g_array_sized_new (TRUE, FALSE, sizeof (SoupHeader), 5);
80         hdrs->type = type;
81         hdrs->encoding = -1;
82         hdrs->ref_count = 1;
83
84         return hdrs;
85 }
86
87 static SoupMessageHeaders *
88 soup_message_headers_copy (SoupMessageHeaders *hdrs)
89 {
90         hdrs->ref_count++;
91         return hdrs;
92 }
93
94 /**
95  * soup_message_headers_free:
96  * @hdrs: a #SoupMessageHeaders
97  *
98  * Frees @hdrs.
99  **/
100 void
101 soup_message_headers_free (SoupMessageHeaders *hdrs)
102 {
103         if (--hdrs->ref_count == 0) {
104                 soup_message_headers_clear (hdrs);
105                 g_array_free (hdrs->array, TRUE);
106                 if (hdrs->concat)
107                         g_hash_table_destroy (hdrs->concat);
108                 g_slice_free (SoupMessageHeaders, hdrs);
109         }
110 }
111
112 GType
113 soup_message_headers_get_type (void)
114 {
115         static volatile gsize type_volatile = 0;
116
117         if (g_once_init_enter (&type_volatile)) {
118                 GType type = g_boxed_type_register_static (
119                         g_intern_static_string ("SoupMessageHeaders"),
120                         (GBoxedCopyFunc) soup_message_headers_copy,
121                         (GBoxedFreeFunc) soup_message_headers_free);
122                 g_once_init_leave (&type_volatile, type);
123         }
124         return type_volatile;
125 }
126
127 /**
128  * soup_message_headers_clear:
129  * @hdrs: a #SoupMessageHeaders
130  *
131  * Clears @hdrs.
132  **/
133 void
134 soup_message_headers_clear (SoupMessageHeaders *hdrs)
135 {
136         SoupHeader *hdr_array = (SoupHeader *)hdrs->array->data;
137         int i;
138
139         for (i = 0; i < hdrs->array->len; i++)
140                 g_free (hdr_array[i].value);
141         g_array_set_size (hdrs->array, 0);
142
143         if (hdrs->concat)
144                 g_hash_table_remove_all (hdrs->concat);
145
146         clear_special_headers (hdrs);
147 }
148
149 /**
150  * soup_message_headers_clean_connection_headers:
151  * @hdrs: a #SoupMessageHeaders
152  *
153  * Removes all the headers listed in the Connection header.
154  *
155  * Since: 2.36
156  */
157 void
158 soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs)
159 {
160         /* RFC 2616 14.10 */
161         const char *connection;
162         GSList *tokens, *t;
163
164         connection = soup_message_headers_get_list (hdrs, "Connection");
165         if (!connection)
166                 return;
167
168         tokens = soup_header_parse_list (connection);
169         for (t = tokens; t; t = t->next)
170                 soup_message_headers_remove (hdrs, t->data);
171         soup_header_free_list (tokens);
172 }
173
174 /**
175  * soup_message_headers_append:
176  * @hdrs: a #SoupMessageHeaders
177  * @name: the header name to add
178  * @value: the new value of @name
179  *
180  * Appends a new header with name @name and value @value to @hdrs. (If
181  * there is an existing header with name @name, then this creates a
182  * second one, which is only allowed for list-valued headers; see also
183  * soup_message_headers_replace().)
184  *
185  * The caller is expected to make sure that @name and @value are
186  * syntactically correct.
187  **/
188 void
189 soup_message_headers_append (SoupMessageHeaders *hdrs,
190                              const char *name, const char *value)
191 {
192         SoupHeader header;
193         SoupHeaderSetter setter;
194
195         g_return_if_fail (name != NULL);
196         g_return_if_fail (value != NULL);
197
198         /* Setting a syntactically invalid header name or value is
199          * considered to be a programming error. However, it can also
200          * be a security hole, so we want to fail here even if
201          * compiled with G_DISABLE_CHECKS.
202          */
203 #ifndef G_DISABLE_CHECKS
204         g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL);
205         g_return_if_fail (strpbrk (value, "\r\n") == NULL);
206 #else
207         if (*name && strpbrk (name, " \t\r\n:")) {
208                 g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name);
209                 return;
210         }
211         if (strpbrk (value, "\r\n")) {
212                 g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value);
213                 return;
214         }
215 #endif
216
217         header.name = intern_header_name (name, &setter);
218         header.value = g_strdup (value);
219         g_array_append_val (hdrs->array, header);
220         if (hdrs->concat)
221                 g_hash_table_remove (hdrs->concat, header.name);
222         if (setter)
223                 setter (hdrs, header.value);
224 }
225
226 /**
227  * soup_message_headers_replace:
228  * @hdrs: a #SoupMessageHeaders
229  * @name: the header name to replace
230  * @value: the new value of @name
231  *
232  * Replaces the value of the header @name in @hdrs with @value. (See
233  * also soup_message_headers_append().)
234  *
235  * The caller is expected to make sure that @name and @value are
236  * syntactically correct.
237  **/
238 void
239 soup_message_headers_replace (SoupMessageHeaders *hdrs,
240                               const char *name, const char *value)
241 {
242         soup_message_headers_remove (hdrs, name);
243         soup_message_headers_append (hdrs, name, value);
244 }
245
246 static int
247 find_header (SoupHeader *hdr_array, const char *interned_name, int nth)
248 {
249         int i;
250
251         for (i = 0; hdr_array[i].name; i++) {
252                 if (hdr_array[i].name == interned_name) {
253                         if (nth-- == 0)
254                                 return i;
255                 }
256         }
257         return -1;
258 }
259
260 static int
261 find_last_header (SoupHeader *hdr_array, guint length, const char *interned_name, int nth)
262 {
263         int i;
264
265         for (i = length; i >= 0; i--) {
266                 if (hdr_array[i].name == interned_name) {
267                         if (nth-- == 0)
268                                 return i;
269                 }
270         }
271         return -1;
272 }
273
274 /**
275  * soup_message_headers_remove:
276  * @hdrs: a #SoupMessageHeaders
277  * @name: the header name to remove
278  *
279  * Removes @name from @hdrs. If there are multiple values for @name,
280  * they are all removed.
281  **/
282 void
283 soup_message_headers_remove (SoupMessageHeaders *hdrs, const char *name)
284 {
285         SoupHeader *hdr_array = (SoupHeader *)(hdrs->array->data);
286         SoupHeaderSetter setter;
287         int index;
288
289         g_return_if_fail (name != NULL);
290
291         name = intern_header_name (name, &setter);
292         while ((index = find_header (hdr_array, name, 0)) != -1) {
293                 g_free (hdr_array[index].value);
294                 g_array_remove_index (hdrs->array, index);
295         }
296         if (hdrs->concat)
297                 g_hash_table_remove (hdrs->concat, name);
298         if (setter)
299                 setter (hdrs, NULL);
300 }
301
302 /**
303  * soup_message_headers_get_one:
304  * @hdrs: a #SoupMessageHeaders
305  * @name: header name
306  * 
307  * Gets the value of header @name in @hdrs. Use this for headers whose
308  * values are <emphasis>not</emphasis> comma-delimited lists, and
309  * which therefore can only appear at most once in the headers. For
310  * list-valued headers, use soup_message_headers_get_list().
311  *
312  * If @hdrs does erroneously contain multiple copies of the header, it
313  * is not defined which one will be returned. (Ideally, it will return
314  * whichever one makes libsoup most compatible with other HTTP
315  * implementations.)
316  *
317  * Return value: the header's value or %NULL if not found.
318  *
319  * Since: 2.26.1
320  **/
321 const char *
322 soup_message_headers_get_one (SoupMessageHeaders *hdrs, const char *name)
323 {
324         SoupHeader *hdr_array = (SoupHeader *)(hdrs->array->data);
325         guint hdr_length = hdrs->array->len;
326         int index;
327
328         g_return_val_if_fail (name != NULL, NULL);
329
330         name = intern_header_name (name, NULL);
331
332         index = find_last_header (hdr_array, hdr_length, name, 0);
333
334         return (index == -1) ? NULL : hdr_array[index].value;
335 }
336
337 /**
338  * soup_message_headers_get_list:
339  * @hdrs: a #SoupMessageHeaders
340  * @name: header name
341  * 
342  * Gets the value of header @name in @hdrs. Use this for headers whose
343  * values are comma-delimited lists, and which are therefore allowed
344  * to appear multiple times in the headers. For non-list-valued
345  * headers, use soup_message_headers_get_one().
346  *
347  * If @name appears multiple times in @hdrs,
348  * soup_message_headers_get_list() will concatenate all of the values
349  * together, separated by commas. This is sometimes awkward to parse
350  * (eg, WWW-Authenticate, Set-Cookie), but you have to be able to deal
351  * with it anyway, because the HTTP spec explicitly states that this
352  * transformation is allowed, and so an upstream proxy could do the
353  * same thing.
354  * 
355  * Return value: the header's value or %NULL if not found.
356  *
357  * Since: 2.26.1
358  **/
359 const char *
360 soup_message_headers_get_list (SoupMessageHeaders *hdrs, const char *name)
361 {
362         SoupHeader *hdr_array = (SoupHeader *)(hdrs->array->data);
363         GString *concat;
364         char *value;
365         int index, i;
366
367         g_return_val_if_fail (name != NULL, NULL);
368
369         name = intern_header_name (name, NULL);
370         if (hdrs->concat) {
371                 value = g_hash_table_lookup (hdrs->concat, name);
372                 if (value)
373                         return value;
374         }
375
376         index = find_header (hdr_array, name, 0);
377         if (index == -1)
378                 return NULL;
379         else if (find_header (hdr_array, name, 1) == -1)
380                 return hdr_array[index].value;
381
382         concat = g_string_new (NULL);
383         for (i = 0; (index = find_header (hdr_array, name, i)) != -1; i++) {
384                 if (i != 0)
385                         g_string_append (concat, ", ");
386                 g_string_append (concat, hdr_array[index].value);
387         }
388         value = g_string_free (concat, FALSE);
389
390         if (!hdrs->concat)
391                 hdrs->concat = g_hash_table_new_full (NULL, NULL, NULL, g_free);
392         g_hash_table_insert (hdrs->concat, (gpointer)name, value);
393         return value;
394 }
395
396 /**
397  * soup_message_headers_get:
398  * @hdrs: a #SoupMessageHeaders
399  * @name: header name
400  * 
401  * Gets the value of header @name in @hdrs.
402  *
403  * This method was supposed to work correctly for both single-valued
404  * and list-valued headers, but because some HTTP clients/servers
405  * mistakenly send multiple copies of headers that are supposed to be
406  * single-valued, it sometimes returns incorrect results. To fix this,
407  * the methods soup_message_headers_get_one() and
408  * soup_message_headers_get_list() were introduced, so callers can
409  * explicitly state which behavior they are expecting.
410  *
411  * Return value: as with soup_message_headers_get_list().
412  * 
413  * Deprecated: Use soup_message_headers_get_one() or
414  * soup_message_headers_get_list() instead.
415  **/
416 const char *
417 soup_message_headers_get (SoupMessageHeaders *hdrs, const char *name)
418 {
419         return soup_message_headers_get_list (hdrs, name);
420 }
421
422 /**
423  * SoupMessageHeadersIter:
424  *
425  * An opaque type used to iterate over a %SoupMessageHeaders
426  * structure.
427  *
428  * After intializing the iterator with
429  * soup_message_headers_iter_init(), call
430  * soup_message_headers_iter_next() to fetch data from it.
431  *
432  * You may not modify the headers while iterating over them.
433  **/
434
435 typedef struct {
436         SoupMessageHeaders *hdrs;
437         int index;
438 } SoupMessageHeadersIterReal;
439
440 /**
441  * soup_message_headers_iter_init:
442  * @iter: (out) (transfer none): a pointer to a %SoupMessageHeadersIter
443  * structure
444  * @hdrs: a %SoupMessageHeaders
445  *
446  * Initializes @iter for iterating @hdrs.
447  **/
448 void
449 soup_message_headers_iter_init (SoupMessageHeadersIter *iter,
450                                 SoupMessageHeaders *hdrs)
451 {
452         SoupMessageHeadersIterReal *real = (SoupMessageHeadersIterReal *)iter;
453
454         real->hdrs = hdrs;
455         real->index = 0;
456 }
457
458 /**
459  * soup_message_headers_iter_next:
460  * @iter: (inout) (transfer none): a %SoupMessageHeadersIter
461  * @name: (out) (transfer none): pointer to a variable to return
462  * the header name in
463  * @value: (out) (transfer none): pointer to a variable to return
464  * the header value in
465  *
466  * Yields the next name/value pair in the %SoupMessageHeaders being
467  * iterated by @iter. If @iter has already yielded the last header,
468  * then soup_message_headers_iter_next() will return %FALSE and @name
469  * and @value will be unchanged.
470  *
471  * Return value: %TRUE if another name and value were returned, %FALSE
472  * if the end of the headers has been reached.
473  **/
474 gboolean
475 soup_message_headers_iter_next (SoupMessageHeadersIter *iter,
476                                 const char **name, const char **value)
477 {
478         SoupMessageHeadersIterReal *real = (SoupMessageHeadersIterReal *)iter;
479         SoupHeader *hdr_array = (SoupHeader *)real->hdrs->array->data;
480
481         if (real->index >= real->hdrs->array->len)
482                 return FALSE;
483
484         *name = hdr_array[real->index].name;
485         *value = hdr_array[real->index].value;
486         real->index++;
487         return TRUE;
488 }
489
490 /**
491  * SoupMessageHeadersForeachFunc:
492  * @name: the header name
493  * @value: the header value
494  * @user_data: the data passed to soup_message_headers_foreach()
495  *
496  * The callback passed to soup_message_headers_foreach().
497  **/
498
499 /**
500  * soup_message_headers_foreach:
501  * @hdrs: a #SoupMessageHeaders
502  * @func: (scope call): callback function to run for each header
503  * @user_data: data to pass to @func
504  * 
505  * Calls @func once for each header value in @hdrs.
506  *
507  * Beware that unlike soup_message_headers_get(), this processes the
508  * headers in exactly the way they were added, rather than
509  * concatenating multiple same-named headers into a single value.
510  * (This is intentional; it ensures that if you call
511  * soup_message_headers_append() multiple times with the same name,
512  * then the I/O code will output multiple copies of the header when
513  * sending the message to the remote implementation, which may be
514  * required for interoperability in some cases.)
515  *
516  * You may not modify the headers from @func.
517  **/
518 void
519 soup_message_headers_foreach (SoupMessageHeaders *hdrs,
520                               SoupMessageHeadersForeachFunc func,
521                               gpointer            user_data)
522 {
523         SoupHeader *hdr_array = (SoupHeader *)hdrs->array->data;
524         int i;
525
526         for (i = 0; i < hdrs->array->len; i++)
527                 func (hdr_array[i].name, hdr_array[i].value, user_data);
528 }
529
530
531 G_LOCK_DEFINE_STATIC (header_pool);
532 static GHashTable *header_pool, *header_setters;
533
534 static void transfer_encoding_setter (SoupMessageHeaders *, const char *);
535 static void content_length_setter (SoupMessageHeaders *, const char *);
536 static void expectation_setter (SoupMessageHeaders *, const char *);
537 static void content_type_setter (SoupMessageHeaders *, const char *);
538
539 static char *
540 intern_header_locked (const char *name)
541 {
542         char *interned;
543
544         interned = g_hash_table_lookup (header_pool, name);
545         if (!interned) {
546                 char *dup = g_strdup (name);
547                 g_hash_table_insert (header_pool, dup, dup);
548                 interned = dup;
549         }
550         return interned;
551 }
552
553 static const char *
554 intern_header_name (const char *name, SoupHeaderSetter *setter)
555 {
556         const char *interned;
557
558         G_LOCK (header_pool);
559
560         if (!header_pool) {
561                 header_pool = g_hash_table_new (soup_str_case_hash, soup_str_case_equal);
562                 header_setters = g_hash_table_new (NULL, NULL);
563                 g_hash_table_insert (header_setters,
564                                      intern_header_locked ("Transfer-Encoding"),
565                                      transfer_encoding_setter);
566                 g_hash_table_insert (header_setters,
567                                      intern_header_locked ("Content-Length"),
568                                      content_length_setter);
569                 g_hash_table_insert (header_setters,
570                                      intern_header_locked ("Expect"),
571                                      expectation_setter);
572                 g_hash_table_insert (header_setters,
573                                      intern_header_locked ("Content-Type"),
574                                      content_type_setter);
575         }
576
577         interned = intern_header_locked (name);
578         if (setter)
579                 *setter = g_hash_table_lookup (header_setters, interned);
580
581         G_UNLOCK (header_pool);
582         return interned;
583 }
584
585 static void
586 clear_special_headers (SoupMessageHeaders *hdrs)
587 {
588         SoupHeaderSetter setter;
589         GHashTableIter iter;
590         gpointer key, value;
591
592         /* Make sure header_setters has been initialized */
593         intern_header_name ("", NULL);
594
595         g_hash_table_iter_init (&iter, header_setters);
596         while (g_hash_table_iter_next (&iter, &key, &value)) {
597                 setter = value;
598                 setter (hdrs, NULL);
599         }
600 }
601
602 /* Specific headers */
603
604 static void
605 transfer_encoding_setter (SoupMessageHeaders *hdrs, const char *value)
606 {
607         if (value) {
608                 if (g_ascii_strcasecmp (value, "chunked") == 0)
609                         hdrs->encoding = SOUP_ENCODING_CHUNKED;
610                 else
611                         hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
612         } else
613                 hdrs->encoding = -1;
614 }
615
616 static void
617 content_length_setter (SoupMessageHeaders *hdrs, const char *value)
618 {
619         /* Transfer-Encoding trumps Content-Length */
620         if (hdrs->encoding == SOUP_ENCODING_CHUNKED)
621                 return;
622
623         if (value) {
624                 char *end;
625
626                 hdrs->content_length = g_ascii_strtoull (value, &end, 10);
627                 if (*end)
628                         hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
629                 else
630                         hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
631         } else
632                 hdrs->encoding = -1;
633 }
634
635 /**
636  * SoupEncoding:
637  * @SOUP_ENCODING_UNRECOGNIZED: unknown / error
638  * @SOUP_ENCODING_NONE: no body is present (which is not the same as a
639  * 0-length body, and only occurs in certain places)
640  * @SOUP_ENCODING_CONTENT_LENGTH: Content-Length encoding
641  * @SOUP_ENCODING_EOF: Response body ends when the connection is closed
642  * @SOUP_ENCODING_CHUNKED: chunked encoding (currently only supported
643  * for response)
644  * @SOUP_ENCODING_BYTERANGES: multipart/byteranges (Reserved for future
645  * use: NOT CURRENTLY IMPLEMENTED)
646  *
647  * How a message body is encoded for transport
648  **/
649
650 /**
651  * soup_message_headers_get_encoding:
652  * @hdrs: a #SoupMessageHeaders
653  *
654  * Gets the message body encoding that @hdrs declare. This may not
655  * always correspond to the encoding used on the wire; eg, a HEAD
656  * response may declare a Content-Length or Transfer-Encoding, but
657  * it will never actually include a body.
658  *
659  * Return value: the encoding declared by @hdrs.
660  **/
661 SoupEncoding
662 soup_message_headers_get_encoding (SoupMessageHeaders *hdrs)
663 {
664         const char *header;
665
666         if (hdrs->encoding != -1)
667                 return hdrs->encoding;
668
669         /* If Transfer-Encoding was set, hdrs->encoding would already
670          * be set. So we don't need to check that possibility.
671          */
672         header = soup_message_headers_get_one (hdrs, "Content-Length");
673         if (header) {
674                 content_length_setter (hdrs, header);
675                 if (hdrs->encoding != -1)
676                         return hdrs->encoding;
677         }
678
679         /* Per RFC 2616 4.4, a response body that doesn't indicate its
680          * encoding otherwise is terminated by connection close, and a
681          * request that doesn't indicate otherwise has no body. Note
682          * that SoupMessage calls soup_message_headers_set_encoding()
683          * to override the response body default for our own
684          * server-side messages.
685          */
686         hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
687                 SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
688         return hdrs->encoding;
689 }
690
691 /**
692  * soup_message_headers_set_encoding:
693  * @hdrs: a #SoupMessageHeaders
694  * @encoding: a #SoupEncoding
695  *
696  * Sets the message body encoding that @hdrs will declare. In particular,
697  * you should use this if you are going to send a request or response in
698  * chunked encoding.
699  **/
700 void
701 soup_message_headers_set_encoding (SoupMessageHeaders *hdrs,
702                                    SoupEncoding        encoding)
703 {
704         if (encoding == hdrs->encoding)
705                 return;
706
707         switch (encoding) {
708         case SOUP_ENCODING_NONE:
709         case SOUP_ENCODING_EOF:
710                 soup_message_headers_remove (hdrs, "Transfer-Encoding");
711                 soup_message_headers_remove (hdrs, "Content-Length");
712                 break;
713
714         case SOUP_ENCODING_CONTENT_LENGTH:
715                 soup_message_headers_remove (hdrs, "Transfer-Encoding");
716                 break;
717
718         case SOUP_ENCODING_CHUNKED:
719                 soup_message_headers_remove (hdrs, "Content-Length");
720                 soup_message_headers_replace (hdrs, "Transfer-Encoding", "chunked");
721                 break;
722
723         default:
724                 g_return_if_reached ();
725         }
726
727         hdrs->encoding = encoding;
728 }
729
730 /**
731  * soup_message_headers_get_content_length:
732  * @hdrs: a #SoupMessageHeaders
733  *
734  * Gets the message body length that @hdrs declare. This will only
735  * be non-0 if soup_message_headers_get_encoding() returns
736  * %SOUP_ENCODING_CONTENT_LENGTH.
737  *
738  * Return value: the message body length declared by @hdrs.
739  **/
740 goffset
741 soup_message_headers_get_content_length (SoupMessageHeaders *hdrs)
742 {
743         return (hdrs->encoding == SOUP_ENCODING_CONTENT_LENGTH) ?
744                 hdrs->content_length : 0;
745 }
746
747 /**
748  * soup_message_headers_set_content_length:
749  * @hdrs: a #SoupMessageHeaders
750  * @content_length: the message body length
751  *
752  * Sets the message body length that @hdrs will declare, and sets
753  * @hdrs's encoding to %SOUP_ENCODING_CONTENT_LENGTH.
754  *
755  * You do not normally need to call this; if @hdrs is set to use
756  * Content-Length encoding, libsoup will automatically set its
757  * Content-Length header for you immediately before sending the
758  * headers. One situation in which this method is useful is when
759  * generating the response to a HEAD request; Calling
760  * soup_message_headers_set_content_length() allows you to put the
761  * correct content length into the response without needing to waste
762  * memory by filling in a response body which won't actually be sent.
763  **/
764 void
765 soup_message_headers_set_content_length (SoupMessageHeaders *hdrs,
766                                          goffset             content_length)
767 {
768         char length[128];
769
770         snprintf (length, sizeof (length), "%" G_GUINT64_FORMAT,
771                   content_length);
772         soup_message_headers_remove (hdrs, "Transfer-Encoding");
773         soup_message_headers_replace (hdrs, "Content-Length", length);
774 }
775
776 static void
777 expectation_setter (SoupMessageHeaders *hdrs, const char *value)
778 {
779         if (value) {
780                 if (!g_ascii_strcasecmp (value, "100-continue"))
781                         hdrs->expectations = SOUP_EXPECTATION_CONTINUE;
782                 else
783                         hdrs->expectations = SOUP_EXPECTATION_UNRECOGNIZED;
784         } else
785                 hdrs->expectations = 0;
786 }
787
788 /**
789  * SoupExpectation:
790  * @SOUP_EXPECTATION_CONTINUE: "100-continue"
791  * @SOUP_EXPECTATION_UNRECOGNIZED: any unrecognized expectation
792  *
793  * Represents the parsed value of the "Expect" header.
794  **/
795
796 /**
797  * soup_message_headers_get_expectations:
798  * @hdrs: a #SoupMessageHeaders
799  *
800  * Gets the expectations declared by @hdrs's "Expect" header.
801  * Currently this will either be %SOUP_EXPECTATION_CONTINUE or
802  * %SOUP_EXPECTATION_UNRECOGNIZED.
803  *
804  * Return value: the contents of @hdrs's "Expect" header
805  **/
806 SoupExpectation
807 soup_message_headers_get_expectations (SoupMessageHeaders *hdrs)
808 {
809         return hdrs->expectations;
810 }
811
812 /**
813  * soup_message_headers_set_expectations:
814  * @hdrs: a #SoupMessageHeaders
815  * @expectations: the expectations to set
816  *
817  * Sets @hdrs's "Expect" header according to @expectations.
818  *
819  * Currently %SOUP_EXPECTATION_CONTINUE is the only known expectation
820  * value. You should set this value on a request if you are sending a
821  * large message body (eg, via POST or PUT), and want to give the
822  * server a chance to reject the request after seeing just the headers
823  * (eg, because it will require authentication before allowing you to
824  * post, or because you're POSTing to a URL that doesn't exist). This
825  * saves you from having to transmit the large request body when the
826  * server is just going to ignore it anyway.
827  **/
828 void
829 soup_message_headers_set_expectations (SoupMessageHeaders *hdrs,
830                                        SoupExpectation     expectations)
831 {
832         g_return_if_fail ((expectations & ~SOUP_EXPECTATION_CONTINUE) == 0);
833
834         if (expectations & SOUP_EXPECTATION_CONTINUE)
835                 soup_message_headers_replace (hdrs, "Expect", "100-continue");
836         else
837                 soup_message_headers_remove (hdrs, "Expect");
838 }
839
840 /**
841  * SoupRange:
842  * @start: the start of the range
843  * @end: the end of the range
844  *
845  * Represents a byte range as used in the Range header.
846  *
847  * If @end is non-negative, then @start and @end represent the bounds
848  * of of the range, counting from 0. (Eg, the first 500 bytes would be
849  * represented as @start = 0 and @end = 499.)
850  *
851  * If @end is -1 and @start is non-negative, then this represents a
852  * range starting at @start and ending with the last byte of the
853  * requested resource body. (Eg, all but the first 500 bytes would be
854  * @start = 500, and @end = -1.)
855  *
856  * If @end is -1 and @start is negative, then it represents a "suffix
857  * range", referring to the last -@start bytes of the resource body.
858  * (Eg, the last 500 bytes would be @start = -500 and @end = -1.)
859  *
860  * Since: 2.26
861  **/
862
863 static int
864 sort_ranges (gconstpointer a, gconstpointer b)
865 {
866         SoupRange *ra = (SoupRange *)a;
867         SoupRange *rb = (SoupRange *)b;
868
869         return ra->start - rb->start;
870 }
871
872 /**
873  * soup_message_headers_get_ranges:
874  * @hdrs: a #SoupMessageHeaders
875  * @total_length: the total_length of the response body
876  * @ranges: (out): return location for an array of #SoupRange
877  * @length: the length of the returned array
878  *
879  * Parses @hdrs's Range header and returns an array of the requested
880  * byte ranges. The returned array must be freed with
881  * soup_message_headers_free_ranges().
882  *
883  * If @total_length is non-0, its value will be used to adjust the
884  * returned ranges to have explicit start and end values, and the
885  * returned ranges will be sorted and non-overlapping. If
886  * @total_length is 0, then some ranges may have an end value of -1,
887  * as described under #SoupRange, and some of the ranges may be
888  * redundant.
889  *
890  * Return value: %TRUE if @hdrs contained a "Range" header containing
891  * byte ranges which could be parsed, %FALSE otherwise (in which case
892  * @range and @length will not be set).
893  *
894  * Since: 2.26
895  **/
896 gboolean
897 soup_message_headers_get_ranges (SoupMessageHeaders  *hdrs,
898                                  goffset              total_length,
899                                  SoupRange          **ranges,
900                                  int                 *length)
901 {
902         const char *range = soup_message_headers_get_one (hdrs, "Range");
903         GSList *range_list, *r;
904         GArray *array;
905         char *spec, *end;
906         int i;
907
908         if (!range || strncmp (range, "bytes", 5) != 0)
909                 return FALSE;
910
911         range += 5;
912         while (g_ascii_isspace (*range))
913                 range++;
914         if (*range++ != '=')
915                 return FALSE;
916         while (g_ascii_isspace (*range))
917                 range++;
918
919         range_list = soup_header_parse_list (range);
920         if (!range_list)
921                 return FALSE;
922
923         array = g_array_new (FALSE, FALSE, sizeof (SoupRange));
924         for (r = range_list; r; r = r->next) {
925                 SoupRange cur;
926
927                 spec = r->data;
928                 if (*spec == '-') {
929                         cur.start = g_ascii_strtoll (spec, &end, 10) + total_length;
930                         cur.end = total_length - 1;
931                 } else {
932                         cur.start = g_ascii_strtoull (spec, &end, 10);
933                         if (*end == '-')
934                                 end++;
935                         if (*end)
936                                 cur.end = g_ascii_strtoull (end, &end, 10);
937                         else
938                                 cur.end = total_length - 1;
939                 }
940                 if (*end) {
941                         g_array_free (array, TRUE);
942                         soup_header_free_list (range_list);
943                         return FALSE;
944                 }
945
946                 g_array_append_val (array, cur);
947         }
948
949         soup_header_free_list (range_list);
950
951         if (total_length) {
952                 g_array_sort (array, sort_ranges);
953                 for (i = 1; i < array->len; i++) {
954                         SoupRange *cur = &((SoupRange *)array->data)[i];
955                         SoupRange *prev = &((SoupRange *)array->data)[i - 1];
956
957                         if (cur->start <= prev->end) {
958                                 prev->end = MAX (prev->end, cur->end);
959                                 g_array_remove_index (array, i);
960                         }
961                 }
962         }
963
964         *ranges = (SoupRange *)array->data;
965         *length = array->len;
966
967         g_array_free (array, FALSE);
968         return TRUE;
969 }
970
971 /**
972  * soup_message_headers_free_ranges:
973  * @hdrs: a #SoupMessageHeaders
974  * @ranges: an array of #SoupRange
975  *
976  * Frees the array of ranges returned from soup_message_headers_get_ranges().
977  *
978  * Since: 2.26
979  **/
980 void
981 soup_message_headers_free_ranges (SoupMessageHeaders  *hdrs,
982                                   SoupRange           *ranges)
983 {
984         g_free (ranges);
985 }
986
987 /**
988  * soup_message_headers_set_ranges:
989  * @hdrs: a #SoupMessageHeaders
990  * @ranges: an array of #SoupRange
991  * @length: the length of @range
992  *
993  * Sets @hdrs's Range header to request the indicated ranges. (If you
994  * only want to request a single range, you can use
995  * soup_message_headers_set_range().)
996  *
997  * Since: 2.26
998  **/
999 void
1000 soup_message_headers_set_ranges (SoupMessageHeaders  *hdrs,
1001                                  SoupRange           *ranges,
1002                                  int                  length)
1003 {
1004         GString *header;
1005         int i;
1006
1007         header = g_string_new ("bytes=");
1008         for (i = 0; i < length; i++) {
1009                 if (i > 0)
1010                         g_string_append_c (header, ',');
1011                 if (ranges[i].end >= 0) {
1012                         g_string_append_printf (header, "%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT,
1013                                                 ranges[i].start, ranges[i].end);
1014                 } else if (ranges[i].start >= 0) {
1015                         g_string_append_printf (header,"%" G_GINT64_FORMAT "-",
1016                                                 ranges[i].start);
1017                 } else {
1018                         g_string_append_printf (header, "%" G_GINT64_FORMAT,
1019                                                 ranges[i].start);
1020                 }
1021         }
1022
1023         soup_message_headers_replace (hdrs, "Range", header->str);
1024         g_string_free (header, TRUE);
1025 }
1026
1027 /**
1028  * soup_message_headers_set_range:
1029  * @hdrs: a #SoupMessageHeaders
1030  * @start: the start of the range to request
1031  * @end: the end of the range to request
1032  *
1033  * Sets @hdrs's Range header to request the indicated range.
1034  * @start and @end are interpreted as in a #SoupRange.
1035  *
1036  * If you need to request multiple ranges, use
1037  * soup_message_headers_set_ranges().
1038  *
1039  * Since: 2.26
1040  **/
1041 void
1042 soup_message_headers_set_range (SoupMessageHeaders  *hdrs,
1043                                 goffset              start,
1044                                 goffset              end)
1045 {
1046         SoupRange range;
1047
1048         range.start = start;
1049         range.end = end;
1050         soup_message_headers_set_ranges (hdrs, &range, 1);
1051 }
1052
1053 /**
1054  * soup_message_headers_get_content_range:
1055  * @hdrs: a #SoupMessageHeaders
1056  * @start: return value for the start of the range
1057  * @end: return value for the end of the range
1058  * @total_length: return value for the total length of the resource,
1059  * or %NULL if you don't care.
1060  *
1061  * Parses @hdrs's Content-Range header and returns it in @start,
1062  * @end, and @total_length. If the total length field in the header
1063  * was specified as "*", then @total_length will be set to -1.
1064  *
1065  * Return value: %TRUE if @hdrs contained a "Content-Range" header
1066  * containing a byte range which could be parsed, %FALSE otherwise.
1067  *
1068  * Since: 2.26
1069  **/
1070 gboolean
1071 soup_message_headers_get_content_range (SoupMessageHeaders  *hdrs,
1072                                         goffset             *start,
1073                                         goffset             *end,
1074                                         goffset             *total_length)
1075 {
1076         const char *header = soup_message_headers_get_one (hdrs, "Content-Range");
1077         goffset length;
1078         char *p;
1079
1080         if (!header || strncmp (header, "bytes ", 6) != 0)
1081                 return FALSE;
1082
1083         header += 6;
1084         while (g_ascii_isspace (*header))
1085                 header++;
1086         if (!g_ascii_isdigit (*header))
1087                 return FALSE;
1088
1089         *start = g_ascii_strtoull (header, &p, 10);
1090         if (*p != '-')
1091                 return FALSE;
1092         *end = g_ascii_strtoull (p + 1, &p, 10);
1093         if (*p != '/')
1094                 return FALSE;
1095         p++;
1096         if (*p == '*') {
1097                 length = -1;
1098                 p++;
1099         } else
1100                 length = g_ascii_strtoull (p, &p, 10);
1101
1102         if (total_length)
1103                 *total_length = length;
1104         return *p == '\0';
1105 }
1106
1107 /**
1108  * soup_message_headers_set_content_range:
1109  * @hdrs: a #SoupMessageHeaders
1110  * @start: the start of the range
1111  * @end: the end of the range
1112  * @total_length: the total length of the resource, or -1 if unknown
1113  *
1114  * Sets @hdrs's Content-Range header according to the given values.
1115  * (Note that @total_length is the total length of the entire resource
1116  * that this is a range of, not simply @end - @start + 1.)
1117  *
1118  * Since: 2.26
1119  **/
1120 void
1121 soup_message_headers_set_content_range (SoupMessageHeaders  *hdrs,
1122                                         goffset              start,
1123                                         goffset              end,
1124                                         goffset              total_length)
1125 {
1126         char *header;
1127
1128         if (total_length >= 0) {
1129                 header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%"
1130                                           G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
1131                                           start, end, total_length);
1132         } else {
1133                 header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%"
1134                                           G_GINT64_FORMAT "/*", start, end);
1135         }
1136         soup_message_headers_replace (hdrs, "Content-Range", header);
1137         g_free (header);
1138 }
1139
1140 static gboolean
1141 parse_content_foo (SoupMessageHeaders *hdrs, const char *header_name,
1142                    char **foo, GHashTable **params)
1143 {
1144         const char *header;
1145         char *semi;
1146
1147         header = soup_message_headers_get_one (hdrs, header_name);
1148         if (!header)
1149                 return FALSE;
1150
1151         if (foo) {
1152                 *foo = g_strdup (header);
1153                 semi = strchr (*foo, ';');
1154                 if (semi) {
1155                         char *p = semi;
1156
1157                         *semi++ = '\0';
1158                         while (p - 1 > *foo && g_ascii_isspace(p[-1]))
1159                                 *(--p) = '\0';
1160                 }
1161         } else {
1162                 semi = strchr (header, ';');
1163                 if (semi)
1164                         semi++;
1165         }
1166
1167         if (!params)
1168                 return TRUE;
1169
1170         if (!semi) {
1171                 *params = soup_header_parse_semi_param_list ("");
1172                 return TRUE;
1173         }
1174
1175         *params = soup_header_parse_semi_param_list (semi);
1176         return TRUE;
1177 }
1178
1179 static void
1180 set_content_foo (SoupMessageHeaders *hdrs, const char *header_name,
1181                  const char *foo, GHashTable *params)
1182 {
1183         GString *str;
1184         GHashTableIter iter;
1185         gpointer key, value;
1186
1187         str = g_string_new (foo);
1188         if (params) {
1189                 g_hash_table_iter_init (&iter, params);
1190                 while (g_hash_table_iter_next (&iter, &key, &value)) {
1191                         g_string_append (str, "; ");
1192                         soup_header_g_string_append_param (str, key, value);
1193                 }
1194         }
1195
1196         soup_message_headers_replace (hdrs, header_name, str->str);
1197         g_string_free (str, TRUE);
1198 }
1199
1200 static void
1201 content_type_setter (SoupMessageHeaders *hdrs, const char *value)
1202 {
1203         g_free (hdrs->content_type);
1204         if (value) {
1205                 char *content_type, *p;
1206
1207                 parse_content_foo (hdrs, "Content-Type", &content_type, NULL);
1208                 p = strpbrk (content_type, " /");
1209                 if (!p || *p != '/' || strpbrk (p + 1, " /")) {
1210                         g_free (content_type);
1211                         hdrs->content_type = NULL;
1212                 } else
1213                         hdrs->content_type = content_type;
1214         } else
1215                 hdrs->content_type = NULL;
1216 }
1217
1218 /**
1219  * soup_message_headers_get_content_type:
1220  * @hdrs: a #SoupMessageHeaders
1221  * @params: (out) (allow-none) (transfer full): return location for
1222  * the Content-Type parameters (eg, "charset"), or %NULL
1223  *
1224  * Looks up the "Content-Type" header in @hdrs, parses it, and returns
1225  * its value in *@content_type and *@params. @params can be %NULL if you
1226  * are only interested in the content type itself.
1227  *
1228  * Return value: a string with the value of the "Content-Type" header
1229  * or NULL if @hdrs does not contain that header or it cannot be
1230  * parsed (in which case *@params will be unchanged).
1231  *
1232  * Since: 2.26
1233  **/
1234 const char *
1235 soup_message_headers_get_content_type (SoupMessageHeaders  *hdrs,
1236                                        GHashTable         **params)
1237 {
1238         if (!hdrs->content_type)
1239                 return NULL;
1240
1241         if (params)
1242                 parse_content_foo (hdrs, "Content-Type", NULL, params);
1243         return hdrs->content_type;
1244 }
1245
1246 /**
1247  * soup_message_headers_set_content_type:
1248  * @hdrs: a #SoupMessageHeaders
1249  * @content_type: the MIME type
1250  * @params: (allow-none) (element-type utf8 utf8): additional
1251  * parameters, or %NULL
1252  *
1253  * Sets the "Content-Type" header in @hdrs to @content_type,
1254  * optionally with additional parameters specified in @params.
1255  *
1256  * Since: 2.26
1257  **/
1258 void
1259 soup_message_headers_set_content_type (SoupMessageHeaders  *hdrs,
1260                                        const char          *content_type,
1261                                        GHashTable          *params)
1262 {
1263         set_content_foo (hdrs, "Content-Type", content_type, params);
1264 }
1265
1266 /**
1267  * soup_message_headers_get_content_disposition:
1268  * @hdrs: a #SoupMessageHeaders
1269  * @disposition: (out) (transfer full): return location for the
1270  * disposition-type, or %NULL
1271  * @params: (out) (transfer full) (element-type utf8 utf8): return
1272  * location for the Content-Disposition parameters, or %NULL
1273  *
1274  * Looks up the "Content-Disposition" header in @hdrs, parses it, and
1275  * returns its value in *@disposition and *@params. @params can be
1276  * %NULL if you are only interested in the disposition-type.
1277  *
1278  * In HTTP, the most common use of this header is to set a
1279  * disposition-type of "attachment", to suggest to the browser that a
1280  * response should be saved to disk rather than displayed in the
1281  * browser. If @params contains a "filename" parameter, this is a
1282  * suggestion of a filename to use. (If the parameter value in the
1283  * header contains an absolute or relative path, libsoup will truncate
1284  * it down to just the final path component, so you do not need to
1285  * test this yourself.)
1286  *
1287  * Content-Disposition is also used in "multipart/form-data", however
1288  * this is handled automatically by #SoupMultipart and the associated
1289  * form methods.
1290  *
1291  * Return value: %TRUE if @hdrs contains a "Content-Disposition"
1292  * header, %FALSE if not (in which case *@disposition and *@params
1293  * will be unchanged).
1294  *
1295  * Since: 2.26
1296  **/
1297 gboolean
1298 soup_message_headers_get_content_disposition (SoupMessageHeaders  *hdrs,
1299                                               char               **disposition,
1300                                               GHashTable         **params)
1301 {
1302         gpointer orig_key, orig_value;
1303
1304         if (!parse_content_foo (hdrs, "Content-Disposition",
1305                                 disposition, params))
1306                 return FALSE;
1307
1308         /* If there is a filename parameter, make sure it contains
1309          * only a single path component
1310          */
1311         if (params && g_hash_table_lookup_extended (*params, "filename",
1312                                                     &orig_key, &orig_value)) {
1313                 char *filename = strrchr (orig_value, '/');
1314
1315                 if (filename)
1316                         g_hash_table_insert (*params, orig_key, filename + 1);
1317         }
1318         return TRUE;
1319 }
1320
1321 /**
1322  * soup_message_headers_set_content_disposition:
1323  * @hdrs: a #SoupMessageHeaders
1324  * @disposition: the disposition-type
1325  * @params: (allow-none) (element-type utf8 utf8): additional
1326  * parameters, or %NULL
1327  *
1328  * Sets the "Content-Disposition" header in @hdrs to @disposition,
1329  * optionally with additional parameters specified in @params.
1330  *
1331  * See soup_message_headers_get_content_disposition() for a discussion
1332  * of how Content-Disposition is used in HTTP.
1333  *
1334  * Since: 2.26
1335  **/
1336 void
1337 soup_message_headers_set_content_disposition (SoupMessageHeaders  *hdrs,
1338                                               const char          *disposition,
1339                                               GHashTable          *params)
1340 {
1341         set_content_foo (hdrs, "Content-Disposition", disposition, params);
1342 }
1343