|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include <stdio.h> |
|
6 #include <ctype.h> |
|
7 #include "nsEscape.h" |
|
8 #include "nsString.h" |
|
9 #include "nsUrlClassifierUtils.h" |
|
10 #include "nsNetUtil.h" |
|
11 #include "stdlib.h" |
|
12 #include "TestHarness.h" |
|
13 |
|
14 static int gTotalTests = 0; |
|
15 static int gPassedTests = 0; |
|
16 |
|
17 static char int_to_hex_digit(int32_t i) { |
|
18 NS_ASSERTION((i >= 0) && (i <= 15), "int too big in int_to_hex_digit"); |
|
19 return static_cast<char>(((i < 10) ? (i + '0') : ((i - 10) + 'A'))); |
|
20 } |
|
21 |
|
22 static void CheckEquals(nsCString & expected, nsCString & actual) |
|
23 { |
|
24 if (!(expected).Equals((actual))) { |
|
25 fail("expected |%s| but got |%s|", (expected).get(), (actual).get()); |
|
26 } else { |
|
27 gPassedTests++; |
|
28 } |
|
29 gTotalTests++; |
|
30 } |
|
31 |
|
32 void TestUnescapeHelper(const char* in, const char* expected) |
|
33 { |
|
34 nsCString out, strIn(in), strExp(expected); |
|
35 nsUrlClassifierUtils utils; |
|
36 |
|
37 NS_UnescapeURL(strIn.get(), strIn.Length(), esc_AlwaysCopy, out); |
|
38 CheckEquals(strExp, out); |
|
39 } |
|
40 |
|
41 // Make sure Unescape from nsEncode.h's unescape does what the server does. |
|
42 void TestUnescape() |
|
43 { |
|
44 // test empty string |
|
45 TestUnescapeHelper("\0", "\0"); |
|
46 |
|
47 // Test docoding of all characters. |
|
48 nsCString allCharsEncoded, allCharsEncodedLowercase, allCharsAsString; |
|
49 for (int32_t i = 1; i < 256; ++i) { |
|
50 allCharsEncoded.Append('%'); |
|
51 allCharsEncoded.Append(int_to_hex_digit(i / 16)); |
|
52 allCharsEncoded.Append((int_to_hex_digit(i % 16))); |
|
53 |
|
54 allCharsEncodedLowercase.Append('%'); |
|
55 allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i / 16))); |
|
56 allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i % 16))); |
|
57 |
|
58 allCharsAsString.Append(static_cast<char>(i)); |
|
59 } |
|
60 |
|
61 nsUrlClassifierUtils utils; |
|
62 nsCString out; |
|
63 NS_UnescapeURL(allCharsEncoded.get(), allCharsEncoded.Length(), esc_AlwaysCopy, out); |
|
64 CheckEquals(allCharsAsString, out); |
|
65 |
|
66 out.Truncate(); |
|
67 NS_UnescapeURL(allCharsEncodedLowercase.get(), allCharsEncodedLowercase.Length(), esc_AlwaysCopy, out); |
|
68 CheckEquals(allCharsAsString, out); |
|
69 |
|
70 // Test %-related edge cases |
|
71 TestUnescapeHelper("%", "%"); |
|
72 TestUnescapeHelper("%xx", "%xx"); |
|
73 TestUnescapeHelper("%%", "%%"); |
|
74 TestUnescapeHelper("%%%", "%%%"); |
|
75 TestUnescapeHelper("%%%%", "%%%%"); |
|
76 TestUnescapeHelper("%1", "%1"); |
|
77 TestUnescapeHelper("%1z", "%1z"); |
|
78 TestUnescapeHelper("a%1z", "a%1z"); |
|
79 TestUnescapeHelper("abc%d%e%fg%hij%klmno%", "abc%d%e%fg%hij%klmno%"); |
|
80 |
|
81 // A few more tests |
|
82 TestUnescapeHelper("%25", "%"); |
|
83 TestUnescapeHelper("%25%32%35", "%25"); |
|
84 } |
|
85 |
|
86 void TestEncodeHelper(const char* in, const char* expected) |
|
87 { |
|
88 nsCString out, strIn(in), strExp(expected); |
|
89 nsUrlClassifierUtils utils; |
|
90 |
|
91 utils.SpecialEncode(strIn, true, out); |
|
92 CheckEquals(strExp, out); |
|
93 } |
|
94 |
|
95 void TestEnc() |
|
96 { |
|
97 // Test empty string |
|
98 TestEncodeHelper("", ""); |
|
99 |
|
100 // Test that all characters we shouldn't encode ([33-36],[38,126]) are not. |
|
101 nsCString noenc; |
|
102 for (int32_t i = 33; i < 127; i++) { |
|
103 if (i != 37) { // skip % |
|
104 noenc.Append(static_cast<char>(i)); |
|
105 } |
|
106 } |
|
107 nsUrlClassifierUtils utils; |
|
108 nsCString out; |
|
109 utils.SpecialEncode(noenc, false, out); |
|
110 CheckEquals(noenc, out); |
|
111 |
|
112 // Test that all the chars that we should encode [0,32],37,[127,255] are |
|
113 nsCString yesAsString, yesExpectedString; |
|
114 for (int32_t i = 1; i < 256; i++) { |
|
115 if (i < 33 || i == 37 || i > 126) { |
|
116 yesAsString.Append(static_cast<char>(i)); |
|
117 yesExpectedString.Append('%'); |
|
118 yesExpectedString.Append(int_to_hex_digit(i / 16)); |
|
119 yesExpectedString.Append(int_to_hex_digit(i % 16)); |
|
120 } |
|
121 } |
|
122 |
|
123 out.Truncate(); |
|
124 utils.SpecialEncode(yesAsString, false, out); |
|
125 CheckEquals(yesExpectedString, out); |
|
126 |
|
127 TestEncodeHelper("blah//blah", "blah/blah"); |
|
128 } |
|
129 |
|
130 void TestCanonicalizeHelper(const char* in, const char* expected) |
|
131 { |
|
132 nsCString out, strIn(in), strExp(expected); |
|
133 nsUrlClassifierUtils utils; |
|
134 |
|
135 utils.CanonicalizePath(strIn, out); |
|
136 CheckEquals(strExp, out); |
|
137 } |
|
138 |
|
139 void TestCanonicalize() |
|
140 { |
|
141 // Test repeated %-decoding. Note: %25 --> %, %32 --> 2, %35 --> 5 |
|
142 TestCanonicalizeHelper("%25", "%25"); |
|
143 TestCanonicalizeHelper("%25%32%35", "%25"); |
|
144 TestCanonicalizeHelper("asdf%25%32%35asd", "asdf%25asd"); |
|
145 TestCanonicalizeHelper("%%%25%32%35asd%%", "%25%25%25asd%25%25"); |
|
146 TestCanonicalizeHelper("%25%32%35%25%32%35%25%32%35", "%25%25%25"); |
|
147 TestCanonicalizeHelper("%25", "%25"); |
|
148 TestCanonicalizeHelper("%257Ea%2521b%2540c%2523d%2524e%25f%255E00%252611%252A22%252833%252944_55%252B", |
|
149 "~a!b@c#d$e%25f^00&11*22(33)44_55+"); |
|
150 |
|
151 TestCanonicalizeHelper("", ""); |
|
152 TestCanonicalizeHelper("%31%36%38%2e%31%38%38%2e%39%39%2e%32%36/%2E%73%65%63%75%72%65/%77%77%77%2E%65%62%61%79%2E%63%6F%6D/", |
|
153 "168.188.99.26/.secure/www.ebay.com/"); |
|
154 TestCanonicalizeHelper("195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/", |
|
155 "195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/"); |
|
156 // Added in bug 489455. %00 should no longer be changed to %01. |
|
157 TestCanonicalizeHelper("%00", "%00"); |
|
158 } |
|
159 |
|
160 void TestParseIPAddressHelper(const char *in, const char *expected) |
|
161 { |
|
162 nsCString out, strIn(in), strExp(expected); |
|
163 nsUrlClassifierUtils utils; |
|
164 utils.Init(); |
|
165 |
|
166 utils.ParseIPAddress(strIn, out); |
|
167 CheckEquals(strExp, out); |
|
168 } |
|
169 |
|
170 void TestParseIPAddress() |
|
171 { |
|
172 TestParseIPAddressHelper("123.123.0.0.1", ""); |
|
173 TestParseIPAddressHelper("255.0.0.1", "255.0.0.1"); |
|
174 TestParseIPAddressHelper("12.0x12.01234", "12.18.2.156"); |
|
175 TestParseIPAddressHelper("276.2.3", "20.2.0.3"); |
|
176 TestParseIPAddressHelper("012.034.01.055", "10.28.1.45"); |
|
177 TestParseIPAddressHelper("0x12.0x43.0x44.0x01", "18.67.68.1"); |
|
178 TestParseIPAddressHelper("167838211", "10.1.2.3"); |
|
179 TestParseIPAddressHelper("3279880203", "195.127.0.11"); |
|
180 TestParseIPAddressHelper("0x12434401", "18.67.68.1"); |
|
181 TestParseIPAddressHelper("413960661", "24.172.137.213"); |
|
182 TestParseIPAddressHelper("03053104725", "24.172.137.213"); |
|
183 TestParseIPAddressHelper("030.0254.0x89d5", "24.172.137.213"); |
|
184 TestParseIPAddressHelper("1.234.4.0377", "1.234.4.255"); |
|
185 TestParseIPAddressHelper("1.2.3.00x0", ""); |
|
186 TestParseIPAddressHelper("10.192.95.89 xy", "10.192.95.89"); |
|
187 TestParseIPAddressHelper("10.192.95.89 xyz", ""); |
|
188 TestParseIPAddressHelper("1.2.3.0x0", "1.2.3.0"); |
|
189 TestParseIPAddressHelper("1.2.3.4", "1.2.3.4"); |
|
190 } |
|
191 |
|
192 void TestCanonicalNumHelper(const char *in, uint32_t bytes, |
|
193 bool allowOctal, const char *expected) |
|
194 { |
|
195 nsCString out, strIn(in), strExp(expected); |
|
196 nsUrlClassifierUtils utils; |
|
197 utils.Init(); |
|
198 |
|
199 utils.CanonicalNum(strIn, bytes, allowOctal, out); |
|
200 CheckEquals(strExp, out); |
|
201 } |
|
202 |
|
203 void TestCanonicalNum() |
|
204 { |
|
205 TestCanonicalNumHelper("", 1, true, ""); |
|
206 TestCanonicalNumHelper("10", 0, true, ""); |
|
207 TestCanonicalNumHelper("45", 1, true, "45"); |
|
208 TestCanonicalNumHelper("0x10", 1, true, "16"); |
|
209 TestCanonicalNumHelper("367", 2, true, "1.111"); |
|
210 TestCanonicalNumHelper("012345", 3, true, "0.20.229"); |
|
211 TestCanonicalNumHelper("0173", 1, true, "123"); |
|
212 TestCanonicalNumHelper("09", 1, false, "9"); |
|
213 TestCanonicalNumHelper("0x120x34", 2, true, ""); |
|
214 TestCanonicalNumHelper("0x12fc", 2, true, "18.252"); |
|
215 TestCanonicalNumHelper("3279880203", 4, true, "195.127.0.11"); |
|
216 TestCanonicalNumHelper("0x0000059", 1, true, "89"); |
|
217 TestCanonicalNumHelper("0x00000059", 1, true, "89"); |
|
218 TestCanonicalNumHelper("0x0000067", 1, true, "103"); |
|
219 } |
|
220 |
|
221 void TestHostnameHelper(const char *in, const char *expected) |
|
222 { |
|
223 nsCString out, strIn(in), strExp(expected); |
|
224 nsUrlClassifierUtils utils; |
|
225 utils.Init(); |
|
226 |
|
227 utils.CanonicalizeHostname(strIn, out); |
|
228 CheckEquals(strExp, out); |
|
229 } |
|
230 |
|
231 void TestHostname() |
|
232 { |
|
233 TestHostnameHelper("abcd123;[]", "abcd123;[]"); |
|
234 TestHostnameHelper("abc.123", "abc.123"); |
|
235 TestHostnameHelper("abc..123", "abc.123"); |
|
236 TestHostnameHelper("trailing.", "trailing"); |
|
237 TestHostnameHelper("i love trailing dots....", "i%20love%20trailing%20dots"); |
|
238 TestHostnameHelper(".leading", "leading"); |
|
239 TestHostnameHelper("..leading", "leading"); |
|
240 TestHostnameHelper(".dots.", "dots"); |
|
241 TestHostnameHelper(".both.", "both"); |
|
242 TestHostnameHelper(".both..", "both"); |
|
243 TestHostnameHelper("..both.", "both"); |
|
244 TestHostnameHelper("..both..", "both"); |
|
245 TestHostnameHelper("..a.b.c.d..", "a.b.c.d"); |
|
246 TestHostnameHelper("..127.0.0.1..", "127.0.0.1"); |
|
247 TestHostnameHelper("asdf!@#$a", "asdf!@#$a"); |
|
248 TestHostnameHelper("AB CD 12354", "ab%20cd%2012354"); |
|
249 TestHostnameHelper("\1\2\3\4\112\177", "%01%02%03%04j%7F"); |
|
250 TestHostnameHelper("<>.AS/-+", "<>.as/-+"); |
|
251 // Added in bug 489455. %00 should no longer be changed to %01. |
|
252 TestHostnameHelper("%00", "%00"); |
|
253 } |
|
254 |
|
255 void TestLongHostname() |
|
256 { |
|
257 static const int kTestSize = 1024 * 150; |
|
258 char *str = static_cast<char*>(malloc(kTestSize + 1)); |
|
259 memset(str, 'x', kTestSize); |
|
260 str[kTestSize] = '\0'; |
|
261 |
|
262 nsUrlClassifierUtils utils; |
|
263 utils.Init(); |
|
264 |
|
265 nsAutoCString out; |
|
266 nsDependentCString in(str); |
|
267 PRIntervalTime clockStart = PR_IntervalNow(); |
|
268 utils.CanonicalizeHostname(in, out); |
|
269 PRIntervalTime clockEnd = PR_IntervalNow(); |
|
270 |
|
271 CheckEquals(in, out); |
|
272 |
|
273 printf("CanonicalizeHostname on long string (%dms)\n", |
|
274 PR_IntervalToMilliseconds(clockEnd - clockStart)); |
|
275 } |
|
276 |
|
277 void TestFragmentSet() |
|
278 { |
|
279 nsUrlClassifierFragmentSet set; |
|
280 set.Init(3); |
|
281 |
|
282 set.Put(NS_LITERAL_CSTRING("a")); |
|
283 set.Put(NS_LITERAL_CSTRING("b")); |
|
284 set.Put(NS_LITERAL_CSTRING("c")); |
|
285 |
|
286 // At this point, adding a fourth element would push "a" off. |
|
287 // Make sure that set.Has("a") moves it to the front of the list |
|
288 set.Has(NS_LITERAL_CSTRING("a")); |
|
289 |
|
290 // Now add a new item. This should now push "b" off the list, |
|
291 // but leave "a" |
|
292 set.Put(NS_LITERAL_CSTRING("d")); |
|
293 |
|
294 gTotalTests++; |
|
295 if (set.Has(NS_LITERAL_CSTRING("a"))) |
|
296 gPassedTests++; |
|
297 else |
|
298 fail("set.Has(\"a\") failed."); |
|
299 |
|
300 gTotalTests++; |
|
301 if (!set.Has(NS_LITERAL_CSTRING("b"))) |
|
302 gPassedTests++; |
|
303 else |
|
304 fail("!set.Has(\"b\") failed."); |
|
305 } |
|
306 |
|
307 int main(int argc, char **argv) |
|
308 { |
|
309 ScopedXPCOM xpcom("URLClassiferUtils"); |
|
310 |
|
311 TestUnescape(); |
|
312 TestEnc(); |
|
313 TestCanonicalize(); |
|
314 TestCanonicalNum(); |
|
315 TestParseIPAddress(); |
|
316 TestHostname(); |
|
317 TestLongHostname(); |
|
318 TestFragmentSet(); |
|
319 |
|
320 if (gPassedTests == gTotalTests) |
|
321 passed(__FILE__); |
|
322 printf("%d of %d tests passed\n", gPassedTests, gTotalTests); |
|
323 // Non-zero return status signals test failure to build system. |
|
324 |
|
325 return (gPassedTests != gTotalTests); |
|
326 } |