diff options
Diffstat (limited to 'WebCore/loader/DocumentThreadableLoader.cpp')
-rw-r--r-- | WebCore/loader/DocumentThreadableLoader.cpp | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/WebCore/loader/DocumentThreadableLoader.cpp b/WebCore/loader/DocumentThreadableLoader.cpp index d0f6c04..16f114d 100644 --- a/WebCore/loader/DocumentThreadableLoader.cpp +++ b/WebCore/loader/DocumentThreadableLoader.cpp @@ -37,10 +37,12 @@ #include "Document.h" #include "Frame.h" #include "FrameLoader.h" +#include "ResourceHandle.h" #include "ResourceRequest.h" #include "SecurityOrigin.h" #include "SubresourceLoader.h" #include "ThreadableLoaderClient.h" +#include <wtf/UnusedParam.h> namespace WebCore { @@ -75,22 +77,25 @@ DocumentThreadableLoader::DocumentThreadableLoader(Document* document, Threadabl } if (m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { - m_client->didFail(ResourceError()); + m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are not supported.")); return; } ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); - if (!m_options.forcePreflight && isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())) - makeSimpleCrossOriginAccessRequest(request); + OwnPtr<ResourceRequest> crossOriginRequest(new ResourceRequest(request)); + crossOriginRequest->removeCredentials(); + crossOriginRequest->setAllowCookies(m_options.allowCredentials); + + if (!m_options.forcePreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields())) + makeSimpleCrossOriginAccessRequest(*crossOriginRequest); else { - m_actualRequest.set(new ResourceRequest(request)); - m_actualRequest->setAllowCookies(m_options.allowCredentials); + m_actualRequest = crossOriginRequest.release(); - if (CrossOriginPreflightResultCache::shared().canSkipPreflight(document->securityOrigin()->toString(), request.url(), m_options.allowCredentials, request.httpMethod(), request.httpHeaderFields())) + if (CrossOriginPreflightResultCache::shared().canSkipPreflight(document->securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials, m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields())) preflightSuccess(); else - makeCrossOriginAccessRequestWithPreflight(request); + makeCrossOriginAccessRequestWithPreflight(*m_actualRequest); } } @@ -100,14 +105,12 @@ void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const Resource // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. if (!request.url().protocolInHTTPFamily()) { - m_client->didFail(ResourceError()); + m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are only supported for HTTP.")); return; } // Make a copy of the passed request so that we can modify some details. ResourceRequest crossOriginRequest(request); - crossOriginRequest.removeCredentials(); - crossOriginRequest.setAllowCookies(m_options.allowCredentials); crossOriginRequest.setHTTPOrigin(m_document->securityOrigin()->toString()); loadRequest(crossOriginRequest, DoSecurityCheck); @@ -185,25 +188,26 @@ void DocumentThreadableLoader::didReceiveResponse(SubresourceLoader* loader, con ASSERT(m_client); ASSERT_UNUSED(loader, loader == m_loader); + String accessControlErrorDescription; if (m_actualRequest) { - if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin())) { - preflightFailure(); + if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin(), accessControlErrorDescription)) { + preflightFailure(response.url(), accessControlErrorDescription); return; } OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult(new CrossOriginPreflightResultCacheItem(m_options.allowCredentials)); - if (!preflightResult->parse(response) - || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod()) - || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields())) { - preflightFailure(); + if (!preflightResult->parse(response, accessControlErrorDescription) + || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod(), accessControlErrorDescription) + || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields(), accessControlErrorDescription)) { + preflightFailure(response.url(), accessControlErrorDescription); return; } CrossOriginPreflightResultCache::shared().appendEntry(m_document->securityOrigin()->toString(), m_actualRequest->url(), preflightResult.release()); } else { if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessControl) { - if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin())) { - m_client->didFail(ResourceError()); + if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin(), accessControlErrorDescription)) { + m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, response.url().string(), accessControlErrorDescription)); return; } } @@ -217,6 +221,10 @@ void DocumentThreadableLoader::didReceiveData(SubresourceLoader* loader, const c ASSERT(m_client); ASSERT_UNUSED(loader, loader == m_loader); + // Ignore response body of preflight requests. + if (m_actualRequest) + return; + m_client->didReceiveData(data, lengthReceived); } @@ -258,14 +266,20 @@ bool DocumentThreadableLoader::getShouldUseCredentialStorage(SubresourceLoader* return false; // Only FrameLoaderClient can ultimately permit credential use. } -void DocumentThreadableLoader::didReceiveAuthenticationChallenge(SubresourceLoader* loader, const AuthenticationChallenge&) +void DocumentThreadableLoader::didReceiveAuthenticationChallenge(SubresourceLoader* loader, const AuthenticationChallenge& challenge) { ASSERT(loader == m_loader); // Users are not prompted for credentials for cross-origin requests. if (!m_sameOriginRequest) { +#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) + loader->handle()->receivedRequestToContinueWithoutCredential(challenge); +#else + // These platforms don't provide a way to continue without credentials, cancel the load altogether. + UNUSED_PARAM(challenge); RefPtr<DocumentThreadableLoader> protect(this); m_client->didFail(loader->blockedError()); cancel(); +#endif } } @@ -285,14 +299,19 @@ void DocumentThreadableLoader::preflightSuccess() loadRequest(*actualRequest, SkipSecurityCheck); } -void DocumentThreadableLoader::preflightFailure() +void DocumentThreadableLoader::preflightFailure(const String& url, const String& errorDescription) { m_actualRequest = 0; // Prevent didFinishLoading() from bypassing access check. - m_client->didFail(ResourceError()); + m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, url, errorDescription)); } void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck) { + // Any credential should have been removed from the cross-site requests. + const KURL& requestURL = request.url(); + ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); + ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); + if (m_async) { // Don't sniff content or send load callbacks for the preflight request. bool sendLoadCallbacks = m_options.sendLoadCallbacks && !m_actualRequest; @@ -316,15 +335,15 @@ void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Secur // No exception for file:/// resources, see <rdar://problem/4962298>. // Also, if we have an HTTP response, then it wasn't a network error in fact. - if (!error.isNull() && !request.url().isLocalFile() && response.httpStatusCode() <= 0) { + if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode() <= 0) { m_client->didFail(error); return; } // FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was - // requested. - if (request.url() != response.url() && !isAllowedRedirect(response.url())) { + // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials. + if (requestURL != response.url() && !isAllowedRedirect(response.url())) { m_client->didFailRedirectCheck(); return; } |