guri: new URI parsing and generating functions

Add a set of new URI parsing and generating functions, including a new
parsed-URI type GUri. Move all the code from gurifuncs.c into guri.c,
reimplementing some of those functions (and
g_string_append_uri_encoded()) in terms of the new code.
This commit is contained in:
Dan Winship
2013-09-21 17:15:00 -04:00
parent 7f5c862e16
commit 7ed12e6d4d
14 changed files with 3291 additions and 457 deletions

View File

@@ -80,7 +80,7 @@
<xi:include href="xml/timers.xml" />
<xi:include href="xml/spawn.xml" />
<xi:include href="xml/fileutils.xml" />
<xi:include href="xml/gurifuncs.xml" />
<xi:include href="xml/guri.xml" />
<xi:include href="xml/ghostutils.xml" />
<xi:include href="xml/shell.xml" />
<xi:include href="xml/option.xml" />

View File

@@ -2856,19 +2856,60 @@ g_base64_decode_inplace
<SECTION>
<TITLE>URI Functions</TITLE>
<FILE>gurifuncs</FILE>
<FILE>guri</FILE>
GUri
g_uri_ref
g_uri_unref
<SUBSECTION>
GUriFlags
g_uri_split
g_uri_split_with_user
g_uri_split_network
g_uri_is_valid
g_uri_join
g_uri_join_with_user
g_uri_parse
g_uri_parse_relative
g_uri_resolve_relative
g_uri_build
g_uri_build_with_user
g_uri_peek_scheme
g_uri_parse_scheme
<SUBSECTION>
GUriHideFlags;
g_uri_to_string
g_uri_to_string_partial
<SUBSECTION>
g_uri_get_scheme
g_uri_get_userinfo
g_uri_get_user
g_uri_get_password
g_uri_get_auth_params
g_uri_get_host
g_uri_get_port
g_uri_get_path
g_uri_get_query
g_uri_get_fragment
<SUBSECTION>
g_uri_parse_params
<SUBSECTION>
G_URI_RESERVED_CHARS_ALLOWED_IN_PATH
G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT
G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO
G_URI_RESERVED_CHARS_GENERIC_DELIMITERS
G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS
g_uri_parse_scheme
g_uri_escape_string
g_uri_unescape_string
g_uri_unescape_segment
<SUBSECTION>
g_uri_list_extract_uris
g_filename_from_uri
g_filename_to_uri
<SUBSECTION>
G_URI_ERROR
GUriError
<SUBSECTION Private>
g_uri_error_quark
</SECTION>
<SECTION>

View File

@@ -390,6 +390,7 @@ G_TYPE_MARKUP_PARSE_CONTEXT
G_TYPE_SOURCE
G_TYPE_POLLFD
G_TYPE_THREAD
G_TYPE_URI
GStrv
<SUBSECTION Standard>

View File

@@ -184,7 +184,7 @@ libglib_2_0_la_SOURCES = \
gunidecomp.h \
gunidecomp.c \
gunicodeprivate.h \
gurifuncs.c \
guri.c \
gutils.c \
gvariant.h \
gvariant.c \
@@ -304,7 +304,7 @@ glibsubinclude_HEADERS = \
gtree.h \
gtypes.h \
gunicode.h \
gurifuncs.h \
guri.h \
gutils.h \
gvarianttype.h \
gvariant.h \

View File

@@ -88,7 +88,7 @@
#include <glib/gtree.h>
#include <glib/gtypes.h>
#include <glib/gunicode.h>
#include <glib/gurifuncs.h>
#include <glib/guri.h>
#include <glib/gutils.h>
#include <glib/gvarianttype.h>
#include <glib/gvariant.h>

View File

