Move URL to use StringView when returning substrings of the URL
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 25 Apr 2020 18:01:55 +0000 (18:01 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 25 Apr 2020 18:01:55 +0000 (18:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=210431

Reviewed by Anders Carlsson.

LayoutTests/imported/w3c:

* web-platform-tests/url/url-setters-expected.txt: Updated expected results for progression in
correct behavior when port numbers are >65535. I didn't originally intend to make this improvement,
but it fell out naturally from the refactoring changes.

Source/WebCore:

* Modules/cache/DOMCacheEngine.cpp:
(WebCore::DOMCacheEngine::matchURLs): Removed unneeded calls to hasQuery.

* Modules/fetch/FetchRequest.cpp:
(WebCore::FetchRequest::initializeWith): Use hasCredentials.
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::redirect): Use hasCredentials.
* Modules/paymentrequest/PaymentRequest.cpp:
(WebCore::isValidURLBasedPaymentMethodIdentifier): Use hasCredentials.

* Modules/plugins/YouTubePluginReplacement.cpp:
(WebCore::createYouTubeURL): Take StringView.
(WebCore::queryKeysAndValues): Take StringView.
(WebCore::processAndCreateYouTubeURL): Use auto since URL pieces are
now returned as StringView.
(WebCore::YouTubePluginReplacement::youTubeURLFromAbsoluteURL):
Use StringView and makeString rather than StringBuilder.

* Modules/websockets/WebSocketHandshake.cpp:
(WebCore::resourceName): Use queryWithLeadingQuestionMark.

* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::internalLinkElement const):
Use StringView.

* dom/Document.cpp:
(WebCore::Document::setURL): Use setHostAndPort.

* dom/Element.cpp:
(WebCore::Element::findAnchorElementForLink): Update since
fragmentIdentifier returns StringView.

* dom/TreeScope.cpp: Added a comment.

* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::replaceRichContentWithAttachments): Update since
lastPathComponent returns a StringView. Also got rid of some strange
use of AtomString that was not necessary and used WTFMove more.

* editing/ios/EditorIOS.mm:
(WebCore::Editor::writeImageToPasteboard): Update since
lastPathComponent returns a StringView.

* html/HTMLAttachmentElement.cpp:
(WebCore::HTMLAttachmentElement::attachmentTitleForDisplay const):
Use makeString instead of StringBuilder, and StringView instead of
String for name and extension values.

* html/HTMLPlugInElement.cpp:
(WebCore::pluginReplacementForType): Update since lastPathComponent
returns a StringView.

* html/MediaFragmentURIParser.cpp:
(WebCore::MediaFragmentURIParser::parseFragments): Update since
fragmentIdentifier returns a StringView.

* html/URLUtils.h: Changed many functions to take a StringView, changed
various other functions to call toString, since the underlying URL
function now returns a StringView. Updated names since "pass" is now
"password".
(WebCore::countASCIIDigits): Added. Replaces unusual function
named parsePortFromStringPosition because we can use StringView now
and so don't need such an unusual function.

* loader/AdClickAttribution.cpp:
(WebCore::AdClickAttribution::parseConversionRequest): Use hasCredentials.
Also removed unnecessary use of ASCIILiteral that hurts performance
a tiny bit.
(WebCore::AdClickAttribution::urlForTesting const): Use makeString
instead of StringBuilder.

* loader/CrossOriginAccessControl.cpp:
(WebCore::validateCrossOriginRedirectionURL): Use hasCredentials.
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::loadRequest): Use hasCredentials.

* loader/FormSubmission.cpp:
(WebCore::appendMailtoPostFormDataToURL): Update since query returns
StringView.

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadInSameDocument): Use equalRespectingNullity on
fragment identifiers to preserve behavior, since at this time
StringView == StringView does not respect nullity, but String == String does.

* loader/appcache/ApplicationCacheHost.cpp:
(WebCore::ApplicationCacheHost::createFileURL): Use fileURLWithFileSystemPath.

* loader/appcache/ManifestParser.cpp:
(WebCore::manifestPath): Return a StringView.
(WebCore::parseManifest): Use StringView.

* loader/cache/CachedFont.cpp:
(WebCore::CachedFont::calculateItemInCollection const): Update since
fragmentIdentifer returns a StringView.
* loader/cache/CachedResourceRequest.cpp:
(WebCore::CachedResourceRequest::splitFragmentIdentifierFromRequestURL): Ditto.
* page/FrameView.cpp:
(WebCore::FrameView::scrollToFragment): Ditto.
(WebCore::FrameView::scrollToFragmentInternal): Updated log message.

* page/History.cpp:
(WebCore::History::stateObjectAdded): Updated for URL::password name change
and to use the new stringWithoutQueryOrFragmentIdentifier rather than the
old equalIgnoringQueryAndFragment.

* page/Location.cpp:
(WebCore::Location::href const): Use removeCredentials.
(WebCore::Location::port const): Streamlined.
(WebCore::Location::pathname const): Use an ASCIILiteral.
(WebCore::Location::search const): Use queryWithLeadingQuestionMark.
(WebCore::Location::hash const): Use fragmentIdentifierWithLeadingNumberSign.
(WebCore::Location::setPort): Use parseUInt16.

* page/UserContentURLPattern.cpp: Coding style tweaks.

* platform/MIMETypeRegistry.cpp:
(WebCore::MIMETypeRegistry::appendFileExtensionIfNecessary):
Use contains instead of reverseFind to check for a period in the filename.

* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::load): Updated since lastPathComponent is a StringView.

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::convertToInternalProtocol): Updated to use makeString since
setProtocol takes a StringView.

* platform/network/ResourceHandleInternal.h: Renamed m_pass to m_password
and call password instead of pass.

* platform/network/ResourceRequestBase.cpp:
(WebCore::ResourceRequestBase::removeCredentials): Use removeCredentials.

* platform/network/cf/ResourceHandleCFNet.cpp:
(WebCore::ResourceHandle::createCFURLConnection): Updated for m_password
name change.
(WebCore::ResourceHandle::willSendRequest): Updated for m_password and
password name changes.
(WebCore::ResourceHandle::tryHandlePasswordBasedAuthentication): Ditto.

* platform/network/curl/CurlProxySettings.cpp:
(WebCore::CurlProxySettings::setUserPass): Updated for setPassword name change.
(WebCore::createProxyUrl): Use hasCredentials, updated for password name change.
* platform/network/curl/CurlProxySettings.h:
(WebCore::CurlProxySettings::password const): Updated for password name change.

* platform/network/curl/ResourceHandleCurl.cpp:
(WebCore::ResourceHandle::didReceiveAuthenticationChallenge): Updated for
m_password name change.
(WebCore::ResourceHandle::getCredential): Ditto.
(WebCore::ResourceHandle::willSendRequest): Updated for m_password and
password name changes.

* platform/network/mac/ResourceHandleMac.mm:
(WebCore::ResourceHandle::createNSURLConnection): Updated for m_password
and setPassword name changes.
(WebCore::ResourceHandle::willSendRequest): Ditto.
(WebCore::ResourceHandle::tryHandlePasswordBasedAuthentication): Ditto.

* platform/network/soup/ResourceRequestSoup.cpp:
(WebCore::ResourceRequest::createSoupURI const): Updated for password name change.
* platform/network/soup/URLSoup.cpp:
(WebCore::soupURIToURL): Updated for setPassword name change.

* platform/win/PasteboardWin.cpp:
(WebCore::writeURL): Updated since lastPathComponent returns a StringView.
(WebCore::filesystemPathFromUrlOrTitle): Ditto.
(WebCore::Pasteboard::write): Ditto.

* style/StyleBuilderState.cpp:
(WebCore::Style::BuilderState::createFilterOperations): Updated since
fragmentIdentifier returns a StringView.

* workers/WorkerLocation.cpp:
(WebCore::WorkerLocation::port const): Streamlined.
(WebCore::WorkerLocation::pathname const): Use an ASCIILiteral.
(WebCore::WorkerLocation::search const): Use queryWithLeadingQuestionMark.
(WebCore::WorkerLocation::hash const): Use fragmentIdentifierWithLeadingNumberSign.

* workers/service/ServiceWorkerRegistrationKey.cpp:
(WebCore::ServiceWorkerRegistrationKey::ServiceWorkerRegistrationKey):
Updated for hasFragmentIdentifier name change.

* workers/service/context/ServiceWorkerThreadProxy.cpp:
(WebCore::topOriginURL): Simplified code to set port.
* workers/service/server/SWServer.cpp:
(WebCore::originURL): Ditto.

* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::open): Updated for setPassword name change.

Source/WebKit:

* NetworkProcess/NetworkLoadChecker.cpp:
(WebKit::NetworkLoadChecker::checkRedirection): Use hasCredentials.
(WebKit::NetworkLoadChecker::applyHTTPSUpgradeIfNeeded const):
Remove use of ASCIILiteral for setProtocol.

* NetworkProcess/curl/NetworkDataTaskCurl.cpp:
(WebKit::NetworkDataTaskCurl::NetworkDataTaskCurl): Updated for
password name change.
(WebKit::NetworkDataTaskCurl::willPerformHTTPRedirection): Ditto.

* NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
(WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa): Updated
for password name change.
(WebKit::NetworkDataTaskCocoa::willPerformHTTPRedirection): Ditto.

* NetworkProcess/soup/NetworkDataTaskSoup.cpp:
(WebKit::NetworkDataTaskSoup::NetworkDataTaskSoup): Updated for
password name change.
(WebKit::NetworkDataTaskSoup::applyAuthenticationToRequest): Ditto.
(WebKit::NetworkDataTaskSoup::continueHTTPRedirection): Ditto.
(WebKit::NetworkDataTaskSoup::shouldAllowHSTSPolicySetting const):
Use != to compare hosts, rather than hostsAreEqual.
(WebKit::NetworkDataTaskSoup::shouldAllowHSTSProtocolUpgrade const):
Refactored to use || to match the function above.

* Shared/API/APIURL.h:
(API::URL::host const): Removed validity check; WTF::URL::host
returns null if the URL is invalid.
(API::URL::protocol const): Ditto.
(API::URL::path const): Ditto.
(API::URL::lastPathComponent const): Ditto. Also added toString
since WTF::URL::lastPathComponent now returns a StringView.

* UIProcess/Cocoa/DownloadClient.mm:
(WebKit::DownloadClient::didFinish): Use hasFragmentIdentifier.

* UIProcess/DeviceIdHashSaltStorage.cpp:
(WebKit::DeviceIdHashSaltStorage::loadStorageFromDisk):
Refactored a bit and use fileURLWithFileSystemPath and
updated since lastPathComponent returns a StringView.

* UIProcess/Plugins/PluginInfoStore.cpp:
(WebKit::pathExtension): Updated since lastPathComponent
returns a StringView. Refactored a little.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::maybeInitializeSandboxExtensionHandle):
Use truncatedForUseAsBase.
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
Use != to compare hosts, rather than hostsAreEqual.
(WebKit::WebPageProxy::decidePolicyForNewWindowAction): Ditto.
(WebKit::WebPageProxy::createNewPage): Ditto.

* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::assumeReadAccessToBaseURL):
Use truncatedForUseAsBase.

* UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:
(WebKit::WebsiteDataStore::initializeAppBoundDomains):
Don't use ASCIILiteral for argument to setProtocol.

* WebProcess/MediaCache/WebMediaKeyStorageManager.cpp:
(WebKit::WebMediaKeyStorageManager::getMediaKeyOrigins):
Use fileURLWithFileSystemPath, also refactored a bit.

* WebProcess/Plugins/PDF/PDFPlugin.mm:
(WebKit::PDFPlugin::installPDFDocument): Updated since
fragmentIdentifier returns a StringView.

* WebProcess/WebCoreSupport/WebContextMenuClient.cpp:
(WebKit::WebContextMenuClient::searchWithGoogle): Streamlined
the implementation a bit.

* WebProcess/WebCoreSupport/mac/WebDragClientMac.mm:
(WebKit::WebDragClient::declareAndWriteDragImage):
Updated since lastPathComponent returns a StringView.

Source/WebKitLegacy/mac:

* WebCoreSupport/WebFrameLoaderClient.mm:
(shouldTryAppLink): Compare hosts with == rather than using hostsAreEqual.

* WebView/WebFrame.mm:
(-[WebFrame _documentFragmentForImageData:withRelativeURLPart:andMIMEType:]):
Updated since fakeURLWithRelativePart takes a StringView. Also use RetainPtr
instead of an explicit call to release.

* WebView/WebHTMLView.mm:
(-[WebHTMLView _web_documentFragmentFromPasteboard:pasteboardType:imageMIMEType:]):
Updated since fakeURLWithRelativePart takes a StringView. No conversion
directly from NSString to StringView, so we have to explicitly use a String.

* WebView/WebImmediateActionController.mm:
(-[WebImmediateActionController _defaultAnimationController]): Update
since protocolIs takes a StringView. No conversion directly from
NSString to StringView, so we have to explicitly use a String.

Source/WebKitLegacy/win:

* Plugins/PluginDatabase.cpp:
(WebCore::PluginDatabase::PluginDatabase): Moved initialization of
m_persistentMetadataCacheIsLoaded to the class definition.
(WebCore::PluginDatabase::MIMETypeForExtension const): Take StringView.
(WebCore::PluginDatabase::findPlugin): Use StringView.

* Plugins/PluginDatabase.h: Changed MIMETypeForExtension to take
a StringView. Took out some unneeded declarations. Initialized
m_persistentMetadataCacheIsLoaded here in the class definition.

* WebCoreSupport/WebFrameLoaderClient.cpp:
(WebFrameLoaderClient::objectContentType): Use StringView a little more.

* WebCoreSupport/WebContextMenuClient.cpp:
(WebContextMenuClient::searchWithGoogle): Streamlined the implementation a bit.
(WebContextMenuClient::lookUpInDictionary): Added "using namespace WebCore".

Source/WTF:

* wtf/URL.cpp: Remove unused CharBuffer type. Remove UCharBuffer
type and write the type explicitly in the 3 places it's used.
Removed the invalidPortNumber constant, since we use Optional
instead of a special port number now.
(WTF::copyASCII): Remove unnecessary special case for empty string.
Tweaked coding style and comment a bit.
(WTF::URL::URL): Streamlined by getting rid of a local variable.
(WTF::shouldTrimFromURL): Tweaked coding style.
(WTF::URL::lastPathComponent const): Return a StringView.
Also, use the pathStart function for clarity.
(WTF::URL::port const): Use a StringView to call parseUInt16.
(WTF::URL::protocolHostAndPort const): Optimized to always allocate
the string in the right size rather than removing characters from it
after creating it.
(WTF::decodeEscapeSequence): Added. Factored out from the function
below to make it a little more readable.
(WTF::decodeEscapeSequencesFromParsedURL): Convert a null StringView
to a null String rather than an empty String, use a stack buffer and
the helper function above, and added some FIXME comments about
encoding handling.
(WTF::URL::user const): Simplified by calling encodedUser.
(WTF::URL::password const): Simplified by calling encodedPassword.
(WTF::URL::encodedUser const): Return a StringView.
(WTF::URL::encodedPassword const): Ditto. Also renamed from encodedPass.
(WTF::URL::fragmentIdentifier const): Ditto.
(WTF::URL::hasFragmentIdentifier const): Moved to header so it can
be inlined.
(WTF::URL::truncatedForUseAsBase const): Renamed from baseAsString.
This function is currently only used with local file URLs and it's
not perfectly clear to me precisely what it is for, hence the name
is not so great.
(WTF::URL::fileSystemPath const): Removed unneeded check for validity
since isLocalFile does that check. Removed unneeded typecast now that
path returns a StringView.
(WTF::defaultPortForProtocolMapForTesting): Deleted.
(WTF::ensureDefaultPortForProtocolMapForTesting): Deleted.
(WTF::registerDefaultPortForProtocolForTesting): Deleted.
(WTF::clearDefaultPortForProtocolMapForTesting): Deleted.
(WTF::defaultPortForProtocol): Deleted.
(WTF::isDefaultPortForProtocol): Deleted.
(WTF::protocolIsInternal): Rewrote to take a StringView. Before it
was written as a template that looked like it supported classes other
than String, but actually would crash if called on a StringView.
(WTF::URL::protocolIs const): Removed unneeded explicit cast to StringView.
(WTF::URL::query const): Return a StringView.
(WTF::URL::path const): Return a StringView, use the pathStart
function for clarity.
(WTF::URL::setProtocol): Use a toStringWithoutCopying to save some
work when making the protocol canonical. Call parse instead of
creating a URLParser here.
(WTF::URL::credentialsEnd const): Added. Helper for various functions
that manipulate the credentials section.
(WTF::URL::setHost): Take StringView. Streamlined the code by using
StringView::contains, by using makeString rather than StringBuilder,
and by calling parse instead of creating a URLParser here.
(WTF::URL::removePort): Deleted, since setPort takes an Optional now.
(WTF::URL::setPort): Take Optional<uint16_t>. Call parse instead of
creating a URLParser here.
(WTF::URL::removeHostAndPort): Deleted. Callers can pass a null
StringView to setHostAndPort instead.
(WTF::URL::setHostAndPort): Take StringView. Don't remove the old
host and port in the nomral case where we end up overwriting the entire
URL at the end of the function anyway. Use parseUInt16 instead of
toIntStrict to check port number for validity, which makes sure we will
reject port numbers larger than 65535. Use makeString instead of
StringBuilder and call parse rather than creating a URLParser here.
(WTF::parse): Added. Helper function for when we create a new string
and want to parse it as the new contents of the URL. Used in almost
every setter function.
(WTF::URL::remove): Added. Helper function for efficiently removing
a piece of the URL string and re-parsing. Used in many setter functions.
(WTF::URL::setUser): Take StringView. Use makeString instead of
StringBuilder, and parse and remove instead of creating a URLParser here.
(WTF::URL::setPassword): Renamed from setPass. Take StringView.
Use makeString instead of StringBuilder, and parse and remove instead of
creating a URLParser here.
(WTF::URL::removeCredientials): Added. Efficiently removes both the
user name and password if either is present.
(WTF::URL::setFragmentIdentifier): Use parse instead of creating
a URL parser here.
(WTF::URL::removeFragmentIdentifier): Removed unnecessary checks for
things already optimized by String::left. Could later consider merging
this in with setFragmentIdentifier, using a null vs. empty distinction,
but not doing that for now.
(WTF::URL::setQuery): Take StringView.
(WTF::URL::setPath): Take StringView.
(WTF::stringWithoutQueryOrFragmentIdentifier): Added.
(WTF::stringWithoutFragmentIdentifier): Added.
(WTF::equalIgnoringFragmentIdentifier): Simplified implementation by
using stringWithoutFragmentIdentifier.
(WTF::equalIgnoringQueryAndFragment): Deleted.
(WTF::hostsAreEqual): Deleted.
(WTF::URL::isMatchingDomain const): Take StringView.
(WTF::protocolIs): Take StringView.
(WTF::URL::protocolIs): Moved to inline in the header.
(WTF::URL::strippedForUseAsReferrer const): Rewrite for efficiency.
(WTF::protocolIsJavaScript): Moved to inline in the header.
(WTF::protocolIsInHTTPFamily): Take StringView.
(WTF::aboutBlankURL): Use ASCIILiteral.
(WTF::aboutSrcDocURL): Use ASCIILiteral.
(WTF::portAllowed): Removed 65535 as a blocked port; wasn't needed.
(WTF::mimeTypeFromDataURL): Take StringView.
(WTF::URL::stringCenterEllipsizedToLength const): Tweaked style.
(WTF::URL::fakeURLWithRelativePart): Take StringView.
(WTF::URL::fileURLWithFileSystemPath): Take StringView..
(WTF::URL::queryWithLeadingQuestionMark const): Added.
(WTF::URL::fragmentIdentifierWithLeadingNumberSign const): Added.
(WTF::URL::hostIsIPAddress): Tweak coding style.

* wtf/URL.h: Made URLTextEncoding destructor protected. Removed
unused forward declaration of URLHash structure. Use WTF_EXPORT_PRIVATE
on functions from URL rather than on the whole class, since the style
checker told me to do that. Moved some inline function bodies out of
the class definition for clarity and to keep the style checker happy.
Updated many arguemnts from String to StringView and return values for
substrings of the URL to StringView. Removed some unused functions and
some obsolete comments.

* wtf/cf/CFURLExtras.cpp:
(WTF::isCFURLSameOrigin): Use hasCredentials.
* wtf/text/StringView.cpp:
(WTF::StringView::endsWith const): Added.
(WTF::parseUInt16): Added.
(WTF::equalRespectingNullity): Added.
(WTF::StringView::contains const): Added overload that takes a
const char* so the call site doesn't have to convert it to a StringView.

* wtf/text/StringView.h: Updated for the additions above.
Also added a default start of 0 to the find function.

* wtf/text/WTFString.cpp:
(WTF::charactersToIntStrict): Removed unneeded explicit template argument.
(WTF::charactersToUIntStrict): Ditto.
(WTF::charactersToInt64Strict): Ditto.
(WTF::charactersToUInt64Strict): Ditto.
(WTF::charactersToIntPtrStrict): Ditto.
(WTF::charactersToInt): Ditto.
(WTF::charactersToUInt): Ditto.
(WTF::charactersToInt64): Ditto.
(WTF::charactersToUInt64): Ditto.
(WTF::charactersToIntPtr): Ditto.

Tools:

* TestWebKitAPI/Tests/WTF/URL.cpp: Removed the test for
equalIgnoringQueryAndFragment since we removed that function.
Updated for rename of URL::password from URL::pass.
Updated arguments to isMatchingDomain to pass literals that can be converted
to StringView rather than ASCIILiteral, which StringView doesn't yet support.

* TestWebKitAPI/Tests/WebCore/URLParserTextEncoding.cpp:
(TestWebKitAPI::checkURL): Updated for rename of URL::password from URL::pass.
(TestWebKitAPI::checkRelativeURL): Ditto.
(TestWebKitAPI::checkURLDifferences): Ditto.
(TestWebKitAPI::checkRelativeURLDifferences): Ditto.
(TestWebKitAPI::testUserPassword): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@260707 268f45cc-cd09-0410-ab3c-d52691b4dbfc

89 files changed:
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/url/url-setters-expected.txt
Source/WTF/ChangeLog
Source/WTF/wtf/URL.cpp
Source/WTF/wtf/URL.h
Source/WTF/wtf/cf/CFURLExtras.cpp
Source/WTF/wtf/text/StringView.cpp
Source/WTF/wtf/text/StringView.h
Source/WTF/wtf/text/WTFString.cpp
Source/WebCore/ChangeLog
Source/WebCore/Modules/cache/DOMCacheEngine.cpp
Source/WebCore/Modules/fetch/FetchRequest.cpp
Source/WebCore/Modules/fetch/FetchResponse.cpp
Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp
Source/WebCore/Modules/plugins/YouTubePluginReplacement.cpp
Source/WebCore/Modules/websockets/WebSocketHandshake.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/TreeScope.cpp
Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm
Source/WebCore/editing/ios/EditorIOS.mm
Source/WebCore/html/HTMLAnchorElement.cpp
Source/WebCore/html/HTMLAttachmentElement.cpp
Source/WebCore/html/HTMLPlugInElement.cpp
Source/WebCore/html/MediaFragmentURIParser.cpp
Source/WebCore/html/URLUtils.h
Source/WebCore/loader/AdClickAttribution.cpp
Source/WebCore/loader/CrossOriginAccessControl.cpp
Source/WebCore/loader/DocumentThreadableLoader.cpp
Source/WebCore/loader/FormSubmission.cpp
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
Source/WebCore/loader/appcache/ManifestParser.cpp
Source/WebCore/loader/cache/CachedFont.cpp
Source/WebCore/loader/cache/CachedResourceRequest.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/History.cpp
Source/WebCore/page/Location.cpp
Source/WebCore/page/UserContentURLPattern.cpp
Source/WebCore/platform/MIMETypeRegistry.cpp
Source/WebCore/platform/graphics/MediaPlayer.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
Source/WebCore/platform/network/ResourceHandleInternal.h
Source/WebCore/platform/network/ResourceRequestBase.cpp
Source/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
Source/WebCore/platform/network/curl/CurlProxySettings.cpp
Source/WebCore/platform/network/curl/CurlProxySettings.h
Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp
Source/WebCore/platform/network/mac/ResourceHandleMac.mm
Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp
Source/WebCore/platform/network/soup/URLSoup.cpp
Source/WebCore/platform/win/PasteboardWin.cpp
Source/WebCore/style/StyleBuilderState.cpp
Source/WebCore/workers/WorkerLocation.cpp
Source/WebCore/workers/service/ServiceWorkerRegistrationKey.cpp
Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp
Source/WebCore/workers/service/server/SWServer.cpp
Source/WebCore/xml/XMLHttpRequest.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkLoadChecker.cpp
Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp
Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
Source/WebKit/Shared/API/APIURL.h
Source/WebKit/UIProcess/Cocoa/DownloadClient.mm
Source/WebKit/UIProcess/DeviceIdHashSaltStorage.cpp
Source/WebKit/UIProcess/Plugins/PluginInfoStore.cpp
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebProcessProxy.cpp
Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm
Source/WebKit/WebProcess/MediaCache/WebMediaKeyStorageManager.cpp
Source/WebKit/WebProcess/Plugins/PDF/PDFPlugin.mm
Source/WebKit/WebProcess/WebCoreSupport/WebContextMenuClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm
Source/WebKitLegacy/mac/WebView/WebFrame.mm
Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
Source/WebKitLegacy/mac/WebView/WebImmediateActionController.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/Plugins/PluginDatabase.cpp
Source/WebKitLegacy/win/Plugins/PluginDatabase.h
Source/WebKitLegacy/win/WebCoreSupport/WebContextMenuClient.cpp
Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/URL.cpp
Tools/TestWebKitAPI/Tests/WTF/URLParser.cpp
Tools/TestWebKitAPI/Tests/WebCore/URLParserTextEncoding.cpp

index 11774f2..197a669 100644 (file)
@@ -1,3 +1,14 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * web-platform-tests/url/url-setters-expected.txt: Updated expected results for progression in
+        correct behavior when port numbers are >65535. I didn't originally intend to make this improvement,
+        but it fell out naturally from the refactoring changes.
+
 2020-04-24  Alexey Shvayka  <shvaikalesh@gmail.com>
 
         Fix WASM Error classes and re-sync wpt/wasm/jsapi from upstream
index 11870b9..79eb117 100644 (file)
@@ -282,9 +282,9 @@ PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080+2' Anyth
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers 
 PASS <a>: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers 
 PASS <area>: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers 
-FAIL URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. assert_equals: expected "http://example.com/path" but got "http://example.net/path"
-FAIL <a>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. assert_equals: expected "http://example.com/path" but got "http://example.com:65536/path"
-FAIL <area>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. assert_equals: expected "http://example.com/path" but got "http://example.com:65536/path"
+PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. 
+PASS <a>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. 
+PASS <area>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. 
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 
 FAIL <a>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 assert_equals: expected "http://example.net/" but got "http://[google.com]/"
 FAIL <area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 assert_equals: expected "http://example.net/" but got "http://[google.com]/"
@@ -459,12 +459,12 @@ PASS <area>: Setting <http://example.net/path>.port = '8080+2' Anything other th
 PASS URL: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers 
 PASS <a>: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers 
 PASS <area>: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers 
-FAIL URL: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path"
-FAIL <a>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path"
-FAIL <area>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path"
-FAIL URL: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "non-special://example.net:8080/path" but got "non-special://example.net:0/path"
-FAIL <a>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "non-special://example.net:8080/path" but got "non-special://example.net:0/path"
-FAIL <area>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "non-special://example.net:8080/path" but got "non-special://example.net:0/path"
+PASS URL: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error 
+PASS <a>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error 
+PASS <area>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error 
+PASS URL: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error 
+PASS <a>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error 
+PASS <area>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error 
 PASS URL: Setting <file://test/>.port = '12' 
 PASS <a>: Setting <file://test/>.port = '12' 
 PASS <area>: Setting <file://test/>.port = '12' 
