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

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

Issue 2497873002: Tidy up ScriptLoader (MIME) type matching. (Closed)
Patch Set: perform case-insensitive equality checks over ASCII only Created 4 years, 1 month 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) 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 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights
6 * reserved. 6 * reserved.
7 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> 7 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 m_forceAsync = false; 122 m_forceAsync = false;
123 } 123 }
124 124
125 void ScriptLoader::detach() { 125 void ScriptLoader::detach() {
126 if (!m_pendingScript) 126 if (!m_pendingScript)
127 return; 127 return;
128 m_pendingScript->dispose(); 128 m_pendingScript->dispose();
129 m_pendingScript = nullptr; 129 m_pendingScript = nullptr;
130 } 130 }
131 131
132 // Helper function. Must take a lowercase language as input.
133 static bool isLegacySupportedJavaScriptLanguage(const String& language) { 132 static bool isLegacySupportedJavaScriptLanguage(const String& language) {
134 // Mozilla 1.8 accepts javascript1.0 - javascript1.7, but WinIE 7 accepts only 133 // Mozilla 1.8 accepts javascript1.0 - javascript1.7, but WinIE 7 accepts only
135 // javascript1.1 - javascript1.3. 134 // javascript1.1 - javascript1.3.
136 // Mozilla 1.8 and WinIE 7 both accept javascript and livescript. 135 // Mozilla 1.8 and WinIE 7 both accept javascript and livescript.
137 // WinIE 7 accepts ecmascript and jscript, but Mozilla 1.8 doesn't. 136 // WinIE 7 accepts ecmascript and jscript, but Mozilla 1.8 doesn't.
138 // Neither Mozilla 1.8 nor WinIE 7 accept leading or trailing whitespace. 137 // Neither Mozilla 1.8 nor WinIE 7 accept leading or trailing whitespace.
139 // We want to accept all the values that either of these browsers accept, but 138 // We want to accept all the values that either of these browsers accept, but
140 // not other values. 139 // not other values.
141 140
142 // FIXME: This function is not HTML5 compliant. These belong in the MIME 141 // FIXME: This function is not HTML5 compliant. These belong in the MIME
143 // registry as "text/javascript<version>" entries. 142 // registry as "text/javascript<version>" entries.
144 DCHECK_EQ(language, language.lower()); 143 return equalIgnoringASCIICase(language, "javascript") ||
145 return language == "javascript" || language == "javascript1.0" || 144 equalIgnoringASCIICase(language, "javascript1.0") ||
146 language == "javascript1.1" || language == "javascript1.2" || 145 equalIgnoringASCIICase(language, "javascript1.1") ||
147 language == "javascript1.3" || language == "javascript1.4" || 146 equalIgnoringASCIICase(language, "javascript1.2") ||
148 language == "javascript1.5" || language == "javascript1.6" || 147 equalIgnoringASCIICase(language, "javascript1.3") ||
149 language == "javascript1.7" || language == "livescript" || 148 equalIgnoringASCIICase(language, "javascript1.4") ||
150 language == "ecmascript" || language == "jscript"; 149 equalIgnoringASCIICase(language, "javascript1.5") ||
150 equalIgnoringASCIICase(language, "javascript1.6") ||
151 equalIgnoringASCIICase(language, "javascript1.7") ||
152 equalIgnoringASCIICase(language, "livescript") ||
153 equalIgnoringASCIICase(language, "ecmascript") ||
154 equalIgnoringASCIICase(language, "jscript");
151 } 155 }
152 156
153 void ScriptLoader::dispatchErrorEvent() { 157 void ScriptLoader::dispatchErrorEvent() {
154 m_element->dispatchEvent(Event::create(EventTypeNames::error)); 158 m_element->dispatchEvent(Event::create(EventTypeNames::error));
155 } 159 }
156 160
157 void ScriptLoader::dispatchLoadEvent() { 161 void ScriptLoader::dispatchLoadEvent() {
158 if (ScriptLoaderClient* client = this->client()) 162 if (ScriptLoaderClient* client = this->client())
159 client->dispatchLoadEvent(); 163 client->dispatchLoadEvent();
160 setHaveFiredLoadEvent(true); 164 setHaveFiredLoadEvent(true);
161 } 165 }
162 166
163 bool ScriptLoader::isValidScriptTypeAndLanguage( 167 bool ScriptLoader::isValidScriptTypeAndLanguage(
164 const String& type, 168 const String& type,
165 const String& language, 169 const String& language,
166 LegacyTypeSupport supportLegacyTypes) { 170 LegacyTypeSupport supportLegacyTypes) {
167 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used 171 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used
168 // here to maintain backwards compatibility with existing layout tests. The 172 // here to maintain backwards compatibility with existing layout tests. The
169 // specific violations are: 173 // specific violations are:
170 // - Allowing type=javascript. type= should only support MIME types, such as 174 // - Allowing type=javascript. type= should only support MIME types, such as
171 // text/javascript. 175 // text/javascript.
172 // - Allowing a different set of languages for language= and type=. language= 176 // - Allowing a different set of languages for language= and type=. language=
173 // supports Javascript 1.1 and 1.4-1.6, but type= does not. 177 // supports Javascript 1.1 and 1.4-1.6, but type= does not.
174 if (type.isEmpty()) { 178 if (type.isEmpty()) {
175 String lowerLanguage = language.lower(); 179 return language.isEmpty() || // assume text/javascript.
176 return language.isEmpty() // assume text/javascript. 180 MIMETypeRegistry::isSupportedJavaScriptMIMEType("text/" +
177 || MIMETypeRegistry::isSupportedJavaScriptMIMEType("text/" + 181 language) ||
178 lowerLanguage) || 182 isLegacySupportedJavaScriptLanguage(language);
179 isLegacySupportedJavaScriptLanguage(lowerLanguage);
180 } else if (RuntimeEnabledFeatures::moduleScriptsEnabled() && 183 } else if (RuntimeEnabledFeatures::moduleScriptsEnabled() &&
181 type == "module") { 184 type == "module") {
182 return true; 185 return true;
183 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType( 186 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(
184 type.stripWhiteSpace()) || 187 type.stripWhiteSpace()) ||
185 (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && 188 (supportLegacyTypes == AllowLegacyTypeInTypeAttribute &&
186 isLegacySupportedJavaScriptLanguage(type.lower()))) { 189 isLegacySupportedJavaScriptLanguage(type))) {
187 return true; 190 return true;
188 } 191 }
189 192
190 return false; 193 return false;
191 } 194 }
192 195
193 bool ScriptLoader::isScriptTypeSupported( 196 bool ScriptLoader::isScriptTypeSupported(
194 LegacyTypeSupport supportLegacyTypes) const { 197 LegacyTypeSupport supportLegacyTypes) const {
195 return isValidScriptTypeAndLanguage(client()->typeAttributeValue(), 198 return isValidScriptTypeAndLanguage(client()->typeAttributeValue(),
196 client()->languageAttributeValue(), 199 client()->languageAttributeValue(),
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 bool isHTMLScriptLoader(Element* element) { 397 bool isHTMLScriptLoader(Element* element) {
395 DCHECK(element); 398 DCHECK(element);
396 return isHTMLScriptElement(*element); 399 return isHTMLScriptElement(*element);
397 } 400 }
398 401
399 bool isSVGScriptLoader(Element* element) { 402 bool isSVGScriptLoader(Element* element) {
400 DCHECK(element); 403 DCHECK(element);
401 return isSVGScriptElement(*element); 404 return isSVGScriptElement(*element);
402 } 405 }
403 406
404 void ScriptLoader::logScriptMimetype(ScriptResource* resource, 407 void ScriptLoader::logScriptMIMEType(LocalFrame* frame,
405 LocalFrame* frame, 408 ScriptResource* resource,
406 String mimetype) { 409 const String& mimeType) {
407 String lowerMimetype = mimetype.lower(); 410 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType))
408 bool text = lowerMimetype.startsWith("text/");
409 bool application = lowerMimetype.startsWith("application/");
410 bool expectedJs =
411 MIMETypeRegistry::isSupportedJavaScriptMIMEType(lowerMimetype) ||
412 (text && isLegacySupportedJavaScriptLanguage(lowerMimetype.substring(5)));
413 bool sameOrigin =
414 m_element->document().getSecurityOrigin()->canRequest(m_resource->url());
415 if (expectedJs) {
416 return; 411 return;
417 } 412 bool isText = mimeType.startsWith("text/", TextCaseASCIIInsensitive);
413 if (isText && isLegacySupportedJavaScriptLanguage(mimeType.substring(5)))
414 return;
415 bool isSameOrigin =
416 m_element->document().getSecurityOrigin()->canRequest(resource->url());
417 bool isApplication =
418 !isText && mimeType.startsWith("application/", TextCaseASCIIInsensitive);
419
418 UseCounter::Feature feature = 420 UseCounter::Feature feature =
419 sameOrigin 421 isSameOrigin
420 ? (text ? UseCounter::SameOriginTextScript 422 ? (isText ? UseCounter::SameOriginTextScript
421 : application ? UseCounter::SameOriginApplicationScript 423 : isApplication ? UseCounter::SameOriginApplicationScript
422 : UseCounter::SameOriginOtherScript) 424 : UseCounter::SameOriginOtherScript)
423 : (text ? UseCounter::CrossOriginTextScript 425 : (isText ? UseCounter::CrossOriginTextScript
424 : application ? UseCounter::CrossOriginApplicationScript 426 : isApplication ? UseCounter::CrossOriginApplicationScript
425 : UseCounter::CrossOriginOtherScript); 427 : UseCounter::CrossOriginOtherScript);
428
426 UseCounter::count(frame, feature); 429 UseCounter::count(frame, feature);
427 } 430 }
428 431
429 bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) { 432 bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) {
430 double scriptExecStartTime = monotonicallyIncreasingTime(); 433 double scriptExecStartTime = monotonicallyIncreasingTime();
431 bool result = doExecuteScript(sourceCode); 434 bool result = doExecuteScript(sourceCode);
432 435
433 // NOTE: we do not check m_willBeParserExecuted here, since 436 // NOTE: we do not check m_willBeParserExecuted here, since
434 // m_willBeParserExecuted is false for inline scripts, and we want to 437 // m_willBeParserExecuted is false for inline scripts, and we want to
435 // include inline script execution time as part of parser blocked script 438 // include inline script execution time as part of parser blocked script
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 contextDocument->addConsoleMessage(ConsoleMessage::create( 483 contextDocument->addConsoleMessage(ConsoleMessage::create(
481 SecurityMessageSource, ErrorMessageLevel, 484 SecurityMessageSource, ErrorMessageLevel,
482 "Refused to execute script from '" + 485 "Refused to execute script from '" +
483 resource->url().elidedString() + "' because its MIME type ('" + 486 resource->url().elidedString() + "' because its MIME type ('" +
484 resource->httpContentType() + "') is not executable, and " 487 resource->httpContentType() + "') is not executable, and "
485 "strict MIME type checking is " 488 "strict MIME type checking is "
486 "enabled.")); 489 "enabled."));
487 return false; 490 return false;
488 } 491 }
489 492
490 String mimetype = resource->httpContentType(); 493 String mimeType = resource->httpContentType();
491 if (mimetype.startsWith("image/") || mimetype == "text/csv" || 494 if (mimeType.startsWith("image/") || mimeType == "text/csv" ||
492 mimetype.startsWith("audio/") || mimetype.startsWith("video/")) { 495 mimeType.startsWith("audio/") || mimeType.startsWith("video/")) {
493 contextDocument->addConsoleMessage(ConsoleMessage::create( 496 contextDocument->addConsoleMessage(ConsoleMessage::create(
494 SecurityMessageSource, ErrorMessageLevel, 497 SecurityMessageSource, ErrorMessageLevel,
495 "Refused to execute script from '" + 498 "Refused to execute script from '" +
496 resource->url().elidedString() + "' because its MIME type ('" + 499 resource->url().elidedString() + "' because its MIME type ('" +
497 mimetype + "') is not executable.")); 500 mimeType + "') is not executable."));
498 if (mimetype.startsWith("image/")) 501 if (mimeType.startsWith("image/"))
499 UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript); 502 UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript);
500 else if (mimetype.startsWith("audio/")) 503 else if (mimeType.startsWith("audio/"))
501 UseCounter::count(frame, UseCounter::BlockedSniffingAudioToScript); 504 UseCounter::count(frame, UseCounter::BlockedSniffingAudioToScript);
502 else if (mimetype.startsWith("video/")) 505 else if (mimeType.startsWith("video/"))
503 UseCounter::count(frame, UseCounter::BlockedSniffingVideoToScript); 506 UseCounter::count(frame, UseCounter::BlockedSniffingVideoToScript);
504 else if (mimetype == "text/csv") 507 else if (mimeType == "text/csv")
505 UseCounter::count(frame, UseCounter::BlockedSniffingCSVToScript); 508 UseCounter::count(frame, UseCounter::BlockedSniffingCSVToScript);
506 return false; 509 return false;
507 } 510 }
508 511
509 logScriptMimetype(resource, frame, mimetype); 512 logScriptMIMEType(frame, resource, mimeType);
510 } 513 }
511 } 514 }
512 515
513 // FIXME: Can this be moved earlier in the function? 516 // FIXME: Can this be moved earlier in the function?
514 // Why are we ever attempting to execute scripts without a frame? 517 // Why are we ever attempting to execute scripts without a frame?
515 if (!frame) 518 if (!frame)
516 return true; 519 return true;
517 520
518 AccessControlStatus accessControlStatus = NotSharableCrossOrigin; 521 AccessControlStatus accessControlStatus = NotSharableCrossOrigin;
519 if (!m_isExternalScript) { 522 if (!m_isExternalScript) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 if (isHTMLScriptLoader(element)) 648 if (isHTMLScriptLoader(element))
646 return toHTMLScriptElement(element)->loader(); 649 return toHTMLScriptElement(element)->loader();
647 650
648 if (isSVGScriptLoader(element)) 651 if (isSVGScriptLoader(element))
649 return toSVGScriptElement(element)->loader(); 652 return toSVGScriptElement(element)->loader();
650 653
651 return 0; 654 return 0;
652 } 655 }
653 656
654 } // namespace blink 657 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/ScriptLoader.h ('k') | third_party/WebKit/Source/platform/MIMETypeRegistry.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698