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

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

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

Powered by Google App Engine
This is Rietveld 408576698