Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |