Example #1
0
/**
 * soup_uri_uses_default_port:
 * @uri: a #SoupURI
 *
 * Tests if @uri uses the default port for its scheme. (Eg, 80 for
 * http.) (This only works for http, https and ftp; libsoup does not know
 * the default ports of other protocols.)
 *
 * Return value: %TRUE or %FALSE
 **/
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);
}
Example #2
0
/**
 * soup_uri_uses_default_port:
 * @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
 * the default ports of other protocols.)
 *
 * Return value: %TRUE or %FALSE
 **/
gboolean
soup_uri_uses_default_port (SoupURI *uri)
{
	g_return_val_if_fail (uri->scheme == SOUP_URI_SCHEME_HTTP ||
			      uri->scheme == SOUP_URI_SCHEME_HTTPS, FALSE);

	return uri->port == soup_scheme_default_port (uri->scheme);
}
Example #3
0
/**
 * soup_uri_set_scheme:
 * @uri: a #SoupURI
 * @scheme: the URI scheme
 *
 * Sets @uri's scheme to @scheme. This will also set @uri's port to
 * the default port for @scheme, if known.
 **/
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);
}
/**
 * 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)
{
	GString *str;
	char *return_result;

	g_return_val_if_fail (uri != NULL, NULL);
	g_warn_if_fail (SOUP_URI_IS_VALID (uri));

	str = g_string_sized_new (20);

	if (uri->scheme && !just_path_and_query)
		g_string_append_printf (str, "%s:", uri->scheme);
	if (uri->host && !just_path_and_query) {
		g_string_append (str, "//");
		if (uri->user) {
			append_uri_encoded (str, uri->user, ":;@?/");
			g_string_append_c (str, '@');
		}
		if (strchr (uri->host, ':')) {
			g_string_append_c (str, '[');
			g_string_append (str, uri->host);
			g_string_append_c (str, ']');
		} else
			append_uri_encoded (str, uri->host, ":/");
		if (uri->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, '?');
		g_string_append (str, uri->query);
	}
	if (uri->fragment && !just_path_and_query) {
		g_string_append_c (str, '#');
		g_string_append (str, uri->fragment);
	}

	return_result = str->str;
	g_string_free (str, FALSE);

	return return_result;
}
Example #5
0
/**
 * 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)
{
	GString *str;
	char *return_result;

	g_return_val_if_fail (uri != NULL, NULL);

	/* IF YOU CHANGE ANYTHING IN THIS FUNCTION, RUN
	 * tests/uri-parsing AFTERWARD.
	 */

	str = g_string_sized_new (20);

	if (uri->scheme && !just_path_and_query)
		g_string_append_printf (str, "%s:", uri->scheme);
	if (uri->host && !just_path_and_query) {
		g_string_append (str, "//");
		if (uri->user) {
			append_uri_encoded (str, uri->user, ":;@?/");
			g_string_append_c (str, '@');
		}
		if (strchr (uri->host, ':')) {
			g_string_append_c (str, '[');
			g_string_append (str, uri->host);
			g_string_append_c (str, ']');
		} else
			append_uri_encoded (str, uri->host, ":/");
		if (uri->port && uri->port != soup_scheme_default_port (uri->scheme))
			g_string_append_printf (str, ":%d", uri->port);
		if (!uri->path && (uri->query || uri->fragment))
			g_string_append_c (str, '/');
	}

	if (uri->path && *uri->path)
		g_string_append (str, uri->path);

	if (uri->query) {
		g_string_append_c (str, '?');
		g_string_append (str, uri->query);
	}
	if (uri->fragment && !just_path_and_query) {
		g_string_append_c (str, '#');
		g_string_append (str, uri->fragment);
	}

	return_result = str->str;
	g_string_free (str, FALSE);

	return return_result;
}
Example #6
0
/**
 * soup_uri_set_scheme:
 * @uri: a #SoupURI
 * @scheme: the URI scheme
 *
 * Sets @uri's scheme to @scheme. This will also set @uri's port to
 * the default port for @scheme, if known.
 **/
void
soup_uri_set_scheme (SoupURI *uri, const char *scheme)
{
	uri->scheme = soup_uri_parse_scheme (scheme, strlen (scheme));
	uri->port = soup_scheme_default_port (uri->scheme);
}
Example #7
0
/**
 * soup_uri_new_with_base:
 * @base: a base URI
 * @uri_string: the URI
 *
 * Parses @uri_string relative to @base.
 *
 * Return value: a parsed #SoupURI.
 **/
