| OLD | NEW | 
|---|
| 1 /* | 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 
| 2  * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3  * | 3 // found in the LICENSE file. | 
| 4  * Redistribution and use in source and binary forms, with or without |  | 
| 5  * modification, are permitted provided that the following conditions |  | 
| 6  * are met: |  | 
| 7  * 1. Redistributions of source code must retain the above copyright |  | 
| 8  *    notice, this list of conditions and the following disclaimer. |  | 
| 9  * 2. Redistributions in binary form must reproduce the above copyright |  | 
| 10  *    notice, this list of conditions and the following disclaimer in the |  | 
| 11  *    documentation and/or other materials provided with the distribution. |  | 
| 12  * |  | 
| 13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |  | 
| 14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |  | 
| 15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |  | 
| 16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR |  | 
| 17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |  | 
| 18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |  | 
| 19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |  | 
| 20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |  | 
| 21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | 
| 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. |  | 
| 24  */ |  | 
| 25 | 4 | 
| 26 #include "core/dom/PendingScript.h" | 5 #include "core/dom/ClassicPendingScript.h" | 
| 27 | 6 | 
| 28 #include "bindings/core/v8/ScriptSourceCode.h" | 7 #include "bindings/core/v8/ScriptSourceCode.h" | 
| 29 #include "bindings/core/v8/ScriptState.h" | 8 #include "bindings/core/v8/ScriptState.h" | 
|  | 9 #include "bindings/core/v8/ScriptStreamer.h" | 
|  | 10 #include "bindings/core/v8/V8Binding.h" | 
| 30 #include "bindings/core/v8/V8BindingForCore.h" | 11 #include "bindings/core/v8/V8BindingForCore.h" | 
| 31 #include "core/dom/ClassicScript.h" |  | 
| 32 #include "core/dom/Document.h" | 12 #include "core/dom/Document.h" | 
| 33 #include "core/dom/ScriptElementBase.h" |  | 
| 34 #include "core/dom/TaskRunnerHelper.h" | 13 #include "core/dom/TaskRunnerHelper.h" | 
| 35 #include "core/frame/LocalFrame.h" | 14 #include "core/frame/LocalFrame.h" | 
| 36 #include "core/frame/SubresourceIntegrity.h" | 15 #include "core/frame/SubresourceIntegrity.h" | 
| 37 #include "platform/SharedBuffer.h" | 16 #include "platform/loader/fetch/MemoryCache.h" | 
| 38 #include "platform/wtf/CurrentTime.h" |  | 
| 39 | 17 | 
| 40 namespace blink { | 18 namespace blink { | 
| 41 | 19 | 
| 42 PendingScript* PendingScript::Create(ScriptElementBase* element, | 20 ClassicPendingScript* ClassicPendingScript::Create(ScriptElementBase* element, | 
| 43                                      ScriptResource* resource) { | 21                                                    ScriptResource* resource) { | 
| 44   return new PendingScript(element, resource, TextPosition()); | 22   return new ClassicPendingScript(element, resource, TextPosition()); | 
| 45 } | 23 } | 
| 46 | 24 | 
| 47 PendingScript* PendingScript::Create(ScriptElementBase* element, | 25 ClassicPendingScript* ClassicPendingScript::Create( | 
| 48                                      const TextPosition& starting_position) { | 26     ScriptElementBase* element, | 
| 49   return new PendingScript(element, nullptr, starting_position); | 27     const TextPosition& starting_position) { | 
|  | 28   return new ClassicPendingScript(element, nullptr, starting_position); | 
| 50 } | 29 } | 
| 51 | 30 | 
| 52 PendingScript* PendingScript::CreateForTesting(ScriptResource* resource) { | 31 ClassicPendingScript* ClassicPendingScript::CreateForTesting( | 
| 53   return new PendingScript(nullptr, resource, TextPosition(), true); | 32     ScriptResource* resource) { | 
|  | 33   return new ClassicPendingScript(nullptr, resource, TextPosition(), true); | 
| 54 } | 34 } | 
| 55 | 35 | 
| 56 PendingScript::PendingScript(ScriptElementBase* element, | 36 ClassicPendingScript::ClassicPendingScript( | 
| 57                              ScriptResource* resource, | 37     ScriptElementBase* element, | 
| 58                              const TextPosition& starting_position, | 38     ScriptResource* resource, | 
| 59                              bool is_for_testing) | 39     const TextPosition& starting_position, | 
| 60     : watching_for_load_(false), | 40     bool is_for_testing) | 
| 61       element_(element), | 41     : PendingScript(element, starting_position), | 
| 62       starting_position_(starting_position), |  | 
| 63       integrity_failure_(false), | 42       integrity_failure_(false), | 
| 64       parser_blocking_load_start_time_(0), |  | 
| 65       client_(nullptr), |  | 
| 66       is_for_testing_(is_for_testing) { | 43       is_for_testing_(is_for_testing) { | 
| 67   CheckState(); | 44   CheckState(); | 
| 68   SetResource(resource); | 45   SetResource(resource); | 
| 69   MemoryCoordinator::Instance().RegisterClient(this); | 46   MemoryCoordinator::Instance().RegisterClient(this); | 
| 70 } | 47 } | 
| 71 | 48 | 
| 72 PendingScript::~PendingScript() {} | 49 ClassicPendingScript::~ClassicPendingScript() {} | 
| 73 | 50 | 
| 74 NOINLINE void PendingScript::CheckState() const { | 51 NOINLINE void ClassicPendingScript::CheckState() const { | 
| 75   // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. | 52   // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. | 
| 76   CHECK(is_for_testing_ || element_); | 53   CHECK(is_for_testing_ || GetElement()); | 
| 77   CHECK(GetResource() || !streamer_); | 54   CHECK(GetResource() || !streamer_); | 
| 78   CHECK(!streamer_ || streamer_->GetResource() == GetResource()); | 55   CHECK(!streamer_ || streamer_->GetResource() == GetResource()); | 
| 79 } | 56 } | 
| 80 | 57 | 
| 81 void PendingScript::Dispose() { | 58 NOINLINE void ClassicPendingScript::Dispose() { | 
| 82   StopWatchingForLoad(); | 59   PendingScript::Dispose(); | 
| 83   DCHECK(!client_); | 60 } | 
| 84   DCHECK(!watching_for_load_); |  | 
| 85 | 61 | 
|  | 62 void ClassicPendingScript::DisposeInternal() { | 
| 86   MemoryCoordinator::Instance().UnregisterClient(this); | 63   MemoryCoordinator::Instance().UnregisterClient(this); | 
| 87   SetResource(nullptr); | 64   SetResource(nullptr); | 
| 88   starting_position_ = TextPosition::BelowRangePosition(); |  | 
| 89   integrity_failure_ = false; | 65   integrity_failure_ = false; | 
| 90   parser_blocking_load_start_time_ = 0; |  | 
| 91   if (streamer_) | 66   if (streamer_) | 
| 92     streamer_->Cancel(); | 67     streamer_->Cancel(); | 
| 93   streamer_ = nullptr; | 68   streamer_ = nullptr; | 
| 94   element_ = nullptr; |  | 
| 95 } | 69 } | 
| 96 | 70 | 
| 97 void PendingScript::WatchForLoad(PendingScriptClient* client) { | 71 void ClassicPendingScript::StreamingFinished() { | 
| 98   CheckState(); |  | 
| 99 |  | 
| 100   DCHECK(!watching_for_load_); |  | 
| 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 |  | 
| 103   // watchForLoad for a PendingScript which isReady. We also need to set |  | 
| 104   // m_watchingForLoad early, since addClient() can result in calling |  | 
| 105   // notifyFinished and further stopWatchingForLoad(). |  | 
| 106   watching_for_load_ = true; |  | 
| 107   client_ = client; |  | 
| 108   if (IsReady()) |  | 
| 109     client_->PendingScriptFinished(this); |  | 
| 110 } |  | 
| 111 |  | 
| 112 void PendingScript::StopWatchingForLoad() { |  | 
| 113   if (!watching_for_load_) |  | 
| 114     return; |  | 
| 115   CheckState(); | 72   CheckState(); | 
| 116   DCHECK(GetResource()); | 73   DCHECK(GetResource()); | 
| 117   client_ = nullptr; | 74   if (Client()) | 
| 118   watching_for_load_ = false; | 75     Client()->PendingScriptFinished(this); | 
| 119 } |  | 
| 120 |  | 
| 121 ScriptElementBase* PendingScript::GetElement() const { |  | 
| 122   // As mentioned in the comment at |m_element| declaration, |  | 
| 123   // |m_element|  must point to the corresponding ScriptLoader's |  | 
| 124   // client. |  | 
| 125   CHECK(element_); |  | 
| 126   return element_.Get(); |  | 
| 127 } |  | 
| 128 |  | 
| 129 void PendingScript::StreamingFinished() { |  | 
| 130   CheckState(); |  | 
| 131   DCHECK(GetResource()); |  | 
| 132   if (client_) |  | 
| 133     client_->PendingScriptFinished(this); |  | 
| 134 } |  | 
| 135 |  | 
| 136 void PendingScript::MarkParserBlockingLoadStartTime() { |  | 
| 137   DCHECK_EQ(parser_blocking_load_start_time_, 0.0); |  | 
| 138   parser_blocking_load_start_time_ = MonotonicallyIncreasingTime(); |  | 
| 139 } | 76 } | 
| 140 | 77 | 
| 141 // Returns true if SRI check passed. | 78 // Returns true if SRI check passed. | 
| 142 static bool CheckScriptResourceIntegrity(Resource* resource, | 79 static bool CheckScriptResourceIntegrity(Resource* resource, | 
| 143                                          ScriptElementBase* element) { | 80                                          ScriptElementBase* element) { | 
| 144   DCHECK_EQ(resource->GetType(), Resource::kScript); | 81   DCHECK_EQ(resource->GetType(), Resource::kScript); | 
| 145   ScriptResource* script_resource = ToScriptResource(resource); | 82   ScriptResource* script_resource = ToScriptResource(resource); | 
| 146   String integrity_attr = element->IntegrityAttributeValue(); | 83   String integrity_attr = element->IntegrityAttributeValue(); | 
| 147 | 84 | 
| 148   // It is possible to get back a script resource with integrity metadata | 85   // It is possible to get back a script resource with integrity metadata | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 176           passed ? ResourceIntegrityDisposition::kPassed | 113           passed ? ResourceIntegrityDisposition::kPassed | 
| 177                  : ResourceIntegrityDisposition::kFailed); | 114                  : ResourceIntegrityDisposition::kFailed); | 
| 178       return passed; | 115       return passed; | 
| 179     } | 116     } | 
| 180   } | 117   } | 
| 181 | 118 | 
| 182   NOTREACHED(); | 119   NOTREACHED(); | 
| 183   return true; | 120   return true; | 
| 184 } | 121 } | 
| 185 | 122 | 
| 186 void PendingScript::NotifyFinished(Resource* resource) { | 123 void ClassicPendingScript::NotifyFinished(Resource* resource) { | 
| 187   // The following SRI checks need to be here because, unfortunately, fetches | 124   // The following SRI checks need to be here because, unfortunately, fetches | 
| 188   // are not done purely according to the Fetch spec. In particular, | 125   // are not done purely according to the Fetch spec. In particular, | 
| 189   // different requests for the same resource do not have different | 126   // different requests for the same resource do not have different | 
| 190   // responses; the memory cache can (and will) return the exact same | 127   // responses; the memory cache can (and will) return the exact same | 
| 191   // Resource object. | 128   // Resource object. | 
| 192   // | 129   // | 
| 193   // For different requests, the same Resource object will be returned and | 130   // For different requests, the same Resource object will be returned and | 
| 194   // will not be associated with the particular request.  Therefore, when the | 131   // 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 | 132   // 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 | 133   // of the Resource object against a particular request (since there may be | 
| 197   // several pending requests all tied to the identical object, and the | 134   // several pending requests all tied to the identical object, and the | 
| 198   // actual requests are not stored). | 135   // actual requests are not stored). | 
| 199   // | 136   // | 
| 200   // In order to simulate the correct behavior, Blink explicitly does the SRI | 137   // In order to simulate the correct behavior, Blink explicitly does the SRI | 
| 201   // checks here, when a PendingScript tied to a particular request is | 138   // 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), | 139   // 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 | 140   // 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 | 141   // fetch JavaScript API. In a future world where the ResourceFetcher uses | 
| 205   // the Fetch algorithm, this should be fixed by having separate Response | 142   // the Fetch algorithm, this should be fixed by having separate Response | 
| 206   // objects (perhaps attached to identical Resource objects) per request. | 143   // objects (perhaps attached to identical Resource objects) per request. | 
| 207   // | 144   // | 
| 208   // See https://crbug.com/500701 for more information. | 145   // See https://crbug.com/500701 for more information. | 
| 209   CheckState(); | 146   CheckState(); | 
| 210   if (element_) { | 147   if (!is_for_testing_ && GetElement()) { | 
| 211     integrity_failure_ = !CheckScriptResourceIntegrity(resource, element_); | 148     integrity_failure_ = !CheckScriptResourceIntegrity(resource, GetElement()); | 
| 212   } | 149   } | 
| 213 | 150 | 
| 214   // If script streaming is in use, the client will be notified in | 151   // If script streaming is in use, the client will be notified in | 
| 215   // streamingFinished. | 152   // streamingFinished. | 
| 216   if (streamer_) | 153   if (streamer_) | 
| 217     streamer_->NotifyFinished(resource); | 154     streamer_->NotifyFinished(resource); | 
| 218   else if (client_) | 155   else if (Client()) | 
| 219     client_->PendingScriptFinished(this); | 156     Client()->PendingScriptFinished(this); | 
| 220 } | 157 } | 
| 221 | 158 | 
| 222 void PendingScript::NotifyAppendData(ScriptResource* resource) { | 159 void ClassicPendingScript::NotifyAppendData(ScriptResource* resource) { | 
| 223   if (streamer_) | 160   if (streamer_) | 
| 224     streamer_->NotifyAppendData(resource); | 161     streamer_->NotifyAppendData(resource); | 
| 225 } | 162 } | 
| 226 | 163 | 
| 227 DEFINE_TRACE(PendingScript) { | 164 DEFINE_TRACE(ClassicPendingScript) { | 
| 228   visitor->Trace(element_); |  | 
| 229   visitor->Trace(streamer_); | 165   visitor->Trace(streamer_); | 
| 230   visitor->Trace(client_); |  | 
| 231   ResourceOwner<ScriptResource>::Trace(visitor); | 166   ResourceOwner<ScriptResource>::Trace(visitor); | 
| 232   MemoryCoordinatorClient::Trace(visitor); | 167   MemoryCoordinatorClient::Trace(visitor); | 
|  | 168   PendingScript::Trace(visitor); | 
| 233 } | 169 } | 
| 234 | 170 | 
| 235 ClassicScript* PendingScript::GetSource(const KURL& document_url, | 171 ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url, | 
| 236                                         bool& error_occurred) const { | 172                                                bool& error_occurred) const { | 
| 237   CheckState(); | 173   CheckState(); | 
| 238 | 174 | 
| 239   error_occurred = this->ErrorOccurred(); | 175   error_occurred = this->ErrorOccurred(); | 
| 240   if (GetResource()) { | 176   if (GetResource()) { | 
| 241     DCHECK(GetResource()->IsLoaded()); | 177     DCHECK(GetResource()->IsLoaded()); | 
| 242     if (streamer_ && !streamer_->StreamingSuppressed()) | 178     if (streamer_ && !streamer_->StreamingSuppressed()) | 
| 243       return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource())); | 179       return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource())); | 
| 244     return ClassicScript::Create(ScriptSourceCode(GetResource())); | 180     return ClassicScript::Create(ScriptSourceCode(GetResource())); | 
| 245   } | 181   } | 
| 246 | 182 | 
| 247   return ClassicScript::Create(ScriptSourceCode( | 183   return ClassicScript::Create(ScriptSourceCode( | 
| 248       element_->TextContent(), document_url, StartingPosition())); | 184       GetElement()->TextContent(), document_url, StartingPosition())); | 
| 249 } | 185 } | 
| 250 | 186 | 
| 251 void PendingScript::SetStreamer(ScriptStreamer* streamer) { | 187 void ClassicPendingScript::SetStreamer(ScriptStreamer* streamer) { | 
| 252   DCHECK(!streamer_); | 188   DCHECK(!streamer_); | 
| 253   DCHECK(!watching_for_load_); | 189   DCHECK(!IsWatchingForLoad()); | 
| 254   streamer_ = streamer; | 190   streamer_ = streamer; | 
| 255   CheckState(); | 191   CheckState(); | 
| 256 } | 192 } | 
| 257 | 193 | 
| 258 bool PendingScript::IsReady() const { | 194 bool ClassicPendingScript::IsReady() const { | 
| 259   CheckState(); | 195   CheckState(); | 
| 260   if (GetResource()) { | 196   if (GetResource()) { | 
| 261     return GetResource()->IsLoaded() && (!streamer_ || streamer_->IsFinished()); | 197     return GetResource()->IsLoaded() && (!streamer_ || streamer_->IsFinished()); | 
| 262   } | 198   } | 
| 263 | 199 | 
| 264   return true; | 200   return true; | 
| 265 } | 201 } | 
| 266 | 202 | 
| 267 bool PendingScript::ErrorOccurred() const { | 203 bool ClassicPendingScript::ErrorOccurred() const { | 
| 268   CheckState(); | 204   CheckState(); | 
| 269   if (GetResource()) | 205   if (GetResource()) | 
| 270     return GetResource()->ErrorOccurred() || integrity_failure_; | 206     return GetResource()->ErrorOccurred() || integrity_failure_; | 
| 271 | 207 | 
| 272   return false; | 208   return false; | 
| 273 } | 209 } | 
| 274 | 210 | 
| 275 void PendingScript::OnPurgeMemory() { | 211 void ClassicPendingScript::OnPurgeMemory() { | 
| 276   CheckState(); | 212   CheckState(); | 
| 277   if (!streamer_) | 213   if (!streamer_) | 
| 278     return; | 214     return; | 
| 279   streamer_->Cancel(); | 215   streamer_->Cancel(); | 
| 280   streamer_ = nullptr; | 216   streamer_ = nullptr; | 
| 281 } | 217 } | 
| 282 | 218 | 
| 283 void PendingScript::StartStreamingIfPossible( | 219 void ClassicPendingScript::StartStreamingIfPossible( | 
| 284     Document* document, | 220     Document* document, | 
| 285     ScriptStreamer::Type streamer_type) { | 221     ScriptStreamer::Type streamer_type) { | 
| 286   if (!document->GetFrame()) | 222   if (!document->GetFrame()) | 
| 287     return; | 223     return; | 
| 288 | 224 | 
| 289   ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame()); | 225   ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame()); | 
| 290   if (!script_state) | 226   if (!script_state) | 
| 291     return; | 227     return; | 
| 292 | 228 | 
| 293   ScriptStreamer::StartStreaming( | 229   ScriptStreamer::StartStreaming( | 
| 294       this, streamer_type, document->GetFrame()->GetSettings(), script_state, | 230       this, streamer_type, document->GetFrame()->GetSettings(), script_state, | 
| 295       TaskRunnerHelper::Get(TaskType::kNetworking, document)); | 231       TaskRunnerHelper::Get(TaskType::kNetworking, document)); | 
| 296 } | 232 } | 
| 297 | 233 | 
|  | 234 bool ClassicPendingScript::WasCanceled() const { | 
|  | 235   return GetResource()->WasCanceled(); | 
|  | 236 } | 
|  | 237 | 
|  | 238 KURL ClassicPendingScript::UrlForClassicScript() const { | 
|  | 239   return GetResource()->Url(); | 
|  | 240 } | 
|  | 241 | 
|  | 242 void ClassicPendingScript::RemoveFromMemoryCache() { | 
|  | 243   GetMemoryCache()->Remove(GetResource()); | 
|  | 244 } | 
|  | 245 | 
| 298 }  // namespace blink | 246 }  // namespace blink | 
| OLD | NEW | 
|---|