index c34b4cc..3424f47 100644 (file)
@@ -1,3 +1,152 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * wtf/URL.cpp: Remove unused CharBuffer type. Remove UCharBuffer
+        type and write the type explicitly in the 3 places it's used.
+        Removed the invalidPortNumber constant, since we use Optional
+        instead of a special port number now.
+        (WTF::copyASCII): Remove unnecessary special case for empty string.
+        Tweaked coding style and comment a bit.
+        (WTF::URL::URL): Streamlined by getting rid of a local variable.
+        (WTF::shouldTrimFromURL): Tweaked coding style.
+        (WTF::URL::lastPathComponent const): Return a StringView.
+        Also, use the pathStart function for clarity.
+        (WTF::URL::port const): Use a StringView to call parseUInt16.
+        (WTF::URL::protocolHostAndPort const): Optimized to always allocate
+        the string in the right size rather than removing characters from it
+        after creating it.
+        (WTF::decodeEscapeSequence): Added. Factored out from the function
+        below to make it a little more readable.
+        (WTF::decodeEscapeSequencesFromParsedURL): Convert a null StringView
+        to a null String rather than an empty String, use a stack buffer and
+        the helper function above, and added some FIXME comments about
+        encoding handling.
+        (WTF::URL::user const): Simplified by calling encodedUser.
+        (WTF::URL::password const): Simplified by calling encodedPassword.
+        (WTF::URL::encodedUser const): Return a StringView.
+        (WTF::URL::encodedPassword const): Ditto. Also renamed from encodedPass.
+        (WTF::URL::fragmentIdentifier const): Ditto.
+        (WTF::URL::hasFragmentIdentifier const): Moved to header so it can
+        be inlined.
+        (WTF::URL::truncatedForUseAsBase const): Renamed from baseAsString.
+        This function is currently only used with local file URLs and it's
+        not perfectly clear to me precisely what it is for, hence the name
+        is not so great.
+        (WTF::URL::fileSystemPath const): Removed unneeded check for validity
+        since isLocalFile does that check. Removed unneeded typecast now that
+        path returns a StringView.
+        (WTF::defaultPortForProtocolMapForTesting): Deleted.
+        (WTF::ensureDefaultPortForProtocolMapForTesting): Deleted.
+        (WTF::registerDefaultPortForProtocolForTesting): Deleted.
+        (WTF::clearDefaultPortForProtocolMapForTesting): Deleted.
+        (WTF::defaultPortForProtocol): Deleted.
+        (WTF::isDefaultPortForProtocol): Deleted.
+        (WTF::protocolIsInternal): Rewrote to take a StringView. Before it
+        was written as a template that looked like it supported classes other
+        than String, but actually would crash if called on a StringView.
+        (WTF::URL::protocolIs const): Removed unneeded explicit cast to StringView.
+        (WTF::URL::query const): Return a StringView.
+        (WTF::URL::path const): Return a StringView, use the pathStart
+        function for clarity.
+        (WTF::URL::setProtocol): Use a toStringWithoutCopying to save some
+        work when making the protocol canonical. Call parse instead of
+        creating a URLParser here.
+        (WTF::URL::credentialsEnd const): Added. Helper for various functions
+        that manipulate the credentials section.
+        (WTF::URL::setHost): Take StringView. Streamlined the code by using
+        StringView::contains, by using makeString rather than StringBuilder,
+        and by calling parse instead of creating a URLParser here.
+        (WTF::URL::removePort): Deleted, since setPort takes an Optional now.
+        (WTF::URL::setPort): Take Optional<uint16_t>. Call parse instead of
+        creating a URLParser here.
+        (WTF::URL::removeHostAndPort): Deleted. Callers can pass a null
+        StringView to setHostAndPort instead.
+        (WTF::URL::setHostAndPort): Take StringView. Don't remove the old
+        host and port in the nomral case where we end up overwriting the entire
+        URL at the end of the function anyway. Use parseUInt16 instead of
+        toIntStrict to check port number for validity, which makes sure we will
+        reject port numbers larger than 65535. Use makeString instead of
+        StringBuilder and call parse rather than creating a URLParser here.
+        (WTF::parse): Added. Helper function for when we create a new string
+        and want to parse it as the new contents of the URL. Used in almost
+        every setter function.
+        (WTF::URL::remove): Added. Helper function for efficiently removing
+        a piece of the URL string and re-parsing. Used in many setter functions.
+        (WTF::URL::setUser): Take StringView. Use makeString instead of
+        StringBuilder, and parse and remove instead of creating a URLParser here.
+        (WTF::URL::setPassword): Renamed from setPass. Take StringView.
+        Use makeString instead of StringBuilder, and parse and remove instead of
+        creating a URLParser here.
+        (WTF::URL::removeCredientials): Added. Efficiently removes both the
+        user name and password if either is present.
+        (WTF::URL::setFragmentIdentifier): Use parse instead of creating
+        a URL parser here.
+        (WTF::URL::removeFragmentIdentifier): Removed unnecessary checks for
+        things already optimized by String::left. Could later consider merging
+        this in with setFragmentIdentifier, using a null vs. empty distinction,
+        but not doing that for now.
+        (WTF::URL::setQuery): Take StringView.
+        (WTF::URL::setPath): Take StringView.
+        (WTF::stringWithoutQueryOrFragmentIdentifier): Added.
+        (WTF::stringWithoutFragmentIdentifier): Added.
+        (WTF::equalIgnoringFragmentIdentifier): Simplified implementation by
+        using stringWithoutFragmentIdentifier.
+        (WTF::equalIgnoringQueryAndFragment): Deleted.
+        (WTF::hostsAreEqual): Deleted.
+        (WTF::URL::isMatchingDomain const): Take StringView.
+        (WTF::protocolIs): Take StringView.
+        (WTF::URL::protocolIs): Moved to inline in the header.
+        (WTF::URL::strippedForUseAsReferrer const): Rewrite for efficiency.
+        (WTF::protocolIsJavaScript): Moved to inline in the header.
+        (WTF::protocolIsInHTTPFamily): Take StringView.
+        (WTF::aboutBlankURL): Use ASCIILiteral.
+        (WTF::aboutSrcDocURL): Use ASCIILiteral.
+        (WTF::portAllowed): Removed 65535 as a blocked port; wasn't needed.
+        (WTF::mimeTypeFromDataURL): Take StringView.
+        (WTF::URL::stringCenterEllipsizedToLength const): Tweaked style.
+        (WTF::URL::fakeURLWithRelativePart): Take StringView.
+        (WTF::URL::fileURLWithFileSystemPath): Take StringView..
+        (WTF::URL::queryWithLeadingQuestionMark const): Added.
+        (WTF::URL::fragmentIdentifierWithLeadingNumberSign const): Added.
+        (WTF::URL::hostIsIPAddress): Tweak coding style.
+
+        * wtf/URL.h: Made URLTextEncoding destructor protected. Removed
+        unused forward declaration of URLHash structure. Use WTF_EXPORT_PRIVATE
+        on functions from URL rather than on the whole class, since the style
+        checker told me to do that. Moved some inline function bodies out of
+        the class definition for clarity and to keep the style checker happy.
+        Updated many arguemnts from String to StringView and return values for
+        substrings of the URL to StringView. Removed some unused functions and
+        some obsolete comments.
+
+        * wtf/cf/CFURLExtras.cpp:
+        (WTF::isCFURLSameOrigin): Use hasCredentials.
+        * wtf/text/StringView.cpp:
+        (WTF::StringView::endsWith const): Added.
+        (WTF::parseUInt16): Added.
+        (WTF::equalRespectingNullity): Added.
+        (WTF::StringView::contains const): Added overload that takes a
+        const char* so the call site doesn't have to convert it to a StringView.
+
+        * wtf/text/StringView.h: Updated for the additions above.
+        Also added a default start of 0 to the find function.
+
+        * wtf/text/WTFString.cpp:
+        (WTF::charactersToIntStrict): Removed unneeded explicit template argument.
+        (WTF::charactersToUIntStrict): Ditto.
+        (WTF::charactersToInt64Strict): Ditto.
+        (WTF::charactersToUInt64Strict): Ditto.
+        (WTF::charactersToIntPtrStrict): Ditto.
+        (WTF::charactersToInt): Ditto.
+        (WTF::charactersToUInt): Ditto.
+        (WTF::charactersToInt64): Ditto.
+        (WTF::charactersToUInt64): Ditto.
+        (WTF::charactersToIntPtr): Ditto.
+
 2020-04-24  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [WTF] allThreads registration is racy with allThreads unregistration
index 610d1c4..3cd24f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 namespace WTF {
 
-typedef Vector<char, 512> CharBuffer;
-typedef Vector<UChar, 512> UCharBuffer;
-
-static constexpr unsigned invalidPortNumber = 0xFFFF;
-
-// Copies the source to the destination, assuming all the source characters are
-// ASCII. The destination buffer must be large enough. Null characters are allowed
-// in the source string, and no attempt is made to null-terminate the result.
-static void copyASCII(const String& string, char* dest)
+// Copies the source to the destination, assuming all the source characters are ASCII.
+// The destination buffer must be large enough. Null characters are allowed in the
+// source string, and no attempt is made to null-terminate the destination buffer.
+static void copyASCII(const String& string, char* destination)
 {
-    if (string.isEmpty())
-        return;
-
     if (string.is8Bit())
-        memcpy(dest, string.characters8(), string.length());
+        memcpy(destination, string.characters8(), string.length());
     else {
-        const UChar* src = string.characters16();
-        size_t length = string.length();
-        for (size_t i = 0; i < length; i++)
-            dest[i] = static_cast<char>(src[i]);
+        auto source = string.characters16();
+        for (unsigned i = 0, length = string.length(); i < length; i++)
+            destination[i] = static_cast<char>(source[i]);
     }
 }
 
@@ -83,16 +74,13 @@ void URL::invalidate()
 
 URL::URL(const URL& base, const String& relative, const URLTextEncoding* encoding)
 {
-    URLParser parser(relative, base, encoding);
-    *this = parser.result();
+    *this = URLParser(relative, base, encoding).result();
 }
 
-static bool shouldTrimFromURL(UChar c)
+static bool shouldTrimFromURL(UChar character)
 {
-    // Browsers ignore leading/trailing whitespace and control
-    // characters from URLs.  Note that c is an *unsigned* char here
-    // so this comparison should only catch control characters.
-    return c <= ' ';
+    // Ignore leading/trailing whitespace and control characters.
+    return character <= ' ';
 }
 
 URL URL::isolatedCopy() const
@@ -102,48 +90,43 @@ URL URL::isolatedCopy() const
     return result;
 }
 
-String URL::lastPathComponent() const
+StringView URL::lastPathComponent() const
 {
     if (!hasPath())
-        return String();
+        return { };
 
     unsigned end = m_pathEnd - 1;
     if (m_string[end] == '/')
         --end;
 
     size_t start = m_string.reverseFind('/', end);
-    if (start < static_cast<unsigned>(m_hostEnd + m_portLength))
-        return String();
+    if (start < pathStart())
+        return { };
     ++start;
 
-    return m_string.substring(start, end - start + 1);
+    return StringView(m_string).substring(start, end - start + 1);
 }
 
 StringView URL::protocol() const
 {
+    if (!m_isValid)
+        return { };
+
     return StringView(m_string).substring(0, m_schemeEnd);
 }
 
 StringView URL::host() const
 {
+    if (!m_isValid)
+        return { };
+
     unsigned start = hostStart();
     return StringView(m_string).substring(start, m_hostEnd - start);
 }
 
 Optional<uint16_t> URL::port() const
 {
-    if (!m_portLength)
-        return WTF::nullopt;
-
-    bool ok = false;
-    unsigned number;
-    if (m_string.is8Bit())
-        number = charactersToUIntStrict(m_string.characters8() + m_hostEnd + 1, m_portLength - 1, &ok);
-    else
-        number = charactersToUIntStrict(m_string.characters16() + m_hostEnd + 1, m_portLength - 1, &ok);
-    if (!ok || number > std::numeric_limits<uint16_t>::max())
-        return WTF::nullopt;
-    return number;
+    return m_portLength ? parseUInt16(StringView(m_string).substring(m_hostEnd + 1, m_portLength - 1)) : WTF::nullopt;
 }
 
 String URL::hostAndPort() const
@@ -155,94 +138,101 @@ String URL::hostAndPort() const
 
 String URL::protocolHostAndPort() const
 {
-    String result = m_string.substring(0, m_hostEnd + m_portLength);
+    if (!hasCredentials())
+        return m_string.substring(0, pathStart());
 
-    if (m_passwordEnd - m_userStart > 0) {
-        const int allowForTrailingAtSign = 1;
-        result.remove(m_userStart, m_passwordEnd - m_userStart + allowForTrailingAtSign);
-    }
+    return makeString(
+        StringView(m_string).substring(0, m_userStart),
+        StringView(m_string).substring(hostStart(), pathStart() - hostStart())
+    );
+}
 
-    return result;
+static Optional<LChar> decodeEscapeSequence(StringView input, unsigned index, unsigned length)
+{
+    if (index + 3 > length || input[index] != '%')
+        return WTF::nullopt;
+    auto digit1 = input[index + 1];
+    auto digit2 = input[index + 2];
+    if (!isASCIIHexDigit(digit1) || !isASCIIHexDigit(digit2))
+        return WTF::nullopt;
+    return toASCIIHexValue(digit1, digit2);
 }
 
 static String decodeEscapeSequencesFromParsedURL(StringView input)
 {
-    auto inputLength = input.length();
-    if (!inputLength)
-        return emptyString();
-    Vector<LChar> percentDecoded;
-    percentDecoded.reserveInitialCapacity(inputLength);
-    for (unsigned i = 0; i < inputLength; ++i) {
-        if (input[i] == '%'
-            && inputLength > 2
-            && i < inputLength - 2
-            && isASCIIHexDigit(input[i + 1])
-            && isASCIIHexDigit(input[i + 2])) {
-            percentDecoded.uncheckedAppend(toASCIIHexValue(input[i + 1], input[i + 2]));
-            i += 2;
-        } else
+    ASSERT(input.isAllASCII());
+
+    auto length = input.length();
+    if (length < 3 || !input.contains('%'))
+        return input.toString();
+
+    // FIXME: This 100 is arbitrary. Should make a histogram of how this function is actually used to choose a better value.
+    Vector<LChar, 100> percentDecoded;
+    percentDecoded.reserveInitialCapacity(length);
+    for (unsigned i = 0; i < length; ) {
+        if (auto decodedCharacter = decodeEscapeSequence(input, i, length)) {
+            percentDecoded.uncheckedAppend(*decodedCharacter);
+            i += 3;
+        } else {
             percentDecoded.uncheckedAppend(input[i]);
+            ++i;
+        }
     }
+
+    // FIXME: Is UTF-8 always the correct encoding?
+    // FIXME: This returns a null string when we encounter an invalid UTF-8 sequence. Is that OK?
     return String::fromUTF8(percentDecoded.data(), percentDecoded.size());
 }
 
 String URL::user() const
 {
-    return decodeEscapeSequencesFromParsedURL(StringView(m_string).substring(m_userStart, m_userEnd - m_userStart));
+    return decodeEscapeSequencesFromParsedURL(encodedUser());
 }
 
-String URL::pass() const
+String URL::password() const
 {
-    if (m_passwordEnd == m_userEnd)
-        return String();
-
-    return decodeEscapeSequencesFromParsedURL(StringView(m_string).substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1));
+    return decodeEscapeSequencesFromParsedURL(encodedPassword());
 }
 
-String URL::encodedUser() const
+StringView URL::encodedUser() const
 {
-    return m_string.substring(m_userStart, m_userEnd - m_userStart);
+    return StringView(m_string).substring(m_userStart, m_userEnd - m_userStart);
 }
 
-String URL::encodedPass() const
+StringView URL::encodedPassword() const
 {
     if (m_passwordEnd == m_userEnd)
-        return String();
+        return { };
 
-    return m_string.substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1);
+    return StringView(m_string).substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1);
 }
 
-String URL::fragmentIdentifier() const
+StringView URL::fragmentIdentifier() const
 {
     if (!hasFragmentIdentifier())
-        return String();
-
-    return m_string.substring(m_queryEnd + 1);
-}
+        return { };
 
-bool URL::hasFragmentIdentifier() const
-{
-    return m_isValid && m_string.length() != m_queryEnd;
+    return StringView(m_string).substring(m_queryEnd + 1);
 }
 
-String URL::baseAsString() const
+URL URL::truncatedForUseAsBase() const
 {
-    return m_string.left(m_pathAfterLastSlash);
+    return URL(URL(), m_string.left(m_pathAfterLastSlash));
 }
 
 #if !USE(CF)
 
 String URL::fileSystemPath() const
 {
-    if (!isValid() || !isLocalFile())
-        return String();
+    if (!isLocalFile())
+        return { };
 
-    return decodeEscapeSequencesFromParsedURL(StringView(path()));
+    return decodeEscapeSequencesFromParsedURL(path());
 }
 
 #endif
 
-#ifdef NDEBUG
+#if !ASSERT_ENABLED
 
 static inline void assertProtocolIsGood(StringView)
 {
@@ -314,7 +304,7 @@ bool isDefaultPortForProtocol(uint16_t port, StringView protocol)
 
 bool URL::protocolIs(const char* protocol) const
 {
-    assertProtocolIsGood(StringView { protocol });
+    assertProtocolIsGood(protocol);
 
     // JavaScript URLs are "valid" and should be executed even if URL decides they are invalid.
     // The free function protocolIsJavaScript() should be used instead. 
@@ -349,73 +339,65 @@ bool URL::protocolIs(StringView protocol) const
     return true;
 }
 
-String URL::query() const
+StringView URL::query() const
 {
     if (m_queryEnd == m_pathEnd)
-        return String();
+        return { };
 
-    return m_string.substring(m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1)); 
+    return StringView(m_string).substring(m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1));
 }
 
 StringView URL::path() const
 {
-    unsigned portEnd = m_hostEnd + m_portLength;
-    return StringView(m_string).substring(portEnd, m_pathEnd - portEnd);
+    if (!m_isValid)
+        return { };
+
+    return StringView(m_string).substring(pathStart(), m_pathEnd - pathStart());
 }
 
-bool URL::setProtocol(const String& s)
+bool URL::setProtocol(StringView newProtocol)
 {
     // Firefox and IE remove everything after the first ':'.
-    size_t separatorPosition = s.find(':');
-    String newProtocol = s.substring(0, separatorPosition);
-    auto canonicalized = URLParser::maybeCanonicalizeScheme(newProtocol);
-    if (!canonicalized)
+    auto newProtocolPrefix = newProtocol.substring(0, newProtocol.find(':'));
+    auto newProtocolCanonicalized = URLParser::maybeCanonicalizeScheme(newProtocolPrefix.toStringWithoutCopying());
+    if (!newProtocolCanonicalized)
         return false;
 
     if (!m_isValid) {
-        URLParser parser(makeString(*canonicalized, ":", m_string));
-        *this = parser.result();
+        parse(makeString(*newProtocolCanonicalized, ':', m_string));
         return true;
     }
 
-    if ((m_passwordEnd != m_userStart || port()) && *canonicalized == "file")
+    if ((m_passwordEnd != m_userStart || port()) && *newProtocolCanonicalized == "file")
         return true;
 
     if (isLocalFile() && host().isEmpty())
         return true;
 
-    URLParser parser(makeString(*canonicalized, m_string.substring(m_schemeEnd)));
-    *this = parser.result();
+    parse(makeString(*newProtocolCanonicalized, StringView(m_string).substring(m_schemeEnd)));
     return true;
 }
 
-static bool isAllASCII(StringView string)
-{
-    if (string.is8Bit())
-        return charactersAreAllASCII(string.characters8(), string.length());
-    return charactersAreAllASCII(string.characters16(), string.length());
-}
-    
 // Appends the punycoded hostname identified by the given string and length to
 // the output buffer. The result will not be null terminated.
 // Return value of false means error in encoding.