SoupURI *
soup_uri_new_with_base (SoupURI *base, const char *uri_string)
{
	SoupURI *uri;
	const char *end, *hash, *colon, *at, *path, *question;
	const char *p, *hostend;
	gboolean remove_dot_segments = TRUE;
	int len;

	/* 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: initial [a-z+.-]* substring until ":" */
	p = uri_string;
	while (p < end && (g_ascii_isalnum (*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)
		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 = uri_decoded_copy (colon + 1,
								  at - colon - 1);
			} else {
				uri->password = NULL;
				colon = at;
			}

			uri->user = uri_decoded_copy (uri_string,
						      colon - uri_string);
			uri_string = at + 1;
		} else
			uri->user = uri->password = NULL;

		/* Find host and port. */
		if (*uri_string == '[') {
			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;
		} else {
			colon = memchr (uri_string, ':', path - uri_string);
			hostend = colon ? colon : path;
		}

		uri->host = uri_decoded_copy (uri_string, hostend - uri_string);

		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;
		}

		/* 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';
	}

	/* HTTP-specific stuff */
	if (uri->scheme == SOUP_URI_SCHEME_HTTP ||
	    uri->scheme == SOUP_URI_SCHEME_HTTPS) {
		if (!uri->path)
			uri->path = g_strdup ("/");
		if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
			soup_uri_free (uri);
			return NULL;
		}
	}

	if (uri->scheme == SOUP_URI_SCHEME_FTP) {
		if (!uri->host) {
			soup_uri_free (uri);
			return NULL;
		}
	}

	if (!uri->port)
		uri->port = soup_scheme_default_port (uri->scheme);
	if (!uri->path)
		uri->path = g_strdup ("");

	return uri;
}
Example #8
0
char *
soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query,
                             gboolean include_password, 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));

    str = g_string_sized_new (40);

    if (uri->scheme && !just_path_and_query)
        g_string_append_printf (str, "%s:", uri->scheme);
    if (uri->host && !just_path_and_query) {
        g_string_append (str, "//");
        if (uri->user) {
            append_uri_encoded (str, uri->user, ":;@?/");
            if (uri->password && include_password) {
                g_string_append_c (str, ':');
                append_uri_encoded (str, uri->password, ";@?/");
            }
            g_string_append_c (str, '@');
        }
        if (strchr (uri->host, ':')) {
            const char *pct;

            g_string_append_c (str, '[');
            pct = strchr (uri->host, '%');
            if (pct) {
                g_string_append_printf (str, "%.*s%%25%s",
                                        (int) (pct - uri->host),
                                        uri->host, pct + 1);
            } else
                g_string_append (str, uri->host);
            g_string_append_c (str, ']');
        } else
            append_uri_encoded (str, uri->host, ":/");
        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, '?');
        g_string_append (str, uri->query);
    }
    if (uri->fragment && !just_path_and_query) {
        g_string_append_c (str, '#');
        g_string_append (str, uri->fragment);
    }

    return_result = str->str;
    g_string_free (str, FALSE);

    return return_result;
}
Example #9
0
/**
 * soup_uri_new_with_base:
 * @base: a base URI
 * @uri_string: the URI
 *
 * Parses @uri_string relative to @base.
 *
 * Return value: a parsed #SoupURI.
 **/
SoupURI *
soup_uri_new_with_base (SoupURI *base, const char *uri_string)
{
	SoupURI *uri;
	const char *end, *hash, *colon, *at, *path, *question;
	const char *p, *hostend;
	gboolean remove_dot_segments = TRUE;

	uri = g_slice_new0 (SoupURI);

	/* See RFC 3986 for details. IF YOU CHANGE ANYTHING IN THIS
	 * FUNCTION, RUN tests/uri-parsing AFTERWARDS.
	 */

	/* Find fragment. */
	end = hash = strchr (uri_string, '#');
	if (hash && hash[1]) {
		uri->fragment = uri_normalized_copy (hash + 1, strlen (hash + 1),
						     NULL, FALSE);
		if (!uri->fragment) {
			soup_uri_free (uri);
			return NULL;
		}
	} else
		end = uri_string + strlen (uri_string);

	/* Find scheme: initial [a-z+.-]* substring until ":" */
	p = uri_string;
	while (p < end && (g_ascii_isalnum (*p) ||
			   *p == '.' || *p == '+' || *p == '-'))
		p++;

	if (p > uri_string && *p == ':') {
		uri->scheme = soup_uri_get_scheme (uri_string, p - uri_string);
		if (!uri->scheme) {
			soup_uri_free (uri);
			return NULL;
		}
		uri_string = p + 1;
	}

	if (!*uri_string && !base)
		return uri;

	/* Check for authority */
	if (strncmp (uri_string, "//", 2) == 0) {
		uri_string += 2;

		path = uri_string + strcspn (uri_string, "/?#");
		at = strchr (uri_string, '@');
		if (at && at < path) {
			colon = strchr (uri_string, ':');
			if (colon && colon < at) {
				uri->password = uri_decoded_copy (colon + 1,
								  at - colon - 1);
				if (!uri->password) {
					soup_uri_free (uri);
					return NULL;
				}
			} else {
				uri->password = NULL;
				colon = at;
			}

			uri->user = uri_decoded_copy (uri_string,
						      colon - uri_string);
			if (!uri->user) {
				soup_uri_free (uri);
				return NULL;
			}
			uri_string = at + 1;
		} else
			uri->user = uri->password = NULL;

		/* Find host and port. */
		if (*uri_string == '[') {
			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;
		} else {
			colon = memchr (uri_string, ':', path - uri_string);
			hostend = colon ? colon : path;
		}

		uri->host = uri_decoded_copy (uri_string, hostend - uri_string);
		if (!uri->host) {
			soup_uri_free (uri);
			return 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) {
		if (question[1]) {
			uri->query = uri_normalized_copy (question + 1,
							  end - (question + 1),
							  NULL, TRUE);
			if (!uri->query) {
				soup_uri_free (uri);
				return NULL;
			}
		}
		end = question;
	}

	if (end != uri_string) {
		uri->path = uri_normalized_copy (uri_string, end - uri_string,
						 NULL, TRUE);
		if (!uri->path) {
			soup_uri_free (uri);
			return NULL;
		}
	}

	/* Apply base URI. Again, 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 - 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 = uri->path, *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;
		}

		/* 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';
	}

	/* HTTP-specific stuff */
	if (uri->scheme == SOUP_URI_SCHEME_HTTP ||
	    uri->scheme == SOUP_URI_SCHEME_HTTPS) {
		if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
			soup_uri_free (uri);
			return NULL;
		}
		if (!uri->path)
			uri->path = g_strdup ("/");
	}

	if (!uri->port)
		uri->port = soup_scheme_default_port (uri->scheme);
	if (!uri->path)
		uri->path = g_strdup ("");

	return uri;
}