| Index: third_party/WebKit/Source/core/dom/PendingScript.cpp
 | 
| diff --git a/third_party/WebKit/Source/core/dom/PendingScript.cpp b/third_party/WebKit/Source/core/dom/PendingScript.cpp
 | 
| index cb907e201d15a4e3f91027ce8752cb158718b415..c3471192149d5137d2587196893412edf0d0d8b1 100644
 | 
| --- a/third_party/WebKit/Source/core/dom/PendingScript.cpp
 | 
| +++ b/third_party/WebKit/Source/core/dom/PendingScript.cpp
 | 
| @@ -25,37 +25,79 @@
 | 
|  
 | 
|  #include "core/dom/PendingScript.h"
 | 
|  
 | 
| +#include "bindings/core/v8/ScriptSourceCode.h"
 | 
| +#include "bindings/core/v8/ScriptState.h"
 | 
| +#include "bindings/core/v8/V8Binding.h"
 | 
| +#include "core/dom/ClassicScript.h"
 | 
| +#include "core/dom/Document.h"
 | 
|  #include "core/dom/ScriptElementBase.h"
 | 
| +#include "core/dom/TaskRunnerHelper.h"
 | 
| +#include "core/frame/LocalFrame.h"
 | 
| +#include "core/frame/SubresourceIntegrity.h"
 | 
| +#include "platform/SharedBuffer.h"
 | 
|  #include "platform/wtf/CurrentTime.h"
 | 
|  
 | 
|  namespace blink {
 | 
|  
 | 
| +PendingScript* PendingScript::Create(ScriptElementBase* element,
 | 
| +                                     ScriptResource* resource) {
 | 
| +  return new PendingScript(element, resource, TextPosition());
 | 
| +}
 | 
| +
 | 
| +PendingScript* PendingScript::Create(ScriptElementBase* element,
 | 
| +                                     const TextPosition& starting_position) {
 | 
| +  return new PendingScript(element, nullptr, starting_position);
 | 
| +}
 | 
| +
 | 
| +PendingScript* PendingScript::CreateForTesting(ScriptResource* resource) {
 | 
| +  return new PendingScript(nullptr, resource, TextPosition(), true);
 | 
| +}
 | 
| +
 | 
|  PendingScript::PendingScript(ScriptElementBase* element,
 | 
| -                             const TextPosition& starting_position)
 | 
| +                             ScriptResource* resource,
 | 
| +                             const TextPosition& starting_position,
 | 
| +                             bool is_for_testing)
 | 
|      : watching_for_load_(false),
 | 
|        element_(element),
 | 
|        starting_position_(starting_position),
 | 
| +      integrity_failure_(false),
 | 
|        parser_blocking_load_start_time_(0),
 | 
| -      client_(nullptr) {}
 | 
| +      client_(nullptr),
 | 
| +      is_for_testing_(is_for_testing) {
 | 
| +  CheckState();
 | 
| +  SetResource(resource);
 | 
| +  MemoryCoordinator::Instance().RegisterClient(this);
 | 
| +}
 | 
|  
 | 
|  PendingScript::~PendingScript() {}
 | 
| +
 | 
| +NOINLINE void PendingScript::CheckState() const {
 | 
| +  // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta.
 | 
| +  CHECK(is_for_testing_ || element_);
 | 
| +  CHECK(GetResource() || !streamer_);
 | 
| +  CHECK(!streamer_ || streamer_->GetResource() == GetResource());
 | 
| +}
 | 
|  
 | 
|  void PendingScript::Dispose() {
 | 
|    StopWatchingForLoad();
 | 
| -  DCHECK(!Client());
 | 
| -  DCHECK(!IsWatchingForLoad());
 | 
| -
 | 
| +  DCHECK(!client_);
 | 
| +  DCHECK(!watching_for_load_);
 | 
| +
 | 
| +  MemoryCoordinator::Instance().UnregisterClient(this);
 | 
| +  SetResource(nullptr);
 | 
|    starting_position_ = TextPosition::BelowRangePosition();
 | 
| +  integrity_failure_ = false;
 | 
|    parser_blocking_load_start_time_ = 0;
 | 
| -
 | 
| -  DisposeInternal();
 | 
| +  if (streamer_)
 | 
| +    streamer_->Cancel();
 | 
| +  streamer_ = nullptr;
 | 
|    element_ = nullptr;
 | 
|  }
 | 
|  
 | 
