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