Chromium Code Reviews| Index: Source/core/loader/DocumentThreadableLoader.cpp |
| diff --git a/Source/core/loader/DocumentThreadableLoader.cpp b/Source/core/loader/DocumentThreadableLoader.cpp |
| index 74bf523ccfafd5dd70bdf8d83fee6171c90a7c4e..fd200356acbd5ff3f971bdcdd06654072ba7a22a 100644 |
| --- a/Source/core/loader/DocumentThreadableLoader.cpp |
| +++ b/Source/core/loader/DocumentThreadableLoader.cpp |
| @@ -100,7 +100,10 @@ DocumentThreadableLoader::DocumentThreadableLoader(Document& document, Threadabl |
| ASSERT(m_async || request.httpReferrer().isEmpty()); |
| if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { |
| - m_client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are not supported.")); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are not supported.")); |
| + // |this| may be dead here. |
| return; |
| } |
| @@ -158,13 +161,17 @@ void DocumentThreadableLoader::dispatchInitialRequest(const ResourceRequest& req |
| void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceRequest& request) |
| { |
| ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); |
| + ASSERT(!resource()); |
| // Cross-origin requests are only allowed certain registered schemes. |
| // We would catch this when checking response headers later, but there |
| // is no reason to send a request, preflighted or not, that's guaranteed |
| // to be denied. |
| if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())) { |
| - m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are only supported for protocol schemes: " + SchemeRegistry::listOfCORSEnabledURLSchemes() + ".")); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are only supported for protocol schemes: " + SchemeRegistry::listOfCORSEnabledURLSchemes() + ".")); |
| + // |this| may be dead here. |
| return; |
| } |
| @@ -232,8 +239,6 @@ void DocumentThreadableLoader::cancel() |
| void DocumentThreadableLoader::cancelWithError(const ResourceError& error) |
| { |
| - RefPtr<DocumentThreadableLoader> protect(this); |
| - |
| // Cancel can re-enter and m_resource might be null here as a result. |
| if (m_client && resource()) { |
| ResourceError errorForCallback = error; |
| @@ -242,11 +247,14 @@ void DocumentThreadableLoader::cancelWithError(const ResourceError& error) |
| errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resource()->url().string(), "Load cancelled"); |
| errorForCallback.setIsCancellation(true); |
| } |
| - m_client->didFail(errorForCallback); |
| + |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFail(errorForCallback); |
| + // |this| may be dead here. |
| + } else { |
| + clear(); |
| } |
| - clearResource(); |
| - m_client = 0; |
| - m_requestStartedSeconds = 0.0; |
| } |
| void DocumentThreadableLoader::setDefersLoading(bool value) |
| @@ -255,6 +263,18 @@ void DocumentThreadableLoader::setDefersLoading(bool value) |
| resource()->setDefersLoading(value); |
| } |
| +void DocumentThreadableLoader::clear() |
| +{ |
| + m_client = 0; |
| + |
| + if (!m_async) |
| + return; |
| + |
| + clearResource(); |
| + m_timeoutTimer.stop(); |
| + m_requestStartedSeconds = 0.0; |
| +} |
| + |
| // In this method, we can clear |request| to tell content::WebURLLoaderImpl of |
| // Chromium not to follow the redirect. This works only when this method is |
| // called by RawResource::willSendRequest(). If called by |
| @@ -270,12 +290,13 @@ void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ |
| RefPtr<DocumentThreadableLoader> protect(this); |
| if (!isAllowedByContentSecurityPolicy(request.url(), ContentSecurityPolicy::DidRedirect)) { |
| - m_client->didFailRedirectCheck(); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailRedirectCheck(); |
| + // |this| may be dead here. |
| - clearResource(); |
| request = ResourceRequest(); |
| - m_requestStartedSeconds = 0.0; |
| return; |
| } |
| @@ -287,7 +308,10 @@ void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ |
| } |
| if (m_corsRedirectLimit <= 0) { |
| - m_client->didFailRedirectCheck(); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailRedirectCheck(); |
| + // |this| may be dead here. |
| } else if (m_options.crossOriginRequestPolicy == UseAccessControl) { |
| --m_corsRedirectLimit; |
| @@ -338,16 +362,18 @@ void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ |
| return; |
| } |
| - ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url().string(), accessControlErrorDescription); |
| - m_client->didFailAccessControlCheck(error); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, redirectResponse.url().string(), accessControlErrorDescription)); |
| + // |this| may be dead here. |
| } else { |
| - m_client->didFailRedirectCheck(); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailRedirectCheck(); |
| + // |this| may be dead here. |
| } |
| - clearResource(); |
| request = ResourceRequest(); |
| - |
| - m_requestStartedSeconds = 0.0; |
| } |
| void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) |
| @@ -468,7 +494,11 @@ void DocumentThreadableLoader::handleResponse(unsigned long identifier, const Re |
| String accessControlErrorDescription; |
| if (!passesAccessControlCheck(response, effectiveAllowCredentials(), securityOrigin(), accessControlErrorDescription)) { |
| reportResponseReceived(identifier, response); |
| - m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, response.url().string(), accessControlErrorDescription)); |
| + |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, response.url().string(), accessControlErrorDescription)); |
| + // |this| may be dead here. |
| return; |
| } |
| } |
| @@ -513,12 +543,15 @@ void DocumentThreadableLoader::notifyFinished(Resource* resource) |
| ASSERT(resource == this->resource()); |
| ASSERT(m_async); |
| - m_timeoutTimer.stop(); |
| - |
| - if (resource->errorOccurred()) |
| - m_client->didFail(resource->resourceError()); |
| - else |
| + if (resource->errorOccurred()) { |
| + ThreadableLoaderClient* client = m_client; |
| + ResourceError error = resource->resourceError(); |
| + clear(); |
| + client->didFail(error); |
| + // |this| may be dead here. |
| + } else { |
| handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime()); |
|
hiroshige
2015/08/03 13:22:19
m_timeoutTimer.stop() is not executed in this bran
tyoshino (SeeGerritForStatus)
2015/08/04 08:32:05
handleSuccessfulFinish does it. If it's just compl
hiroshige
2015/08/04 10:20:16
I see, thanks.
|
| + } |
| } |
| void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier, double finishTime) |
| @@ -530,9 +563,14 @@ void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier, |
| ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); |
| loadActualRequest(); |
| } else { |
| - // FIXME: Should prevent timeout from being overridden after finished loading, without |
| - // resetting m_requestStartedSeconds to 0.0 |
| - m_client->didFinishLoading(identifier, finishTime); |
| + ThreadableLoaderClient* client = m_client; |
| + m_client = 0; |
| + if (m_async) { |
| + m_timeoutTimer.stop(); |
| + m_requestStartedSeconds = 0.0; |
| + } |
| + client->didFinishLoading(identifier, finishTime); |
| + // |this| may be dead here. |
| } |
| } |
| @@ -576,9 +614,10 @@ void DocumentThreadableLoader::handlePreflightFailure(const String& url, const S |
| // Prevent handleSuccessfulFinish() from bypassing access check. |
| m_actualRequest = nullptr; |
| - // FIXME: Should prevent timeout from being overridden after preflight failure, without |
| - // resetting m_requestStartedSeconds to 0.0 |
| - m_client->didFailAccessControlCheck(error); |
| + ThreadableLoaderClient* client = m_client; |
| + clear(); |
| + client->didFailAccessControlCheck(error); |
| + // |this| may be dead here. |
| } |
| void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, ResourceLoaderOptions resourceLoaderOptions) |
| @@ -646,6 +685,14 @@ void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou |
| handleResponse(identifier, response, nullptr); |
| + // handleResponse() may detect an error. In such a case (check |m_client| |
| + // as it gets reset by clear() call), skip the rest. |
| + // |
| + // |this| is alive here since loadResourceSynchronously() keeps it alive |
| + // until the end of the function. |
| + if (!m_client) |
| + return; |
| + |
| SharedBuffer* data = resource->resourceBuffer(); |
| if (data) |
| handleReceivedData(data->data(), data->size()); |