1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
19 #include "deployment.h"
23 /* see rfc1738, section 2.2 */
25 is_unsafe (unsigned char c
)
27 if (c
<= 0x1f || c
>= 0x7f)
51 uri_params_clear (Uri::Param
**params
)
53 Uri::Param
*next
, *param
= *params
;
57 g_free (param
->value
);
67 uri_params_copy (Uri::Param
*params
)
69 Uri::Param
*list
, *param
, *cur
, *tail
;
72 tail
= (Uri::Param
*) &list
;
76 param
= g_new (Uri::Param
, 1);
77 param
->value
= g_strdup (cur
->value
);
78 param
->name
= g_strdup (cur
->name
);
91 uri_params_equal (Uri::Param
*params0
, Uri::Param
*params1
)
93 // Note: this might need to be changed to allow params out of order
94 Uri::Param
*p0
= params0
;
95 Uri::Param
*p1
= params1
;
98 if (!p1
|| strcmp (p0
->name
, p1
->name
) != 0
99 || strcmp (p0
->value
, p1
->value
) != 0)
124 originalString
= g_strdup("");
128 Uri::Uri (const Uri
& uri
)
140 originalString
= NULL
;
143 Uri::Copy (&uri
, this);
154 g_free (scheme
); scheme
= NULL
;
155 g_free (user
); user
= NULL
;
156 g_free (auth
); auth
= NULL
;
157 g_free (passwd
); passwd
= NULL
;
158 g_free (host
); host
= NULL
;
159 g_free (path
); path
= NULL
;
160 uri_params_clear (¶ms
);
161 g_free (query
); query
= NULL
;
162 g_free (fragment
); fragment
= NULL
;
163 g_free (originalString
); originalString
= NULL
;
168 Uri::Copy (const Uri
*from
, Uri
*to
)
171 to
->scheme
= g_strdup (from
->scheme
);
172 to
->user
= g_strdup (from
->user
);
173 to
->auth
= g_strdup (from
->auth
);
174 to
->passwd
= g_strdup (from
->passwd
);
175 to
->host
= g_strdup (from
->host
);
176 to
->port
= from
->port
;
177 to
->path
= g_strdup (from
->path
);
178 to
->params
= uri_params_copy (from
->params
);
179 to
->query
= g_strdup (from
->query
);
180 to
->fragment
= g_strdup (from
->fragment
);
181 to
->originalString
= g_strdup (from
->originalString
);
182 to
->isAbsolute
= from
->isAbsolute
;
193 to
->originalString
= NULL
;
194 to
->isAbsolute
= false;
198 /* canonicalise a path */
200 canon_path (char *path
, bool allow_root
, bool allow_trailing_sep
)
202 register char *d
, *inptr
;
207 if (inptr
[0] == '/' && (inptr
[1] == '/' || (inptr
[1] == '\0' && !allow_trailing_sep
)))
213 if (!allow_root
&& (d
== path
+ 1) && d
[-1] == '/')
215 else if (allow_root
&& d
== path
&& path
[0] == '/')
220 return path
[0] ? path
: NULL
;
223 struct path_component_t
{
229 flatten_path (const char *path
)
231 path_component_t part
;
242 parts
= g_array_new (false, false, sizeof (path_component_t
));
247 while (*inptr
== '/')
254 while (*inptr
&& *inptr
!= '/')
257 part
.len
= (size_t) (inptr
- part
.start
);
259 if (part
.len
== 2 && !strncmp (part
.start
, "..", 2)) {
260 // drop the most recent parent (if not ..)
261 if (parts
->len
> 0) {
262 path_component_t prev_part
= g_array_index (parts
, path_component_t
, parts
->len
- 1);
263 if (prev_part
.len
== 2 && !strncmp (prev_part
.start
, "..", 2)) {
273 } else if (part
.len
== 1 && !strncmp (part
.start
, ".", 1)) {
274 // drop this path component
276 } else if (part
.len
> 0) {
277 // keep track of this component
282 g_array_append_val (parts
, part
);
287 // at this point, n is the char count of all path components (minus separators)
289 p
= result
= (char *) g_malloc (n
+ 2);
294 for (i
= 0; i
< parts
->len
; i
++) {
295 part
= g_array_index (parts
, path_component_t
, i
);
296 memcpy (p
, part
.start
, part
.len
);
302 if (p
> result
&& inptr
> path
&& inptr
[-1] != '/')
305 g_array_free (parts
, true);
310 #define HEXVAL(c) (isdigit ((int) ((unsigned char) c)) ? (c) - '0' : tolower ((unsigned char) c) - 'a' + 10)
312 #define is_xdigit(c) isxdigit ((int) ((unsigned char) c))
315 url_decode (char *in
, const char *url
)
317 register char *inptr
, *outptr
;
322 if (is_xdigit (inptr
[1]) && is_xdigit (inptr
[2])) {
323 *outptr
++ = HEXVAL (inptr
[1]) * 16 + HEXVAL (inptr
[2]);
326 g_warning ("Invalid encoding in url: %s at %s", url
, inptr
);
327 *outptr
++ = *inptr
++;
330 *outptr
++ = *inptr
++;
342 { "mms", 80 }, /* 1755 */
343 { "rtsp", 80 }, /* 554 */
344 { "rtsps", 80 }, /* 332 */
348 get_port_by_name (const char *name
)
352 for (i
= 0; i
< G_N_ELEMENTS (services
); i
++) {
353 if (!strcmp (services
[i
].name
, name
))
354 return services
[i
].port
;
361 Uri::Parse (const char *uri
, bool allow_trailing_sep
)
363 char *name
, *value
, *scheme
= NULL
, *user
= NULL
, *auth
= NULL
, *passwd
= NULL
, *host
= NULL
, *path
= NULL
, *query
= NULL
, *fragment
= NULL
;
364 Uri::Param
*param
, *tail
, *params
= NULL
;
365 register const char *start
, *inptr
;
367 bool parse_path
= false;
371 tail
= (Uri::Param
*) ¶ms
;
382 while (*inptr
&& *inptr
!= ':' && *inptr
!= '/' && *inptr
!= '?' && *inptr
!= '#' && *inptr
!= '\\')
385 if (inptr
> start
&& *inptr
== ':') {
386 scheme
= g_ascii_strdown (start
, inptr
- start
);
394 if (!strncmp (inptr
, "//", 2))
398 while (*inptr
&& *inptr
!= ';' && *inptr
!= ':' && *inptr
!= '@' && *inptr
!= '/')
401 isAbsolute
= !strncmp (inptr
, "\\\\", 2);
408 case ';': /* <user>;auth= */
409 case ':': /* <user>:passwd or <host>:port */
410 case '@': /* <user>@host */
412 user
= g_strndup (start
, inptr
- start
);
413 url_decode (user
, uri
);
417 case ';': /* ;auth= */
418 if (!g_ascii_strncasecmp (inptr
, ";auth=", 6)) {
421 while (*inptr
&& *inptr
!= ':' && *inptr
!= '@')
425 auth
= g_strndup (start
, inptr
- start
);
426 url_decode (auth
, uri
);
433 } else if (*inptr
== '@') {
440 case ':': /* <user>:passwd@ or <host>:port */
444 while (*inptr
&& *inptr
!= '@' && *inptr
!= '/')
450 passwd
= g_strndup (start
, inptr
- start
);
451 url_decode (passwd
, uri
);
466 case '@': /* <user>@host */
470 while (*inptr
&& *inptr
!= ':' && *inptr
!= '/')
475 while (n
> 0 && start
[n
- 1] == '.')
479 host
= g_ascii_strdown (start
, n
);
487 while (*inptr
>= '0' && *inptr
<= '9' && port
< 6554)
488 port
= (port
* 10) + ((*inptr
++) - '0');
491 /* chop off the last digit */
495 /* remove default port numbers */
496 if (scheme
&& port
== get_port_by_name (scheme
))
499 while (*inptr
&& *inptr
!= '/')
504 case '/': /* <host>/path or simply <host> */
508 while (n
> 0 && start
[n
- 1] == '.')
512 host
= g_ascii_strdown (start
, n
);
519 if (parse_path
|| *inptr
== '/') {
520 /* look for params, query, or fragment */
522 while (*inptr
&& *inptr
!= ';' && *inptr
!= '?' && *inptr
!= '#')
525 /* canonicalise and save the path component */
526 if ((n
= (inptr
- start
))) {
527 value
= g_strndup (start
, n
);
528 url_decode (value
, uri
);
530 if (!(path
= canon_path (value
, !host
, allow_trailing_sep
)))
534 value
= flatten_path (path
);
542 while (*inptr
== ';') {
543 while (*inptr
== ';')
547 while (*inptr
&& *inptr
!= '=' && *inptr
!= ';' && *inptr
!= '?' && *inptr
!= '#')
550 name
= g_strndup (start
, inptr
- start
);
551 url_decode (name
, uri
);
556 while (*inptr
&& *inptr
!= ';' && *inptr
!= '?' && *inptr
!= '#')
559 value
= g_strndup (start
, inptr
- start
);
560 url_decode (value
, uri
);
562 value
= g_strdup ("");
565 param
= g_new (Uri::Param
, 1);
566 param
->value
= value
;
575 goto decode_fragment
;
576 else if (*inptr
!= '?')
583 while (*inptr
&& *inptr
!= '#')
586 query
= g_strndup (start
, inptr
- start
);
587 url_decode (query
, uri
);
595 fragment
= g_strdup (inptr
+ 1);
596 url_decode (fragment
, uri
);
607 this->scheme
= scheme
;
610 this->passwd
= passwd
;
614 this->params
= params
;
616 this->fragment
= fragment
;
617 this->originalString
= g_strdup (uri
);
618 this->isAbsolute
= isAbsolute
;
624 Uri::Combine (const char *relative_path
)
626 Deployment
*deployment
= Deployment::GetCurrent ();
630 if (deployment
->IsLoadedFromXap () || relative_path
[0] != '/') {
631 // strip off the 'filename' component
632 if (!(p
= strrchr (path
, '/')))
636 // combine with the relative path
637 combined
= g_strdup_printf ("%s/%s", path
, relative_path
);
640 // flatten the resulting combined path
641 path
= flatten_path (combined
);
646 path
= flatten_path (relative_path
);
649 path
= flatten_path (relative_path
);
654 Uri::Combine (const Uri
*relative_uri
)
656 if (relative_uri
->isAbsolute
)
657 g_warning ("Uri::Combine (): Not a relative Uri");
658 if (relative_uri
->path
)
659 Combine (relative_uri
->path
);
663 append_url_encoded (GString
*string
, const char *in
, const char *extra
)
665 register const char *inptr
= in
;
670 while (*inptr
&& !is_unsafe (*inptr
) && !strchr (extra
, *inptr
))
673 g_string_append_len (string
, start
, inptr
- start
);
675 while (*inptr
&& (is_unsafe (*inptr
) || strchr (extra
, *inptr
)))
676 g_string_append_printf (string
, "%%%.02hhx", *inptr
++);
681 append_param (GString
*string
, Uri::Param
*param
)
683 g_string_append_c (string
, ';');
685 append_url_encoded (string
, param
->name
, "?=#");
687 if (param
->value
&& *param
->value
) {
688 g_string_append_c (string
, '=');
689 append_url_encoded (string
, param
->value
, "?;#");
694 Uri::ToString (UriToStringFlags flags
) const
700 string
= g_string_new ("");
703 g_string_append (string
, this->scheme
);
704 g_string_append (string
, "://");
707 append_url_encoded (string
, this->user
, ":;@/");
710 g_string_append (string
, ";auth=");
711 append_url_encoded (string
, this->auth
, ":@/");
714 if (this->passwd
&& !(flags
& UriHidePasswd
)) {
715 g_string_append_c (string
, ':');
716 append_url_encoded (string
, this->passwd
, "@/");
719 g_string_append_c (string
, '@');
722 g_string_append (string
, this->host
);
725 g_string_append_printf (string
, ":%d", this->port
);
729 if (this->host
&& *this->path
!= '/')
730 g_string_append_c (string
, '/');
732 append_url_encoded (string
, this->path
, " ;?#");
733 } else if (this->host
&& (this->params
|| this->query
|| this->fragment
)) {
734 g_string_append_c (string
, '/');
737 param
= this->params
;
739 append_param (string
, param
);
743 if (this->query
&& !(flags
& UriHideQuery
)) {
744 g_string_append_c (string
, '?');
745 append_url_encoded (string
, this->query
, "#");
748 if (this->fragment
&& !(flags
& UriHideFragment
)) {
749 g_string_append_c (string
, '#');
750 append_url_encoded (string
, this->fragment
, "");
754 g_string_free (string
, false);
760 Uri::operator== (const Uri
&v
) const
762 if (isAbsolute
!= v
.isAbsolute
)
766 if (!!scheme
!= !!v
.scheme
767 || (scheme
&& strcmp (scheme
, v
.scheme
)))
769 if (!!user
!= !!v
.user
770 || (user
&& strcmp (user
, v
.user
)))
772 if (!!auth
!= !!v
.auth
773 || (auth
&& strcmp (auth
, v
.auth
)))
775 if (!!passwd
!= !!v
.passwd
776 || (passwd
&& strcmp (passwd
, v
.passwd
)))
778 if (!!host
!= !!v
.host
779 || (host
&& strcmp (host
, v
.host
)))
781 if (!!path
!= !!v
.path
782 || (path
&& strcmp (path
, v
.path
)))
784 if (!!query
!= !!v
.query
785 || (query
&& strcmp (query
, v
.query
)))
787 if (!!fragment
!= !!v
.fragment
788 || (fragment
&& strcmp (fragment
, v
.fragment
)))
790 if (!uri_params_equal (params
, v
.params
))
793 // we intentionally don't compare original strings
798 Uri::Equals (const Uri
*left
, const Uri
*right
)
804 return left
->operator==(*right
);
808 Uri::IsNullOrEmpty (const Uri
*uri
)
810 if (!uri
|| (uri
->scheme
== NULL
&& uri
->user
== NULL
&& uri
->auth
== NULL
&&
811 uri
->passwd
== NULL
&& uri
->host
== NULL
&& uri
->port
== 0 && uri
->path
== NULL
812 && uri
->params
== NULL
&& uri
->query
== NULL
&& uri
->fragment
== NULL
&&
813 strcmp (uri
->originalString
, "") == 0 && !uri
->isAbsolute
))
822 char* str
= ToString();
823 guint hash
= g_str_hash (str
);
829 Uri::IsScheme (const char *scheme
) const
831 if (!!this->scheme
!= !!scheme
)
835 return !g_ascii_strcasecmp (this->scheme
, scheme
);
841 Uri::SameSiteOfOrigin (const Uri
*left
, const Uri
*right
)
843 // works only on absolute URI
844 if (!left
|| !left
->isAbsolute
|| !right
|| !right
->isAbsolute
)
847 if (left
->port
!= right
->port
)
850 if (!left
->scheme
|| !right
->scheme
|| (strcmp (left
->scheme
, right
->scheme
) != 0))
853 // comparing 2 file:/// URI where no hosts is present
854 if (!left
->host
&& !right
->host
&& (strcmp (left
->scheme
, "file") == 0))
857 if (!left
->host
|| !right
->host
|| (strcmp (left
->host
, right
->host
) != 0))