blob: 0bc25d99c5b364416883ff1f4560bad0078a96e4 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/script/detect_javascript_frameworks.h"
#include "third_party/blink/public/common/loader/loading_behavior_flag.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
namespace blink {
namespace {
bool IsFrameworkVariableUsed(v8::Local<v8::Context> context,
const String& framework_variable_name) {
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> global = context->Global();
v8::TryCatch try_catch(isolate);
bool has_property;
bool succeeded =
global
->HasRealNamedProperty(
context, V8AtomicString(isolate, framework_variable_name))
.To(&has_property);
DCHECK(succeeded && !try_catch.HasCaught());
return has_property;
}
bool IsFrameworkIDUsed(Document& document, const AtomicString& framework_id) {
if (document.getElementById(framework_id)) {
return true;
}
return false;
}
void CheckForNextJS(Document& document, v8::Local<v8::Context> context) {
if (IsFrameworkIDUsed(document, "__next") &&
IsFrameworkVariableUsed(context, "__NEXT_DATA__")) {
document.Loader()->DidObserveLoadingBehavior(
LoadingBehaviorFlag::kLoadingBehaviorNextJSFrameworkUsed);
}
}
} // namespace
void DetectJavascriptFrameworksOnLoad(Document& document) {
// Only detect Javascript frameworks on the main frame and if URL and BaseURL
// is HTTP. Note: Without these checks, ToScriptStateForMainWorld will
// initialize WindowProxy and trigger a second DidClearWindowObject() earlier
// than expected for Android WebView. The Gin Java Bridge has a race condition
// that relies on a second DidClearWindowObject() firing immediately before
// executing JavaScript. See the document that explains this in more detail:
// https://docs.google.com/document/d/1R5170is5vY425OO2Ru-HJBEraEKu0HjQEakcYldcSzM/edit?usp=sharing
if (!document.GetFrame() || !document.GetFrame()->IsMainFrame() ||
!document.Url().ProtocolIsInHTTPFamily() ||
!document.BaseURL().ProtocolIsInHTTPFamily()) {
return;
}
ScriptState* script_state = ToScriptStateForMainWorld(document.GetFrame());
if (!script_state || !script_state->ContextIsValid()) {
return;
}
ScriptState::Scope scope(script_state);
v8::Local<v8::Context> context = script_state->GetContext();
CheckForNextJS(document, context);
}
} // namespace blink