Revision 72cbfa74
Added by koszko almost 2 years ago
common/patterns.js | ||
---|---|---|
5 | 5 |
* Redistribution terms are gathered in the `copyright' file. |
6 | 6 |
*/ |
7 | 7 |
|
8 |
const MAX_URL_PATH_LEN = 12; |
|
9 |
const MAX_URL_PATH_CHARS = 255; |
|
10 |
const MAX_DOMAIN_LEN = 7; |
|
11 |
const MAX_DOMAIN_CHARS = 100; |
|
12 |
|
|
8 | 13 |
const proto_regex = /^(\w+):\/\/(.*)$/; |
9 | 14 |
|
10 | 15 |
const user_re = "[^/?#@]+@" |
... | ... | |
37 | 42 |
[deco.domain, deco.path, deco.query] = http_match.slice(1, 4); |
38 | 43 |
} |
39 | 44 |
|
40 |
if (deco.domain) |
|
41 |
deco.domain = deco.domain.split("."); |
|
42 |
|
|
43 | 45 |
const leading_dash = deco.path[0] === "/"; |
44 | 46 |
deco.trailing_dash = deco.path[deco.path.length - 1] === "/"; |
45 |
deco.path = deco.path.split("/").filter(s => s !== ""); |
|
46 |
if (leading_dash || deco.path.length === 0) |
|
47 |
deco.path.unshift(""); |
|
48 | 47 |
|
49 |
return deco; |
|
50 |
} |
|
48 |
if (deco.domain) { |
|
49 |
if (deco.domain.length > MAX_DOMAIN_CHARS) { |
|
50 |
const idx = deco.domain.indexOf(".", deco.domain.length - |
|
51 |
MAX_DOMAIN_CHARS); |
|
52 |
if (idx === -1) |
|
53 |
deco.domain = []; |
|
54 |
else |
|
55 |
deco.domain = deco.domain.substring(idx + 1); |
|
51 | 56 |
|
52 |
/* Be sane: both arguments should be arrays of length >= 2 */ |
|
53 |
function domain_matches(url_domain, pattern_domain) |
|
54 |
{ |
|
55 |
const length_difference = url_domain.length - pattern_domain.length; |
|
56 |
|
|
57 |
for (let i = 1; i <= url_domain.length; i++) { |
|
58 |
const url_part = url_domain[url_domain.length - i]; |
|
59 |
const pattern_part = pattern_domain[pattern_domain.length - i]; |
|
60 |
|
|
61 |
if (pattern_domain.length === i) { |
|
62 |
if (pattern_part === "*") |
|
63 |
return length_difference === 0; |
|
64 |
if (pattern_part === "**") |
|
65 |
return length_difference > 0; |
|
66 |
if (pattern_part === "***") |
|
67 |
return true; |
|
68 |
return length_difference === 0 && pattern_part === url_part; |
|
57 |
deco.domain_truncated = true; |
|
69 | 58 |
} |
70 | 59 |
|
71 |
if (pattern_part !== url_part) |
|
72 |
return false; |
|
73 |
} |
|
74 |
|
|
75 |
return pattern_domain.length === url_domain.length + 1 && |
|
76 |
pattern_domain[0] === "***"; |
|
77 |
} |
|
78 |
|
|
79 |
function path_matches(url_path, url_trailing_dash, |
|
80 |
pattern_path, pattern_trailing_dash) |
|
81 |
{ |
|
82 |
const dashes_ok = !(pattern_trailing_dash && !url_trailing_dash); |
|
83 |
|
|
84 |
if (pattern_path.length === 0) |
|
85 |
return url_path.length === 0 && dashes_ok; |
|
86 |
|
|
87 |
const length_difference = url_path.length - pattern_path.length; |
|
88 |
|
|
89 |
for (let i = 0; i < url_path.length; i++) { |
|
90 |
if (pattern_path.length === i + 1) { |
|
91 |
if (pattern_path[i] === "*") |
|
92 |
return length_difference === 0; |
|
93 |
if (pattern_path[i] === "**") { |
|
94 |
return length_difference > 0 || |
|
95 |
(url_path[i] === "**" && dashes_ok); |
|
96 |
} |
|
97 |
if (pattern_path[i] === "***") |
|
98 |
return length_difference >= 0; |
|
99 |
return length_difference === 0 && |
|
100 |
pattern_path[i] === url_path[i] && dashes_ok; |
|
60 |
if (deco.path.length > MAX_URL_PATH_CHARS) { |
|
61 |
deco.path = deco.path.substring(0, deco.path.lastIndexOf("/")); |
|
62 |
deco.path_truncated = true; |
|
101 | 63 |
} |
102 |
|
|
103 |
if (pattern_path[i] !== url_path[i]) |
|
104 |
return false; |
|
105 | 64 |
} |
106 | 65 |
|
107 |
return false; |
|
108 |
} |
|
109 |
|
|
110 |
function url_matches(url, pattern) |
|
111 |
{ |
|
112 |
const url_deco = deconstruct_url(url); |
|
113 |
const pattern_deco = deconstruct_url(pattern); |
|
114 |
|
|
115 |
if (url_deco === undefined || pattern_deco === undefined) { |
|
116 |
console.log(`bad comparison: ${url} and ${pattern}`); |
|
117 |
return false |
|
66 |
if (typeof deco.domain === "string") { |
|
67 |
deco.domain = deco.domain.split("."); |
|
68 |
if (deco.domain.splice(0, deco.domain.length - MAX_DOMAIN_LEN).length |
|
69 |
> 0) |
|
70 |
deco.domain_truncated = true; |
|
118 | 71 |
} |
119 | 72 |
|
120 |
return pattern_deco.proto === url_deco.proto &&
|
|
121 |
!(pattern_deco.proto === "file" && pattern_deco.trailing_dash) &&
|
|
122 |
!!url_deco.domain === !!pattern_deco.domain &&
|
|
123 |
(!url_deco.domain ||
|
|
124 |
domain_matches(url_deco.domain, pattern_deco.domain)) &&
|
|
125 |
path_matches(url_deco.path, url_deco.trailing_dash, |
|
126 |
pattern_deco.path, pattern_deco.trailing_dash);
|
|
73 |
deco.path = deco.path.split("/").filter(s => s !== "");
|
|
74 |
if (deco.domain && deco.path.splice(MAX_URL_PATH_LEN).length > 0)
|
|
75 |
deco.path_truncated = true;
|
|
76 |
if (leading_dash || deco.path.length === 0)
|
|
77 |
deco.path.unshift("");
|
|
78 |
|
|
79 |
return deco;
|
|
127 | 80 |
} |
128 | 81 |
|
129 |
function* each_domain_pattern(domain_segments)
|
|
82 |
function* each_domain_pattern(deco)
|
|
130 | 83 |
{ |
131 |
for (let slice = 0; slice < domain_segments.length; slice++) {
|
|
132 |
const domain_part = domain_segments.slice(slice).join(".");
|
|
84 |
for (let slice = 0; slice < deco.domain.length - 1; slice++) {
|
|
85 |
const domain_part = deco.domain.slice(slice).join(".");
|
|
133 | 86 |
const domain_wildcards = []; |
134 |
if (slice === 0) |
|
87 |
if (slice === 0 && !deco.domain_truncated)
|
|
135 | 88 |
yield domain_part; |
136 |
if (slice === 1) |
|
89 |
if (slice === 1 && !deco.domain_truncated)
|
|
137 | 90 |
yield "*." + domain_part; |
138 | 91 |
if (slice > 1) |
139 | 92 |
yield "**." + domain_part; |
... | ... | |
141 | 94 |
} |
142 | 95 |
} |
143 | 96 |
|
144 |
function* each_path_pattern(path_segments, trailing_dash)
|
|
97 |
function* each_path_pattern(deco)
|
|
145 | 98 |
{ |
146 |
for (let slice = path_segments.length; slice > 0; slice--) {
|
|
147 |
const path_part = path_segments.slice(0, slice).join("/");
|
|
99 |
for (let slice = deco.path.length; slice > 0; slice--) {
|
|
100 |
const path_part = deco.path.slice(0, slice).join("/");
|
|
148 | 101 |
const path_wildcards = []; |
149 |
if (slice === path_segments.length) {
|
|
150 |
if (trailing_dash) |
|
102 |
if (slice === deco.path.length && !deco.path_truncated) {
|
|
103 |
if (deco.trailing_dash)
|
|
151 | 104 |
yield path_part + "/"; |
152 | 105 |
yield path_part; |
153 | 106 |
} |
154 |
if (slice === path_segments.length - 1 && path_segments[slice] !== "*") |
|
107 |
if (slice === deco.path.length - 1 && !deco.path_truncated && |
|
108 |
deco.path[slice] !== "*") |
|
155 | 109 |
yield path_part + "/*"; |
156 |
if (slice < path_segments.length - 1)
|
|
110 |
if (slice < deco.path.length - 1)
|
|
157 | 111 |
yield path_part + "/**"; |
158 |
if (slice < path_segments.length - 1 ||
|
|
159 |
path_segments[path_segments.length - 1] !== "***")
|
|
112 |
if (slice !== deco.path.length - 1 || deco.path_truncated ||
|
|
113 |
deco.path[slice] !== "***")
|
|
160 | 114 |
yield path_part + "/***"; |
161 | 115 |
} |
162 | 116 |
} |
... | ... | |
167 | 121 |
const deco = deconstruct_url(url); |
168 | 122 |
|
169 | 123 |
if (deco === undefined) { |
170 |
console.log("bad url format", url);
|
|
124 |
console.error("bad url format", url);
|
|
171 | 125 |
return false; |
172 | 126 |
} |
173 | 127 |
|
174 |
const all_domains = deco.domain ? each_domain_pattern(deco.domain) : [""];
|
|
128 |
const all_domains = deco.domain ? each_domain_pattern(deco) : [""]; |
|
175 | 129 |
for (const domain of all_domains) { |
176 |
for (const path of each_path_pattern(deco.path, deco.trailing_dash))
|
|
130 |
for (const path of each_path_pattern(deco)) |
|
177 | 131 |
yield `${deco.proto}://${domain}${path}`; |
178 | 132 |
} |
179 | 133 |
} |
180 | 134 |
|
181 | 135 |
/* |
182 | 136 |
* EXPORTS_START |
183 |
* EXPORT url_matches |
|
184 | 137 |
* EXPORT each_url_pattern |
185 | 138 |
* EXPORTS_END |
186 | 139 |
*/ |
Also available in: Unified diff
limit allowed pattern lengths