diff options
author | Dan Winship <danw@gnome.org> | 2013-11-24 14:50:41 -0500 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2013-11-24 14:50:41 -0500 |
commit | 677194110578397e3325055e89bd76ca56d3f09e (patch) | |
tree | a7987766c152c09c41a61ee4c0caffcb98e1e0b3 | |
parent | b16b45344b10d6dc3abcca10ed477c5ea45787c8 (diff) | |
download | libsoup-wip/danw/guri.tar.gz |
-rw-r--r-- | libsoup/soup-uri.c | 311 |
1 files changed, 68 insertions, 243 deletions
diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c index e3092dcf..1e0b2397 100644 --- a/libsoup/soup-uri.c +++ b/libsoup/soup-uri.c @@ -163,26 +163,6 @@ gpointer _SOUP_URI_SCHEME_HTTP, _SOUP_URI_SCHEME_HTTPS; gpointer _SOUP_URI_SCHEME_FTP; 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) -{ - if (len == 4 && !g_ascii_strncasecmp (scheme, "http", 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; - - lower_scheme = g_ascii_strdown (scheme, len); - scheme = g_intern_static_string (lower_scheme); - if (scheme != (const char *)lower_scheme) - g_free (lower_scheme); - return scheme; - } -} - static inline guint soup_scheme_default_port (const char *scheme) { @@ -196,6 +176,38 @@ soup_scheme_default_port (const char *scheme) return 0; } +static GUri * +soup_uri_to_g_uri (SoupURI *uri, gboolean override_port, guint port) +{ + if (!uri) + return NULL; + + return g_uri_build_with_user (G_URI_ENCODED | G_URI_HAS_PASSWORD, + uri->scheme, + uri->user, uri->password, NULL, + uri->host, + override_port ? port : uri->port, + uri->path, uri->query, uri->fragment); +} + +static SoupURI * +soup_uri_from_g_uri (GUri *guri) +{ + SoupURI *uri; + + uri = g_slice_new0 (SoupURI); + uri->scheme = g_intern_string (g_uri_get_scheme (guri)); + uri->user = g_strdup (g_uri_get_user (guri)); + uri->password = g_strdup (g_uri_get_password (guri)); + uri->host = g_strdup (g_uri_get_host (guri)); + uri->port = g_uri_get_port (guri); + uri->path = g_strdup (g_uri_get_path (guri)); + uri->query = g_strdup (g_uri_get_query (guri)); + uri->fragment = g_strdup (g_uri_get_fragment (guri)); + + return uri; +} + /** * soup_uri_new_with_base: * @base: a base URI @@ -209,12 +221,7 @@ SoupURI * soup_uri_new_with_base (SoupURI *base, const char *uri_string) { 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); + GUri *base_guri, *guri; /* Allow a %NULL path in @base, for compatibility */ if (base && base->scheme && !base->path) { @@ -227,225 +234,24 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) 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. - */ - while (g_ascii_isspace (*uri_string)) - uri_string++; - - len = strcspn (uri_string, "\t\n\r"); - if (uri_string[len]) { - char *clean = g_malloc (strlen (uri_string) + 1), *d; - const char *s; - - for (s = uri_string, d = clean; *s; s++) { - if (*s != '\t' && *s != '\n' && *s != '\r') - *d++ = *s; - } - *d = '\0'; - - uri = soup_uri_new_with_base (base, clean); - g_free (clean); - return uri; - } - end = uri_string + len; - while (end > uri_string && g_ascii_isspace (end[-1])) - end--; - - uri = g_slice_new0 (SoupURI); - - /* Find fragment. */ - hash = strchr (uri_string, '#'); - if (hash) { - uri->fragment = uri_normalized_copy (hash + 1, end - hash + 1, - NULL); - end = hash; - } - - /* Find scheme */ - p = uri_string; - while (p < end && (g_ascii_isalpha (*p) || - (p > uri_string && (g_ascii_isdigit (*p) || - *p == '.' || - *p == '+' || - *p == '-')))) - p++; - - if (p > uri_string && *p == ':') { - uri->scheme = soup_uri_parse_scheme (uri_string, p - uri_string); - uri_string = p + 1; - } - - if (uri_string == end && !base && !uri->fragment) { - uri->path = g_strdup (""); - return uri; - } - - /* Check for authority */ - if (strncmp (uri_string, "//", 2) == 0) { - uri_string += 2; - - path = uri_string + strcspn (uri_string, "/?#"); - if (path > end) - path = end; - at = strchr (uri_string, '@'); - if (at && at < path) { - colon = strchr (uri_string, ':'); - if (colon && colon < at) { - uri->password = soup_uri_decoded_copy (colon + 1, - at - colon - 1, NULL); - } else { - uri->password = NULL; - colon = at; - } - - uri->user = soup_uri_decoded_copy (uri_string, - colon - uri_string, NULL); - uri_string = at + 1; - } else - uri->user = uri->password = NULL; - - /* Find host and port. */ - if (*uri_string == '[') { - const char *pct; - - uri_string++; - hostend = strchr (uri_string, ']'); - if (!hostend || hostend > path) { - soup_uri_free (uri); - return NULL; - } - if (*(hostend + 1) == ':') - colon = hostend + 1; - else - colon = NULL; + base_guri = soup_uri_to_g_uri (base, FALSE, 0); + guri = g_uri_parse_relative (base_guri, uri_string, G_URI_ENCODED | G_URI_HAS_PASSWORD, NULL); + if (base_guri) + g_uri_unref (base_guri); - pct = memchr (uri_string, '%', hostend - uri_string); - if (!pct || (pct[1] == '2' && pct[2] == '5')) { - uri->host = soup_uri_decoded_copy (uri_string, - hostend - uri_string, NULL); - } else - uri->host = g_strndup (uri_string, hostend - uri_string); - } else { - colon = memchr (uri_string, ':', path - uri_string); - hostend = colon ? colon : path; - uri->host = soup_uri_decoded_copy (uri_string, - hostend - uri_string, NULL); - } - - if (colon && colon != path - 1) { - char *portend; - uri->port = strtoul (colon + 1, &portend, 10); - if (portend != (char *)path) { - soup_uri_free (uri); - return NULL; - } - } - - uri_string = path; - } - - /* Find query */ - question = memchr (uri_string, '?', end - uri_string); - if (question) { - uri->query = uri_normalized_copy (question + 1, - end - (question + 1), - NULL); - end = question; - } - - if (end != uri_string) { - uri->path = uri_normalized_copy (uri_string, end - uri_string, - NULL); - } - - /* Apply base URI. This is spelled out in RFC 3986. */ - if (base && !uri->scheme && uri->host) - uri->scheme = base->scheme; - else if (base && !uri->scheme) { - uri->scheme = base->scheme; - uri->user = g_strdup (base->user); - uri->password = g_strdup (base->password); - uri->host = g_strdup (base->host); - uri->port = base->port; - - if (!uri->path) { - uri->path = g_strdup (base->path); - if (!uri->query) - uri->query = g_strdup (base->query); - remove_dot_segments = FALSE; - } else if (*uri->path != '/') { - char *newpath, *last; - - last = strrchr (base->path, '/'); - if (last) { - newpath = g_strdup_printf ("%.*s%s", - (int)(last + 1 - base->path), - base->path, - uri->path); - } else - newpath = g_strdup_printf ("/%s", uri->path); - - g_free (uri->path); - uri->path = newpath; - } - } - - if (remove_dot_segments && uri->path && *uri->path) { - char *p, *q; - - /* Remove "./" where "." is a complete segment. */ - for (p = uri->path + 1; *p; ) { - if (*(p - 1) == '/' && - *p == '.' && *(p + 1) == '/') - memmove (p, p + 2, strlen (p + 2) + 1); - else - p++; - } - /* Remove "." at end. */ - if (p > uri->path + 2 && - *(p - 1) == '.' && *(p - 2) == '/') - *(p - 1) = '\0'; - - /* Remove "<segment>/../" where <segment> != ".." */ - for (p = uri->path + 1; *p; ) { - if (!strncmp (p, "../", 3)) { - p += 3; - continue; - } - q = strchr (p + 1, '/'); - if (!q) - break; - if (strncmp (q, "/../", 4) != 0) { - p = q + 1; - continue; - } - memmove (p, q + 4, strlen (q + 4) + 1); - p = uri->path + 1; - } - /* Remove "<segment>/.." at end where <segment> != ".." */ - q = strrchr (uri->path, '/'); - if (q && !strcmp (q, "/..")) { - p = q - 1; - while (p > uri->path && *p != '/') - p--; - if (strncmp (p, "/../", 4) != 0) - *(p + 1) = 0; - } + if (!guri) + return NULL; - /* Remove extraneous initial "/.."s */ - while (!strncmp (uri->path, "/../", 4)) - memmove (uri->path, uri->path + 3, strlen (uri->path) - 2); - if (!strcmp (uri->path, "/..")) - uri->path[1] = '\0'; - } + uri = soup_uri_from_g_uri (guri); + g_uri_unref (guri); - /* HTTP-specific stuff */ + /* HTTP-specific fixes */ if (uri->scheme == SOUP_URI_SCHEME_HTTP || uri->scheme == SOUP_URI_SCHEME_HTTPS) { - if (!uri->path) + if (!*uri->path) { + g_free (uri->path); uri->path = g_strdup ("/"); + } if (!SOUP_URI_VALID_FOR_HTTP (uri)) { soup_uri_free (uri); return NULL; @@ -461,8 +267,6 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string) if (!uri->port) uri->port = soup_scheme_default_port (uri->scheme); - if (!uri->path) - uri->path = g_strdup (""); return uri; } @@ -581,7 +385,28 @@ soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query, char * soup_uri_to_string (SoupURI *uri, gboolean just_path_and_query) { - return soup_uri_to_string_internal (uri, just_path_and_query, FALSE); + GUri *guri; + char *ret; + + g_return_val_if_fail (uri != NULL, NULL); + + if (!SOUP_URI_IS_VALID (uri)) { + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + return g_strdup (""); + } + + if (just_path_and_query) { + guri = g_uri_build (G_URI_ENCODED, + NULL, NULL, NULL, 0, + uri->path, uri->query, NULL); + } else + guri = soup_uri_to_g_uri (uri, soup_uri_uses_default_port (uri), 0); + g_return_val_if_fail (guri != NULL, NULL); + + ret = g_uri_to_string_partial (guri, G_URI_HIDE_PASSWORD); + g_uri_unref (guri); + + return ret; } /** @@ -916,7 +741,7 @@ 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->scheme = g_intern_string (scheme); uri->port = soup_scheme_default_port (uri->scheme); } |