-static bool appendEncodedHostname(UCharBuffer& buffer, StringView string)
+static bool appendEncodedHostname(Vector<UChar, 512>& buffer, StringView string)
 {
     // Needs to be big enough to hold an IDN-encoded name.
     // For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
     const unsigned hostnameBufferLength = 2048;
-    
-    if (string.length() > hostnameBufferLength || isAllASCII(string)) {
+
+    if (string.length() > hostnameBufferLength || string.isAllASCII()) {
         append(buffer, string);
         return true;
     }
-    
+
     UChar hostnameBuffer[hostnameBufferLength];
     UErrorCode error = U_ZERO_ERROR;
     UIDNAInfo processingDetails = UIDNA_INFO_INITIALIZER;
     int32_t numCharactersConverted = uidna_nameToASCII(&URLParser::internationalDomainNameTranscoder(),
         string.upconvertedCharacters(), string.length(), hostnameBuffer, hostnameBufferLength, &processingDetails, &error);
-    
+
     if (U_SUCCESS(error) && !processingDetails.errors) {
         buffer.append(hostnameBuffer, numCharactersConverted);
         return true;
@@ -428,101 +410,86 @@ unsigned URL::hostStart() const
     return (m_passwordEnd == m_userStart) ? m_passwordEnd : m_passwordEnd + 1;
 }
 
-void URL::setHost(const String& s)
+unsigned URL::credentialsEnd() const
+{
+    // Include '@' too if we have it.
+    unsigned end = m_passwordEnd;
+    if (end != m_hostEnd && m_string[end] == '@')
+        end += 1;
+    return end;
+}
+
+void URL::setHost(StringView newHost)
 {
     if (!m_isValid)
         return;
 
-    auto colonIndex = s.find(':');
-    if (colonIndex != notFound)
+    if (newHost.contains(':'))
         return;
 
-    UCharBuffer encodedHostName;
-    if (!appendEncodedHostname(encodedHostName, s))
+    Vector<UChar, 512> encodedHostName;
+    if (!appendEncodedHostname(encodedHostName, newHost))
         return;
-    
-    bool slashSlashNeeded = m_userStart == static_cast<unsigned>(m_schemeEnd + 1);
-    
-    StringBuilder builder;
-    builder.append(m_string.left(hostStart()));
-    if (slashSlashNeeded)
-        builder.appendLiteral("//");
-    builder.append(StringView(encodedHostName.data(), encodedHostName.size()));
-    builder.append(m_string.substring(m_hostEnd));
 
-    URLParser parser(builder.toString());
-    *this = parser.result();
+    bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
+    parse(makeString(
+        StringView(m_string).left(hostStart()),
+        slashSlashNeeded ? "//" : "",
+        StringView(encodedHostName.data(), encodedHostName.size()),
+        StringView(m_string).substring(m_hostEnd)
+    ));
 }
 
-void URL::removePort()
-{
-    if (!m_portLength)
-        return;
-    URLParser parser(makeString(StringView(m_string).left(m_hostEnd), StringView(m_string).substring(m_hostEnd + m_portLength)));
-    *this = parser.result();
-}
-
-void URL::setPort(unsigned short i)
+void URL::setPort(Optional<uint16_t> port)
 {
     if (!m_isValid)
         return;
 
-    bool colonNeeded = !m_portLength;
-    unsigned portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1);
-
-    URLParser parser(makeString(StringView(m_string).left(portStart), (colonNeeded ? ":" : ""), static_cast<unsigned>(i), StringView(m_string).substring(m_hostEnd + m_portLength)));
-    *this = parser.result();
-}
-
-void URL::removeHostAndPort()
-{
-    if (!m_isValid)
+    if (!port) {
+        remove(m_hostEnd, m_portLength);
         return;
-    if (!host().isEmpty())
-        setHost({ });
-    removePort();
+    }
+
+    parse(makeString(
+        StringView(m_string).left(m_hostEnd),
+        ':',
+        static_cast<unsigned>(*port),
+        StringView(m_string).substring(pathStart())
+    ));
 }
 
-void URL::setHostAndPort(const String& hostAndPort)
+void URL::setHostAndPort(StringView hostAndPort)
 {
     if (!m_isValid)
         return;
 
-    StringView hostName(hostAndPort);
-    StringView port;
-    
+    auto hostName = hostAndPort;
+    StringView portString;
     auto colonIndex = hostName.find(':');
     if (colonIndex != notFound) {
-        port = hostName.substring(colonIndex + 1);
-        bool ok;
-        int portInt = port.toIntStrict(ok);
-        if (!ok || portInt < 0)
-            return;
+        portString = hostName.substring(colonIndex + 1);
         hostName = hostName.substring(0, colonIndex);
+        if (!parseUInt16(portString))
+            portString = { };
     }
-
-    if (hostName.isEmpty())
+    if (hostName.isEmpty()) {
+        remove(hostStart(), pathStart() - hostStart());
         return;
+    }
 
-    UCharBuffer encodedHostName;
+    Vector<UChar, 512> encodedHostName;
     if (!appendEncodedHostname(encodedHostName, hostName))
         return;
 
-    bool slashSlashNeeded = m_userStart == static_cast<unsigned>(m_schemeEnd + 1);
-
-    StringBuilder builder;
-    builder.append(m_string.left(hostStart()));
-    if (slashSlashNeeded)
-        builder.appendLiteral("//");
-    builder.append(StringView(encodedHostName.data(), encodedHostName.size()));
-    if (!port.isEmpty()) {
-        builder.appendLiteral(":");
-        builder.append(port);
-    }
-    builder.append(StringView(m_string).substring(m_hostEnd + m_portLength));
-
-    URLParser parser(builder.toString());
-    *this = parser.result();
+    bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
+    parse(makeString(
+        StringView(m_string).left(hostStart()),
+        slashSlashNeeded ? "//" : "",
+        StringView(encodedHostName.data(), encodedHostName.size()),
+        portString.isEmpty() ? "" : ":",
+        portString,
+        StringView(m_string).substring(pathStart())
+    ));
 }
 
 static String percentEncodeCharacters(const String& input, bool(*shouldEncode)(UChar))
@@ -551,81 +518,89 @@ static String percentEncodeCharacters(const String& input, bool(*shouldEncode)(U
     return input;
 }
 
-void URL::setUser(const String& user)
+void URL::parse(const String& string)
 {
-    if (!m_isValid)
+    *this = URLParser(string).result();
+}
+
+void URL::remove(unsigned start, unsigned length)
+{
+    if (!length)
         return;
+    ASSERT(start < m_string.length());
+    ASSERT(length <= m_string.length() - start);
+
+    auto stringAfterRemoval = WTFMove(m_string);
+    stringAfterRemoval.remove(start, length);
+    parse(stringAfterRemoval);
+}
 
-    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
-    // and to avoid changing more than just the user login.
+void URL::setUser(StringView newUser)
+{
+    if (!m_isValid)
+        return;
 
     unsigned end = m_userEnd;
-    if (!user.isEmpty()) {
-        String u = percentEncodeCharacters(user, URLParser::isInUserInfoEncodeSet);
-        if (m_userStart == static_cast<unsigned>(m_schemeEnd + 1))
-            u = "//" + u;
-        // Add '@' if we didn't have one before.
-        if (end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@'))
-            u.append('@');
-        URLParser parser(makeString(StringView(m_string).left(m_userStart), u, StringView(m_string).substring(end)));
-        *this = parser.result();
+    if (!newUser.isEmpty()) {
+        bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
+        bool needSeparator = end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@');
+        parse(makeString(
+            StringView(m_string).left(m_userStart),
+            slashSlashNeeded ? "//" : "",
+            percentEncodeCharacters(newUser.toStringWithoutCopying(), URLParser::isInUserInfoEncodeSet),
+            needSeparator ? "@" : "",
+            StringView(m_string).substring(end)
+        ));
     } else {
         // Remove '@' if we now have neither user nor password.
         if (m_userEnd == m_passwordEnd && end != m_hostEnd && m_string[end] == '@')
             end += 1;
-        // We don't want to parse in the extremely common case where we are not going to make a change.
-        if (m_userStart != end) {
-            URLParser parser(makeString(StringView(m_string).left(m_userStart), StringView(m_string).substring(end)));
-            *this = parser.result();
-        }
+        remove(m_userStart, end - m_userStart);
     }
 }
 
-void URL::setPass(const String& password)
+void URL::setPassword(StringView newPassword)
 {
     if (!m_isValid)
         return;
 
-    unsigned end = m_passwordEnd;
-    if (!password.isEmpty()) {
-        String p = ":" + percentEncodeCharacters(password, URLParser::isInUserInfoEncodeSet) + "@";
-        if (m_userEnd == static_cast<unsigned>(m_schemeEnd + 1))
-            p = "//" + p;
-        // Eat the existing '@' since we are going to add our own.
-        if (end != m_hostEnd && m_string[end] == '@')
-            end += 1;
-        URLParser parser(makeString(StringView(m_string).left(m_userEnd), p, StringView(m_string).substring(end)));
-        *this = parser.result();
+    if (!newPassword.isEmpty()) {
+        bool needLeadingSlashes = m_userEnd == m_schemeEnd + 1;
+        parse(makeString(
+            StringView(m_string).left(m_userEnd),
+            needLeadingSlashes ? "//:" : ":",
+            percentEncodeCharacters(newPassword.toStringWithoutCopying(), URLParser::isInUserInfoEncodeSet),
+            '@',
+            StringView(m_string).substring(credentialsEnd())
+        ));
     } else {
-        // Remove '@' if we now have neither user nor password.
-        if (m_userStart == m_userEnd && end != m_hostEnd && m_string[end] == '@')
-            end += 1;
-        // We don't want to parse in the extremely common case where we are not going to make a change.
-        if (m_userEnd != end) {
-            URLParser parser(makeString(StringView(m_string).left(m_userEnd), StringView(m_string).substring(end)));
-            *this = parser.result();
-        }
+        unsigned end = m_userStart == m_userEnd ? credentialsEnd() : m_passwordEnd;
+        remove(m_userEnd, end - m_userEnd);
     }
 }
 
+void URL::removeCredentials()
+{
+    if (!m_isValid)
+        return;
+
+    remove(m_userStart, credentialsEnd() - m_userStart);
+}
+
 void URL::setFragmentIdentifier(StringView identifier)
 {
     if (!m_isValid)
         return;
 
-    // FIXME: Optimize the case where the identifier already happens to be equal to what was passed?
-    // FIXME: Is it correct to do this without encoding and escaping non-ASCII characters?
-    *this = URLParser { makeString(StringView { m_string }.substring(0, m_queryEnd), '#', identifier) }.result();
+    parse(makeString(StringView(m_string).left(m_queryEnd), '#', identifier));
 }
 
 void URL::removeFragmentIdentifier()
 {
-    if (!m_isValid) {
-        ASSERT(!m_queryEnd);
+    if (!m_isValid)
         return;
-    }
-    if (m_isValid && m_string.length() > m_queryEnd)
-        m_string = m_string.left(m_queryEnd);
+
+    m_string = m_string.left(m_queryEnd);
 }
 
 void URL::removeQueryAndFragmentIdentifier()
@@ -637,62 +612,62 @@ void URL::removeQueryAndFragmentIdentifier()
     m_queryEnd = m_pathEnd;
 }
 
-void URL::setQuery(const String& query)
+void URL::setQuery(StringView newQuery)
 {
+    // FIXME: Consider renaming this function to setEncodedQuery and/or calling percentEncodeCharacters the way setPath does.
+    // https://webkit.org/b/161176
+
     if (!m_isValid)
         return;
 
-    // FIXME: '#' and non-ASCII characters must be encoded and escaped.
-    // Usually, the query is encoded using document encoding, not UTF-8, but we don't have
-    // access to the document in this function.
-    // https://webkit.org/b/161176
-    if ((query.isEmpty() || query[0] != '?') && !query.isNull()) {
-        URLParser parser(makeString(StringView(m_string).left(m_pathEnd), "?", query, StringView(m_string).substring(m_queryEnd)));
-        *this = parser.result();
-    } else {
-        URLParser parser(makeString(StringView(m_string).left(m_pathEnd), query, StringView(m_string).substring(m_queryEnd)));
-        *this = parser.result();
-    }
+    parse(makeString(
+        StringView(m_string).left(m_pathEnd),
+        (!newQuery.startsWith('?') && !newQuery.isNull()) ? "?" : "",
+        newQuery,
+        StringView(m_string).substring(m_queryEnd)
+    ));
+}
 
+static String escapePathWithoutCopying(StringView path)
+{
+    auto questionMarkOrNumberSign = [] (UChar character) {
+        return character == '?' || character == '#';
+    };
+    return percentEncodeCharacters(path.toStringWithoutCopying(), questionMarkOrNumberSign);
 }
 
-void URL::setPath(const String& s)
+void URL::setPath(StringView path)
 {
     if (!m_isValid)
         return;
 
-    String path = s;
-    if (path.isEmpty() || path[0] != '/')
-        path = "/" + path;
+    parse(makeString(
+        StringView(m_string).left(pathStart()),
+        path.startsWith('/') ? "" : "/",
+        escapePathWithoutCopying(path),
+        StringView(m_string).substring(m_pathEnd)
+    ));
+}
 
-    auto questionMarkOrNumberSign = [] (UChar character) {
-        return character == '?' || character == '#';
-    };
-    URLParser parser(makeString(StringView(m_string).left(m_hostEnd + m_portLength), percentEncodeCharacters(path, questionMarkOrNumberSign), StringView(m_string).substring(m_pathEnd)));
-    *this = parser.result();
+StringView URL::stringWithoutQueryOrFragmentIdentifier() const
+{
+    if (!m_isValid)
+        return m_string;
+
+    return StringView(m_string).left(pathEnd());
 }
 
-bool equalIgnoringFragmentIdentifier(const URL& a, const URL& b)
+StringView URL::stringWithoutFragmentIdentifier() const
 {
-    if (a.m_queryEnd != b.m_queryEnd)
-        return false;
-    unsigned queryLength = a.m_queryEnd;
-    for (unsigned i = 0; i < queryLength; ++i)
-        if (a.string()[i] != b.string()[i])
-            return false;
-    return true;
+    if (!m_isValid)
+        return m_string;
+
+    return StringView(m_string).left(m_queryEnd);
 }
 
-bool equalIgnoringQueryAndFragment(const URL& a, const URL& b)
+bool equalIgnoringFragmentIdentifier(const URL& a, const URL& b)
 {
-    if (a.pathEnd() != b.pathEnd())
-        return false;
-    unsigned pathEnd = a.pathEnd();
-    for (unsigned i = 0; i < pathEnd; ++i) {
-        if (a.string()[i] != b.string()[i])
-            return false;
-    }
-    return true;
+    return a.stringWithoutFragmentIdentifier() == b.stringWithoutFragmentIdentifier();
 }
 
 bool protocolHostAndPortAreEqual(const URL& a, const URL& b)
@@ -725,25 +700,10 @@ bool protocolHostAndPortAreEqual(const URL& a, const URL& b)
     return true;
 }
 
-bool hostsAreEqual(const URL& a, const URL& b)
+bool URL::isMatchingDomain(StringView domain) const
 {
-    unsigned hostStartA = a.hostStart();
-    unsigned hostLengthA = a.m_hostEnd - hostStartA;
-    unsigned hostStartB = b.hostStart();
-    unsigned hostLengthB = b.m_hostEnd - hostStartB;
-    if (hostLengthA != hostLengthB)
-        return false;
-
-    for (unsigned i = 0; i < hostLengthA; ++i) {
-        if (a.string()[hostStartA + i] != b.string()[hostStartB + i])
-            return false;
-    }
-
-    return true;
-}
+    // FIXME: Consider moving this to an appropriate place in WebCore's plug-in code; don't want people tempted to use this instead of SecurityOrigin.
 
-bool URL::isMatchingDomain(const String& domain) const
-{
     if (isNull())
         return false;
 
@@ -760,6 +720,7 @@ bool URL::isMatchingDomain(const String& domain) const
     return host.length() == domain.length() || host[host.length() - domain.length() - 1] == '.';
 }
 
+// FIXME: Rename this so it's clear that it does the appropriate escaping for URL query field values.
 String encodeWithURLEscapeSequences(const String& input)
 {
     return percentEncodeCharacters(input, URLParser::isInUserInfoEncodeSet);
@@ -781,41 +742,34 @@ void URL::copyToBuffer(Vector<char, 512>& buffer) const
     copyASCII(m_string, buffer.data());
 }
 
-template<typename StringClass>
-bool protocolIsInternal(const StringClass& url, const char* protocol)
+static bool protocolIsInternal(StringView string, const char* protocol)
 {
-    // Do the comparison without making a new string object.
-    assertProtocolIsGood(StringView { protocol });
+    assertProtocolIsGood(protocol);
     bool isLeading = true;
-    for (unsigned i = 0, j = 0; url[i]; ++i) {
-        // Skip leading whitespace and control characters.
-        if (isLeading && shouldTrimFromURL(url[i]))
-            continue;
-        isLeading = false;
-
-        // Skip any tabs and newlines.
-        if (url[i] == '\t' || url[i] == '\r' || url[i] == '\n')
-            continue;
+    for (auto codeUnit : string.codeUnits()) {
+        if (isLeading) {
+            // Skip leading whitespace and control characters.
+            if (shouldTrimFromURL(codeUnit))
+                continue;
+            isLeading = false;
+        } else {
+            // Skip tabs and newlines even later in the protocol.
+            if (codeUnit == '\t' || codeUnit == '\r' || codeUnit == '\n')
+                continue;
+        }
 
-        if (!protocol[j])
-            return url[i] == ':';
-        if (!isASCIIAlphaCaselessEqual(url[i], protocol[j]))
+        char expectedCharacter = *protocol++;
+        if (!expectedCharacter)
+            return codeUnit == ':';
+        if (!isASCIIAlphaCaselessEqual(codeUnit, expectedCharacter))
             return false;
-
-        ++j;
     }
-    
     return false;
 }
 
-bool protocolIs(const String& url, const char* protocol)
-{
-    return protocolIsInternal(url, protocol);
-}
-
-inline bool URL::protocolIs(const String& string, const char* protocol)
+bool protocolIs(StringView string, const char* protocol)
 {
-    return WTF::protocolIsInternal(string, protocol);
+    return protocolIsInternal(string, protocol);
 }
 
 #ifndef NDEBUG
@@ -829,11 +783,18 @@ void URL::print() const
 
 String URL::strippedForUseAsReferrer() const
 {
-    URL referrer(*this);
-    referrer.setUser(String());
-    referrer.setPass(String());
-    referrer.removeFragmentIdentifier();
-    return referrer.string();
+    if (!m_isValid)
+        return m_string;
+
+    unsigned end = credentialsEnd();
+
+    if (m_userStart == end && m_queryEnd == m_string.length())
+        return m_string;
+
+    return makeString(
+        StringView(m_string).substring(0, m_userStart),
+        StringView(m_string).substring(end, m_queryEnd - end)
+    );
 }
 
 bool URL::isLocalFile() const
@@ -845,17 +806,12 @@ bool URL::isLocalFile() const
     return protocolIs("file");
 }
 
-bool protocolIsJavaScript(const String& url)
+bool protocolIsJavaScript(StringView string)
 {
-    return protocolIsInternal(url, "javascript");
+    return protocolIsInternal(string, "javascript");
 }
 
-bool protocolIsJavaScript(StringView url)
-{
-    return protocolIsInternal(url, "javascript");
-}
-
-bool protocolIsInHTTPFamily(const String& url)
+bool protocolIsInHTTPFamily(StringView url)
 {
     auto length = url.length();
     // Do the comparison without making a new string object.
@@ -869,13 +825,13 @@ bool protocolIsInHTTPFamily(const String& url)
 
 const URL& aboutBlankURL()
 {
-    static NeverDestroyed<URL> staticBlankURL(URL(), "about:blank");
+    static NeverDestroyed<URL> staticBlankURL(URL(), "about:blank"_s);
     return staticBlankURL;
 }
 
 const URL& aboutSrcDocURL()
 {
-    static NeverDestroyed<URL> staticAboutSrcDocURL(URL(), "about:srcdoc");
+    static NeverDestroyed<URL> staticAboutSrcDocURL(URL(), "about:srcdoc"_s);
     return staticAboutSrcDocURL;
 }
 
@@ -964,7 +920,6 @@ bool portAllowed(const URL& url)
         6669, // Alternate IRC [Apple addition]
         6679, // Alternate IRC SSL [Apple addition]
         6697, // IRC+SSL [Apple addition]
-        invalidPortNumber, // Used to block all invalid port numbers
     };
 
     // If the port is not in the blocked port list, allow it.
@@ -983,15 +938,15 @@ bool portAllowed(const URL& url)
     return false;
 }
 
-String mimeTypeFromDataURL(const String& url)
+String mimeTypeFromDataURL(StringView dataURL)
 {
-    ASSERT(protocolIsInternal(url, "data"));
+    ASSERT(protocolIsInternal(dataURL, "data"));
 
     // FIXME: What's the right behavior when the URL has a comma first, but a semicolon later?
-    // Currently this code will break at the semicolon in that case. Not sure that's correct.
-    auto index = url.find(';', 5);
+    // Currently this code will break at the semicolon in that case; should add a test.
+    auto index = dataURL.find(';', 5);
     if (index == notFound)
-        index = url.find(',', 5);
+        index = dataURL.find(',', 5);
     if (index == notFound) {
         // FIXME: There was an old comment here that made it sound like this should be returning text/plain.
         // But we have been returning empty string here for some time, so not changing its behavior at this time.
@@ -1000,25 +955,45 @@ String mimeTypeFromDataURL(const String& url)
     if (index == 5)
         return "text/plain"_s;
     ASSERT(index >= 5);
-    return url.substring(5, index - 5).convertToASCIILowercase();
+    return dataURL.substring(5, index - 5).convertToASCIILowercase();
 }
 
 String URL::stringCenterEllipsizedToLength(unsigned length) const
 {
-    if (string().length() <= length)
-        return string();
+    if (m_string.length() <= length)
+        return m_string;
+
+    return makeString(StringView(m_string).left(length / 2 - 1), "...", StringView(m_string).right(length / 2 - 2));
+}
+
+URL URL::fakeURLWithRelativePart(StringView relativePart)
+{
+    return URL(URL(), makeString("webkit-fake-url://", createCanonicalUUIDString(), '/', relativePart));
+}
 
-    return string().left(length / 2 - 1) + "..." + string().right(length / 2 - 2);
+URL URL::fileURLWithFileSystemPath(StringView path)
+{
+    return URL(URL(), makeString(
+        "file://",
+        path.startsWith('/') ? "" : "/",
+        escapePathWithoutCopying(path)
+    ));
 }
 
-URL URL::fakeURLWithRelativePart(const String& relativePart)
+StringView URL::queryWithLeadingQuestionMark() const
 {
-    return URL(URL(), "webkit-fake-url://" + createCanonicalUUIDString() + '/' + relativePart);
+    if (m_queryEnd <= m_pathEnd)
+        return { };
+
+    return StringView(m_string).substring(m_pathEnd, m_queryEnd - m_pathEnd);
 }
 
-URL URL::fileURLWithFileSystemPath(const String& filePath)
+StringView URL::fragmentIdentifierWithLeadingNumberSign() const
 {
-    return URL(URL(), "file:///" + filePath);
+    if (!m_isValid || m_string.length() <= m_queryEnd)
+        return { };
+
+    return StringView(m_string).substring(m_queryEnd);
 }
 
 bool URL::isAboutBlank() const
@@ -1038,6 +1013,7 @@ TextStream& operator<<(TextStream& ts, const URL& url)
 }
 
 #if !PLATFORM(COCOA) && !USE(SOUP)
+
 static bool isIPv4Address(StringView string)
 {
     auto count = 0;
@@ -1124,11 +1100,9 @@ static bool isIPv6Address(StringView string)
 
 bool URL::hostIsIPAddress(StringView host)
 {
-    if (host.find(':') == notFound)
-        return isIPv4Address(host);
-
-    return isIPv6Address(host);
+    return host.contains(':') ? isIPv6Address(host) : isIPv4Address(host);
 }
+
 #endif
 
 } // namespace WTF
index 5ddde67..24c0d89 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,47 +38,39 @@ OBJC_CLASS NSURL;
 #endif
 
 namespace WTF {
+
 class TextStream;
 
 class URLTextEncoding {
 public:
     virtual Vector<uint8_t> encodeForURLParsing(StringView) const = 0;
-    virtual ~URLTextEncoding() { };
+protected:
+    virtual ~URLTextEncoding() { }
 };
 
-struct URLHash;
-
-class WTF_EXPORT_PRIVATE URL {
+class URL {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     // Generates a URL which contains a null string.
     URL() { invalidate(); }
 
-    explicit URL(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { }
-    bool isHashTableDeletedValue() const { return string().isHashTableDeletedValue(); }
+    explicit URL(HashTableDeletedValueType);
+    bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); }
 
     // Resolves the relative URL with the given base URL. If provided, the
     // URLTextEncoding is used to encode non-ASCII characers. The base URL can be
-    // null or empty, in which case the relative URL will be interpreted as
-    // absolute.
-    // FIXME: If the base URL is invalid, this always creates an invalid
-    // URL. Instead I think it would be better to treat all invalid base URLs
-    // the same way we treate null and empty base URLs.
-    URL(const URL& base, const String& relative, const URLTextEncoding* = nullptr);
+    // null or empty, in which case the relative URL will be interpreted as absolute.
+    WTF_EXPORT_PRIVATE URL(const URL& base, const String& relative, const URLTextEncoding* = nullptr);
 
-    static URL fakeURLWithRelativePart(const String&);
-    static URL fileURLWithFileSystemPath(const String&);
+    WTF_EXPORT_PRIVATE static URL fakeURLWithRelativePart(StringView);
+    WTF_EXPORT_PRIVATE static URL fileURLWithFileSystemPath(StringView);
 
-    String strippedForUseAsReferrer() const;
-
-    // FIXME: The above functions should be harmonized so that passing a
-    // base of null or the empty string gives the same result as the
-    // standard String constructor.
+    WTF_EXPORT_PRIVATE String strippedForUseAsReferrer() const;
 
     // Makes a deep copy. Helpful only if you need to use a URL on another
     // thread. Since the underlying StringImpl objects are immutable, there's
     // no other reason to ever prefer isolatedCopy() over plain old assignment.
-    URL isolatedCopy() const;
+    WTF_EXPORT_PRIVATE URL isolatedCopy() const;
 
     bool isNull() const;
     bool isEmpty() const;
@@ -89,122 +81,126 @@ public:
     bool canSetHostOrPort() const { return isHierarchical(); }
 
     bool canSetPathname() const { return isHierarchical(); }
-    bool isHierarchical() const;
+    WTF_EXPORT_PRIVATE bool isHierarchical() const;
 
     const String& string() const { return m_string; }
+    WTF_EXPORT_PRIVATE String stringCenterEllipsizedToLength(unsigned length = 1024) const;
 
-    String stringCenterEllipsizedToLength(unsigned length = 1024) const;
-
-    StringView protocol() const;
-    StringView host() const;
-    Optional<uint16_t> port() const;
-    String hostAndPort() const;
-    String protocolHostAndPort() const;
-    String user() const;
-    String pass() const;
-    StringView path() const;
-    String lastPathComponent() const;
-    String query() const;
-    String fragmentIdentifier() const;
-    bool hasFragmentIdentifier() const;
+    // Unlike user() and password(), encodedUser() and encodedPassword() don't decode escape sequences.
+    // This is necessary for accurate round-tripping, because encoding doesn't encode '%' characters.
+
+    WTF_EXPORT_PRIVATE StringView protocol() const;
+    WTF_EXPORT_PRIVATE StringView encodedUser() const;
+    WTF_EXPORT_PRIVATE StringView encodedPassword() const;
+    WTF_EXPORT_PRIVATE StringView host() const;
+    WTF_EXPORT_PRIVATE Optional<uint16_t> port() const;
+    WTF_EXPORT_PRIVATE StringView path() const;
+    WTF_EXPORT_PRIVATE StringView lastPathComponent() const;
+    WTF_EXPORT_PRIVATE StringView query() const;
+    WTF_EXPORT_PRIVATE StringView fragmentIdentifier() const;
+
+    WTF_EXPORT_PRIVATE StringView queryWithLeadingQuestionMark() const;
+    WTF_EXPORT_PRIVATE StringView fragmentIdentifierWithLeadingNumberSign() const;
+    WTF_EXPORT_PRIVATE StringView stringWithoutQueryOrFragmentIdentifier() const;
+    StringView stringWithoutFragmentIdentifier() const;
+
+    WTF_EXPORT_PRIVATE String protocolHostAndPort() const;
+    WTF_EXPORT_PRIVATE String hostAndPort() const;
+    WTF_EXPORT_PRIVATE String user() const;
+    WTF_EXPORT_PRIVATE String password() const;
+    WTF_EXPORT_PRIVATE String fileSystemPath() const;
+
+    WTF_EXPORT_PRIVATE URL truncatedForUseAsBase() const;
 
-    bool hasUsername() const;
-    bool hasPassword() const;
     bool hasQuery() const;
-    bool hasFragment() const;
+    bool hasFragmentIdentifier() const;
     bool hasPath() const;
 
-    // Unlike user() and pass(), these functions don't decode escape sequences.
-    // This is necessary for accurate round-tripping, because encoding doesn't encode '%' characters.
-    String encodedUser() const;
-    String encodedPass() const;
-
-    String baseAsString() const;
-
-    String fileSystemPath() const;
+    bool hasCredentials() const;
 
     // Returns true if the current URL's protocol is the same as the null-
     // terminated ASCII argument. The argument must be lower-case.
-    bool protocolIs(const char*) const;
-    bool protocolIs(StringView) const;
+    WTF_EXPORT_PRIVATE bool protocolIs(const char*) const;
+    WTF_EXPORT_PRIVATE bool protocolIs(StringView) const;
     bool protocolIsBlob() const { return protocolIs("blob"); }
     bool protocolIsData() const { return protocolIs("data"); }
-    bool protocolIsAbout() const;
+    WTF_EXPORT_PRIVATE bool protocolIsAbout() const;
     bool protocolIsInHTTPFamily() const;
-    bool isLocalFile() const;
+    WTF_EXPORT_PRIVATE bool isLocalFile() const;
     bool cannotBeABaseURL() const { return m_cannotBeABaseURL; }
 
-    bool isAboutBlank() const;
-    bool isAboutSrcDoc() const;
+    WTF_EXPORT_PRIVATE bool isAboutBlank() const;
+    WTF_EXPORT_PRIVATE bool isAboutSrcDoc() const;
 
-    bool isMatchingDomain(const String&) const;
+    WTF_EXPORT_PRIVATE bool isMatchingDomain(StringView) const;
 
-    bool setProtocol(const String&);
-    void setHost(const String&);
+    WTF_EXPORT_PRIVATE bool setProtocol(StringView);
+    WTF_EXPORT_PRIVATE void setHost(StringView);
 
-    void removePort();
-    void setPort(unsigned short);
+    WTF_EXPORT_PRIVATE void setPort(Optional<uint16_t>);
 
     // Input is like "foo.com" or "foo.com:8000".
-    void setHostAndPort(const String&);
-    void removeHostAndPort();
+    WTF_EXPORT_PRIVATE void setHostAndPort(StringView);
 
-    void setUser(const String&);
-    void setPass(const String&);
+    WTF_EXPORT_PRIVATE void setUser(StringView);
+    WTF_EXPORT_PRIVATE void setPassword(StringView);
+    WTF_EXPORT_PRIVATE void removeCredentials();
 
-    // If you pass an empty path for HTTP or HTTPS URLs, the resulting path
-    // will be "/".
-    void setPath(const String&);
+    // If you pass an empty path for HTTP or HTTPS URLs, the resulting path will be "/".
+    WTF_EXPORT_PRIVATE void setPath(StringView);
 
     // The query may begin with a question mark, or, if not, one will be added
     // for you. Setting the query to the empty string will leave a "?" in the
     // URL (with nothing after it). To clear the query, pass a null string.
-    void setQuery(const String&);
+    WTF_EXPORT_PRIVATE void setQuery(StringView);
 
-    void setFragmentIdentifier(StringView);
-    void removeFragmentIdentifier();
+    WTF_EXPORT_PRIVATE void setFragmentIdentifier(StringView);
+    WTF_EXPORT_PRIVATE void removeFragmentIdentifier();
 
-    void removeQueryAndFragmentIdentifier();
+    WTF_EXPORT_PRIVATE void removeQueryAndFragmentIdentifier();
 
-    static bool hostIsIPAddress(StringView);
+    WTF_EXPORT_PRIVATE static bool hostIsIPAddress(StringView);
 
     unsigned pathStart() const;
     unsigned pathEnd() const;
     unsigned pathAfterLastSlash() const;
 
-    operator const String&() const { return string(); }
+    operator const String&() const { return m_string; }
+    operator StringView() const { return m_string; }
 
 #if USE(CF)
-    URL(CFURLRef);
-    RetainPtr<CFURLRef> createCFURL() const;
+    WTF_EXPORT_PRIVATE URL(CFURLRef);
+    WTF_EXPORT_PRIVATE RetainPtr<CFURLRef> createCFURL() const;
 #endif
 
 #if USE(FOUNDATION)
-    URL(NSURL*);
-    operator NSURL*() const;
+    WTF_EXPORT_PRIVATE URL(NSURL *);
+    WTF_EXPORT_PRIVATE operator NSURL *() const;
 #endif
+
 #ifdef __OBJC__
-    operator NSString*() const { return string(); }
+    operator NSString *() const { return m_string; }
 #endif
 
 #ifndef NDEBUG
     void print() const;
 #endif
 
-    template <class Encoder> void encode(Encoder&) const;
-    template <class Decoder> static WARN_UNUSED_RETURN bool decode(Decoder&, URL&);
-    template <class Decoder> static Optional<URL> decode(Decoder&);
+    template<typename Encoder> void encode(Encoder&) const;
+    template<typename Decoder> static WARN_UNUSED_RETURN bool decode(Decoder&, URL&);
+    template<typename Decoder> static Optional<URL> decode(Decoder&);
 
 private:
     friend class URLParser;
-    void invalidate();
-    static bool protocolIs(const String&, const char*);
+
+    WTF_EXPORT_PRIVATE void invalidate();
     void copyToBuffer(Vector<char, 512>& buffer) const;
     unsigned hostStart() const;
+    unsigned credentialsEnd() const;
+    void remove(unsigned start, unsigned length);
+    void parse(const String&);
 
-    friend WTF_EXPORT_PRIVATE bool equalIgnoringFragmentIdentifier(const URL&, const URL&);
     friend WTF_EXPORT_PRIVATE bool protocolHostAndPortAreEqual(const URL&, const URL&);
-    friend WTF_EXPORT_PRIVATE bool hostsAreEqual(const URL&, const URL&);
 
     String m_string;
 
@@ -229,49 +225,27 @@ private:
 
 static_assert(sizeof(URL) == sizeof(String) + 8 * sizeof(unsigned), "URL should stay small");
 
-template <class Encoder>
-void URL::encode(Encoder& encoder) const
-{
-    encoder << m_string;
-}
-
-template <class Decoder>
-bool URL::decode(Decoder& decoder, URL& url)
-{
-    auto optionalURL = URL::decode(decoder);
-    if (!optionalURL)
-        return false;
-    url = WTFMove(*optionalURL);
-    return true;
-}
-
-template <class Decoder>
-Optional<URL> URL::decode(Decoder& decoder)
-{
-    Optional<String> string;
-    decoder >> string;
-    if (!string)
-        return WTF::nullopt;
-    return URL(URL(), WTFMove(*string));
-}
+bool operator==(const URL&, const URL&);
+bool operator==(const URL&, const String&);
+bool operator==(const String&, const URL&);
+bool operator!=(const URL&, const URL&);
+bool operator!=(const URL&, const String&);
+bool operator!=(const String&, const URL&);
 
 WTF_EXPORT_PRIVATE bool equalIgnoringFragmentIdentifier(const URL&, const URL&);
-WTF_EXPORT_PRIVATE bool equalIgnoringQueryAndFragment(const URL&, const URL&);
 WTF_EXPORT_PRIVATE bool protocolHostAndPortAreEqual(const URL&, const URL&);
-WTF_EXPORT_PRIVATE bool hostsAreEqual(const URL&, const URL&);
 
 WTF_EXPORT_PRIVATE const URL& aboutBlankURL();
 WTF_EXPORT_PRIVATE const URL& aboutSrcDocURL();
 
 // Functions to do URL operations on strings.
 // These are operations that aren't faster on a parsed URL.
-// These are also different from the URL functions in that they don't require the string to be a valid and parsable URL.
-// This is especially important because valid javascript URLs are not necessarily considered valid by URL.
+// These are also different from the WTF::URL functions in that they don't require the string to be a valid and parsable URL.
+// This is especially important because valid javascript URLs are not necessarily considered valid by WTF::URL.
 
-WTF_EXPORT_PRIVATE bool protocolIs(const String& url, const char* protocol);
-WTF_EXPORT_PRIVATE bool protocolIsJavaScript(const String& url);
+WTF_EXPORT_PRIVATE bool protocolIs(StringView url, const char* protocol);
 WTF_EXPORT_PRIVATE bool protocolIsJavaScript(StringView url);
-WTF_EXPORT_PRIVATE bool protocolIsInHTTPFamily(const String& url);
+WTF_EXPORT_PRIVATE bool protocolIsInHTTPFamily(StringView url);
 
 WTF_EXPORT_PRIVATE Optional<uint16_t> defaultPortForProtocol(StringView protocol);
 WTF_EXPORT_PRIVATE bool isDefaultPortForProtocol(uint16_t port, StringView protocol);
@@ -280,11 +254,9 @@ WTF_EXPORT_PRIVATE bool portAllowed(const URL&); // Blacklist ports that should
 WTF_EXPORT_PRIVATE void registerDefaultPortForProtocolForTesting(uint16_t port, const String& protocol);
 WTF_EXPORT_PRIVATE void clearDefaultPortForProtocolMapForTesting();
 
-WTF_EXPORT_PRIVATE bool isValidProtocol(const String&);
+WTF_EXPORT_PRIVATE String mimeTypeFromDataURL(StringView dataURL);
 
-WTF_EXPORT_PRIVATE String mimeTypeFromDataURL(const String& url);
-
-// FIXME: This is a wrong concept to expose, different parts of a URL need different escaping per the URL Standard.
+// FIXME: This needs a new, more specific name. The general thing named here can't be implemented correctly, since different parts of a URL need different escaping.
 WTF_EXPORT_PRIVATE String encodeWithURLEscapeSequences(const String&);
 
 #ifdef __OBJC__
@@ -294,7 +266,35 @@ WTF_EXPORT_PRIVATE Optional<URL> makeVectorElement(const URL*, id);
 
 #endif
 
-// Inlines.
+WTF_EXPORT_PRIVATE TextStream& operator<<(TextStream&, const URL&);
+
+template<> struct DefaultHash<URL>;
+template<> struct HashTraits<URL>;
+
+// Function template and inline function definitions.
+
+template<typename Encoder> void URL::encode(Encoder& encoder) const
+{
+    encoder << m_string;
+}
+
+template<typename Decoder> bool URL::decode(Decoder& decoder, URL& url)
+{
+    auto optionalURL = decode(decoder);
+    if (!optionalURL)
+        return false;
+    url = WTFMove(*optionalURL);
+    return true;
+}
+
+template<typename Decoder> Optional<URL> URL::decode(Decoder& decoder)
+{
+    Optional<String> string;
+    decoder >> string;
+    if (!string)
+        return WTF::nullopt;
+    return URL(URL(), WTFMove(*string));
+}
 
 inline bool operator==(const URL& a, const URL& b)
 {
@@ -326,8 +326,10 @@ inline bool operator!=(const String& a, const URL& b)
     return a != b.string();
 }
 
-// Inline versions of some non-GoogleURL functions so we can get inlining
-// without having to have a lot of ugly ifdefs in the class definition.
+inline URL::URL(HashTableDeletedValueType)
+    : m_string(HashTableDeletedValue)
+{
+}
 
 inline bool URL::isNull() const
 {
@@ -346,17 +348,12 @@ inline bool URL::isValid() const
 
 inline bool URL::hasPath() const
 {
-    return m_pathEnd != m_hostEnd + m_portLength;
+    return m_pathEnd > pathStart();
 }
 
-inline bool URL::hasUsername() const
+inline bool URL::hasCredentials() const
 {
-    return m_userEnd > m_userStart;
-}
-
-inline bool URL::hasPassword() const
-{
-    return m_passwordEnd > (m_userEnd + 1);
+    return m_passwordEnd > m_userStart;
 }
 
 inline bool URL::hasQuery() const
@@ -364,7 +361,7 @@ inline bool URL::hasQuery() const
     return m_queryEnd > m_pathEnd;
 }
 
-inline bool URL::hasFragment() const
+inline bool URL::hasFragmentIdentifier() const
 {
     return m_isValid && m_string.length() > m_queryEnd;
 }
@@ -389,11 +386,6 @@ inline unsigned URL::pathAfterLastSlash() const
     return m_pathAfterLastSlash;
 }
 
-WTF_EXPORT_PRIVATE WTF::TextStream& operator<<(WTF::TextStream&, const URL&);
-
-template<> struct DefaultHash<URL>;
-template<> struct HashTraits<URL>;
-
 } // namespace WTF
 
 using WTF::aboutBlankURL;
index 06b0aec..fa08c9f 100644 (file)
@@ -64,7 +64,7 @@ bool isCFURLSameOrigin(CFURLRef cfURL, const URL& url)
 {
     ASSERT(url.protocolIsInHTTPFamily());
 
-    if (url.hasUsername() || url.hasPassword())
+    if (url.hasCredentials())
         return protocolHostAndPortAreEqual(url, URL { cfURL });
 
     URLCharBuffer bytes;
index d13bb6c..c25e015 100644 (file)
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <wtf/Lock.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/Optional.h>
+#include <wtf/text/StringToIntegerConversion.h>
 #include <wtf/text/TextBreakIterator.h>
 
 namespace WTF {
@@ -74,6 +75,11 @@ bool StringView::startsWithIgnoringASCIICase(const StringView& prefix) const
     return ::WTF::startsWithIgnoringASCIICase(*this, prefix);
 }
 
+bool StringView::endsWith(UChar character) const
+{
+    return m_length && (*this)[m_length - 1] == character;
+}
+
 bool StringView::endsWith(const StringView& suffix) const
 {
     return ::WTF::endsWith(*this, suffix);
@@ -306,6 +312,35 @@ String normalizedNFC(const String& string)
     return result.underlyingString;
 }
 
+// FIXME: Should this be named parseNumber<uint16_t> instead?
+// FIXME: Should we replace the toInt family of functions with this style?
+Optional<uint16_t> parseUInt16(StringView string)
+{
+    bool ok = false;
+    auto number = toIntegralType<uint16_t>(string, &ok);
+    if (!ok)
+        return WTF::nullopt;
+    return number;
+}
+
+bool equalRespectingNullity(StringView a, StringView b)
+{
+    if (a.m_characters == b.m_characters) {
+        ASSERT(a.is8Bit() == b.is8Bit());
+        return a.length() == b.length();
+    }
+
+    if (a.isEmpty() && b.isEmpty())
+        return a.isNull() == b.isNull();
+
+    return equalCommon(a, b);
+}
+
+bool StringView::contains(const char* string) const
+{
+    return find(string) != notFound;
+}
+
 #if CHECK_STRINGVIEW_LIFETIME
 
 // Manage reference count manually so UnderlyingString does not need to be defined in the header.
index 6cfebdb..09c7934 100644 (file)
@@ -137,8 +137,7 @@ public:
 
     size_t find(UChar, unsigned start = 0) const;
     size_t find(CodeUnitMatchFunction, unsigned start = 0) const;
-
-    WTF_EXPORT_PRIVATE size_t find(StringView, unsigned start) const;
+    WTF_EXPORT_PRIVATE size_t find(StringView, unsigned start = 0) const;
 
     size_t reverseFind(UChar, unsigned index = std::numeric_limits<unsigned>::max()) const;
 
@@ -151,6 +150,7 @@ public:
     bool contains(UChar) const;
     bool contains(CodeUnitMatchFunction) const;
     bool contains(StringView string) const { return find(string, 0) != notFound; }
+    WTF_EXPORT_PRIVATE bool contains(const char*) const;
 
     WTF_EXPORT_PRIVATE bool containsIgnoringASCIICase(const StringView&) const;
     WTF_EXPORT_PRIVATE bool containsIgnoringASCIICase(const StringView&, unsigned startOffset) const;
@@ -159,6 +159,7 @@ public:
     WTF_EXPORT_PRIVATE bool startsWith(const StringView&) const;
     WTF_EXPORT_PRIVATE bool startsWithIgnoringASCIICase(const StringView&) const;
 
+    WTF_EXPORT_PRIVATE bool endsWith(UChar) const;
     WTF_EXPORT_PRIVATE bool endsWith(const StringView&) const;
     WTF_EXPORT_PRIVATE bool endsWithIgnoringASCIICase(const StringView&) const;
 
@@ -174,6 +175,7 @@ public:
 
 private:
     friend bool equal(StringView, StringView);
+    friend WTF_EXPORT_PRIVATE bool equalRespectingNullity(StringView, StringView);
 
     void initialize(const LChar*, unsigned length);
     void initialize(const UChar*, unsigned length);
@@ -191,6 +193,7 @@ private:
     void setUnderlyingString(const StringImpl*) { }
     void setUnderlyingString(const StringView&) { }
 #endif
+
     void clear();
 
     const void* m_characters { nullptr };
@@ -210,6 +213,9 @@ bool equal(StringView, const LChar* b);
 bool equalIgnoringASCIICase(StringView, StringView);
 bool equalIgnoringASCIICase(StringView, const char*);
 
+WTF_EXPORT_PRIVATE bool equalRespectingNullity(StringView, StringView);
+bool equalIgnoringNullity(StringView, StringView);
+
 template<unsigned length> bool equalLettersIgnoringASCIICase(StringView, const char (&lowercaseLetters)[length]);
 template<unsigned length> bool startsWithLettersIgnoringASCIICase(StringView, const char (&lowercaseLetters)[length]);
 
@@ -234,6 +240,8 @@ WTF_EXPORT_PRIVATE StringViewWithUnderlyingString normalizedNFC(StringView);
 
 WTF_EXPORT_PRIVATE String normalizedNFC(const String&);
 
+WTF_EXPORT_PRIVATE Optional<uint16_t> parseUInt16(StringView);
+
 }
 
 #include <wtf/text/AtomString.h>
@@ -1043,6 +1051,12 @@ template<unsigned length> inline bool startsWithLettersIgnoringASCIICase(StringV
     return startsWithLettersIgnoringASCIICaseCommon(string, lowercaseLetters);
 }
 
+inline bool equalIgnoringNullity(StringView a, StringView b)
+{
+    // FIXME: equal(StringView, StringView) ignores nullity; consider changing to be like other string classes and respecting it.
+    return equal(a, b);
+}
+
 } // namespace WTF
 
 using WTF::append;
index f12ad36..afc92f5 100644 (file)
@@ -924,102 +924,102 @@ static unsigned lengthOfCharactersAsInteger(const CharacterType* data, size_t le
 
 int charactersToIntStrict(const LChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<int, LChar>(data, length, ok, base);
+    return toIntegralType<int>(data, length, ok, base);
 }
 
 int charactersToIntStrict(const UChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<int, UChar>(data, length, ok, base);
+    return toIntegralType<int>(data, length, ok, base);
 }
 
 unsigned charactersToUIntStrict(const LChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<unsigned, LChar>(data, length, ok, base);
+    return toIntegralType<unsigned>(data, length, ok, base);
 }
 
 unsigned charactersToUIntStrict(const UChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<unsigned, UChar>(data, length, ok, base);
+    return toIntegralType<unsigned>(data, length, ok, base);
 }
 
 int64_t charactersToInt64Strict(const LChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<int64_t, LChar>(data, length, ok, base);
+    return toIntegralType<int64_t>(data, length, ok, base);
 }
 
 int64_t charactersToInt64Strict(const UChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<int64_t, UChar>(data, length, ok, base);
+    return toIntegralType<int64_t>(data, length, ok, base);
 }
 
 uint64_t charactersToUInt64Strict(const LChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<uint64_t, LChar>(data, length, ok, base);
+    return toIntegralType<uint64_t>(data, length, ok, base);
 }
 
 uint64_t charactersToUInt64Strict(const UChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<uint64_t, UChar>(data, length, ok, base);
+    return toIntegralType<uint64_t>(data, length, ok, base);
 }
 
 intptr_t charactersToIntPtrStrict(const LChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<intptr_t, LChar>(data, length, ok, base);
+    return toIntegralType<intptr_t>(data, length, ok, base);
 }
 
 intptr_t charactersToIntPtrStrict(const UChar* data, size_t length, bool* ok, int base)
 {
-    return toIntegralType<intptr_t, UChar>(data, length, ok, base);
+    return toIntegralType<intptr_t>(data, length, ok, base);
 }
 
 int charactersToInt(const LChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<int, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+    return toIntegralType<int>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
 }
 
 int charactersToInt(const UChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<int, UChar>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
+    return toIntegralType<int>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
 }
 
 unsigned charactersToUInt(const LChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<unsigned, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+    return toIntegralType<unsigned>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
 }
 
 unsigned charactersToUInt(const UChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<unsigned, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+    return toIntegralType<unsigned>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
 }
 
 int64_t charactersToInt64(const LChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<int64_t, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+    return toIntegralType<int64_t>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
 }
 
 int64_t charactersToInt64(const UChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<int64_t, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+    return toIntegralType<int64_t>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
 }
 
 uint64_t charactersToUInt64(const LChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<uint64_t, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+    return toIntegralType<uint64_t>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
 }
 
 uint64_t charactersToUInt64(const UChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<uint64_t, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+    return toIntegralType<uint64_t>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
 }
 
 intptr_t charactersToIntPtr(const LChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<intptr_t, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+    return toIntegralType<intptr_t>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
 }
 
 intptr_t charactersToIntPtr(const UChar* data, size_t length, bool* ok)
 {
-    return toIntegralType<intptr_t, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+    return toIntegralType<intptr_t>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
 }
 
 enum TrailingJunkPolicy { DisallowTrailingJunk, AllowTrailingJunk };
index fef9014..cd678dc 100644 (file)
@@ -1,3 +1,201 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * Modules/cache/DOMCacheEngine.cpp:
+        (WebCore::DOMCacheEngine::matchURLs): Removed unneeded calls to hasQuery.
+
+        * Modules/fetch/FetchRequest.cpp:
+        (WebCore::FetchRequest::initializeWith): Use hasCredentials.
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::redirect): Use hasCredentials.
+        * Modules/paymentrequest/PaymentRequest.cpp:
+        (WebCore::isValidURLBasedPaymentMethodIdentifier): Use hasCredentials.
+
+        * Modules/plugins/YouTubePluginReplacement.cpp:
+        (WebCore::createYouTubeURL): Take StringView.
+        (WebCore::queryKeysAndValues): Take StringView.
+        (WebCore::processAndCreateYouTubeURL): Use auto since URL pieces are
+        now returned as StringView.
+        (WebCore::YouTubePluginReplacement::youTubeURLFromAbsoluteURL):
+        Use StringView and makeString rather than StringBuilder.
+
+        * Modules/websockets/WebSocketHandshake.cpp:
+        (WebCore::resourceName): Use queryWithLeadingQuestionMark.
+
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::internalLinkElement const):
+        Use StringView.
+
+        * dom/Document.cpp:
+        (WebCore::Document::setURL): Use setHostAndPort.
+
+        * dom/Element.cpp:
+        (WebCore::Element::findAnchorElementForLink): Update since
+        fragmentIdentifier returns StringView.
+
+        * dom/TreeScope.cpp: Added a comment.
+
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::replaceRichContentWithAttachments): Update since
+        lastPathComponent returns a StringView. Also got rid of some strange
+        use of AtomString that was not necessary and used WTFMove more.
+
+        * editing/ios/EditorIOS.mm:
+        (WebCore::Editor::writeImageToPasteboard): Update since
+        lastPathComponent returns a StringView.
+
+        * html/HTMLAttachmentElement.cpp:
+        (WebCore::HTMLAttachmentElement::attachmentTitleForDisplay const):
+        Use makeString instead of StringBuilder, and StringView instead of
+        String for name and extension values.
+
+        * html/HTMLPlugInElement.cpp:
+        (WebCore::pluginReplacementForType): Update since lastPathComponent
+        returns a StringView.
+
+        * html/MediaFragmentURIParser.cpp:
+        (WebCore::MediaFragmentURIParser::parseFragments): Update since
+        fragmentIdentifier returns a StringView.
+
+        * html/URLUtils.h: Changed many functions to take a StringView, changed
+        various other functions to call toString, since the underlying URL
+        function now returns a StringView. Updated names since "pass" is now
+        "password".
+        (WebCore::countASCIIDigits): Added. Replaces unusual function
+        named parsePortFromStringPosition because we can use StringView now
+        and so don't need such an unusual function.
+
+        * loader/AdClickAttribution.cpp:
+        (WebCore::AdClickAttribution::parseConversionRequest): Use hasCredentials.
+        Also removed unnecessary use of ASCIILiteral that hurts performance
+        a tiny bit.
+        (WebCore::AdClickAttribution::urlForTesting const): Use makeString
+        instead of StringBuilder.
+
+        * loader/CrossOriginAccessControl.cpp:
+        (WebCore::validateCrossOriginRedirectionURL): Use hasCredentials.
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::loadRequest): Use hasCredentials.
+
+        * loader/FormSubmission.cpp:
+        (WebCore::appendMailtoPostFormDataToURL): Update since query returns
+        StringView.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::loadInSameDocument): Use equalRespectingNullity on
+        fragment identifiers to preserve behavior, since at this time
+        StringView == StringView does not respect nullity, but String == String does.
+
+        * loader/appcache/ApplicationCacheHost.cpp:
+        (WebCore::ApplicationCacheHost::createFileURL): Use fileURLWithFileSystemPath.
+
+        * loader/appcache/ManifestParser.cpp:
+        (WebCore::manifestPath): Return a StringView.
+        (WebCore::parseManifest): Use StringView.
+
+        * loader/cache/CachedFont.cpp:
+        (WebCore::CachedFont::calculateItemInCollection const): Update since
+        fragmentIdentifer returns a StringView.
+        * loader/cache/CachedResourceRequest.cpp:
+        (WebCore::CachedResourceRequest::splitFragmentIdentifierFromRequestURL): Ditto.
+        * page/FrameView.cpp:
+        (WebCore::FrameView::scrollToFragment): Ditto.
+        (WebCore::FrameView::scrollToFragmentInternal): Updated log message.
+
+        * page/History.cpp:
+        (WebCore::History::stateObjectAdded): Updated for URL::password name change
+        and to use the new stringWithoutQueryOrFragmentIdentifier rather than the
+        old equalIgnoringQueryAndFragment.
+
+        * page/Location.cpp:
+        (WebCore::Location::href const): Use removeCredentials.
+        (WebCore::Location::port const): Streamlined.
+        (WebCore::Location::pathname const): Use an ASCIILiteral.
+        (WebCore::Location::search const): Use queryWithLeadingQuestionMark.
+        (WebCore::Location::hash const): Use fragmentIdentifierWithLeadingNumberSign.
+        (WebCore::Location::setPort): Use parseUInt16.
+
+        * page/UserContentURLPattern.cpp: Coding style tweaks.
+
+        * platform/MIMETypeRegistry.cpp:
+        (WebCore::MIMETypeRegistry::appendFileExtensionIfNecessary):
+        Use contains instead of reverseFind to check for a period in the filename.
+
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::load): Updated since lastPathComponent is a StringView.
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::convertToInternalProtocol): Updated to use makeString since
+        setProtocol takes a StringView.
+
+        * platform/network/ResourceHandleInternal.h: Renamed m_pass to m_password
+        and call password instead of pass.
+
+        * platform/network/ResourceRequestBase.cpp:
+        (WebCore::ResourceRequestBase::removeCredentials): Use removeCredentials.
+
+        * platform/network/cf/ResourceHandleCFNet.cpp:
+        (WebCore::ResourceHandle::createCFURLConnection): Updated for m_password
+        name change.
+        (WebCore::ResourceHandle::willSendRequest): Updated for m_password and
+        password name changes.
+        (WebCore::ResourceHandle::tryHandlePasswordBasedAuthentication): Ditto.
+
+        * platform/network/curl/CurlProxySettings.cpp:
+        (WebCore::CurlProxySettings::setUserPass): Updated for setPassword name change.
+        (WebCore::createProxyUrl): Use hasCredentials, updated for password name change.
+        * platform/network/curl/CurlProxySettings.h:
+        (WebCore::CurlProxySettings::password const): Updated for password name change.
+
+        * platform/network/curl/ResourceHandleCurl.cpp:
+        (WebCore::ResourceHandle::didReceiveAuthenticationChallenge): Updated for
+        m_password name change.
+        (WebCore::ResourceHandle::getCredential): Ditto.
+        (WebCore::ResourceHandle::willSendRequest): Updated for m_password and
+        password name changes.
+
+        * platform/network/mac/ResourceHandleMac.mm:
+        (WebCore::ResourceHandle::createNSURLConnection): Updated for m_password
+        and setPassword name changes.
+        (WebCore::ResourceHandle::willSendRequest): Ditto.
+        (WebCore::ResourceHandle::tryHandlePasswordBasedAuthentication): Ditto.
+
+        * platform/network/soup/ResourceRequestSoup.cpp:
+        (WebCore::ResourceRequest::createSoupURI const): Updated for password name change.
+        * platform/network/soup/URLSoup.cpp:
+        (WebCore::soupURIToURL): Updated for setPassword name change.
+
+        * platform/win/PasteboardWin.cpp:
+        (WebCore::writeURL): Updated since lastPathComponent returns a StringView.
+        (WebCore::filesystemPathFromUrlOrTitle): Ditto.
+        (WebCore::Pasteboard::write): Ditto.
+
+        * style/StyleBuilderState.cpp:
+        (WebCore::Style::BuilderState::createFilterOperations): Updated since
+        fragmentIdentifier returns a StringView.
+
+        * workers/WorkerLocation.cpp:
+        (WebCore::WorkerLocation::port const): Streamlined.
+        (WebCore::WorkerLocation::pathname const): Use an ASCIILiteral.
+        (WebCore::WorkerLocation::search const): Use queryWithLeadingQuestionMark.
+        (WebCore::WorkerLocation::hash const): Use fragmentIdentifierWithLeadingNumberSign.
+
+        * workers/service/ServiceWorkerRegistrationKey.cpp:
+        (WebCore::ServiceWorkerRegistrationKey::ServiceWorkerRegistrationKey):
+        Updated for hasFragmentIdentifier name change.
+
+        * workers/service/context/ServiceWorkerThreadProxy.cpp:
+        (WebCore::topOriginURL): Simplified code to set port.
+        * workers/service/server/SWServer.cpp:
+        (WebCore::originURL): Ditto.
+
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::open): Updated for setPassword name change.
+
 2020-04-25  Chris Fleizach  <cfleizach@apple.com>
 
         AX: Improve tracking of Element* pointers in AXObjectCache with WeakHashSet