@@ -495,90 +495,6 @@ g_string_insert_len (GString *string,
return string;
}
#define SUB_DELIM_CHARS "!$&'()*+,;="
static gboolean
is_valid (char c,
const char *reserved_chars_allowed)
{
if (g_ascii_isalnum (c) ||
c == '-' ||
c == '.' ||
c == '_' ||
c == '~')
return TRUE;
if (reserved_chars_allowed &&
strchr (reserved_chars_allowed, c) != NULL)
return TRUE;
return FALSE;
}
static gboolean
gunichar_ok (gunichar c)
{
return
(c != (gunichar) -2) &&
(c != (gunichar) -1);
}
/**
* g_string_append_uri_escaped:
* @string: a #GString
* @unescaped: a string
* @reserved_chars_allowed: a string of reserved characters allowed
* to be used, or %NULL
* @allow_utf8: set %TRUE if the escaped string may include UTF8 characters
*
* Appends @unescaped to @string, escaped any characters that
* are reserved in URIs using URI-style escape sequences.
*
* Returns: @string
*
* Since: 2.16
*/
GString *
g_string_append_uri_escaped (GString *string,
const gchar *unescaped,
const gchar *reserved_chars_allowed,
gboolean allow_utf8)
{
unsigned char c;
const gchar *end;
static const gchar hex[16] = "0123456789ABCDEF";
g_return_val_if_fail (string != NULL, NULL);
g_return_val_if_fail (unescaped != NULL, NULL);
end = unescaped + strlen (unescaped);
while ((c = *unescaped) != 0)
{
if (c >= 0x80 && allow_utf8 &&
gunichar_ok (g_utf8_get_char_validated (unescaped, end - unescaped)))
{
int len = g_utf8_skip [c];
g_string_append_len (string, unescaped, len);
unescaped += len;
}
else if (is_valid (c, reserved_chars_allowed))
{
g_string_append_c (string, c);
unescaped++;
}
else
{
g_string_append_c (string, '%');
g_string_append_c (string, hex[((guchar)c) >> 4]);
g_string_append_c (string, hex[((guchar)c) & 0xf]);
unescaped++;
}
}
return string;
}
/**
* g_string_append:
* @string: a #GString

220
glib/guri-notes.txt Normal file
View File

@@ -0,0 +1,220 @@
aaa/aaas (rfc3588):
aaa://host[:port][;transport=tcp][;protocol=diameter]
technically violates 3986, since ";" could appear in authority
acap (rfc2244):
acap://[user[;AUTH=mech]@]host[:port]/data
cap (rfc4324):
cap://host[:port][/data]
cid/mid (rfc2392):
cid:content-id-data
mid:message-id-data[/content-id-data]
crid (rfc4078):
crid://host/data
data (rfc2397):
data:[type/subtype][;attr=value]*[;base64],data
dav (rfc4918):
dav:data
opaquelocktoken:uuid[path]
dict (rfc2229):
dict://[user[;authmech]@]host[:port]/d:word[:database[:nth]]
dict://[user[;authmech]@]host[:port]/m:word[:database[:strategy[:nth]]]
dns (rfc4501):
dns:[//host[:port]/]name[?[attr=value[;attr=value]*]]
file (rfc1738):
file://[host]/path
ftp (rfc1738):
ftp://[user[:pass]@]host[:port][/path[;type=type]]
geo (draft...):
geo:data
go (rfc3368):
go:[//host[:port]?]data[;attr=[type,]value]*
gopher (rfc4266):
gopher://host[:port]/path
h323 (rfc3508):
h323:[user@]host[:port][;params]*
http (rfc 2616):
http://host[:port][/path[?query]]
https (rfc 2818):
https://host[:port][/path[?query]]
iax (rfc 5456):
iax:[user@]host[:port][/number[?context]]
icap (rfc3507):
icap://[userinfo@]host[:port]/path[?query]
im (rfc3860):
im:mailbox[?[header=value[;header=value]*]]
imap (rfc5092):
imap://[user[;AUTH=mech]@]host[:port][/[mailbox[validity]]]
imap://[user[;AUTH=mech]@]host[:port]/mailbox[validity]?search
imap://[user[;AUTH=mech]@]host[:port]/mailbox[validity]uid[sect][part][auth]
info (rfc4452):
info:namespace/identifier[#fragment]
ipp (rfc3510):
ipp://host[:port][/path[?query]]
iris (rfc3981, 3983, 4992, 4993):
iris[.transport]:urn/[method]/[userinfo@]host[:port][/class/name]
ldap (rfc4516):
ldap://[host[:port]][/dn[?[attrs][?[scope][?[filter][?exts]]]]]
mailto (rfc2368):
mailto:mailbox[?[header=value[;header=value]*]]
msrp (rfc4975):
msrp://authority[/id];tcp[;attr=value]*
msrps://authority[/id];tcp[;attr=value]*
technically violates 3986, since ";" could appear in authority
mtqp (rfc3887):
mtqp://authority/track/id/secret
mupdate (rfc3656):
based on imap
news/nntp (rfc5538):
news:[//authority/]article-or-groups
nntp://authority/group[/article]
nfs (rfc2224):
nfs://host[:port][path]
pop (rfc2384):
pop://[[user][;auth=mech]@]host[:port]
pres (rfc3859):
pres:mailbox[?[header=value[;header=value]*]]
rtsp (rfc2326):
rtsp://host[:port][path]
rtspu://host[:port][path]
service (rfc2609):
service:... (possibly including authority)
shttp (rfc2660):
http-ish
sieve (draft...):
sieve://authority[path]
sip (3261)
sip:[user[:pass]@]host[:port][;name=val]*[?hname=hval[&hname=hval]*]
sips:[user[:pass]@]host[:port][;name=val]*[?hname=hval[&hname=hval]*]
sms (5724)
sms:phone[,phone]*[?name=val[&name=val]*]
snmp (4088)
snmp://[userinfo@]host[:port][/context...]
soap.beep (4227)
standard
tag (4151)
tag:host-or-email,8601date:data[#fragment]
tel (3966)
tel:number[;attr=value]*
telnet (4248)
telnet://[user[:pass]@]host[:port][/]
tftp (3617)
tftp://host/file[;mode=type]
tip (2371)
tip://host[:port]/path?trans
tv (2838)
tv:dnsid
urn (2141)
urn:data
vemmi (2122)
vemmi://host[:port]/service[;attr=val]*
xmlrpc.beep (3529)
standard
xmpp (5122)
xmpp:[//node@host[/]][[node@]host[/resource]][?query[;attr=val]*][#fragment]
x39.50 (2056)
z39.50r://host[:port][/[database[?docid]][;esn=data][;rs=data]]
z39.50s://host[:port][/[database[?docid]][;esn=data][;rs=data]]
HTML5 rules:
- strip leading and trailing spaces
- chars less than U+0020 or greater than U+007F in unreserved
- U+0022, U+003C, U+003E, U+005B..E, U+0060, U+007B..D in unreserved
( " < > [ \ ] ^ ` { | } ~ )
- Allow single % except in hostname
- Allow # in fragment
- if host has non-UTF8 %-encoded, fail
- if host fails IDNA ToASCII, fail
- forcibly %-encode all reserved/non-ASCII path chars
- re-encode query to the URL's encoding (from enclosing doc) and
%-encode. replace unencodable chars with '?'
- if fully-resolved URI uses authority, replace all \ with /
gvfs and EUri both allow '@' in username
EUri does "parameters", but seems unused
hide_password in to_string
CamelURL does hide_auth too
CamelURL does params and uses them
CamelURL special-cases file URLs on win32 (via g_filename_to/from_uri)
http://www.freedesktop.org/wiki/Specifications/file-uri-spec says:
non-ASCII chars are %-encoded
URIs are in filesystem encoding, NOT UTF-8
accept "file:/path" for compat
http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx:
IE allows "file://" + windows path (eg, "file://D:\blah blah\bl%h")
file://// == file://
don't use %-encoding for non-ASCII, just use non-ASCII.
(http://en.wikipedia.org/wiki/File_URI_scheme contradicts this?)
IE allows "|" instead of ":" for drive separator, but very deprecated
MUST NOT use %-encoding where not required
Bug 489862 - Basic URI operations
https://bugzilla.gnome.org/show_bug.cgi?id=489862
Bug 620417 - g_uri_unescape_string cannot unescape %00
https://bugzilla.gnome.org/show_bug.cgi?id=620417
Bug 611687 - gconvert g_filename_to_uri doesn't do what the documentation says
https://bugzilla.gnome.org/show_bug.cgi?id=611687
Bug 550110 - RFC: g_uri_is_valid (from GStreamer gst_uri_is_valid)
https://bugzilla.gnome.org/show_bug.cgi?id=550110
Add fireball URI matcher
(make sure it does email addresses too)

2323
glib/guri.c Normal file

File diff suppressed because it is too large Load Diff

286
glib/guri.h Normal file
View File

@@ -0,0 +1,286 @@
/* GLIB - Library of useful routines for C programming
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Copyright 2010-2013 Red Hat, Inc.
*/
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#ifndef __G_URI_H__
#define __G_URI_H__
#include <glib/gtypes.h>
G_BEGIN_DECLS
typedef struct _GUri GUri;
GLIB_AVAILABLE_IN_2_44
GUri * g_uri_ref (GUri *uri);
GLIB_AVAILABLE_IN_2_44
void g_uri_unref (GUri *uri);
typedef enum {
G_URI_PARSE_STRICT = 1 << 0,
G_URI_HAS_PASSWORD = 1 << 1,
G_URI_HAS_AUTH_PARAMS = 1 << 2,
G_URI_ENCODED = 1 << 3,
G_URI_NON_DNS = 1 << 4,
} GUriFlags;
GLIB_AVAILABLE_IN_2_44
gboolean g_uri_split (const gchar *uri_string,
GUriFlags flags,
gchar **scheme,
gchar **userinfo,
gchar **host,
gint *port,
gchar **path,
gchar **query,
gchar **fragment,
GError **error);
GLIB_AVAILABLE_IN_2_44
gboolean g_uri_split_with_user (const gchar *uri_string,
GUriFlags flags,
gchar **scheme,
gchar **user,
gchar **password,
gchar **auth_params,
gchar **host,
gint *port,
gchar **path,
gchar **query,
gchar **fragment,
GError **error);
GLIB_AVAILABLE_IN_2_44
gboolean g_uri_split_network (const gchar *uri_string,
GUriFlags flags,
gchar **scheme,
gchar **host,
gint *port,
GError **error);
GLIB_AVAILABLE_IN_2_44
gboolean g_uri_is_valid (const gchar *uri_string,
GUriFlags flags,
GError **error);
GLIB_AVAILABLE_IN_2_44
gchar * g_uri_join (GUriFlags flags,
const gchar *scheme,
const gchar *userinfo,
const gchar *host,
gint port,
const gchar *path,
const gchar *query,
const gchar *fragment);
GLIB_AVAILABLE_IN_2_44
gchar * g_uri_join_with_user (GUriFlags flags,
const gchar *scheme,
const gchar *user,
const gchar *password,
const gchar *auth_params,
const gchar *host,
gint port,
const gchar *path,
const gchar *query,
const gchar *fragment);
GLIB_AVAILABLE_IN_2_44
GUri * g_uri_parse (const gchar *uri_string,
GUriFlags flags,
GError **error);
GLIB_AVAILABLE_IN_2_44
GUri * g_uri_parse_relative (GUri *base_uri,
const gchar *uri_string,
GUriFlags flags,
GError **error);
GLIB_AVAILABLE_IN_2_44
gchar * g_uri_resolve_relative (const gchar *base_uri_string,
const gchar *uri_string,
GUriFlags flags,
GError **error);
GLIB_AVAILABLE_IN_2_44
GUri * g_uri_build (GUriFlags flags,
const gchar *scheme,
const gchar *userinfo,
const gchar *host,
gint port,
const gchar *path,
const gchar *query,
const gchar *fragment);
GLIB_AVAILABLE_IN_2_44
GUri * g_uri_build_with_user (GUriFlags flags,
const gchar *scheme,
const gchar *user,
const gchar *password,
const gchar *auth_params,
const gchar *host,
gint port,
const gchar *path,
const gchar *query,
const gchar *fragment);
typedef enum {
G_URI_HIDE_USERINFO = 1 << 0,
G_URI_HIDE_PASSWORD = 1 << 1,
G_URI_HIDE_AUTH_PARAMS = 1 << 2,
G_URI_HIDE_FRAGMENT = 1 << 3,
} GUriHideFlags;
GLIB_AVAILABLE_IN_2_44
char * g_uri_to_string (GUri *uri);
GLIB_AVAILABLE_IN_2_44
char * g_uri_to_string_partial (GUri *uri,
GUriHideFlags flags);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_scheme (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_userinfo (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_user (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_password (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_auth_params (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_host (GUri *uri);
GLIB_AVAILABLE_IN_2_44
gint g_uri_get_port (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_path (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_query (GUri *uri);
GLIB_AVAILABLE_IN_2_44
const gchar *g_uri_get_fragment (GUri *uri);
GLIB_AVAILABLE_IN_2_44
GHashTable * g_uri_parse_params (const gchar *params,
gssize length,
gchar separator,
gboolean case_insensitive);
/**
* G_URI_ERROR:
*
* Error domain for URI methods. Errors in this domain will be from
* the #GUriError enumeration. See #GError for information on error
* domains.
*/
#define G_URI_ERROR (g_uri_error_quark ())
GLIB_AVAILABLE_IN_2_44
GQuark g_uri_error_quark (void);
/**
* GUriError:
* @G_URI_ERROR_MISC: miscellaneous error
* @G_URI_ERROR_BAD_SCHEME: the scheme of a URI could not be parsed.
* @G_URI_ERROR_BAD_USER: the user/userinfo of a URI could not be parsed.
* @G_URI_ERROR_BAD_PASSWORD: the password of a URI could not be parsed.
* @G_URI_ERROR_BAD_AUTH_PARAMS: the authentication parameters of a URI could not be parsed.
* @G_URI_ERROR_BAD_HOST: the host of a URI could not be parsed.
* @G_URI_ERROR_BAD_PORT: the port of a URI could not be parsed.
* @G_URI_ERROR_BAD_PATH: the path of a URI could not be parsed.
* @G_URI_ERROR_BAD_QUERY: the query of a URI could not be parsed.
* @G_URI_ERROR_BAD_FRAGMENT: the fragment of a URI could not be parsed.
*
* Error codes returned by #GUri methods.
*/
typedef enum
{
G_URI_ERROR_MISC,
G_URI_ERROR_BAD_SCHEME,
G_URI_ERROR_BAD_USER,
G_URI_ERROR_BAD_PASSWORD,
G_URI_ERROR_BAD_AUTH_PARAMS,
G_URI_ERROR_BAD_HOST,
G_URI_ERROR_BAD_PORT,
G_URI_ERROR_BAD_PATH,
G_URI_ERROR_BAD_QUERY,
G_URI_ERROR_BAD_FRAGMENT
} GUriError;
/**
* G_URI_RESERVED_CHARS_GENERIC_DELIMITERS:
*
* Generic delimiters characters as defined in RFC 3986. Includes ":/?#[]@".
**/
#define G_URI_RESERVED_CHARS_GENERIC_DELIMITERS ":/?#[]@"
/**
* G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS:
*
* Subcomponent delimiter characters as defined in RFC 3986. Includes "!$&'()*+,;=".
**/
#define G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS "!$&'()*+,;="
/**
* G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT:
*
* Allowed characters in path elements. Includes "!$&'()*+,;=:@".
**/
#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":@"
/**
* G_URI_RESERVED_CHARS_ALLOWED_IN_PATH:
*
* Allowed characters in a path. Includes "!$&'()*+,;=:@/".
**/
#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT "/"
/**
* G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO:
*
* Allowed characters in userinfo as defined in RFC 3986. Includes "!$&'()*+,;=:".
**/
#define G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":"
GLIB_AVAILABLE_IN_ALL
char * g_uri_unescape_string (const char *escaped_string,
const char *illegal_characters);
GLIB_AVAILABLE_IN_ALL
char * g_uri_unescape_segment (const char *escaped_string,
const char *escaped_string_end,
const char *illegal_characters);
GLIB_DEPRECATED_IN_2_44_FOR(g_uri_peek_scheme)
char * g_uri_parse_scheme (const char *uri);
GLIB_AVAILABLE_IN_2_44
const char *g_uri_peek_scheme (const char *uri);
GLIB_AVAILABLE_IN_ALL
char * g_uri_escape_string (const char *unescaped,
const char *reserved_chars_allowed,
gboolean allow_utf8);
GLIB_AVAILABLE_IN_2_44
GBytes * g_uri_unescape_bytes (const char *escaped_string,
gssize length,
const char *illegal_characters);
GLIB_AVAILABLE_IN_2_44
char * g_uri_escape_bytes (const guchar *unescaped,
gsize length,
const char *reserved_chars_allowed);
G_END_DECLS
#endif /* __G_URI_H__ */

View File

@@ -1,252 +0,0 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include "gurifuncs.h"
#include <glib/gstrfuncs.h>
#include <glib/gmessages.h>
#include <glib/gstring.h>
#include <glib/gmem.h>
#include <string.h>
#include "config.h"
/**
* SECTION:gurifuncs
* @title: URI Functions
* @short_description: manipulating URIs
*
* Functions for manipulating Universal Resource Identifiers (URIs) as
* defined by
* [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
* It is highly recommended that you have read and
* understand RFC 3986 for understanding this API.
*/
static int
unescape_character (const char *scanner)
{
int first_digit;
int second_digit;
first_digit = g_ascii_xdigit_value (*scanner++);
if (first_digit < 0)
return -1;
second_digit = g_ascii_xdigit_value (*scanner++);
if (second_digit < 0)
return -1;
return (first_digit << 4) | second_digit;
}
/**
* g_uri_unescape_segment:
* @escaped_string: (allow-none): A string, may be %NULL
* @escaped_string_end: (allow-none): Pointer to end of @escaped_string, may be %NULL
* @illegal_characters: (allow-none): An optional string of illegal characters not to be allowed, may be %NULL
*
* Unescapes a segment of an escaped string.
*
* If any of the characters in @illegal_characters or the character zero appears
* as an escaped character in @escaped_string then that is an error and %NULL
* will be returned. This is useful it you want to avoid for instance having a
* slash being expanded in an escaped path element, which might confuse pathname
* handling.
*
* Returns: an unescaped version of @escaped_string or %NULL on error.
* The returned string should be freed when no longer needed. As a
* special case if %NULL is given for @escaped_string, this function
* will return %NULL.
*
* Since: 2.16
**/
char *
g_uri_unescape_segment (const char *escaped_string,
const char *escaped_string_end,
const char *illegal_characters)
{
const char *in;
char *out, *result;
gint character;
if (escaped_string == NULL)
return NULL;
if (escaped_string_end == NULL)
escaped_string_end = escaped_string + strlen (escaped_string);
result = g_malloc (escaped_string_end - escaped_string + 1);
out = result;
for (in = escaped_string; in < escaped_string_end; in++)
{
character = *in;
if (*in == '%')
{
in++;
if (escaped_string_end - in < 2)
{
/* Invalid escaped char (to short) */
g_free (result);
return NULL;
}
character = unescape_character (in);
/* Check for an illegal character. We consider '\0' illegal here. */
if (character <= 0 ||
(illegal_characters != NULL &&
strchr (illegal_characters, (char)character) != NULL))
{
g_free (result);
return NULL;
}
in++; /* The other char will be eaten in the loop header */
}
*out++ = (char)character;
}
*out = '\0';
return result;
}
/**
* g_uri_unescape_string:
* @escaped_string: an escaped string to be unescaped.
* @illegal_characters: (allow-none): a string of illegal characters not to be
* allowed, or %NULL.
*
* Unescapes a whole escaped string.
*
* If any of the characters in @illegal_characters or the character zero appears
* as an escaped character in @escaped_string then that is an error and %NULL
* will be returned. This is useful it you want to avoid for instance having a
* slash being expanded in an escaped path element, which might confuse pathname
* handling.
*
* Returns: an unescaped version of @escaped_string. The returned string
* should be freed when no longer needed.
*
* Since: 2.16
**/
char *
g_uri_unescape_string (const char *escaped_string,
const char *illegal_characters)
{
return g_uri_unescape_segment (escaped_string, NULL, illegal_characters);
}
/**
* g_uri_parse_scheme:
* @uri: a valid URI.
*
* Gets the scheme portion of a URI string. RFC 3986 decodes the scheme as:
* |[
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
* ]|
* Common schemes include "file", "http", "svn+ssh", etc.
*
* Returns: The "Scheme" component of the URI, or %NULL on error.
* The returned string should be freed when no longer needed.
*
* Since: 2.16
**/
char *
g_uri_parse_scheme (const char *uri)
{
const char *p;
char c;
g_return_val_if_fail (uri != NULL, NULL);
/* From RFC 3986 Decodes:
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
*/
p = uri;
/* Decode scheme:
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
*/
if (!g_ascii_isalpha (*p))
return NULL;
while (1)
{
c = *p++;
if (c == ':')
break;
if (!(g_ascii_isalnum(c) ||
c == '+' ||
c == '-' ||
c == '.'))
return NULL;
}
return g_strndup (uri, p - uri - 1);
}
/**
* g_uri_escape_string:
* @unescaped: the unescaped input string.
* @reserved_chars_allowed: (allow-none): a string of reserved characters that
* are allowed to be used, or %NULL.
* @allow_utf8: %TRUE if the result can include UTF-8 characters.
*
* Escapes a string for use in a URI.
*
* Normally all characters that are not "unreserved" (i.e. ASCII alphanumerical
* characters plus dash, dot, underscore and tilde) are escaped.
* But if you specify characters in @reserved_chars_allowed they are not
* escaped. This is useful for the "reserved" characters in the URI
* specification, since those are allowed unescaped in some portions of
* a URI.
*
* Returns: an escaped version of @unescaped. The returned string should be
* freed when no longer needed.
*
* Since: 2.16
**/
char *
g_uri_escape_string (const char *unescaped,
const char *reserved_chars_allowed,
gboolean allow_utf8)
{
GString *s;
g_return_val_if_fail (unescaped != NULL, NULL);
s = g_string_sized_new (strlen (unescaped) + 10);
g_string_append_uri_escaped (s, unescaped, reserved_chars_allowed, allow_utf8);
return g_string_free (s, FALSE);
}

View File

@@ -1,83 +0,0 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#ifndef __G_URI_FUNCS_H__
#define __G_URI_FUNCS_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
/**
* G_URI_RESERVED_CHARS_GENERIC_DELIMITERS:
*
* Generic delimiters characters as defined in RFC 3986. Includes ":/?#[]@".
**/
#define G_URI_RESERVED_CHARS_GENERIC_DELIMITERS ":/?#[]@"
/**
* G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS:
*
* Subcomponent delimiter characters as defined in RFC 3986. Includes "!$&'()*+,;=".
**/
#define G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS "!$&'()*+,;="
/**
* G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT:
*
* Allowed characters in path elements. Includes "!$&'()*+,;=:@".
**/
#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":@"
/**
* G_URI_RESERVED_CHARS_ALLOWED_IN_PATH:
*
* Allowed characters in a path. Includes "!$&'()*+,;=:@/".
**/
#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT "/"
/**
* G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO:
*
* Allowed characters in userinfo as defined in RFC 3986. Includes "!$&'()*+,;=:".
**/
#define G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":"
GLIB_AVAILABLE_IN_ALL
char * g_uri_unescape_string (const char *escaped_string,
const char *illegal_characters);
GLIB_AVAILABLE_IN_ALL
char * g_uri_unescape_segment (const char *escaped_string,
const char *escaped_string_end,
const char *illegal_characters);
GLIB_AVAILABLE_IN_ALL
char * g_uri_parse_scheme (const char *uri);
GLIB_AVAILABLE_IN_ALL
char * g_uri_escape_string (const char *unescaped,
const char *reserved_chars_allowed,
gboolean allow_utf8);
G_END_DECLS
#endif /* __G_URI_FUNCS_H__ */

View File

@@ -33,10 +33,10 @@ typedef struct
char *hostname;
char *expected_result;
GConvertError expected_error; /* If failed */
} ToUriTest;
} FileToUriTest;
ToUriTest
to_uri_tests[] = {
FileToUriTest
file_to_uri_tests[] = {
{ "/etc", NULL, "file:///etc"},
{ "/etc", "", "file:///etc"},
{ "/etc", "otherhost", "file://otherhost/etc"},
@@ -101,10 +101,10 @@ typedef struct
char *expected_filename;
char *expected_hostname;
GConvertError expected_error; /* If failed */
} FromUriTest;
} FileFromUriTest;
FromUriTest
from_uri_tests[] = {
FileFromUriTest
file_from_uri_tests[] = {
{ "file:///etc", "/etc"},
{ "file:/etc", "/etc"},
#ifdef G_OS_WIN32
@@ -163,23 +163,23 @@ from_uri_tests[] = {
};
static void
run_to_uri_tests (void)
run_file_to_uri_tests (void)
{
int i;
gchar *res;
GError *error;
for (i = 0; i < G_N_ELEMENTS (to_uri_tests); i++)
for (i = 0; i < G_N_ELEMENTS (file_to_uri_tests); i++)
{
error = NULL;
res = g_filename_to_uri (to_uri_tests[i].filename,
to_uri_tests[i].hostname,
res = g_filename_to_uri (file_to_uri_tests[i].filename,
file_to_uri_tests[i].hostname,
&error);
if (res)
g_assert_cmpstr (res, ==, to_uri_tests[i].expected_result);
g_assert_cmpstr (res, ==, file_to_uri_tests[i].expected_result);
else
g_assert_error (error, G_CONVERT_ERROR, to_uri_tests[i].expected_error);
g_assert_error (error, G_CONVERT_ERROR, file_to_uri_tests[i].expected_error);
g_free (res);
g_clear_error (&error);
@@ -187,25 +187,26 @@ run_to_uri_tests (void)
}
static void
run_from_uri_tests (void)
run_file_from_uri_tests (void)
{
int i;
gchar *res;
gchar *hostname;
GError *error;
for (i = 0; i < G_N_ELEMENTS (from_uri_tests); i++)
for (i = 0; i < G_N_ELEMENTS (file_from_uri_tests); i++)
{
error = NULL;
res = g_filename_from_uri (from_uri_tests[i].uri,
res = g_filename_from_uri (file_from_uri_tests[i].uri,
&hostname,
&error);
#ifdef G_OS_WIN32
if (from_uri_tests[i].expected_filename)
if (file_from_uri_tests[i].expected_filename)
{
gchar *p, *slash;
p = from_uri_tests[i].expected_filename = g_strdup (from_uri_tests[i].expected_filename);
p = file_from_uri_tests[i].expected_filename =
g_strdup (file_from_uri_tests[i].expected_filename);
while ((slash = strchr (p, '/')) != NULL)
{
*slash = '\\';
@@ -214,10 +215,10 @@ run_from_uri_tests (void)
}
#endif
if (res)
g_assert_cmpstr (res, ==, from_uri_tests[i].expected_filename);
g_assert_cmpstr (res, ==, file_from_uri_tests[i].expected_filename);
else
g_assert_error (error, G_CONVERT_ERROR, from_uri_tests[i].expected_error);
g_assert_cmpstr (hostname, ==, from_uri_tests[i].expected_hostname);
g_assert_error (error, G_CONVERT_ERROR, file_from_uri_tests[i].expected_error);
g_assert_cmpstr (hostname, ==, file_from_uri_tests[i].expected_hostname);
g_free (res);
g_free (hostname);
@@ -266,20 +267,20 @@ safe_strcmp_hostname (const gchar *a, const gchar *b)
}
static void
run_roundtrip_tests (void)
run_file_roundtrip_tests (void)
{
int i;
gchar *uri, *hostname, *res;
GError *error;
for (i = 0; i < G_N_ELEMENTS (to_uri_tests); i++)
for (i = 0; i < G_N_ELEMENTS (file_to_uri_tests); i++)
{
if (to_uri_tests[i].expected_error != 0)
if (file_to_uri_tests[i].expected_error != 0)
continue;
error = NULL;
uri = g_filename_to_uri (to_uri_tests[i].filename,
to_uri_tests[i].hostname,
uri = g_filename_to_uri (file_to_uri_tests[i].filename,
file_to_uri_tests[i].hostname,
&error);
g_assert_no_error (error);
@@ -287,8 +288,8 @@ run_roundtrip_tests (void)
res = g_filename_from_uri (uri, &hostname, &error);
g_assert_no_error (error);
g_assert (safe_strcmp_filename (to_uri_tests[i].filename, res) == 0);
g_assert (safe_strcmp_hostname (to_uri_tests[i].hostname, hostname) == 0);
g_assert (safe_strcmp_filename (file_to_uri_tests[i].filename, res) == 0);
g_assert (safe_strcmp_hostname (file_to_uri_tests[i].hostname, hostname) == 0);
g_free (res);
g_free (uri);
g_free (hostname);
@@ -364,15 +365,391 @@ test_uri_escape (void)
static void
test_uri_scheme (void)
{
const gchar *s1, *s2;
gchar *s;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
s = g_uri_parse_scheme ("ftp://ftp.gtk.org");
g_assert_cmpstr (s, ==, "ftp");
g_free (s);
s = g_uri_parse_scheme ("1bad:");
g_assert (s == NULL);
g_assert_cmpstr (s, ==, NULL);
s = g_uri_parse_scheme ("bad");
g_assert (s == NULL);
g_assert_cmpstr (s, ==, NULL);
G_GNUC_END_IGNORE_DEPRECATIONS;
s1 = g_uri_peek_scheme ("ftp://ftp.gtk.org");
g_assert_cmpstr (s1, ==, "ftp");
s2 = g_uri_peek_scheme ("FTP://ftp.gtk.org");
g_assert_cmpstr (s2, ==, "ftp");
g_assert_true (s1 == s2);
s1 = g_uri_peek_scheme ("1bad:");
g_assert_cmpstr (s, ==, NULL);
s1 = g_uri_peek_scheme ("bad");
g_assert_cmpstr (s, ==, NULL);
}
typedef struct {
const gchar *scheme;
const gchar *userinfo;
const gchar *host;
gint port;
const gchar *path;
const gchar *query;
const gchar *fragment;
} UriParts;
typedef struct {
const gchar *orig;
const UriParts parts;
} UriAbsoluteTest;
static const UriAbsoluteTest absolute_tests[] = {
{ "foo:",
{ "foo", NULL, NULL, -1, "", NULL, NULL }
},
{ "file:/dev/null",
{ "file", NULL, NULL, -1, "/dev/null", NULL, NULL }
},
{ "file:///dev/null",
{ "file", NULL, "", -1, "/dev/null", NULL, NULL }
},
{ "ftp://user@host/path",
{ "ftp", "user", "host", -1, "/path", NULL, NULL }
},
{ "ftp://user@host:9999/path",
{ "ftp", "user", "host", 9999, "/path", NULL, NULL }
},
{ "ftp://user:password@host/path",
{ "ftp", "user:password", "host", -1, "/path", NULL, NULL }
},
{ "ftp://user:password@host:9999/path",
{ "ftp", "user:password", "host", 9999, "/path", NULL, NULL }
},
{ "ftp://user:password@host",
{ "ftp", "user:password", "host", -1, "", NULL, NULL }
},
{ "http://us%65r@host",
{ "http", "user", "host", -1, "", NULL, NULL }
},
{ "http://us%40r@host",
{ "http", "us@r", "host", -1, "", NULL, NULL }
},
{ "http://us%3ar@host",
{ "http", "us:r", "host", -1, "", NULL, NULL }
},
{ "http://us%2fr@host",
{ "http", "us/r", "host", -1, "", NULL, NULL }
},
{ "http://us%3fr@host",
{ "http", "us?r", "host", -1, "", NULL, NULL }
},
{ "http://host?query",
{ "http", NULL, "host", -1, "", "query", NULL }
},
{ "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue&param=value",
{ "http", NULL, "host", -1, "/path", "query=http://host/path?childparam=childvalue&param=value", NULL }
},
{ "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F",
{ "http", NULL, "control-chars", -1, "/\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F", NULL, NULL }
},
{ "http://space/%20",
{ "http", NULL, "space", -1, "/ ", NULL, NULL }
},
{ "http://delims/%3C%3E%23%25%22",
{ "http", NULL, "delims", -1, "/<>#%\"", NULL, NULL }
},
{ "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60",
{ "http", NULL, "unwise-chars", -1, "/{}|\\^[]`", NULL, NULL }
},
/* From RFC 2732 */
{ "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html",
{ "http", NULL, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80, "/index.html", NULL, NULL }
},
{ "http://[1080:0:0:0:8:800:200C:417A]/index.html",
{ "http", NULL, "1080:0:0:0:8:800:200C:417A", -1, "/index.html", NULL, NULL }
},
{ "http://[3ffe:2a00:100:7031::1]",
{ "http", NULL, "3ffe:2a00:100:7031::1", -1, "", NULL, NULL }
},
{ "http://[1080::8:800:200C:417A]/foo",
{ "http", NULL, "1080::8:800:200C:417A", -1, "/foo", NULL, NULL }
},
{ "http://[::192.9.5.5]/ipng",
{ "http", NULL, "::192.9.5.5", -1, "/ipng", NULL, NULL }
},
{ "http://[::FFFF:129.144.52.38]:80/index.html",
{ "http", NULL, "::FFFF:129.144.52.38", 80, "/index.html", NULL, NULL }
},
{ "http://[2010:836B:4179::836B:4179]",
{ "http", NULL, "2010:836B:4179::836B:4179", -1, "", NULL, NULL }
},
#if 0
/* Try to recover certain kinds of invalid URIs */
{ "http://host/path with spaces",
{ "http", NULL, "host", -1, "/path%20with%20spaces", NULL, NULL }
"http://host/path%20with%20spaces",
},
{ " http://host/path",
{ "http", NULL, "host", -1, "/path", NULL, NULL }
"http://host/path"
},
{ "http://host/path ",
{ "http", NULL, "host", -1, "/path", NULL, NULL }
"http://host/path"
},
{ "http://host ",
{ "http", NULL, "host", -1, "", NULL, NULL }
"http://host"
},
{ "http://host:999 ",
{ "http", NULL, "host", 999, "", NULL, NULL }
"http://host:999"
},
{ "http://host/pa\nth",
{ "http", NULL, "host", -1, "/path", NULL, NULL }
"http://host/path"
},
{ "http:\r\n//host/path",
{ "http", NULL, "host", -1, "/path", NULL, NULL }
"http://host/path"
},
{ "http://\thost/path",
{ "http", NULL, "host", -1, "/path", NULL, NULL }
"http://host/path"
},
#endif
/* Bug 594405; 0-length is different from not-present */
{ "http://host/path?",
{ "http", NULL, "host", -1, "/path", "", NULL }
},
{ "http://host/path#",
{ "http", NULL, "host", -1, "/path", NULL, "" },
},
/* Bug 590524; ignore bad %-encoding */
{ "http://host/path%",
{ "http", NULL, "host", -1, "/path%", NULL, NULL }
},
{ "http://h%ost/path",
{ "http", NULL, "h%ost", -1, "/path", NULL, NULL }
},
{ "http://host/path%%",
{ "http", NULL, "host", -1, "/path%%", NULL, NULL }
},
{ "http://host/path%%%",
{ "http", NULL, "host", -1, "/path%%%", NULL, NULL }
},
{ "http://host/path%/x/",
{ "http", NULL, "host", -1, "/path%/x/", NULL, NULL }
},
{ "http://host/path%0x/",
{ "http", NULL, "host", -1, "/path%0x/", NULL, NULL }
},
{ "http://host/path%ax",
{ "http", NULL, "host", -1, "/path%ax", NULL, NULL }
},
#if 0
/* Bug 662806; %-encode non-ASCII characters */
{ "http://host/p\xc3\xa4th/",
{ "http", NULL, "host", -1, "/p%C3%A4th/", NULL, NULL }
{ "http", NULL, "host", -1, "/p%C3%A4th/", NULL, NULL }
},
#endif
{ "HTTP:////////////////",
{ "http", NULL, "", -1, "//////////////", NULL, NULL }
},
{ "http://@host",
{ "http", "", "host", -1, "", NULL, NULL }
},
{ "http://:@host",
{ "http", ":", "host", -1, "", NULL, NULL }
},
#if 0
{ "http://host/keep%00nuls",
{ "http", NULL, "host", -1, "/keep%00nuls", NULL, NULL }
},
#endif
/* IPv6 scope ID parsing (both correct and incorrect) */
{ "http://[fe80::dead:beef%em1]/",
{ "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL }
},
{ "http://[fe80::dead:beef%25em1]/",
{ "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL }
},
{ "http://[fe80::dead:beef%10]/",
{ "http", NULL, "fe80::dead:beef%10", -1, "/", NULL, NULL }
}
};
static int num_absolute_tests = G_N_ELEMENTS (absolute_tests);
static void
test_uri_parsing_absolute (void)
{
int i;
for (i = 0; i < num_absolute_tests; i++)
{
const UriAbsoluteTest *test = &absolute_tests[i];
GError *error = NULL;
GUri *uri;
uri = g_uri_parse (test->orig, 0, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_uri_get_scheme (uri), ==, test->parts.scheme);
g_assert_cmpstr (g_uri_get_userinfo (uri), ==, test->parts.userinfo);
g_assert_cmpstr (g_uri_get_host (uri), ==, test->parts.host);
g_assert_cmpint (g_uri_get_port (uri), ==, test->parts.port);
g_assert_cmpstr (g_uri_get_path (uri), ==, test->parts.path);
g_assert_cmpstr (g_uri_get_query (uri), ==, test->parts.query);
g_assert_cmpstr (g_uri_get_fragment (uri), ==, test->parts.fragment);
g_uri_unref (uri);
}
}
typedef struct {
const gchar *orig, *resolved;
UriParts parts;
} UriRelativeTest;
/* This all comes from RFC 3986 */
static const char *relative_test_base = "http://a/b/c/d;p?q";
static const UriRelativeTest relative_tests[] = {
{ "g:h", "g:h",
{ "g", NULL, NULL, -1, "h", NULL, NULL } },
{ "g", "http://a/b/c/g",
{ "http", NULL, "a", -1, "/b/c/g", NULL, NULL } },
{ "./g", "http://a/b/c/g",
{ "http", NULL, "a", -1, "/b/c/g", NULL, NULL } },
{ "g/", "http://a/b/c/g/",
{ "http", NULL, "a", -1, "/b/c/g/", NULL, NULL } },
{ "/g", "http://a/g",
{ "http", NULL, "a", -1, "/g", NULL, NULL } },
{ "//g", "http://g",
{ "http", NULL, "g", -1, "", NULL, NULL } },
{ "?y", "http://a/b/c/d;p?y",
{ "http", NULL, "a", -1, "/b/c/d;p", "y", NULL } },
{ "g?y", "http://a/b/c/g?y",
{ "http", NULL, "a", -1, "/b/c/g", "y", NULL } },
{ "#s", "http://a/b/c/d;p?q#s",
{ "http", NULL, "a", -1, "/b/c/d;p", "q", "s" } },
{ "g#s", "http://a/b/c/g#s",
{ "http", NULL, "a", -1, "/b/c/g", NULL, "s" } },
{ "g?y#s", "http://a/b/c/g?y#s",
{ "http", NULL, "a", -1, "/b/c/g", "y", "s" } },
{ ";x", "http://a/b/c/;x",
{ "http", NULL, "a", -1, "/b/c/;x", NULL, NULL } },
{ "g;x", "http://a/b/c/g;x",
{ "http", NULL, "a", -1, "/b/c/g;x", NULL, NULL } },
{ "g;x?y#s", "http://a/b/c/g;x?y#s",
{ "http", NULL, "a", -1, "/b/c/g;x", "y", "s" } },
{ ".", "http://a/b/c/",
{ "http", NULL, "a", -1, "/b/c/", NULL, NULL } },
{ "./", "http://a/b/c/",
{ "http", NULL, "a", -1, "/b/c/", NULL, NULL } },
{ "..", "http://a/b/",
{ "http", NULL, "a", -1, "/b/", NULL, NULL } },
{ "../", "http://a/b/",
{ "http", NULL, "a", -1, "/b/", NULL, NULL } },
{ "../g", "http://a/b/g",
{ "http", NULL, "a", -1, "/b/g", NULL, NULL } },
{ "../..", "http://a/",
{ "http", NULL, "a", -1, "/", NULL, NULL } },
{ "../../", "http://a/",
{ "http", NULL, "a", -1, "/", NULL, NULL } },
{ "../../g", "http://a/g",
{ "http", NULL, "a", -1, "/g", NULL, NULL } },
{ "", "http://a/b/c/d;p?q",
{ "http", NULL, "a", -1, "/b/c/d;p", "q", NULL } },
{ "../../../g", "http://a/g",
{ "http", NULL, "a", -1, "/g", NULL, NULL } },
{ "../../../../g", "http://a/g",
{ "http", NULL, "a", -1, "/g", NULL, NULL } },
{ "/./g", "http://a/g",
{ "http", NULL, "a", -1, "/g", NULL, NULL } },
{ "/../g", "http://a/g",
{ "http", NULL, "a", -1, "/g", NULL, NULL } },
{ "g.", "http://a/b/c/g.",
{ "http", NULL, "a", -1, "/b/c/g.", NULL, NULL } },
{ ".g", "http://a/b/c/.g",
{ "http", NULL, "a", -1, "/b/c/.g", NULL, NULL } },
{ "g..", "http://a/b/c/g..",
{ "http", NULL, "a", -1, "/b/c/g..", NULL, NULL } },
{ "..g", "http://a/b/c/..g",
{ "http", NULL, "a", -1, "/b/c/..g", NULL, NULL } },
{ "./../g", "http://a/b/g",
{ "http", NULL, "a", -1, "/b/g", NULL, NULL } },
{ "./g/.", "http://a/b/c/g/",
{ "http", NULL, "a", -1, "/b/c/g/", NULL, NULL } },
{ "g/./h", "http://a/b/c/g/h",
{ "http", NULL, "a", -1, "/b/c/g/h", NULL, NULL } },
{ "g/../h", "http://a/b/c/h",
{ "http", NULL, "a", -1, "/b/c/h", NULL, NULL } },
{ "g;x=1/./y", "http://a/b/c/g;x=1/y",
{ "http", NULL, "a", -1, "/b/c/g;x=1/y", NULL, NULL } },
{ "g;x=1/../y", "http://a/b/c/y",
{ "http", NULL, "a", -1, "/b/c/y", NULL, NULL } },
{ "g?y/./x", "http://a/b/c/g?y/./x",
{ "http", NULL, "a", -1, "/b/c/g", "y/./x", NULL } },
{ "g?y/../x", "http://a/b/c/g?y/../x",
{ "http", NULL, "a", -1, "/b/c/g", "y/../x", NULL } },
{ "g#s/./x", "http://a/b/c/g#s/./x",
{ "http", NULL, "a", -1, "/b/c/g", NULL, "s/./x" } },
{ "g#s/../x", "http://a/b/c/g#s/../x",
{ "http", NULL, "a", -1, "/b/c/g", NULL, "s/../x" } },
{ "http:g", "http:g",
{ "http", NULL, NULL, -1, "g", NULL, NULL } }
};
static int num_relative_tests = G_N_ELEMENTS (relative_tests);
static void
test_uri_parsing_relative (void)
{
int i;
GUri *base;
GError *error = NULL;
base = g_uri_parse (relative_test_base, 0, &error);
g_assert_no_error (error);
for (i = 0; i < num_relative_tests; i++)
{
const UriRelativeTest *test = &relative_tests[i];
gchar *tostring, *resolved;
GUri *uri;
uri = g_uri_parse_relative (base, test->orig, 0, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_uri_get_scheme (uri), ==, test->parts.scheme);
g_assert_cmpstr (g_uri_get_userinfo (uri), ==, test->parts.userinfo);
g_assert_cmpstr (g_uri_get_host (uri), ==, test->parts.host);
g_assert_cmpint (g_uri_get_port (uri), ==, test->parts.port);
g_assert_cmpstr (g_uri_get_path (uri), ==, test->parts.path);
g_assert_cmpstr (g_uri_get_query (uri), ==, test->parts.query);
g_assert_cmpstr (g_uri_get_fragment (uri), ==, test->parts.fragment);
tostring = g_uri_to_string (uri);
g_assert_cmpstr (tostring, ==, test->resolved);
g_free (tostring);
g_uri_unref (uri);
resolved = g_uri_resolve_relative (relative_test_base, test->orig, 0, &error);
g_assert_no_error (error);
g_assert_cmpstr (resolved, ==, test->resolved);
g_free (resolved);
}
}
int
@@ -381,13 +758,15 @@ main (int argc,
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/uri/to-uri", run_to_uri_tests);
g_test_add_func ("/uri/from-uri", run_from_uri_tests);
g_test_add_func ("/uri/roundtrip", run_roundtrip_tests);
g_test_add_func ("/uri/file-to-uri", run_file_to_uri_tests);
g_test_add_func ("/uri/file-from-uri", run_file_from_uri_tests);
g_test_add_func ("/uri/file-roundtrip", run_file_roundtrip_tests);
g_test_add_func ("/uri/list", run_uri_list_tests);
g_test_add_func ("/uri/unescape", test_uri_unescape);
g_test_add_func ("/uri/escape", test_uri_escape);
g_test_add_func ("/uri/scheme", test_uri_scheme);
g_test_add_func ("/uri/parsing/absolute", test_uri_parsing_absolute);
g_test_add_func ("/uri/parsing/relative", test_uri_parsing_relative);
return g_test_run ();
}

View File

@@ -164,6 +164,7 @@ G_DEFINE_BOXED_TYPE (GMarkupParseContext, g_markup_parse_context, g_markup_parse
G_DEFINE_BOXED_TYPE (GThread, g_thread, g_thread_ref, g_thread_unref)
G_DEFINE_BOXED_TYPE (GChecksum, g_checksum, g_checksum_copy, g_checksum_free)
G_DEFINE_BOXED_TYPE (GUri, g_uri, g_uri_ref, g_uri_unref)
/* This one can't use G_DEFINE_BOXED_TYPE (GStrv, g_strv, g_strdupv, g_strfreev) */
GType

View File

@@ -342,6 +342,8 @@ GLIB_AVAILABLE_IN_2_36
GType g_markup_parse_context_get_type (void) G_GNUC_CONST;
GLIB_AVAILABLE_IN_2_40
GType g_mapped_file_get_type (void) G_GNUC_CONST;
GLIB_AVAILABLE_IN_2_40
GType g_uri_get_type (void) G_GNUC_CONST;
GLIB_DEPRECATED_FOR('G_TYPE_VARIANT')
GType g_variant_get_gtype (void) G_GNUC_CONST;