653
662
soup_message_headers_remove (hdrs, "Expect");
667
* @start: the start of the range
668
* @end: the end of the range
670
* Represents a byte range as used in the Range header.
672
* If @end is non-negative, then @start and @end represent the bounds
673
* of of the range, counting from %0. (Eg, the first 500 bytes would be
674
* represented as @start = %0 and @end = %499.)
676
* If @end is %-1 and @start is non-negative, then this represents a
677
* range starting at @start and ending with the last byte of the
678
* requested resource body. (Eg, all but the first 500 bytes would be
679
* @start = %500, and @end = %-1.)
681
* If @end is %-1 and @start is negative, then it represents a "suffix
682
* range", referring to the last -@start bytes of the resource body.
683
* (Eg, the last 500 bytes would be @start = %-500 and @end = %-1.)
687
sort_ranges (gconstpointer a, gconstpointer b)
689
SoupRange *ra = (SoupRange *)a;
690
SoupRange *rb = (SoupRange *)b;
692
return ra->start - rb->start;
696
* soup_message_headers_get_ranges:
697
* @hdrs: a #SoupMessageHeaders
698
* @total_length: the total_length of the response body
699
* @ranges: return location for an array of #SoupRange
700
* @length: the length of the returned array
702
* Parses @hdrs's Range header and returns an array of the requested
703
* byte ranges. The returned array must be freed with
704
* soup_message_headers_free_ranges().
706
* If @total_length is non-0, its value will be used to adjust the
707
* returned ranges to have explicit start and end values, and the
708
* returned ranges will be sorted and non-overlapping. If
709
* @total_length is 0, then some ranges may have an end value of -1,
710
* as described under #SoupRange, and some of the ranges may be
713
* Return value: %TRUE if @hdrs contained a "Range" header containing
714
* byte ranges which could be parsed, %FALSE otherwise (in which case
715
* @range and @length will not be set).
718
soup_message_headers_get_ranges (SoupMessageHeaders *hdrs,
719
goffset total_length,
723
const char *range = soup_message_headers_get (hdrs, "Range");
724
GSList *range_list, *r;
729
if (!range || strncmp (range, "bytes", 5) != 0)
733
while (g_ascii_isspace (*range))
737
while (g_ascii_isspace (*range))
740
range_list = soup_header_parse_list (range);
744
array = g_array_new (FALSE, FALSE, sizeof (SoupRange));
745
for (r = range_list; r; r = r->next) {
750
cur.start = g_ascii_strtoll (spec, &end, 10) + total_length;
751
cur.end = total_length - 1;
753
cur.start = g_ascii_strtoull (spec, &end, 10);
757
cur.end = g_ascii_strtoull (end, &end, 10);
759
cur.end = total_length - 1;
762
g_array_free (array, TRUE);
763
soup_header_free_list (range_list);
767
g_array_append_val (array, cur);
770
soup_header_free_list (range_list);
773
g_array_sort (array, sort_ranges);
774
for (i = 1; i < array->len; i++) {
775
SoupRange *cur = &((SoupRange *)array->data)[i];
776
SoupRange *prev = &((SoupRange *)array->data)[i - 1];
778
if (cur->start <= prev->end) {
779
prev->end = MAX (prev->end, cur->end);
780
g_array_remove_index (array, i);
785
*ranges = (SoupRange *)array->data;
786
*length = array->len;
788
g_array_free (array, FALSE);
793
* soup_message_headers_free_ranges:
794
* @hdrs: a #SoupMessageHeaders
795
* @ranges: an array of #SoupRange
797
* Frees the array of ranges returned from soup_message_headers_get_ranges().
800
soup_message_headers_free_ranges (SoupMessageHeaders *hdrs,
807
* soup_message_headers_set_ranges:
808
* @hdrs: a #SoupMessageHeaders
809
* @ranges: an array of #SoupRange
810
* @length: the length of @range
812
* Sets @hdrs's Range header to request the indicated ranges. (If you
813
* only want to request a single range, you can use
814
* soup_message_headers_set_range().)
817
soup_message_headers_set_ranges (SoupMessageHeaders *hdrs,
824
header = g_string_new ("bytes=");
825
for (i = 0; i < length; i++) {
827
g_string_append_c (header, ',');
828
if (ranges[i].end >= 0) {
829
g_string_append_printf (header, "%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT,
830
ranges[i].start, ranges[i].end);
831
} else if (ranges[i].start >= 0) {
832
g_string_append_printf (header,"%" G_GINT64_FORMAT "-",
835
g_string_append_printf (header, "%" G_GINT64_FORMAT,
840
soup_message_headers_replace (hdrs, "Range", header->str);
841
g_string_free (header, TRUE);
845
* soup_message_headers_set_range:
846
* @hdrs: a #SoupMessageHeaders
847
* @start: the start of the range to request
848
* @end: the end of the range to request
850
* Sets @hdrs's Range header to request the indicated range.
851
* @start and @end are interpreted as in a #SoupRange.
853
* If you need to request multiple ranges, use
854
* soup_message_headers_set_ranges().
857
soup_message_headers_set_range (SoupMessageHeaders *hdrs,
865
soup_message_headers_set_ranges (hdrs, &range, 1);
869
* soup_message_headers_get_content_range:
870
* @hdrs: a #SoupMessageHeaders
871
* @start: return value for the start of the range
872
* @end: return value for the end of the range
873
* @total_length: return value for the total length of the resource,
874
* or %NULL if you don't care.
876
* Parses @hdrs's Content-Range header and returns it in @start,
877
* @end, and @total_length. If the total length field in the header
878
* was specified as "*", then @total_length will be set to -1.
880
* Return value: %TRUE if @hdrs contained a "Content-Range" header
881
* containing a byte range which could be parsed, %FALSE otherwise.
884
soup_message_headers_get_content_range (SoupMessageHeaders *hdrs,
887
goffset *total_length)
889
const char *header = soup_message_headers_get (hdrs, "Content-Range");
893
if (!header || strncmp (header, "bytes ", 6) != 0)
897
while (g_ascii_isspace (*header))
899
if (!g_ascii_isdigit (*header))
902
*start = g_ascii_strtoull (header, &p, 10);
905
*end = g_ascii_strtoull (p + 1, &p, 10);
913
length = g_ascii_strtoull (p, &p, 10);
916
*total_length = length;
921
* soup_message_headers_set_content_range:
922
* @hdrs: a #SoupMessageHeaders
923
* @start: the start of the range
924
* @end: the end of the range
925
* @total_length: the total length of the resource, or -1 if unknown
927
* Sets @hdrs's Content-Range header according to the given values.
928
* (Note that @total_length is the total length of the entire resource
929
* that this is a range of, not simply @end - @start + 1.)
932
soup_message_headers_set_content_range (SoupMessageHeaders *hdrs,
935
goffset total_length)
939
if (total_length >= 0) {
940
header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%"
941
G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
942
start, end, total_length);
944
header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%"
945
G_GINT64_FORMAT "/*", start, end);
947
soup_message_headers_replace (hdrs, "Content-Range", header);
952
parse_content_foo (SoupMessageHeaders *hdrs, const char *header_name,
953
char **foo, GHashTable **params)
958
header = soup_message_headers_get (hdrs, header_name);
963
*foo = g_strdup (header);
964
semi = strchr (*foo, ';');
969
while (p - 1 > *foo && g_ascii_isspace(p[-1]))
973
semi = strchr (header, ';');
982
*params = soup_header_parse_semi_param_list ("");
986
*params = soup_header_parse_semi_param_list (semi);
991
set_content_foo (SoupMessageHeaders *hdrs, const char *header_name,
992
const char *foo, GHashTable *params)
998
str = g_string_new (foo);
1000
g_hash_table_iter_init (&iter, params);
1001
while (g_hash_table_iter_next (&iter, &key, &value)) {
1002
g_string_append (str, "; ");
1003
soup_header_g_string_append_param (str, key, value);
1007
soup_message_headers_replace (hdrs, header_name, str->str);
1008
g_string_free (str, TRUE);
1012
content_type_setter (SoupMessageHeaders *hdrs, const char *value)
1014
g_free (hdrs->content_type);
1016
parse_content_foo (hdrs, "Content-Type",
1017
&hdrs->content_type, NULL);
1019
hdrs->content_type = NULL;
1023
* soup_message_headers_get_content_type:
1024
* @hdrs: a #SoupMessageHeaders
1025
* @params: return location for the Content-Type parameters (eg,
1026
* "charset"), or %NULL
1028
* Looks up the "Content-Type" header in @hdrs, parses it, and returns
1029
* its value in *@content_type and *@params. @params can be %NULL if you
1030
* are only interested in the content type itself.
1032
* Return value: %TRUE if @hdrs contains a "Content-Type" header,
1033
* %FALSE if not (in which case *@content_type and *@params will be
1037
soup_message_headers_get_content_type (SoupMessageHeaders *hdrs,
1038
GHashTable **params)
1040
if (!hdrs->content_type)
1044
parse_content_foo (hdrs, "Content-Type", NULL, params);
1045
return hdrs->content_type;
1049
* soup_message_headers_set_content_type:
1050
* @hdrs: a #SoupMessageHeaders
1051
* @content_type: the MIME type
1052
* @params: additional parameters, or %NULL
1054
* Sets the "Content-Type" header in @hdrs to @content_type,
1055
* optionally with additional parameters specified in @params.
1058
soup_message_headers_set_content_type (SoupMessageHeaders *hdrs,
1059
const char *content_type,
1062
set_content_foo (hdrs, "Content-Type", content_type, params);
1066
* soup_message_headers_get_content_disposition:
1067
* @hdrs: a #SoupMessageHeaders
1068
* @disposition: return location for the disposition-type, or %NULL
1069
* @params: return location for the Content-Disposition parameters, or
1072
* Looks up the "Content-Disposition" header in @hdrs, parses it, and
1073
* returns its value in *@disposition and *@params. @params can be
1074
* %NULL if you are only interested in the disposition-type.
1076
* In HTTP, the most common use of this header is to set a
1077
* disposition-type of "attachment", to suggest to the browser that a
1078
* response should be saved to disk rather than displayed in the
1079
* browser. If @params contains a "filename" parameter, this is a
1080
* suggestion of a filename to use. (If the parameter value in the
1081
* header contains an absolute or relative path, libsoup will truncate
1082
* it down to just the final path component, so you do not need to
1083
* test this yourself.)
1085
* Content-Disposition is also used in "multipart/form-data", however
1086
* this is handled automatically by #SoupMultipart and the associated
1089
* Return value: %TRUE if @hdrs contains a "Content-Disposition"
1090
* header, %FALSE if not (in which case *@disposition and *@params
1091
* will be unchanged).
1094
soup_message_headers_get_content_disposition (SoupMessageHeaders *hdrs,
1096
GHashTable **params)
1098
gpointer orig_key, orig_value;
1100
if (!parse_content_foo (hdrs, "Content-Disposition",
1101
disposition, params))
1104
/* If there is a filename parameter, make sure it contains
1105
* only a single path component
1107
if (params && g_hash_table_lookup_extended (*params, "filename",
1108
&orig_key, &orig_value)) {
1109
char *filename = strrchr (orig_value, '/');
1112
g_hash_table_insert (*params, orig_key, filename + 1);
1118
* soup_message_headers_set_content_disposition:
1119
* @hdrs: a #SoupMessageHeaders
1120
* @disposition: the disposition-type
1121
* @params: additional parameters, or %NULL
1123
* Sets the "Content-Disposition" header in @hdrs to @disposition,
1124
* optionally with additional parameters specified in @params.
1126
* See soup_message_headers_get_content_disposition() for a discussion
1127
* of how Content-Disposition is used in HTTP.
1130
soup_message_headers_set_content_disposition (SoupMessageHeaders *hdrs,
1131
const char *disposition,
1134
set_content_foo (hdrs, "Content-Disposition", disposition, params);