2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
28 #include "swfdec_url.h"
29 #include "swfdec_debug.h"
34 * @short_description: URL handling in Swfdec
36 * SwfdecURL is Swfdec's way of handling URLs. You probably don't need to mess
37 * with this type unless you want to write a #SwfdecLoader. In that case you
38 * will want to use swfdec_loader_get_url() to get its url and then use the
39 * functions in this section to access it.
41 * Note that URLs inside Swfdec mirror the behavior of Flash and will therefore
42 * not miror standards behavior, but the behavior of Flash.
44 * @see_also: #SwfdecLoader
50 * this is the structure used for URLs. It is a boxed type to glib's type system
51 * and it is not reference counted. It is also a static struct in that it cannot
52 * be modified after creation.
56 char * url
; /* the complete url */
57 char * protocol
; /* lowercase, http, file, rtmp, ... */
58 char * host
; /* lowercase, can be NULL for files */
59 guint port
; /* can be 0 */
60 char * path
; /* can be NULL for root path */
61 char * query
; /* can be NULL */
65 swfdec_url_get_type (void)
67 static GType type
= 0;
70 type
= g_boxed_type_register_static ("SwfdecURL",
71 (GBoxedCopyFunc
) swfdec_url_copy
, (GBoxedFreeFunc
) swfdec_url_free
);
78 * @string: a valid utf-8 string possibly containing an URL
80 * Parses the given string into a URL for use in swfdec.
82 * Returns: a new #SwfdecURL or %NULL if the URL was invalid
85 swfdec_url_new (const char *string
)
90 g_return_val_if_fail (string
!= NULL
, NULL
);
92 /* FIXME: error checking? */
93 SWFDEC_DEBUG ("new url: %s", string
);
94 url
= g_slice_new0 (SwfdecURL
);
95 url
->url
= g_strdup (string
);
96 s
= strstr (string
, "://");
98 SWFDEC_INFO ("URL %s has no protocol", string
);
101 url
->protocol
= g_utf8_strdown (string
, s
- string
);
103 s
= strchr (string
, '/');
106 url
->host
= g_ascii_strdown (string
, s
? s
- string
: -1);
107 colon
= strrchr (url
->host
, ':');
111 url
->port
= strtoul (colon
+ 1, &colon
, 10);
112 if (errno
|| *colon
!= 0) {
113 SWFDEC_INFO ("%s: invalid port number", string
);
121 s
= strchr (string
, '?');
123 url
->path
= *string
? g_strdup (string
) : NULL
;
126 url
->path
= g_strndup (string
, s
- string
);
129 url
->query
= g_strdup (s
);
133 swfdec_url_free (url
);
138 * swfdec_url_new_components:
139 * @protocol: protocol to use
140 * @hostname: hostname or IP address or %NULL
141 * @port: port number or 0. Must be 0 if no hostname is given
142 * @path: a path or %NULL
143 * @query: the query string or %NULL
145 * Creates a new URL from the given components.
147 * Returns: a new url pointing to the url from the given components
150 swfdec_url_new_components (const char *protocol
, const char *hostname
,
151 guint port
, const char *path
, const char *query
)
156 g_return_val_if_fail (protocol
!= NULL
, NULL
);
157 g_return_val_if_fail (hostname
!= NULL
|| port
== 0, NULL
);
158 g_return_val_if_fail (port
< 65536, NULL
);
160 url
= g_slice_new0 (SwfdecURL
);
161 str
= g_string_new ("");
164 url
->protocol
= g_ascii_strdown (protocol
, -1);
165 g_string_append (str
, url
->protocol
);
166 g_string_append (str
, "://");
168 /* hostname + port */
170 url
->host
= g_ascii_strdown (hostname
, -1);
172 g_string_append (str
, url
->host
);
174 g_string_append_printf (str
, ":%u", port
);
177 g_string_append (str
, "/");
181 url
->path
= g_strdup (path
);
182 g_string_append (str
, path
);
187 url
->query
= g_strdup (query
);
188 g_string_append (str
, "?");
189 g_string_append (str
, query
);
192 url
->url
= g_string_free (str
, FALSE
);
197 swfdec_url_path_to_parent_path (char *path
)
199 char *last
= strrchr (path
, '/');
204 if (last
[1] == '\0') {
206 return swfdec_url_path_to_parent_path (path
);
214 * swfdec_url_new_parent:
217 * Creates a new url that is the parent of @url. If the given @url has no
218 * parent, a copy of itself is returned.
220 * Returns: a new url pointing to the parent of @url or %NULL on failure.
223 swfdec_url_new_parent (const SwfdecURL
*url
)
228 path
= g_strdup (url
->path
);
230 if (!swfdec_url_path_to_parent_path (path
)) {
235 ret
= swfdec_url_new_components (url
->protocol
, url
->host
, url
->port
,
242 * swfdec_url_new_relative:
244 * @string: a relative or absolute URL path
246 * Parses @string into a new URL. If the given @string is a relative URL, it
247 * uses @url to resolve it to an absolute url; @url must already contain a
250 * Returns: a new #SwfdecURL or %NULL if an error was detected.
253 swfdec_url_new_relative (const SwfdecURL
*url
, const char *string
)
258 g_return_val_if_fail (url
!= NULL
, NULL
);
259 g_return_val_if_fail (string
!= NULL
, NULL
);
261 /* check for full-qualified URL */
262 if (strstr (string
, "://"))
263 return swfdec_url_new (string
);
265 if (string
[0] == '/') {
268 query
= strchr (string
, '?');
270 path
= *string
? g_strdup (string
) : NULL
;
272 path
= g_strndup (string
, query
- string
);
273 query
= g_strdup (query
+ 1);
277 char *cur
= g_strdup (url
->path
);
278 while (g_str_has_prefix (string
, "../")) {
279 if (cur
&& !swfdec_url_path_to_parent_path (cur
)) {
285 if (strstr (string
, "/../")) {
290 path
= g_strconcat (cur
, "/", string
, NULL
);
294 cur
= g_strdup (string
);
296 query
= strchr (cur
, '?');
298 path
= *string
? g_strdup (cur
) : NULL
;
300 path
= g_strndup (cur
, query
- cur
);
301 query
= g_strdup (query
+ 1);
305 ret
= swfdec_url_new_components (url
->protocol
, url
->host
, url
->port
,
316 * copies the given url.
318 * Returns: a new #SwfdecURL
321 swfdec_url_copy (const SwfdecURL
*url
)
325 g_return_val_if_fail (url
!= NULL
, NULL
);
327 copy
= g_slice_new0 (SwfdecURL
);
328 copy
->url
= g_strdup (url
->url
);
329 copy
->protocol
= g_strdup (url
->protocol
);
330 copy
->host
= g_strdup (url
->host
);
331 copy
->port
= url
->port
;
332 copy
->path
= g_strdup (url
->path
);
333 copy
->query
= g_strdup (url
->query
);
342 * Frees the URL and its associated ressources.
345 swfdec_url_free (SwfdecURL
*url
)
347 g_return_if_fail (url
!= NULL
);
350 g_free (url
->protocol
);
354 g_slice_free (SwfdecURL
, url
);
358 * swfdec_url_get_url:
361 * Gets the whole URL.
363 * Returns: the complete URL as string
366 swfdec_url_get_url (const SwfdecURL
*url
)
368 g_return_val_if_fail (url
!= NULL
, NULL
);
374 * swfdec_url_get_protocol:
377 * Gets the protocol used by this URL, such as "http" or "file".
379 * Returns: the protocol used or "error" if the URL is broken
382 swfdec_url_get_protocol (const SwfdecURL
*url
)
384 g_return_val_if_fail (url
!= NULL
, NULL
);
387 return url
->protocol
;
393 * swfdec_url_has_protocol:
395 * @protocol: protocol name to check for
397 * Checks if the given @url references the given @protocol
399 * Returns: %TRUE if both protocols match, %FALSE otherwise
402 swfdec_url_has_protocol (const SwfdecURL
*url
, const char *protocol
)
404 g_return_val_if_fail (url
!= NULL
, FALSE
);
405 g_return_val_if_fail (protocol
!= NULL
, FALSE
);
407 return g_str_equal (url
->protocol
, protocol
);
411 * swfdec_url_get_host:
414 * Gets the host for @url as a lower case string.
416 * Returns: the host or %NULL if none (typically for file URLs).
419 swfdec_url_get_host (const SwfdecURL
*url
)
421 g_return_val_if_fail (url
!= NULL
, NULL
);
427 * swfdec_url_get_port:
430 * Gets the port number specified by the given @url. If the @url does not
431 * specify a port number, 0 will be returned.
433 * Returns: the specified port or 0 if none was given.
436 swfdec_url_get_port (const SwfdecURL
*url
)
438 g_return_val_if_fail (url
!= NULL
, 0);
444 * swfdec_url_get_path:
447 * Gets the path associated with @url. If it contains no path, %NULL is
449 * <note>The returned path does not start with a slash. So in particular for
450 * files, you want to prepend the slash yourself.</note>
452 * Returns: the path or %NULL if none
455 swfdec_url_get_path (const SwfdecURL
*url
)
457 g_return_val_if_fail (url
!= NULL
, NULL
);
463 * swfdec_url_get_query:
466 * Gets the query string associated with @url. If the URL does not have a query
467 * string, %NULL is returned.
469 * Returns: Query string or %NULL
472 swfdec_url_get_query (const SwfdecURL
*url
)
474 g_return_val_if_fail (url
!= NULL
, NULL
);
480 * swfdec_url_is_parent:
481 * @parent: the supposed parent url
482 * @child: the supposed child url
484 * Checks if the given @parent url is a parent url of the given @child url. The
485 * algorithm used is the same as checking policy files if hey apply. If @parent
486 * equals @child, %TRUE is returned. This function does not compare query
489 * Returns: %TRUE if @parent is a parent of @child, %FALSE otherwise.
492 swfdec_url_is_parent (const SwfdecURL
*parent
, const SwfdecURL
*child
)
496 g_return_val_if_fail (parent
!= NULL
, FALSE
);
497 g_return_val_if_fail (child
!= NULL
, FALSE
);
499 if (!g_str_equal (parent
->protocol
, child
->protocol
))
501 if (parent
->host
== NULL
) {
502 if (child
->host
!= NULL
)
505 if (child
->host
== NULL
|| !g_str_equal (parent
->host
, child
->host
))
508 if (parent
->port
!= child
->port
)
510 if (parent
->path
== NULL
)
512 if (child
->path
== NULL
)
514 len
= strlen (parent
->path
);
515 if (strncmp (parent
->path
, child
->path
, len
) != 0)
517 return child
->path
[len
] == '\0' || child
->path
[len
] == '/';
521 * swfdec_url_is_local:
522 * @url: the url to check
524 * Checks if the given @url references a local resource. Local resources are
525 * treated differently by Flash, since they get a higher degree of trust.
527 * Returns: %TRUE if the given url is local.
530 swfdec_url_is_local (const SwfdecURL
*url
)
532 g_return_val_if_fail (url
!= NULL
, FALSE
);
534 /* FIXME: If we ever support gnome-vfs, this might become tricky */
535 return swfdec_url_has_protocol (url
, "file");
539 * swfdec_url_host_equal:
543 * Compares the 2 given URLs for equality, ignoring path. 2 URLs are
544 * considered to have equal hosts when they have the same protocol,
546 * Returns: %TRUE if the 2 given urls point to the same host, %FALSE
550 swfdec_url_host_equal (gconstpointer a
, gconstpointer b
)
552 const SwfdecURL
*urla
= a
;
553 const SwfdecURL
*urlb
= b
;
555 if (!swfdec_url_has_protocol (urla
, urlb
->protocol
))
558 if (urla
->host
== NULL
) {
559 if (urlb
->host
!= NULL
)
562 if (urlb
->host
== NULL
||
563 !g_str_equal (urla
->host
, urlb
->host
))
567 if (urla
->port
!= urlb
->port
)
578 * Compares the 2 given URLs for equality. 2 URLs are considered equal, when
579 * they point to the same resource. This function is intended to be
580 * used together with swfdec_url_hash() in a #GHashtable.
582 * Returns: %TRUE if the 2 given urls point to the same resource, %FALSE
586 swfdec_url_equal (gconstpointer a
, gconstpointer b
)
588 const SwfdecURL
*urla
= a
;
589 const SwfdecURL
*urlb
= b
;
591 if (!swfdec_url_host_equal (urla
, urlb
))
594 if (urla
->path
== NULL
) {
595 if (urlb
->path
!= NULL
)
598 if (urlb
->path
== NULL
||
599 !g_str_equal (urla
->path
, urlb
->path
))
603 /* FIXME: include query strings? */
604 if (urla
->query
== NULL
) {
605 if (urlb
->query
!= NULL
)
608 if (urlb
->query
== NULL
||
609 !g_str_equal (urla
->query
, urlb
->query
))
620 * Creates a hash value for the given @url. This function is intended to be
621 * used together with swfdec_url_equal() in a #GHashtable.
623 * Returns: a hash value
626 swfdec_url_hash (gconstpointer url
)
628 const SwfdecURL
*u
= url
;
631 /* random hash function, feel free to improve it */
632 ret
= g_str_hash (u
->protocol
);
634 ret
^= g_str_hash (u
->host
);
637 ret
^= g_str_hash (u
->path
);
638 /* queries aren't used often in hashed urls, so ignore them */
643 * swfdec_url_path_is_relative:
644 * @path: a string used to specify a url
646 * Checks if the given URL is relative or absolute.
648 * Returns: %TRUE if the path is a relative path, %FALSE if it is absolute
651 swfdec_url_path_is_relative (const char *path
)
653 g_return_val_if_fail (path
!= NULL
, FALSE
);
655 return strstr (path
, "://") == NULL
;
659 * swfdec_url_new_from_input:
660 * @input: the input povided
662 * Tries to guess the right URL from the given @input. This function is meant
663 * as a utility function helping to convert user input (like command line
664 * arguments) to a URL without requiring the full URL.
666 * Returns: a new url best matching the given @input.
669 swfdec_url_new_from_input (const char *input
)
673 g_return_val_if_fail (input
!= NULL
, NULL
);
675 /* if it's a full URL, return it */
676 if (!swfdec_url_path_is_relative (input
) &&
677 (url
= swfdec_url_new (input
)))
680 /* FIXME: split at '?' for query? */
681 if (g_path_is_absolute (input
)) {
683 g_uri_escape_string (input
[0] == '/' ? &input
[1] : &input
[0], "/", TRUE
);
684 url
= swfdec_url_new_components ("file", NULL
, 0, escaped
, NULL
);
687 char *absolute
, *cur
;
688 cur
= g_get_current_dir ();
689 absolute
= g_build_filename (cur
, input
, NULL
);
691 cur
= g_uri_escape_string (absolute
, "/", TRUE
);
693 url
= swfdec_url_new_components ("file", NULL
, 0, cur
, NULL
);
697 g_return_val_if_fail (url
!= NULL
, NULL
);
702 * swfdec_url_format_for_display:
703 * @url: the url to display
705 * Creates a string suitable to display the given @url. An example for using
706 * this function is to identify a currently playing Flash URL. Use
707 * swfdec_player_get_url() to query the player's URL and then use this function
708 * to get a displayable string.
710 * Returns: A new string containig a short description for this URL. g_free()
714 swfdec_url_format_for_display (const SwfdecURL
*url
)
718 g_return_val_if_fail (url
!= NULL
, NULL
);
720 if (swfdec_url_is_local (url
)) {
723 if (url
->path
== NULL
)
724 return g_strdup ("/");
725 slash
= strrchr (url
->path
, '/');
726 if (slash
&& slash
[1] != '\0') {
727 return g_strdup (slash
+ 1);
729 return g_strdup (url
->path
);
732 str
= g_string_new (url
->protocol
);
733 g_string_append (str
, "://");
735 g_string_append (str
, url
->host
);
736 g_string_append (str
, "/");
738 g_string_append (str
, url
->path
);
740 return g_string_free (str
, FALSE
);