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