2018-10-19 13:50:30 +00:00
|
|
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
|
|
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE-CHROMIUM file.
|
|
|
|
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/ui/inspectable_web_contents.h"
|
2018-10-19 13:50:30 +00:00
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
#include <memory>
|
2024-01-11 01:00:37 +00:00
|
|
|
#include <string_view>
|
2020-07-15 18:27:42 +00:00
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include "base/base64.h"
|
2023-05-11 20:07:39 +00:00
|
|
|
#include "base/memory/raw_ptr.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "base/metrics/histogram.h"
|
2024-01-30 20:48:47 +00:00
|
|
|
#include "base/ranges/algorithm.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "base/strings/pattern.h"
|
2024-01-24 22:43:31 +00:00
|
|
|
#include "base/strings/string_number_conversions.h"
|
chore: bump chromium to 128.0.6611.0 (main) (#42779)
* chore: bump chromium in DEPS to 128.0.6577.0
* chore: bump chromium in DEPS to 128.0.6579.0
* 5675706: Reland "Reland "Reland "Reland "Add toolchains without PartitionAlloc-Everywhere for dump_syms et al""""
https://chromium-review.googlesource.com/c/chromium/src/+/5675706
* 5668597: [PDF Ink Signatures] Prompt download menu on save when there are edits
https://chromium-review.googlesource.com/c/chromium/src/+/5668597
* 5677014: Reland "Pull data_sharing_sdk from CIPD"
https://chromium-review.googlesource.com/c/chromium/src/+/5677014
* chore: fixup patch indices
* chore: bump chromium in DEPS to 128.0.6581.0
* chore: bump chromium in DEPS to 128.0.6583.0
* update patches
* 5455480: [Extensions] Allow service worker requests to continue without a cert
https://chromium-review.googlesource.com/c/chromium/src/+/5455480
* try to get some debugging output from script/push-patch.js
* chore: bump chromium in DEPS to 128.0.6585.0
* chore: bump chromium in DEPS to 128.0.6587.0
* update patches
* chore: bump chromium in DEPS to 128.0.6589.0
* more patch work
* maybe over here?
* chore: update patches
* 5673207: [HTTPS Upgrades] Disable in captive portal login webview
https://chromium-review.googlesource.com/c/chromium/src/+/5673207
* 5636785: Extensions: WAR: manifest.json's use_dynamic_url requires a dynamic url
https://chromium-review.googlesource.com/c/chromium/src/+/5636785
* chore: bump chromium in DEPS to 128.0.6591.0
* 5665458: Trigger WN2 page when feature is enabled
https://chromium-review.googlesource.com/c/chromium/src/+/5665458
* update patches
* chore: bump chromium in DEPS to 128.0.6593.0
* chore: bump chromium in DEPS to 128.0.6595.0
* chore: bump chromium in DEPS to 128.0.6597.0
* (patch update) 5694586: [compile hints] Remove the usage of v8::Isolate::SetJavaScriptCompileHintsMagicEnabledCallback API
https://chromium-review.googlesource.com/c/chromium/src/+/5694586
* update patches
* 5691287: Reland "Change blink::WebKeyboardEvent to use std::array in is members"
https://chromium-review.googlesource.com/c/chromium/src/+/5691287
The code changed here is modeled after code in `content/renderer/pepper/event_conversion.cc` that was also modified in this CL, so I took the same approach.
* 5529018: Cleanup EnableWebHidOnExtensionServiceWorker flag
https://chromium-review.googlesource.com/c/chromium/src/+/5529018
* 5526324: [Code Health] Add deprecation comment for base::SupportsWeakPtr.
https://chromium-review.googlesource.com/c/chromium/src/+/5526324
Note that this CL actually does make `SupportsWeakPtr` strictly restricted to existing implementations, no new ones. We could add a patch to add ourselves to this list, but it looks like we'll have to refactor this anyways in the near future. Since the refactor seems straightforward, let's try that first.
* chore: bump chromium in DEPS to 128.0.6598.0
* chore: update patches
* 5704737: Rename ExclusiveAccessContext::GetActiveWebContents to avoid conflict
https://chromium-review.googlesource.com/c/chromium/src/+/5704737
* chore: bump chromium in DEPS to 128.0.6601.0
* chore: update patches
* Add `base::StringPiece` header includes
Chromium is working on replacing `base::StringPiece` with `std::string_view`. (See the Chromium Bug below.) They're currently running mass codemods (across many multiple changes) to replace uses of `StringPiece` with `string_view`, including removing the header include for `StringPiece` in those files. This cascades down to our files that were implicitly depending on those includes through some other include.
They're on track to eventually deprecate and remove `StringPiece` so our code should be converted, but that can be done as an upgrade follow-up task. For now, adding the header back to files that need it should suffice for minimal upgrade changes.
Chromium Bug: https://issues.chromium.org/issues/40506050
* 5702737: GlobalRequestID: Avoid unwanted inlining and narrowing int conversions
https://chromium-review.googlesource.com/c/chromium/src/+/5702737
contender for smallest commit 2024
* 5706534: Rename GlobalFeatures to GlobalDesktopFeatures.
https://chromium-review.googlesource.com/c/chromium/src/+/5706534
* 5691321: ui: remove params variants of SelectFile listener functions
https://chromium-review.googlesource.com/c/chromium/src/+/5691321
* 5714949: [Extensions] Display re-enable dialog for MV2 disabled stage
https://chromium-review.googlesource.com/c/chromium/src/+/5714949
* chore: update libc++ filenames
* patch: disable scope reuse & associated dchecks in v8 (hopefully temp, upgrade follow-up)
* fixup! Add `base::StringPiece` header includes
* update MAS patch
5710330: Add crash keys to debug NativeWidgetMacNSWindowBorderlessFrame exception
https://chromium-review.googlesource.com/c/chromium/src/+/5710330
* chore: bump chromium in DEPS to 128.0.6603.0
* chore: update patches
* 5713258: Reland "Preparation for decoupling creation/initialization of context"
https://chromium-review.googlesource.com/c/chromium/src/+/5713258
When destroying a context, it must already be shutdown, and this change enforces it with a new CHECK.
We were overriding `BrowserContextKeyedServiceFactory::BrowserContextShutdown` with an empty implementation, which differed from the default implementation that notifies the `KeyedServiceFactory` that the context has shutdown. Since we were missing this notification, the CHECK would later trip when the service was being destoryed because it was not registered as shutdown when it was shutdown.
* chore: bump chromium in DEPS to 128.0.6605.2
* chore: update patches
* refactor: linux open/save dialog patch
Our existing implementation was relying on an opaque `void* params` parameter that was passed through `ui::SelectFileDialog`.
Recently, that parameter has been getting removed:
- 5691321: ui: remove params variants of SelectFile listener functions | https://chromium-review.googlesource.com/c/chromium/src/+/5691321
- 5709097: ui: remove SelectFileDialog impl params | https://chromium-review.googlesource.com/c/chromium/src/+/5709097
- https://issues.chromium.org/issues/340178601 "reconsider SelectFileDialog"
This restructures the patch to work with mostly the same mechanics, but directly on the `ui::SelectFileDialog` object. This nets us some wins in terms of a smaller patch.
* 5713262: DevTools UI binding AIDA client event returns response
https://chromium-review.googlesource.com/c/chromium/src/+/5713262
* fixup! refactor: linux open/save dialog patch
* chore: bump chromium in DEPS to 128.0.6606.0
* chore: update patches
* fixup! refactor: linux open/save dialog patch
* chore: bump chromium in DEPS to 128.0.6607.0
* chore: update printing.patch
Xref: https://chromium-review.googlesource.com/c/chromium/src/+/5722937
* fix: pwd error in electron-test, nan-test
fix: unshallow depot_tools before 3-way apply
* chore: e patches all
* fixup! fix: pwd error in electron-test, nan-test
* chore: bump chromium in DEPS to 128.0.6609.0
* chore: bump chromium in DEPS to 128.0.6611.0
* chore: update patches
* chore: update libcxx filenames
---------
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: clavin <clavin@electronjs.org>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: Alice Zhao <alice@makenotion.com>
2024-07-23 15:59:44 +00:00
|
|
|
#include "base/strings/string_piece.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "base/strings/string_util.h"
|
|
|
|
#include "base/strings/stringprintf.h"
|
|
|
|
#include "base/strings/utf_string_conversions.h"
|
2024-07-22 09:31:32 +00:00
|
|
|
#include "base/timer/timer.h"
|
2023-06-13 18:45:48 +00:00
|
|
|
#include "base/uuid.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "base/values.h"
|
2023-06-06 19:03:39 +00:00
|
|
|
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "components/prefs/pref_registry_simple.h"
|
|
|
|
#include "components/prefs/pref_service.h"
|
|
|
|
#include "components/prefs/scoped_user_pref_update.h"
|
|
|
|
#include "content/public/browser/browser_context.h"
|
|
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
|
|
#include "content/public/browser/file_select_listener.h"
|
|
|
|
#include "content/public/browser/file_url_loader.h"
|
|
|
|
#include "content/public/browser/host_zoom_map.h"
|
|
|
|
#include "content/public/browser/navigation_handle.h"
|
|
|
|
#include "content/public/browser/render_frame_host.h"
|
|
|
|
#include "content/public/browser/render_view_host.h"
|
|
|
|
#include "content/public/browser/shared_cors_origin_access_list.h"
|
|
|
|
#include "content/public/browser/storage_partition.h"
|
|
|
|
#include "content/public/common/user_agent.h"
|
|
|
|
#include "ipc/ipc_channel.h"
|
|
|
|
#include "net/http/http_response_headers.h"
|
2021-06-01 01:47:53 +00:00
|
|
|
#include "net/http/http_status_code.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "services/network/public/cpp/simple_url_loader.h"
|
|
|
|
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
|
2020-09-21 08:00:36 +00:00
|
|
|
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
|
2021-04-23 20:51:37 +00:00
|
|
|
#include "shell/browser/api/electron_api_web_contents.h"
|
2023-09-07 08:14:01 +00:00
|
|
|
#include "shell/browser/native_window_views.h"
|
2021-04-12 04:59:36 +00:00
|
|
|
#include "shell/browser/net/asar/asar_url_loader_factory.h"
|
|
|
|
#include "shell/browser/protocol_registry.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "shell/browser/ui/inspectable_web_contents_delegate.h"
|
|
|
|
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
|
|
|
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
|
2023-09-07 08:14:01 +00:00
|
|
|
#include "shell/common/application_info.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
#include "shell/common/platform_util.h"
|
|
|
|
#include "third_party/blink/public/common/logging/logging_utils.h"
|
|
|
|
#include "third_party/blink/public/common/page/page_zoom.h"
|
|
|
|
#include "ui/display/display.h"
|
|
|
|
#include "ui/display/screen.h"
|
2021-04-23 20:51:37 +00:00
|
|
|
#include "v8/include/v8.h"
|
2020-07-15 18:27:42 +00:00
|
|
|
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
|
|
#include "chrome/common/extensions/chrome_manifest_url_handlers.h"
|
|
|
|
#include "content/public/browser/child_process_security_policy.h"
|
|
|
|
#include "content/public/browser/render_process_host.h"
|
|
|
|
#include "extensions/browser/extension_registry.h"
|
|
|
|
#include "extensions/common/permissions/permissions_data.h"
|
|
|
|
#endif
|
2018-10-19 13:50:30 +00:00
|
|
|
|
2019-06-19 21:23:04 +00:00
|
|
|
namespace electron {
|
2018-10-19 13:50:30 +00:00
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
const double kPresetZoomFactors[] = {0.25, 0.333, 0.5, 0.666, 0.75, 0.9,
|
|
|
|
1.0, 1.1, 1.25, 1.5, 1.75, 2.0,
|
|
|
|
2.5, 3.0, 4.0, 5.0};
|
|
|
|
|
|
|
|
const char kChromeUIDevToolsURL[] =
|
|
|
|
"devtools://devtools/bundled/devtools_app.html?"
|
|
|
|
"remoteBase=%s&"
|
|
|
|
"can_dock=%s&"
|
|
|
|
"toolbarColor=rgba(223,223,223,1)&"
|
|
|
|
"textColor=rgba(0,0,0,1)&"
|
|
|
|
"experiments=true";
|
|
|
|
const char kChromeUIDevToolsRemoteFrontendBase[] =
|
|
|
|
"https://chrome-devtools-frontend.appspot.com/";
|
|
|
|
const char kChromeUIDevToolsRemoteFrontendPath[] = "serve_file";
|
|
|
|
|
|
|
|
const char kDevToolsBoundsPref[] = "electron.devtools.bounds";
|
|
|
|
const char kDevToolsZoomPref[] = "electron.devtools.zoom";
|
|
|
|
const char kDevToolsPreferences[] = "electron.devtools.preferences";
|
|
|
|
|
|
|
|
const char kFrontendHostId[] = "id";
|
|
|
|
const char kFrontendHostMethod[] = "method";
|
|
|
|
const char kFrontendHostParams[] = "params";
|
|
|
|
const char kTitleFormat[] = "Developer Tools - %s";
|
|
|
|
|
|
|
|
const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
|
|
|
|
|
2023-05-23 19:58:58 +00:00
|
|
|
base::Value::Dict RectToDictionary(const gfx::Rect& bounds) {
|
|
|
|
return base::Value::Dict{}
|
|
|
|
.Set("x", bounds.x())
|
|
|
|
.Set("y", bounds.y())
|
|
|
|
.Set("width", bounds.width())
|
|
|
|
.Set("height", bounds.height());
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2023-03-10 16:07:42 +00:00
|
|
|
gfx::Rect DictionaryToRect(const base::Value::Dict& dict) {
|
2024-01-30 20:48:47 +00:00
|
|
|
return gfx::Rect{dict.FindInt("x").value_or(0), dict.FindInt("y").value_or(0),
|
|
|
|
dict.FindInt("width").value_or(800),
|
|
|
|
dict.FindInt("height").value_or(600)};
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsPointInScreen(const gfx::Point& point) {
|
2024-01-30 20:48:47 +00:00
|
|
|
return base::ranges::any_of(display::Screen::GetScreen()->GetAllDisplays(),
|
|
|
|
[&point](auto const& display) {
|
|
|
|
return display.bounds().Contains(point);
|
|
|
|
});
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetZoomLevelForWebContents(content::WebContents* web_contents,
|
|
|
|
double level) {
|
|
|
|
content::HostZoomMap::SetZoomLevel(web_contents, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
double GetNextZoomLevel(double level, bool out) {
|
2024-07-02 07:51:33 +00:00
|
|
|
double factor = blink::ZoomLevelToZoomFactor(level);
|
2022-03-25 01:39:03 +00:00
|
|
|
size_t size = std::size(kPresetZoomFactors);
|
2020-07-15 18:27:42 +00:00
|
|
|
for (size_t i = 0; i < size; ++i) {
|
2024-07-02 07:51:33 +00:00
|
|
|
if (!blink::ZoomValuesEqual(kPresetZoomFactors[i], factor))
|
2020-07-15 18:27:42 +00:00
|
|
|
continue;
|
|
|
|
if (out && i > 0)
|
2024-07-02 07:51:33 +00:00
|
|
|
return blink::ZoomFactorToZoomLevel(kPresetZoomFactors[i - 1]);
|
2020-07-15 18:27:42 +00:00
|
|
|
if (!out && i != size - 1)
|
2024-07-02 07:51:33 +00:00
|
|
|
return blink::ZoomFactorToZoomLevel(kPresetZoomFactors[i + 1]);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
|
|
|
GURL GetRemoteBaseURL() {
|
|
|
|
return GURL(base::StringPrintf("%s%s/%s/",
|
|
|
|
kChromeUIDevToolsRemoteFrontendBase,
|
|
|
|
kChromeUIDevToolsRemoteFrontendPath,
|
2021-06-22 19:17:16 +00:00
|
|
|
content::GetChromiumGitRevision().c_str()));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GURL GetDevToolsURL(bool can_dock) {
|
|
|
|
auto url_string = base::StringPrintf(kChromeUIDevToolsURL,
|
|
|
|
GetRemoteBaseURL().spec().c_str(),
|
|
|
|
can_dock ? "true" : "");
|
|
|
|
return GURL(url_string);
|
|
|
|
}
|
|
|
|
|
2022-03-08 19:40:25 +00:00
|
|
|
void OnOpenItemComplete(const base::FilePath& path, const std::string& result) {
|
|
|
|
platform_util::ShowItemInFolder(path);
|
|
|
|
}
|
|
|
|
|
2021-11-24 08:45:59 +00:00
|
|
|
constexpr base::TimeDelta kInitialBackoffDelay = base::Milliseconds(250);
|
|
|
|
constexpr base::TimeDelta kMaxBackoffDelay = base::Seconds(10);
|
2020-07-15 18:27:42 +00:00
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
class InspectableWebContents::NetworkResourceLoader
|
|
|
|
: public network::SimpleURLLoaderStreamConsumer {
|
|
|
|
public:
|
|
|
|
class URLLoaderFactoryHolder {
|
|
|
|
public:
|
|
|
|
network::mojom::URLLoaderFactory* get() {
|
|
|
|
return ptr_.get() ? ptr_.get() : refptr_.get();
|
|
|
|
}
|
|
|
|
void operator=(std::unique_ptr<network::mojom::URLLoaderFactory>&& ptr) {
|
|
|
|
ptr_ = std::move(ptr);
|
|
|
|
}
|
|
|
|
void operator=(scoped_refptr<network::SharedURLLoaderFactory>&& refptr) {
|
|
|
|
refptr_ = std::move(refptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unique_ptr<network::mojom::URLLoaderFactory> ptr_;
|
|
|
|
scoped_refptr<network::SharedURLLoaderFactory> refptr_;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void Create(int stream_id,
|
|
|
|
InspectableWebContents* bindings,
|
|
|
|
const network::ResourceRequest& resource_request,
|
|
|
|
const net::NetworkTrafficAnnotationTag& traffic_annotation,
|
|
|
|
URLLoaderFactoryHolder url_loader_factory,
|
2021-01-12 23:31:23 +00:00
|
|
|
DispatchCallback callback,
|
2020-07-15 18:27:42 +00:00
|
|
|
base::TimeDelta retry_delay = base::TimeDelta()) {
|
2024-01-05 11:18:31 +00:00
|
|
|
bindings->loaders_.insert(
|
2020-07-15 18:27:42 +00:00
|
|
|
std::make_unique<InspectableWebContents::NetworkResourceLoader>(
|
|
|
|
stream_id, bindings, resource_request, traffic_annotation,
|
2024-01-05 11:18:31 +00:00
|
|
|
std::move(url_loader_factory), std::move(callback), retry_delay));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NetworkResourceLoader(
|
|
|
|
int stream_id,
|
|
|
|
InspectableWebContents* bindings,
|
|
|
|
const network::ResourceRequest& resource_request,
|
|
|
|
const net::NetworkTrafficAnnotationTag& traffic_annotation,
|
|
|
|
URLLoaderFactoryHolder url_loader_factory,
|
2021-01-12 23:31:23 +00:00
|
|
|
DispatchCallback callback,
|
2020-07-15 18:27:42 +00:00
|
|
|
base::TimeDelta delay)
|
|
|
|
: stream_id_(stream_id),
|
|
|
|
bindings_(bindings),
|
|
|
|
resource_request_(resource_request),
|
|
|
|
traffic_annotation_(traffic_annotation),
|
|
|
|
loader_(network::SimpleURLLoader::Create(
|
|
|
|
std::make_unique<network::ResourceRequest>(resource_request),
|
|
|
|
traffic_annotation)),
|
|
|
|
url_loader_factory_(std::move(url_loader_factory)),
|
2021-01-12 23:31:23 +00:00
|
|
|
callback_(std::move(callback)),
|
2020-07-15 18:27:42 +00:00
|
|
|
retry_delay_(delay) {
|
|
|
|
loader_->SetOnResponseStartedCallback(base::BindOnce(
|
|
|
|
&NetworkResourceLoader::OnResponseStarted, base::Unretained(this)));
|
|
|
|
timer_.Start(FROM_HERE, delay,
|
|
|
|
base::BindRepeating(&NetworkResourceLoader::DownloadAsStream,
|
|
|
|
base::Unretained(this)));
|
|
|
|
}
|
|
|
|
|
|
|
|
NetworkResourceLoader(const NetworkResourceLoader&) = delete;
|
|
|
|
NetworkResourceLoader& operator=(const NetworkResourceLoader&) = delete;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void DownloadAsStream() {
|
|
|
|
loader_->DownloadAsStream(url_loader_factory_.get(), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
base::TimeDelta GetNextExponentialBackoffDelay(const base::TimeDelta& delta) {
|
|
|
|
if (delta.is_zero()) {
|
|
|
|
return kInitialBackoffDelay;
|
|
|
|
} else {
|
|
|
|
return delta * 1.3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnResponseStarted(const GURL& final_url,
|
|
|
|
const network::mojom::URLResponseHead& response_head) {
|
|
|
|
response_headers_ = response_head.headers;
|
|
|
|
}
|
|
|
|
|
2024-06-20 08:49:07 +00:00
|
|
|
// network::SimpleURLLoaderStreamConsumer
|
2020-07-15 18:27:42 +00:00
|
|
|
void OnDataReceived(base::StringPiece chunk,
|
|
|
|
base::OnceClosure resume) override {
|
|
|
|
bool encoded = !base::IsStringUTF8(chunk);
|
2024-01-15 10:01:35 +00:00
|
|
|
bindings_->CallClientFunction(
|
|
|
|
"DevToolsAPI", "streamWrite", base::Value{stream_id_},
|
|
|
|
base::Value{encoded ? base::Base64Encode(chunk) : chunk},
|
|
|
|
base::Value{encoded});
|
2020-07-15 18:27:42 +00:00
|
|
|
std::move(resume).Run();
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnComplete(bool success) override {
|
|
|
|
if (!success && loader_->NetError() == net::ERR_INSUFFICIENT_RESOURCES &&
|
|
|
|
retry_delay_ < kMaxBackoffDelay) {
|
|
|
|
const base::TimeDelta delay =
|
|
|
|
GetNextExponentialBackoffDelay(retry_delay_);
|
|
|
|
LOG(WARNING) << "InspectableWebContents::NetworkResourceLoader id = "
|
|
|
|
<< stream_id_
|
|
|
|
<< " failed with insufficient resources, retrying in "
|
|
|
|
<< delay << "." << std::endl;
|
|
|
|
NetworkResourceLoader::Create(
|
|
|
|
stream_id_, bindings_, resource_request_, traffic_annotation_,
|
2021-01-12 23:31:23 +00:00
|
|
|
std::move(url_loader_factory_), std::move(callback_), delay);
|
2020-07-15 18:27:42 +00:00
|
|
|
} else {
|
2023-01-06 02:35:34 +00:00
|
|
|
base::Value response(base::Value::Type::DICT);
|
|
|
|
response.GetDict().Set(
|
|
|
|
"statusCode", response_headers_ ? response_headers_->response_code()
|
|
|
|
: net::HTTP_OK);
|
2020-07-15 18:27:42 +00:00
|
|
|
|
2023-01-06 02:35:34 +00:00
|
|
|
base::Value::Dict headers;
|
2020-07-15 18:27:42 +00:00
|
|
|
size_t iterator = 0;
|
|
|
|
std::string name;
|
|
|
|
std::string value;
|
|
|
|
while (response_headers_ &&
|
|
|
|
response_headers_->EnumerateHeaderLines(&iterator, &name, &value))
|
2023-01-06 02:35:34 +00:00
|
|
|
headers.Set(name, value);
|
|
|
|
|
|
|
|
response.GetDict().Set("headers", std::move(headers));
|
2020-07-15 18:27:42 +00:00
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
std::move(callback_).Run(&response);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-05 11:18:31 +00:00
|
|
|
bindings_->loaders_.erase(this);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OnRetry(base::OnceClosure start_retry) override {}
|
|
|
|
|
|
|
|
const int stream_id_;
|
2023-05-11 20:07:39 +00:00
|
|
|
raw_ptr<InspectableWebContents> const bindings_;
|
2020-07-15 18:27:42 +00:00
|
|
|
const network::ResourceRequest resource_request_;
|
|
|
|
const net::NetworkTrafficAnnotationTag traffic_annotation_;
|
|
|
|
std::unique_ptr<network::SimpleURLLoader> loader_;
|
|
|
|
URLLoaderFactoryHolder url_loader_factory_;
|
|
|
|
DispatchCallback callback_;
|
|
|
|
scoped_refptr<net::HttpResponseHeaders> response_headers_;
|
|
|
|
base::OneShotTimer timer_;
|
|
|
|
base::TimeDelta retry_delay_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// static
|
|
|
|
void InspectableWebContents::RegisterPrefs(PrefRegistrySimple* registry) {
|
|
|
|
registry->RegisterDictionaryPref(kDevToolsBoundsPref,
|
2023-05-23 19:58:58 +00:00
|
|
|
RectToDictionary(gfx::Rect{0, 0, 800, 600}));
|
2020-07-15 18:27:42 +00:00
|
|
|
registry->RegisterDoublePref(kDevToolsZoomPref, 0.);
|
|
|
|
registry->RegisterDictionaryPref(kDevToolsPreferences);
|
|
|
|
}
|
|
|
|
|
|
|
|
InspectableWebContents::InspectableWebContents(
|
2021-09-20 00:34:11 +00:00
|
|
|
std::unique_ptr<content::WebContents> web_contents,
|
2018-10-19 13:50:30 +00:00
|
|
|
PrefService* pref_service,
|
2020-07-15 18:27:42 +00:00
|
|
|
bool is_guest)
|
2021-01-26 18:16:21 +00:00
|
|
|
: pref_service_(pref_service),
|
2021-09-20 00:34:11 +00:00
|
|
|
web_contents_(std::move(web_contents)),
|
2020-07-15 18:27:42 +00:00
|
|
|
is_guest_(is_guest),
|
2024-03-04 17:32:40 +00:00
|
|
|
view_(new InspectableWebContentsView(this)) {
|
2022-09-07 07:46:37 +00:00
|
|
|
const base::Value* bounds_dict =
|
|
|
|
&pref_service_->GetValue(kDevToolsBoundsPref);
|
2020-07-15 18:27:42 +00:00
|
|
|
if (bounds_dict->is_dict()) {
|
2023-03-10 16:07:42 +00:00
|
|
|
devtools_bounds_ = DictionaryToRect(bounds_dict->GetDict());
|
2020-07-15 18:27:42 +00:00
|
|
|
// Sometimes the devtools window is out of screen or has too small size.
|
|
|
|
if (devtools_bounds_.height() < 100 || devtools_bounds_.width() < 100) {
|
|
|
|
devtools_bounds_.set_height(600);
|
|
|
|
devtools_bounds_.set_width(800);
|
|
|
|
}
|
|
|
|
if (!IsPointInScreen(devtools_bounds_.origin())) {
|
|
|
|
gfx::Rect display;
|
2021-09-20 00:34:11 +00:00
|
|
|
if (!is_guest && web_contents_->GetNativeView()) {
|
2020-07-15 18:27:42 +00:00
|
|
|
display = display::Screen::GetScreen()
|
2021-09-20 00:34:11 +00:00
|
|
|
->GetDisplayNearestView(web_contents_->GetNativeView())
|
2020-07-15 18:27:42 +00:00
|
|
|
.bounds();
|
|
|
|
} else {
|
|
|
|
display = display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
|
|
|
|
}
|
|
|
|
|
|
|
|
devtools_bounds_.set_x(display.x() +
|
|
|
|
(display.width() - devtools_bounds_.width()) / 2);
|
|
|
|
devtools_bounds_.set_y(
|
|
|
|
display.y() + (display.height() - devtools_bounds_.height()) / 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InspectableWebContents::~InspectableWebContents() {
|
|
|
|
// Unsubscribe from devtools and Clean up resources.
|
2021-03-15 22:43:25 +00:00
|
|
|
if (GetDevToolsWebContents())
|
2020-07-15 18:27:42 +00:00
|
|
|
WebContentsDestroyed();
|
|
|
|
// Let destructor destroy managed_devtools_web_contents_.
|
|
|
|
}
|
|
|
|
|
|
|
|
InspectableWebContentsView* InspectableWebContents::GetView() const {
|
|
|
|
return view_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
content::WebContents* InspectableWebContents::GetWebContents() const {
|
|
|
|
return web_contents_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
content::WebContents* InspectableWebContents::GetDevToolsWebContents() const {
|
|
|
|
if (external_devtools_web_contents_)
|
|
|
|
return external_devtools_web_contents_;
|
|
|
|
else
|
|
|
|
return managed_devtools_web_contents_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::InspectElement(int x, int y) {
|
|
|
|
if (agent_host_)
|
2022-06-27 20:50:08 +00:00
|
|
|
agent_host_->InspectElement(web_contents_->GetPrimaryMainFrame(), x, y);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SetDelegate(
|
|
|
|
InspectableWebContentsDelegate* delegate) {
|
|
|
|
delegate_ = delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
InspectableWebContentsDelegate* InspectableWebContents::GetDelegate() const {
|
|
|
|
return delegate_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ReleaseWebContents() {
|
|
|
|
web_contents_.release();
|
2021-03-15 22:43:25 +00:00
|
|
|
WebContentsDestroyed();
|
|
|
|
view_.reset();
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SetDockState(const std::string& state) {
|
|
|
|
if (state == "detach") {
|
|
|
|
can_dock_ = false;
|
|
|
|
} else {
|
|
|
|
can_dock_ = true;
|
|
|
|
dock_state_ = state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-15 05:32:53 +00:00
|
|
|
void InspectableWebContents::SetDevToolsTitle(const std::u16string& title) {
|
|
|
|
devtools_title_ = title;
|
|
|
|
view_->SetTitle(devtools_title_);
|
|
|
|
}
|
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
void InspectableWebContents::SetDevToolsWebContents(
|
|
|
|
content::WebContents* devtools) {
|
|
|
|
if (!managed_devtools_web_contents_)
|
|
|
|
external_devtools_web_contents_ = devtools;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ShowDevTools(bool activate) {
|
|
|
|
if (embedder_message_dispatcher_) {
|
|
|
|
if (managed_devtools_web_contents_)
|
|
|
|
view_->ShowDevTools(activate);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
activate_ = activate;
|
|
|
|
|
|
|
|
// Show devtools only after it has done loading, this is to make sure the
|
|
|
|
// SetIsDocked is called *BEFORE* ShowDevTools.
|
|
|
|
embedder_message_dispatcher_ =
|
|
|
|
DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this);
|
|
|
|
|
|
|
|
if (!external_devtools_web_contents_) { // no external devtools
|
|
|
|
managed_devtools_web_contents_ = content::WebContents::Create(
|
|
|
|
content::WebContents::CreateParams(web_contents_->GetBrowserContext()));
|
|
|
|
managed_devtools_web_contents_->SetDelegate(this);
|
2021-04-23 20:51:37 +00:00
|
|
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
|
|
v8::HandleScope scope(isolate);
|
|
|
|
api::WebContents::FromOrCreate(isolate,
|
|
|
|
managed_devtools_web_contents_.get());
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Observe(GetDevToolsWebContents());
|
|
|
|
AttachTo(content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get()));
|
|
|
|
|
|
|
|
GetDevToolsWebContents()->GetController().LoadURL(
|
|
|
|
GetDevToolsURL(can_dock_), content::Referrer(),
|
|
|
|
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::CloseDevTools() {
|
|
|
|
if (GetDevToolsWebContents()) {
|
|
|
|
frontend_loaded_ = false;
|
|
|
|
if (managed_devtools_web_contents_) {
|
|
|
|
view_->CloseDevTools();
|
|
|
|
managed_devtools_web_contents_.reset();
|
|
|
|
}
|
|
|
|
embedder_message_dispatcher_.reset();
|
2024-02-09 09:29:14 +00:00
|
|
|
if (!is_guest())
|
2020-07-15 18:27:42 +00:00
|
|
|
web_contents_->Focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InspectableWebContents::IsDevToolsViewShowing() {
|
|
|
|
return managed_devtools_web_contents_ && view_->IsDevToolsViewShowing();
|
|
|
|
}
|
|
|
|
|
2023-08-15 05:32:53 +00:00
|
|
|
std::u16string InspectableWebContents::GetDevToolsTitle() {
|
|
|
|
return view_->GetTitle();
|
|
|
|
}
|
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
void InspectableWebContents::AttachTo(
|
|
|
|
scoped_refptr<content::DevToolsAgentHost> host) {
|
|
|
|
Detach();
|
|
|
|
agent_host_ = std::move(host);
|
|
|
|
// We could use ForceAttachClient here if problem arises with
|
|
|
|
// devtools multiple session support.
|
|
|
|
agent_host_->AttachClient(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::Detach() {
|
|
|
|
if (agent_host_)
|
|
|
|
agent_host_->DetachClient(this);
|
|
|
|
agent_host_ = nullptr;
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
void InspectableWebContents::Reattach(DispatchCallback callback) {
|
2020-07-15 18:27:42 +00:00
|
|
|
if (agent_host_) {
|
|
|
|
agent_host_->DetachClient(this);
|
|
|
|
agent_host_->AttachClient(this);
|
|
|
|
}
|
2021-01-12 23:31:23 +00:00
|
|
|
std::move(callback).Run(nullptr);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::CallClientFunction(
|
2022-06-29 16:39:48 +00:00
|
|
|
const std::string& object_name,
|
|
|
|
const std::string& method_name,
|
|
|
|
base::Value arg1,
|
|
|
|
base::Value arg2,
|
|
|
|
base::Value arg3,
|
|
|
|
base::OnceCallback<void(base::Value)> cb) {
|
2020-07-15 18:27:42 +00:00
|
|
|
if (!GetDevToolsWebContents())
|
|
|
|
return;
|
|
|
|
|
2022-06-29 16:39:48 +00:00
|
|
|
base::Value::List arguments;
|
|
|
|
if (!arg1.is_none()) {
|
|
|
|
arguments.Append(std::move(arg1));
|
|
|
|
if (!arg2.is_none()) {
|
|
|
|
arguments.Append(std::move(arg2));
|
|
|
|
if (!arg3.is_none()) {
|
|
|
|
arguments.Append(std::move(arg3));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-29 16:39:48 +00:00
|
|
|
|
|
|
|
GetDevToolsWebContents()->GetPrimaryMainFrame()->ExecuteJavaScriptMethod(
|
|
|
|
base::ASCIIToUTF16(object_name), base::ASCIIToUTF16(method_name),
|
|
|
|
std::move(arguments), std::move(cb));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SaveDevToolsBounds(const gfx::Rect& bounds) {
|
2023-05-23 19:58:58 +00:00
|
|
|
pref_service_->Set(kDevToolsBoundsPref,
|
|
|
|
base::Value{RectToDictionary(bounds)});
|
2020-07-15 18:27:42 +00:00
|
|
|
devtools_bounds_ = bounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
double InspectableWebContents::GetDevToolsZoomLevel() const {
|
|
|
|
return pref_service_->GetDouble(kDevToolsZoomPref);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::UpdateDevToolsZoomLevel(double level) {
|
|
|
|
pref_service_->SetDouble(kDevToolsZoomPref, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ActivateWindow() {
|
|
|
|
// Set the zoom level.
|
|
|
|
SetZoomLevelForWebContents(GetDevToolsWebContents(), GetDevToolsZoomLevel());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::CloseWindow() {
|
|
|
|
GetDevToolsWebContents()->DispatchBeforeUnload(false /* auto_cancel */);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::LoadCompleted() {
|
|
|
|
frontend_loaded_ = true;
|
|
|
|
if (managed_devtools_web_contents_)
|
|
|
|
view_->ShowDevTools(activate_);
|
|
|
|
|
|
|
|
// If the devtools can dock, "SetIsDocked" will be called by devtools itself.
|
|
|
|
if (!can_dock_) {
|
|
|
|
SetIsDocked(DispatchCallback(), false);
|
2023-08-15 05:32:53 +00:00
|
|
|
if (!devtools_title_.empty()) {
|
|
|
|
view_->SetTitle(devtools_title_);
|
|
|
|
}
|
2020-07-15 18:27:42 +00:00
|
|
|
} else {
|
|
|
|
if (dock_state_.empty()) {
|
2022-10-03 20:21:00 +00:00
|
|
|
const base::Value::Dict& prefs =
|
|
|
|
pref_service_->GetDict(kDevToolsPreferences);
|
2022-02-10 02:58:52 +00:00
|
|
|
const std::string* current_dock_state =
|
2022-10-03 20:21:00 +00:00
|
|
|
prefs.FindString("currentDockState");
|
2022-02-10 02:58:52 +00:00
|
|
|
base::RemoveChars(*current_dock_state, "\"", &dock_state_);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
2023-09-07 08:14:01 +00:00
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
|
|
auto* api_web_contents = api::WebContents::From(GetWebContents());
|
|
|
|
if (api_web_contents) {
|
|
|
|
auto* win =
|
|
|
|
static_cast<NativeWindowViews*>(api_web_contents->owner_window());
|
|
|
|
// When WCO is enabled, undock the devtools if the current dock
|
|
|
|
// position overlaps with the position of window controls to avoid
|
|
|
|
// broken layout.
|
|
|
|
if (win && win->IsWindowControlsOverlayEnabled()) {
|
|
|
|
if (IsAppRTL() && dock_state_ == "left") {
|
|
|
|
dock_state_ = "undocked";
|
|
|
|
} else if (dock_state_ == "right") {
|
|
|
|
dock_state_ = "undocked";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-03-16 16:18:45 +00:00
|
|
|
std::u16string javascript = base::UTF8ToUTF16(
|
2023-10-26 18:36:04 +00:00
|
|
|
"EUI.DockController.DockController.instance().setDockSide(\"" +
|
|
|
|
dock_state_ + "\");");
|
2022-06-27 20:50:08 +00:00
|
|
|
GetDevToolsWebContents()->GetPrimaryMainFrame()->ExecuteJavaScript(
|
2020-07-15 18:27:42 +00:00
|
|
|
javascript, base::NullCallback());
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
|
|
AddDevToolsExtensionsToClient();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (view_->GetDelegate())
|
|
|
|
view_->GetDelegate()->DevToolsOpened();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
|
|
void InspectableWebContents::AddDevToolsExtensionsToClient() {
|
|
|
|
// get main browser context
|
|
|
|
auto* browser_context = web_contents_->GetBrowserContext();
|
|
|
|
const extensions::ExtensionRegistry* registry =
|
|
|
|
extensions::ExtensionRegistry::Get(browser_context);
|
|
|
|
if (!registry)
|
|
|
|
return;
|
|
|
|
|
2022-06-29 16:39:48 +00:00
|
|
|
base::Value::List results;
|
2020-07-15 18:27:42 +00:00
|
|
|
for (auto& extension : registry->enabled_extensions()) {
|
|
|
|
auto devtools_page_url =
|
|
|
|
extensions::chrome_manifest_urls::GetDevToolsPage(extension.get());
|
|
|
|
if (devtools_page_url.is_empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Each devtools extension will need to be able to run in the devtools
|
|
|
|
// process. Grant the devtools process the ability to request URLs from the
|
|
|
|
// extension.
|
|
|
|
content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestOrigin(
|
2022-06-27 20:50:08 +00:00
|
|
|
web_contents_->GetPrimaryMainFrame()->GetProcess()->GetID(),
|
2020-07-15 18:27:42 +00:00
|
|
|
url::Origin::Create(extension->url()));
|
|
|
|
|
2022-06-29 16:39:48 +00:00
|
|
|
base::Value::Dict extension_info;
|
|
|
|
extension_info.Set("startPage", devtools_page_url.spec());
|
|
|
|
extension_info.Set("name", extension->name());
|
|
|
|
extension_info.Set("exposeExperimentalAPIs",
|
|
|
|
extension->permissions_data()->HasAPIPermission(
|
|
|
|
extensions::mojom::APIPermissionID::kExperimental));
|
2023-07-31 17:47:32 +00:00
|
|
|
extension_info.Set("allowFileAccess",
|
|
|
|
(extension->creation_flags() &
|
|
|
|
extensions::Extension::ALLOW_FILE_ACCESS) != 0);
|
2023-03-20 14:26:42 +00:00
|
|
|
results.Append(std::move(extension_info));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2022-06-29 16:39:48 +00:00
|
|
|
CallClientFunction("DevToolsAPI", "addExtensions",
|
|
|
|
base::Value(std::move(results)));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void InspectableWebContents::SetInspectedPageBounds(const gfx::Rect& rect) {
|
|
|
|
if (managed_devtools_web_contents_)
|
2023-06-06 19:03:39 +00:00
|
|
|
view_->SetContentsResizingStrategy(DevToolsContentsResizingStrategy{rect});
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::InspectElementCompleted() {}
|
|
|
|
|
|
|
|
void InspectableWebContents::InspectedURLChanged(const std::string& url) {
|
2023-08-15 05:32:53 +00:00
|
|
|
if (managed_devtools_web_contents_) {
|
|
|
|
if (devtools_title_.empty()) {
|
|
|
|
view_->SetTitle(
|
|
|
|
base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
|
|
|
|
}
|
|
|
|
}
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
void InspectableWebContents::LoadNetworkResource(DispatchCallback callback,
|
|
|
|
const std::string& url,
|
|
|
|
const std::string& headers,
|
|
|
|
int stream_id) {
|
2020-07-15 18:27:42 +00:00
|
|
|
GURL gurl(url);
|
|
|
|
if (!gurl.is_valid()) {
|
2023-01-06 02:35:34 +00:00
|
|
|
base::Value response(base::Value::Type::DICT);
|
|
|
|
response.GetDict().Set("statusCode", net::HTTP_NOT_FOUND);
|
2021-01-12 23:31:23 +00:00
|
|
|
std::move(callback).Run(&response);
|
2020-07-15 18:27:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create traffic annotation tag.
|
|
|
|
net::NetworkTrafficAnnotationTag traffic_annotation =
|
|
|
|
net::DefineNetworkTrafficAnnotation("devtools_network_resource", R"(
|
|
|
|
semantics {
|
|
|
|
sender: "Developer Tools"
|
|
|
|
description:
|
|
|
|
"When user opens Developer Tools, the browser may fetch additional "
|
|
|
|
"resources from the network to enrich the debugging experience "
|
|
|
|
"(e.g. source map resources)."
|
|
|
|
trigger: "User opens Developer Tools to debug a web page."
|
|
|
|
data: "Any resources requested by Developer Tools."
|
|
|
|
destination: WEBSITE
|
|
|
|
}
|
|
|
|
policy {
|
|
|
|
cookies_allowed: YES
|
|
|
|
cookies_store: "user"
|
|
|
|
setting:
|
|
|
|
"It's not possible to disable this feature from settings."
|
|
|
|
})");
|
|
|
|
|
|
|
|
network::ResourceRequest resource_request;
|
|
|
|
resource_request.url = gurl;
|
|
|
|
resource_request.site_for_cookies = net::SiteForCookies::FromUrl(gurl);
|
|
|
|
resource_request.headers.AddHeadersFromString(headers);
|
|
|
|
|
2024-05-09 13:53:09 +00:00
|
|
|
const auto* const protocol_registry = ProtocolRegistry::FromBrowserContext(
|
2021-04-12 04:59:36 +00:00
|
|
|
GetDevToolsWebContents()->GetBrowserContext());
|
2020-07-15 18:27:42 +00:00
|
|
|
NetworkResourceLoader::URLLoaderFactoryHolder url_loader_factory;
|
|
|
|
if (gurl.SchemeIsFile()) {
|
2020-09-21 08:00:36 +00:00
|
|
|
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote =
|
2021-04-12 04:59:36 +00:00
|
|
|
AsarURLLoaderFactory::Create();
|
|
|
|
url_loader_factory = network::SharedURLLoaderFactory::Create(
|
|
|
|
std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
|
|
|
|
std::move(pending_remote)));
|
2024-05-09 13:53:09 +00:00
|
|
|
} else if (const auto* const protocol_handler =
|
|
|
|
protocol_registry->FindRegistered(gurl.scheme())) {
|
2020-09-21 08:00:36 +00:00
|
|
|
url_loader_factory = network::SharedURLLoaderFactory::Create(
|
|
|
|
std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
|
2024-05-09 13:53:09 +00:00
|
|
|
ElectronURLLoaderFactory::Create(protocol_handler->first,
|
|
|
|
protocol_handler->second)));
|
2020-07-15 18:27:42 +00:00
|
|
|
} else {
|
2021-05-04 03:13:46 +00:00
|
|
|
auto* partition = GetDevToolsWebContents()
|
|
|
|
->GetBrowserContext()
|
|
|
|
->GetDefaultStoragePartition();
|
2020-07-15 18:27:42 +00:00
|
|
|
url_loader_factory = partition->GetURLLoaderFactoryForBrowserProcess();
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
NetworkResourceLoader::Create(
|
|
|
|
stream_id, this, resource_request, traffic_annotation,
|
|
|
|
std::move(url_loader_factory), std::move(callback));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
void InspectableWebContents::SetIsDocked(DispatchCallback callback,
|
2020-07-15 18:27:42 +00:00
|
|
|
bool docked) {
|
|
|
|
if (managed_devtools_web_contents_)
|
|
|
|
view_->SetIsDocked(docked, activate_);
|
|
|
|
if (!callback.is_null())
|
2021-01-12 23:31:23 +00:00
|
|
|
std::move(callback).Run(nullptr);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 08:54:26 +00:00
|
|
|
void InspectableWebContents::OpenInNewTab(const std::string& url) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsOpenInNewTab(url);
|
|
|
|
}
|
2020-07-15 18:27:42 +00:00
|
|
|
|
2024-02-29 09:31:13 +00:00
|
|
|
void InspectableWebContents::OpenSearchResultsInNewTab(
|
|
|
|
const std::string& query) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsOpenSearchResultsInNewTab(query);
|
|
|
|
}
|
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
void InspectableWebContents::ShowItemInFolder(
|
|
|
|
const std::string& file_system_path) {
|
|
|
|
if (file_system_path.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
|
2022-03-08 19:40:25 +00:00
|
|
|
platform_util::OpenPath(path.DirName(),
|
|
|
|
base::BindOnce(&OnOpenItemComplete, path));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SaveToFile(const std::string& url,
|
|
|
|
const std::string& content,
|
2024-06-07 21:18:35 +00:00
|
|
|
bool save_as,
|
|
|
|
bool is_base64) {
|
2020-07-15 18:27:42 +00:00
|
|
|
if (delegate_)
|
2024-06-07 21:18:35 +00:00
|
|
|
delegate_->DevToolsSaveToFile(url, content, save_as, is_base64);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::AppendToFile(const std::string& url,
|
|
|
|
const std::string& content) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsAppendToFile(url, content);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::RequestFileSystems() {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsRequestFileSystems();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::AddFileSystem(const std::string& type) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsAddFileSystem(type, base::FilePath());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::RemoveFileSystem(
|
|
|
|
const std::string& file_system_path) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsRemoveFileSystem(
|
|
|
|
base::FilePath::FromUTF8Unsafe(file_system_path));
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::UpgradeDraggedFileSystemPermissions(
|
|
|
|
const std::string& file_system_url) {}
|
|
|
|
|
|
|
|
void InspectableWebContents::IndexPath(int request_id,
|
|
|
|
const std::string& file_system_path,
|
|
|
|
const std::string& excluded_folders) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsIndexPath(request_id, file_system_path,
|
|
|
|
excluded_folders);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::StopIndexing(int request_id) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsStopIndexing(request_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SearchInPath(int request_id,
|
|
|
|
const std::string& file_system_path,
|
|
|
|
const std::string& query) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsSearchInPath(request_id, file_system_path, query);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SetWhitelistedShortcuts(
|
|
|
|
const std::string& message) {}
|
|
|
|
|
2021-06-17 13:42:51 +00:00
|
|
|
void InspectableWebContents::SetEyeDropperActive(bool active) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsSetEyeDropperActive(active);
|
|
|
|
}
|
2020-07-15 18:27:42 +00:00
|
|
|
void InspectableWebContents::ShowCertificateViewer(
|
|
|
|
const std::string& cert_chain) {}
|
|
|
|
|
|
|
|
void InspectableWebContents::ZoomIn() {
|
|
|
|
double new_level = GetNextZoomLevel(GetDevToolsZoomLevel(), false);
|
|
|
|
SetZoomLevelForWebContents(GetDevToolsWebContents(), new_level);
|
|
|
|
UpdateDevToolsZoomLevel(new_level);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ZoomOut() {
|
|
|
|
double new_level = GetNextZoomLevel(GetDevToolsZoomLevel(), true);
|
|
|
|
SetZoomLevelForWebContents(GetDevToolsWebContents(), new_level);
|
|
|
|
UpdateDevToolsZoomLevel(new_level);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ResetZoom() {
|
|
|
|
SetZoomLevelForWebContents(GetDevToolsWebContents(), 0.);
|
|
|
|
UpdateDevToolsZoomLevel(0.);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SetDevicesDiscoveryConfig(
|
|
|
|
bool discover_usb_devices,
|
|
|
|
bool port_forwarding_enabled,
|
|
|
|
const std::string& port_forwarding_config,
|
|
|
|
bool network_discovery_enabled,
|
|
|
|
const std::string& network_discovery_config) {}
|
|
|
|
|
|
|
|
void InspectableWebContents::SetDevicesUpdatesEnabled(bool enabled) {}
|
|
|
|
|
|
|
|
void InspectableWebContents::OpenRemotePage(const std::string& browser_id,
|
|
|
|
const std::string& url) {}
|
|
|
|
|
|
|
|
void InspectableWebContents::OpenNodeFrontend() {}
|
|
|
|
|
|
|
|
void InspectableWebContents::DispatchProtocolMessageFromDevToolsFrontend(
|
|
|
|
const std::string& message) {
|
|
|
|
// If the devtools wants to reload the page, hijack the message and handle it
|
|
|
|
// to the delegate.
|
|
|
|
if (base::MatchPattern(message,
|
|
|
|
"{\"id\":*,"
|
|
|
|
"\"method\":\"Page.reload\","
|
|
|
|
"\"params\":*}")) {
|
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsReloadPage();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (agent_host_)
|
|
|
|
agent_host_->DispatchProtocolMessage(
|
|
|
|
this, base::as_bytes(base::make_span(message)));
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
void InspectableWebContents::SendJsonRequest(DispatchCallback callback,
|
2020-07-15 18:27:42 +00:00
|
|
|
const std::string& browser_id,
|
|
|
|
const std::string& url) {
|
2021-01-12 23:31:23 +00:00
|
|
|
std::move(callback).Run(nullptr);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 23:31:23 +00:00
|
|
|
void InspectableWebContents::GetPreferences(DispatchCallback callback) {
|
2022-10-03 20:21:00 +00:00
|
|
|
const base::Value& prefs = pref_service_->GetValue(kDevToolsPreferences);
|
|
|
|
std::move(callback).Run(&prefs);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2022-01-10 22:31:39 +00:00
|
|
|
void InspectableWebContents::GetPreference(DispatchCallback callback,
|
|
|
|
const std::string& name) {
|
2022-10-03 20:21:00 +00:00
|
|
|
if (auto* pref = pref_service_->GetDict(kDevToolsPreferences).Find(name)) {
|
2022-01-10 22:31:39 +00:00
|
|
|
std::move(callback).Run(pref);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pref wasn't found, return an empty value
|
|
|
|
base::Value no_pref;
|
|
|
|
std::move(callback).Run(&no_pref);
|
|
|
|
}
|
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
void InspectableWebContents::SetPreference(const std::string& name,
|
|
|
|
const std::string& value) {
|
2023-01-06 02:35:34 +00:00
|
|
|
ScopedDictPrefUpdate update(pref_service_, kDevToolsPreferences);
|
|
|
|
update->Set(name, base::Value(value));
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::RemovePreference(const std::string& name) {
|
2023-01-06 02:35:34 +00:00
|
|
|
ScopedDictPrefUpdate update(pref_service_, kDevToolsPreferences);
|
|
|
|
update->Remove(name);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ClearPreferences() {
|
2023-01-06 02:35:34 +00:00
|
|
|
ScopedDictPrefUpdate unsynced_update(pref_service_, kDevToolsPreferences);
|
|
|
|
unsynced_update->clear();
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 08:45:59 +00:00
|
|
|
void InspectableWebContents::GetSyncInformation(DispatchCallback callback) {
|
2023-03-10 16:07:42 +00:00
|
|
|
base::Value result(base::Value::Type::DICT);
|
2023-03-15 13:07:51 +00:00
|
|
|
result.GetDict().Set("isSyncActive", false);
|
2021-11-24 08:45:59 +00:00
|
|
|
std::move(callback).Run(&result);
|
|
|
|
}
|
|
|
|
|
2024-06-07 21:18:35 +00:00
|
|
|
void InspectableWebContents::GetHostConfig(DispatchCallback callback) {
|
|
|
|
base::Value::Dict response_dict;
|
|
|
|
base::Value response = base::Value(std::move(response_dict));
|
|
|
|
std::move(callback).Run(&response);
|
|
|
|
}
|
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
void InspectableWebContents::ConnectionReady() {}
|
|
|
|
|
|
|
|
void InspectableWebContents::RegisterExtensionsAPI(const std::string& origin,
|
|
|
|
const std::string& script) {
|
|
|
|
extensions_api_[origin + "/"] = script;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::HandleMessageFromDevToolsFrontend(
|
2022-07-13 21:26:16 +00:00
|
|
|
base::Value::Dict message) {
|
2020-07-15 18:27:42 +00:00
|
|
|
// TODO(alexeykuzmin): Should we expect it to exist?
|
|
|
|
if (!embedder_message_dispatcher_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-13 21:26:16 +00:00
|
|
|
const std::string* method = message.FindString(kFrontendHostMethod);
|
|
|
|
base::Value* params = message.Find(kFrontendHostParams);
|
2021-04-27 21:27:34 +00:00
|
|
|
|
|
|
|
if (!method || (params && !params->is_list())) {
|
2020-07-15 18:27:42 +00:00
|
|
|
LOG(ERROR) << "Invalid message was sent to embedder: " << message;
|
|
|
|
return;
|
|
|
|
}
|
2022-07-13 21:26:16 +00:00
|
|
|
|
|
|
|
const base::Value::List no_params;
|
|
|
|
const base::Value::List& params_list =
|
|
|
|
params != nullptr && params->is_list() ? params->GetList() : no_params;
|
|
|
|
|
|
|
|
const int id = message.FindInt(kFrontendHostId).value_or(0);
|
2020-07-15 18:27:42 +00:00
|
|
|
embedder_message_dispatcher_->Dispatch(
|
|
|
|
base::BindRepeating(&InspectableWebContents::SendMessageAck,
|
|
|
|
weak_factory_.GetWeakPtr(), id),
|
2021-04-27 21:27:34 +00:00
|
|
|
*method, params_list);
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::DispatchProtocolMessage(
|
|
|
|
content::DevToolsAgentHost* agent_host,
|
|
|
|
base::span<const uint8_t> message) {
|
|
|
|
if (!frontend_loaded_)
|
|
|
|
return;
|
|
|
|
|
2024-01-11 01:00:37 +00:00
|
|
|
const std::string_view str_message{
|
|
|
|
reinterpret_cast<const char*>(message.data()), message.size()};
|
2022-06-29 16:39:48 +00:00
|
|
|
if (str_message.length() < kMaxMessageChunkSize) {
|
|
|
|
CallClientFunction("DevToolsAPI", "dispatchMessage",
|
|
|
|
base::Value(std::string(str_message)));
|
|
|
|
} else {
|
|
|
|
size_t total_size = str_message.length();
|
|
|
|
for (size_t pos = 0; pos < str_message.length();
|
|
|
|
pos += kMaxMessageChunkSize) {
|
|
|
|
base::StringPiece str_message_chunk =
|
|
|
|
str_message.substr(pos, kMaxMessageChunkSize);
|
|
|
|
|
|
|
|
CallClientFunction(
|
|
|
|
"DevToolsAPI", "dispatchMessageChunk",
|
|
|
|
base::Value(std::string(str_message_chunk)),
|
|
|
|
base::Value(base::NumberToString(pos ? 0 : total_size)));
|
|
|
|
}
|
2020-07-15 18:27:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::AgentHostClosed(
|
|
|
|
content::DevToolsAgentHost* agent_host) {}
|
|
|
|
|
|
|
|
void InspectableWebContents::RenderFrameHostChanged(
|
|
|
|
content::RenderFrameHost* old_host,
|
|
|
|
content::RenderFrameHost* new_host) {
|
|
|
|
if (new_host->GetParent())
|
|
|
|
return;
|
|
|
|
frontend_host_ = content::DevToolsFrontendHost::Create(
|
|
|
|
new_host, base::BindRepeating(
|
|
|
|
&InspectableWebContents::HandleMessageFromDevToolsFrontend,
|
|
|
|
weak_factory_.GetWeakPtr()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::WebContentsDestroyed() {
|
2021-03-15 22:43:25 +00:00
|
|
|
if (managed_devtools_web_contents_)
|
|
|
|
managed_devtools_web_contents_->SetDelegate(nullptr);
|
|
|
|
|
2020-07-15 18:27:42 +00:00
|
|
|
frontend_loaded_ = false;
|
|
|
|
external_devtools_web_contents_ = nullptr;
|
|
|
|
Observe(nullptr);
|
|
|
|
Detach();
|
|
|
|
embedder_message_dispatcher_.reset();
|
2023-12-01 19:37:52 +00:00
|
|
|
frontend_host_.reset();
|
2020-07-15 18:27:42 +00:00
|
|
|
|
|
|
|
if (view_ && view_->GetDelegate())
|
|
|
|
view_->GetDelegate()->DevToolsClosed();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InspectableWebContents::HandleKeyboardEvent(
|
|
|
|
content::WebContents* source,
|
2024-06-07 21:18:35 +00:00
|
|
|
const input::NativeWebKeyboardEvent& event) {
|
2020-07-15 18:27:42 +00:00
|
|
|
auto* delegate = web_contents_->GetDelegate();
|
|
|
|
return !delegate || delegate->HandleKeyboardEvent(source, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::CloseContents(content::WebContents* source) {
|
|
|
|
// This is where the devtools closes itself (by clicking the x button).
|
|
|
|
CloseDevTools();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::RunFileChooser(
|
|
|
|
content::RenderFrameHost* render_frame_host,
|
|
|
|
scoped_refptr<content::FileSelectListener> listener,
|
|
|
|
const blink::mojom::FileChooserParams& params) {
|
|
|
|
auto* delegate = web_contents_->GetDelegate();
|
|
|
|
if (delegate)
|
|
|
|
delegate->RunFileChooser(render_frame_host, std::move(listener), params);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::EnumerateDirectory(
|
|
|
|
content::WebContents* source,
|
|
|
|
scoped_refptr<content::FileSelectListener> listener,
|
|
|
|
const base::FilePath& path) {
|
|
|
|
auto* delegate = web_contents_->GetDelegate();
|
|
|
|
if (delegate)
|
|
|
|
delegate->EnumerateDirectory(source, std::move(listener), path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::OnWebContentsFocused(
|
|
|
|
content::RenderWidgetHost* render_widget_host) {
|
|
|
|
#if defined(TOOLKIT_VIEWS)
|
|
|
|
if (view_->GetDelegate())
|
|
|
|
view_->GetDelegate()->DevToolsFocused();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::ReadyToCommitNavigation(
|
|
|
|
content::NavigationHandle* navigation_handle) {
|
2023-12-01 19:37:52 +00:00
|
|
|
if (navigation_handle->IsInPrimaryMainFrame()) {
|
2020-07-15 18:27:42 +00:00
|
|
|
if (navigation_handle->GetRenderFrameHost() ==
|
2022-06-27 20:50:08 +00:00
|
|
|
GetDevToolsWebContents()->GetPrimaryMainFrame() &&
|
2020-07-15 18:27:42 +00:00
|
|
|
frontend_host_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
frontend_host_ = content::DevToolsFrontendHost::Create(
|
2022-06-27 20:50:08 +00:00
|
|
|
web_contents()->GetPrimaryMainFrame(),
|
2020-07-15 18:27:42 +00:00
|
|
|
base::BindRepeating(
|
|
|
|
&InspectableWebContents::HandleMessageFromDevToolsFrontend,
|
|
|
|
base::Unretained(this)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::DidFinishNavigation(
|
|
|
|
content::NavigationHandle* navigation_handle) {
|
2023-12-01 19:37:52 +00:00
|
|
|
if (navigation_handle->IsInPrimaryMainFrame() ||
|
2020-07-15 18:27:42 +00:00
|
|
|
!navigation_handle->GetURL().SchemeIs("chrome-extension") ||
|
|
|
|
!navigation_handle->HasCommitted())
|
|
|
|
return;
|
|
|
|
content::RenderFrameHost* frame = navigation_handle->GetRenderFrameHost();
|
2021-11-24 08:45:59 +00:00
|
|
|
auto origin = navigation_handle->GetURL().DeprecatedGetOriginAsURL().spec();
|
2020-07-15 18:27:42 +00:00
|
|
|
auto it = extensions_api_.find(origin);
|
|
|
|
if (it == extensions_api_.end())
|
|
|
|
return;
|
|
|
|
// Injected Script from devtools frontend doesn't expose chrome,
|
|
|
|
// most likely bug in chromium.
|
|
|
|
base::ReplaceFirstSubstringAfterOffset(&it->second, 0, "var chrome",
|
|
|
|
"var chrome = window.chrome ");
|
2023-06-13 18:45:48 +00:00
|
|
|
auto script = base::StringPrintf(
|
|
|
|
"%s(\"%s\")", it->second.c_str(),
|
|
|
|
base::Uuid::GenerateRandomV4().AsLowercaseString().c_str());
|
2020-07-15 18:27:42 +00:00
|
|
|
// Invoking content::DevToolsFrontendHost::SetupExtensionsAPI(frame, script);
|
|
|
|
// should be enough, but it seems to be a noop currently.
|
|
|
|
frame->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script),
|
|
|
|
base::NullCallback());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContents::SendMessageAck(int request_id,
|
|
|
|
const base::Value* arg) {
|
2022-06-29 16:39:48 +00:00
|
|
|
if (arg) {
|
|
|
|
CallClientFunction("DevToolsAPI", "embedderMessageAck",
|
|
|
|
base::Value(request_id), arg->Clone());
|
|
|
|
} else {
|
|
|
|
CallClientFunction("DevToolsAPI", "embedderMessageAck",
|
|
|
|
base::Value(request_id));
|
|
|
|
}
|
2018-10-19 13:50:30 +00:00
|
|
|
}
|
|
|
|
|
2019-06-19 21:23:04 +00:00
|
|
|
} // namespace electron
|