Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Side by Side Diff: third_party/WebKit/Source/core/fetch/ResourceLoader.cpp

Issue 1923003002: Clear Resource::m_loader in Resource::finish() and Resource::error() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix ResourceFetchertest.RevalidateWhileFinishingLoading memory leak Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved.
3 * (C) 2007 Graham Dennis (graham.dennis@gmail.com) 3 * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 visitor->trace(m_resource); 73 visitor->trace(m_resource);
74 } 74 }
75 75
76 void ResourceLoader::releaseResources() 76 void ResourceLoader::releaseResources()
77 { 77 {
78 ASSERT(m_state != ConnectionStateReleased); 78 ASSERT(m_state != ConnectionStateReleased);
79 ASSERT(m_notifiedLoadComplete); 79 ASSERT(m_notifiedLoadComplete);
80 m_fetcher->didLoadResource(m_resource.get()); 80 m_fetcher->didLoadResource(m_resource.get());
81 if (m_state == ConnectionStateReleased) 81 if (m_state == ConnectionStateReleased)
82 return; 82 return;
83 m_resource->clearLoader();
84 m_resource = nullptr; 83 m_resource = nullptr;
85 84
86 ASSERT(m_state != ConnectionStateReleased); 85 ASSERT(m_state != ConnectionStateReleased);
87 m_state = ConnectionStateReleased; 86 m_state = ConnectionStateReleased;
88 if (m_loader) { 87 if (m_loader) {
89 m_loader->cancel(); 88 m_loader->cancel();
90 m_loader.clear(); 89 m_loader.clear();
91 } 90 }
92 m_fetcher.clear(); 91 m_fetcher.clear();
93 } 92 }
(...skipping 28 matching lines...) Expand all
122 RELEASE_ASSERT(m_state == ConnectionStateReceivedResponse); 121 RELEASE_ASSERT(m_state == ConnectionStateReceivedResponse);
123 m_fetcher->didDownloadData(m_resource.get(), length, encodedDataLength); 122 m_fetcher->didDownloadData(m_resource.get(), length, encodedDataLength);
124 if (m_state == ConnectionStateReleased) 123 if (m_state == ConnectionStateReleased)
125 return; 124 return;
126 m_resource->didDownloadData(length); 125 m_resource->didDownloadData(length);
127 } 126 }
128 127
129 void ResourceLoader::didFinishLoadingOnePart(double finishTime, int64_t encodedD ataLength) 128 void ResourceLoader::didFinishLoadingOnePart(double finishTime, int64_t encodedD ataLength)
130 { 129 {
131 ASSERT(m_state != ConnectionStateReleased); 130 ASSERT(m_state != ConnectionStateReleased);
132 if (isFinishing()) { 131 if (m_state == ConnectionStateFinishedLoading) {
133 m_fetcher->removeResourceLoader(this); 132 m_fetcher->removeResourceLoader(this);
134 } else { 133 } else {
135 // When loading a multipart resource, make the loader non-block when 134 // When loading a multipart resource, make the loader non-block when
136 // finishing loading the first part. 135 // finishing loading the first part.
137 m_fetcher->moveResourceLoaderToNonBlocking(this); 136 m_fetcher->moveResourceLoaderToNonBlocking(this);
138 137
139 m_fetcher->didLoadResource(m_resource.get()); 138 m_fetcher->didLoadResource(m_resource.get());
140 if (m_state == ConnectionStateReleased) 139 if (m_state == ConnectionStateReleased)
141 return; 140 return;
142 } 141 }
143 142
144 if (m_notifiedLoadComplete) 143 if (m_notifiedLoadComplete)
145 return; 144 return;
146 m_notifiedLoadComplete = true; 145 m_notifiedLoadComplete = true;
147 m_fetcher->didFinishLoading(m_resource.get(), finishTime, encodedDataLength) ; 146 m_fetcher->didFinishLoading(m_resource.get(), finishTime, encodedDataLength) ;
148 } 147 }
149 148
150 void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority, int in traPriorityValue) 149 void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority, int in traPriorityValue)
151 { 150 {
152 ASSERT(m_state != ConnectionStateReleased); 151 ASSERT(m_state != ConnectionStateReleased);
153 if (m_loader) 152 if (m_loader)
154 m_loader->didChangePriority(static_cast<WebURLRequest::Priority>(loadPri ority), intraPriorityValue); 153 m_loader->didChangePriority(static_cast<WebURLRequest::Priority>(loadPri ority), intraPriorityValue);
155 } 154 }
156 155
157 void ResourceLoader::cancelIfNotFinishing()
158 {
159 if (isFinishing())
160 return;
161 cancel();
162 }
163
164 void ResourceLoader::cancel() 156 void ResourceLoader::cancel()
165 { 157 {
166 cancel(ResourceError()); 158 cancel(ResourceError());
167 } 159 }
168 160
169 void ResourceLoader::cancel(const ResourceError& error) 161 void ResourceLoader::cancel(const ResourceError& error)
170 { 162 {
171 // If the load has already completed - succeeded, failed, or previously canc elled - do nothing. 163 ASSERT(m_state != ConnectionStateFinishedLoading);
172 if (m_state == ConnectionStateReleased) 164 ASSERT(m_state != ConnectionStateReleased);
173 return;
174 if (isFinishing()) {
175 releaseResources();
176 return;
177 }
178
179 ResourceError nonNullError = error.isNull() ? ResourceError::cancelledError( m_resource->lastResourceRequest().url()) : error;
180
181 WTF_LOG(ResourceLoading, "Cancelled load of '%s'.\n", m_resource->url().getS tring().latin1().data());
182 m_state = ConnectionStateCanceled;
183 m_resource->setResourceError(nonNullError);
184 165
185 // If we don't immediately clear m_loader when cancelling, we might get 166 // If we don't immediately clear m_loader when cancelling, we might get
186 // unexpected reentrancy. m_resource->error() can trigger JS events, which 167 // unexpected reentrancy. m_resource->error() can trigger JS events, which
187 // could start a modal dialog. Normally, a modal dialog would defer loading 168 // could start a modal dialog. Normally, a modal dialog would defer loading
188 // and prevent receiving messages for a cancelled ResourceLoader, but 169 // and prevent receiving messages for a cancelled ResourceLoader, but
189 // m_fetcher->didFailLoading() severs the connection by which all of a 170 // m_fetcher->didFailLoading() severs the connection by which all of a
190 // page's loads are deferred. A response can then arrive, see m_state 171 // page's loads are deferred. A response can then arrive, see m_state
191 // is ConnectionStateCanceled, and ASSERT or break in other ways. 172 // is ConnectionStateFinishedLoading, and ASSERT or break in other ways.
192 if (m_loader) { 173 if (m_loader) {
193 m_loader->cancel(); 174 m_loader->cancel();
194 m_loader.clear(); 175 m_loader.clear();
195 } 176 }
196 177 didFail(nullptr, error.isNull() ? ResourceError::cancelledError(m_resource-> lastResourceRequest().url()) : error);
197 if (!m_notifiedLoadComplete) {
198 m_notifiedLoadComplete = true;
199 m_fetcher->didFailLoading(m_resource.get(), nonNullError);
200 }
201
202 if (m_state != ConnectionStateReleased)
203 m_resource->error(Resource::LoadError);
204 if (m_state != ConnectionStateReleased)
205 releaseResources();
206 } 178 }
207 179
208 void ResourceLoader::willFollowRedirect(WebURLLoader*, WebURLRequest& passedNewR equest, const WebURLResponse& passedRedirectResponse) 180 void ResourceLoader::willFollowRedirect(WebURLLoader*, WebURLRequest& passedNewR equest, const WebURLResponse& passedRedirectResponse)
209 { 181 {
210 ASSERT(m_state != ConnectionStateReleased); 182 ASSERT(m_state != ConnectionStateReleased);
211 ASSERT(!passedNewRequest.isNull()); 183 ASSERT(!passedNewRequest.isNull());
212 ASSERT(!passedRedirectResponse.isNull()); 184 ASSERT(!passedRedirectResponse.isNull());
213 185
214 ResourceRequest& newRequest(passedNewRequest.toMutableResourceRequest()); 186 ResourceRequest& newRequest(passedNewRequest.toMutableResourceRequest());
215 const ResourceResponse& redirectResponse(passedRedirectResponse.toResourceRe sponse()); 187 const ResourceResponse& redirectResponse(passedRedirectResponse.toResourceRe sponse());
216 newRequest.setFollowedRedirect(true); 188 newRequest.setFollowedRedirect(true);
217 189
218 if (m_fetcher->willFollowRedirect(m_resource.get(), newRequest, redirectResp onse)) { 190 if (m_fetcher->willFollowRedirect(m_resource.get(), newRequest, redirectResp onse)) {
219 m_resource->willFollowRedirect(newRequest, redirectResponse); 191 m_resource->willFollowRedirect(newRequest, redirectResponse);
220 } else { 192 } else {
221 m_resource->willNotFollowRedirect(); 193 m_resource->willNotFollowRedirect();
222 cancel(ResourceError::cancelledDueToAccessCheckError(newRequest.url())); 194 if (m_state != ConnectionStateReleased)
195 cancel(ResourceError::cancelledDueToAccessCheckError(newRequest.url( )));
223 } 196 }
224 } 197 }
225 198
226 void ResourceLoader::didReceiveCachedMetadata(WebURLLoader*, const char* data, i nt length) 199 void ResourceLoader::didReceiveCachedMetadata(WebURLLoader*, const char* data, i nt length)
227 { 200 {
228 RELEASE_ASSERT(m_state == ConnectionStateReceivedResponse || m_state == Conn ectionStateReceivingData); 201 RELEASE_ASSERT(m_state == ConnectionStateReceivedResponse || m_state == Conn ectionStateReceivingData);
229 m_resource->setSerializedCachedMetadata(data, length); 202 m_resource->setSerializedCachedMetadata(data, length);
230 } 203 }
231 204
232 void ResourceLoader::didSendData(WebURLLoader*, unsigned long long bytesSent, un signed long long totalBytesToBeSent) 205 void ResourceLoader::didSendData(WebURLLoader*, unsigned long long bytesSent, un signed long long totalBytesToBeSent)
(...skipping 30 matching lines...) Expand all
263 ResourceRequest request = m_resource->lastResourceRequest(); 236 ResourceRequest request = m_resource->lastResourceRequest();
264 ASSERT(!request.skipServiceWorker()); 237 ASSERT(!request.skipServiceWorker());
265 request.setSkipServiceWorker(true); 238 request.setSkipServiceWorker(true);
266 m_loader->loadAsynchronously(WrappedResourceRequest(request), th is); 239 m_loader->loadAsynchronously(WrappedResourceRequest(request), th is);
267 return; 240 return;
268 } 241 }
269 } else { 242 } else {
270 if (!m_resource->isCacheValidator() || resourceResponse.httpStatusCo de() != 304) 243 if (!m_resource->isCacheValidator() || resourceResponse.httpStatusCo de() != 304)
271 m_resource->setResponse(resourceResponse); 244 m_resource->setResponse(resourceResponse);
272 if (!m_fetcher->canAccessResource(m_resource.get(), m_resource->opti ons().securityOrigin.get(), response.url(), ResourceFetcher::ShouldLogAccessCont rolErrors)) { 245 if (!m_fetcher->canAccessResource(m_resource.get(), m_resource->opti ons().securityOrigin.get(), response.url(), ResourceFetcher::ShouldLogAccessCont rolErrors)) {
273 m_fetcher->didReceiveResponse(m_resource.get(), resourceResponse ); 246 m_fetcher->didReceiveResponse(m_resource.get(), resourceResponse );
yhirano 2016/05/02 12:38:45 Do we need |if (m_state != Released) | here?
Nate Chapin 2016/05/02 20:07:37 canAccessResource() doesn't cancel() the ResourceL
274 cancel(ResourceError::cancelledDueToAccessCheckError(KURL(respon se.url()))); 247 cancel(ResourceError::cancelledDueToAccessCheckError(KURL(respon se.url())));
275 return; 248 return;
276 } 249 }
277 } 250 }
278 } 251 }
279 252
280 m_resource->responseReceived(resourceResponse, handle.release()); 253 m_resource->responseReceived(resourceResponse, handle.release());
281 if (m_state == ConnectionStateReleased) 254 if (m_state == ConnectionStateReleased)
282 return; 255 return;
283 256
284 m_fetcher->didReceiveResponse(m_resource.get(), resourceResponse); 257 m_fetcher->didReceiveResponse(m_resource.get(), resourceResponse);
285 if (m_state == ConnectionStateReleased) 258 if (m_state == ConnectionStateReleased)
286 return; 259 return;
287 260
288 if (m_resource->response().httpStatusCode() < 400 || m_resource->shouldIgnor eHTTPStatusCodeErrors()) 261 if (m_resource->response().httpStatusCode() < 400 || m_resource->shouldIgnor eHTTPStatusCodeErrors())
289 return; 262 return;
290
291 if (!m_notifiedLoadComplete) {
292 m_notifiedLoadComplete = true;
293 m_fetcher->didFailLoading(m_resource.get(), ResourceError::cancelledErro r(resourceResponse.url()));
294 }
295
296 ASSERT(m_state != ConnectionStateReleased);
297 m_resource->error(Resource::LoadError);
298 cancel(ResourceError::cancelledError(resourceResponse.url())); 263 cancel(ResourceError::cancelledError(resourceResponse.url()));
299 } 264 }
300 265
301 void ResourceLoader::didReceiveResponse(WebURLLoader* loader, const WebURLRespon se& response) 266 void ResourceLoader::didReceiveResponse(WebURLLoader* loader, const WebURLRespon se& response)
302 { 267 {
303 didReceiveResponse(loader, response, nullptr); 268 didReceiveResponse(loader, response, nullptr);
304 } 269 }
305 270
306 void ResourceLoader::didReceiveData(WebURLLoader*, const char* data, int length, int encodedDataLength) 271 void ResourceLoader::didReceiveData(WebURLLoader*, const char* data, int length, int encodedDataLength)
307 { 272 {
(...skipping 10 matching lines...) Expand all
318 // Could be an issue with a giant local file. 283 // Could be an issue with a giant local file.
319 m_fetcher->didReceiveData(m_resource.get(), data, length, encodedDataLength) ; 284 m_fetcher->didReceiveData(m_resource.get(), data, length, encodedDataLength) ;
320 if (m_state == ConnectionStateReleased) 285 if (m_state == ConnectionStateReleased)
321 return; 286 return;
322 RELEASE_ASSERT(length >= 0); 287 RELEASE_ASSERT(length >= 0);
323 m_resource->appendData(data, length); 288 m_resource->appendData(data, length);
324 } 289 }
325 290
326 void ResourceLoader::didFinishLoading(WebURLLoader*, double finishTime, int64_t encodedDataLength) 291 void ResourceLoader::didFinishLoading(WebURLLoader*, double finishTime, int64_t encodedDataLength)
327 { 292 {
328
329 RELEASE_ASSERT(m_state == ConnectionStateReceivedResponse || m_state == Conn ectionStateReceivingData); 293 RELEASE_ASSERT(m_state == ConnectionStateReceivedResponse || m_state == Conn ectionStateReceivingData);
330 m_state = ConnectionStateFinishedLoading; 294 m_state = ConnectionStateFinishedLoading;
331 WTF_LOG(ResourceLoading, "Received '%s'.", m_resource->url().getString().lat in1().data());
332
333 m_resource->setLoadFinishTime(finishTime); 295 m_resource->setLoadFinishTime(finishTime);
334 didFinishLoadingOnePart(finishTime, encodedDataLength); 296 didFinishLoadingOnePart(finishTime, encodedDataLength);
335 if (m_state == ConnectionStateReleased)
336 return;
337 m_resource->finish(); 297 m_resource->finish();
hiroshige 2016/05/02 06:39:27 How about adding ASSERT(m_state != ConnectionState
Nate Chapin 2016/05/02 20:07:37 Done.
hiroshige 2016/05/10 10:22:48 Ack. (memo: ASSERT() after this line is not needed
338
339 // If the load has been cancelled by a delegate in response to didFinishLoad (), do not release
340 // the resources a second time, they have been released by cancel.
341 if (m_state == ConnectionStateReleased)
342 return;
343 releaseResources(); 298 releaseResources();
344 } 299 }
345 300
346 void ResourceLoader::didFail(WebURLLoader*, const WebURLError& error) 301 void ResourceLoader::didFail(WebURLLoader*, const WebURLError& error)
347 { 302 {
348 303 ASSERT(m_state != ConnectionStateFinishedLoading);
349 ASSERT(m_state != ConnectionStateReleased); 304 ASSERT(m_state != ConnectionStateReleased);
350 m_state = ConnectionStateFailed; 305 m_state = ConnectionStateFinishedLoading;
351 WTF_LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().getStri ng().latin1().data());
352
353 m_resource->setResourceError(error); 306 m_resource->setResourceError(error);
354 307 m_notifiedLoadComplete = true;
hiroshige 2016/05/02 06:39:27 How about adding ASSERT(!m_notifiedLoadComplete) b
Nate Chapin 2016/05/02 20:07:37 This isn't always the case as-is. It can be true h
hiroshige 2016/05/10 10:22:48 Hmm, so this CL adds ResourceFetcher::didFailLoadi
Nate Chapin 2016/05/10 18:26:17 The only non-test difference I see will be that th
hiroshige 2016/05/11 09:28:38 Sounds reasonable. Please mention briefly about th
Nate Chapin 2016/05/11 18:49:53 Done.
355 if (!m_notifiedLoadComplete) { 308 m_fetcher->didFailLoading(m_resource.get(), error);
356 m_notifiedLoadComplete = true;
357 m_fetcher->didFailLoading(m_resource.get(), error);
358 }
359 if (m_state == ConnectionStateReleased)
360 return;
361
362 m_resource->error(Resource::LoadError); 309 m_resource->error(Resource::LoadError);
hiroshige 2016/05/02 06:39:27 How about adding ASSERT(m_state != ConnectionState
Nate Chapin 2016/05/02 20:07:37 Done.
363
364 if (m_state == ConnectionStateReleased)
365 return;
366
367 releaseResources(); 310 releaseResources();
368 } 311 }
369 312
370 void ResourceLoader::requestSynchronously(ResourceRequest& request) 313 void ResourceLoader::requestSynchronously(ResourceRequest& request)
371 { 314 {
372 // downloadToFile is not supported for synchronous requests. 315 // downloadToFile is not supported for synchronous requests.
373 ASSERT(!request.downloadToFile()); 316 ASSERT(!request.downloadToFile());
374 ASSERT(m_loader); 317 ASSERT(m_loader);
375 318
376 // Synchronous requests should always be max priority, lest they hang the re nderer. 319 // Synchronous requests should always be max priority, lest they hang the re nderer.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 // empty buffer is a noop in most cases, but is destructive in the case of 351 // empty buffer is a noop in most cases, but is destructive in the case of
409 // a 304, where it will overwrite the cached data we should be reusing. 352 // a 304, where it will overwrite the cached data we should be reusing.
410 if (dataOut.size()) { 353 if (dataOut.size()) {
411 m_fetcher->didReceiveData(m_resource.get(), dataOut.data(), dataOut.size (), encodedDataLength); 354 m_fetcher->didReceiveData(m_resource.get(), dataOut.data(), dataOut.size (), encodedDataLength);
412 m_resource->setResourceBuffer(dataOut); 355 m_resource->setResourceBuffer(dataOut);
413 } 356 }
414 didFinishLoading(0, monotonicallyIncreasingTime(), encodedDataLength); 357 didFinishLoading(0, monotonicallyIncreasingTime(), encodedDataLength);
415 } 358 }
416 359
417 } // namespace blink 360 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698