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

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

Issue 2653923008: Reland of Split PendingScript into PendingScript and ClassicPendingScript (Closed)
Patch Set: Fix file header Created 3 years, 8 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) 2010 Google, Inc. All Rights Reserved. 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * 12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "core/dom/PendingScript.h" 26 #include "core/dom/PendingScript.h"
27 27
28 #include "bindings/core/v8/ScriptSourceCode.h"
29 #include "bindings/core/v8/ScriptState.h"
30 #include "bindings/core/v8/V8Binding.h"
31 #include "core/dom/ClassicScript.h"
32 #include "core/dom/Document.h"
33 #include "core/dom/ScriptElementBase.h" 28 #include "core/dom/ScriptElementBase.h"
34 #include "core/dom/TaskRunnerHelper.h"
35 #include "core/frame/LocalFrame.h"
36 #include "core/frame/SubresourceIntegrity.h"
37 #include "platform/SharedBuffer.h"
38 #include "wtf/CurrentTime.h" 29 #include "wtf/CurrentTime.h"
39 30
40 namespace blink { 31 namespace blink {
41 32
42 PendingScript* PendingScript::create(ScriptElementBase* element,
43 ScriptResource* resource) {
44 return new PendingScript(element, resource, TextPosition());
45 }
46
47 PendingScript* PendingScript::create(ScriptElementBase* element,
48 const TextPosition& startingPosition) {
49 return new PendingScript(element, nullptr, startingPosition);
50 }
51
52 PendingScript* PendingScript::createForTesting(ScriptResource* resource) {
53 return new PendingScript(nullptr, resource, TextPosition(), true);
54 }
55
56 PendingScript::PendingScript(ScriptElementBase* element, 33 PendingScript::PendingScript(ScriptElementBase* element,
57 ScriptResource* resource, 34 const TextPosition& startingPosition)
58 const TextPosition& startingPosition,
59 bool isForTesting)
60 : m_watchingForLoad(false), 35 : m_watchingForLoad(false),
61 m_element(element), 36 m_element(element),
62 m_startingPosition(startingPosition), 37 m_startingPosition(startingPosition),
63 m_integrityFailure(false),
64 m_parserBlockingLoadStartTime(0), 38 m_parserBlockingLoadStartTime(0),
65 m_client(nullptr), 39 m_client(nullptr) {}
66 m_isForTesting(isForTesting) {
67 checkState();
68 setResource(resource);
69 MemoryCoordinator::instance().registerClient(this);
70 }
71 40
72 PendingScript::~PendingScript() {} 41 PendingScript::~PendingScript() {}
73 42
74 NOINLINE void PendingScript::checkState() const {
75 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta.
76 CHECK(m_isForTesting || m_element);
77 CHECK(resource() || !m_streamer);
78 CHECK(!m_streamer || m_streamer->resource() == resource());
79 }
80
81 void PendingScript::dispose() { 43 void PendingScript::dispose() {
82 stopWatchingForLoad(); 44 stopWatchingForLoad();
83 DCHECK(!m_client); 45 DCHECK(!client());
84 DCHECK(!m_watchingForLoad); 46 DCHECK(!isWatchingForLoad());
85 47
86 MemoryCoordinator::instance().unregisterClient(this);
87 setResource(nullptr);
88 m_startingPosition = TextPosition::belowRangePosition(); 48 m_startingPosition = TextPosition::belowRangePosition();
89 m_integrityFailure = false;
90 m_parserBlockingLoadStartTime = 0; 49 m_parserBlockingLoadStartTime = 0;
91 if (m_streamer) 50
92 m_streamer->cancel(); 51 disposeInternal();
93 m_streamer = nullptr;
94 m_element = nullptr; 52 m_element = nullptr;
95 } 53 }
96 54
97 void PendingScript::watchForLoad(PendingScriptClient* client) { 55 void PendingScript::watchForLoad(PendingScriptClient* client) {
98 checkState(); 56 checkState();
99 57
100 DCHECK(!m_watchingForLoad); 58 DCHECK(!isWatchingForLoad());
101 // addClient() will call streamingFinished() if the load is complete. Callers 59 // addClient() will call streamingFinished() if the load is complete. Callers
102 // who do not expect to be re-entered from this call should not call 60 // who do not expect to be re-entered from this call should not call
103 // watchForLoad for a PendingScript which isReady. We also need to set 61 // watchForLoad for a PendingScript which isReady. We also need to set
104 // m_watchingForLoad early, since addClient() can result in calling 62 // m_watchingForLoad early, since addClient() can result in calling
105 // notifyFinished and further stopWatchingForLoad(). 63 // notifyFinished and further stopWatchingForLoad().
106 m_watchingForLoad = true; 64 m_watchingForLoad = true;
107 m_client = client; 65 m_client = client;
108 if (isReady()) 66 if (isReady())
109 m_client->pendingScriptFinished(this); 67 m_client->pendingScriptFinished(this);
110 } 68 }
111 69
112 void PendingScript::stopWatchingForLoad() { 70 void PendingScript::stopWatchingForLoad() {
113 if (!m_watchingForLoad) 71 if (!isWatchingForLoad())
114 return; 72 return;
115 checkState(); 73 checkState();
116 DCHECK(resource()); 74 DCHECK(isExternal());
117 m_client = nullptr; 75 m_client = nullptr;
118 m_watchingForLoad = false; 76 m_watchingForLoad = false;
119 } 77 }
120 78
121 ScriptElementBase* PendingScript::element() const { 79 ScriptElementBase* PendingScript::element() const {
122 // As mentioned in the comment at |m_element| declaration, 80 // As mentioned in the comment at |m_element| declaration,
123 // |m_element| must point to the corresponding ScriptLoader's 81 // |m_element| must point to the corresponding ScriptLoader's
124 // client. 82 // client.
125 CHECK(m_element); 83 CHECK(m_element);
126 return m_element.get(); 84 return m_element.get();
127 } 85 }
128 86
129 void PendingScript::streamingFinished() {
130 checkState();
131 DCHECK(resource());
132 if (m_client)
133 m_client->pendingScriptFinished(this);
134 }
135
136 void PendingScript::markParserBlockingLoadStartTime() { 87 void PendingScript::markParserBlockingLoadStartTime() {
137 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0); 88 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0);
138 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime(); 89 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime();
139 } 90 }
140 91
141 // Returns true if SRI check passed.
142 static bool checkScriptResourceIntegrity(Resource* resource,
143 ScriptElementBase* element) {
144 DCHECK_EQ(resource->getType(), Resource::Script);
145 ScriptResource* scriptResource = toScriptResource(resource);
146 String integrityAttr = element->integrityAttributeValue();
147
148 // It is possible to get back a script resource with integrity metadata
149 // for a request with an empty integrity attribute. In that case, the
150 // integrity check should be skipped, so this check ensures that the
151 // integrity attribute isn't empty in addition to checking if the
152 // resource has empty integrity metadata.
153 if (integrityAttr.isEmpty() || scriptResource->integrityMetadata().isEmpty())
154 return true;
155
156 switch (scriptResource->integrityDisposition()) {
157 case ResourceIntegrityDisposition::Passed:
158 return true;
159
160 case ResourceIntegrityDisposition::Failed:
161 // TODO(jww): This should probably also generate a console
162 // message identical to the one produced by
163 // CheckSubresourceIntegrity below. See https://crbug.com/585267.
164 return false;
165
166 case ResourceIntegrityDisposition::NotChecked: {
167 if (!resource->resourceBuffer())
168 return true;
169
170 bool passed = SubresourceIntegrity::CheckSubresourceIntegrity(
171 scriptResource->integrityMetadata(), element->document(),
172 resource->resourceBuffer()->data(),
173 resource->resourceBuffer()->size(), resource->url(), *resource);
174 scriptResource->setIntegrityDisposition(
175 passed ? ResourceIntegrityDisposition::Passed
176 : ResourceIntegrityDisposition::Failed);
177 return passed;
178 }
179 }
180
181 NOTREACHED();
182 return true;
183 }
184
185 void PendingScript::notifyFinished(Resource* resource) {
186 // The following SRI checks need to be here because, unfortunately, fetches
187 // are not done purely according to the Fetch spec. In particular,
188 // different requests for the same resource do not have different
189 // responses; the memory cache can (and will) return the exact same
190 // Resource object.
191 //
192 // For different requests, the same Resource object will be returned and
193 // will not be associated with the particular request. Therefore, when the
194 // body of the response comes in, there's no way to validate the integrity
195 // of the Resource object against a particular request (since there may be
196 // several pending requests all tied to the identical object, and the
197 // actual requests are not stored).
198 //
199 // In order to simulate the correct behavior, Blink explicitly does the SRI
200 // checks here, when a PendingScript tied to a particular request is
201 // finished (and in the case of a StyleSheet, at the point of execution),
202 // while having proper Fetch checks in the fetch module for use in the
203 // fetch JavaScript API. In a future world where the ResourceFetcher uses
204 // the Fetch algorithm, this should be fixed by having separate Response
205 // objects (perhaps attached to identical Resource objects) per request.
206 //
207 // See https://crbug.com/500701 for more information.
208 checkState();
209 if (m_element) {
210 m_integrityFailure = !checkScriptResourceIntegrity(resource, m_element);
211 }
212
213 // If script streaming is in use, the client will be notified in
214 // streamingFinished.
215 if (m_streamer)
216 m_streamer->notifyFinished(resource);
217 else if (m_client)
218 m_client->pendingScriptFinished(this);
219 }
220
221 void PendingScript::notifyAppendData(ScriptResource* resource) {
222 if (m_streamer)
223 m_streamer->notifyAppendData(resource);
224 }
225
226 DEFINE_TRACE(PendingScript) { 92 DEFINE_TRACE(PendingScript) {
227 visitor->trace(m_element); 93 visitor->trace(m_element);
228 visitor->trace(m_streamer);
229 visitor->trace(m_client); 94 visitor->trace(m_client);
230 ResourceOwner<ScriptResource>::trace(visitor);
231 MemoryCoordinatorClient::trace(visitor);
232 }
233
234 ClassicScript* PendingScript::getSource(const KURL& documentURL,
235 bool& errorOccurred) const {
236 checkState();
237
238 errorOccurred = this->errorOccurred();
239 if (resource()) {
240 DCHECK(resource()->isLoaded());
241 if (m_streamer && !m_streamer->streamingSuppressed())
242 return ClassicScript::create(ScriptSourceCode(m_streamer, resource()));
243 return ClassicScript::create(ScriptSourceCode(resource()));
244 }
245
246 return ClassicScript::create(ScriptSourceCode(
247 m_element->textContent(), documentURL, startingPosition()));
248 }
249
250 void PendingScript::setStreamer(ScriptStreamer* streamer) {
251 DCHECK(!m_streamer);
252 DCHECK(!m_watchingForLoad);
253 m_streamer = streamer;
254 checkState();
255 }
256
257 bool PendingScript::isReady() const {
258 checkState();
259 if (resource()) {
260 return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished());
261 }
262
263 return true;
264 }
265
266 bool PendingScript::errorOccurred() const {
267 checkState();
268 if (resource())
269 return resource()->errorOccurred() || m_integrityFailure;
270
271 return false;
272 }
273
274 void PendingScript::onPurgeMemory() {
275 checkState();
276 if (!m_streamer)
277 return;
278 m_streamer->cancel();
279 m_streamer = nullptr;
280 }
281
282 void PendingScript::startStreamingIfPossible(
283 Document* document,
284 ScriptStreamer::Type streamerType) {
285 if (!document->frame())
286 return;
287
288 ScriptState* scriptState = toScriptStateForMainWorld(document->frame());
289 if (!scriptState)
290 return;
291
292 ScriptStreamer::startStreaming(
293 this, streamerType, document->frame()->settings(), scriptState,
294 TaskRunnerHelper::get(TaskType::Networking, document));
295 } 95 }
296 96
297 } // namespace blink 97 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698