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

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

Issue 2828193003: Explicitly track the lifecycle of PendingScript. (Closed)
Patch Set: document, and replace watching_for_load_ 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
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 } 50 }
51 51
52 PendingScript* PendingScript::CreateForTesting(ScriptResource* resource) { 52 PendingScript* PendingScript::CreateForTesting(ScriptResource* resource) {
53 return new PendingScript(nullptr, resource, TextPosition(), true); 53 return new PendingScript(nullptr, resource, TextPosition(), true);
54 } 54 }
55 55
56 PendingScript::PendingScript(ScriptElementBase* element, 56 PendingScript::PendingScript(ScriptElementBase* element,
57 ScriptResource* resource, 57 ScriptResource* resource,
58 const TextPosition& starting_position, 58 const TextPosition& starting_position,
59 bool is_for_testing) 59 bool is_for_testing)
60 : watching_for_load_(false), 60 : ready_state_(resource ? kWaitingForResource : kReady),
61 element_(element), 61 element_(element),
62 starting_position_(starting_position), 62 starting_position_(starting_position),
63 integrity_failure_(false), 63 integrity_failure_(false),
64 parser_blocking_load_start_time_(0), 64 parser_blocking_load_start_time_(0),
65 client_(nullptr), 65 client_(nullptr),
66 is_for_testing_(is_for_testing) { 66 is_for_testing_(is_for_testing) {
67 CheckState(); 67 CheckState();
68 SetResource(resource); 68 SetResource(resource);
69 MemoryCoordinator::Instance().RegisterClient(this); 69 MemoryCoordinator::Instance().RegisterClient(this);
70 } 70 }
71 71
72 PendingScript::~PendingScript() {} 72 PendingScript::~PendingScript() {}
73 73
74 NOINLINE void PendingScript::CheckState() const { 74 NOINLINE void PendingScript::CheckState() const {
75 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. 75 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta.
76 CHECK(is_for_testing_ || element_); 76 CHECK(is_for_testing_ || element_);
77 CHECK(GetResource() || !streamer_); 77 CHECK(GetResource() || !streamer_);
78 CHECK(!streamer_ || streamer_->GetResource() == GetResource()); 78 CHECK(!streamer_ || streamer_->GetResource() == GetResource());
79 } 79 }
80 80
81 void PendingScript::Dispose() { 81 void PendingScript::Dispose() {
82 StopWatchingForLoad(); 82 StopWatchingForLoad();
83 DCHECK(!client_); 83 DCHECK(!WatchingForLoad());
84 DCHECK(!watching_for_load_);
85 84
86 MemoryCoordinator::Instance().UnregisterClient(this); 85 MemoryCoordinator::Instance().UnregisterClient(this);
87 SetResource(nullptr); 86 SetResource(nullptr);
88 starting_position_ = TextPosition::BelowRangePosition(); 87 starting_position_ = TextPosition::BelowRangePosition();
89 integrity_failure_ = false; 88 integrity_failure_ = false;
90 parser_blocking_load_start_time_ = 0; 89 parser_blocking_load_start_time_ = 0;
91 if (streamer_) 90 if (streamer_)
92 streamer_->Cancel(); 91 streamer_->Cancel();
93 streamer_ = nullptr; 92 streamer_ = nullptr;
94 element_ = nullptr; 93 element_ = nullptr;
95 } 94 }
96 95
97 void PendingScript::WatchForLoad(PendingScriptClient* client) { 96 void PendingScript::WatchForLoad(PendingScriptClient* client) {
98 CheckState(); 97 CheckState();
99 98
100 DCHECK(!watching_for_load_); 99 DCHECK(!WatchingForLoad());
100 DCHECK(client);
101 // addClient() will call streamingFinished() if the load is complete. Callers 101 // 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 102 // 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 103 // watchForLoad for a PendingScript which isReady. We also need to set
104 // m_watchingForLoad early, since addClient() can result in calling 104 // m_watchingForLoad early, since addClient() can result in calling
105 // notifyFinished and further stopWatchingForLoad(). 105 // notifyFinished and further stopWatchingForLoad().
106 watching_for_load_ = true;
107 client_ = client; 106 client_ = client;
108 if (IsReady()) 107 if (IsReady())
109 client_->PendingScriptFinished(this); 108 client_->PendingScriptFinished(this);
110 } 109 }
111 110
112 void PendingScript::StopWatchingForLoad() { 111 void PendingScript::StopWatchingForLoad() {
113 if (!watching_for_load_) 112 if (!WatchingForLoad())
114 return; 113 return;
115 CheckState(); 114 CheckState();
116 DCHECK(GetResource()); 115 DCHECK(GetResource());
117 client_ = nullptr; 116 client_ = nullptr;
118 watching_for_load_ = false;
119 } 117 }
120 118
121 ScriptElementBase* PendingScript::GetElement() const { 119 ScriptElementBase* PendingScript::GetElement() const {
122 // As mentioned in the comment at |m_element| declaration, 120 // As mentioned in the comment at |m_element| declaration,
123 // |m_element| must point to the corresponding ScriptLoader's 121 // |m_element| must point to the corresponding ScriptLoader's
124 // client. 122 // client.
125 CHECK(element_); 123 CHECK(element_);
126 return element_.Get(); 124 return element_.Get();
127 } 125 }
128 126
129 void PendingScript::StreamingFinished() { 127 void PendingScript::StreamingFinished() {
130 CheckState(); 128 CheckState();
131 DCHECK(GetResource()); 129 DCHECK(GetResource());
hiroshige 2017/04/24 19:16:53 DCHECK_EQ(ready_state_, kWaitingForStreaming);
jbroman 2017/05/01 15:08:01 Done.
132 if (client_) 130
133 client_->PendingScriptFinished(this); 131 bool error_occurred = GetResource()->ErrorOccurred() || integrity_failure_;
132 AdvanceReadyState(error_occurred ? kErrorOccurred : kReady);
134 } 133 }
135 134
136 void PendingScript::MarkParserBlockingLoadStartTime() { 135 void PendingScript::MarkParserBlockingLoadStartTime() {
137 DCHECK_EQ(parser_blocking_load_start_time_, 0.0); 136 DCHECK_EQ(parser_blocking_load_start_time_, 0.0);
138 parser_blocking_load_start_time_ = MonotonicallyIncreasingTime(); 137 parser_blocking_load_start_time_ = MonotonicallyIncreasingTime();
139 } 138 }
140 139
141 // Returns true if SRI check passed. 140 // Returns true if SRI check passed.
142 static bool CheckScriptResourceIntegrity(Resource* resource, 141 static bool CheckScriptResourceIntegrity(Resource* resource,
143 ScriptElementBase* element) { 142 ScriptElementBase* element) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 : ResourceIntegrityDisposition::kFailed); 176 : ResourceIntegrityDisposition::kFailed);
178 return passed; 177 return passed;
179 } 178 }
180 } 179 }
181 180
182 NOTREACHED(); 181 NOTREACHED();
183 return true; 182 return true;
184 } 183 }
185 184
186 void PendingScript::NotifyFinished(Resource* resource) { 185 void PendingScript::NotifyFinished(Resource* resource) {
186 DCHECK_EQ(ready_state_, kWaitingForResource);
187
187 // The following SRI checks need to be here because, unfortunately, fetches 188 // The following SRI checks need to be here because, unfortunately, fetches
188 // are not done purely according to the Fetch spec. In particular, 189 // are not done purely according to the Fetch spec. In particular,
189 // different requests for the same resource do not have different 190 // different requests for the same resource do not have different
190 // responses; the memory cache can (and will) return the exact same 191 // responses; the memory cache can (and will) return the exact same
191 // Resource object. 192 // Resource object.
192 // 193 //
193 // For different requests, the same Resource object will be returned and 194 // For different requests, the same Resource object will be returned and
194 // will not be associated with the particular request. Therefore, when the 195 // 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 // 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 // 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 // several pending requests all tied to the identical object, and the
198 // actual requests are not stored). 199 // actual requests are not stored).
199 // 200 //
200 // In order to simulate the correct behavior, Blink explicitly does the SRI 201 // 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 // 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 // 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 // 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 // fetch JavaScript API. In a future world where the ResourceFetcher uses
205 // the Fetch algorithm, this should be fixed by having separate Response 206 // the Fetch algorithm, this should be fixed by having separate Response
206 // objects (perhaps attached to identical Resource objects) per request. 207 // objects (perhaps attached to identical Resource objects) per request.
207 // 208 //
208 // See https://crbug.com/500701 for more information. 209 // See https://crbug.com/500701 for more information.
209 CheckState(); 210 CheckState();
210 if (element_) { 211 if (element_) {
211 integrity_failure_ = !CheckScriptResourceIntegrity(resource, element_); 212 integrity_failure_ = !CheckScriptResourceIntegrity(resource, element_);
212 } 213 }
213 214
214 // If script streaming is in use, the client will be notified in 215 // We are now waiting for script streaming to finish.
215 // streamingFinished. 216 // If there is no script streamer, this step completes immediately.
217 AdvanceReadyState(kWaitingForStreaming);
216 if (streamer_) 218 if (streamer_)
217 streamer_->NotifyFinished(resource); 219 streamer_->NotifyFinished(resource);
218 else if (client_) 220 else
219 client_->PendingScriptFinished(this); 221 StreamingFinished();
220 } 222 }
221 223
222 void PendingScript::NotifyAppendData(ScriptResource* resource) { 224 void PendingScript::NotifyAppendData(ScriptResource* resource) {
223 if (streamer_) 225 if (streamer_)
224 streamer_->NotifyAppendData(resource); 226 streamer_->NotifyAppendData(resource);
225 } 227 }
226 228
227 DEFINE_TRACE(PendingScript) { 229 DEFINE_TRACE(PendingScript) {
228 visitor->Trace(element_); 230 visitor->Trace(element_);
229 visitor->Trace(streamer_); 231 visitor->Trace(streamer_);
230 visitor->Trace(client_); 232 visitor->Trace(client_);
231 ResourceOwner<ScriptResource>::Trace(visitor); 233 ResourceOwner<ScriptResource>::Trace(visitor);
232 MemoryCoordinatorClient::Trace(visitor); 234 MemoryCoordinatorClient::Trace(visitor);
233 } 235 }
234 236
235 ClassicScript* PendingScript::GetSource(const KURL& document_url, 237 ClassicScript* PendingScript::GetSource(const KURL& document_url,
236 bool& error_occurred) const { 238 bool& error_occurred) const {
237 CheckState(); 239 CheckState();
240 DCHECK(IsReady());
238 241
239 error_occurred = this->ErrorOccurred(); 242 error_occurred = ErrorOccurred();
240 if (GetResource()) { 243 if (GetResource()) {
241 DCHECK(GetResource()->IsLoaded()); 244 DCHECK(GetResource()->IsLoaded());
242 if (streamer_ && !streamer_->StreamingSuppressed()) 245 if (streamer_ && !streamer_->StreamingSuppressed())
243 return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource())); 246 return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource()));
244 return ClassicScript::Create(ScriptSourceCode(GetResource())); 247 return ClassicScript::Create(ScriptSourceCode(GetResource()));
245 } 248 }
246 249
247 return ClassicScript::Create(ScriptSourceCode( 250 return ClassicScript::Create(ScriptSourceCode(
248 element_->TextContent(), document_url, StartingPosition())); 251 element_->TextContent(), document_url, StartingPosition()));
249 } 252 }
250 253
251 void PendingScript::SetStreamer(ScriptStreamer* streamer) { 254 void PendingScript::SetStreamer(ScriptStreamer* streamer) {
252 DCHECK(!streamer_); 255 DCHECK(!streamer_);
253 DCHECK(!watching_for_load_); 256 DCHECK(!WatchingForLoad());
257 DCHECK(!streamer->IsFinished());
258 DCHECK_LT(ready_state_, kWaitingForStreaming);
254 streamer_ = streamer; 259 streamer_ = streamer;
255 CheckState(); 260 CheckState();
256 } 261 }
257 262
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() { 263 void PendingScript::OnPurgeMemory() {
276 CheckState(); 264 CheckState();
277 if (!streamer_) 265 if (!streamer_)
278 return; 266 return;
279 streamer_->Cancel(); 267 streamer_->Cancel();
280 streamer_ = nullptr; 268 streamer_ = nullptr;
281 } 269 }
282 270
283 void PendingScript::StartStreamingIfPossible( 271 void PendingScript::StartStreamingIfPossible(
284 Document* document, 272 Document* document,
285 ScriptStreamer::Type streamer_type) { 273 ScriptStreamer::Type streamer_type) {
286 if (!document->GetFrame()) 274 if (!document->GetFrame())
287 return; 275 return;
288 276
289 ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame()); 277 ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame());
290 if (!script_state) 278 if (!script_state)
291 return; 279 return;
292 280
293 ScriptStreamer::StartStreaming( 281 ScriptStreamer::StartStreaming(
294 this, streamer_type, document->GetFrame()->GetSettings(), script_state, 282 this, streamer_type, document->GetFrame()->GetSettings(), script_state,
295 TaskRunnerHelper::Get(TaskType::kNetworking, document)); 283 TaskRunnerHelper::Get(TaskType::kNetworking, document));
296 } 284 }
297 285
286 void PendingScript::AdvanceReadyState(ReadyState ready_state) {
287 // The ready state should monotonically advance.
288 DCHECK_GT(ready_state, ready_state_);
289
290 // The state should not advance from one completed state to another.
291 if (ready_state >= kReady)
292 DCHECK_LT(ready_state_, kReady);
293
294 ready_state_ = ready_state;
295 if (ready_state >= kReady && client_)
296 client_->PendingScriptFinished(this);
297 }
298
298 } // namespace blink 299 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698