|  void PendingScript::WatchForLoad(PendingScriptClient* client) {
 | 
|    CheckState();
 | 
|  
 | 
| -  DCHECK(!IsWatchingForLoad());
 | 
| +  DCHECK(!watching_for_load_);
 | 
|    // addClient() will call streamingFinished() if the load is complete. Callers
 | 
|    // who do not expect to be re-entered from this call should not call
 | 
|    // watchForLoad for a PendingScript which isReady. We also need to set
 | 
| @@ -68,10 +110,10 @@
 | 
|  }
 | 
|  
 | 
|  void PendingScript::StopWatchingForLoad() {
 | 
| -  if (!IsWatchingForLoad())
 | 
| -    return;
 | 
| -  CheckState();
 | 
| -  DCHECK(IsExternal());
 | 
| +  if (!watching_for_load_)
 | 
| +    return;
 | 
| +  CheckState();
 | 
| +  DCHECK(GetResource());
 | 
|    client_ = nullptr;
 | 
|    watching_for_load_ = false;
 | 
|  }
 | 
| @@ -84,14 +126,173 @@
 | 
|    return element_.Get();
 | 
|  }
 | 
|  
 | 
| +void PendingScript::StreamingFinished() {
 | 
| +  CheckState();
 | 
| +  DCHECK(GetResource());
 | 
| +  if (client_)
 | 
| +    client_->PendingScriptFinished(this);
 | 
| +}
 | 
| +
 | 
|  void PendingScript::MarkParserBlockingLoadStartTime() {
 | 
|    DCHECK_EQ(parser_blocking_load_start_time_, 0.0);
 | 
|    parser_blocking_load_start_time_ = MonotonicallyIncreasingTime();
 | 
|  }
 | 
|  
 | 
| +// Returns true if SRI check passed.
 | 
| +static bool CheckScriptResourceIntegrity(Resource* resource,
 | 
| +                                         ScriptElementBase* element) {
 | 
| +  DCHECK_EQ(resource->GetType(), Resource::kScript);
 | 
| +  ScriptResource* script_resource = ToScriptResource(resource);
 | 
| +  String integrity_attr = element->IntegrityAttributeValue();
 | 
| +
 | 
| +  // It is possible to get back a script resource with integrity metadata
 | 
| +  // for a request with an empty integrity attribute. In that case, the
 | 
| +  // integrity check should be skipped, so this check ensures that the
 | 
| +  // integrity attribute isn't empty in addition to checking if the
 | 
| +  // resource has empty integrity metadata.
 | 
| +  if (integrity_attr.IsEmpty() ||
 | 
| +      script_resource->IntegrityMetadata().IsEmpty())
 | 
| +    return true;
 | 
| +
 | 
| +  switch (script_resource->IntegrityDisposition()) {
 | 
| +    case ResourceIntegrityDisposition::kPassed:
 | 
| +      return true;
 | 
| +
 | 
| +    case ResourceIntegrityDisposition::kFailed:
 | 
| +      // TODO(jww): This should probably also generate a console
 | 
| +      // message identical to the one produced by
 | 
| +      // CheckSubresourceIntegrity below. See https://crbug.com/585267.
 | 
| +      return false;
 | 
| +
 | 
| +    case ResourceIntegrityDisposition::kNotChecked: {
 | 
| +      if (!resource->ResourceBuffer())
 | 
| +        return true;
 | 
| +
 | 
| +      bool passed = SubresourceIntegrity::CheckSubresourceIntegrity(
 | 
| +          script_resource->IntegrityMetadata(), element->GetDocument(),
 | 
| +          resource->ResourceBuffer()->Data(),
 | 
| +          resource->ResourceBuffer()->size(), resource->Url(), *resource);
 | 
| +      script_resource->SetIntegrityDisposition(
 | 
| +          passed ? ResourceIntegrityDisposition::kPassed
 | 
| +                 : ResourceIntegrityDisposition::kFailed);
 | 
| +      return passed;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  NOTREACHED();
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +void PendingScript::NotifyFinished(Resource* resource) {
 | 
| +  // The following SRI checks need to be here because, unfortunately, fetches
 | 
| +  // are not done purely according to the Fetch spec. In particular,
 | 
| +  // different requests for the same resource do not have different
 | 
| +  // responses; the memory cache can (and will) return the exact same
 | 
| +  // Resource object.
 | 
| +  //
 | 
| +  // For different requests, the same Resource object will be returned and
 | 
| +  // will not be associated with the particular request.  Therefore, when the
 | 
| +  // body of the response comes in, there's no way to validate the integrity
 | 
| +  // of the Resource object against a particular request (since there may be
 | 
| +  // several pending requests all tied to the identical object, and the
 | 
| +  // actual requests are not stored).
 | 
| +  //
 | 
| +  // In order to simulate the correct behavior, Blink explicitly does the SRI
 | 
| +  // checks here, when a PendingScript tied to a particular request is
 | 
| +  // finished (and in the case of a StyleSheet, at the point of execution),
 | 
| +  // while having proper Fetch checks in the fetch module for use in the
 | 
| +  // fetch JavaScript API. In a future world where the ResourceFetcher uses
 | 
| +  // the Fetch algorithm, this should be fixed by having separate Response
 | 
| +  // objects (perhaps attached to identical Resource objects) per request.
 | 
| +  //
 | 
| +  // See https://crbug.com/500701 for more information.
 | 
| +  CheckState();
 | 
| +  if (element_) {
 | 
| +    integrity_failure_ = !CheckScriptResourceIntegrity(resource, element_);
 | 
| +  }
 | 
| +
 | 
| +  // If script streaming is in use, the client will be notified in
 | 
| +  // streamingFinished.
 | 
| +  if (streamer_)
 | 
| +    streamer_->NotifyFinished(resource);
 | 
| +  else if (client_)
 | 
| +    client_->PendingScriptFinished(this);
 | 
| +}
 | 
| +
 | 
| +void PendingScript::NotifyAppendData(ScriptResource* resource) {
 | 
| +  if (streamer_)
 | 
| +    streamer_->NotifyAppendData(resource);
 | 
| +}
 | 
| +
 | 
|  DEFINE_TRACE(PendingScript) {
 | 
|    visitor->Trace(element_);
 | 
| +  visitor->Trace(streamer_);
 | 
|    visitor->Trace(client_);
 | 
| +  ResourceOwner<ScriptResource>::Trace(visitor);
 | 
| +  MemoryCoordinatorClient::Trace(visitor);
 | 
| +}
 | 
| +
 | 
| +ClassicScript* PendingScript::GetSource(const KURL& document_url,
 | 
| +                                        bool& error_occurred) const {
 | 
| +  CheckState();
 | 
| +
 | 
| +  error_occurred = this->ErrorOccurred();
 | 
| +  if (GetResource()) {
 | 
| +    DCHECK(GetResource()->IsLoaded());
 | 
| +    if (streamer_ && !streamer_->StreamingSuppressed())
 | 
| +      return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource()));
 | 
| +    return ClassicScript::Create(ScriptSourceCode(GetResource()));
 | 
| +  }
 | 
| +
 | 
| +  return ClassicScript::Create(ScriptSourceCode(
 | 
| +      element_->TextContent(), document_url, StartingPosition()));
 | 
| +}
 | 
| +
 | 
| +void PendingScript::SetStreamer(ScriptStreamer* streamer) {
 | 
| +  DCHECK(!streamer_);
 | 
| +  DCHECK(!watching_for_load_);
 | 
| +  streamer_ = streamer;
 | 
| +  CheckState();
 | 
| +}
 | 
| +
 | 
| +bool PendingScript::IsReady() const {
 | 
| +  CheckState();
 | 
| +  if (GetResource()) {
 | 
| +    return GetResource()->IsLoaded() && (!streamer_ || streamer_->IsFinished());
 | 
| +  }
 | 
| +
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool PendingScript::ErrorOccurred() const {
 | 
| +  CheckState();
 | 
| +  if (GetResource())
 | 
| +    return GetResource()->ErrorOccurred() || integrity_failure_;
 | 
| +
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +void PendingScript::OnPurgeMemory() {
 | 
| +  CheckState();
 | 
| +  if (!streamer_)
 | 
| +    return;
 | 
| +  streamer_->Cancel();
 | 
| +  streamer_ = nullptr;
 | 
| +}
 | 
| +
 | 
| +void PendingScript::StartStreamingIfPossible(
 | 
| +    Document* document,
 | 
| +    ScriptStreamer::Type streamer_type) {
 | 
| +  if (!document->GetFrame())
 | 
| +    return;
 | 
| +
 | 
| +  ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame());
 | 
| +  if (!script_state)
 | 
| +    return;
 | 
| +
 | 
| +  ScriptStreamer::StartStreaming(
 | 
| +      this, streamer_type, document->GetFrame()->GetSettings(), script_state,
 | 
| +      TaskRunnerHelper::Get(TaskType::kNetworking, document));
 | 
|  }
 | 
|  
 | 
|  }  // namespace blink
 | 
| 
 |