Skip to content

Commit 9eb4d66

Browse files
committed
fetch network resource on worker thread
1 parent b06b7b2 commit 9eb4d66

17 files changed

Lines changed: 505 additions & 144 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
const { addFallThroughListener } = internalBinding('inspector');
3+
const { InternalWorker } = require('internal/worker');
4+
5+
function spawnLoadNetworkResourceWorker() {
6+
const worker = new InternalWorker('internal/inspector/load_network_resource_worker', {
7+
stderr: false,
8+
stdin: false,
9+
stdout: false,
10+
trackUnmanagedFds: false,
11+
});
12+
13+
worker.unref();
14+
15+
addFallThroughListener((sessionId, callId, method, message) => {
16+
if (method === 'Network.loadNetworkResource') {
17+
worker.postMessage({
18+
sessionId,
19+
callId,
20+
method,
21+
message,
22+
});
23+
}
24+
});
25+
}
26+
27+
module.exports = {
28+
spawnLoadNetworkResourceWorker,
29+
};
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict';
2+
const {
3+
JSONParse,
4+
JSONStringify,
5+
} = primordials;
6+
const {
7+
emitProtocolResponseInParent,
8+
addIoData,
9+
} = internalBinding('inspector');
10+
const { AbortController } = require('internal/abort_controller');
11+
const { setTimeout, clearTimeout } = require('timers');
12+
const { fetch } = require('internal/deps/undici/undici');
13+
14+
module.exports = function setupInspectorWorker(_, port) {
15+
function emitResponse(callId, sessionId, success, streamId = null) {
16+
const result = {
17+
id: callId,
18+
result: {
19+
resource: {
20+
success,
21+
},
22+
},
23+
};
24+
if (success && streamId !== null) {
25+
result.result.resource.stream = streamId.toString();
26+
}
27+
emitProtocolResponseInParent(callId, JSONStringify(result), sessionId);
28+
}
29+
30+
port.on('message', (msg) => {
31+
const { sessionId, callId, message } = msg;
32+
const url = JSONParse(message).params.url;
33+
34+
const controller = new AbortController();
35+
const timeoutId = setTimeout(() => controller.abort(), 2000);
36+
37+
fetch(url, { signal: controller.signal })
38+
.then((response) => {
39+
clearTimeout(timeoutId);
40+
if (!response.ok) {
41+
emitResponse(callId, sessionId, false);
42+
return null;
43+
}
44+
return response.text().then((text) => {
45+
const streamId = addIoData(text);
46+
emitResponse(callId, sessionId, true, streamId);
47+
});
48+
})
49+
.catch(() => {
50+
clearTimeout(timeoutId);
51+
emitResponse(callId, sessionId, false);
52+
});
53+
});
54+
};

