diff options
Diffstat (limited to 'libsoup/soup-message-headers.c')
-rw-r--r-- | libsoup/soup-message-headers.c | 142 |
1 files changed, 100 insertions, 42 deletions
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c index b9bab238..9c704b49 100644 --- a/libsoup/soup-message-headers.c +++ b/libsoup/soup-message-headers.c @@ -9,6 +9,7 @@ #include "soup-message-headers.h" #include "soup.h" +#include "soup-misc-private.h" /** * SECTION:soup-message-headers @@ -300,7 +301,7 @@ soup_message_headers_remove (SoupMessageHeaders *hdrs, const char *name) * * Return value: the header's value or %NULL if not found. * - * Since: 2.26.1 + * Since: 2.28 **/ const char * soup_message_headers_get_one (SoupMessageHeaders *hdrs, const char *name) @@ -338,7 +339,7 @@ soup_message_headers_get_one (SoupMessageHeaders *hdrs, const char *name) * * Return value: the header's value or %NULL if not found. * - * Since: 2.26.1 + * Since: 2.28 **/ const char * soup_message_headers_get_list (SoupMessageHeaders *hdrs, const char *name) @@ -858,56 +859,40 @@ sort_ranges (gconstpointer a, gconstpointer b) return ra->start - rb->start; } -/** - * soup_message_headers_get_ranges: - * @hdrs: a #SoupMessageHeaders - * @total_length: the total_length of the response body - * @ranges: (out): return location for an array of #SoupRange - * @length: the length of the returned array - * - * Parses @hdrs's Range header and returns an array of the requested - * byte ranges. The returned array must be freed with - * soup_message_headers_free_ranges(). - * - * If @total_length is non-0, its value will be used to adjust the - * returned ranges to have explicit start and end values, and the - * returned ranges will be sorted and non-overlapping. If - * @total_length is 0, then some ranges may have an end value of -1, - * as described under #SoupRange, and some of the ranges may be - * redundant. - * - * Return value: %TRUE if @hdrs contained a "Range" header containing - * byte ranges which could be parsed, %FALSE otherwise (in which case - * @range and @length will not be set). - * - * Since: 2.26 - **/ -gboolean -soup_message_headers_get_ranges (SoupMessageHeaders *hdrs, - goffset total_length, - SoupRange **ranges, - int *length) +/* like soup_message_headers_get_ranges(), except it returns: + * SOUP_STATUS_OK if there is no Range or it should be ignored. + * SOUP_STATUS_PARTIAL_CONTENT if there is at least one satisfiable range. + * SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE if @check_satisfiable + * is %TRUE and the request is not satisfiable given @total_length. + */ +guint +soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs, + goffset total_length, + gboolean check_satisfiable, + SoupRange **ranges, + int *length) { const char *range = soup_message_headers_get_one (hdrs, "Range"); GSList *range_list, *r; GArray *array; char *spec, *end; int i; + guint status = SOUP_STATUS_OK; if (!range || strncmp (range, "bytes", 5) != 0) - return FALSE; + return status; range += 5; while (g_ascii_isspace (*range)) range++; if (*range++ != '=') - return FALSE; + return status; while (g_ascii_isspace (*range)) range++; range_list = soup_header_parse_list (range); if (!range_list) - return FALSE; + return status; array = g_array_new (FALSE, FALSE, sizeof (SoupRange)); for (r = range_list; r; r = r->next) { @@ -921,22 +906,34 @@ soup_message_headers_get_ranges (SoupMessageHeaders *hdrs, cur.start = g_ascii_strtoull (spec, &end, 10); if (*end == '-') end++; - if (*end) + if (*end) { cur.end = g_ascii_strtoull (end, &end, 10); - else + if (cur.end < cur.start) { + status = SOUP_STATUS_OK; + break; + } + } else cur.end = total_length - 1; } if (*end) { - g_array_free (array, TRUE); - soup_header_free_list (range_list); - return FALSE; + status = SOUP_STATUS_OK; + break; + } else if (check_satisfiable && cur.start >= total_length) { + if (status == SOUP_STATUS_OK) + status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE; + continue; } g_array_append_val (array, cur); + status = SOUP_STATUS_PARTIAL_CONTENT; } - soup_header_free_list (range_list); + if (status != SOUP_STATUS_PARTIAL_CONTENT) { + g_array_free (array, TRUE); + return status; + } + if (total_length) { g_array_sort (array, sort_ranges); for (i = 1; i < array->len; i++) { @@ -954,7 +951,62 @@ soup_message_headers_get_ranges (SoupMessageHeaders *hdrs, *length = array->len; g_array_free (array, FALSE); - return TRUE; + return SOUP_STATUS_PARTIAL_CONTENT; +} + +/** + * soup_message_headers_get_ranges: + * @hdrs: a #SoupMessageHeaders + * @total_length: the total_length of the response body + * @ranges: (out): return location for an array of #SoupRange + * @length: the length of the returned array + * + * Parses @hdrs's Range header and returns an array of the requested + * byte ranges. The returned array must be freed with + * soup_message_headers_free_ranges(). + * + * If @total_length is non-0, its value will be used to adjust the + * returned ranges to have explicit start and end values, and the + * returned ranges will be sorted and non-overlapping. If + * @total_length is 0, then some ranges may have an end value of -1, + * as described under #SoupRange, and some of the ranges may be + * redundant. + * + * Beware that even if given a @total_length, this function does not + * check that the ranges are satisfiable. + * + * <note><para> + * #SoupServer has built-in handling for range requests. If your + * server handler returns a %SOUP_STATUS_OK response containing the + * complete response body (rather than pausing the message and + * returning some of the response body later), and there is a Range + * header in the request, then libsoup will automatically convert the + * response to a %SOUP_STATUS_PARTIAL_CONTENT response containing only + * the range(s) requested by the client. + * + * The only time you need to process the Range header yourself is if + * either you need to stream the response body rather than returning + * it all at once, or you do not already have the complete response + * body available, and only want to generate the parts that were + * actually requested by the client. + * </para></note> + * + * Return value: %TRUE if @hdrs contained a syntactically-valid + * "Range" header, %FALSE otherwise (in which case @range and @length + * will not be set). + * + * Since: 2.26 + **/ +gboolean +soup_message_headers_get_ranges (SoupMessageHeaders *hdrs, + goffset total_length, + SoupRange **ranges, + int *length) +{ + guint status; + + status = soup_message_headers_get_ranges_internal (hdrs, total_length, FALSE, ranges, length); + return status == SOUP_STATUS_PARTIAL_CONTENT; } /** @@ -1104,6 +1156,12 @@ soup_message_headers_get_content_range (SoupMessageHeaders *hdrs, * (Note that @total_length is the total length of the entire resource * that this is a range of, not simply @end - @start + 1.) * + * <note><para> + * #SoupServer has built-in handling for range requests, and you do + * not normally need to call this function youself. See + * soup_message_headers_get_ranges() for more details. + * </para></note> + * * Since: 2.26 **/ void @@ -1303,7 +1361,7 @@ soup_message_headers_get_content_disposition (SoupMessageHeaders *hdrs, char *filename = strrchr (orig_value, '/'); if (filename) - g_hash_table_insert (*params, orig_key, filename + 1); + g_hash_table_insert (*params, g_strdup (orig_key), filename + 1); } return TRUE; } |