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

Side by Side Diff: Source/core/dom/ScriptLoader.cpp

Issue 271533002: Make ScriptLoader into a ResourceOwner (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 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 | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserv ed. 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserv ed.
6 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> 6 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 #include "platform/MIMETypeRegistry.h" 47 #include "platform/MIMETypeRegistry.h"
48 #include "platform/weborigin/SecurityOrigin.h" 48 #include "platform/weborigin/SecurityOrigin.h"
49 #include "wtf/StdLibExtras.h" 49 #include "wtf/StdLibExtras.h"
50 #include "wtf/text/StringBuilder.h" 50 #include "wtf/text/StringBuilder.h"
51 #include "wtf/text/StringHash.h" 51 #include "wtf/text/StringHash.h"
52 52
53 namespace WebCore { 53 namespace WebCore {
54 54
55 ScriptLoader::ScriptLoader(Element* element, bool parserInserted, bool alreadySt arted) 55 ScriptLoader::ScriptLoader(Element* element, bool parserInserted, bool alreadySt arted)
56 : m_element(element) 56 : m_element(element)
57 , m_resource(0)
58 , m_startLineNumber(WTF::OrdinalNumber::beforeFirst()) 57 , m_startLineNumber(WTF::OrdinalNumber::beforeFirst())
59 , m_parserInserted(parserInserted) 58 , m_parserInserted(parserInserted)
60 , m_isExternalScript(false) 59 , m_isExternalScript(false)
61 , m_alreadyStarted(alreadyStarted) 60 , m_alreadyStarted(alreadyStarted)
62 , m_haveFiredLoad(false) 61 , m_haveFiredLoad(false)
63 , m_willBeParserExecuted(false) 62 , m_willBeParserExecuted(false)
64 , m_readyToBeParserExecuted(false) 63 , m_readyToBeParserExecuted(false)
65 , m_willExecuteWhenDocumentFinishedParsing(false) 64 , m_willExecuteWhenDocumentFinishedParsing(false)
66 , m_forceAsync(!parserInserted) 65 , m_forceAsync(!parserInserted)
67 , m_willExecuteInOrder(false) 66 , m_willExecuteInOrder(false)
68 { 67 {
69 ASSERT(m_element); 68 ASSERT(m_element);
70 if (parserInserted && element->document().scriptableDocumentParser() && !ele ment->document().isInDocumentWrite()) 69 if (parserInserted && element->document().scriptableDocumentParser() && !ele ment->document().isInDocumentWrite())
71 m_startLineNumber = element->document().scriptableDocumentParser()->line Number(); 70 m_startLineNumber = element->document().scriptableDocumentParser()->line Number();
72 } 71 }
73 72
74 ScriptLoader::~ScriptLoader() 73 ScriptLoader::~ScriptLoader()
75 { 74 {
76 stopLoadRequest();
77 } 75 }
78 76
79 void ScriptLoader::didNotifySubtreeInsertionsToDocument() 77 void ScriptLoader::didNotifySubtreeInsertionsToDocument()
80 { 78 {
81 if (!m_parserInserted) 79 if (!m_parserInserted)
82 prepareScript(); // FIXME: Provide a real starting line number here. 80 prepareScript(); // FIXME: Provide a real starting line number here.
83 } 81 }
84 82
85 void ScriptLoader::childrenChanged() 83 void ScriptLoader::childrenChanged()
86 { 84 {
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type) || isLegacySup portedJavaScriptLanguage(language)) 156 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type) || isLegacySup portedJavaScriptLanguage(language))
159 return true; 157 return true;
160 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSp ace()) || (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySuppo rtedJavaScriptLanguage(type))) { 158 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSp ace()) || (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySuppo rtedJavaScriptLanguage(type))) {
161 return true; 159 return true;
162 } 160 }
163 161
164 return false; 162 return false;
165 } 163 }
166 164
167 // http://dev.w3.org/html5/spec/Overview.html#prepare-a-script 165 // http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
168 bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy TypeSupport supportLegacyTypes) 166 bool ScriptLoader::prepareScript(ResourcePtr<ScriptResource>* fetchedResource, c onst TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes)
169 { 167 {
170 if (m_alreadyStarted) 168 if (m_alreadyStarted)
171 return false; 169 return false;
172 170
173 ScriptLoaderClient* client = this->client(); 171 ScriptLoaderClient* client = this->client();
174 172
175 bool wasParserInserted; 173 bool wasParserInserted;
176 if (m_parserInserted) { 174 if (m_parserInserted) {
177 wasParserInserted = true; 175 wasParserInserted = true;
178 m_parserInserted = false; 176 m_parserInserted = false;
(...skipping 29 matching lines...) Expand all
208 return false; 206 return false;
209 207
210 if (!isScriptForEventSupported()) 208 if (!isScriptForEventSupported())
211 return false; 209 return false;
212 210
213 if (!client->charsetAttributeValue().isEmpty()) 211 if (!client->charsetAttributeValue().isEmpty())
214 m_characterEncoding = client->charsetAttributeValue(); 212 m_characterEncoding = client->charsetAttributeValue();
215 else 213 else
216 m_characterEncoding = elementDocument.charset(); 214 m_characterEncoding = elementDocument.charset();
217 215
216 ResourcePtr<ScriptResource> resource;
218 if (client->hasSourceAttribute()) { 217 if (client->hasSourceAttribute()) {
219 if (!fetchScript(client->sourceAttributeValue())) 218 resource = fetchScript(client->sourceAttributeValue());
219 if (!resource) {
220 dispatchErrorEvent();
220 return false; 221 return false;
222 }
221 } 223 }
222 224
223 if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parse rInserted && !client->asyncAttributeValue()) { 225 if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parse rInserted && !client->asyncAttributeValue()) {
224 m_willExecuteWhenDocumentFinishedParsing = true; 226 m_willExecuteWhenDocumentFinishedParsing = true;
225 m_willBeParserExecuted = true; 227 m_willBeParserExecuted = true;
226 } else if (client->hasSourceAttribute() && m_parserInserted && !client->asyn cAttributeValue()) { 228 } else if (client->hasSourceAttribute() && m_parserInserted && !client->asyn cAttributeValue()) {
227 m_willBeParserExecuted = true; 229 m_willBeParserExecuted = true;
228 } else if (!client->hasSourceAttribute() && m_parserInserted && !elementDocu ment.isRenderingReady()) { 230 } else if (!client->hasSourceAttribute() && m_parserInserted && !elementDocu ment.isRenderingReady()) {
229 m_willBeParserExecuted = true; 231 m_willBeParserExecuted = true;
230 m_readyToBeParserExecuted = true; 232 m_readyToBeParserExecuted = true;
231 } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) { 233 } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) {
232 m_willExecuteInOrder = true; 234 m_willExecuteInOrder = true;
233 contextDocument->scriptRunner()->queueScriptForExecution(this, m_resourc e, ScriptRunner::IN_ORDER_EXECUTION); 235 contextDocument->scriptRunner()->queueScriptForExecution(this, resource, ScriptRunner::IN_ORDER_EXECUTION);
234 m_resource->addClient(this);
235 } else if (client->hasSourceAttribute()) { 236 } else if (client->hasSourceAttribute()) {
236 contextDocument->scriptRunner()->queueScriptForExecution(this, m_resourc e, ScriptRunner::ASYNC_EXECUTION); 237 contextDocument->scriptRunner()->queueScriptForExecution(this, resource, ScriptRunner::ASYNC_EXECUTION);
237 m_resource->addClient(this);
238 } else { 238 } else {
239 // Reset line numbering for nested writes. 239 // Reset line numbering for nested writes.
240 TextPosition position = elementDocument.isInDocumentWrite() ? TextPositi on() : scriptStartPosition; 240 TextPosition position = elementDocument.isInDocumentWrite() ? TextPositi on() : scriptStartPosition;
241 KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInsert ed) ? elementDocument.url() : KURL(); 241 KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInsert ed) ? elementDocument.url() : KURL();
242 executeScript(ScriptSourceCode(scriptContent(), scriptURL, position)); 242 executeScript(ScriptSourceCode(scriptContent(), scriptURL, position));
243 } 243 }
244 244
245 if (resource) {
246 // We have to return fetchedResource instead of let callers ask ScriptLo ader::resource()
247 // because resource() can be null when it is accessed: Following setReso urce() can trigger clearResource().
248 if (fetchedResource)
249 *fetchedResource = resource;
250 setResource(resource);
251 }
252
245 return true; 253 return true;
246 } 254 }
247 255
248 bool ScriptLoader::fetchScript(const String& sourceUrl) 256 ResourcePtr<ScriptResource> ScriptLoader::fetchScript(const String& sourceUrl)
249 { 257 {
250 ASSERT(m_element); 258 ASSERT(m_element);
251 259
252 RefPtr<Document> elementDocument(m_element->document()); 260 RefPtr<Document> elementDocument(m_element->document());
253 if (!m_element->inDocument() || m_element->document() != elementDocument) 261 if (!m_element->inDocument() || m_element->document() != elementDocument)
254 return false; 262 return ResourcePtr<ScriptResource>();
255 263
256 ASSERT(!m_resource); 264 ASSERT(!resource());
265 ResourcePtr<ScriptResource> resource;
257 if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) { 266 if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) {
258 FetchRequest request(ResourceRequest(elementDocument->completeURL(source Url)), m_element->localName()); 267 FetchRequest request(ResourceRequest(elementDocument->completeURL(source Url)), m_element->localName());
259 268
260 AtomicString crossOriginMode = m_element->fastGetAttribute(HTMLNames::cr ossoriginAttr); 269 AtomicString crossOriginMode = m_element->fastGetAttribute(HTMLNames::cr ossoriginAttr);
261 if (!crossOriginMode.isNull()) 270 if (!crossOriginMode.isNull())
262 request.setCrossOriginAccessControl(elementDocument->securityOrigin( ), crossOriginMode); 271 request.setCrossOriginAccessControl(elementDocument->securityOrigin( ), crossOriginMode);
263 request.setCharset(scriptCharset()); 272 request.setCharset(scriptCharset());
264 273
265 bool isValidScriptNonce = elementDocument->contentSecurityPolicy()->allo wScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr)); 274 bool isValidScriptNonce = elementDocument->contentSecurityPolicy()->allo wScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr));
266 if (isValidScriptNonce) 275 if (isValidScriptNonce)
267 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); 276 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy);
268 277
269 m_resource = elementDocument->fetcher()->fetchScript(request); 278 resource = elementDocument->fetcher()->fetchScript(request);
270 m_isExternalScript = true; 279 m_isExternalScript = true;
271 } 280 }
272 281
273 if (m_resource) 282 return resource;
274 return true;
275
276 dispatchErrorEvent();
277 return false;
278 } 283 }
279 284
280 bool isHTMLScriptLoader(Element* element) 285 bool isHTMLScriptLoader(Element* element)
281 { 286 {
282 ASSERT(element); 287 ASSERT(element);
283 return isHTMLScriptElement(*element); 288 return isHTMLScriptElement(*element);
284 } 289 }
285 290
286 bool isSVGScriptLoader(Element* element) 291 bool isSVGScriptLoader(Element* element)
287 { 292 {
(...skipping 14 matching lines...) Expand all
302 return; 307 return;
303 308
304 LocalFrame* frame = contextDocument->frame(); 309 LocalFrame* frame = contextDocument->frame();
305 310
306 bool shouldBypassMainWorldContentSecurityPolicy = (frame && frame->script(). shouldBypassMainWorldContentSecurityPolicy()) || elementDocument->contentSecurit yPolicy()->allowScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr)) | | elementDocument->contentSecurityPolicy()->allowScriptHash(sourceCode.source()) ; 311 bool shouldBypassMainWorldContentSecurityPolicy = (frame && frame->script(). shouldBypassMainWorldContentSecurityPolicy()) || elementDocument->contentSecurit yPolicy()->allowScriptNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr)) | | elementDocument->contentSecurityPolicy()->allowScriptHash(sourceCode.source()) ;
307 312
308 if (!m_isExternalScript && (!shouldBypassMainWorldContentSecurityPolicy && ! elementDocument->contentSecurityPolicy()->allowInlineScript(elementDocument->url (), m_startLineNumber))) 313 if (!m_isExternalScript && (!shouldBypassMainWorldContentSecurityPolicy && ! elementDocument->contentSecurityPolicy()->allowInlineScript(elementDocument->url (), m_startLineNumber)))
309 return; 314 return;
310 315
311 if (m_isExternalScript) { 316 if (m_isExternalScript) {
312 ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.re source(); 317 ScriptResource* resource = this->resource() ? this->resource() : sourceC ode.resource();
313 if (resource && !resource->mimeTypeAllowedByNosniff()) { 318 if (resource && !resource->mimeTypeAllowedByNosniff()) {
314 contextDocument->addConsoleMessage(SecurityMessageSource, ErrorMessa geLevel, "Refused to execute script from '" + resource->url().elidedString() + " ' because its MIME type ('" + resource->mimeType() + "') is not executable, and strict MIME type checking is enabled."); 319 contextDocument->addConsoleMessage(SecurityMessageSource, ErrorMessa geLevel, "Refused to execute script from '" + resource->url().elidedString() + " ' because its MIME type ('" + resource->mimeType() + "') is not executable, and strict MIME type checking is enabled.");
315 return; 320 return;
316 } 321 }
317 } 322 }
318 323
319 if (frame) { 324 if (frame) {
320 const bool isImportedScript = contextDocument != elementDocument; 325 const bool isImportedScript = contextDocument != elementDocument;
321 // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script -block step 2.3 326 // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script -block step 2.3
322 // with additional support for HTML imports. 327 // with additional support for HTML imports.
(...skipping 11 matching lines...) Expand all
334 // Note: This is where the script is compiled and actually executed. 339 // Note: This is where the script is compiled and actually executed.
335 frame->script().executeScriptInMainWorld(sourceCode, corsCheck); 340 frame->script().executeScriptInMainWorld(sourceCode, corsCheck);
336 341
337 if (isHTMLScriptLoader(m_element)) { 342 if (isHTMLScriptLoader(m_element)) {
338 ASSERT(contextDocument->currentScript() == m_element); 343 ASSERT(contextDocument->currentScript() == m_element);
339 contextDocument->popCurrentScript(); 344 contextDocument->popCurrentScript();
340 } 345 }
341 } 346 }
342 } 347 }
343 348
344 void ScriptLoader::stopLoadRequest()
345 {
346 if (m_resource) {
347 if (!m_willBeParserExecuted)
348 m_resource->removeClient(this);
349 m_resource = 0;
350 }
351 }
352
353 void ScriptLoader::execute(ScriptResource* resource) 349 void ScriptLoader::execute(ScriptResource* resource)
354 { 350 {
355 ASSERT(!m_willBeParserExecuted); 351 ASSERT(!m_willBeParserExecuted);
356 ASSERT(resource); 352 ASSERT(resource);
357 if (resource->errorOccurred()) { 353 if (resource->errorOccurred()) {
358 dispatchErrorEvent(); 354 dispatchErrorEvent();
359 } else if (!resource->wasCanceled()) { 355 } else if (!resource->wasCanceled()) {
360 executeScript(ScriptSourceCode(resource)); 356 executeScript(ScriptSourceCode(resource));
361 dispatchLoadEvent(); 357 dispatchLoadEvent();
362 } 358 }
363 resource->removeClient(this); 359
360 clearResource();
364 } 361 }
365 362
366 void ScriptLoader::cancel(Document* contextDocument) 363 void ScriptLoader::cancel(Document* contextDocument)
367 { 364 {
368 if (!m_resource) 365 if (!resource())
369 return; 366 return;
370 finishLoading(contextDocument, FinishWithCancel); 367 finishLoading(contextDocument, FinishWithCancel);
371 } 368 }
372 369
373 void ScriptLoader::notifyFinished(Resource* resource) 370 void ScriptLoader::notifyFinished(Resource* resource)
374 { 371 {
375 // Resource possibly invokes this notifyFinished() more than 372 // Resource possibly invokes this notifyFinished() more than
376 // once because ScriptLoader doesn't unsubscribe itself from 373 // once because ScriptLoader doesn't unsubscribe itself from
377 // Resource here and does it in execute() instead. 374 // Resource here and does it in execute() instead.
378 // We use m_resource to check if this function is already called. 375 // We use resource() to check if this function is already called.
379 ASSERT_UNUSED(resource, resource == m_resource); 376 ASSERT_UNUSED(resource, resource == this->resource());
380 if (!m_resource) 377 if (!this->resource())
381 return; 378 return;
382 379
380 RefPtr<Element> protect(m_element);
383 RefPtr<Document> elementDocument(m_element->document()); 381 RefPtr<Document> elementDocument(m_element->document());
384 RefPtr<Document> contextDocument = elementDocument->contextDocument().get(); 382 RefPtr<Document> contextDocument = elementDocument->contextDocument().get();
385 finishLoading(contextDocument.get(), resource->errorOccurred() ? FinishWithE rror : FinishSuccessfully); 383 finishLoading(contextDocument.get(), resource->errorOccurred() ? FinishWithE rror : FinishSuccessfully);
386 } 384 }
387 385
388 void ScriptLoader::finishLoading(Document* contextDocument, ScriptLoader::Finish Type type) 386 void ScriptLoader::finishLoading(Document* contextDocument, ScriptLoader::Finish Type type)
389 { 387 {
390 if (!contextDocument) 388 if (!m_willBeParserExecuted && contextDocument)
391 return; 389 notifyRunnerFinishLoading(contextDocument->scriptRunner(), type);
390 clearResource();
391 }
392 392
393 void ScriptLoader::notifyRunnerFinishLoading(ScriptRunner* runner, ScriptLoader: :FinishType type)
394 {
393 switch (type) { 395 switch (type) {
394 case FinishWithCancel: 396 case FinishWithCancel:
395 if (!m_willBeParserExecuted) 397 runner->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner: :IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION);
396 contextDocument->scriptRunner()->notifyScriptLoadError(this, m_willE xecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION );
397 stopLoadRequest();
398 break; 398 break;
399 case FinishWithError: 399 case FinishWithError:
400 ASSERT(!m_willBeParserExecuted);
401 dispatchErrorEvent(); 400 dispatchErrorEvent();
402 contextDocument->scriptRunner()->notifyScriptLoadError(this, m_willExecu teInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); 401 runner->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner: :IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION);
403 m_resource = 0;
404 break; 402 break;
405 case FinishSuccessfully: 403 case FinishSuccessfully:
406 ASSERT(!m_willBeParserExecuted); 404 runner->notifyScriptReady(this, m_willExecuteInOrder ? ScriptRunner::IN_ ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION);
407 contextDocument->scriptRunner()->notifyScriptReady(this, m_willExecuteIn Order ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION);
408 m_resource = 0;
409 break; 405 break;
410 } 406 }
411 } 407 }
412 408
409
Nate Chapin 2014/05/07 18:13:10 Nit: Remove this line.
413 bool ScriptLoader::ignoresLoadRequest() const 410 bool ScriptLoader::ignoresLoadRequest() const
414 { 411 {
415 return m_alreadyStarted || m_isExternalScript || m_parserInserted || !elemen t() || !element()->inDocument(); 412 return m_alreadyStarted || m_isExternalScript || m_parserInserted || !elemen t() || !element()->inDocument();
416 } 413 }
417 414
418 bool ScriptLoader::isScriptForEventSupported() const 415 bool ScriptLoader::isScriptForEventSupported() const
419 { 416 {
420 String eventAttribute = client()->eventAttributeValue(); 417 String eventAttribute = client()->eventAttributeValue();
421 String forAttribute = client()->forAttributeValue(); 418 String forAttribute = client()->forAttributeValue();
422 if (!eventAttribute.isEmpty() && !forAttribute.isEmpty()) { 419 if (!eventAttribute.isEmpty() && !forAttribute.isEmpty()) {
(...skipping 30 matching lines...) Expand all
453 if (isHTMLScriptLoader(element)) 450 if (isHTMLScriptLoader(element))
454 return toHTMLScriptElement(element)->loader(); 451 return toHTMLScriptElement(element)->loader();
455 452
456 if (isSVGScriptLoader(element)) 453 if (isSVGScriptLoader(element))
457 return toSVGScriptElement(element)->loader(); 454 return toSVGScriptElement(element)->loader();
458 455
459 return 0; 456 return 0;
460 } 457 }
461 458
462 } 459 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698