OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved. |
3 * Copyright (C) 2012 Research In Motion Limited. All rights reserved. | 3 * Copyright (C) 2012 Research In Motion Limited. All rights reserved. |
4 * Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved. | 4 * Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved. |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
8 * are met: | 8 * are met: |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 16 matching lines...) Expand all Loading... |
27 | 27 |
28 #include "platform/weborigin/KURL.h" | 28 #include "platform/weborigin/KURL.h" |
29 | 29 |
30 #include "platform/weborigin/KnownPorts.h" | 30 #include "platform/weborigin/KnownPorts.h" |
31 #include "url/url_util.h" | 31 #include "url/url_util.h" |
32 #include "wtf/MathExtras.h" | 32 #include "wtf/MathExtras.h" |
33 #include "wtf/PtrUtil.h" | 33 #include "wtf/PtrUtil.h" |
34 #include "wtf/StdLibExtras.h" | 34 #include "wtf/StdLibExtras.h" |
35 #include "wtf/text/CString.h" | 35 #include "wtf/text/CString.h" |
36 #include "wtf/text/StringHash.h" | 36 #include "wtf/text/StringHash.h" |
37 #include "wtf/text/StringStatics.h" | |
38 #include "wtf/text/StringUTF8Adaptor.h" | 37 #include "wtf/text/StringUTF8Adaptor.h" |
39 #include "wtf/text/TextEncoding.h" | 38 #include "wtf/text/TextEncoding.h" |
40 #include <algorithm> | 39 #include <algorithm> |
41 #ifndef NDEBUG | 40 #ifndef NDEBUG |
42 #include <stdio.h> | 41 #include <stdio.h> |
43 #endif | 42 #endif |
44 | 43 |
45 namespace blink { | 44 namespace blink { |
46 | 45 |
47 static const int maximumValidPortNumber = 0xFFFE; | 46 static const int maximumValidPortNumber = 0xFFFE; |
48 static const int invalidPortNumber = 0xFFFF; | 47 static const int invalidPortNumber = 0xFFFF; |
49 | 48 |
50 static void assertProtocolIsGood(const char* protocol) { | 49 static void assertProtocolIsGood(const char* protocol) { |
51 #if ENABLE(ASSERT) | 50 #if ENABLE(ASSERT) |
52 DCHECK_NE(protocol, ""); | |
53 const char* p = protocol; | 51 const char* p = protocol; |
54 while (*p) { | 52 while (*p) { |
55 ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z')); | 53 ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z')); |
56 ++p; | 54 ++p; |
57 } | 55 } |
58 #endif | 56 #endif |
59 } | 57 } |
60 | 58 |
61 // Note: You must ensure that |spec| is a valid canonicalized URL before calling | 59 // Note: You must ensure that |spec| is a valid canonicalized URL before calling |
62 // this function. | 60 // this function. |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 init(base, relative, &encoding.encodingForFormSubmission()); | 234 init(base, relative, &encoding.encodingForFormSubmission()); |
237 } | 235 } |
238 | 236 |
239 KURL::KURL(const AtomicString& canonicalString, | 237 KURL::KURL(const AtomicString& canonicalString, |
240 const url::Parsed& parsed, | 238 const url::Parsed& parsed, |
241 bool isValid) | 239 bool isValid) |
242 : m_isValid(isValid), | 240 : m_isValid(isValid), |
243 m_protocolIsInHTTPFamily(false), | 241 m_protocolIsInHTTPFamily(false), |
244 m_parsed(parsed), | 242 m_parsed(parsed), |
245 m_string(canonicalString) { | 243 m_string(canonicalString) { |
246 initProtocolMetadata(); | 244 initProtocolIsInHTTPFamily(); |
247 initInnerURL(); | 245 initInnerURL(); |
248 } | 246 } |
249 | 247 |
250 KURL::KURL(WTF::HashTableDeletedValueType) | 248 KURL::KURL(WTF::HashTableDeletedValueType) |
251 : m_isValid(false), | 249 : m_isValid(false), |
252 m_protocolIsInHTTPFamily(false), | 250 m_protocolIsInHTTPFamily(false), |
253 m_string(WTF::HashTableDeletedValue) {} | 251 m_string(WTF::HashTableDeletedValue) {} |
254 | 252 |
255 KURL::KURL(const KURL& other) | 253 KURL::KURL(const KURL& other) |
256 : m_isValid(other.m_isValid), | 254 : m_isValid(other.m_isValid), |
257 m_protocolIsInHTTPFamily(other.m_protocolIsInHTTPFamily), | 255 m_protocolIsInHTTPFamily(other.m_protocolIsInHTTPFamily), |
258 m_protocol(other.m_protocol), | |
259 m_parsed(other.m_parsed), | 256 m_parsed(other.m_parsed), |
260 m_string(other.m_string) { | 257 m_string(other.m_string) { |
261 if (other.m_innerURL.get()) | 258 if (other.m_innerURL.get()) |
262 m_innerURL = WTF::wrapUnique(new KURL(other.m_innerURL->copy())); | 259 m_innerURL = WTF::wrapUnique(new KURL(other.m_innerURL->copy())); |
263 } | 260 } |
264 | 261 |
265 KURL::~KURL() {} | 262 KURL::~KURL() {} |
266 | 263 |
267 KURL& KURL::operator=(const KURL& other) { | 264 KURL& KURL::operator=(const KURL& other) { |
268 m_isValid = other.m_isValid; | 265 m_isValid = other.m_isValid; |
269 m_protocolIsInHTTPFamily = other.m_protocolIsInHTTPFamily; | 266 m_protocolIsInHTTPFamily = other.m_protocolIsInHTTPFamily; |
270 m_protocol = other.m_protocol; | |
271 m_parsed = other.m_parsed; | 267 m_parsed = other.m_parsed; |
272 m_string = other.m_string; | 268 m_string = other.m_string; |
273 if (other.m_innerURL) | 269 if (other.m_innerURL) |
274 m_innerURL = WTF::wrapUnique(new KURL(other.m_innerURL->copy())); | 270 m_innerURL = WTF::wrapUnique(new KURL(other.m_innerURL->copy())); |
275 else | 271 else |
276 m_innerURL.reset(); | 272 m_innerURL.reset(); |
277 return *this; | 273 return *this; |
278 } | 274 } |
279 | 275 |
280 KURL KURL::copy() const { | 276 KURL KURL::copy() const { |
281 KURL result; | 277 KURL result; |
282 result.m_isValid = m_isValid; | 278 result.m_isValid = m_isValid; |
283 result.m_protocolIsInHTTPFamily = m_protocolIsInHTTPFamily; | 279 result.m_protocolIsInHTTPFamily = m_protocolIsInHTTPFamily; |
284 result.m_protocol = m_protocol.isolatedCopy(); | |
285 result.m_parsed = m_parsed; | 280 result.m_parsed = m_parsed; |
286 result.m_string = m_string.isolatedCopy(); | 281 result.m_string = m_string.isolatedCopy(); |
287 if (m_innerURL) | 282 if (m_innerURL) |
288 result.m_innerURL = WTF::wrapUnique(new KURL(m_innerURL->copy())); | 283 result.m_innerURL = WTF::wrapUnique(new KURL(m_innerURL->copy())); |
289 return result; | 284 return result; |
290 } | 285 } |
291 | 286 |
292 bool KURL::isNull() const { | 287 bool KURL::isNull() const { |
293 return m_string.isNull(); | 288 return m_string.isNull(); |
294 } | 289 } |
(...skipping 15 matching lines...) Expand all Loading... |
310 } | 305 } |
311 | 306 |
312 bool KURL::hasPath() const { | 307 bool KURL::hasPath() const { |
313 // Note that http://www.google.com/" has a path, the path is "/". This can | 308 // Note that http://www.google.com/" has a path, the path is "/". This can |
314 // return false only for invalid or nonstandard URLs. | 309 // return false only for invalid or nonstandard URLs. |
315 return m_parsed.path.len >= 0; | 310 return m_parsed.path.len >= 0; |
316 } | 311 } |
317 | 312 |
318 String KURL::lastPathComponent() const { | 313 String KURL::lastPathComponent() const { |
319 if (!m_isValid) | 314 if (!m_isValid) |
320 return stringViewForInvalidComponent().toString(); | 315 return stringForInvalidComponent(); |
321 ASSERT(!m_string.isNull()); | 316 ASSERT(!m_string.isNull()); |
322 | 317 |
323 // When the output ends in a slash, WebCore has different expectations than | 318 // When the output ends in a slash, WebCore has different expectations than |
324 // the GoogleURL library. For "/foo/bar/" the library will return the empty | 319 // the GoogleURL library. For "/foo/bar/" the library will return the empty |
325 // string, but WebCore wants "bar". | 320 // string, but WebCore wants "bar". |
326 url::Component path = m_parsed.path; | 321 url::Component path = m_parsed.path; |
327 if (path.len > 0 && m_string[path.end() - 1] == '/') | 322 if (path.len > 0 && m_string[path.end() - 1] == '/') |
328 path.len--; | 323 path.len--; |
329 | 324 |
330 url::Component file; | 325 url::Component file; |
331 if (m_string.is8Bit()) | 326 if (m_string.is8Bit()) |
332 url::ExtractFileName(asURLChar8Subtle(m_string), path, &file); | 327 url::ExtractFileName(asURLChar8Subtle(m_string), path, &file); |
333 else | 328 else |
334 url::ExtractFileName(m_string.characters16(), path, &file); | 329 url::ExtractFileName(m_string.characters16(), path, &file); |
335 | 330 |
336 // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns | 331 // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns |
337 // a null string when the path is empty, which we duplicate here. | 332 // a null string when the path is empty, which we duplicate here. |
338 if (!file.is_nonempty()) | 333 if (!file.is_nonempty()) |
339 return String(); | 334 return String(); |
340 return componentString(file); | 335 return componentString(file); |
341 } | 336 } |
342 | 337 |
343 String KURL::protocol() const { | 338 String KURL::protocol() const { |
344 DCHECK_EQ(componentString(m_parsed.scheme), m_protocol); | 339 return componentString(m_parsed.scheme); |
345 return m_protocol; | |
346 } | 340 } |
347 | 341 |
348 String KURL::host() const { | 342 String KURL::host() const { |
349 return componentString(m_parsed.host); | 343 return componentString(m_parsed.host); |
350 } | 344 } |
351 | 345 |
352 // Returns 0 when there is no port. | 346 // Returns 0 when there is no port. |
353 // | 347 // |
354 // We treat URL's with out-of-range port numbers as invalid URLs, and they will | 348 // We treat URL's with out-of-range port numbers as invalid URLs, and they will |
355 // be rejected by the canonicalizer. KURL.cpp will allow them in parsing, but | 349 // be rejected by the canonicalizer. KURL.cpp will allow them in parsing, but |
356 // return invalidPortNumber from this port() function, so we mirror that | 350 // return invalidPortNumber from this port() function, so we mirror that |
357 // behavior here. | 351 // behavior here. |
358 unsigned short KURL::port() const { | 352 unsigned short KURL::port() const { |
359 if (!m_isValid || m_parsed.port.len <= 0) | 353 if (!m_isValid || m_parsed.port.len <= 0) |
360 return 0; | 354 return 0; |
361 ASSERT(!m_string.isNull()); | 355 ASSERT(!m_string.isNull()); |
362 int port = m_string.is8Bit() | 356 int port = m_string.is8Bit() |
363 ? url::ParsePort(asURLChar8Subtle(m_string), m_parsed.port) | 357 ? url::ParsePort(asURLChar8Subtle(m_string), m_parsed.port) |
364 : url::ParsePort(m_string.characters16(), m_parsed.port); | 358 : url::ParsePort(m_string.characters16(), m_parsed.port); |
365 ASSERT(port != url::PORT_UNSPECIFIED); // Checked port.len <= 0 before. | 359 ASSERT(port != url::PORT_UNSPECIFIED); // Checked port.len <= 0 before. |
366 | 360 |
367 if (port == url::PORT_INVALID || | 361 if (port == url::PORT_INVALID || |
368 port > maximumValidPortNumber) // Mimic KURL::port() | 362 port > maximumValidPortNumber) // Mimic KURL::port() |
369 port = invalidPortNumber; | 363 port = invalidPortNumber; |
370 | 364 |
371 return static_cast<unsigned short>(port); | 365 return static_cast<unsigned short>(port); |
372 } | 366 } |
373 | 367 |
374 // TODO(csharrison): Migrate pass() and user() to return a StringView. Most | |
375 // consumers just need to know if the string is empty. | |
376 | |
377 String KURL::pass() const { | 368 String KURL::pass() const { |
378 // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns | 369 // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns |
379 // a null string when the password is empty, which we duplicate here. | 370 // a null string when the password is empty, which we duplicate here. |
380 if (!m_parsed.password.is_nonempty()) | 371 if (!m_parsed.password.is_nonempty()) |
381 return String(); | 372 return String(); |
382 return componentString(m_parsed.password); | 373 return componentString(m_parsed.password); |
383 } | 374 } |
384 | 375 |
385 String KURL::user() const { | 376 String KURL::user() const { |
386 return componentString(m_parsed.username); | 377 return componentString(m_parsed.username); |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 // non-Atomic input as Atomic here, we will render the (const) input string | 760 // non-Atomic input as Atomic here, we will render the (const) input string |
770 // thread unsafe. | 761 // thread unsafe. |
771 if (!relative.isNull() && relative.impl()->isAtomic() && | 762 if (!relative.isNull() && relative.impl()->isAtomic() && |
772 StringView(output.data(), static_cast<unsigned>(output.length())) == | 763 StringView(output.data(), static_cast<unsigned>(output.length())) == |
773 relative) { | 764 relative) { |
774 m_string = relative; | 765 m_string = relative; |
775 } else { | 766 } else { |
776 m_string = AtomicString::fromUTF8(output.data(), output.length()); | 767 m_string = AtomicString::fromUTF8(output.data(), output.length()); |
777 } | 768 } |
778 | 769 |
779 initProtocolMetadata(); | 770 initProtocolIsInHTTPFamily(); |
780 initInnerURL(); | 771 initInnerURL(); |
| 772 DCHECK_EQ(protocol(), protocol().lower()); |
781 } | 773 } |
782 | 774 |
783 void KURL::initInnerURL() { | 775 void KURL::initInnerURL() { |
784 if (!m_isValid) { | 776 if (!m_isValid) { |
785 m_innerURL.reset(); | 777 m_innerURL.reset(); |
786 return; | 778 return; |
787 } | 779 } |
788 if (url::Parsed* innerParsed = m_parsed.inner_parsed()) | 780 if (url::Parsed* innerParsed = m_parsed.inner_parsed()) |
789 m_innerURL = WTF::wrapUnique(new KURL( | 781 m_innerURL = WTF::wrapUnique(new KURL( |
790 ParsedURLString, | 782 ParsedURLString, |
791 m_string.substring(innerParsed->scheme.begin, | 783 m_string.substring(innerParsed->scheme.begin, |
792 innerParsed->Length() - innerParsed->scheme.begin))); | 784 innerParsed->Length() - innerParsed->scheme.begin))); |
793 else | 785 else |
794 m_innerURL.reset(); | 786 m_innerURL.reset(); |
795 } | 787 } |
796 | 788 |
797 void KURL::initProtocolMetadata() { | 789 template <typename CHAR> |
| 790 bool internalProtocolIs(const url::Component& scheme, |
| 791 const CHAR* spec, |
| 792 const char* protocol) { |
| 793 const CHAR* begin = spec + scheme.begin; |
| 794 const CHAR* end = begin + scheme.len; |
| 795 |
| 796 while (begin != end && *protocol) { |
| 797 ASSERT(toASCIILower(*protocol) == *protocol); |
| 798 if (toASCIILower(*begin++) != *protocol++) |
| 799 return false; |
| 800 } |
| 801 |
| 802 // Both strings are equal (ignoring case) if and only if all of the characters |
| 803 // were equal, and the end of both has been reached. |
| 804 return begin == end && !*protocol; |
| 805 } |
| 806 |
| 807 template <typename CHAR> |
| 808 bool checkIfProtocolIsInHTTPFamily(const url::Component& scheme, |
| 809 const CHAR* spec) { |
| 810 if (scheme.len == 4) |
| 811 return internalProtocolIs(scheme, spec, "http"); |
| 812 if (scheme.len == 5) |
| 813 return internalProtocolIs(scheme, spec, "https"); |
| 814 if (scheme.len == 7) |
| 815 return internalProtocolIs(scheme, spec, "http-so"); |
| 816 if (scheme.len == 8) |
| 817 return internalProtocolIs(scheme, spec, "https-so"); |
| 818 return false; |
| 819 } |
| 820 |
| 821 void KURL::initProtocolIsInHTTPFamily() { |
798 if (!m_isValid) { | 822 if (!m_isValid) { |
799 m_protocolIsInHTTPFamily = false; | 823 m_protocolIsInHTTPFamily = false; |
800 m_protocol = componentString(m_parsed.scheme); | |
801 return; | 824 return; |
802 } | 825 } |
803 | 826 |
804 DCHECK(!m_string.isNull()); | 827 ASSERT(!m_string.isNull()); |
805 StringView protocol = componentStringView(m_parsed.scheme); | 828 m_protocolIsInHTTPFamily = |
806 m_protocolIsInHTTPFamily = true; | 829 m_string.is8Bit() ? checkIfProtocolIsInHTTPFamily(m_parsed.scheme, |
807 if (protocol == WTF::httpsAtom) { | 830 m_string.characters8()) |
808 m_protocol = WTF::httpsAtom; | 831 : checkIfProtocolIsInHTTPFamily( |
809 } else if (protocol == WTF::httpAtom) { | 832 m_parsed.scheme, m_string.characters16()); |
810 m_protocol = WTF::httpAtom; | |
811 } else { | |
812 m_protocol = AtomicString(protocol.toString()); | |
813 m_protocolIsInHTTPFamily = | |
814 m_protocol == "http-so" || m_protocol == "https-so"; | |
815 } | |
816 DCHECK_EQ(m_protocol, m_protocol.lower()); | |
817 } | 833 } |
818 | 834 |
819 bool KURL::protocolIs(const char* protocol) const { | 835 bool KURL::protocolIs(const char* protocol) const { |
820 assertProtocolIsGood(protocol); | 836 assertProtocolIsGood(protocol); |
821 | 837 |
822 // JavaScript URLs are "valid" and should be executed even if KURL decides | 838 // JavaScript URLs are "valid" and should be executed even if KURL decides |
823 // they are invalid. The free function protocolIsJavaScript() should be used | 839 // they are invalid. The free function protocolIsJavaScript() should be used |
824 // instead. | 840 // instead. |
825 // FIXME: Chromium code needs to be fixed for this assert to be enabled. | 841 // FIXME: Chromium code needs to be fixed for this assert to be enabled. |
826 // ASSERT(strcmp(protocol, "javascript")); | 842 // ASSERT(strcmp(protocol, "javascript")); |
827 return m_protocol == protocol; | 843 |
| 844 if (m_string.isNull() || m_parsed.scheme.len <= 0) |
| 845 return *protocol == '\0'; |
| 846 |
| 847 return m_string.is8Bit() |
| 848 ? internalProtocolIs(m_parsed.scheme, m_string.characters8(), |
| 849 protocol) |
| 850 : internalProtocolIs(m_parsed.scheme, m_string.characters16(), |
| 851 protocol); |
828 } | 852 } |
829 | 853 |
830 StringView KURL::stringViewForInvalidComponent() const { | 854 String KURL::stringForInvalidComponent() const { |
831 return m_string.isNull() ? StringView() : StringView("", 0); | 855 if (m_string.isNull()) |
| 856 return String(); |
| 857 return emptyString(); |
832 } | 858 } |
833 | 859 |
834 StringView KURL::componentStringView(const url::Component& component) const { | 860 String KURL::componentString(const url::Component& component) const { |
835 if (!m_isValid || component.len <= 0) | 861 if (!m_isValid || component.len <= 0) |
836 return stringViewForInvalidComponent(); | 862 return stringForInvalidComponent(); |
837 // begin and len are in terms of bytes which do not match | 863 // begin and len are in terms of bytes which do not match |
838 // if string() is UTF-16 and input contains non-ASCII characters. | 864 // if string() is UTF-16 and input contains non-ASCII characters. |
839 // However, the only part in urlString that can contain non-ASCII | 865 // However, the only part in urlString that can contain non-ASCII |
840 // characters is 'ref' at the end of the string. In that case, | 866 // characters is 'ref' at the end of the string. In that case, |
841 // begin will always match the actual value and len (in terms of | 867 // begin will always match the actual value and len (in terms of |
842 // byte) will be longer than what's needed by 'mid'. However, mid | 868 // byte) will be longer than what's needed by 'mid'. However, mid |
843 // truncates len to avoid go past the end of a string so that we can | 869 // truncates len to avoid go past the end of a string so that we can |
844 // get away without doing anything here. | 870 // get away without doing anything here. |
845 | 871 return getString().substring(component.begin, component.len); |
846 int maxLength = getString().length() - component.begin; | |
847 return StringView(getString(), component.begin, | |
848 component.len > maxLength ? maxLength : component.len); | |
849 } | |
850 | |
851 String KURL::componentString(const url::Component& component) const { | |
852 return componentStringView(component).toString(); | |
853 } | 872 } |
854 | 873 |
855 template <typename CHAR> | 874 template <typename CHAR> |
856 void KURL::replaceComponents(const url::Replacements<CHAR>& replacements) { | 875 void KURL::replaceComponents(const url::Replacements<CHAR>& replacements) { |
857 url::RawCanonOutputT<char> output; | 876 url::RawCanonOutputT<char> output; |
858 url::Parsed newParsed; | 877 url::Parsed newParsed; |
859 | 878 |
860 StringUTF8Adaptor utf8(m_string); | 879 StringUTF8Adaptor utf8(m_string); |
861 m_isValid = url::ReplaceComponents(utf8.data(), utf8.length(), m_parsed, | 880 m_isValid = url::ReplaceComponents(utf8.data(), utf8.length(), m_parsed, |
862 replacements, 0, &output, &newParsed); | 881 replacements, 0, &output, &newParsed); |
863 | 882 |
864 m_parsed = newParsed; | 883 m_parsed = newParsed; |
865 m_string = AtomicString::fromUTF8(output.data(), output.length()); | 884 m_string = AtomicString::fromUTF8(output.data(), output.length()); |
866 initProtocolMetadata(); | |
867 } | 885 } |
868 | 886 |
869 bool KURL::isSafeToSendToAnotherThread() const { | 887 bool KURL::isSafeToSendToAnotherThread() const { |
870 return m_string.isSafeToSendToAnotherThread() && | 888 return m_string.isSafeToSendToAnotherThread() && |
871 (!m_innerURL || m_innerURL->isSafeToSendToAnotherThread()); | 889 (!m_innerURL || m_innerURL->isSafeToSendToAnotherThread()); |
872 } | 890 } |
873 | 891 |
874 } // namespace blink | 892 } // namespace blink |
OLD | NEW |