static char * soup_auth_manager_extract_challenge (const char *challenges, const char *scheme) { GSList *items, *i, *next; int schemelen = strlen (scheme); char *item; GString *challenge; items = soup_header_parse_list (challenges); /* First item will start with the scheme name, followed by * either nothing, or else a space and then the first * auth-param. */ for (i = items; i; i = next_challenge_start (i->next)) { item = i->data; if (!g_ascii_strncasecmp (item, scheme, schemelen) && (!item[schemelen] || g_ascii_isspace (item[schemelen]))) break; } if (!i) { soup_header_free_list (items); return NULL; } next = next_challenge_start (i->next); challenge = g_string_new (item); for (i = i->next; i != next; i = i->next) { item = i->data; g_string_append (challenge, ", "); g_string_append (challenge, item); } soup_header_free_list (items); return g_string_free (challenge, FALSE); }
/** * soup_message_headers_clean_connection_headers: * @hdrs: a #SoupMessageHeaders * * Removes all the headers listed in the Connection header. * * Since: 2.36 */ void soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) { /* RFC 2616 14.10 */ const char *connection; GSList *tokens, *t; connection = soup_message_headers_get_list (hdrs, "Connection"); if (!connection) return; tokens = soup_header_parse_list (connection); for (t = tokens; t; t = t->next) soup_message_headers_remove (hdrs, t->data); soup_header_free_list (tokens); }
SoupAuthDigestQop soup_auth_digest_parse_qop (const char *qop) { GSList *qop_values, *iter; SoupAuthDigestQop out = 0; g_return_val_if_fail (qop != NULL, 0); qop_values = soup_header_parse_list (qop); for (iter = qop_values; iter; iter = iter->next) { if (!g_ascii_strcasecmp (iter->data, "auth")) out |= SOUP_AUTH_DIGEST_QOP_AUTH; else if (!g_ascii_strcasecmp (iter->data, "auth-int")) out |= SOUP_AUTH_DIGEST_QOP_AUTH_INT; } soup_header_free_list (qop_values); return out; }
static void server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { const char *accept_encoding, *options; GSList *codings; char *file = NULL, *contents; gsize length; options = soup_message_headers_get_one (msg->request_headers, "X-Test-Options"); if (!options) options = ""; accept_encoding = soup_message_headers_get_list (msg->request_headers, "Accept-Encoding"); if (accept_encoding && !soup_header_contains (options, "force-encode")) codings = soup_header_parse_quality_list (accept_encoding, NULL); else codings = NULL; if (codings) { gboolean claim_deflate, claim_gzip; const char *file_path = NULL, *encoding = NULL; claim_deflate = g_slist_find_custom (codings, "deflate", (GCompareFunc)g_ascii_strcasecmp) != NULL; claim_gzip = g_slist_find_custom (codings, "gzip", (GCompareFunc)g_ascii_strcasecmp) != NULL; if (claim_gzip && (!claim_deflate || (!soup_header_contains (options, "prefer-deflate-zlib") && !soup_header_contains (options, "prefer-deflate-raw")))) { file_path = SRCDIR "/resources%s.gz"; encoding = "gzip"; } else if (claim_deflate) { if (soup_header_contains (options, "prefer-deflate-raw")) { file_path = SRCDIR "/resources%s.raw"; encoding = "deflate"; } else { file_path = SRCDIR "/resources%s.zlib"; encoding = "deflate"; } } if (file_path && encoding) { file = g_strdup_printf (file_path, path); if (g_file_test (file, G_FILE_TEST_EXISTS)) { soup_message_headers_append (msg->response_headers, "Content-Encoding", encoding); } else { g_free (file); file = NULL; } } } soup_header_free_list (codings); if (!file) file = g_strdup_printf (SRCDIR "/resources%s", path); if (!g_file_get_contents (file, &contents, &length, NULL)) { /* If path.gz exists but can't be read, we'll send back * the error with "Content-Encoding: gzip" but there's * no body, so, eh. */ g_free (file); soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); return; } g_free (file); if (soup_header_contains (options, "force-encode")) { const gchar *encoding = "gzip"; if (soup_header_contains (options, "prefer-deflate-zlib") || soup_header_contains (options, "prefer-deflate-raw")) encoding = "deflate"; soup_message_headers_replace (msg->response_headers, "Content-Encoding", encoding); } /* Content-Type matches the "real" format, not the sent format */ if (g_str_has_suffix (path, ".gz")) { soup_message_headers_append (msg->response_headers, "Content-Type", "application/gzip"); } else { soup_message_headers_append (msg->response_headers, "Content-Type", "text/plain"); } soup_message_set_status (msg, SOUP_STATUS_OK); soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CHUNKED); if (!soup_header_contains (options, "empty")) { soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE, contents, length); } else g_free (contents); if (soup_header_contains (options, "trailing-junk")) { soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, options, strlen (options)); } soup_message_body_complete (msg->response_body); }
static void resource_available (GSSDPResourceBrowser *resource_browser, SoupMessageHeaders *headers) { GSSDPResourceBrowserPrivate *priv; const char *usn; const char *header; Resource *resource; gboolean was_cached; guint timeout; GList *locations; gboolean destroyLocations; GList *it1, *it2; char *canonical_usn; priv = gssdp_resource_browser_get_instance_private (resource_browser); usn = soup_message_headers_get_one (headers, "USN"); if (!usn) return; /* No USN specified */ /* Build list of locations */ locations = NULL; destroyLocations = TRUE; header = soup_message_headers_get_one (headers, "Location"); if (header) locations = g_list_append (locations, g_strdup (header)); header = soup_message_headers_get_one (headers, "AL"); if (header) { /* Parse AL header. The format is: * <uri1><uri2>... */ const char *start, *end; char *uri; start = header; while ((start = strchr (start, '<'))) { start += 1; if (!start || !*start) break; end = strchr (start, '>'); if (!end || !*end) break; uri = g_strndup (start, end - start); locations = g_list_append (locations, uri); start = end; } } if (!locations) return; /* No location specified */ if (priv->version > 0) { char *version; version = g_strrstr (usn, ":"); canonical_usn = g_strndup (usn, version - usn); } else { canonical_usn = g_strdup (usn); } /* Get from cache, if possible */ resource = g_hash_table_lookup (priv->resources, canonical_usn); /* Put usn into fresh resources, so this resource will not be * removed on cache refreshing. */ if (priv->fresh_resources != NULL) { g_hash_table_add (priv->fresh_resources, g_strdup (canonical_usn)); } /* If location does not match, expect that we missed bye bye packet */ if (resource) { for (it1 = locations, it2 = resource->locations; it1 && it2; it1 = it1->next, it2 = it2->next) { if (strcmp ((const char *) it1->data, (const char *) it2->data) != 0) { resource_unavailable (resource_browser, headers); /* Will be destroyed by resource_unavailable */ resource = NULL; break; } } } if (resource) { /* Remove old timeout */ g_source_destroy (resource->timeout_src); was_cached = TRUE; } else { /* Create new Resource data structure */ resource = g_slice_new (Resource); resource->resource_browser = resource_browser; resource->usn = g_strdup (usn); resource->locations = locations; destroyLocations = FALSE; /* Ownership passed to resource */ g_hash_table_insert (priv->resources, canonical_usn, resource); was_cached = FALSE; /* hash-table takes ownership of this */ canonical_usn = NULL; } g_free (canonical_usn); /* Calculate new timeout */ header = soup_message_headers_get_one (headers, "Cache-Control"); if (header) { GSList *list; int res; res = 0; for (list = soup_header_parse_list (header); list; list = list->next) { res = sscanf (list->data, "max-age = %d", &timeout); if (res == 1) break; } if (res != 1) { g_warning ("Invalid 'Cache-Control' header. Assuming " "default max-age of %d.\n" "Header was:\n%s", SSDP_DEFAULT_MAX_AGE, header); timeout = SSDP_DEFAULT_MAX_AGE; } soup_header_free_list (list); } else { const char *expires; expires = soup_message_headers_get_one (headers, "Expires"); if (expires) { SoupDate *soup_exp_time; time_t exp_time, cur_time; soup_exp_time = soup_date_new_from_string (expires); exp_time = soup_date_to_time_t (soup_exp_time); soup_date_free (soup_exp_time); cur_time = time (NULL); if (exp_time > cur_time) timeout = exp_time - cur_time; else { g_warning ("Invalid 'Expires' header. Assuming " "default max-age of %d.\n" "Header was:\n%s", SSDP_DEFAULT_MAX_AGE, expires); timeout = SSDP_DEFAULT_MAX_AGE; } } else { g_warning ("No 'Cache-Control' nor any 'Expires' " "header was specified. Assuming default " "max-age of %d.", SSDP_DEFAULT_MAX_AGE); timeout = SSDP_DEFAULT_MAX_AGE; } } resource->timeout_src = g_timeout_source_new_seconds (timeout); g_source_set_callback (resource->timeout_src, resource_expire, resource, NULL); g_source_attach (resource->timeout_src, g_main_context_get_thread_default ()); g_source_unref (resource->timeout_src); /* Only continue with signal emission if this resource was not * cached already */ if (!was_cached) { /* Emit signal */ g_signal_emit (resource_browser, signals[RESOURCE_AVAILABLE], 0, usn, locations); } /* Cleanup */ if (destroyLocations) g_list_free_full (locations, g_free); }
/** * 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) { const char *range = soup_message_headers_get_one (hdrs, "Range"); GSList *range_list, *r; GArray *array; char *spec, *end; int i; if (!range || strncmp (range, "bytes", 5) != 0) return FALSE; range += 5; while (g_ascii_isspace (*range)) range++; if (*range++ != '=') return FALSE; while (g_ascii_isspace (*range)) range++; range_list = soup_header_parse_list (range); if (!range_list) return FALSE; array = g_array_new (FALSE, FALSE, sizeof (SoupRange)); for (r = range_list; r; r = r->next) { SoupRange cur; spec = r->data; if (*spec == '-') { cur.start = g_ascii_strtoll (spec, &end, 10) + total_length; cur.end = total_length - 1; } else { cur.start = g_ascii_strtoull (spec, &end, 10); if (*end == '-') end++; if (*end) cur.end = g_ascii_strtoull (end, &end, 10); else cur.end = total_length - 1; } if (*end) { g_array_free (array, TRUE); soup_header_free_list (range_list); return FALSE; } g_array_append_val (array, cur); } soup_header_free_list (range_list); if (total_length) { g_array_sort (array, sort_ranges); for (i = 1; i < array->len; i++) { SoupRange *cur = &((SoupRange *)array->data)[i]; SoupRange *prev = &((SoupRange *)array->data)[i - 1]; if (cur->start <= prev->end) { prev->end = MAX (prev->end, cur->end); g_array_remove_index (array, i); } } } *ranges = (SoupRange *)array->data; *length = array->len; g_array_free (array, FALSE); return TRUE; }
/* 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 status; range += 5; while (g_ascii_isspace (*range)) range++; if (*range++ != '=') return status; while (g_ascii_isspace (*range)) range++; range_list = soup_header_parse_list (range); if (!range_list) return status; array = g_array_new (FALSE, FALSE, sizeof (SoupRange)); for (r = range_list; r; r = r->next) { SoupRange cur; spec = r->data; if (*spec == '-') { cur.start = g_ascii_strtoll (spec, &end, 10) + total_length; cur.end = total_length - 1; } else { cur.start = g_ascii_strtoull (spec, &end, 10); if (*end == '-') end++; if (*end) { cur.end = g_ascii_strtoull (end, &end, 10); if (cur.end < cur.start) { status = SOUP_STATUS_OK; break; } } else cur.end = total_length - 1; } if (*end) { 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++) { SoupRange *cur = &((SoupRange *)array->data)[i]; SoupRange *prev = &((SoupRange *)array->data)[i - 1]; if (cur->start <= prev->end) { prev->end = MAX (prev->end, cur->end); g_array_remove_index (array, i); } } } *ranges = (SoupRange *)array->data; *length = array->len; g_array_free (array, FALSE); return SOUP_STATUS_PARTIAL_CONTENT; }