2011-10-19 07:53:18 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2011 Christian Dywan <christian@twotoasts.de>
|
|
|
|
|
|
|
|
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.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
See the file COPYING for the full license text.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace GLib {
|
|
|
|
extern static string hostname_to_unicode (string hostname);
|
|
|
|
extern static string hostname_to_ascii (string hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Midori {
|
|
|
|
public class URI : Object {
|
2011-11-18 00:42:02 +00:00
|
|
|
public static string? parse_hostname (string? uri, out string path) {
|
|
|
|
/* path may be null. */
|
2011-10-19 07:53:18 +00:00
|
|
|
if (uri == null)
|
|
|
|
return uri;
|
|
|
|
unowned string? hostname = uri.chr (-1, '/');
|
2011-10-28 22:40:34 +00:00
|
|
|
if (hostname == null || hostname[1] != '/'
|
|
|
|
|| hostname.chr (-1, ' ') != null)
|
2011-11-18 00:42:02 +00:00
|
|
|
return null;
|
2011-10-19 07:53:18 +00:00
|
|
|
hostname = hostname.offset (2);
|
|
|
|
if (&path != null) {
|
|
|
|
if ((path = hostname.chr (-1, '/')) != null)
|
|
|
|
return hostname.split ("/")[0];
|
|
|
|
}
|
|
|
|
return hostname;
|
|
|
|
}
|
|
|
|
public static string to_ascii (string uri) {
|
|
|
|
/* Convert hostname to ASCII. */
|
|
|
|
string? proto = null;
|
|
|
|
if (uri.chr (-1, '/') != null && uri.chr (-1, ':') != null)
|
|
|
|
proto = uri.split ("://")[0];
|
|
|
|
string? path = null;
|
2011-11-18 00:42:02 +00:00
|
|
|
string? hostname = parse_hostname (uri, out path) ?? uri;
|
2011-10-19 07:53:18 +00:00
|
|
|
string encoded = hostname_to_ascii (hostname);
|
|
|
|
if (encoded != null) {
|
|
|
|
return (proto ?? "")
|
|
|
|
+ (proto != null ? "://" : "")
|
|
|
|
+ encoded + path;
|
|
|
|
}
|
|
|
|
return uri;
|
|
|
|
}
|
|
|
|
public static string unescape (string uri) {
|
|
|
|
/* Unescape, pass through + and %20 */
|
|
|
|
if (uri.chr (-1, '%') != null || uri.chr (-1, ' ') != null) {
|
|
|
|
/* Preserve %20 for pasting URLs into other windows */
|
|
|
|
string? unescaped = GLib.Uri.unescape_string (uri, "+");
|
|
|
|
if (unescaped == null)
|
|
|
|
return uri;
|
|
|
|
return unescaped.replace (" ", "%20");
|
|
|
|
}
|
|
|
|
return uri;
|
|
|
|
}
|
|
|
|
public static string format_for_display (string? uri) {
|
|
|
|
/* Percent-decode and decode puniycode for user display */
|
|
|
|
if (uri != null && uri.has_prefix ("http://")) {
|
|
|
|
string unescaped = unescape (uri);
|
|
|
|
if (unescaped == null)
|
|
|
|
return uri;
|
|
|
|
else if (!unescaped.validate ())
|
|
|
|
return uri;
|
|
|
|
string path;
|
2011-11-18 00:42:02 +00:00
|
|
|
string hostname = parse_hostname (unescaped, out path);
|
2011-10-19 07:53:18 +00:00
|
|
|
string decoded = hostname_to_unicode (hostname);
|
|
|
|
if (decoded != null)
|
|
|
|
return "http://" + decoded + path;
|
|
|
|
return unescaped;
|
|
|
|
}
|
|
|
|
return uri;
|
|
|
|
}
|
|
|
|
public static string for_search (string? uri, string keywords) {
|
|
|
|
/* Take a search engine URI and insert specified keywords.
|
|
|
|
Keywords are percent-encoded. If the uri contains a %s
|
|
|
|
the keywords are inserted there, otherwise appended. */
|
|
|
|
if (uri == null)
|
|
|
|
return keywords;
|
|
|
|
string escaped = GLib.Uri.escape_string (keywords, ":/", true);
|
|
|
|
if (uri.str ("%s") != null)
|
|
|
|
return uri.printf (escaped);
|
|
|
|
return uri + escaped;
|
|
|
|
}
|
|
|
|
public static bool is_blank (string? uri) {
|
|
|
|
return !(uri != null && uri != "" && !uri.has_prefix ("about:"));
|
|
|
|
}
|
2011-10-28 20:47:17 +00:00
|
|
|
public static bool is_http (string? uri) {
|
|
|
|
return uri != null
|
|
|
|
&& (uri.has_prefix ("http://") || uri.has_prefix ("https://"));
|
|
|
|
}
|
2011-10-19 07:53:18 +00:00
|
|
|
public static bool is_resource (string? uri) {
|
|
|
|
return uri != null
|
2011-10-28 20:47:17 +00:00
|
|
|
&& (is_http (uri)
|
|
|
|
|| (uri.has_prefix ("data:") && uri.chr (-1, ';') != null));
|
2011-10-19 07:53:18 +00:00
|
|
|
}
|
|
|
|
public static bool is_location (string? uri) {
|
|
|
|
/* file:// is not considered a location for security reasons */
|
|
|
|
return uri != null
|
|
|
|
&& ((uri.str ("://") != null && uri.chr (-1, ' ') == null)
|
2011-11-15 20:48:59 +00:00
|
|
|
|| is_http (uri)
|
2011-10-19 07:53:18 +00:00
|
|
|
|| uri.has_prefix ("about:")
|
|
|
|
|| (uri.has_prefix ("data:") && uri.chr (-1, ';') != null)
|
|
|
|
|| (uri.has_prefix ("geo:") && uri.chr (-1, ',') != null)
|
|
|
|
|| uri.has_prefix ("javascript:"));
|
|
|
|
}
|
|
|
|
public static bool is_email (string? uri) {
|
|
|
|
return uri != null
|
|
|
|
&& (uri.chr (-1, '@') != null || uri.has_prefix ("mailto:"))
|
|
|
|
/* :// and @ together would mean login credentials */
|
|
|
|
&& uri.str ("://") == null;
|
|
|
|
}
|
|
|
|
public static bool is_ip_address (string? uri) {
|
|
|
|
/* Quick check for IPv4 or IPv6, no validation.
|
|
|
|
FIXME: Schemes are not handled
|
|
|
|
hostname_is_ip_address () is not used because
|
|
|
|
we'd have to separate the path from the URI first. */
|
|
|
|
return uri != null && uri[0].isdigit ()
|
|
|
|
&& (uri.chr (4, '.') != null || uri.chr (4, ':') != null);
|
|
|
|
}
|
|
|
|
public static bool is_valid (string? uri) {
|
|
|
|
return uri != null
|
|
|
|
&& uri.chr (-1, ' ') == null
|
|
|
|
&& (URI.is_location (uri) || uri.chr (-1, '.') != null);
|
|
|
|
}
|
2011-11-07 22:07:57 +00:00
|
|
|
public static GLib.ChecksumType get_fingerprint (string uri,
|
|
|
|
out string checksum, out string label) {
|
|
|
|
|
|
|
|
/* http://foo.bar/baz/spam.eggs#!algo!123456 */
|
|
|
|
unowned string delimiter = "#!md5!";
|
|
|
|
unowned string display = _("MD5-Checksum:");
|
|
|
|
GLib.ChecksumType type = GLib.ChecksumType.MD5;
|
|
|
|
unowned string? fragment = uri.str (delimiter);
|
|
|
|
if (fragment == null) {
|
|
|
|
delimiter = "#!sha1!";
|
|
|
|
display = _("SHA1-Checksum:");
|
|
|
|
type = GLib.ChecksumType.SHA1;
|
|
|
|
fragment = uri.str (delimiter);
|
|
|
|
}
|
|
|
|
if (fragment == null) {
|
|
|
|
type = (GLib.ChecksumType)int.MAX;
|
|
|
|
display = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (&checksum != null)
|
|
|
|
checksum = fragment != null
|
|
|
|
? fragment.offset (delimiter.length) : null;
|
|
|
|
if (&label != null)
|
|
|
|
label = display;
|
|
|
|
return type;
|
|
|
|
}
|
2011-10-19 07:53:18 +00:00
|
|
|
}
|
|
|
|
}
|