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

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: Crash fix by adding Dispose() as ClassicPendingScript prefinalizer 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/ScriptStreamerImpl.h"
31 #include "bindings/core/v8/V8Binding.h"
32 #include "core/dom/ClassicScript.h"
33 #include "core/dom/Document.h"
34 #include "core/dom/ScriptElementBase.h" 28 #include "core/dom/ScriptElementBase.h"
35 #include "core/dom/TaskRunnerHelper.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/SubresourceIntegrity.h"
38 #include "platform/SharedBuffer.h"
39 #include "platform/wtf/CurrentTime.h" 29 #include "platform/wtf/CurrentTime.h"
40 30
41 namespace blink { 31 namespace blink {
42 32
43 PendingScript* PendingScript::Create(ScriptElementBase* element,
44 ScriptResource* resource) {
45 return new PendingScript(element, resource, TextPosition());
46 }
47
48 PendingScript* PendingScript::Create(ScriptElementBase* element,
49 const TextPosition& starting_position) {
50 return new PendingScript(element, nullptr, starting_position);
51 }
52
53 PendingScript* PendingScript::CreateForTesting(ScriptResource* resource) {
54 return new PendingScript(nullptr, resource, TextPosition(), true);
55 }
56
57 PendingScript::PendingScript(ScriptElementBase* element, 33 PendingScript::PendingScript(ScriptElementBase* element,
58 ScriptResource* resource, 34 const TextPosition& starting_position)
59 const TextPosition& starting_position,
60 bool is_for_testing)
61 : watching_for_load_(false), 35 : watching_for_load_(false),
62 element_(element), 36 element_(element),
63 starting_position_(starting_position), 37 starting_position_(starting_position),
64 integrity_failure_(false),
65 parser_blocking_load_start_time_(0), 38 parser_blocking_load_start_time_(0),
66 client_(nullptr), 39 client_(nullptr) {}
67 is_for_testing_(is_for_testing) {
68 CheckState();
69 SetResource(resource);
70 MemoryCoordinator::Instance().RegisterClient(this);
71 }
72 40
73 PendingScript::~PendingScript() {} 41 PendingScript::~PendingScript() {}
74 42
75 NOINLINE void PendingScript::CheckState() const {
76 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta.
77 CHECK(is_for_testing_ || element_);
78 CHECK(GetResource() || !streamer_);
79 CHECK(!streamer_ || streamer_->GetResource() == GetResource());
80 }
81
82 void PendingScript::Dispose() { 43 void PendingScript::Dispose() {
83 StopWatchingForLoad(); 44 StopWatchingForLoad();
84 DCHECK(!client_); 45 DCHECK(!Client());
85 DCHECK(!watching_for_load_); 46 DCHECK(!IsWatchingForLoad());
86 47
87 MemoryCoordinator::Instance().UnregisterClient(this);
88 SetResource(nullptr);
89 starting_position_ = TextPosition::BelowRangePosition(); 48 starting_position_ = TextPosition::BelowRangePosition();
90 integrity_failure_ = false;
91 parser_blocking_load_start_time_ = 0; 49 parser_blocking_load_start_time_ = 0;
92 if (streamer_) 50
93 streamer_->Cancel(); 51 DisposeInternal();
94 streamer_ = nullptr;
95 element_ = nullptr; 52 element_ = nullptr;
96 } 53 }
97 54
98 void PendingScript::WatchForLoad(PendingScriptClient* client) { 55 void PendingScript::WatchForLoad(PendingScriptClient* client) {
99 CheckState(); 56 CheckState();
100 57
101 DCHECK(!watching_for_load_); 58 DCHECK(!IsWatchingForLoad());
102 // addClient() will call streamingFinished() if the load is complete. Callers 59 // addClient() will call streamingFinished() if the load is complete. Callers
103 // 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
104 // watchForLoad for a PendingScript which isReady. We also need to set 61 // watchForLoad for a PendingScript which isReady. We also need to set
105 // m_watchingForLoad early, since addClient() can result in calling 62 // m_watchingForLoad early, since addClient() can result in calling
106 // notifyFinished and further stopWatchingForLoad(). 63 // notifyFinished and further stopWatchingForLoad().
107 watching_for_load_ = true; 64 watching_for_load_ = true;
108 client_ = client; 65 client_ = client;
109 if (IsReady()) 66 if (IsReady())
110 client_->PendingScriptFinished(this); 67 client_->PendingScriptFinished(this);
111 } 68 }
112 69
113 void PendingScript::StopWatchingForLoad() { 70 void PendingScript::StopWatchingForLoad() {
114 if (!watching_for_load_) 71 if (!IsWatchingForLoad())
115 return; 72 return;
116 CheckState(); 73 CheckState();
117 DCHECK(GetResource()); 74 DCHECK(IsExternal());
118 client_ = nullptr; 75 client_ = nullptr;
119 watching_for_load_ = false; 76 watching_for_load_ = false;
120 } 77 }
121 78
122 ScriptElementBase* PendingScript::GetElement() const { 79 ScriptElementBase* PendingScript::GetElement() const {
123 // As mentioned in the comment at |m_element| declaration, 80 // As mentioned in the comment at |m_element| declaration,
124 // |m_element| must point to the corresponding ScriptLoader's 81 // |m_element| must point to the corresponding ScriptLoader's
125 // client. 82 // client.
126 CHECK(element_); 83 CHECK(element_);
127 return element_.Get(); 84 return element_.Get();
128 } 85 }
129 86
130 void PendingScript::StreamingFinished() {
131 CheckState();
132 DCHECK(GetResource());
133 if (client_)
134 client_->PendingScriptFinished(this);
135 }
136
137 void PendingScript::MarkParserBlockingLoadStartTime() { 87 void PendingScript::MarkParserBlockingLoadStartTime() {
138 DCHECK_EQ(parser_blocking_load_start_time_, 0.0); 88 DCHECK_EQ(parser_blocking_load_start_time_, 0.0);
139 parser_blocking_load_start_time_ = MonotonicallyIncreasingTime(); 89 parser_blocking_load_start_time_ = MonotonicallyIncreasingTime();
140 } 90 }
141 91
142 // Returns true if SRI check passed.
143 static bool CheckScriptResourceIntegrity(Resource* resource,
144 ScriptElementBase* element) {
145 DCHECK_EQ(resource->GetType(), Resource::kScript);
146 ScriptResource* script_resource = ToScriptResource(resource);
147 String integrity_attr = element->IntegrityAttributeValue();
148
149 // It is possible to get back a script resource with integrity metadata
150 // for a request with an empty integrity attribute. In that case, the
151 // integrity check should be skipped, so this check ensures that the
152 // integrity attribute isn't empty in addition to checking if the
153 // resource has empty integrity metadata.
154 if (integrity_attr.IsEmpty() ||
155 script_resource->IntegrityMetadata().IsEmpty())
156 return true;
157
158 switch (script_resource->IntegrityDisposition()) {
159 case ResourceIntegrityDisposition::kPassed:
160 return true;
161
162 case ResourceIntegrityDisposition::kFailed:
163 // TODO(jww): This should probably also generate a console
164 // message identical to the one produced by
165 // CheckSubresourceIntegrity below. See https://crbug.com/585267.
166 return false;
167
168 case ResourceIntegrityDisposition::kNotChecked: {
169 if (!resource->ResourceBuffer())
170 return true;
171
172 bool passed = SubresourceIntegrity::CheckSubresourceIntegrity(
173 script_resource->IntegrityMetadata(), element->GetDocument(),
174 resource->ResourceBuffer()->Data(),
175 resource->ResourceBuffer()->size(), resource->Url(), *resource);
176 script_resource->SetIntegrityDisposition(
177 passed ? ResourceIntegrityDisposition::kPassed
178 : ResourceIntegrityDisposition::kFailed);
179 return passed;
180 }
181 }
182
183 NOTREACHED();
184 return true;
185 }
186
187 void PendingScript::NotifyFinished(Resource* resource) {
188 // The following SRI checks need to be here because, unfortunately, fetches
189 // are not done purely according to the Fetch spec. In particular,
190 // different requests for the same resource do not have different
191 // responses; the memory cache can (and will) return the exact same
192 // Resource object.
193 //
194 // For different requests, the same Resource object will be returned and
195 // will not be associated with the particular request. Therefore, when the
196 // body of the response comes in, there's no way to validate the integrity
197 // of the Resource object against a particular request (since there may be
198 // several pending requests all tied to the identical object, and the
199 // actual requests are not stored).
200 //
201 // In order to simulate the correct behavior, Blink explicitly does the SRI
202 // checks here, when a PendingScript tied to a particular request is
203 // finished (and in the case of a StyleSheet, at the point of execution),
204 // while having proper Fetch checks in the fetch module for use in the
205 // fetch JavaScript API. In a future world where the ResourceFetcher uses
206 // the Fetch algorithm, this should be fixed by having separate Response
207 // objects (perhaps attached to identical Resource objects) per request.
208 //
209 // See https://crbug.com/500701 for more information.
210 CheckState();
211 if (element_) {
212 integrity_failure_ = !CheckScriptResourceIntegrity(resource, element_);
213 }
214
215 // If script streaming is in use, the client will be notified in
216 // streamingFinished.
217 if (streamer_)
218 streamer_->NotifyFinished(resource);
219 else if (client_)
220 client_->PendingScriptFinished(this);
221 }
222
223 void PendingScript::NotifyAppendData(ScriptResource* resource) {
224 if (streamer_)
225 streamer_->NotifyAppendData(resource);
226 }
227
228 DEFINE_TRACE(PendingScript) { 92 DEFINE_TRACE(PendingScript) {
229 visitor->Trace(element_); 93 visitor->Trace(element_);
230 visitor->Trace(streamer_);
231 visitor->Trace(client_); 94 visitor->Trace(client_);
232 ResourceOwner<ScriptResource>::Trace(visitor);
233 MemoryCoordinatorClient::Trace(visitor);
234 }
235
236 ClassicScript* PendingScript::GetSource(const KURL& document_url,
237 bool& error_occurred) const {
238 CheckState();
239
240 error_occurred = this->ErrorOccurred();
241 if (GetResource()) {
242 DCHECK(GetResource()->IsLoaded());
243 if (streamer_ && !streamer_->StreamingSuppressed())
244 return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource()));
245 return ClassicScript::Create(ScriptSourceCode(GetResource()));
246 }
247
248 return ClassicScript::Create(ScriptSourceCode(
249 element_->TextContent(), document_url, StartingPosition()));
250 }
251
252 void PendingScript::SetStreamer(ScriptStreamer* streamer) {
253 DCHECK(!streamer_);
254 DCHECK(!watching_for_load_);
255 streamer_ = streamer;
256 CheckState();
257 }
258
259 bool PendingScript::IsReady() const {
260 CheckState();
261 if (GetResource()) {
262 return GetResource()->IsLoaded() && (!streamer_ || streamer_->IsFinished());
263 }
264
265 return true;
266 }
267
268 bool PendingScript::ErrorOccurred() const {
269 CheckState();
270 if (GetResource())
271 return GetResource()->ErrorOccurred() || integrity_failure_;
272
273 return false;
274 }
275
276 void PendingScript::OnPurgeMemory() {
277 CheckState();
278 if (!streamer_)
279 return;
280 streamer_->Cancel();
281 streamer_ = nullptr;
282 }
283
284 void PendingScript::StartStreamingIfPossible(
285 Document* document,
286 ScriptStreamer::Type streamer_type) {
287 if (!document->GetFrame())
288 return;
289
290 ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame());
291 if (!script_state)
292 return;
293
294 ScriptStreamerImpl::StartStreaming(
295 this, streamer_type, document->GetFrame()->GetSettings(), script_state,
296 TaskRunnerHelper::Get(TaskType::kNetworking, document));
297 } 95 }
298 96
299 } // namespace blink 97 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698