forked from adamhooper/bodacity-js-util
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcanonical_url.js
155 lines (130 loc) · 3.93 KB
/
canonical_url.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
(function () {
/*
* Canonical URL creator.
*
* Given a URL (e.g., window.location.href or a relative URL such as
* "/search"), returns a canonical URL so that both can be compared.
*
* Also provided is a helper method for that purpose: url_equals(). So on the
* page "http://example.com/search", url_equals("/search", window.location)
* will return true.
*
* See: http://www.ietf.org/rfc/rfc1808.txt Relative Uniform Resource Locators
*
* --
* Bodacity JavaScript Utilities
* http://adamhooper.com/bodacity
* Public Domain (no licensing restrictions)
*/
function dirname(filename) {
// Assume the filename is of the form "/a/b/c" (and return "/a/b").
var i = filename.lastIndexOf('/');
if (i > 0) {
return filename.substring(0, i);
} else {
return '/';
}
}
var base,
relative,
// http://www.ietf.org/rfc/rfc1808.txt "Step 6"
RE_CLEAN_PATH_DOT_SLASHES = /\/\.\//g,
RE_CLEAN_PATH_DOT_AT_END = /\/\.$/,
RE_CLEAN_PATH_DOTDOT = /[^\/]+\/\.\.\//,
RE_CLEAN_PATH_DOTDOT_AT_END = /[^\/]+\/\.\.$/,
RE_CLEAN_URL = /^(\w+):\/\/([^:\/]+)?(:\d+)?([^\?#]*)(?:\?(\S+))?/,
RE_PROTO = /^\w+:\/\//,
RE_ALL_BUT_PATH = /^(\w+:\/\/[^\/]*)/;
/*
* Returns the base URL according to the <base> element.
*/
function get_base(options) {
if (options && options.base) { return dirname(options.base); }
if (base === undefined) {
var base_elem = document.getElementsByTagName('base')[0];
if (base_elem) {
base = dirname(base_elem.href);
} else {
base = null;
}
}
return base;
}
/*
* Returns the base URL according to window.location.
*
* This will be the dirname of the current file.
*/
function get_relative(options) {
var loc, href;
if (options && options.location) {
loc = options.location;
} else {
loc = window.location;
}
href = loc.protocol;
href += '//';
href += loc.hostname;
if (loc.port) {
href += ':' + loc.port;
}
href += loc.pathname;
href += loc.search;
href += loc.hash;
return dirname(href);
}
/*
* Takes ":80" and returns either ":80" or "", depending on the value of proto.
*/
function clean_port_with_proto(port, proto) {
if (proto === 'http' && port === ':80') { return ''; }
if (proto === 'https' && port === ':443') { return ''; }
if (proto === 'ftp' && port === ':21') { return ''; }
return port || '';
}
/*
* Takes "//a" and returns "/a"; takes "" and returns "/".
*/
function clean_path(path) {
if (!path) { return '/'; }
while (RE_CLEAN_PATH_DOT_SLASHES.test(path)) {
path = path.replace(RE_CLEAN_PATH_DOT_SLASHES, '/');
}
path = path.replace(RE_CLEAN_PATH_DOT_AT_END, '/');
while (RE_CLEAN_PATH_DOTDOT.test(path)) {
path = path.replace(RE_CLEAN_PATH_DOTDOT, '');
}
path = path.replace(RE_CLEAN_PATH_DOTDOT_AT_END, '');
return path;
}
function clean_url(url, options) {
var match = RE_CLEAN_URL.exec(url),
proto = match[1],
host = match[2] || '',
port = clean_port_with_proto(match[3], proto),
path = clean_path(match[4]),
query = match[5],
clean = proto + '://' + host + port + path;
if (options && options.include_query && query) {
clean += '?' + query;
}
return clean;
}
function canonical_url(url, options) {
if (RE_PROTO.test(url)) {
return clean_url(url);
}
var start = get_base(options) || get_relative(options),
all_but_path_match;
if (url[0] === '/') {
all_but_path_match = RE_ALL_BUT_PATH.exec(start);
return clean_url(all_but_path_match[1] + url, options);
}
return clean_url(start + '/' + url, options);
}
function url_equals(url1, url2, options) {
return canonical_url(url1, options) === canonical_url(url2, options);
}
window.canonical_url = canonical_url;
window.url_equals = url_equals;
}());