index b0db57a..782b262 100644 (file)
@@ -72,10 +72,8 @@ static inline bool matchURLs(const ResourceRequest& request, const URL& cachedUR
     URL cachedRequestURL = cachedURL;
 
     if (options.ignoreSearch) {
-        if (requestURL.hasQuery())
-            requestURL.setQuery({ });
-        if (cachedRequestURL.hasQuery())
-            cachedRequestURL.setQuery({ });
+        requestURL.setQuery({ });
+        cachedRequestURL.setQuery({ });
     }
     return equalIgnoringFragmentIdentifier(requestURL, cachedRequestURL);
 }
index 3a55218..dfb733e 100644 (file)
@@ -160,9 +160,10 @@ static inline Optional<Exception> processInvalidSignal(ScriptExecutionContext& c
 ExceptionOr<void> FetchRequest::initializeWith(const String& url, Init&& init)
 {
     ASSERT(scriptExecutionContext());
-    // FIXME: Tighten the URL parsing algorithm according https://url.spec.whatwg.org/#concept-url-parser.
+
+    // FIXME: Tighten the URL parsing algorithm according to https://url.spec.whatwg.org/#concept-url-parser.
     URL requestURL = scriptExecutionContext()->completeURL(url, ScriptExecutionContext::ForceUTF8::Yes);
-    if (!requestURL.isValid() || !requestURL.user().isEmpty() || !requestURL.pass().isEmpty())
+    if (!requestURL.isValid() || requestURL.hasCredentials())
         return Exception { TypeError, "URL is not valid or contains user credentials."_s };
 
     m_options.mode = Mode::Cors;
index 609aa8a..05f49f8 100644 (file)
@@ -151,7 +151,7 @@ ExceptionOr<Ref<FetchResponse>> FetchResponse::redirect(ScriptExecutionContext&
     URL requestURL = context.completeURL(url);
     if (!requestURL.isValid())
         return Exception { TypeError, makeString("Redirection URL '", requestURL.string(), "' is invalid") };
-    if (!requestURL.user().isEmpty() || !requestURL.pass().isEmpty())
+    if (requestURL.hasCredentials())
         return Exception { TypeError, "Redirection URL contains credentials"_s };
     if (!ResourceResponse::isRedirectionStatusCode(status))
         return Exception { RangeError, makeString("Status code ", status, "is not a redirection status code") };
index caadf87..e7135be 100644 (file)
@@ -220,13 +220,7 @@ static bool isValidStandardizedPaymentMethodIdentifier(StringView identifier)
 // https://www.w3.org/TR/payment-method-id/#validation
 static bool isValidURLBasedPaymentMethodIdentifier(const URL& url)
 {
-    if (!url.protocolIs("https"))
-        return false;
-
-    if (!url.user().isEmpty() || !url.pass().isEmpty())
-        return false;
-
-    return true;
+    return url.protocolIs("https") && !url.hasCredentials();
 }
 
 // Implements "validate a payment method identifier"
index 4e7a025..ab4d5fb 100644 (file)
@@ -103,19 +103,14 @@ bool YouTubePluginReplacement::installReplacement(ShadowRoot& root)
     return true;
 }
     
-static inline URL createYouTubeURL(const String& videoID, const String& timeID)
+static URL createYouTubeURL(StringView videoID, StringView timeID)
 {
     ASSERT(!videoID.isEmpty());
     ASSERT(videoID != "/");
-    
-    URL result(URL(), "youtube:" + videoID);
-    if (!timeID.isEmpty())
-        result.setQuery("t=" + timeID);
-    
-    return result;
+    return URL(URL(), makeString("youtube:", videoID, timeID.isEmpty() ? "" : "t=", timeID));
 }
-    
-static YouTubePluginReplacement::KeyValueMap queryKeysAndValues(const String& queryString)
+
+static YouTubePluginReplacement::KeyValueMap queryKeysAndValues(StringView queryString)
 {
     YouTubePluginReplacement::KeyValueMap queryDictionary;
     
@@ -155,7 +150,7 @@ static YouTubePluginReplacement::KeyValueMap queryKeysAndValues(const String& qu
         // Save the key and the value.
         if (keyLength && valueLength) {
             String key = queryString.substring(keyLocation, keyLength).convertToASCIILowercase();
-            String value = queryString.substring(valueLocation, valueLength);
+            String value = queryString.substring(valueLocation, valueLength).toString();
             value.replace('+', ' ');
 
             if (!key.isEmpty() && !value.isEmpty())
@@ -209,16 +204,16 @@ static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedUR
 
     // Short URL of the form: http://youtu.be/v1d301D
     if (isYouTubeShortenedURL) {
-        String videoID = url.lastPathComponent();
+        auto videoID = url.lastPathComponent();
         if (videoID.isEmpty() || videoID == "/")
             return URL();
-        return createYouTubeURL(videoID, emptyString());
+        return createYouTubeURL(videoID, { });
     }
-    
+
     auto path = url.path();
-    String query = url.query();
-    String fragment = url.fragmentIdentifier();
-    
+    auto query = url.query();
+    auto fragment = url.fragmentIdentifier();
+
     // On the YouTube mobile web app, the path and query string are put into the
     // fragment so that one web page is only ever loaded (see <rdar://problem/9550639>).
     if (isYouTubeMobileWebAppURL) {
@@ -227,7 +222,7 @@ static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedUR
             path = fragment;
             query = emptyString();
         } else {
-            path = StringView(fragment).substring(0, location);
+            path = fragment.substring(0, location);
             query = fragment.substring(location + 1);
         }
         fragment = emptyString();
@@ -260,10 +255,10 @@ static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedUR
             }
         }
     } else if (startsWithLettersIgnoringASCIICase(path, "/v/") || startsWithLettersIgnoringASCIICase(path, "/e/")) {
-        String lastPathComponent = url.lastPathComponent();
-        String videoID;
-        String pathAfterFirstAmpersand;
+        StringView videoID;
+        StringView pathAfterFirstAmpersand;
 
+        auto lastPathComponent = url.lastPathComponent();
         size_t ampersandLocation = lastPathComponent.find('&');
         if (ampersandLocation != notFound) {
             // Some URLs we care about use & in place of ? for the first query parameter.
@@ -273,11 +268,11 @@ static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedUR
             videoID = lastPathComponent;
 
         if (!videoID.isEmpty()) {
-            outPathAfterFirstAmpersand = pathAfterFirstAmpersand;
+            outPathAfterFirstAmpersand = pathAfterFirstAmpersand.toString();
             return createYouTubeURL(videoID, emptyString());
         }
     }
-    
+
     return URL();
 }
 
@@ -290,13 +285,13 @@ String YouTubePluginReplacement::youTubeURL(const String& srcString)
 String YouTubePluginReplacement::youTubeURLFromAbsoluteURL(const URL& srcURL, const String& srcString)
 {
     bool isYouTubeShortenedURL = false;
-    String possibleMalformedQuery;
-    URL youTubeURL = processAndCreateYouTubeURL(srcURL, isYouTubeShortenedURL, possibleMalformedQuery);
+    String possiblyMalformedQuery;
+    URL youTubeURL = processAndCreateYouTubeURL(srcURL, isYouTubeShortenedURL, possiblyMalformedQuery);
     if (srcURL.isEmpty() || youTubeURL.isEmpty())
         return srcString;
 
     // Transform the youtubeURL (youtube:VideoID) to iframe embed url which has the format: http://www.youtube.com/embed/VideoID
-    auto srcPath = srcURL.path().toString();
+    auto srcPath = srcURL.path();
     const String& videoID = youTubeURL.string().substring(youTubeURL.protocol().length() + 1);
     size_t locationOfVideoIDInPath = srcPath.find(videoID);
 
@@ -305,7 +300,7 @@ String YouTubePluginReplacement::youTubeURLFromAbsoluteURL(const URL& srcURL, co
         ASSERT(locationOfVideoIDInPath);
     
         // From the original URL, we need to get the part before /path/VideoId.
-        locationOfPathBeforeVideoID = srcString.find(srcPath.substring(0, locationOfVideoIDInPath));
+        locationOfPathBeforeVideoID = StringView(srcString).find(srcPath.substring(0, locationOfVideoIDInPath));
     } else if (equalLettersIgnoringASCIICase(srcPath, "/watch")) {
         // From the original URL, we need to get the part before /watch/#!v=VideoID
         // FIXME: Shouldn't this be ASCII case-insensitive?
@@ -315,22 +310,21 @@ String YouTubePluginReplacement::youTubeURLFromAbsoluteURL(const URL& srcURL, co
 
     ASSERT(locationOfPathBeforeVideoID != notFound);
 
-    const String& srcURLPrefix = srcString.substring(0, locationOfPathBeforeVideoID);
-    String query = srcURL.query();
+    auto srcURLPrefix = StringView(srcString).substring(0, locationOfPathBeforeVideoID);
+    auto query = srcURL.query();
+
     // If the URL has no query, use the possibly malformed query we found.
     if (query.isEmpty())
-        query = possibleMalformedQuery;
+        query = possiblyMalformedQuery;
 
     // Append the query string if it is valid.
-    StringBuilder finalURL;
-    if (isYouTubeShortenedURL)
-        finalURL.appendLiteral("http://www.youtube.com");
-    else
-        finalURL.append(srcURLPrefix);
-    finalURL.append("/embed/", videoID);
-    if (!query.isEmpty())
-        finalURL.append('?', query);
-    return finalURL.toString();
+    return makeString(
+        isYouTubeShortenedURL ? "http://www.youtube.com" : srcURLPrefix,
+        "/embed/",
+        videoID,
+        query.isEmpty() ? "" : "?",
+        query
+    );
 }
     
 bool YouTubePluginReplacement::supportsURL(const URL& url)
index 9926cef..e237497 100644 (file)
@@ -64,15 +64,12 @@ namespace WebCore {
 
 static String resourceName(const URL& url)
 {
-    StringBuilder name;
-    name.append(url.path());
-    if (name.isEmpty())
-        name.append('/');
-    if (!url.query().isNull()) {
-        name.append('?');
-        name.append(url.query());
-    }
-    String result = name.toString();
+    auto path = url.path();
+    auto result = makeString(
+        path,
+        path.isEmpty() ? "/" : "",
+        url.queryWithLeadingQuestionMark()
+    );
     ASSERT(!result.isEmpty());
     ASSERT(!result.contains(' '));
     return result;
index 35a66be..cf6dc5d 100644 (file)
@@ -944,26 +944,27 @@ IntPoint AccessibilityRenderObject::clickPoint()
     
 AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const
 {
-    Element* element = anchorElement();
+    auto element = anchorElement();
+
     // Right now, we do not support ARIA links as internal link elements
     if (!is<HTMLAnchorElement>(element))
         return nullptr;
-    HTMLAnchorElement& anchor = downcast<HTMLAnchorElement>(*element);
-    
-    URL linkURL = anchor.href();
-    String fragmentIdentifier = linkURL.fragmentIdentifier();
+    auto& anchor = downcast<HTMLAnchorElement>(*element);
+
+    auto linkURL = anchor.href();
+    auto fragmentIdentifier = linkURL.fragmentIdentifier();
     if (fragmentIdentifier.isEmpty())
         return nullptr;
-    
+
     // check if URL is the same as current URL
-    URL documentURL = m_renderer->document().url();
+    auto documentURL = m_renderer->document().url();
     if (!equalIgnoringFragmentIdentifier(documentURL, linkURL))
         return nullptr;
-    
-    Node* linkedNode = m_renderer->document().findAnchor(fragmentIdentifier);
+
+    auto linkedNode = m_renderer->document().findAnchor(fragmentIdentifier.toStringWithoutCopying());
     if (!linkedNode)
         return nullptr;
-    
+
     // The element we find may not be accessible, so find the first accessible object.
     return firstAccessibleObjectFromNode(linkedNode);
 }
index 1972aed..e4454e6 100644 (file)
@@ -3251,7 +3251,7 @@ void Document::setURL(const URL& url)
 
     m_url = newURL;
     if (SecurityOrigin::shouldIgnoreHost(m_url))
-        m_url.removeHostAndPort();
+        m_url.setHostAndPort({ });
 
     m_documentURI = m_url.string();
     updateBaseURL();
index ed35fcd..1ff23e1 100644 (file)
@@ -4491,7 +4491,7 @@ Element* Element::findAnchorElementForLink(String& outAnchorName)
         return nullptr;
 
     if (url.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(url, document.baseURL())) {
-        outAnchorName = url.fragmentIdentifier();
+        outAnchorName = url.fragmentIdentifier().toString();
         return document.findAnchor(outAnchorName);
     }
 
index 1daa858..30ed9f3 100644 (file)
@@ -440,6 +440,8 @@ Vector<RefPtr<Element>> TreeScope::elementsFromPoint(const FloatPoint& p)
     return elementsFromPoint(p.x(), p.y());
 }
 
+// FIXME: Would be nice to change this to take a StringView, since that's what callers have
+// and there is no particular advantage to already having a String.
 Element* TreeScope::findAnchor(const String& name)
 {
     if (name.isEmpty())
index 0c9f9d0..fa61c5c 100644 (file)
@@ -328,13 +328,13 @@ static void replaceRichContentWithAttachments(Frame& frame, DocumentFragment& fr
         if (resource == urlToResourceMap.end())
             continue;
 
-        auto name = image.attributeWithoutSynchronization(HTMLNames::altAttr);
+        String name = image.attributeWithoutSynchronization(HTMLNames::altAttr);
         if (name.isEmpty())
-            name = URL({ }, resourceURLString).lastPathComponent();
+            name = URL({ }, resourceURLString).lastPathComponent().toString();
         if (name.isEmpty())
-            name = AtomString("media");
+            name = "media"_s;
 
-        attachmentInsertionInfo.append({ name, resource->value->mimeType(), resource->value->data(), image });
+        attachmentInsertionInfo.append({ WTFMove(name), resource->value->mimeType(), resource->value->data(), image });
     }
 
     for (auto& object : descendantsOfType<HTMLObjectElement>(fragment)) {
@@ -348,11 +348,11 @@ static void replaceRichContentWithAttachments(Frame& frame, DocumentFragment& fr
         if (resource == urlToResourceMap.end())
             continue;
 
-        auto name = URL({ }, resourceURLString).lastPathComponent();
+        String name = URL({ }, resourceURLString).lastPathComponent().toString();
         if (name.isEmpty())
-            name = AtomString("file");
+            name = "file"_s;
 
-        attachmentInsertionInfo.append({ name, resource->value->mimeType(), resource->value->data(), object });
+        attachmentInsertionInfo.append({ WTFMove(name), resource->value->mimeType(), resource->value->data(), object });
     }
 
     for (auto& info : attachmentInsertionInfo) {
index f2a2d52..b7d29cd 100644 (file)
@@ -202,7 +202,7 @@ void Editor::writeImageToPasteboard(Pasteboard& pasteboard, Element& imageElemen
         pasteboardImage.url.url = pasteboardImageURL;
         pasteboardImage.url.title = title;
     }
-    pasteboardImage.suggestedName = imageSourceURL.lastPathComponent();
+    pasteboardImage.suggestedName = imageSourceURL.lastPathComponent().toString();
     pasteboardImage.imageSize = image->size();
     pasteboardImage.resourceMIMEType = pasteboard.resourceMIMEType(cachedImage->response().mimeType());
     pasteboardImage.resourceData = cachedImage->resourceBuffer();
index bf89288..52acf07 100644 (file)
@@ -51,7 +51,6 @@
 #include "SecurityOrigin.h"
 #include "SecurityPolicy.h"
 #include "Settings.h"
-#include "URLUtils.h"
 #include "UserGestureIndicator.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/Optional.h>
index 3a11d92..90210f5 100644 (file)
@@ -177,22 +177,17 @@ String HTMLAttachmentElement::attachmentTitle() const
 String HTMLAttachmentElement::attachmentTitleForDisplay() const
 {
     auto title = attachmentTitle();
-
     auto indexOfLastDot = title.reverseFind('.');
     if (indexOfLastDot == notFound)
         return title;
 
-    String name = title.left(indexOfLastDot);
-    String extension = title.substring(indexOfLastDot);
-
-    StringBuilder builder;
-    builder.append(leftToRightMark);
-    builder.append(firstStrongIsolate);
-    builder.append(name);
-    builder.append(popDirectionalIsolate);
-    builder.append(extension);
-
-    return builder.toString();
+    return makeString(
+        leftToRightMark,
+        firstStrongIsolate,
+        StringView(title).left(indexOfLastDot),
+        popDirectionalIsolate,
+        StringView(title).substring(indexOfLastDot)
+    );
 }
 
 String HTMLAttachmentElement::attachmentType() const
index 03d905b..6bfe707 100644 (file)
@@ -357,14 +357,14 @@ static ReplacementPlugin* pluginReplacementForType(const URL& url, const String&
         return nullptr;
 
     String extension;
-    String lastPathComponent = url.lastPathComponent();
+    auto lastPathComponent = url.lastPathComponent();
     size_t dotOffset = lastPathComponent.reverseFind('.');
     if (dotOffset != notFound)
-        extension = lastPathComponent.substring(dotOffset + 1);
+        extension = lastPathComponent.substring(dotOffset + 1).toString();
 
     String type = mimeType;
     if (type.isEmpty() && url.protocolIsData())
-        type = mimeTypeFromDataURL(url.string());
+        type = mimeTypeFromDataURL(url);
     
     if (type.isEmpty() && !extension.isEmpty()) {
         for (auto* replacement : replacements) {
index e7a516e..5b84541 100644 (file)
@@ -98,9 +98,7 @@ MediaTime MediaFragmentURIParser::endTime()
 
 void MediaFragmentURIParser::parseFragments()
 {
-    if (!m_url.hasFragmentIdentifier())
-        return;
-    String fragmentString = m_url.fragmentIdentifier();
+    auto fragmentString = m_url.fragmentIdentifier();
     if (fragmentString.isEmpty())
         return;
 
index b70e5dc..ae340e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,8 +29,8 @@
 
 namespace WebCore {
 
-template <typename T>
-class URLUtils {
+// FIXME: Rename this to URLDecompositionFunctions.
+template<typename T> class URLUtils {
 public:
     URL href() const { return static_cast<const T*>(this)->href(); }
     void setHref(const String& url) { static_cast<T*>(this)->setHref(url); }
@@ -41,76 +41,68 @@ public:
     String origin() const;
 
     String protocol() const;
-    void setProtocol(const String&);
+    void setProtocol(StringView);
 
     String username() const;
-    void setUsername(const String&);
+    void setUsername(StringView);
 
     String password() const;
-    void setPassword(const String&);
+    void setPassword(StringView);
 
     String host() const;
-    void setHost(const String&);
+    void setHost(StringView);
 
     String hostname() const;
-    void setHostname(const String&);
+    void setHostname(StringView);
 
     String port() const;
-    void setPort(const String&);
+    void setPort(StringView);
 
     String pathname() const;
-    void setPathname(const String&);
+    void setPathname(StringView);
 
     String search() const;
     void setSearch(const String&);
 
     String hash() const;
-    void setHash(const String&);
+    void setHash(StringView);
 };
 
-template <typename T>
-String URLUtils<T>::toString() const
+template<typename T> String URLUtils<T>::toString() const
 {
     return href().string();
 }
 
-template <typename T>
-String URLUtils<T>::toJSON() const
+template<typename T> String URLUtils<T>::toJSON() const
 {
     return href().string();
 }
 
-template <typename T>
-String URLUtils<T>::origin() const
+template<typename T> String URLUtils<T>::origin() const
 {
-    auto origin = SecurityOrigin::create(href());
-    return origin->toString();
+    return SecurityOrigin::create(href())->toString();
 }
 
-template <typename T>
-String URLUtils<T>::protocol() const
+template<typename T> String URLUtils<T>::protocol() const
 {
     if (WTF::protocolIsJavaScript(href()))
         return "javascript:"_s;
     return makeString(href().protocol(), ':');
 }
 
-template <typename T>
-void URLUtils<T>::setProtocol(const String& value)
+template<typename T> void URLUtils<T>::setProtocol(StringView value)
 {
     URL url = href();
     url.setProtocol(value);
     setHref(url.string());
 }
 
-template <typename T>
-String URLUtils<T>::username() const
+template<typename T> String URLUtils<T>::username() const
 {
-    return href().encodedUser();
+    return href().encodedUser().toString();
 }
 
-template <typename T>
-void URLUtils<T>::setUsername(const String& user)
+template<typename T> void URLUtils<T>::setUsername(StringView user)
 {
     URL url = href();
     if (url.cannotBeABaseURL())
@@ -119,39 +111,36 @@ void URLUtils<T>::setUsername(const String& user)
     setHref(url);
 }
 
-template <typename T>
-String URLUtils<T>::password() const
+template<typename T> String URLUtils<T>::password() const
 {
-    return href().encodedPass();
+    return href().encodedPassword().toString();
 }
 
-template <typename T>
-void URLUtils<T>::setPassword(const String& pass)
+template<typename T> void URLUtils<T>::setPassword(StringView password)
 {
     URL url = href();
     if (url.cannotBeABaseURL())
         return;
-    url.setPass(pass);
+    url.setPassword(password);
     setHref(url);
 }
 
-template <typename T>
-String URLUtils<T>::host() const
+template<typename T> String URLUtils<T>::host() const
 {
     return href().hostAndPort();
 }
 
-// This function does not allow leading spaces before the port number.
-static inline unsigned parsePortFromStringPosition(const String& value, unsigned portStart, unsigned& portEnd)
+inline unsigned countASCIIDigits(StringView string)
 {
-    portEnd = portStart;
-    while (isASCIIDigit(value[portEnd]))
-        ++portEnd;
-    return value.substring(portStart, portEnd - portStart).toUInt();
+    unsigned length = string.length();
+    for (unsigned count = 0; count < length; ++count) {
+        if (!isASCIIDigit(string[count]))
+            return count;
+    }
+    return length;
 }
 
-template <typename T>
-void URLUtils<T>::setHost(const String& value)
+template<typename T> void URLUtils<T>::setHost(StringView value)
 {
     if (value.isEmpty())
         return;
@@ -168,40 +157,44 @@ void URLUtils<T>::setHost(const String& value)
     if (separator == notFound)
         url.setHostAndPort(value);
     else {
-        unsigned portEnd;
-        unsigned port = parsePortFromStringPosition(value, separator + 1, portEnd);
-        if (!port) {
+        unsigned portLength = countASCIIDigits(value.substring(separator + 1));
+        if (!portLength) {
             // http://dev.w3.org/html5/spec/infrastructure.html#url-decomposition-idl-attributes
             // specifically goes against RFC 3986 (p3.2) and
             // requires setting the port to "0" if it is set to empty string.
-            url.setHostAndPort(value.substring(0, separator + 1) + '0');
+            // FIXME: This seems like something that has since been changed and this rule and code may be obsolete.
+            url.setHostAndPort(makeString(value.substring(0, separator + 1), '0'));
         } else {
-            if (WTF::isDefaultPortForProtocol(port, url.protocol()))
+            auto portNumber = parseUInt16(value.substring(separator + 1, portLength));
+            if (portNumber && WTF::isDefaultPortForProtocol(*portNumber, url.protocol()))
                 url.setHostAndPort(value.substring(0, separator));
             else
-                url.setHostAndPort(value.substring(0, portEnd));
+                url.setHostAndPort(value.substring(0, separator + 1 + portLength));
         }
     }
     setHref(url.string());
 }
 
-template <typename T>
-String URLUtils<T>::hostname() const
+template<typename T> String URLUtils<T>::hostname() const
 {
     return href().host().toString();
 }
 
-template <typename T>
-void URLUtils<T>::setHostname(const String& value)
+inline StringView removeAllLeadingSolidusCharacters(StringView string)
+{
+    unsigned i;
+    unsigned length = string.length();
+    for (i = 0; i < length; ++i) {
+        if (string[i] != '/')
+            break;
+    }
+    return string.substring(i);
+}
+
+template<typename T> void URLUtils<T>::setHostname(StringView value)
 {
-    // Before setting new value:
-    // Remove all leading U+002F SOLIDUS ("/") characters.
-    unsigned i = 0;
-    unsigned hostLength = value.length();
-    while (value[i] == '/')
-        i++;
-
-    if (i == hostLength)
+    auto host = removeAllLeadingSolidusCharacters(value);
+    if (host.isEmpty())
         return;
 
     URL url = href();
@@ -210,12 +203,11 @@ void URLUtils<T>::setHostname(const String& value)
     if (!url.canSetHostOrPort())
         return;
 
-    url.setHost(value.substring(i));
+    url.setHost(host);
     setHref(url.string());
 }
 
-template <typename T>
-String URLUtils<T>::port() const
+template<typename T> String URLUtils<T>::port() const
 {
     if (href().port())
         return String::number(href().port().value());
@@ -223,33 +215,32 @@ String URLUtils<T>::port() const
     return emptyString();
 }
 
-template <typename T>
-void URLUtils<T>::setPort(const String& value)
+template<typename T> void URLUtils<T>::setPort(StringView value)
 {
     URL url = href();
-    if (url.cannotBeABaseURL() || url.protocolIs("file"))
-        return;
-    if (!url.canSetHostOrPort())
+    if (url.cannotBeABaseURL() || url.protocolIs("file") || !url.canSetHostOrPort())
         return;
 
-    bool success = true;
-    unsigned port = value.toUInt(&success);
-    if (!success || WTF::isDefaultPortForProtocol(port, url.protocol()))
-        url.removePort();
-    else
-        url.setPort(port);
+    auto digitsOnly = value.left(countASCIIDigits(value));
+    Optional<uint16_t> port;
+    if (!digitsOnly.isEmpty()) {
+        port = parseUInt16(digitsOnly);
+        if (!port)
+            return;
+        if (WTF::isDefaultPortForProtocol(*port, url.protocol()))
+            port = WTF::nullopt;
+    }
+    url.setPort(port);
 
     setHref(url.string());
 }
 
-template <typename T>
-String URLUtils<T>::pathname() const
+template<typename T> String URLUtils<T>::pathname() const
 {
     return href().path().toString();
 }
 
-template <typename T>
-void URLUtils<T>::setPathname(const String& value)
+template<typename T> void URLUtils<T>::setPathname(StringView value)
 {
     URL url = href();
     if (url.cannotBeABaseURL())
@@ -257,30 +248,27 @@ void URLUtils<T>::setPathname(const String& value)
     if (!url.canSetPathname())
         return;
 
-    if (value[0U] == '/')
+    if (value.startsWith('/'))
         url.setPath(value);
     else
-        url.setPath("/" + value);
+        url.setPath(makeString('/', value));
 
     setHref(url.string());
 }
 
-template <typename T>
-String URLUtils<T>::search() const
+template<typename T> String URLUtils<T>::search() const
 {
-    String query = href().query();
-    return query.isEmpty() ? emptyString() : "?" + query;
+    return href().query().isEmpty() ? emptyString() : href().queryWithLeadingQuestionMark().toString();
 }
 
-template <typename T>
-void URLUtils<T>::setSearch(const String& value)
+template<typename T> void URLUtils<T>::setSearch(const String& value)
 {
     URL url = href();
     if (value.isEmpty()) {
         // If the given value is the empty string, set url's query to null.
         url.setQuery({ });
     } else {
-        String newSearch = (value[0U] == '?') ? value.substring(1) : value;
+        String newSearch = value.startsWith('?') ? value.substring(1) : value;
         // Make sure that '#' in the query does not leak to the hash.
         url.setQuery(newSearch.replaceWithLiteral('#', "%23"));
     }
@@ -288,20 +276,16 @@ void URLUtils<T>::setSearch(const String& value)
     setHref(url.string());
 }
 
-template <typename T>
-String URLUtils<T>::hash() const
+template<typename T> String URLUtils<T>::hash() const
 {
-    String fragmentIdentifier = href().fragmentIdentifier();
-    if (fragmentIdentifier.isEmpty())
-        return emptyString();
-    return AtomString(String("#" + fragmentIdentifier));
+    // FIXME: Why convert this string to an atom here instead of just a string? Intentionally to save memory? An error?
+    return href().fragmentIdentifier().isEmpty() ? emptyAtom() : href().fragmentIdentifierWithLeadingNumberSign().toAtomString();
 }
 
-template <typename T>
-void URLUtils<T>::setHash(const String& value)
+template<typename T> void URLUtils<T>::setHash(StringView value)
 {
     URL url = href();
-    String newFragment = value[0U] == '#' ? value.substring(1) : value;
+    auto newFragment = value.startsWith('#') ? StringView(value).substring(1) : StringView(value);
     if (newFragment.isEmpty())
         url.removeFragmentIdentifier();
     else
index 633e775..76d4afb 100644 (file)
@@ -53,7 +53,7 @@ bool AdClickAttribution::isValid() const
 
 Expected<AdClickAttribution::Conversion, String> AdClickAttribution::parseConversionRequest(const URL& redirectURL)
 {
-    if (!redirectURL.protocolIs("https"_s) || redirectURL.hasUsername() || redirectURL.hasPassword() || redirectURL.hasQuery() || redirectURL.hasFragment()) {
+    if (!redirectURL.protocolIs("https") || redirectURL.hasCredentials() || redirectURL.hasQuery() || redirectURL.hasFragmentIdentifier()) {
         if (UNLIKELY(debugModeEnabled())) {
             RELEASE_LOG_INFO(AdClickAttribution, "Conversion was not accepted because the URL's protocol is not HTTPS or the URL contains one or more of username, password, query string, and fragment.");
             return makeUnexpected("[Ad Click Attribution] Conversion was not accepted because the URL's protocol is not HTTPS or the URL contains one or more of username, password, query string, and fragment."_s);
@@ -189,17 +189,12 @@ URL AdClickAttribution::urlForTesting(const URL& baseURL) const
     auto host = m_source.registrableDomain.string();
     if (host != "localhost" && host != "127.0.0.1")
         return URL();
-
-    StringBuilder builder;
-    builder.appendLiteral("?conversion=");
-    builder.appendNumber(m_conversion.value().data);
-    builder.appendLiteral("&campaign=");
-    builder.appendNumber(m_campaign.id);
-    if (baseURL.hasQuery()) {
-        builder.append('&');
-        builder.append(baseURL.query());
-    }
-    return URL(baseURL, builder.toString());
+    String relativeURL;
+    if (!baseURL.hasQuery())
+        relativeURL = makeString("?conversion=", m_conversion.value().data, "&campaign=", m_campaign.id);
+    else
+        relativeURL = makeString("?conversion=", m_conversion.value().data, "&campaign=", m_campaign.id, '&', baseURL.query());
+    return URL(baseURL, relativeURL);
 }
 
 void AdClickAttribution::markConversionAsSent()
index 8290628..e053c9b 100644 (file)
@@ -167,7 +167,7 @@ String validateCrossOriginRedirectionURL(const URL& redirectURL)
     if (!LegacySchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(redirectURL.protocol().toStringWithoutCopying()))
         return makeString("not allowed to follow a cross-origin CORS redirection with non CORS scheme");
 
-    if (redirectURL.hasUsername() || redirectURL.hasPassword())
+    if (redirectURL.hasCredentials())
         return makeString("redirection URL ", redirectURL.string(), " has credentials");
 
     return { };
index 2177f4b..df3d08c 100644 (file)
@@ -532,8 +532,7 @@ void DocumentThreadableLoader::loadRequest(ResourceRequest&& request, SecurityCh
     // Any credential should have been removed from the cross-site requests.
     const URL& requestURL = request.url();
     m_options.securityCheck = securityCheck;
-    ASSERT(m_sameOriginRequest || requestURL.user().isEmpty());
-    ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty());
+    ASSERT(m_sameOriginRequest || !requestURL.hasCredentials());
 
     if (!m_referrer.isNull())
         request.setHTTPReferrer(m_referrer);
index 3aaa8ee..30af900 100644 (file)
@@ -78,11 +78,11 @@ static void appendMailtoPostFormDataToURL(URL& url, const FormData& data, const
     FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8());
     body = String(bodyData.data(), bodyData.size()).replaceWithLiteral('+', "%20");
 
-    String query = url.query();
+    auto query = url.query();
     if (query.isEmpty())
         url.setQuery(body);
     else
-        url.setQuery(query + '&' + body);
+        url.setQuery(makeString(query, '&', body));
 }
 
 void FormSubmission::Attributes::parseAction(const String& action)
index 7fff826..3241705 100644 (file)
@@ -1151,9 +1151,9 @@ void FrameLoader::loadInSameDocument(const URL& url, SerializedScriptValue* stat
 
         history().updateBackForwardListForFragmentScroll();
     }
-    
-    bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
-    
+
+    bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && !equalRespectingNullity(url.fragmentIdentifier(), oldURL.fragmentIdentifier());
+
     history().updateForSameDocumentNavigation();
 
     // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
index 323db46..4882d77 100644 (file)
@@ -246,15 +246,12 @@ bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoa
 
 URL ApplicationCacheHost::createFileURL(const String& path)
 {
-    // FIXME: Can we just use fileURLWithFileSystemPath instead?
 #if USE(CF) && PLATFORM(WIN)
-    URL url(adoptCF(CFURLCreateWithFileSystemPath(0, path.createCFString().get(), kCFURLWindowsPathStyle, false)).get());
+    // FIXME: Is this correct? Seems improbable that the passed-in paths would be in the Windows path style.
+    return adoptCF(CFURLCreateWithFileSystemPath(0, path.createCFString().get(), kCFURLWindowsPathStyle, false)).get();
 #else
-    URL url;
-    url.setProtocol("file"_s);
-    url.setPath(path);
+    return URL::fileURLWithFileSystemPath(path);
 #endif
-    return url;
 }
 
 static inline RefPtr<SharedBuffer> bufferFromResource(ApplicationCacheResource& resource)
index faae51f..734da76 100644 (file)
@@ -35,13 +35,13 @@ namespace WebCore {
 
 enum Mode { Explicit, Fallback, OnlineWhitelist, Unknown };
 
-static String manifestPath(const URL& manifestURL)
+static StringView manifestPath(const URL& manifestURL)
 {
     auto manifestPath = manifestURL.path();
     ASSERT(manifestPath[0] == '/');
     manifestPath = manifestPath.substring(0, manifestPath.reverseFind('/') + 1);
     ASSERT(manifestPath[0] == manifestPath[manifestPath.length() - 1]);
-    return manifestPath.toString();
+    return manifestPath;
 }
 
 bool parseManifest(const URL& manifestURL, const String& manifestMIMEType, const char* data, int length, Manifest& manifest)
@@ -51,7 +51,7 @@ bool parseManifest(const URL& manifestURL, const String& manifestMIMEType, const
     ASSERT(manifest.fallbackURLs.isEmpty());
     manifest.allowAllNetworkRequests = false;
 
-    String manifestPath = WebCore::manifestPath(manifestURL);
+    auto manifestPath = WebCore::manifestPath(manifestURL);
 
     const char cacheManifestMIMEType[] = "text/cache-manifest";
     bool allowFallbackNamespaceOutsideManfestPath = equalLettersIgnoringASCIICase(manifestMIMEType, cacheManifestMIMEType);
index 3f4699c..cd949e7 100644 (file)
@@ -86,10 +86,7 @@ bool CachedFont::ensureCustomFontData(const AtomString&)
 
 String CachedFont::calculateItemInCollection() const
 {
-    auto& url = this->url();
-    if (!url.hasFragmentIdentifier())
-        return String();
-    return url.fragmentIdentifier();
+    return url().fragmentIdentifier().toString();
 }
 
 bool CachedFont::ensureCustomFontData(SharedBuffer* data)
index 6a28a85..e4a94a5 100644 (file)
@@ -55,7 +55,7 @@ String CachedResourceRequest::splitFragmentIdentifierFromRequestURL(ResourceRequ
     if (!MemoryCache::shouldRemoveFragmentIdentifier(request.url()))
         return { };
     URL url = request.url();
-    String fragmentIdentifier = url.fragmentIdentifier();
+    auto fragmentIdentifier = url.fragmentIdentifier().toString();
     url.removeFragmentIdentifier();
     request.setURL(url);
     return fragmentIdentifier;
index d90089c..ee5e53a 100644 (file)
@@ -2179,8 +2179,8 @@ void FrameView::restoreScrollbar()
 
 bool FrameView::scrollToFragment(const URL& url)
 {
-    String fragmentIdentifier = url.fragmentIdentifier();
-    if (scrollToFragmentInternal(fragmentIdentifier))
+    auto fragmentIdentifier = url.fragmentIdentifier();
+    if (scrollToFragmentInternal(fragmentIdentifier.toString()))
         return true;
 
     // Try again after decoding the ref, based on the document's encoding.
@@ -2195,7 +2195,7 @@ bool FrameView::scrollToFragment(const URL& url)
 
 bool FrameView::scrollToFragmentInternal(const String& fragmentIdentifier)
 {
-    LOG(Scrolling, "FrameView::scrollToAnchor %s", fragmentIdentifier.utf8().data());
+    LOG(Scrolling, "FrameView::scrollToFragmentInternal %s", fragmentIdentifier.utf8().data());
 
     // If our URL has no ref, then we have no place we need to jump to.
     if (fragmentIdentifier.isNull())
index 9c58b06..38fd7b2 100644 (file)
@@ -201,13 +201,14 @@ ExceptionOr<void> History::stateObjectAdded(RefPtr<SerializedScriptValue>&& data
         const char* functionName = stateObjectType == StateObjectType::Replace ? "history.replaceState()" : "history.pushState()";
         return Exception { SecurityError, makeString("Blocked attempt to use ", functionName, " to change session history URL from ", documentURL.stringCenterEllipsizedToLength(), " to ", fullURL.stringCenterEllipsizedToLength(), ". ", suffix) };
     };
-    if (!protocolHostAndPortAreEqual(fullURL, documentURL) || fullURL.user() != documentURL.user() || fullURL.pass() != documentURL.pass())
+    if (!protocolHostAndPortAreEqual(fullURL, documentURL) || fullURL.user() != documentURL.user() || fullURL.password() != documentURL.password())
         return createBlockedURLSecurityErrorWithMessageSuffix("Protocols, domains, ports, usernames, and passwords must match.");
 
     const auto& documentSecurityOrigin = frame->document()->securityOrigin();
     // We allow sandboxed documents, 'data:'/'file:' URLs, etc. to use 'pushState'/'replaceState' to modify the URL query and fragments.
     // See https://bugs.webkit.org/show_bug.cgi?id=183028 for the compatibility concerns.
-    bool allowSandboxException = (documentSecurityOrigin.isLocal() || documentSecurityOrigin.isUnique()) && equalIgnoringQueryAndFragment(documentURL, fullURL);
+    bool allowSandboxException = (documentSecurityOrigin.isLocal() || documentSecurityOrigin.isUnique())
+        && documentURL.stringWithoutQueryOrFragmentIdentifier() == fullURL.stringWithoutQueryOrFragmentIdentifier();
 
     if (!allowSandboxException && !documentSecurityOrigin.canRequest(fullURL) && (fullURL.path() != documentURL.path() || fullURL.query() != documentURL.query()))
         return createBlockedURLSecurityErrorWithMessageSuffix("Paths and fragments must match for a sandboxed document.");
index 28789cd..36c1c9b 100644 (file)
@@ -61,14 +61,8 @@ inline const URL& Location::url() const
 
 String Location::href() const
 {
-    auto& url = this->url();
-
-    if (!url.hasUsername() && !url.hasPassword())
-        return url.string();
-
-    URL urlWithoutCredentials(url);
-    urlWithoutCredentials.setUser(WTF::emptyString());
-    urlWithoutCredentials.setPass(WTF::emptyString());
+    URL urlWithoutCredentials(url());
+    urlWithoutCredentials.removeCredentials();
     return urlWithoutCredentials.string();
 }
 
@@ -91,20 +85,19 @@ String Location::hostname() const
 
 String Location::port() const
 {
-    const URL& url = this->url();
-    return url.port() ? String::number(url.port().value()) : emptyString();
+    auto port = url().port();
+    return port ? String::number(*port) : emptyString();
 }
 
 String Location::pathname() const
 {
     auto path = url().path();
-    return path.isEmpty() ? "/" : path.toString();
+    return path.isEmpty() ? "/"_s : path.toString();
 }
 
 String Location::search() const
 {
-    const URL& url = this->url();
-    return url.query().isEmpty() ? emptyString() : "?" + url.query();
+    return url().query().isEmpty() ? emptyString() : url().queryWithLeadingQuestionMark().toString();
 }
 
 String Location::origin() const
@@ -125,8 +118,7 @@ Ref<DOMStringList> Location::ancestorOrigins() const
 
 String Location::hash() const
 {
-    const String& fragmentIdentifier = url().fragmentIdentifier();
-    return fragmentIdentifier.isEmpty() ? emptyString() : "#" + fragmentIdentifier;
+    return url().fragmentIdentifier().isEmpty() ? emptyString() : url().fragmentIdentifierWithLeadingNumberSign().toString();
 }
 
 ExceptionOr<void> Location::setHref(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& url)
@@ -144,7 +136,7 @@ ExceptionOr<void> Location::setProtocol(DOMWindow& activeWindow, DOMWindow& firs
     URL url = frame->document()->url();
     if (!url.setProtocol(protocol))
         return Exception { SyntaxError };
-    return setLocation(activeWindow, firstWindow, url.string());
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::setHost(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& host)
@@ -154,7 +146,7 @@ ExceptionOr<void> Location::setHost(DOMWindow& activeWindow, DOMWindow& firstWin
         return { };
     URL url = frame->document()->url();
     url.setHostAndPort(host);
-    return setLocation(activeWindow, firstWindow, url.string());
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::setHostname(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& hostname)
@@ -164,7 +156,7 @@ ExceptionOr<void> Location::setHostname(DOMWindow& activeWindow, DOMWindow& firs
         return { };
     URL url = frame->document()->url();
     url.setHost(hostname);
-    return setLocation(activeWindow, firstWindow, url.string());
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::setPort(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& portString)
@@ -173,12 +165,8 @@ ExceptionOr<void> Location::setPort(DOMWindow& activeWindow, DOMWindow& firstWin
     if (!frame)
         return { };
     URL url = frame->document()->url();
-    int port = portString.toInt();
-    if (port < 0 || port > 0xFFFF || portString.isEmpty())
-        url.removePort();
-    else
-        url.setPort(port);
-    return setLocation(activeWindow, firstWindow, url.string());
+    url.setPort(parseUInt16(portString));
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::setPathname(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& pathname)
@@ -188,7 +176,7 @@ ExceptionOr<void> Location::setPathname(DOMWindow& activeWindow, DOMWindow& firs
         return { };
     URL url = frame->document()->url();
     url.setPath(pathname);
-    return setLocation(activeWindow, firstWindow, url.string());
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::setSearch(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& search)
@@ -198,7 +186,7 @@ ExceptionOr<void> Location::setSearch(DOMWindow& activeWindow, DOMWindow& firstW
         return { };
     URL url = frame->document()->url();
     url.setQuery(search);
-    return setLocation(activeWindow, firstWindow, url.string());
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::setHash(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& hash)
@@ -218,7 +206,7 @@ ExceptionOr<void> Location::setHash(DOMWindow& activeWindow, DOMWindow& firstWin
     // cases where fragment identifiers are ignored or invalid. 
     if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
         return { };
-    return setLocation(activeWindow, firstWindow, url.string());
+    return setLocation(activeWindow, firstWindow, url);
 }
 
 ExceptionOr<void> Location::assign(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& url)
index ace5b7e..2d51469 100644 (file)
@@ -147,22 +147,19 @@ bool UserContentURLPattern::matchesHost(const URL& test) const
     return host[host.length() - m_host.length() - 1] == '.';
 }
 
-struct MatchTester
-{
+struct MatchTester {
     StringView m_pattern;
-    unsigned m_patternIndex;
-    
+    unsigned m_patternIndex { 0 };
+
     StringView m_test;
-    unsigned m_testIndex;
-    
+    unsigned m_testIndex { 0 };
+
     MatchTester(StringView pattern, StringView test)
-    : m_pattern(pattern)
-    , m_patternIndex(0)
-    , m_test(test)
-    , m_testIndex(0)
+        : m_pattern(pattern)
+        , m_test(test)
     {
     }
-    
+
     bool testStringFinished() const { return m_testIndex >= m_test.length(); }
     bool patternStringFinished() const { return m_patternIndex >= m_pattern.length(); }
 
@@ -174,7 +171,7 @@ struct MatchTester
             m_patternIndex++;
         }
     }
-    
+
     void eatSameChars()
     {
         while (!patternStringFinished() && !testStringFinished()) {
@@ -226,8 +223,7 @@ struct MatchTester
 
 bool UserContentURLPattern::matchesPath(const URL& test) const
 {
-    MatchTester match(StringView(m_path), test.path());
-    return match.test();
+    return MatchTester(m_path, test.path()).test();
 }
 
 } // namespace WebCore
index 4a0c34e..470fe54 100644 (file)
@@ -790,16 +790,10 @@ String MIMETypeRegistry::getNormalizedMIMEType(const String& mimeType)
 
 String MIMETypeRegistry::appendFileExtensionIfNecessary(const String& filename, const String& mimeType)
 {
-    if (filename.isEmpty())
-        return emptyString();
-
-    if (equalIgnoringASCIICase(mimeType, defaultMIMEType()))
-        return filename;
-
-    if (filename.reverseFind('.') != notFound)
+    if (filename.isEmpty() || filename.contains('.') || equalIgnoringASCIICase(mimeType, defaultMIMEType()))
         return filename;
 
-    String preferredExtension = getPreferredExtensionForMIMEType(mimeType);
+    auto preferredExtension = getPreferredExtensionForMIMEType(mimeType);
     if (preferredExtension.isEmpty())
         return filename;
 
index ab7e605..c828bbe 100644 (file)
@@ -441,12 +441,12 @@ bool MediaPlayer::load(const URL& url, const ContentType& contentType, const Str
     AtomString containerType = m_contentType.containerType();
     if (containerType.isEmpty() || containerType == applicationOctetStream() || containerType == textPlain()) {
         if (m_url.protocolIsData())
-            m_contentType = ContentType(mimeTypeFromDataURL(m_url.string()));
+            m_contentType = ContentType(mimeTypeFromDataURL(m_url));
         else {
-            String lastPathComponent = url.lastPathComponent();
+            auto lastPathComponent = url.lastPathComponent();
             size_t pos = lastPathComponent.reverseFind('.');
             if (pos != notFound) {
-                String extension = lastPathComponent.substring(pos + 1);
+                String extension = lastPathComponent.substring(pos + 1).toString();
                 String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(extension);
                 if (!mediaType.isEmpty()) {
                     m_contentType = ContentType { WTFMove(mediaType) };
index 6162ada..2ec975c 100644 (file)
@@ -172,7 +172,7 @@ static void convertToInternalProtocol(URL& url)
     if (webkitGstCheckVersion(1, 12, 0))
         return;
     if (url.protocolIsInHTTPFamily() || url.protocolIsBlob())
-        url.setProtocol("webkit+" + url.protocol());
+        url.setProtocol(makeString("webkit+", url.protocol()));
 }
 
 #if USE(TEXTURE_MAPPER_GL)
index 728fa2e..d3b3382 100644 (file)
@@ -80,7 +80,7 @@ public:
     {
         const URL& url = m_firstRequest.url();
         m_user = url.user();
-        m_pass = url.pass();
+        m_password = url.password();
         m_firstRequest.removeCredentials();
     }
     
@@ -96,7 +96,7 @@ public:
 
     // Suggested credentials for the current redirection step.
     String m_user;
-    String m_pass;
+    String m_password;
     
     Credential m_initialCredential;
     
index a937320..530eccf 100644 (file)
@@ -165,12 +165,10 @@ void ResourceRequestBase::removeCredentials()
 {
     updateResourceRequest(); 
 
-    if (m_url.user().isEmpty() && m_url.pass().isEmpty())
+    if (!m_url.hasCredentials())
         return;
 
-    m_url.setUser(String());
-    m_url.setPass(String());
-
+    m_url.removeCredentials();
     m_platformRequestUpdated = false;
 }
 
index 90081cb..3ecf71e 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 #include "config.h"
-
 #include "ResourceHandleInternal.h"
 
 #include "AuthenticationCF.h"
@@ -59,7 +58,6 @@
 #if PLATFORM(WIN)
 #include <process.h>
 
-// FIXME: Remove this declaration once it's in WebKitSupportLibrary.
 extern "C" {
 __declspec(dllimport) CFURLConnectionRef CFURLConnectionCreateWithProperties(
   CFAllocatorRef           alloc,
@@ -133,11 +131,11 @@ static void setClientCertificateInSSLProperties(CFMutableDictionaryRef sslProps,
 
 void ResourceHandle::createCFURLConnection(bool shouldUseCredentialStorage, bool shouldContentSniff, bool shouldContentEncodingSniff, RefPtr<SynchronousLoaderMessageQueue>&& messageQueue, CFDictionaryRef clientProperties)
 {
-    if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !firstRequest().url().protocolIsInHTTPFamily()) {
+    if ((!d->m_user.isEmpty() || !d->m_password.isEmpty()) && !firstRequest().url().protocolIsInHTTPFamily()) {
         // Credentials for ftp can only be passed in URL, the didReceiveAuthenticationChallenge delegate call won't be made.
         URL urlWithCredentials(firstRequest().url());
         urlWithCredentials.setUser(d->m_user);
-        urlWithCredentials.setPass(d->m_pass);
+        urlWithCredentials.setPassword(d->m_password);
         firstRequest().setURL(urlWithCredentials);
     }
 
@@ -146,7 +144,7 @@ void ResourceHandle::createCFURLConnection(bool shouldUseCredentialStorage, bool
     // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication,
     // try and reuse the credential preemptively, as allowed by RFC 2617.
     if (shouldUseCredentialStorage && firstRequest().url().protocolIsInHTTPFamily()) {
-        if (d->m_user.isEmpty() && d->m_pass.isEmpty()) {
+        if (d->m_user.isEmpty() && d->m_password.isEmpty()) {
             // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 
             // try and reuse the credential preemptively, as allowed by RFC 2617.
             d->m_initialCredential = d->m_context->storageSession()->credentialStorage().get(partition, firstRequest().url());
@@ -154,7 +152,7 @@ void ResourceHandle::createCFURLConnection(bool shouldUseCredentialStorage, bool
             // If there is already a protection space known for the URL, update stored credentials before sending a request.
             // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately
             // (so that an authentication dialog doesn't pop up).
-            d->m_context->storageSession()->credentialStorage().set(partition, Credential(d->m_user, d->m_pass, CredentialPersistenceNone), firstRequest().url());
+            d->m_context->storageSession()->credentialStorage().set(partition, Credential(d->m_user, d->m_password, CredentialPersistenceNone), firstRequest().url());
         }
     }
         
@@ -292,7 +290,7 @@ void ResourceHandle::willSendRequest(ResourceRequest&& request, ResourceResponse
 {
     const URL& url = request.url();
     d->m_user = url.user();
-    d->m_pass = url.pass();
+    d->m_password = url.password();
     d->m_lastHTTPMethod = request.httpMethod();
     request.removeCredentials();
 
@@ -306,7 +304,7 @@ void ResourceHandle::willSendRequest(ResourceRequest&& request, ResourceResponse
     } else {
         // Only consider applying authentication credentials if this is actually a redirect and the redirect
         // URL didn't include credentials of its own.
-        if (d->m_user.isEmpty() && d->m_pass.isEmpty() && !redirectResponse.isNull()) {
+        if (d->m_user.isEmpty() && d->m_password.isEmpty() && !redirectResponse.isNull()) {
             Credential credential = d->m_context->storageSession()->credentialStorage().get(partition, request.url());
             if (!credential.isEmpty()) {
                 d->m_initialCredential = credential;
@@ -371,8 +369,8 @@ bool ResourceHandle::tryHandlePasswordBasedAuthentication(const AuthenticationCh
 
     String partition = firstRequest().cachePartition();
 
-    if (!d->m_user.isNull() && !d->m_pass.isNull()) {
-        RetainPtr<CFURLCredentialRef> cfCredential = adoptCF(CFURLCredentialCreate(kCFAllocatorDefault, d->m_user.createCFString().get(), d->m_pass.createCFString().get(), 0, kCFURLCredentialPersistenceNone));
+    if (!d->m_user.isNull() && !d->m_password.isNull()) {
+        auto cfCredential = adoptCF(CFURLCredentialCreate(kCFAllocatorDefault, d->m_user.createCFString().get(), d->m_password.createCFString().get(), 0, kCFURLCredentialPersistenceNone));
 #if PLATFORM(COCOA)
         Credential credential = Credential(cfCredential.get());
 #else
@@ -386,7 +384,7 @@ bool ResourceHandle::tryHandlePasswordBasedAuthentication(const AuthenticationCh
         
         CFURLConnectionUseCredential(d->m_connection.get(), cfCredential.get(), challenge.cfURLAuthChallengeRef());
         d->m_user = String();
-        d->m_pass = String();
+        d->m_password = String();
         // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
         return true;
     }
index 0c2d3f0..1837db4 100644 (file)
 #endif
 
 #include <curl/curl.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 namespace WebCore {
 
-static const uint16_t SocksProxyPort = 1080;
+static constexpr uint16_t SocksProxyPort = 1080;
 
-static Optional<uint16_t> getProxyPort(const URL&);
 static Optional<String> createProxyUrl(const URL&);
 
 CurlProxySettings::CurlProxySettings(URL&& proxyUrl, String&& ignoreHosts)
@@ -61,7 +61,7 @@ void CurlProxySettings::rebuildUrl()
 void CurlProxySettings::setUserPass(const String& user, const String& password)
 {
     m_url.setUser(user);
-    m_url.setPass(password);
+    m_url.setPassword(password);
 
     rebuildUrl();
 }
@@ -118,8 +118,8 @@ static Optional<String> createProxyUrl(const URL &url)
     if (!port)
         return WTF::nullopt;
 
-    auto userpass = (url.hasUsername() || url.hasPassword()) ? makeString(url.user(), ":", url.pass(), "@") : String();
-    return makeString(url.protocol(), "://", userpass, url.host(), ":", String::number(*port));
+    auto userpass = url.hasCredentials() ? makeString(url.user(), ":", url.password(), "@") : String();
+    return makeString(url.protocol(), "://", userpass, url.host(), ":", *port);
 }
 
 }
index af31354..583e00c 100644 (file)
@@ -56,7 +56,7 @@ public:
 
     WEBCORE_EXPORT void setUserPass(const String&, const String&);
     const String user() const { return m_url.user(); }
-    const String password() const { return m_url.pass(); }
+    const String password() const { return m_url.password(); }
 
     void setDefaultAuthMethod() { m_authMethod = kCURLAUTH_ANY; }
     void setAuthMethod(long);
index 4915d90..40c798a 100644 (file)
@@ -214,8 +214,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
 
     String partition = firstRequest().cachePartition();
 
-    if (!d->m_user.isNull() && !d->m_pass.isNull()) {
-        Credential credential(d->m_user, d->m_pass, CredentialPersistenceNone);
+    if (!d->m_user.isNull() && !d->m_password.isNull()) {
+        Credential credential(d->m_user, d->m_password, CredentialPersistenceNone);
 
         URL urlToStore;
         if (challenge.failureResponse().httpStatusCode() == 401)
@@ -225,7 +225,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
         restartRequestWithCredential(challenge.protectionSpace(), credential);
 
         d->m_user = String();
-        d->m_pass = String();
+        d->m_password = String();
         // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
         return;
     }
@@ -327,7 +327,7 @@ void ResourceHandle::receivedChallengeRejection(const AuthenticationChallenge&)
 Optional<Credential> ResourceHandle::getCredential(const ResourceRequest& request, bool redirect)
 {
     // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
-    Credential credential { d->m_user, d->m_pass, CredentialPersistenceNone };
+    Credential credential { d->m_user, d->m_password, CredentialPersistenceNone };
 
     if (shouldUseCredentialStorage()) {
         String partition = request.cachePartition();
@@ -476,7 +476,7 @@ void ResourceHandle::willSendRequest()
         newRequest.clearHTTPReferrer();
 
     d->m_user = newURL.user();
-    d->m_pass = newURL.pass();
+    d->m_password = newURL.password();
     newRequest.removeCredentials();
 
     if (crossOrigin) {
index 767c579..ee603d7 100644 (file)
@@ -142,15 +142,15 @@ void ResourceHandle::createNSURLConnection(id delegate, bool shouldUseCredential
 #endif
 {
     // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made.
-    if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !firstRequest().url().protocolIsInHTTPFamily()) {
+    if ((!d->m_user.isEmpty() || !d->m_password.isEmpty()) && !firstRequest().url().protocolIsInHTTPFamily()) {
         URL urlWithCredentials(firstRequest().url());
         urlWithCredentials.setUser(d->m_user);
-        urlWithCredentials.setPass(d->m_pass);
+        urlWithCredentials.setPassword(d->m_password);
         firstRequest().setURL(urlWithCredentials);
     }
 
     if (shouldUseCredentialStorage && firstRequest().url().protocolIsInHTTPFamily()) {
-        if (d->m_user.isEmpty() && d->m_pass.isEmpty()) {
+        if (d->m_user.isEmpty() && d->m_password.isEmpty()) {
             // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 
             // try and reuse the credential preemptively, as allowed by RFC 2617.
             if (auto* networkStorageSession = d->m_context->storageSession())
@@ -160,7 +160,7 @@ void ResourceHandle::createNSURLConnection(id delegate, bool shouldUseCredential
             // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately
             // (so that an authentication dialog doesn't pop up).
             if (auto* networkStorageSession = d->m_context->storageSession())
-                networkStorageSession->credentialStorage().set(firstRequest().cachePartition(), Credential(d->m_user, d->m_pass, CredentialPersistenceNone), firstRequest().url());
+                networkStorageSession->credentialStorage().set(firstRequest().cachePartition(), Credential(d->m_user, d->m_password, CredentialPersistenceNone), firstRequest().url());
         }
     }
         
@@ -435,7 +435,7 @@ void ResourceHandle::willSendRequest(ResourceRequest&& request, ResourceResponse
 
     const URL& url = request.url();
     d->m_user = url.user();
-    d->m_pass = url.pass();
+    d->m_password = url.password();
     d->m_lastHTTPMethod = request.httpMethod();
     request.removeCredentials();
 
@@ -447,7 +447,7 @@ void ResourceHandle::willSendRequest(ResourceRequest&& request, ResourceResponse
     } else {
         // Only consider applying authentication credentials if this is actually a redirect and the redirect
         // URL didn't include credentials of its own.
-        if (d->m_user.isEmpty() && d->m_pass.isEmpty() && !redirectResponse.isNull()) {
+        if (d->m_user.isEmpty() && d->m_password.isEmpty() && !redirectResponse.isNull()) {
             Credential credential;
             if (auto* networkStorageSession = d->m_context->storageSession())
                 credential = networkStorageSession->credentialStorage().get(request.cachePartition(), request.url());
@@ -521,17 +521,15 @@ bool ResourceHandle::tryHandlePasswordBasedAuthentication(const AuthenticationCh
     if (!challenge.protectionSpace().isPasswordBased())
         return false;
 
-    if (!d->m_user.isNull() && !d->m_pass.isNull()) {
-        NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:d->m_user
-                                                                   password:d->m_pass
-                                                                persistence:NSURLCredentialPersistenceForSession];
+    if (!d->m_user.isNull() && !d->m_password.isNull()) {
+        auto credential = adoptNS([[NSURLCredential alloc] initWithUser:d->m_user
+            password:d->m_password persistence:NSURLCredentialPersistenceForSession]);
         d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
         d->m_currentWebChallenge = challenge;
-        receivedCredential(challenge, Credential(credential));
-        [credential release];
+        receivedCredential(challenge, Credential(credential.get()));
         // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
         d->m_user = String();
-        d->m_pass = String();
+        d->m_password = String();
         return true;
     }
 
index d828db7..3f2d36c 100644 (file)
@@ -241,7 +241,7 @@ GUniquePtr<SoupURI> ResourceRequest::createSoupURI() const
     // when both the username and password are non-null. When we have credentials, empty usernames and passwords
     // should be empty strings instead of null.
     String urlUser = m_url.user();
-    String urlPass = m_url.pass();
+    String urlPass = m_url.password();
     if (!urlUser.isEmpty() || !urlPass.isEmpty()) {
         soup_uri_set_user(soupURI.get(), urlUser.utf8().data());
         soup_uri_set_password(soupURI.get(), urlPass.utf8().data());
index f51c4fd..e85bf40 100644 (file)
@@ -44,7 +44,7 @@ URL soupURIToURL(SoupURI* soupURI)
         // built. Fixing soup_uri_to_string is a no-no as the maintainer does
         // not want to break compatibility with previous implementations
         if (soupURI->password)
-            url.setPass(String::fromUTF8(soupURI->password));
+            url.setPassword(String::fromUTF8(soupURI->password));
     }
 
     return url;
index 28d873c..7183f90 100644 (file)
@@ -370,7 +370,7 @@ static bool writeURL(WCDataObject *data, const URL& url, String title, bool with
         return false;
 
     if (title.isEmpty()) {
-        title = url.lastPathComponent();
+        title = url.lastPathComponent().toString();
         if (title.isEmpty())
             title = url.host().toString();
     }
@@ -579,10 +579,10 @@ static String filesystemPathFromUrlOrTitle(const String& url, const String& titl
         // the path. If we can't find it, or we're coming up with the name for a link
         // we just use the entire url.
         DWORD len = fsPathMaxLengthExcludingExtension;
-        String lastComponent = kurl.lastPathComponent();
+        auto lastComponent = kurl.lastPathComponent();
         if (kurl.isLocalFile() || (!isLink && !lastComponent.isEmpty())) {
             len = std::min<DWORD>(fsPathMaxLengthExcludingExtension, lastComponent.length());
-            StringView(lastComponent).substring(0, len).getCharactersWithUpconvert(fsPathBuffer);
+            lastComponent.substring(0, len).getCharactersWithUpconvert(fsPathBuffer);
         } else {
             len = std::min<DWORD>(fsPathMaxLengthExcludingExtension, url.length());
             StringView(url).substring(0, len).getCharactersWithUpconvert(fsPathBuffer);
@@ -708,7 +708,7 @@ void Pasteboard::write(const PasteboardURL& pasteboardURL)
 
     String title(pasteboardURL.title);
     if (title.isEmpty()) {
-        title = pasteboardURL.url.lastPathComponent();
+        title = pasteboardURL.url.lastPathComponent().toString();
         if (title.isEmpty())
             title = pasteboardURL.url.host().toString();
     }
index 2c6c70e..b15a4e9 100644 (file)
@@ -165,17 +165,14 @@ bool BuilderState::createFilterOperations(const CSSValue& inValue, FilterOperati
 
     FilterOperations operations;
     for (auto& currentValue : downcast<CSSValueList>(inValue)) {
-
         if (is<CSSPrimitiveValue>(currentValue)) {
             auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
             if (!primitiveValue.isURI())
                 continue;
 
-            String cssUrl = primitiveValue.stringValue();
-            URL url = document().completeURL(cssUrl);
-
-            auto operation = ReferenceFilterOperation::create(cssUrl, url.fragmentIdentifier());
-            operations.operations().append(WTFMove(operation));
+            auto filterURL = primitiveValue.stringValue();
+            auto fragment = document().completeURL(filterURL).fragmentIdentifier().toString();
+            operations.operations().append(ReferenceFilterOperation::create(filterURL, fragment));
             continue;
         }
 
index d79e800..83476fe 100644 (file)
@@ -53,23 +53,24 @@ String WorkerLocation::hostname() const
 
 String WorkerLocation::port() const
 {
-    return m_url.port() ? String::number(m_url.port().value()) : emptyString();
+    auto port = m_url.port();
+    return port ? String::number(*port) : emptyString();
 }
 
 String WorkerLocation::pathname() const
 {
     auto path = m_url.path();
-    return path.isEmpty() ? "/" : path.toString();
+    return path.isEmpty() ? "/"_s : path.toString();
 }
 
 String WorkerLocation::search() const
 {
-    return m_url.query().isEmpty() ? emptyString() : "?" + m_url.query();
+    return m_url.query().isEmpty() ? emptyString() : m_url.queryWithLeadingQuestionMark().toString();
 }
 
 String WorkerLocation::hash() const
 {
-    return m_url.fragmentIdentifier().isEmpty() ? emptyString() : "#" + m_url.fragmentIdentifier();
+    return m_url.fragmentIdentifier().isEmpty() ? emptyString() : m_url.fragmentIdentifierWithLeadingNumberSign().toString();
 }
 
 String WorkerLocation::origin() const
index 0d53bcf..1896c24 100644 (file)
@@ -37,7 +37,7 @@ ServiceWorkerRegistrationKey::ServiceWorkerRegistrationKey(SecurityOriginData&&
     : m_topOrigin(WTFMove(topOrigin))
     , m_scope(WTFMove(scope))
 {
-    ASSERT(!m_scope.hasFragment());
+    ASSERT(!m_scope.hasFragmentIdentifier());
 }
 
 ServiceWorkerRegistrationKey ServiceWorkerRegistrationKey::emptyKey()
index 7386254..ba74f6d 100644 (file)
 
 namespace WebCore {
 
-URL static inline topOriginURL(const SecurityOrigin& origin)
+static URL topOriginURL(const SecurityOrigin& origin)
 {
     URL url;
     url.setProtocol(origin.protocol());
     url.setHost(origin.host());
-    if (origin.port())
-        url.setPort(*origin.port());
+    url.setPort(origin.port());
     return url;
 }
 
index bfc1572..dbb595b 100644 (file)
@@ -427,8 +427,7 @@ URL static inline originURL(const SecurityOrigin& origin)
     URL url;
     url.setProtocol(origin.protocol());
     url.setHost(origin.host());
-    if (origin.port())
-        url.setPort(*origin.port());
+    url.setPort(*origin.port());
     return url;
 }
 
index 1528155..a0de49f 100644 (file)
@@ -402,7 +402,7 @@ ExceptionOr<void> XMLHttpRequest::open(const String& method, const String& url,
     if (!user.isNull())
         urlWithCredentials.setUser(user);
     if (!password.isNull())
-        urlWithCredentials.setPass(password);
+        urlWithCredentials.setPassword(password);
 
     return open(method, urlWithCredentials, async);
 }
index 9891994..6734314 100644 (file)
@@ -1,3 +1,87 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * NetworkProcess/NetworkLoadChecker.cpp:
+        (WebKit::NetworkLoadChecker::checkRedirection): Use hasCredentials.
+        (WebKit::NetworkLoadChecker::applyHTTPSUpgradeIfNeeded const):
+        Remove use of ASCIILiteral for setProtocol.
+
+        * NetworkProcess/curl/NetworkDataTaskCurl.cpp:
+        (WebKit::NetworkDataTaskCurl::NetworkDataTaskCurl): Updated for
+        password name change.
+        (WebKit::NetworkDataTaskCurl::willPerformHTTPRedirection): Ditto.
+
+        * NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
+        (WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa): Updated
+        for password name change.
+        (WebKit::NetworkDataTaskCocoa::willPerformHTTPRedirection): Ditto.
+
+        * NetworkProcess/soup/NetworkDataTaskSoup.cpp:
+        (WebKit::NetworkDataTaskSoup::NetworkDataTaskSoup): Updated for
+        password name change.
+        (WebKit::NetworkDataTaskSoup::applyAuthenticationToRequest): Ditto.
+        (WebKit::NetworkDataTaskSoup::continueHTTPRedirection): Ditto.
+        (WebKit::NetworkDataTaskSoup::shouldAllowHSTSPolicySetting const):
+        Use != to compare hosts, rather than hostsAreEqual.
+        (WebKit::NetworkDataTaskSoup::shouldAllowHSTSProtocolUpgrade const):
+        Refactored to use || to match the function above.
+
+        * Shared/API/APIURL.h:
+        (API::URL::host const): Removed validity check; WTF::URL::host
+        returns null if the URL is invalid.
+        (API::URL::protocol const): Ditto.
+        (API::URL::path const): Ditto.
+        (API::URL::lastPathComponent const): Ditto. Also added toString
+        since WTF::URL::lastPathComponent now returns a StringView.
+
+        * UIProcess/Cocoa/DownloadClient.mm:
+        (WebKit::DownloadClient::didFinish): Use hasFragmentIdentifier.
+
+        * UIProcess/DeviceIdHashSaltStorage.cpp:
+        (WebKit::DeviceIdHashSaltStorage::loadStorageFromDisk):
+        Refactored a bit and use fileURLWithFileSystemPath and
+        updated since lastPathComponent returns a StringView.
+
+        * UIProcess/Plugins/PluginInfoStore.cpp:
+        (WebKit::pathExtension): Updated since lastPathComponent
+        returns a StringView. Refactored a little.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::maybeInitializeSandboxExtensionHandle):
+        Use truncatedForUseAsBase.
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+        Use != to compare hosts, rather than hostsAreEqual.
+        (WebKit::WebPageProxy::decidePolicyForNewWindowAction): Ditto.
+        (WebKit::WebPageProxy::createNewPage): Ditto.
+
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::assumeReadAccessToBaseURL):
+        Use truncatedForUseAsBase.
+
+        * UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:
+        (WebKit::WebsiteDataStore::initializeAppBoundDomains):
+        Don't use ASCIILiteral for argument to setProtocol.
+
+        * WebProcess/MediaCache/WebMediaKeyStorageManager.cpp:
+        (WebKit::WebMediaKeyStorageManager::getMediaKeyOrigins):
+        Use fileURLWithFileSystemPath, also refactored a bit.
+
+        * WebProcess/Plugins/PDF/PDFPlugin.mm:
+        (WebKit::PDFPlugin::installPDFDocument): Updated since
+        fragmentIdentifier returns a StringView.
+
+        * WebProcess/WebCoreSupport/WebContextMenuClient.cpp:
+        (WebKit::WebContextMenuClient::searchWithGoogle): Streamlined
+        the implementation a bit.
+
+        * WebProcess/WebCoreSupport/mac/WebDragClientMac.mm:
+        (WebKit::WebDragClient::declareAndWriteDragImage):
+        Updated since lastPathComponent returns a StringView.
+
 2020-04-25  David Kilzer  <ddkilzer@apple.com>
 
         IPC::Decoder::isInvalid() should be renamed to isValid()
index 9e0b682..955d388 100644 (file)
@@ -133,7 +133,7 @@ void NetworkLoadChecker::checkRedirection(ResourceRequest&& request, ResourceReq
             handler(redirectionError(redirectResponse, makeString("Cross-origin redirection to ", redirectRequest.url().string(), " denied by Cross-Origin Resource Sharing policy: not allowed to follow a cross-origin CORS redirection with non CORS scheme")));
             return;
         }
-        if (location.hasUsername() || location.hasPassword()) {
+        if (location.hasCredentials()) {
             handler(redirectionError(redirectResponse, makeString("Cross-origin redirection to ", redirectRequest.url().string(), " denied by Cross-Origin Resource Sharing policy: redirection URL ", location.string(), " has credentials")));
             return;
         }
@@ -235,7 +235,7 @@ void NetworkLoadChecker::applyHTTPSUpgradeIfNeeded(ResourceRequest&& request, Co
     httpsUpgradeChecker.query(url.host().toString(), m_sessionID, [request = WTFMove(request), handler = WTFMove(handler)] (bool foundHost) mutable {
         if (foundHost) {
             auto newURL = request.url();
-            newURL.setProtocol("https"_s);
+            newURL.setProtocol("https");
             request.setURL(newURL);
         }
 
index 4af9db2..7ea387d 100644 (file)
@@ -213,7 +213,7 @@ NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataT
     auto url = request.url();
     if (storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use && url.protocolIsInHTTPFamily()) {
         m_user = url.user();
-        m_password = url.pass();
+        m_password = url.password();
         request.removeCredentials();
         url = request.url();
     
@@ -371,7 +371,7 @@ void NetworkDataTaskCocoa::willPerformHTTPRedirection(WebCore::ResourceResponse&
     
     const auto& url = request.url();
     m_user = url.user();
-    m_password = url.pass();
+    m_password = url.password();
     m_lastHTTPMethod = request.httpMethod();
     request.removeCredentials();
     
index 977a403..26d961d 100644 (file)
@@ -56,7 +56,7 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas
         if (m_storedCredentialsPolicy == StoredCredentialsPolicy::Use) {
             auto url = request.url();
             m_user = url.user();
-            m_password = url.pass();
+            m_password = url.password();
             request.removeCredentials();
 
             if (m_user.isEmpty() && m_password.isEmpty())
@@ -274,7 +274,7 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection()
     bool didChangeCredential = false;
     const auto& url = request.url();
     m_user = url.user();
-    m_password = url.pass();
+    m_password = url.password();
     m_lastHTTPMethod = request.httpMethod();
     request.removeCredentials();
 
index fe1b63e..9c04650 100644 (file)
@@ -67,7 +67,7 @@ NetworkDataTaskSoup::NetworkDataTaskSoup(NetworkSession& session, NetworkDataTas
         auto url = request.url();
         if (m_storedCredentialsPolicy == StoredCredentialsPolicy::Use) {
             m_user = url.user();
-            m_password = url.pass();
+            m_password = url.password();
             request.removeCredentials();
 
             if (m_user.isEmpty() && m_password.isEmpty())
@@ -467,7 +467,7 @@ void NetworkDataTaskSoup::applyAuthenticationToRequest(ResourceRequest& request)
 
     auto url = request.url();
     url.setUser(m_user);
-    url.setPass(m_password);
+    url.setPassword(m_password);
     request.setURL(url);
 
     m_user = String();
@@ -688,7 +688,7 @@ void NetworkDataTaskSoup::continueHTTPRedirection()
 
     const auto& url = request.url();
     m_user = url.user();
-    m_password = url.pass();
+    m_password = url.password();
     m_lastHTTPMethod = request.httpMethod();
     request.removeCredentials();
 
@@ -1117,24 +1117,22 @@ void NetworkDataTaskSoup::startingCallback(SoupMessage* soupMessage, NetworkData
 }
 
 #if SOUP_CHECK_VERSION(2, 67, 1)
+
 bool NetworkDataTaskSoup::shouldAllowHSTSPolicySetting() const
 {
     // Follow Apple's HSTS abuse mitigation 1:
     //  "Limit HSTS State to the Hostname, or the Top Level Domain + 1"
-    if (isTopLevelNavigation() || hostsAreEqual(m_currentRequest.url(), m_currentRequest.firstPartyForCookies()) || isPublicSuffix(m_currentRequest.url().host().toStringWithoutCopying()))
-        return true;
-
-    return false;
+    return isTopLevelNavigation()
+        || m_currentRequest.url().host() == m_currentRequest.firstPartyForCookies().host()
+        || isPublicSuffix(m_currentRequest.url().host().toStringWithoutCopying());
 }
 
 bool NetworkDataTaskSoup::shouldAllowHSTSProtocolUpgrade() const
 {
-    // Follow Apple's HSTS abuse mitgation 2:
+    // Follow Apple's HSTS abuse mitigation 2:
     // "Ignore HSTS State for Subresource Requests to Blocked Domains"
-    if (!isTopLevelNavigation() && !m_currentRequest.allowCookies())
-        return false;
-
-    return true;
+    return isTopLevelNavigation()
+        || m_currentRequest.allowCookies();
 }
 
 void NetworkDataTaskSoup::protocolUpgradedViaHSTS(SoupMessage* soupMessage)
@@ -1153,6 +1151,7 @@ void NetworkDataTaskSoup::hstsEnforced(SoupHSTSEnforcer*, SoupMessage* soupMessa
     if (soupMessage == task->m_soupMessage.get())
         task->protocolUpgradedViaHSTS(soupMessage);
 }
+
 #endif
 
 void NetworkDataTaskSoup::didStartRequest()
index 2d77634..4c838af 100644 (file)
@@ -63,25 +63,25 @@ public:
     WTF::String host() const
     {
         parseURLIfNecessary();
-        return m_parsedURL->isValid() ? m_parsedURL->host().toString() : WTF::String();
+        return m_parsedURL->host().toString();
     }
 
     WTF::String protocol() const
     {
         parseURLIfNecessary();
-        return m_parsedURL->isValid() ? m_parsedURL->protocol().toString() : WTF::String();
+        return m_parsedURL->protocol().toString();
     }
 
     WTF::String path() const
     {
         parseURLIfNecessary();
-        return m_parsedURL->isValid() ? m_parsedURL->path().toString() : WTF::String();
+        return m_parsedURL->path().toString();
     }
 
     WTF::String lastPathComponent() const
     {
         parseURLIfNecessary();
-        return m_parsedURL->isValid() ? m_parsedURL->lastPathComponent() : WTF::String();
+        return m_parsedURL->lastPathComponent().toString();
     }
 
     void encode(IPC::Encoder& encoder) const
index b1c36db..07cd10f 100644 (file)
@@ -220,8 +220,8 @@ void DownloadClient::didFinish(DownloadProxy& downloadProxy)
 #if USE(SYSTEM_PREVIEW)
     if (downloadProxy.isSystemPreviewDownload()) {
         if (auto* controller = systemPreviewController(downloadProxy)) {
-            WTF::URL destinationURL = WTF::URL::fileURLWithFileSystemPath(downloadProxy.destinationFilename());
-            if (!destinationURL.fragmentIdentifier().length())
+            auto destinationURL = WTF::URL::fileURLWithFileSystemPath(downloadProxy.destinationFilename());
+            if (!destinationURL.hasFragmentIdentifier())
                 destinationURL.setFragmentIdentifier(downloadProxy.request().url().fragmentIdentifier());
             controller->finish(destinationURL);
         }
index 47b54ca..3936eb7 100644 (file)
@@ -114,15 +114,9 @@ void DeviceIdHashSaltStorage::loadStorageFromDisk(CompletionHandler<void(HashMap
 
         FileSystem::makeAllDirectories(m_deviceIdHashSaltStorageDirectory);
 
-        auto originPaths = FileSystem::listDirectory(m_deviceIdHashSaltStorageDirectory, "*");
-
         HashMap<String, std::unique_ptr<HashSaltForOrigin>> deviceIdHashSaltForOrigins;
-        for (const auto& originPath : originPaths) {
-            URL url;
-            url.setProtocol("file"_s);
-            url.setPath(originPath);
-
-            String deviceIdHashSalt = url.lastPathComponent();
+        for (auto& originPath : FileSystem::listDirectory(m_deviceIdHashSaltStorageDirectory, "*")) {
+            auto deviceIdHashSalt = URL::fileURLWithFileSystemPath(originPath).lastPathComponent().toString();
 
             if (hashSaltSize != deviceIdHashSalt.length()) {
                 RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: The length of the hash salt (%d) is different to the length of the hash salts defined in WebKit (%d)", deviceIdHashSalt.length(), hashSaltSize);
index d305553..b7af5cd 100644 (file)
@@ -145,16 +145,15 @@ PluginModuleInfo PluginInfoStore::findPluginForExtension(const String& extension
     return PluginModuleInfo();
 }
 
-static inline String pathExtension(const URL& url)
+static String pathExtension(const URL& url)
 {
-    String extension;
-    String filename = url.lastPathComponent();
-    if (!filename.endsWith('/')) {
-        size_t extensionPos = filename.reverseFind('.');
-        if (extensionPos != notFound)
-            extension = filename.substring(extensionPos + 1);
-    }
-    return extension.convertToASCIILowercase();
+    auto filename = url.lastPathComponent();
+    if (filename.endsWith('/'))
+        return { };
+    size_t lastDotPosition = filename.reverseFind('.');
+    if (lastDotPosition == notFound)
+        return { };
+    return filename.substring(lastDotPosition + 1).convertToASCIILowercase();
 }
 
 #if !PLATFORM(COCOA)
index 79baec5..4aa6ff8 100644 (file)
@@ -1255,7 +1255,7 @@ void WebPageProxy::maybeInitializeSandboxExtensionHandle(WebProcessProxy& proces
 #endif
 
     // We failed to issue an universal file read access sandbox, fall back to issuing one for the base URL instead.
-    auto baseURL = URL(URL(), url.baseAsString());
+    auto baseURL = url.truncatedForUseAsBase();
     auto basePath = baseURL.fileSystemPath();
     if (basePath.isNull())
         return;
@@ -5246,7 +5246,7 @@ void WebPageProxy::decidePolicyForNavigationAction(Ref<WebProcessProxy>&& proces
 
         bool shouldOpenAppLinks = !m_shouldSuppressAppLinksInNextNavigationPolicyDecision
             && destinationFrameInfo->isMainFrame()
-            && (m_mainFrame ? !hostsAreEqual(m_mainFrame->url(), request.url()) : false)
+            && (m_mainFrame && m_mainFrame->url().host() != request.url().host())
             && navigationActionData.navigationType != WebCore::NavigationType::BackForward;
 
         auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), destinationFrameInfo.ptr(), WTF::nullopt, WTFMove(request), originalRequest.url(), shouldOpenAppLinks, WTFMove(userInitiatedActivity), mainFrameNavigation);
@@ -5372,7 +5372,7 @@ void WebPageProxy::decidePolicyForNewWindowAction(FrameIdentifier frameID, Frame
             sourceFrameInfo = API::FrameInfo::create(WTFMove(frameInfo), this);
 
         auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
-        bool shouldOpenAppLinks = m_mainFrame ? !hostsAreEqual(m_mainFrame->url(), request.url()) : false;
+        bool shouldOpenAppLinks = m_mainFrame && m_mainFrame->url().host() != request.url().host();
         auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), nullptr, frameName, WTFMove(request), URL { }, shouldOpenAppLinks, WTFMove(userInitiatedActivity));
 
         m_navigationClient->decidePolicyForNavigationAction(*this, navigationAction.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
@@ -5570,7 +5570,7 @@ void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, Optio
 
         reply(newPage->webPageID(), newPage->creationParameters(m_process, *newPage->drawingArea()));
 
-        newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = hostsAreEqual(URL({ }, mainFrameURL), request.url());
+        newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = URL({ }, mainFrameURL).host() == request.url().host();
 
 #if HAVE(APP_SSO)
         newPage->m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision = true;
@@ -5578,7 +5578,7 @@ void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, Optio
     };
 
     auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
-    bool shouldOpenAppLinks = !hostsAreEqual(originatingFrameInfo->request().url(), request.url());
+    bool shouldOpenAppLinks = originatingFrameInfo->request().url().host() != request.url().host();
     auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), originatingFrameInfo.ptr(), nullptr, WTF::nullopt, WTFMove(request), URL(), shouldOpenAppLinks, WTFMove(userInitiatedActivity));
 
     trySOAuthorization(WTFMove(navigationAction), *this, WTFMove(completionHandler), [this, protectedThis = makeRef(*this), windowFeatures = WTFMove(windowFeatures)] (Ref<API::NavigationAction>&& navigationAction, CompletionHandler<void(RefPtr<WebPageProxy>&&)>&& completionHandler) mutable {
index c2588a8..e4a86fa 100644 (file)
@@ -567,11 +567,10 @@ void WebProcessProxy::assumeReadAccessToBaseURL(WebPageProxy& page, const String
 
     // There's a chance that urlString does not point to a directory.
     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
-    URL baseURL(URL(), url.baseAsString());
-    String path = baseURL.fileSystemPath();
+    auto path = url.truncatedForUseAsBase().fileSystemPath();
     if (path.isNull())
         return;
-    
+
     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
     // to have read access to this directory already.
     m_localPathsWithAssumedReadAccess.add(path);
index 315cf3f..f3423a9 100644 (file)
@@ -419,7 +419,7 @@ void WebsiteDataStore::initializeAppBoundDomains(ForceReinitialization forceRein
             for (NSString *domain in domains.get()) {
                 URL url { URL(), domain };
                 if (url.protocol().isEmpty())
-                    url.setProtocol("https"_s);
+                    url.setProtocol("https");
                 if (!url.isValid())
                     continue;
                 WebCore::RegistrableDomain appBoundDomain { url };
index 903990b..48751ab 100644 (file)
@@ -60,19 +60,10 @@ Vector<SecurityOriginData> WebMediaKeyStorageManager::getMediaKeyOrigins()
     if (m_mediaKeyStorageDirectory.isEmpty())
         return results;
 
-    Vector<String> originPaths = FileSystem::listDirectory(m_mediaKeyStorageDirectory, "*");
-    for (const auto& originPath : originPaths) {
-        URL url;
-        url.setProtocol("file"_s);
-        url.setPath(originPath);
-
-        String mediaKeyIdentifier = url.lastPathComponent();
-
-        auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier);
-        if (!securityOrigin)
-            continue;
-
-        results.append(*securityOrigin);
+    for (auto& originPath : FileSystem::listDirectory(m_mediaKeyStorageDirectory, "*")) {
+        auto identifier = URL::fileURLWithFileSystemPath(originPath).lastPathComponent().toString();
+        if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(identifier))
+            results.append(*securityOrigin);
     }
 
     return results;
index aed301a..e4efa48 100644 (file)
@@ -1562,10 +1562,8 @@ void PDFPlugin::installPDFDocument()
     if ([m_pdfDocument isLocked])
         createPasswordEntryForm();
 
-    if ([m_pdfLayerController respondsToSelector:@selector(setURLFragment:)]) {
-        String pdfURLFragment = m_frame.url().fragmentIdentifier();
-        [m_pdfLayerController setURLFragment:pdfURLFragment];
-    }
+    if ([m_pdfLayerController respondsToSelector:@selector(setURLFragment:)])
+        [m_pdfLayerController setURLFragment:m_frame.url().fragmentIdentifier().createNSString().get()];
 }
 
 void PDFPlugin::setSuggestedFilename(const String& suggestedFilename)
index 768ba2d..41d3ed8 100644 (file)
  */
 
 #include "config.h"
+#include "WebContextMenuClient.h"
 
 #if ENABLE(CONTEXT_MENUS)
 
-#include "WebContextMenuClient.h"
-
 #include "WebContextMenu.h"
-#include "WebContextMenuItemData.h"
 #include "WebPage.h"
-#include <WebCore/ContextMenu.h>
 #include <WebCore/Editor.h>
-#include <WebCore/Event.h>
 #include <WebCore/Frame.h>
 #include <WebCore/FrameLoader.h>
 #include <WebCore/NotImplemented.h>
@@ -42,7 +38,6 @@
 #include <WebCore/UserGestureIndicator.h>
 
 namespace WebKit {
-using namespace WebCore;
 
 void WebContextMenuClient::contextMenuDestroyed()
 {
@@ -56,19 +51,21 @@ void WebContextMenuClient::downloadURL(const URL&)
 }
 
 #if !PLATFORM(COCOA)
-void WebContextMenuClient::searchWithGoogle(const Frame* frame)
+
+void WebContextMenuClient::searchWithGoogle(const WebCore::Frame* frame)
 {
-    String searchString = frame->editor().selectedText();
-    searchString.stripWhiteSpace();
-    String encoded = encodeWithURLEscapeSequences(searchString);
-    encoded.replace("%20"_s, "+"_s);
+    auto page = frame->page();
+    if (!page)
+        return;
 
-    String url = "https://www.google.com/search?q=" + encoded + "&ie=UTF-8&oe=UTF-8";
+    auto searchString = frame->editor().selectedText();
+    searchString.stripWhiteSpace();
+    searchString = encodeWithURLEscapeSequences(searchString);
+    searchString.replace("%20"_s, "+"_s);
+    auto searchURL = URL { { }, "https://www.google.com/search?q=" + searchString + "&ie=UTF-8&oe=UTF-8" };
 
-    if (Page* page = frame->page()) {
-        UserGestureIndicator indicator(ProcessingUserGesture);
-        page->mainFrame().loader().changeLocation(URL { URL { }, url }, { }, nullptr, LockHistory::No, LockBackForwardList::No, ReferrerPolicy::EmptyString, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
-    }
+    WebCore::UserGestureIndicator indicator { WebCore::ProcessingUserGesture };
+    page->mainFrame().loader().changeLocation(searchURL, { }, nullptr, WebCore::LockHistory::No, WebCore::LockBackForwardList::No, WebCore::ReferrerPolicy::EmptyString, WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
 }
 
 void WebContextMenuClient::lookUpInDictionary(WebCore::Frame*)
@@ -91,14 +88,18 @@ void WebContextMenuClient::stopSpeaking()
 {
     notImplemented();
 }
+
 #endif
 
 #if USE(ACCESSIBILITY_CONTEXT_MENUS)
+
 void WebContextMenuClient::showContextMenu()
 {
     m_page->contextMenu()->show();
 }
+
 #endif
 
 } // namespace WebKit
+
 #endif // ENABLE(CONTEXT_MENUS)
index 8094a62..30c6ffe 100644 (file)
@@ -129,7 +129,7 @@ void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, Eleme
 
     String title = label;
     if (title.isEmpty()) {
-        title = url.lastPathComponent();
+        title = url.lastPathComponent().toString();
         if (title.isEmpty())
             title = WTF::userVisibleString(url);
     }
index e381aae..bab9c71 100644 (file)
@@ -1,3 +1,28 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * WebCoreSupport/WebFrameLoaderClient.mm:
+        (shouldTryAppLink): Compare hosts with == rather than using hostsAreEqual.
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame _documentFragmentForImageData:withRelativeURLPart:andMIMEType:]):
+        Updated since fakeURLWithRelativePart takes a StringView. Also use RetainPtr
+        instead of an explicit call to release.
+
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView _web_documentFragmentFromPasteboard:pasteboardType:imageMIMEType:]):
+        Updated since fakeURLWithRelativePart takes a StringView. No conversion
+        directly from NSString to StringView, so we have to explicitly use a String.
+
+        * WebView/WebImmediateActionController.mm:
+        (-[WebImmediateActionController _defaultAnimationController]): Update
+        since protocolIs takes a StringView. No conversion directly from
+        NSString to StringView, so we have to explicitly use a String.
+
 2020-04-24  Megan Gardner  <megan_gardner@apple.com>
 
         Make LEGACY_PDF_SUPPORT feature flag.
index c8448c5..ccae212 100644 (file)
@@ -882,7 +882,7 @@ static BOOL shouldTryAppLink(WebView *webView, const WebCore::NavigationAction&
     if (!action.processingUserGesture())
         return NO;
 
-    if (targetFrame && targetFrame->document() && hostsAreEqual(targetFrame->document()->url(), action.url()))
+    if (targetFrame && targetFrame->document() && targetFrame->document()->url().host() == action.url().host())
         return NO;
 
     return YES;
index 53673e9..7d489e6 100644 (file)
@@ -2286,14 +2286,10 @@ static WebFrameLoadType toWebFrameLoadType(WebCore::FrameLoadType frameLoadType)
 
 - (DOMDocumentFragment *)_documentFragmentForImageData:(NSData *)data withRelativeURLPart:(NSString *)relativeURLPart andMIMEType:(NSString *)mimeType
 {
-    WebResource *resource = [[WebResource alloc] initWithData:data
-                                                          URL:URL::fakeURLWithRelativePart(relativeURLPart)
-                                                     MIMEType:mimeType
-                                             textEncodingName:nil
-                                                    frameName:nil];
-    DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
-    [resource release];
-    return fragment;
+    auto resource = adoptNS([[WebResource alloc] initWithData:data
+        URL:URL::fakeURLWithRelativePart(String { relativeURLPart })
+        MIMEType:mimeType textEncodingName:nil frameName:nil]);
+    return [[self _dataSource] _documentFragmentWithImageResource:resource.get()];
 }
 
 - (BOOL)focusedNodeHasContent
index ac6b713..7a4f5a8 100644 (file)
@@ -2306,7 +2306,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END
 
 - (DOMDocumentFragment *)_web_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard pasteboardType:(NSString *)pasteboardType imageMIMEType:(NSString *)imageMIMEType
 {
-    auto filename = [imageMIMEType stringByReplacingOccurrencesOfString:@"/" withString:@"."];
+    String filename = [imageMIMEType stringByReplacingOccurrencesOfString:@"/" withString:@"."];
     auto resource = adoptNS([[WebResource alloc] initWithData:[pasteboard dataForType:pasteboardType]
         URL:URL::fakeURLWithRelativePart(filename) MIMEType:imageMIMEType textEncodingName:nil frameName:nil]);
     return [[self _dataSource] _documentFragmentWithImageResource:resource.get()];
index aa51b63..f141863 100644 (file)
@@ -255,7 +255,7 @@ SOFT_LINK_CLASS(QuickLookUI, QLPreviewMenuItem)
         return [[[WebAnimationController alloc] init] autorelease];
 
     NSURL *url = _hitTestResult.absoluteLinkURL();
-    NSString *absoluteURLString = [url absoluteString];
+    String absoluteURLString = [url absoluteString];
     if (url && _hitTestResult.URLElement()) {
         if (WTF::protocolIs(absoluteURLString, "mailto")) {
             _type = WebImmediateActionMailtoLink;
index bfa0aaa..ec30f23 100644 (file)
@@ -1,3 +1,27 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * Plugins/PluginDatabase.cpp:
+        (WebCore::PluginDatabase::PluginDatabase): Moved initialization of
+        m_persistentMetadataCacheIsLoaded to the class definition.
+        (WebCore::PluginDatabase::MIMETypeForExtension const): Take StringView.
+        (WebCore::PluginDatabase::findPlugin): Use StringView.
+
+        * Plugins/PluginDatabase.h: Changed MIMETypeForExtension to take
+        a StringView. Took out some unneeded declarations. Initialized
+        m_persistentMetadataCacheIsLoaded here in the class definition.
+
+        * WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebFrameLoaderClient::objectContentType): Use StringView a little more.
+
+        * WebCoreSupport/WebContextMenuClient.cpp:
+        (WebContextMenuClient::searchWithGoogle): Streamlined the implementation a bit.
+        (WebContextMenuClient::lookUpInDictionary): Added "using namespace WebCore".
+
 2020-04-24  Antoine Quint  <graouts@apple.com>
 
         Update the css/css-animations WPT tests
index 641ac35..92789cd 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
- * Copyright (C) 2008 Collabora, Ltd.  All rights reserved.
+ * Copyright (C) 2006-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace WebCore {
 
-typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap;
+typedef HashMap<String, RefPtr<PluginPackage>> PluginPackageByNameMap;
 
 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
 
-static const size_t maximumPersistentPluginMetadataCacheSize = 32768;
+constexpr size_t maximumPersistentPluginMetadataCacheSize = 32768;
 
 static bool gPersistentPluginMetadataCacheIsEnabled;
 
@@ -55,9 +55,6 @@ String& persistentPluginMetadataCachePath()
 #endif
 
 PluginDatabase::PluginDatabase()
-#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
-    : m_persistentMetadataCacheIsLoaded(false)
-#endif
 {
 }
 
@@ -228,7 +225,7 @@ PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType)
     return pluginChoices[0];
 }
 
-String PluginDatabase::MIMETypeForExtension(const String& extension) const
+String PluginDatabase::MIMETypeForExtension(StringView extension) const
 {
     if (extension.isEmpty())
         return String();
@@ -250,7 +247,7 @@ String PluginDatabase::MIMETypeForExtension(const String& extension) const
             const Vector<String>& extensions = mime_it->value;
             bool foundMapping = false;
             for (unsigned i = 0; i < extensions.size(); i++) {
-                if (equalIgnoringASCIICase(extensions[i], extension)) {
+                if (equalIgnoringASCIICase(StringView { extensions[i] }, extension)) {
                     PluginPackage* plugin = (*it).get();
 
                     if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin))
@@ -284,20 +281,19 @@ PluginPackage* PluginDatabase::findPlugin(const URL& url, String& mimeType)
     if (!mimeType.isEmpty())
         return pluginForMIMEType(mimeType);
     
-    String filename = url.lastPathComponent();
+    auto filename = url.lastPathComponent();
     if (filename.endsWith('/'))
-        return 0;
+        return nullptr;
     
-    int extensionPos = filename.reverseFind('.');
-    if (extensionPos == -1)
-        return 0;
+    auto dotPosition = filename.reverseFind('.');
+    if (dotPosition == notFound)
+        return nullptr;
     
-    String mimeTypeForExtension = MIMETypeForExtension(filename.substring(extensionPos + 1));
+    String mimeTypeForExtension = MIMETypeForExtension(filename.substring(dotPosition + 1));
     PluginPackage* plugin = pluginForMIMEType(mimeTypeForExtension);
     if (!plugin) {
-        // FIXME: if no plugin could be found, query Windows for the mime type
-        // corresponding to the extension.
-        return 0;
+        // FIXME: If no plugin could be found, query Windows for the MIME type corresponding to the extension.
+        return nullptr;
     }
     
     mimeType = mimeTypeForExtension;
@@ -374,6 +370,7 @@ bool PluginDatabase::addDisabledPluginFile(const String& fileName)
 }
 
 #if !ENABLE(NETSCAPE_PLUGIN_API)
+
 // For Safari/Win the following three methods are implemented
 // in PluginDatabaseWin.cpp, but if we can use WebCore constructs
 // for the logic we should perhaps move it here under XP_WIN?
@@ -470,8 +467,8 @@ static bool readTime(time_t& resultTime, char*& start, const char* end)
     return true;
 }
 
-static const char schemaVersion = '1';
-static const char persistentPluginMetadataCacheFilename[] = "PluginMetadataCache.bin";
+constexpr char schemaVersion = '1';
+constexpr char persistentPluginMetadataCacheFilename[] = "PluginMetadataCache.bin";
 
 void PluginDatabase::loadPersistentMetadataCache()
 {
@@ -617,5 +614,7 @@ void PluginDatabase::setPersistentMetadataCachePath(const String& persistentMeta
 {
     WebCore::persistentPluginMetadataCachePath() = persistentMetadataCachePath;
 }
+
 #endif
+
 }
index acc0e1f..472499b 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
- * Copyright (C) 2008 Collabora, Ltd.  All rights reserved.
+ * Copyright (C) 2006-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
  *
  * Redistribution and use in source and binary forms, with or without
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef PluginDatabase_h
-#define PluginDatabase_h
+#pragma once
 
 #include "PluginPackage.h"
 #include <wtf/HashSet.h>
 #include <wtf/Vector.h>
 #include <wtf/text/StringHash.h>
-#include <wtf/text/WTFString.h>
 
 namespace WebCore {
-    class Element;
-    class Frame;
-    class IntSize;
-    class PluginDatabaseClient;
-    class PluginPackage;
 
     typedef HashSet<RefPtr<PluginPackage>, PluginPackageHash, PluginPackageHashTraits> PluginSet;
 
@@ -79,7 +72,8 @@ namespace WebCore {
         static Vector<String> defaultPluginDirectories();
         Vector<String> pluginDirectories() const { return m_pluginDirectories; }
 
-        String MIMETypeForExtension(const String& extension) const;
+        String MIMETypeForExtension(StringView extension) const;
+
 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
         static bool isPersistentMetadataCacheEnabled();
         static void setPersistentMetadataCacheEnabled(bool isEnabled);
@@ -108,10 +102,8 @@ namespace WebCore {
         HashMap<String, time_t> m_pluginPathsWithTimes;
         HashMap<String, RefPtr<PluginPackage>, ASCIICaseInsensitiveHash> m_preferredPlugins;
 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
-        bool m_persistentMetadataCacheIsLoaded;
+        bool m_persistentMetadataCacheIsLoaded { false };
 #endif
     };
 
 } // namespace WebCore
-
-#endif
index c265e08..7f38bba 100644 (file)
 
 #include "WebContextMenuClient.h"
 
-#include "WebElementPropertyBag.h"
-#include "WebLocalizableStrings.h"
 #include "WebView.h"
-#include <WebCore/ContextMenuController.h>
 #include <WebCore/Editor.h>
-#include <WebCore/Event.h>
 #include <WebCore/Frame.h>
 #include <WebCore/FrameLoader.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/Page.h>
-#include <WebCore/ResourceRequest.h>
 #include <WebCore/UserGestureIndicator.h>
 
-using namespace WebCore;
-
 WebContextMenuClient::WebContextMenuClient(WebView* webView)
     : m_webView(webView)
 {
@@ -55,22 +48,23 @@ void WebContextMenuClient::downloadURL(const URL& url)
     m_webView->downloadURL(url);
 }
 
-void WebContextMenuClient::searchWithGoogle(const Frame* frame)
+void WebContextMenuClient::searchWithGoogle(const WebCore::Frame* frame)
 {
-    String searchString = frame->editor().selectedText();
-    searchString.stripWhiteSpace();
-    String encoded = encodeWithURLEscapeSequences(searchString);
-    encoded.replace("%20"_s, "+"_s);
+    auto page = frame->page();
+    if (!page)
+        return;
 
-    String url = "https://www.google.com/search?q=" + encoded + "&ie=UTF-8&oe=UTF-8";
+    auto searchString = frame->editor().selectedText();
+    searchString.stripWhiteSpace();
+    searchString = encodeWithURLEscapeSequences(searchString);
+    searchString.replace("%20"_s, "+"_s);
+    auto searchURL = URL { { }, "https://www.google.com/search?q=" + searchString + "&ie=UTF-8&oe=UTF-8" };
 
-    if (Page* page = frame->page()) {
-        UserGestureIndicator indicator(ProcessingUserGesture);
-        page->mainFrame().loader().changeLocation(URL { URL { }, url }, { }, nullptr, LockHistory::No, LockBackForwardList::No, ReferrerPolicy::EmptyString, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
-    }
+    WebCore::UserGestureIndicator indicator { WebCore::ProcessingUserGesture };
+    page->mainFrame().loader().changeLocation(searchURL, { }, nullptr, WebCore::LockHistory::No, WebCore::LockBackForwardList::No, WebCore::ReferrerPolicy::EmptyString, WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
 }
 
-void WebContextMenuClient::lookUpInDictionary(Frame*)
+void WebContextMenuClient::lookUpInDictionary(WebCore::Frame*)
 {
     notImplemented();
 }
index 6222820..539be77 100644 (file)
@@ -1014,7 +1014,7 @@ ObjectContentType WebFrameLoaderClient::objectContentType(const URL& url, const
 
     if (mimeType.isEmpty()) {
         String decodedPath = decodeURLEscapeSequences(url.path());
-        mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(decodedPath.substring(decodedPath.reverseFind('.') + 1));
+        mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(StringView { decodedPath }.substring(decodedPath.reverseFind('.') + 1));
     }
 
     if (mimeType.isEmpty())
index c0646b6..bcd01a4 100644 (file)
@@ -1,3 +1,23 @@
+2020-04-25  Darin Adler  <darin@apple.com>
+
+        Move URL to use StringView when returning substrings of the URL
+        https://bugs.webkit.org/show_bug.cgi?id=210431
+
+        Reviewed by Anders Carlsson.
+
+        * TestWebKitAPI/Tests/WTF/URL.cpp: Removed the test for
+        equalIgnoringQueryAndFragment since we removed that function.
+        Updated for rename of URL::password from URL::pass.
+        Updated arguments to isMatchingDomain to pass literals that can be converted
+        to StringView rather than ASCIILiteral, which StringView doesn't yet support.
+
+        * TestWebKitAPI/Tests/WebCore/URLParserTextEncoding.cpp:
+        (TestWebKitAPI::checkURL): Updated for rename of URL::password from URL::pass.
+        (TestWebKitAPI::checkRelativeURL): Ditto.
+        (TestWebKitAPI::checkURLDifferences): Ditto.
+        (TestWebKitAPI::checkRelativeURLDifferences): Ditto.
+        (TestWebKitAPI::testUserPassword): Ditto.
+
 2020-04-25  Diego Pino Garcia  <dpino@igalia.com>
 
         [Flatpak SDK][EWS] Install dependencies step needs configuration as argument
index 937b9f9..6bf275a 100644 (file)
@@ -61,7 +61,7 @@ TEST_F(WTF_URL, URLConstructorConstChar)
     EXPECT_TRUE(!!kurl.port());
     EXPECT_EQ(8080, kurl.port().value());
     EXPECT_EQ(String("username"), kurl.user());
-    EXPECT_EQ(String("password"), kurl.pass());
+    EXPECT_EQ(String("password"), kurl.password());
     EXPECT_EQ(String("/index.html"), kurl.path());
     EXPECT_EQ(String("index.html"), kurl.lastPathComponent());
     EXPECT_EQ(String("var=val"), kurl.query());
@@ -261,57 +261,6 @@ TEST_F(WTF_URL, EqualIgnoringFragmentIdentifier)
     }
 }
 
-TEST_F(WTF_URL, EqualIgnoringQueryAndFragment)
-{
-    struct TestCase {
-        const char* url1;
-        const char* url2;
-        bool expected;
-    } cases[] = {
-        {"http://example.com/", "http://example.com/", true},
-        {"http://example.com/#hash", "http://example.com/", true},
-        {"http://example.com/path", "http://example.com/", false},
-        {"http://example.com/path", "http://example.com/path", true},
-        {"http://example.com/path#hash", "http://example.com/path", true},
-        {"http://example.com/path?query", "http://example.com/path", true},
-        {"http://example.com/path?query#hash", "http://example.com/path", true},
-        {"http://example.com/otherpath", "http://example.com/path", false},
-        {"http://example.com:80/", "http://example.com/", true},
-        {"http://example.com:80/#hash", "http://example.com/", true},
-        {"http://example.com:80/path", "http://example.com/", false},
-        {"http://example.com:80/path#hash", "http://example.com/path", true},
-        {"http://example.com:80/path?query", "http://example.com/path", true},
-        {"http://example.com:80/path?query#hash", "http://example.com/path", true},
-        {"http://example.com:80/otherpath", "http://example.com/path", false},
-        {"http://not-example.com:80/", "http://example.com:80/", false},
-        {"http://example.com:81/", "http://example.com/", false},
-        {"http://example.com:81/#hash", "http://example.com:81/", true},
-        {"http://example.com:81/path", "http://example.com:81", false},
-        {"http://example.com:81/path#hash", "http://example.com:81/path", true},
-        {"http://example.com:81/path?query", "http://example.com:81/path", true},
-        {"http://example.com:81/path?query#hash", "http://example.com:81/path", true},
-        {"http://example.com:81/otherpath", "http://example.com:81/path", false},
-        {"file:///path/to/file.html", "file:///path/to/file.html", true},
-        {"file:///path/to/file.html#hash", "file:///path/to/file.html", true},
-        {"file:///path/to/file.html?query", "file:///path/to/file.html", true},
-        {"file:///path/to/file.html?query#hash", "file:///path/to/file.html", true},
-        {"file:///path/to/other_file.html", "file:///path/to/file.html", false},
-        {"file:///path/to/other/file.html", "file:///path/to/file.html", false},
-        {"data:text/plain;charset=utf-8;base64,76O/76O/76O/", "data:text/plain;charset=utf-8;base64,760/760/760/", false},
-        {"http://example.com", "file://example.com", false},
-        {"http://example.com/#hash", "file://example.com", false},
-        {"http://example.com/?query", "file://example.com/", false},
-        {"http://example.com/?query#hash", "file://example.com/", false},
-    };
-
-    for (const auto& test : cases) {
-        URL url1 = createURL(test.url1);
-        URL url2 = createURL(test.url2);
-        EXPECT_EQ(test.expected, equalIgnoringQueryAndFragment(url1, url2))
-            << "Test failed for " << test.url1 << " vs. " << test.url2;
-    }
-}
-
 TEST_F(WTF_URL, ProtocolIsInHTTPFamily)
 {
     EXPECT_FALSE(WTF::protocolIsInHTTPFamily({ }));
@@ -376,22 +325,22 @@ TEST_F(WTF_URL, HostIsMatchingDomain)
 
     EXPECT_TRUE(url.isMatchingDomain(String { }));
     EXPECT_TRUE(url.isMatchingDomain(emptyString()));
-    EXPECT_TRUE(url.isMatchingDomain("org"_s));
-    EXPECT_TRUE(url.isMatchingDomain("webkit.org"_s));
-    EXPECT_TRUE(url.isMatchingDomain("www.webkit.org"_s));
+    EXPECT_TRUE(url.isMatchingDomain("org"));
+    EXPECT_TRUE(url.isMatchingDomain("webkit.org"));
+    EXPECT_TRUE(url.isMatchingDomain("www.webkit.org"));
 
-    EXPECT_FALSE(url.isMatchingDomain("rg"_s));
-    EXPECT_FALSE(url.isMatchingDomain(".org"_s));
-    EXPECT_FALSE(url.isMatchingDomain("ww.webkit.org"_s));
-    EXPECT_FALSE(url.isMatchingDomain("http://www.webkit.org"_s));
+    EXPECT_FALSE(url.isMatchingDomain("rg"));
+    EXPECT_FALSE(url.isMatchingDomain(".org"));
+    EXPECT_FALSE(url.isMatchingDomain("ww.webkit.org"));
+    EXPECT_FALSE(url.isMatchingDomain("http://www.webkit.org"));
 
     url = createURL("file:///www.webkit.org");
 
     EXPECT_TRUE(url.isMatchingDomain(String { }));
     EXPECT_TRUE(url.isMatchingDomain(emptyString()));
-    EXPECT_FALSE(url.isMatchingDomain("org"_s));
-    EXPECT_FALSE(url.isMatchingDomain("webkit.org"_s));
-    EXPECT_FALSE(url.isMatchingDomain("www.webkit.org"_s));
+    EXPECT_FALSE(url.isMatchingDomain("org"));
+    EXPECT_FALSE(url.isMatchingDomain("webkit.org"));
+    EXPECT_FALSE(url.isMatchingDomain("www.webkit.org"));
 
     URL emptyURL;
     EXPECT_FALSE(emptyURL.isMatchingDomain(String { }));
index 1039e54..08a3a9e 100644 (file)
@@ -92,7 +92,7 @@ static void checkURL(const String& urlString, const ExpectedParts& parts, TestTa
     
     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
     EXPECT_TRUE(eq(parts.user, url.user()));
-    EXPECT_TRUE(eq(parts.password, url.pass()));
+    EXPECT_TRUE(eq(parts.password, url.password()));
     EXPECT_TRUE(eq(parts.host, url.host()));
     EXPECT_EQ(parts.port, url.port().valueOr(0));
     EXPECT_TRUE(eq(parts.path, url.path()));
@@ -119,7 +119,7 @@ static void checkRelativeURL(const String& urlString, const String& baseURLStrin
     
     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
     EXPECT_TRUE(eq(parts.user, url.user()));
-    EXPECT_TRUE(eq(parts.password, url.pass()));
+    EXPECT_TRUE(eq(parts.password, url.password()));
     EXPECT_TRUE(eq(parts.host, url.host()));
     EXPECT_EQ(parts.port, url.port().valueOr(0));
     EXPECT_TRUE(eq(parts.path, url.path()));
@@ -148,7 +148,7 @@ static void checkURLDifferences(const String& urlString, const ExpectedParts& pa
     
     EXPECT_TRUE(eq(partsNew.protocol, url.protocol()));
     EXPECT_TRUE(eq(partsNew.user, url.user()));
-    EXPECT_TRUE(eq(partsNew.password, url.pass()));
+    EXPECT_TRUE(eq(partsNew.password, url.password()));
     EXPECT_TRUE(eq(partsNew.host, url.host()));
     EXPECT_EQ(partsNew.port, url.port().valueOr(0));
     EXPECT_TRUE(eq(partsNew.path, url.path()));
@@ -177,7 +177,7 @@ static void checkRelativeURLDifferences(const String& urlString, const String& b
     
     EXPECT_TRUE(eq(partsNew.protocol, url.protocol()));
     EXPECT_TRUE(eq(partsNew.user, url.user()));
-    EXPECT_TRUE(eq(partsNew.password, url.pass()));
+    EXPECT_TRUE(eq(partsNew.password, url.password()));
     EXPECT_TRUE(eq(partsNew.host, url.host()));
     EXPECT_EQ(partsNew.port, url.port().valueOr(0));
     EXPECT_TRUE(eq(partsNew.path, url.path()));
@@ -462,19 +462,19 @@ TEST_F(WTF_URLParser, Basic)
     checkURL("http://:@host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
 }
 
-static void testUserPass(const String& value, const String& decoded, const String& encoded)
+static void testUserPassword(const String& value, const String& decoded, const String& encoded)
 {
     URL userURL(URL(), makeString("http://", value, "@example.com/"));
     URL passURL(URL(), makeString("http://user:", value, "@example.com/"));
     EXPECT_EQ(encoded, userURL.encodedUser());
-    EXPECT_EQ(encoded, passURL.encodedPass());
+    EXPECT_EQ(encoded, passURL.encodedPassword());
     EXPECT_EQ(decoded, userURL.user());
-    EXPECT_EQ(decoded, passURL.pass());
+    EXPECT_EQ(decoded, passURL.password());
 }
 
-static void testUserPass(const String& value, const String& encoded)
+static void testUserPassword(const String& value, const String& encoded)
 {
-    testUserPass(value, value, encoded);
+    testUserPassword(value, value, encoded);
 }
 
 TEST_F(WTF_URLParser, Credentials)
@@ -483,20 +483,20 @@ TEST_F(WTF_URLParser, Credentials)
     auto invalidSurrogate = utf16String<3>({0xD800, 'A', '\0'});
     auto replacementA = utf16String<3>({0xFFFD, 'A', '\0'});
 
-    testUserPass("a", "a");
-    testUserPass("%", "%");
-    testUserPass("%25", "%", "%25");
-    testUserPass("%2525", "%25", "%2525");
-    testUserPass("%FX", "%FX");
-    testUserPass("%00", String::fromUTF8("\0", 1), "%00");
-    testUserPass("%F%25", "%F%", "%F%25");
-    testUserPass("%X%25", "%X%", "%X%25");
-    testUserPass("%%25", "%%", "%%25");
-    testUserPass("💩", "%C3%B0%C2%9F%C2%92%C2%A9");
-    testUserPass("%💩", "%%C3%B0%C2%9F%C2%92%C2%A9");
-    testUserPass(validSurrogate, "%F0%90%85%95");
-    testUserPass(replacementA, "%EF%BF%BDA");
-    testUserPass(invalidSurrogate, replacementA, "%EF%BF%BDA");
+    testUserPassword("a", "a");
+    testUserPassword("%", "%");
+    testUserPassword("%25", "%", "%25");
+    testUserPassword("%2525", "%25", "%2525");
+    testUserPassword("%FX", "%FX");
+    testUserPassword("%00", String::fromUTF8("\0", 1), "%00");
+    testUserPassword("%F%25", "%F%", "%F%25");
+    testUserPassword("%X%25", "%X%", "%X%25");
+    testUserPassword("%%25", "%%", "%%25");
+    testUserPassword("💩", "%C3%B0%C2%9F%C2%92%C2%A9");
+    testUserPassword("%💩", "%%C3%B0%C2%9F%C2%92%C2%A9");
+    testUserPassword(validSurrogate, "%F0%90%85%95");
+    testUserPassword(replacementA, "%EF%BF%BDA");
+    testUserPassword(invalidSurrogate, replacementA, "%EF%BF%BDA");
 }
 
 TEST_F(WTF_URLParser, ParseRelative)
index a26816d..e261793 100644 (file)
@@ -94,7 +94,7 @@ static void checkURL(const String& urlString, const TextEncoding* encoding, cons
     auto url = URL({ }, urlString, encoding);
     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
     EXPECT_TRUE(eq(parts.user, url.user()));
-    EXPECT_TRUE(eq(parts.password, url.pass()));
+    EXPECT_TRUE(eq(parts.password, url.password()));
     EXPECT_TRUE(eq(parts.host, url.host()));
     EXPECT_EQ(parts.port, url.port().valueOr(0));
     EXPECT_TRUE(eq(parts.path, url.path()));
@@ -118,7 +118,7 @@ static void checkURL(const String& urlString, const String& baseURLString, const
     auto url = URL(URL({ }, baseURLString), urlString, encoding);
     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
     EXPECT_TRUE(eq(parts.user, url.user()));
-    EXPECT_TRUE(eq(parts.password, url.pass()));
+    EXPECT_TRUE(eq(parts.password, url.password()));
     EXPECT_TRUE(eq(parts.host, url.host()));
     EXPECT_EQ(parts.port, url.port().valueOr(0));
     EXPECT_TRUE(eq(parts.path, url.path()));