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 = wrapUnique(new KURL(other.m_innerURL->copy())); | 262 m_innerURL = 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 = wrapUnique(new KURL(other.m_innerURL->copy())); | 274 m_innerURL = 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 = wrapUnique(new KURL(m_innerURL->copy())); | 288 result.m_innerURL = 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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 return m_protocol; |
340 } | 345 } |
341 | 346 |
342 String KURL::host() const { | 347 String KURL::host() const { |
343 return componentString(m_parsed.host); | 348 return componentString(m_parsed.host); |
344 } | 349 } |
345 | 350 |
346 // Returns 0 when there is no port. | 351 // Returns 0 when there is no port. |
347 // | 352 // |
348 // We treat URL's with out-of-range port numbers as invalid URLs, and they will | 353 // 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 | 354 // be rejected by the canonicalizer. KURL.cpp will allow them in parsing, but |
350 // return invalidPortNumber from this port() function, so we mirror that | 355 // return invalidPortNumber from this port() function, so we mirror that |
351 // behavior here. | 356 // behavior here. |
352 unsigned short KURL::port() const { | 357 unsigned short KURL::port() const { |
353 if (!m_isValid || m_parsed.port.len <= 0) | 358 if (!m_isValid || m_parsed.port.len <= 0) |
354 return 0; | 359 return 0; |
355 ASSERT(!m_string.isNull()); | 360 ASSERT(!m_string.isNull()); |
356 int port = m_string.is8Bit() | 361 int port = m_string.is8Bit() |
357 ? url::ParsePort(asURLChar8Subtle(m_string), m_parsed.port) | 362 ? url::ParsePort(asURLChar8Subtle(m_string), m_parsed.port) |
358 : url::ParsePort(m_string.characters16(), m_parsed.port); | 363 : url::ParsePort(m_string.characters16(), m_parsed.port); |
359 ASSERT(port != url::PORT_UNSPECIFIED); // Checked port.len <= 0 before. | 364 ASSERT(port != url::PORT_UNSPECIFIED); // Checked port.len <= 0 before. |
360 | 365 |
361 if (port == url::PORT_INVALID || | 366 if (port == url::PORT_INVALID || |
362 port > maximumValidPortNumber) // Mimic KURL::port() | 367 port > maximumValidPortNumber) // Mimic KURL::port() |
363 port = invalidPortNumber; | 368 port = invalidPortNumber; |
364 | 369 |
365 return static_cast<unsigned short>(port); | 370 return static_cast<unsigned short>(port); |
366 } | 371 } |
367 | 372 |
373 // TODO(csharrison): Migrate pass() and user() to return a StringView. Most | |
374 // consumers just need to know if the string is empty. | |
375 | |
368 String KURL::pass() const { | 376 String KURL::pass() const { |
369 // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns | 377 // 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. | 378 // a null string when the password is empty, which we duplicate here. |
371 if (!m_parsed.password.is_nonempty()) | 379 if (!m_parsed.password.is_nonempty()) |
372 return String(); | 380 return String(); |
373 return componentString(m_parsed.password); | 381 return componentString(m_parsed.password); |
374 } | 382 } |
375 | 383 |
376 String KURL::user() const { | 384 String KURL::user() const { |
377 return componentString(m_parsed.username); | 385 return componentString(m_parsed.username); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
426 if (!url::CanonicalizeScheme(newProtocolUTF8.data(), | 434 if (!url::CanonicalizeScheme(newProtocolUTF8.data(), |
427 url::Component(0, newProtocolUTF8.length()), | 435 url::Component(0, newProtocolUTF8.length()), |
428 &canonProtocol, &protocolComponent) || | 436 &canonProtocol, &protocolComponent) || |
429 !protocolComponent.is_nonempty()) | 437 !protocolComponent.is_nonempty()) |
430 return false; | 438 return false; |
431 | 439 |
432 url::Replacements<char> replacements; | 440 url::Replacements<char> replacements; |
433 replacements.SetScheme(charactersOrEmpty(newProtocolUTF8), | 441 replacements.SetScheme(charactersOrEmpty(newProtocolUTF8), |
434 url::Component(0, newProtocolUTF8.length())); | 442 url::Component(0, newProtocolUTF8.length())); |
435 replaceComponents(replacements); | 443 replaceComponents(replacements); |
444 initProtocolMetadata(); | |
436 | 445 |
437 // isValid could be false but we still return true here. This is because | 446 // isValid could be false but we still return true here. This is because |
438 // WebCore or JS scripts can build up a URL by setting individual | 447 // WebCore or JS scripts can build up a URL by setting individual |
439 // components, and a JS exception is based on the return value of this | 448 // components, and a JS exception is based on the return value of this |
440 // function. We want to throw the exception and stop the script only when | 449 // function. We want to throw the exception and stop the script only when |
441 // its trying to set a bad protocol, and not when it maybe just hasn't | 450 // its trying to set a bad protocol, and not when it maybe just hasn't |
442 // finished building up its final scheme. | 451 // finished building up its final scheme. |
443 return true; | 452 return true; |
444 } | 453 } |
445 | 454 |
(...skipping 314 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()); | 781 DCHECK_EQ(protocol(), protocol().lower()); |
773 } | 782 } |
774 | 783 |
775 void KURL::initInnerURL() { | 784 void KURL::initInnerURL() { |
776 if (!m_isValid) { | 785 if (!m_isValid) { |
777 m_innerURL.reset(); | 786 m_innerURL.reset(); |
778 return; | 787 return; |
779 } | 788 } |
780 if (url::Parsed* innerParsed = m_parsed.inner_parsed()) | 789 if (url::Parsed* innerParsed = m_parsed.inner_parsed()) |
781 m_innerURL = wrapUnique(new KURL( | 790 m_innerURL = wrapUnique(new KURL( |
782 ParsedURLString, | 791 ParsedURLString, |
783 m_string.substring(innerParsed->scheme.begin, | 792 m_string.substring(innerParsed->scheme.begin, |
784 innerParsed->Length() - innerParsed->scheme.begin))); | 793 innerParsed->Length() - innerParsed->scheme.begin))); |
785 else | 794 else |
786 m_innerURL.reset(); | 795 m_innerURL.reset(); |
787 } | 796 } |
788 | 797 |
789 template <typename CHAR> | 798 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"); | |
esprehn
2016/12/12 22:18:46
This was all case insensitive before.
Charlie Harrison
2016/12/12 22:26:06
We should always have a canonical, lowercase schem
Charlie Harrison
2016/12/13 16:03:22
Actually, we have a DCHECK_EQ(protocol(), protocol
| |
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) { | 799 if (!m_isValid) { |
823 m_protocolIsInHTTPFamily = false; | 800 m_protocolIsInHTTPFamily = false; |
824 return; | 801 return; |
825 } | 802 } |
826 | 803 |
827 ASSERT(!m_string.isNull()); | 804 ASSERT(!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"; | |
esprehn
2016/12/12 22:18:46
What strange protocols are these?
Charlie Harrison
2016/12/12 22:26:06
suborigin protocols:
https://w3c.github.io/webapps
| |
815 } | |
833 } | 816 } |
834 | 817 |
835 bool KURL::protocolIs(const char* protocol) const { | 818 bool KURL::protocolIs(const char* protocol) const { |
836 assertProtocolIsGood(protocol); | 819 assertProtocolIsGood(protocol); |
837 | 820 |
838 // JavaScript URLs are "valid" and should be executed even if KURL decides | 821 // JavaScript URLs are "valid" and should be executed even if KURL decides |
839 // they are invalid. The free function protocolIsJavaScript() should be used | 822 // they are invalid. The free function protocolIsJavaScript() should be used |
840 // instead. | 823 // instead. |
841 // FIXME: Chromium code needs to be fixed for this assert to be enabled. | 824 // FIXME: Chromium code needs to be fixed for this assert to be enabled. |
842 // ASSERT(strcmp(protocol, "javascript")); | 825 // ASSERT(strcmp(protocol, "javascript")); |
843 | 826 return m_protocol == protocol; |
esprehn
2016/12/12 22:18:46
internalProtocolIs was case insensitive, are you s
Charlie Harrison
2016/12/12 22:26:06
assertProtocolIsGood checks that the input protoco
| |
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 } | 827 } |
853 | 828 |
854 String KURL::stringForInvalidComponent() const { | 829 String KURL::stringForInvalidComponent() const { |
855 if (m_string.isNull()) | 830 if (m_string.isNull()) |
856 return String(); | 831 return String(); |
857 return emptyString(); | 832 return emptyString(); |
858 } | 833 } |
859 | 834 |
860 String KURL::componentString(const url::Component& component) const { | 835 StringView KURL::componentStringView(const url::Component& component) const { |
861 if (!m_isValid || component.len <= 0) | 836 if (!m_isValid || component.len <= 0) |
862 return stringForInvalidComponent(); | 837 return stringForInvalidComponent(); |
863 // begin and len are in terms of bytes which do not match | 838 // begin and len are in terms of bytes which do not match |
864 // if string() is UTF-16 and input contains non-ASCII characters. | 839 // if string() is UTF-16 and input contains non-ASCII characters. |
865 // However, the only part in urlString that can contain non-ASCII | 840 // However, the only part in urlString that can contain non-ASCII |
866 // characters is 'ref' at the end of the string. In that case, | 841 // 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 | 842 // 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 | 843 // 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 | 844 // truncates len to avoid go past the end of a string so that we can |
870 // get away without doing anything here. | 845 // get away without doing anything here. |
871 return getString().substring(component.begin, component.len); | 846 |
847 int maxLength = getString().length() - component.begin; | |
848 return StringView(getString(), component.begin, | |
849 component.len > maxLength ? maxLength : component.len); | |
850 } | |
851 | |
852 String KURL::componentString(const url::Component& component) const { | |
853 return componentStringView(component).toString(); | |
872 } | 854 } |
873 | 855 |
874 template <typename CHAR> | 856 template <typename CHAR> |
875 void KURL::replaceComponents(const url::Replacements<CHAR>& replacements) { | 857 void KURL::replaceComponents(const url::Replacements<CHAR>& replacements) { |
876 url::RawCanonOutputT<char> output; | 858 url::RawCanonOutputT<char> output; |
877 url::Parsed newParsed; | 859 url::Parsed newParsed; |
878 | 860 |
879 StringUTF8Adaptor utf8(m_string); | 861 StringUTF8Adaptor utf8(m_string); |
880 m_isValid = url::ReplaceComponents(utf8.data(), utf8.length(), m_parsed, | 862 m_isValid = url::ReplaceComponents(utf8.data(), utf8.length(), m_parsed, |
881 replacements, 0, &output, &newParsed); | 863 replacements, 0, &output, &newParsed); |
882 | 864 |
883 m_parsed = newParsed; | 865 m_parsed = newParsed; |
884 m_string = AtomicString::fromUTF8(output.data(), output.length()); | 866 m_string = AtomicString::fromUTF8(output.data(), output.length()); |
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 |