lib/internal/modules/run_main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ function runEntryPointWithESMLoader(callback) {
136136
* @param {string} main - First positional CLI argument, such as `'entry.js'` from `node entry.js`
137137
*/
138138
function executeUserEntryPoint(main = process.argv[1]) {
139+
if (getOptionValue('--experimental-inspector-network-resource')) {
140+
require('internal/inspector/fall_through_handle').spawnLoadNetworkResourceWorker();
141+
}
142+
139143
let useESMLoader;
140144
let resolvedMain;
141145
if (getOptionValue('--entry-url')) {

src/inspector/io_agent.cc

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "io_agent.h"
2+
#include <string>
23
#include "crdtp/dispatch.h"
4+
#include "node_mutex.h"
35

46
namespace node::inspector::protocol {
57

@@ -8,17 +10,47 @@ void IoAgent::Wire(UberDispatcher* dispatcher) {
810
IO::Dispatcher::wire(dispatcher, this);
911
}
1012

13+
std::unordered_map<int, int> IoAgent::offset_map_;
14+
std::unordered_map<int, std::string> IoAgent::data_map_;
15+
std::atomic<int> IoAgent::stream_counter_{1};
16+
Mutex IoAgent::data_mutex_;
17+
18+
int IoAgent::setData(const std::string& value) {
19+
int key = getNextStreamId();
20+
Mutex::ScopedLock lock(data_mutex_);
21+
data_map_[key] = value;
22+
23+
return key;
24+
}
25+
26+
int IoAgent::getNextStreamId() {
27+
return stream_counter_++;
28+
}
29+
1130
DispatchResponse IoAgent::read(const String& in_handle,
1231
Maybe<int> in_offset,
1332
Maybe<int> in_size,
1433
String* out_data,
1534
bool* out_eof) {
16-
std::string txt = data_map_[in_handle];
35+
Mutex::ScopedReadLock lock(data_mutex_);
36+
std::string in_handle_str = in_handle;
37+
int stream_id = 0;
38+
bool is_number = std::all_of(in_handle_str.begin(),
39+
in_handle_str.end(),
40+
::isdigit);
41+
if (is_number) {
42+
stream_id = std::stoi(in_handle_str);
43+
} else {
44+
out_data = new String("");
45+
*out_eof = true;
46+
}
47+
48+
std::string txt = data_map_[stream_id];
1749
int offset = 0;
1850
if (in_offset.isJust()) {
1951
offset = in_offset.fromJust();
20-
} else if (offset_map_.find(in_handle) != offset_map_.end()) {
21-
offset = offset_map_[in_handle];
52+
} else if (offset_map_.find(stream_id) != offset_map_.end()) {
53+
offset = offset_map_[stream_id];
2254
}
2355
int size = 1 << 20;
2456
if (in_size.isJust()) {
@@ -28,18 +60,28 @@ DispatchResponse IoAgent::read(const String& in_handle,
2860
if (static_cast<std::size_t>(offset) < txt.length()) {
2961
std::string out_txt = txt.substr(offset, size);
3062
out_data->assign(out_txt);
63+
*out_eof = false;
3164
} else {
3265
*out_eof = true;
3366
}
3467

35-
offset_map_[in_handle] = offset + size;
68+
offset_map_[stream_id] = offset + size;
3669

3770
return DispatchResponse::Success();
3871
}
3972

4073
DispatchResponse IoAgent::close(const String& in_handle) {
41-
offset_map_.erase(in_handle);
42-
data_map_.erase(in_handle);
74+
Mutex::ScopedWriteLock lock(data_mutex_);
75+
std::string in_handle_str = in_handle;
76+
int stream_id = 0;
77+
bool is_number = std::all_of(in_handle_str.begin(),
78+
in_handle_str.end(),
79+
::isdigit);
80+
if (is_number) {
81+
stream_id = std::stoi(in_handle_str);
82+
offset_map_.erase(stream_id);
83+
data_map_.erase(stream_id);
84+
}
4385
return DispatchResponse::Success();
4486
}
4587
} // namespace node::inspector::protocol

src/inspector/io_agent.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <unordered_map>
55
#include "node/inspector/protocol/IO.h"
6+
#include "node_mutex.h"
67

78
namespace node::inspector::protocol {
89

@@ -17,15 +18,16 @@ class IoAgent : public IO::Backend {
1718
bool* out_eof) override;
1819
DispatchResponse close(const String& in_handle) override;
1920

20-
void setData(const std::string& key, const std::string value) {
21-
data_map_[key] = value;
22-
}
21+
static int setData(const std::string& value);
2322

2423
private:
2524
std::shared_ptr<IO::Frontend> frontend_;
26-
std::unordered_map<std::string, int> offset_map_;
27-
std::unordered_map<std::string, std::string> data_map_;
25+
static int getNextStreamId();
26+
27+
static std::unordered_map<int, std::string> data_map_;
28+
static std::unordered_map<int, int> offset_map_;
29+
static std::atomic<int> stream_counter_;
30+
static Mutex data_mutex_;
2831
};
2932
} // namespace node::inspector::protocol
30-
3133
#endif // SRC_INSPECTOR_IO_AGENT_H_

src/inspector/network_agent.cc

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,10 @@ std::unique_ptr<protocol::Network::Response> createResponseFromObject(
184184

185185
NetworkAgent::NetworkAgent(NetworkInspector* inspector,
186186
v8_inspector::V8Inspector* v8_inspector,
187-
Environment* env,
188-
std::shared_ptr<protocol::IoAgent> io_agent)
187+
Environment* env)
189188
: inspector_(inspector),
190189
v8_inspector_(v8_inspector),
191-
env_(env),
192-
io_agent_(io_agent) {
190+
env_(env) {
193191
event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent;
194192
event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived;
195193
event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed;
@@ -349,41 +347,7 @@ protocol::DispatchResponse NetworkAgent::loadNetworkResource(
349347
const protocol::String& in_url,
350348
std::unique_ptr<protocol::Network::LoadNetworkResourcePageResult>*
351349
out_resource) {
352-
if (!env_->options()->experimental_inspector_network_resource) {
353-
return protocol::DispatchResponse::MethodNotFound(
354-
"Network.loadNetworkResource is not supported in this environment. "
355-
"Please enable the experimental-inspector-network-resource option.");
356-
}
357-
DCHECK(io_agent_);
358-
359-
std::string code = R"(
360-
fetch(process.argv[1], {signal: AbortSignal.timeout(2000) }).then(res => {
361-
if (res.ok) {
362-
res.text().then(console.log)
363-
} else {
364-
throw new Error('Network error: ' + res.status);
365-
}
366-
})
367-
)";
368-
369-
auto [r, response, err] = spawnFetchProcess(code, env_, in_url);
370-
if (r == 0 && err.empty()) {
371-
std::string uuid = std::to_string(load_id_counter_);
372-
load_id_counter_++;
373-
io_agent_->setData(uuid, response);
374-
auto result = protocol::Network::LoadNetworkResourcePageResult::create()
375-
.setSuccess(true)
376-
.setStream(uuid)
377-
.build();
378-
out_resource->reset(result.release());
379-
} else {
380-
auto result = protocol::Network::LoadNetworkResourcePageResult::create()
381-
.setSuccess(false)
382-
.build();
383-
out_resource->reset(result.release());
384-
}
385-
386-
return protocol::DispatchResponse::Success();
350+
return protocol::DispatchResponse::FallThrough();
387351
}
388352

389353
void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context,

src/inspector/network_agent.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ class NetworkAgent : public protocol::Network::Backend {
2424
public:
2525
explicit NetworkAgent(NetworkInspector* inspector,
2626
v8_inspector::V8Inspector* v8_inspector,
27-
Environment* env,
28-
std::shared_ptr<protocol::IoAgent> io_agent);
27+
Environment* env);
2928

3029
void Wire(protocol::UberDispatcher* dispatcher);
3130

src/inspector/network_inspector.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ namespace node {
44
namespace inspector {
55

66
NetworkInspector::NetworkInspector(Environment* env,
7-
v8_inspector::V8Inspector* v8_inspector,
8-
std::shared_ptr<protocol::IoAgent> io_agent)
7+
v8_inspector::V8Inspector* v8_inspector)
98
: enabled_(false), env_(env) {
109
network_agent_ =
11-
std::make_unique<NetworkAgent>(this, v8_inspector, env, io_agent);
10+
std::make_unique<NetworkAgent>(this, v8_inspector, env);
1211
}
1312
NetworkInspector::~NetworkInspector() {
1413
network_agent_.reset();

src/inspector/network_inspector.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ class NetworkInspector {
1313
public:
1414
explicit NetworkInspector(
1515
Environment* env,
16-
v8_inspector::V8Inspector* v8_inspector,
17-
std::shared_ptr<protocol::IoAgent> io_agent = nullptr);
16+
v8_inspector::V8Inspector* v8_inspector);
1817
~NetworkInspector();
1918

2019
void Wire(protocol::UberDispatcher* dispatcher);

src/inspector/node_protocol.pdl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ experimental domain Network
188188
# Enables network tracking, network events will now be delivered to the client.
189189
command enable
190190

191-
<<<<<<< HEAD
192191
# Enables streaming of the response for the given requestId.
193192
# If enabled, the dataReceived event contains the data that was received during streaming.
194193
experimental command streamResourceContent
@@ -198,15 +197,13 @@ experimental domain Network
198197
returns
199198
# Data that has been buffered until streaming is enabled.
200199
binary bufferedData
201-
=======
202200
# Fetches the resource and returns the content.
203201
command loadNetworkResource
204202
parameters
205203
# URL of the resource to get content for.
206204
string url
207205
returns
208206
LoadNetworkResourcePageResult resource
209-
>>>>>>> ba6277dcf1 (inspector: initial support for Network.loadNetworkResource)
210207

211208
# Fired when page is about to send HTTP request.
212209
event requestWillBeSent

0 commit comments

Comments
 (0)