Move URL from WebCore to WTF
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebCore / cocoa / URLExtras.mm
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27
28 #import <wtf/Vector.h>
29 #import <wtf/cocoa/NSURLExtras.h>
30 #import <wtf/text/WTFString.h>
31
32 namespace TestWebKitAPI {
33
34 static NSData *literalAsData(const char* literal)
35 {
36     return [NSData dataWithBytes:literal length:strlen(literal)];
37 }
38
39 static const char* dataAsString(NSData *data)
40 {
41     static char buffer[1000];
42     if ([data length] > sizeof(buffer) - 1)
43         return "ERROR";
44     if (memchr([data bytes], 0, [data length]))
45         return "ERROR";
46     memcpy(buffer, [data bytes], [data length]);
47     buffer[[data length]] = '\0';
48     return buffer;
49 }
50
51 static const char* originalDataAsString(NSURL *URL)
52 {
53     return dataAsString(WTF::originalURLData(URL));
54 }
55
56 static const char* userVisibleString(NSURL *URL)
57 {
58     return [WTF::userVisibleString(URL) UTF8String];
59 }
60
61 static NSURL *literalURL(const char* literal)
62 {
63     return WTF::URLWithData(literalAsData(literal), nil);
64 }
65
66 TEST(WebCore, URLExtras)
67 {
68     EXPECT_STREQ("http://site.com", originalDataAsString(literalURL("http://site.com")));
69     EXPECT_STREQ("http://%77ebsite.com", originalDataAsString(literalURL("http://%77ebsite.com")));
70
71     EXPECT_STREQ("http://site.com", userVisibleString(literalURL("http://site.com")));
72     EXPECT_STREQ("http://%77ebsite.com", userVisibleString(literalURL("http://%77ebsite.com")));
73 }
74     
75 TEST(WebCore, URLExtras_Spoof)
76 {
77     Vector<String> punycodedSpoofHosts = {
78         "xn--cfa45g", // U+0131, U+0307
79         "xn--tma03b", // U+0237, U+0307
80         "xn--tma03bxga", // U+0237, U+034F, U+034F, U+0307
81         "xn--tma03bl01e", // U+0237, U+200B, U+0307
82         "xn--a-egb", // a, U+034F
83         "xn--a-qgn", // a, U+200B
84         "xn--a-mgn", // a, U+2009
85         "xn--u7f", // U+1D04
86         "xn--57f", // U+1D0F
87         "xn--i38a", // U+A731
88         "xn--j8f", // U+1D1C
89         "xn--n8f", // U+1D20
90         "xn--o8f", // U+1D21
91         "xn--p8f", // U+1D22
92         "xn--0na", // U+0261
93         "xn--cn-ded", // U+054D
94         "xn--ews-nfe.org", // U+054D
95         "xn--yotube-qkh", // U+0578
96         "xn--cla-7fe.edu", // U+0578
97         "xn--rsa94l", // U+05D5 U+0307
98         "xn--hdb9c", // U+05D5 U+05B9
99         "xn--idb7c", // U+05D5 U+05BA
100         "xn--pdb3b", // U+05D5 U+05C1
101         "xn--qdb1b", // U+05D5 U+05C2
102         "xn--sdb7a", // U+05D5 U+05C4
103         "xn--2-zic", // U+0032 U+05E1
104     };
105     for (const String& host : punycodedSpoofHosts) {
106         auto url = makeString("http://", host, "/").utf8();
107         EXPECT_STREQ(url.data(), userVisibleString(literalURL(url.data())));
108     }
109 }
110
111 TEST(WebCore, URLExtras_NotSpoofed)
112 {
113     // Valid mixtures of Armenian and other scripts
114     EXPECT_STREQ("https://en.wikipedia.org/wiki/.\u0570\u0561\u0575", userVisibleString(literalURL("https://en.wikipedia.org/wiki/.\u0570\u0561\u0575")));
115     EXPECT_STREQ("https://\u0573\u0574\u0578.\u0570\u0561\u0575", userVisibleString(literalURL("https://\u0573\u0574\u0578.\u0570\u0561\u0575")));
116     EXPECT_STREQ("https://\u0573-1-\u0574\u0578.\u0570\u0561\u0575", userVisibleString(literalURL("https://\u0573-1-\u0574\u0578.\u0570\u0561\u0575")));
117     EXPECT_STREQ("https://2\u0573_\u0574\u0578.\u0570\u0561\u0575", userVisibleString(literalURL("https://2\u0573_\u0574\u0578.\u0570\u0561\u0575")));
118     EXPECT_STREQ("https://\u0573_\u0574\u05783.\u0570\u0561\u0575", userVisibleString(literalURL("https://\u0573_\u0574\u05783.\u0570\u0561\u0575")));
119     EXPECT_STREQ("https://got\u0551\u0535\u0543.com", userVisibleString(literalURL("https://got\u0551\u0535\u0543.com")));
120     EXPECT_STREQ("https://\u0551\u0535\u0543fans.net", userVisibleString(literalURL("https://\u0551\u0535\u0543fans.net")));
121     EXPECT_STREQ("https://\u0551\u0535or\u0575\u0543.biz", userVisibleString(literalURL("https://\u0551\u0535or\u0575\u0543.biz")));
122     EXPECT_STREQ("https://\u0551\u0535and!$^&*()-~+={}or<>,.?\u0575\u0543.biz", userVisibleString(literalURL("https://\u0551\u0535and!$^&*()-~+={}or<>,.?\u0575\u0543.biz")));
123 }
124
125 TEST(WebCore, URLExtras_DivisionSign)
126 {
127     // Selected the division sign as an example of a non-ASCII character that is allowed in host names, since it's a lookalike character.
128
129     // Code path similar to the one used when typing in a URL.
130     EXPECT_STREQ("http://site.xn--comothersite-kjb.org", originalDataAsString(WTF::URLWithUserTypedString(@"http://site.com\xC3\xB7othersite.org", nil)));
131     EXPECT_STREQ("http://site.com\xC3\xB7othersite.org", userVisibleString(WTF::URLWithUserTypedString(@"http://site.com\xC3\xB7othersite.org", nil)));
132
133     // Code paths similar to the ones used for URLs found in webpages or HTTP responses.
134     EXPECT_STREQ("http://site.com\xC3\xB7othersite.org", originalDataAsString(literalURL("http://site.com\xC3\xB7othersite.org")));
135     EXPECT_STREQ("http://site.com\xC3\xB7othersite.org", userVisibleString(literalURL("http://site.com\xC3\xB7othersite.org")));
136     EXPECT_STREQ("http://site.com%C3%B7othersite.org", originalDataAsString(literalURL("http://site.com%C3%B7othersite.org")));
137     EXPECT_STREQ("http://site.com\xC3\xB7othersite.org", userVisibleString(literalURL("http://site.com%C3%B7othersite.org")));
138
139     // Separate functions that deal with just a host name on its own.
140     EXPECT_STREQ("site.xn--comothersite-kjb.org", [WTF::encodeHostName(@"site.com\xC3\xB7othersite.org") UTF8String]);
141     EXPECT_STREQ("site.com\xC3\xB7othersite.org", [WTF::decodeHostName(@"site.com\xC3\xB7othersite.org") UTF8String]);
142 }
143
144 TEST(WTF, URLExtras_Solidus)
145 {
146     // Selected full width solidus, which looks like the solidus, which is the character that indicates the end of the host name.
147
148     // Code path similar to the one used when typing in a URL.
149     EXPECT_STREQ("http://site.com/othersite.org", originalDataAsString(WTF::URLWithUserTypedString(@"http://site.com\xEF\xBC\x8Fothersite.org", nil)));
150     EXPECT_STREQ("http://site.com/othersite.org", userVisibleString(WTF::URLWithUserTypedString(@"http://site.com\xEF\xBC\x8Fothersite.org", nil)));
151
152     // Code paths similar to the ones used for URLs found in webpages or HTTP responses.
153     EXPECT_STREQ("http://site.com\xEF\xBC\x8Fothersite.org", originalDataAsString(literalURL("http://site.com\xEF\xBC\x8Fothersite.org")));
154     EXPECT_STREQ("http://site.com%EF%BC%8Fothersite.org", userVisibleString(literalURL("http://site.com\xEF\xBC\x8Fothersite.org")));
155     EXPECT_STREQ("http://site.com%EF%BC%8Fothersite.org", originalDataAsString(literalURL("http://site.com%EF%BC%8Fothersite.org")));
156     EXPECT_STREQ("http://site.com%EF%BC%8Fothersite.org", userVisibleString(literalURL("http://site.com%EF%BC%8Fothersite.org")));
157
158     // Separate functions that deal with just a host name on its own.
159     EXPECT_STREQ("site.com/othersite.org", [WTF::encodeHostName(@"site.com\xEF\xBC\x8Fothersite.org") UTF8String]);
160     EXPECT_STREQ("site.com/othersite.org", [WTF::decodeHostName(@"site.com\xEF\xBC\x8Fothersite.org") UTF8String]);
161 }
162
163 TEST(WebCore, URLExtras_Space)
164 {
165     // Selected ideographic space, which looks like the ASCII space, which is not allowed unescaped.
166
167     // Code path similar to the one used when typing in a URL.
168     EXPECT_STREQ("http://site.com%20othersite.org", originalDataAsString(WTF::URLWithUserTypedString(@"http://site.com\xE3\x80\x80othersite.org", nil)));
169     EXPECT_STREQ("http://site.com%20othersite.org", userVisibleString(WTF::URLWithUserTypedString(@"http://site.com\xE3\x80\x80othersite.org", nil)));
170
171     // Code paths similar to the ones used for URLs found in webpages or HTTP responses.
172     EXPECT_STREQ("http://site.com\xE3\x80\x80othersite.org", originalDataAsString(literalURL("http://site.com\xE3\x80\x80othersite.org")));
173     EXPECT_STREQ("http://site.com%E3%80%80othersite.org", userVisibleString(literalURL("http://site.com\xE3\x80\x80othersite.org")));
174     EXPECT_STREQ("http://site.com%E3%80%80othersite.org", originalDataAsString(literalURL("http://site.com%E3%80%80othersite.org")));
175     EXPECT_STREQ("http://site.com%E3%80%80othersite.org", userVisibleString(literalURL("http://site.com%E3%80%80othersite.org")));
176
177     // Separate functions that deal with just a host name on its own.
178     EXPECT_STREQ("site.com othersite.org", [WTF::encodeHostName(@"site.com\xE3\x80\x80othersite.org") UTF8String]);
179     EXPECT_STREQ("site.com\xE3\x80\x80othersite.org", [WTF::decodeHostName(@"site.com\xE3\x80\x80othersite.org") UTF8String]);
180 }
181
182 TEST(WebCore, URLExtras_File)
183 {
184     EXPECT_STREQ("file:///%E2%98%83", [[WTF::URLWithUserTypedString(@"file:///☃", nil) absoluteString] UTF8String]);
185 }
186
187 TEST(WebCore, URLExtras_ParsingError)
188 {
189     // Expect IDN failure.
190     NSURL *url = WTF::URLWithUserTypedString(@"http://.com", nil);
191     EXPECT_TRUE(url == nil);
192
193     NSString *encodedHostName = WTF::encodeHostName(@"http://.com");
194     EXPECT_TRUE(encodedHostName == nil);
195 }
196
197 TEST(WebCore, URLExtras_Nil)
198 {
199     NSURL *url1 = WTF::URLWithUserTypedString(nil, nil);
200     EXPECT_TRUE(url1 == nil);
201
202     NSURL *url2 = WTF::URLWithUserTypedStringDeprecated(nil, nil);
203     EXPECT_TRUE(url2 == nil);
204 }
205
206 } // namespace TestWebKitAPI
207