Headless
Chrome
skyostil@ / alexclarke@
BlinkOn 6
Headless mode
Out of scope:
Motivation
Motivation
Headless Chrome
Headless Chrome
Headless API
Headless browser
Headless Chrome
Headless API
Headless browser
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Headless Chrome
Headless API
Embedding app
Headless browser
Embedding app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Headless Chrome
Headless API
Embedding app
Headless browser
Embedding app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Headless API
Embedding app
Headless library
Embedding C++ app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Headless Chrome
Headless API
Embedding app
Headless browser
Embedding app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Headless API
Embedding app
Headless library
Embedding C++ app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
DevTools over websocket
DevTools C++ API
Headless Chrome
Headless API
Embedding app
Headless browser
Embedding app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Headless API
Embedding app
Headless library
Embedding C++ app
Headless API
Renderer
Tab
Tab
Headless API
Renderer
Tab
Custom networking
Mojo modules
DevTools C++ API
DevTools over websocket
Headless Chrome
Content API
Ozone
Scheduler
Net
Content
base/
net/
Ozone
Content API
Blink
Content API
Components
Content API
Chrome
Content API
Chrome
Headless Chrome
Content API
Ozone
Scheduler
Net
Content
base/
net/
Ozone
Content API
Blink
Content API
Components
Content API
Chrome
Headless additions
Web data extraction
Determinism: Session isolation
Headless browser
Browser
context #1
Browser process
Renderer #1
Browser
context #2
Cookies, local storage, cache, ...
Cookies, local storage, cache, ...
Renderer processes
Renderer #1
WebContents
WebContents
Renderer #1
Renderer #2
WebContents
Determinism: Virtual time
Determinism: Virtual time
Timer t=1
Timer t=3
Timer t=1
Timer t=3
Timer t=1
Timer t=3
Timer t=1
1 2 3 4 real time
Timer t=3
Timer t=1
1 2 3 4 real time
Timer t=3
Timer t=1
1 2 3 4 real time
Timer t=3
No virtual time
Fast forwarding
Suspension
Controlling the browser: DevTools protocol
Controlling the browser: DevTools protocol
Accessibility
Console
Device orientation
Emulation
Animation
CSS
DOM
Heap profiler
Application cache
Database
DOM debugger
IndexedDB
Cache storage
Debugger
DOM storage
Input
Inspector
IO
Layer tree
Memory
Network
Page
Profiler
Rendering
Runtime
Security
Service worker
Tracing
Worker
DevTools wire protocol
Headless API
Embedding app
DevTools target
DevTools client
DevTools wire protocol
Headless API
Embedding app
DevTools target
DevTools client
{id: 1, method: "Runtime.evaluate", params: {
expression: "1 + 1"
}}
DevTools wire protocol
Headless API
Embedding app
DevTools target
DevTools client
{id:1, result: {
result: {
type: "number", value: 2, description: "2"
},
wasThrown: false
}}
{id: 1, method: "Runtime.evaluate", params: {
expression: "1 + 1"
}}
DevTools wire protocol
Headless API
Embedding app
DevTools target
DevTools client
{method: "Page.loadEventFired", params: {
timestamp: 376371.511946
}}
DevTools bindings for Headless
DevTools bindings for Headless
client->GetRuntime()->Evaluate("1 + 1", base::Bind(&OnResult));
void OnResult(std::unique_ptr<headless::runtime::EvaluateResult> result) {
std::string value;
result->GetResult()->GetValue()->GetAsString(&value);
std::cout << value << std::endl;
}
C++
DevTools bindings for Headless
client->GetRuntime()->Evaluate("1 + 1", base::Bind(&OnResult));
void OnResult(std::unique_ptr<headless::runtime::EvaluateResult> result) {
std::string value;
result->GetResult()->GetValue()->GetAsString(&value);
std::cout << value << std::endl;
}
client.runtime.evaluate("1 + 1").then(response => {
console.log(response.result.value);
});
C++
JS
DevTools bindings for Headless
client->GetRuntime()->Evaluate("1 + 1", base::Bind(&OnResult));
void OnResult(std::unique_ptr<headless::runtime::EvaluateResult> result) {
std::string value;
result->GetResult()->GetValue()->GetAsString(&value);
std::cout << value << std::endl;
}
let response = await client.runtime.evaluate("1 + 1");
console.log(response.result.value);
C++
ES6
DevTools bindings for Headless
client->GetPage()->Enable();
client->GetPage()->AddObserver(this);
void MyObserver::OnLoadEventFired(
std::unique_ptr<page::LoadEventFiredParams> params) override {
std::cout << params->GetTimestamp() << std::endl;
}
client.page.enable();
client.page.addLoadEventFiredListener(params => {
console.log(params.timestamp);
});
C++
JS
Network customization (C++)
Headless browser
content/
content/
Network backend
Request
MyProtocolHandler
MyURLRequestJob
Response
net/
net/
MyProtocolHandler
MyURLRequestJob
net::URLRequest�JobFactoryImpl
http
Creates
Mojo services
Headless API
Embedding app
Headless browser
Embedding C++ app
Mojo service
Mojo services
Mojo service
Headless API
Renderer
Mojo services
Mojo service
Headless API
Renderer
module example;
MyService {
SendTestResults(string result);
};
.mojom
Mojo services
Mojo service
Headless API
Renderer
Mojo.example.MyService.then(service => {
service.sendTestResults("all passed");
});
module example;
MyService {
SendTestResults(string result);
};
JS
.mojom
Mojo services
Mojo service
Headless API
Renderer
Mojo.example.MyService.then(service => {
service.sendTestResults("all passed");
});
module example;
MyService {
SendTestResults(string result);
};
class MyServiceImpl : public example::MyService {
void SendTestResult(const mojo::String& result) override {
EXPECT_EQ("all passed", result.get());
}
};
C++
JS
.mojom
Distribution
$ chrome --headless --remote-debugging-port=9222
Future work
Give it a try
$ mkdir -p out/Debug
$ echo 'import("//build/args/headless.gn")' > out/Debug/args.gn
$ gn gen out/Debug
$ ninja -C out/Debug headless_shell
$ out/Debug/headless_shell https://www.chromium.org
Mailing list: headless-dev@chromium.org (bit.ly/1ZBcyLx)
Documentation: bit.ly/23LR2pW Bug label: Proj-Headless