X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libsoup%2Fsoup-uri.c;h=26ec24a04d0489aa6b6c618a512de96785499f88;hb=8c5ae3c24c95381b52530ac76a80598bb750c1ef;hp=1ece165c180d511000a91cdbc403da28e2117b6a;hpb=672d2560b015855ab0350655ecae73f8045c2dc7;p=platform%2Fupstream%2Flibsoup.git diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c index 1ece165..26ec24a 100644 --- a/libsoup/soup-uri.c +++ b/libsoup/soup-uri.c @@ -5,14 +5,12 @@ * Copyright 1999-2003 Ximian, Inc. */ -#include #include #include #include "soup-uri.h" +#include "soup.h" #include "soup-misc-private.h" -#include "soup-form.h" -#include "soup-misc.h" /** * SECTION:soup-uri @@ -81,6 +79,21 @@ **/ /** + * SOUP_URI_IS_VALID: + * @uri: a #SoupURI + * + * Tests whether @uri is a valid #SoupURI; that is, that it is non-%NULL + * and its @scheme and @path members are also non-%NULL. + * + * This macro does not check whether http and https URIs have a non-%NULL + * @host member. + * + * Return value: %TRUE if @uri is valid for use. + * + * Since: 2.38 + **/ + +/** * SOUP_URI_VALID_FOR_HTTP: * @uri: a #SoupURI * @@ -92,12 +105,63 @@ * Since: 2.24 **/ +/** + * SOUP_URI_SCHEME_HTTP: + * + * "http" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + */ +/** + * SOUP_URI_SCHEME_HTTPS: + * + * "https" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + */ +/** + * SOUP_URI_SCHEME_FTP: + * + * "ftp" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.30 + */ +/** + * SOUP_URI_SCHEME_FILE: + * + * "file" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.30 + */ +/** + * SOUP_URI_SCHEME_DATA: + * + * "data" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.30 + */ +/** + * SOUP_URI_SCHEME_RESOURCE: + * + * "data" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.42 + */ + static void append_uri_encoded (GString *str, const char *in, const char *extra_enc_chars); static char *uri_normalized_copy (const char *str, int length, const char *unescape_extra); gpointer _SOUP_URI_SCHEME_HTTP, _SOUP_URI_SCHEME_HTTPS; gpointer _SOUP_URI_SCHEME_FTP; -gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA; +gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA, _SOUP_URI_SCHEME_RESOURCE; static inline const char * soup_uri_parse_scheme (const char *scheme, int len) @@ -106,6 +170,8 @@ soup_uri_parse_scheme (const char *scheme, int len) return SOUP_URI_SCHEME_HTTP; } else if (len == 5 && !g_ascii_strncasecmp (scheme, "https", len)) { return SOUP_URI_SCHEME_HTTPS; + } else if (len == 8 && !g_ascii_strncasecmp (scheme, "resource", len)) { + return SOUP_URI_SCHEME_RESOURCE; } else { char *lower_scheme; @@ -142,12 +208,25 @@ soup_scheme_default_port (const char *scheme) SoupURI * soup_uri_new_with_base (SoupURI *base, const char *uri_string) { - SoupURI *uri; + SoupURI *uri, fixed_base; const char *end, *hash, *colon, *at, *path, *question; const char *p, *hostend; gboolean remove_dot_segments = TRUE; int len; + g_return_val_if_fail (uri_string != NULL, NULL); + + /* Allow a %NULL path in @base, for compatibility */ + if (base && base->scheme && !base->path) { + g_warn_if_fail (SOUP_URI_IS_VALID (base)); + + memcpy (&fixed_base, base, sizeof (SoupURI)); + fixed_base.path = ""; + base = &fixed_base; + } + + g_return_val_if_fail (base == NULL || SOUP_URI_IS_VALID (base), NULL); + /* First some cleanup steps (which are supposed to all be no-ops, * but...). Skip initial whitespace, strip out internal tabs and * line breaks, and ignore trailing whitespace. @@ -186,7 +265,7 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) /* Find scheme: initial [a-z+.-]* substring until ":" */ p = uri_string; - while (p < end && (g_ascii_isalnum (*p) || + while (p < end && (g_ascii_isalpha (*p) || *p == '.' || *p == '+' || *p == '-')) p++; @@ -212,14 +291,14 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) colon = strchr (uri_string, ':'); if (colon && colon < at) { uri->password = uri_decoded_copy (colon + 1, - at - colon - 1); + at - colon - 1, NULL); } else { uri->password = NULL; colon = at; } uri->user = uri_decoded_copy (uri_string, - colon - uri_string); + colon - uri_string, NULL); uri_string = at + 1; } else uri->user = uri->password = NULL; @@ -241,7 +320,7 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) hostend = colon ? colon : path; } - uri->host = uri_decoded_copy (uri_string, hostend - uri_string); + uri->host = uri_decoded_copy (uri_string, hostend - uri_string, NULL); if (colon && colon != path - 1) { char *portend; @@ -378,7 +457,7 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) /** * soup_uri_new: - * @uri_string: a URI + * @uri_string: (allow-none): a URI * * Parses an absolute URI. * @@ -387,7 +466,8 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) * call at least soup_uri_set_scheme() and soup_uri_set_path(), since * those fields are required.) * - * Return value: a #SoupURI, or %NULL. + * Return value: a #SoupURI, or %NULL if the given string was found to be + * invalid. **/ SoupURI * soup_uri_new (const char *uri_string) @@ -400,7 +480,7 @@ soup_uri_new (const char *uri_string) uri = soup_uri_new_with_base (NULL, uri_string); if (!uri) return NULL; - if (!uri->scheme) { + if (!SOUP_URI_IS_VALID (uri)) { soup_uri_free (uri); return NULL; } @@ -409,32 +489,17 @@ soup_uri_new (const char *uri_string) } -/** - * soup_uri_to_string: - * @uri: a #SoupURI - * @just_path_and_query: if %TRUE, output just the path and query portions - * - * Returns a string representing @uri. - * - * If @just_path_and_query is %TRUE, this concatenates the path and query - * together. That is, it constructs the string that would be needed in - * the Request-Line of an HTTP request for @uri. - * - * Return value: a string representing @uri, which the caller must free. - **/ char * -soup_uri_to_string (SoupURI *uri, gboolean just_path_and_query) +soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query, + gboolean force_port) { GString *str; char *return_result; g_return_val_if_fail (uri != NULL, NULL); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); - /* IF YOU CHANGE ANYTHING IN THIS FUNCTION, RUN - * tests/uri-parsing AFTERWARD. - */ - - str = g_string_sized_new (20); + str = g_string_sized_new (40); if (uri->scheme && !just_path_and_query) g_string_append_printf (str, "%s:", uri->scheme); @@ -450,14 +515,20 @@ soup_uri_to_string (SoupURI *uri, gboolean just_path_and_query) g_string_append_c (str, ']'); } else append_uri_encoded (str, uri->host, ":/"); - if (uri->port && uri->port != soup_scheme_default_port (uri->scheme)) + if (uri->port && (force_port || uri->port != soup_scheme_default_port (uri->scheme))) g_string_append_printf (str, ":%u", uri->port); if (!uri->path && (uri->query || uri->fragment)) g_string_append_c (str, '/'); + else if ((!uri->path || !*uri->path) && + (uri->scheme == SOUP_URI_SCHEME_HTTP || + uri->scheme == SOUP_URI_SCHEME_HTTPS)) + g_string_append_c (str, '/'); } if (uri->path && *uri->path) g_string_append (str, uri->path); + else if (just_path_and_query) + g_string_append_c (str, '/'); if (uri->query) { g_string_append_c (str, '?'); @@ -475,6 +546,25 @@ soup_uri_to_string (SoupURI *uri, gboolean just_path_and_query) } /** + * soup_uri_to_string: + * @uri: a #SoupURI + * @just_path_and_query: if %TRUE, output just the path and query portions + * + * Returns a string representing @uri. + * + * If @just_path_and_query is %TRUE, this concatenates the path and query + * together. That is, it constructs the string that would be needed in + * the Request-Line of an HTTP request for @uri. + * + * Return value: a string representing @uri, which the caller must free. + **/ +char * +soup_uri_to_string (SoupURI *uri, gboolean just_path_and_query) +{ + return soup_uri_to_string_internal (uri, just_path_and_query, FALSE); +} + +/** * soup_uri_copy: * @uri: a #SoupURI * @@ -488,6 +578,7 @@ soup_uri_copy (SoupURI *uri) SoupURI *dup; g_return_val_if_fail (uri != NULL, NULL); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); dup = g_slice_new0 (SoupURI); dup->scheme = uri->scheme; @@ -524,6 +615,11 @@ parts_equal (const char *one, const char *two, gboolean insensitive) gboolean soup_uri_equal (SoupURI *uri1, SoupURI *uri2) { + g_return_val_if_fail (uri1 != NULL, FALSE); + g_return_val_if_fail (uri2 != NULL, FALSE); + g_warn_if_fail (SOUP_URI_IS_VALID (uri1)); + g_warn_if_fail (SOUP_URI_IS_VALID (uri2)); + if (uri1->scheme != uri2->scheme || uri1->port != uri2->port || !parts_equal (uri1->user, uri2->user, FALSE) || @@ -591,6 +687,8 @@ soup_uri_encode (const char *part, const char *escape_extra) GString *str; char *encoded; + g_return_val_if_fail (part != NULL, NULL); + str = g_string_new (NULL); append_uri_encoded (str, part, escape_extra); encoded = str->str; @@ -603,11 +701,13 @@ soup_uri_encode (const char *part, const char *escape_extra) #define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2])) char * -uri_decoded_copy (const char *part, int length) +uri_decoded_copy (const char *part, int length, int *decoded_length) { unsigned char *s, *d; char *decoded = g_strndup (part, length); + g_return_val_if_fail (part != NULL, NULL); + s = d = (unsigned char *)decoded; do { if (*s == '%') { @@ -622,6 +722,9 @@ uri_decoded_copy (const char *part, int length) *d++ = *s; } while (*s++); + if (decoded_length) + *decoded_length = d - (unsigned char *)decoded - 1; + return decoded; } @@ -640,7 +743,9 @@ uri_decoded_copy (const char *part, int length) char * soup_uri_decode (const char *part) { - return uri_decoded_copy (part, strlen (part)); + g_return_val_if_fail (part != NULL, NULL); + + return uri_decoded_copy (part, strlen (part), NULL); } static char * @@ -651,20 +756,23 @@ uri_normalized_copy (const char *part, int length, char *normalized = g_strndup (part, length); gboolean need_fixup = FALSE; + if (!unescape_extra) + unescape_extra = ""; + s = d = (unsigned char *)normalized; - do { + while (*s) { if (*s == '%') { if (!g_ascii_isxdigit (s[1]) || !g_ascii_isxdigit (s[2])) { - *d++ = *s; + *d++ = *s++; continue; } c = HEXCHAR (s); if (soup_char_is_uri_unreserved (c) || - (unescape_extra && strchr (unescape_extra, c))) { + (c && strchr (unescape_extra, c))) { *d++ = c; - s += 2; + s += 3; } else { /* We leave it unchanged. We used to uppercase percent-encoded * triplets but we do not do it any more as RFC3986 Section 6.2.2.1 @@ -672,14 +780,16 @@ uri_normalized_copy (const char *part, int length, */ *d++ = *s++; *d++ = *s++; - *d++ = *s; + *d++ = *s++; } } else { - if (!g_ascii_isgraph (*s)) + if (!g_ascii_isgraph (*s) && + !strchr (unescape_extra, *s)) need_fixup = TRUE; - *d++ = *s; + *d++ = *s++; } - } while (*s++); + } + *d = '\0'; if (need_fixup) { GString *fixed; @@ -687,7 +797,8 @@ uri_normalized_copy (const char *part, int length, fixed = g_string_new (NULL); s = (guchar *)normalized; while (*s) { - if (g_ascii_isgraph (*s)) + if (g_ascii_isgraph (*s) || + strchr (unescape_extra, *s)) g_string_append_c (fixed, *s); else g_string_append_printf (fixed, "%%%02X", (int)*s); @@ -727,6 +838,8 @@ uri_normalized_copy (const char *part, int length, char * soup_uri_normalize (const char *part, const char *unescape_extra) { + g_return_val_if_fail (part != NULL, NULL); + return uri_normalized_copy (part, strlen (part), unescape_extra); } @@ -736,7 +849,7 @@ soup_uri_normalize (const char *part, const char *unescape_extra) * @uri: a #SoupURI * * Tests if @uri uses the default port for its scheme. (Eg, 80 for - * http.) (This only works for http and https; libsoup does not know + * http.) (This only works for http, https and ftp; libsoup does not know * the default ports of other protocols.) * * Return value: %TRUE or %FALSE @@ -744,6 +857,9 @@ soup_uri_normalize (const char *part, const char *unescape_extra) gboolean soup_uri_uses_default_port (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, FALSE); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + return uri->port == soup_scheme_default_port (uri->scheme); } @@ -762,6 +878,15 @@ soup_uri_uses_default_port (SoupURI *uri) **/ /** + * SOUP_URI_SCHEME_RESOURCE: + * + * "resource" as an interned string. This can be compared directly + * against the value of a #SoupURI's scheme + * + * Since: 2.42 + **/ + +/** * soup_uri_get_scheme: * @uri: a #SoupURI * @@ -774,6 +899,8 @@ soup_uri_uses_default_port (SoupURI *uri) const char * soup_uri_get_scheme (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->scheme; } @@ -788,6 +915,9 @@ soup_uri_get_scheme (SoupURI *uri) void soup_uri_set_scheme (SoupURI *uri, const char *scheme) { + g_return_if_fail (uri != NULL); + g_return_if_fail (scheme != NULL); + uri->scheme = soup_uri_parse_scheme (scheme, strlen (scheme)); uri->port = soup_scheme_default_port (uri->scheme); } @@ -805,19 +935,23 @@ soup_uri_set_scheme (SoupURI *uri, const char *scheme) const char * soup_uri_get_user (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->user; } /** * soup_uri_set_user: * @uri: a #SoupURI - * @user: the username, or %NULL + * @user: (allow-none): the username, or %NULL * * Sets @uri's user to @user. **/ void soup_uri_set_user (SoupURI *uri, const char *user) { + g_return_if_fail (uri != NULL); + g_free (uri->user); uri->user = g_strdup (user); } @@ -835,19 +969,23 @@ soup_uri_set_user (SoupURI *uri, const char *user) const char * soup_uri_get_password (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->password; } /** * soup_uri_set_password: * @uri: a #SoupURI - * @password: the password, or %NULL + * @password: (allow-none): the password, or %NULL * * Sets @uri's password to @password. **/ void soup_uri_set_password (SoupURI *uri, const char *password) { + g_return_if_fail (uri != NULL); + g_free (uri->password); uri->password = g_strdup (password); } @@ -865,23 +1003,29 @@ soup_uri_set_password (SoupURI *uri, const char *password) const char * soup_uri_get_host (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->host; } /** * soup_uri_set_host: * @uri: a #SoupURI - * @host: the hostname or IP address, or %NULL + * @host: (allow-none): the hostname or IP address, or %NULL * * Sets @uri's host to @host. * * If @host is an IPv6 IP address, it should not include the brackets * required by the URI syntax; they will be added automatically when * converting @uri to a string. + * + * http and https URIs should not have a %NULL @host. **/ void soup_uri_set_host (SoupURI *uri, const char *host) { + g_return_if_fail (uri != NULL); + g_free (uri->host); uri->host = g_strdup (host); } @@ -899,6 +1043,8 @@ soup_uri_set_host (SoupURI *uri, const char *host) guint soup_uri_get_port (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, 0); + return uri->port; } @@ -913,6 +1059,8 @@ soup_uri_get_port (SoupURI *uri) void soup_uri_set_port (SoupURI *uri, guint port) { + g_return_if_fail (uri != NULL); + uri->port = port; } @@ -929,19 +1077,29 @@ soup_uri_set_port (SoupURI *uri, guint port) const char * soup_uri_get_path (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->path; } /** * soup_uri_set_path: * @uri: a #SoupURI - * @path: the path + * @path: the non-%NULL path * * Sets @uri's path to @path. **/ void soup_uri_set_path (SoupURI *uri, const char *path) { + g_return_if_fail (uri != NULL); + + /* We allow a NULL path for compatibility, but warn about it. */ + if (!path) { + g_warn_if_fail (path != NULL); + path = ""; + } + g_free (uri->path); uri->path = g_strdup (path); } @@ -959,19 +1117,23 @@ soup_uri_set_path (SoupURI *uri, const char *path) const char * soup_uri_get_query (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->query; } /** * soup_uri_set_query: * @uri: a #SoupURI - * @query: the query + * @query: (allow-none): the query * * Sets @uri's query to @query. **/ void soup_uri_set_query (SoupURI *uri, const char *query) { + g_return_if_fail (uri != NULL); + g_free (uri->query); uri->query = g_strdup (query); } @@ -988,6 +1150,8 @@ soup_uri_set_query (SoupURI *uri, const char *query) void soup_uri_set_query_from_form (SoupURI *uri, GHashTable *form) { + g_return_if_fail (uri != NULL); + g_free (uri->query); uri->query = soup_form_encode_hash (form); } @@ -1010,6 +1174,8 @@ soup_uri_set_query_from_fields (SoupURI *uri, { va_list args; + g_return_if_fail (uri != NULL); + g_free (uri->query); va_start (args, first_field); uri->query = soup_form_encode_valist (first_field, args); @@ -1029,19 +1195,23 @@ soup_uri_set_query_from_fields (SoupURI *uri, const char * soup_uri_get_fragment (SoupURI *uri) { + g_return_val_if_fail (uri != NULL, NULL); + return uri->fragment; } /** * soup_uri_set_fragment: * @uri: a #SoupURI - * @fragment: the fragment + * @fragment: (allow-none): the fragment * * Sets @uri's fragment to @fragment. **/ void soup_uri_set_fragment (SoupURI *uri, const char *fragment) { + g_return_if_fail (uri != NULL); + g_free (uri->fragment); uri->fragment = g_strdup (fragment); } @@ -1054,7 +1224,7 @@ soup_uri_set_fragment (SoupURI *uri, const char *fragment) * * Return value: the new #SoupURI * - * Since: 2.26.3 + * Since: 2.28 **/ SoupURI * soup_uri_copy_host (SoupURI *uri) @@ -1062,27 +1232,26 @@ soup_uri_copy_host (SoupURI *uri) SoupURI *dup; g_return_val_if_fail (uri != NULL, NULL); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); dup = soup_uri_new (NULL); dup->scheme = uri->scheme; dup->host = g_strdup (uri->host); dup->port = uri->port; - if (dup->scheme == SOUP_URI_SCHEME_HTTP || - dup->scheme == SOUP_URI_SCHEME_HTTPS) - dup->path = g_strdup (""); + dup->path = g_strdup (""); return dup; } /** * soup_uri_host_hash: - * @key: (type Soup.URI): a #SoupURI + * @key: (type Soup.URI): a #SoupURI with a non-%NULL @host member * * Hashes @key, considering only the scheme, host, and port. * * Return value: a hash * - * Since: 2.26.3 + * Since: 2.28 **/ guint soup_uri_host_hash (gconstpointer key) @@ -1090,6 +1259,7 @@ soup_uri_host_hash (gconstpointer key) const SoupURI *uri = key; g_return_val_if_fail (uri != NULL && uri->host != NULL, 0); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); return GPOINTER_TO_UINT (uri->scheme) + uri->port + soup_str_case_hash (uri->host); @@ -1097,15 +1267,15 @@ soup_uri_host_hash (gconstpointer key) /** * soup_uri_host_equal: - * @v1: (type Soup.URI): a #SoupURI - * @v2: (type Soup.URI): a #SoupURI + * @v1: (type Soup.URI): a #SoupURI with a non-%NULL @host member + * @v2: (type Soup.URI): a #SoupURI with a non-%NULL @host member * * Compares @v1 and @v2, considering only the scheme, host, and port. * * Return value: whether or not the URIs are equal in scheme, host, * and port. * - * Since: 2.26.3 + * Since: 2.28 **/ gboolean soup_uri_host_equal (gconstpointer v1, gconstpointer v2) @@ -1115,6 +1285,8 @@ soup_uri_host_equal (gconstpointer v1, gconstpointer v2) g_return_val_if_fail (one != NULL && two != NULL, one == two); g_return_val_if_fail (one->host != NULL && two->host != NULL, one->host == two->host); + g_warn_if_fail (SOUP_URI_IS_VALID (one)); + g_warn_if_fail (SOUP_URI_IS_VALID (two)); if (one->scheme != two->scheme) return FALSE; @@ -1124,18 +1296,4 @@ soup_uri_host_equal (gconstpointer v1, gconstpointer v2) return g_ascii_strcasecmp (one->host, two->host) == 0; } - -GType -soup_uri_get_type (void) -{ - static volatile gsize type_volatile = 0; - - if (g_once_init_enter (&type_volatile)) { - GType type = g_boxed_type_register_static ( - g_intern_static_string ("SoupURI"), - (GBoxedCopyFunc) soup_uri_copy, - (GBoxedFreeFunc) soup_uri_free); - g_once_init_leave (&type_volatile, type); - } - return type_volatile; -} +G_DEFINE_BOXED_TYPE (SoupURI, soup_uri, soup_uri_copy, soup_uri_free)