TEST(KnownPortsTest, IsDefaultPortForProtocol) { struct TestCase { const unsigned short port; const char* protocol; const bool isKnown; } inputs[] = { // Known ones. { 80, "http", true }, { 443, "https", true }, { 80, "ws", true }, { 443, "wss", true }, { 21, "ftp", true }, { 990, "ftps", true }, // Unknown ones. { 5, "foo", false }, { 80, "http:", false }, { 443, "http", false }, { 21, "ftps", false }, { 990, "ftp", false }, // With upper cases. { 80, "HTTP", false }, { 443, "Https", false }, }; for (const TestCase& test : inputs) { bool result = isDefaultPortForProtocol(test.port, test.protocol); EXPECT_EQ(test.isKnown, result); } }
String DOMURLUtilsReadOnly::host(const KURL& kurl) { if (kurl.hostEnd() == kurl.pathStart()) return kurl.host(); if (isDefaultPortForProtocol(kurl.port(), kurl.protocol())) return kurl.host(); return kurl.host() + ":" + String::number(kurl.port()); }
void HTMLAnchorElement::setHost(const String& value) { if (value.isEmpty()) return; KURL url = href(); if (!url.canSetHostOrPort()) return; size_t separator = value.find(':'); if (!separator) return; if (separator == notFound) url.setHostAndPort(value); else { unsigned portEnd; unsigned port = parsePortFromStringPosition(value, separator + 1, portEnd); if (!port) { // 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"); } else { if (isDefaultPortForProtocol(port, url.protocol())) url.setHostAndPort(value.substring(0, separator)); else url.setHostAndPort(value.substring(0, portEnd)); } } setHref(url.string()); }
bool portMatches(const KURL& url) const { if (m_portHasWildcard) return true; int port = url.port(); return port ? port == m_port : isDefaultPortForProtocol(m_port, url.protocol()); }
String HTMLAnchorElement::host() const { const KURL& url = href(); if (url.hostEnd() == url.pathStart()) return url.host(); if (isDefaultPortForProtocol(url.port(), url.protocol())) return url.host(); return url.host() + ":" + String::number(url.port()); }
bool CSPSource::portMatches(int port, const String& protocol) const { if (m_portWildcard == HasWildcard) return true; if (port == m_port) return true; if (m_port == 80 && (port == 443 || (port == 0 && defaultPortForProtocol(protocol) == 443))) return true; if (!port) return isDefaultPortForProtocol(m_port, protocol); if (!m_port) return isDefaultPortForProtocol(port, protocol); return false; }
bool CSPSource::portMatches(const KURL& url) const { if (m_portWildcard == HasWildcard) return true; int port = url.port(); if (port == m_port) return true; if (m_port == 80 && (port == 443 || (port == 0 && (url.protocol() == "https" || url.protocol() == "wss")))) return true; if (!port) return isDefaultPortForProtocol(m_port, url.protocol()); if (!m_port) return isDefaultPortForProtocol(port, url.protocol()); return false; }
void KURL::setPort(unsigned short port) { if (isDefaultPortForProtocol(port, protocol())) { removePort(); return; } String portString = String::number(port); ASSERT(portString.is8Bit()); url::Replacements<char> replacements; replacements.SetPort(reinterpret_cast<const char*>(portString.characters8()), url::Component(0, portString.length())); replaceComponents(replacements); }
void HTMLAnchorElement::setPort(const String& value) { KURL url = href(); if (!url.canSetHostOrPort()) return; // 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. unsigned port = value.toUInt(); if (isDefaultPortForProtocol(port, url.protocol())) url.removePort(); else url.setPort(port); setHref(url.string()); }
void applyBlockedStatusToRequest(const BlockedStatus& status, ResourceRequest& request) { if (status.blockedCookies) request.setAllowCookies(false); if (status.madeHTTPS) { const URL& originalURL = request.url(); ASSERT(originalURL.protocolIs("http")); ASSERT(!originalURL.port() || isDefaultPortForProtocol(originalURL.port().value(), originalURL.protocol())); URL newURL = originalURL; newURL.setProtocol("https"); if (originalURL.port()) newURL.setPort(defaultPortForProtocol("https").value()); request.setURL(newURL); } }
SecurityOrigin::SecurityOrigin(const URL& url) : m_protocol(url.protocol().isNull() ? emptyString() : url.protocol().toString().convertToASCIILowercase()) , m_host(url.host().isNull() ? emptyString() : url.host().convertToASCIILowercase()) , m_port(url.port()) { // document.domain starts as m_host, but can be set by the DOM. m_domain = m_host; if (m_port && isDefaultPortForProtocol(m_port.value(), m_protocol)) m_port = Nullopt; // By default, only local SecurityOrigins can load local resources. m_canLoadLocalResources = isLocal(); if (m_canLoadLocalResources) m_filePath = url.path(); // In case enforceFilePathSeparation() is called. }
void ResourceLoader::didReceiveResponse(const ResourceResponse& r) { ASSERT(!m_reachedTerminalState); // Protect this in this delegate method since the additional processing can do // anything including possibly derefing this; one example of this is Radar 3266216. Ref<ResourceLoader> protectedThis(*this); logResourceResponseSource(m_frame.get(), r.source()); m_response = r; if (m_response.isHttpVersion0_9()) { auto url = m_response.url(); // Non-HTTP responses are interpreted as HTTP/0.9 which may allow exfiltration of data // from non-HTTP services. Therefore cancel if the document was loaded with different // HTTP version or if the resource request was to a non-default port. if (!m_documentLoader->response().isHttpVersion0_9()) { String message = "Cancelled resource load from '" + url.string() + "' because it is using HTTP/0.9 and the document was loaded with a different HTTP version."; m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier()); ResourceError error(emptyString(), 0, url, message); didFail(error); return; } if (!isDefaultPortForProtocol(url.port(), url.protocol())) { String message = "Cancelled resource load from '" + url.string() + "' because it is using HTTP/0.9 on a non-default port."; m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier()); ResourceError error(emptyString(), 0, url, message); didFail(error); return; } String message = "Sandboxing '" + m_response.url().string() + "' because it is using HTTP/0.9."; m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, m_identifier); frameLoader()->forceSandboxFlags(SandboxScripts | SandboxPlugins); } if (FormData* data = m_request.httpBody()) data->removeGeneratedFilesIfNeeded(); if (m_options.sendLoadCallbacks() == SendCallbacks) frameLoader()->notifier().didReceiveResponse(this, m_response); }
SecurityOrigin::SecurityOrigin(const KUrl& url) : m_protocol(url.protocol().toLower()) , m_host(url.host().toLower()) , m_port(url.port()) , m_domainWasSetInDOM(false) , m_isUnique(false) { // These protocols do not create security origins; the owner frame provides the origin if (m_protocol == "about" || m_protocol == "javascript") m_protocol = ""; // For edge case URLs that were probably misparsed, make sure that the origin is unique. if (m_host.isEmpty() && KProtocolInfo::protocolClass(m_protocol) == QLatin1String(":internet")) m_isUnique = true; // document.domain starts as m_host, but can be set by the DOM. m_domain = m_host; if (url.port() == -1 || isDefaultPortForProtocol(m_port, m_protocol)) m_port = 0; }
SecurityOrigin::SecurityOrigin(const KURL& url) : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) , m_host(url.host().isNull() ? "" : url.host().lower()) , m_port(url.port()) , m_isUnique(false) , m_universalAccess(false) , m_domainWasSetInDOM(false) , m_enforceFilePathSeparation(false) , m_needsDatabaseIdentifierQuirkForFiles(false) { // document.domain starts as m_host, but can be set by the DOM. m_domain = m_host; if (isDefaultPortForProtocol(m_port, m_protocol)) m_port = InvalidPort; // By default, only local SecurityOrigins can load local resources. m_canLoadLocalResources = isLocal(); if (m_canLoadLocalResources) m_filePath = url.path(); // In case enforceFilePathSeparation() is called. }
SecurityOrigin::SecurityOrigin(const KURL& url) : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) , m_host(url.host().isNull() ? "" : url.host().lower()) , m_port(url.port()) , m_noAccess(false) , m_domainWasSetInDOM(false) { // These protocols do not create security origins; the owner frame provides the origin if (m_protocol == "about" || m_protocol == "javascript") m_protocol = ""; // data: URLs are not allowed access to anything other than themselves. if (m_protocol == "data") m_noAccess = true; // document.domain starts as m_host, but can be set by the DOM. m_domain = m_host; // By default, only local SecurityOrigins can load local resources. m_canLoadLocalResources = isLocal(); if (isDefaultPortForProtocol(m_port, m_protocol)) m_port = 0; }
BlockedStatus ContentExtensionsBackend::processContentExtensionRulesForLoad(const URL& url, ResourceType resourceType, DocumentLoader& initiatingDocumentLoader) { if (m_contentExtensions.isEmpty()) return { }; Document* currentDocument = nullptr; URL mainDocumentURL; if (Frame* frame = initiatingDocumentLoader.frame()) { currentDocument = frame->document(); if (initiatingDocumentLoader.isLoadingMainResource() && frame->isMainFrame() && resourceType == ResourceType::Document) mainDocumentURL = url; else if (Document* mainDocument = frame->mainFrame().document()) mainDocumentURL = mainDocument->url(); } ResourceLoadInfo resourceLoadInfo = { url, mainDocumentURL, resourceType }; Vector<ContentExtensions::Action> actions = actionsForResourceLoad(resourceLoadInfo); bool willBlockLoad = false; bool willBlockCookies = false; bool willMakeHTTPS = false; for (const auto& action : actions) { switch (action.type()) { case ContentExtensions::ActionType::BlockLoad: willBlockLoad = true; break; case ContentExtensions::ActionType::BlockCookies: willBlockCookies = true; break; case ContentExtensions::ActionType::CSSDisplayNoneSelector: if (resourceType == ResourceType::Document) initiatingDocumentLoader.addPendingContentExtensionDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID()); else if (currentDocument) currentDocument->extensionStyleSheets().addDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID()); break; case ContentExtensions::ActionType::CSSDisplayNoneStyleSheet: { StyleSheetContents* styleSheetContents = globalDisplayNoneStyleSheet(action.stringArgument()); if (styleSheetContents) { if (resourceType == ResourceType::Document) initiatingDocumentLoader.addPendingContentExtensionSheet(action.stringArgument(), *styleSheetContents); else if (currentDocument) currentDocument->extensionStyleSheets().maybeAddContentExtensionSheet(action.stringArgument(), *styleSheetContents); } break; } case ContentExtensions::ActionType::MakeHTTPS: { if ((url.protocolIs("http") || url.protocolIs("ws")) && (!url.port() || isDefaultPortForProtocol(url.port().value(), url.protocol()))) willMakeHTTPS = true; break; } case ContentExtensions::ActionType::IgnorePreviousRules: case ContentExtensions::ActionType::InvalidAction: RELEASE_ASSERT_NOT_REACHED(); } } if (currentDocument) { if (willMakeHTTPS) { ASSERT(url.protocolIs("http") || url.protocolIs("ws")); String newProtocol = url.protocolIs("http") ? ASCIILiteral("https") : ASCIILiteral("wss"); currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker promoted URL from ", url.string(), " to ", newProtocol)); } if (willBlockLoad) currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker prevented frame displaying ", mainDocumentURL.string(), " from loading a resource from ", url.string())); } return { willBlockLoad, willBlockCookies, willMakeHTTPS }; }
BlockedStatus ContentExtensionsBackend::processContentExtensionRulesForLoad(ResourceRequest& request, ResourceType resourceType, DocumentLoader& initiatingDocumentLoader) { Document* currentDocument = nullptr; URL mainDocumentURL; if (Frame* frame = initiatingDocumentLoader.frame()) { currentDocument = frame->document(); if (initiatingDocumentLoader.isLoadingMainResource() && frame->isMainFrame() && resourceType == ResourceType::Document) mainDocumentURL = request.url(); else if (Document* mainDocument = frame->mainFrame().document()) mainDocumentURL = mainDocument->url(); } ResourceLoadInfo resourceLoadInfo = { request.url(), mainDocumentURL, resourceType }; Vector<ContentExtensions::Action> actions = actionsForResourceLoad(resourceLoadInfo); bool willBlockLoad = false; for (const auto& action : actions) { switch (action.type()) { case ContentExtensions::ActionType::BlockLoad: willBlockLoad = true; break; case ContentExtensions::ActionType::BlockCookies: request.setAllowCookies(false); break; case ContentExtensions::ActionType::CSSDisplayNoneSelector: if (resourceType == ResourceType::Document) initiatingDocumentLoader.addPendingContentExtensionDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID()); else if (currentDocument) currentDocument->extensionStyleSheets().addDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID()); break; case ContentExtensions::ActionType::CSSDisplayNoneStyleSheet: { StyleSheetContents* styleSheetContents = globalDisplayNoneStyleSheet(action.stringArgument()); if (styleSheetContents) { if (resourceType == ResourceType::Document) initiatingDocumentLoader.addPendingContentExtensionSheet(action.stringArgument(), *styleSheetContents); else if (currentDocument) currentDocument->extensionStyleSheets().maybeAddContentExtensionSheet(action.stringArgument(), *styleSheetContents); } break; } case ContentExtensions::ActionType::MakeHTTPS: { const URL originalURL = request.url(); if (originalURL.protocolIs("http") && (!originalURL.hasPort() || isDefaultPortForProtocol(originalURL.port(), originalURL.protocol()))) { URL newURL = originalURL; newURL.setProtocol("https"); if (originalURL.hasPort()) newURL.setPort(defaultPortForProtocol("https")); request.setURL(newURL); if (resourceType == ResourceType::Document && initiatingDocumentLoader.isLoadingMainResource()) { // This is to make sure the correct 'new' URL shows in the location bar. initiatingDocumentLoader.request().setURL(newURL); initiatingDocumentLoader.frameLoader()->client().dispatchDidChangeProvisionalURL(); } if (currentDocument) currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker promoted URL from ", originalURL.string(), " to ", newURL.string())); } break; } case ContentExtensions::ActionType::IgnorePreviousRules: case ContentExtensions::ActionType::InvalidAction: RELEASE_ASSERT_NOT_REACHED(); } } if (willBlockLoad) { if (currentDocument) currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker prevented frame displaying ", mainDocumentURL.string(), " from loading a resource from ", request.url().string())); return BlockedStatus::Blocked; } return BlockedStatus::NotBlocked; }