| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d0302e7 commit 402ac8b
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -511,6 +511,19 @@ inspector.Network.requestWillBeSent({ | |||
| 511 | 511 | }); | |
| 512 | 512 | ``` | |
| 513 | 513 | ||
| 514 | + ### `inspector.Network.dataReceived([params])` | ||
| 515 | + | ||
| 516 | + <!-- YAML | ||
| 517 | + added: REPLACEME | ||
| 518 | + --> | ||
| 519 | + | ||
| 520 | + * `params` {Object} | ||
| 521 | + | ||
| 522 | + This feature is only available with the `--experimental-network-inspection` flag enabled. | ||
| 523 | + | ||
| 524 | + Broadcasts the `Network.dataReceived` event to connected frontends, or buffers the data if | ||
| 525 | + `Network.streamResourceContent` command was not invoked for the given request yet. | ||
| 526 | + | ||
| 514 | 527 | ### `inspector.Network.requestWillBeSent([params])` | |
| 515 | 528 | ||
| 516 | 529 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -214,6 +214,7 @@ const Network = { | |||
| 214 | 214 | responseReceived: (params) => broadcastToFrontend('Network.responseReceived', params), | |
| 215 | 215 | loadingFinished: (params) => broadcastToFrontend('Network.loadingFinished', params), | |
| 216 | 216 | loadingFailed: (params) => broadcastToFrontend('Network.loadingFailed', params), | |
| 217 | + dataReceived: (params) => broadcastToFrontend('Network.dataReceived', params), | ||
| 217 | 218 | }; | |
| 218 | 219 | ||
| 219 | 220 | module.exports = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,6 +15,7 @@ using v8::Maybe; | |||
| 15 | 15 | using v8::MaybeLocal; | |
| 16 | 16 | using v8::Nothing; | |
| 17 | 17 | using v8::Object; | |
| 18 | + using v8::Uint8Array; | ||
| 18 | 19 | using v8::Value; | |
| 19 | 20 | ||
| 20 | 21 | // Get a protocol string property from the object. | |
@@ -183,6 +184,7 @@ NetworkAgent::NetworkAgent(NetworkInspector* inspector, | |||
| 183 | 184 | event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived; | |
| 184 | 185 | event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed; | |
| 185 | 186 | event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished; | |
| 187 | + event_notifier_map_["dataReceived"] = &NetworkAgent::dataReceived; | ||
| 186 | 188 | } | |
| 187 | 189 | ||
| 188 | 190 | void NetworkAgent::emitNotification(v8::Local<v8::Context> context, | |
@@ -211,6 +213,30 @@ protocol::DispatchResponse NetworkAgent::disable() { | |||
| 211 | 213 | return protocol::DispatchResponse::Success(); | |
| 212 | 214 | } | |
| 213 | 215 | ||
| 216 | + protocol::DispatchResponse NetworkAgent::streamResourceContent( | ||
| 217 | + const protocol::String& in_requestId, protocol::Binary* out_bufferedData) { | ||
| 218 | + if (!requests_.contains(in_requestId)) { | ||
| 219 | + // Request not found, ignore it. | ||
| 220 | + return protocol::DispatchResponse::InvalidParams("Request not found"); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + auto& it = requests_[in_requestId]; | ||
| 224 | + | ||
| 225 | + it.is_streaming = true; | ||
| 226 | + | ||
| 227 | + // Concat response bodies. | ||
| 228 | + *out_bufferedData = protocol::Binary::concat(it.response_data_blobs); | ||
| 229 | + // Clear buffered data. | ||
| 230 | + it.response_data_blobs.clear(); | ||
| 231 | + | ||
| 232 | + if (it.is_finished) { | ||
| 233 | + // If the request is finished, remove the entry. | ||
| 234 | + requests_.erase(in_requestId); | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + return protocol::DispatchResponse::Success(); | ||
| 238 | + } | ||
| 239 | + | ||
| 214 | 240 | void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context, | |
| 215 | 241 | v8::Local<v8::Object> params) { | |
| 216 | 242 | protocol::String request_id; | |
@@ -247,6 +273,12 @@ void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context, | |||
| 247 | 273 | std::move(initiator), | |
| 248 | 274 | timestamp, | |
| 249 | 275 | wall_time); | |
| 276 | + | ||
| 277 | + if (requests_.contains(request_id)) { | ||
| 278 | + // Duplicate entry, ignore it. | ||
| 279 | + return; | ||
| 280 | + } | ||
| 281 | + requests_.emplace(request_id, RequestEntry{timestamp, false, false, {}}); | ||
| 250 | 282 | } | |
| 251 | 283 | ||
| 252 | 284 | void NetworkAgent::responseReceived(v8::Local<v8::Context> context, | |
@@ -295,6 +327,8 @@ void NetworkAgent::loadingFailed(v8::Local<v8::Context> context, | |||
| 295 | 327 | } | |
| 296 | 328 | ||
| 297 | 329 | frontend_->loadingFailed(request_id, timestamp, type, error_text); | |
| 330 | + | ||
| 331 | + requests_.erase(request_id); | ||
| 298 | 332 | } | |
| 299 | 333 | ||
| 300 | 334 | void NetworkAgent::loadingFinished(v8::Local<v8::Context> context, | |
@@ -309,6 +343,63 @@ void NetworkAgent::loadingFinished(v8::Local<v8::Context> context, | |||
| 309 | 343 | } | |
| 310 | 344 | ||
| 311 | 345 | frontend_->loadingFinished(request_id, timestamp); | |
| 346 | + | ||
| 347 | + auto request_entry = requests_.find(request_id); | ||
| 348 | + if (request_entry == requests_.end()) { | ||
| 349 | + // No entry found. Ignore it. | ||
| 350 | + return; | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + if (request_entry->second.is_streaming) { | ||
| 354 | + // Streaming finished, remove the entry. | ||
| 355 | + requests_.erase(request_id); | ||
| 356 | + } else { | ||
| 357 | + request_entry->second.is_finished = true; | ||
| 358 | + } | ||
| 359 | + } | ||
| 360 | + | ||
| 361 | + void NetworkAgent::dataReceived(v8::Local<v8::Context> context, | ||
| 362 | + v8::Local<v8::Object> params) { | ||
| 363 | + protocol::String request_id; | ||
| 364 | + if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) { | ||
| 365 | + return; | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + auto request_entry = requests_.find(request_id); | ||
| 369 | + if (request_entry == requests_.end()) { | ||
| 370 | + // No entry found. Ignore it. | ||
| 371 | + return; | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + double timestamp; | ||
| 375 | + if (!ObjectGetDouble(context, params, "timestamp").To(×tamp)) { | ||
| 376 | + return; | ||
| 377 | + } | ||
| 378 | + int data_length; | ||
| 379 | + if (!ObjectGetInt(context, params, "dataLength").To(&data_length)) { | ||
| 380 | + return; | ||
| 381 | + } | ||
| 382 | + int encoded_data_length; | ||
| 383 | + if (!ObjectGetInt(context, params, "encodedDataLength") | ||
| 384 | + .To(&encoded_data_length)) { | ||
| 385 | + return; | ||
| 386 | + } | ||
| 387 | + Local<Object> data_obj; | ||
| 388 | + if (!ObjectGetObject(context, params, "data").ToLocal(&data_obj)) { | ||
| 389 | + return; | ||
| 390 | + } | ||
| 391 | + if (!data_obj->IsUint8Array()) { | ||
| 392 | + return; | ||
| 393 | + } | ||
| 394 | + Local<Uint8Array> data = data_obj.As<Uint8Array>(); | ||
| 395 | + auto data_bin = protocol::Binary::fromUint8Array(data); | ||
| 396 | + | ||
| 397 | + if (request_entry->second.is_streaming) { | ||
| 398 | + frontend_->dataReceived( | ||
| 399 | + request_id, timestamp, data_length, encoded_data_length, data_bin); | ||
| 400 | + } else { | ||
| 401 | + requests_[request_id].response_data_blobs.push_back(data_bin); | ||
| 402 | + } | ||
| 312 | 403 | } | |
| 313 | 404 | ||
| 314 | 405 | } // namespace inspector | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,13 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | 4 | #include "node/inspector/protocol/Network.h" | |
| 5 | 5 | ||
| 6 | + #include <map> | ||
| 6 | 7 | #include <unordered_map> | |
| 7 | 8 | ||
| 8 | 9 | namespace node { | |
| 9 | 10 | namespace inspector { | |
| 10 | 11 | ||
| 11 | 12 | class NetworkInspector; | |
| 12 | 13 | ||
| 14 | + struct RequestEntry { | ||
| 15 | + double timestamp; | ||
| 16 | + bool is_finished; | ||
| 17 | + bool is_streaming; | ||
| 18 | + std::vector<protocol::Binary> response_data_blobs; | ||
| 19 | + }; | ||
| 20 | + | ||
| 13 | 21 | class NetworkAgent : public protocol::Network::Backend { | |
| 14 | 22 | public: | |
| 15 | 23 | explicit NetworkAgent(NetworkInspector* inspector, | |
@@ -21,6 +29,10 @@ class NetworkAgent : public protocol::Network::Backend { | |||
| 21 | 29 | ||
| 22 | 30 | protocol::DispatchResponse disable() override; | |
| 23 | 31 | ||
| 32 | + protocol::DispatchResponse streamResourceContent( | ||
| 33 | + const protocol::String& in_requestId, | ||
| 34 | + protocol::Binary* out_bufferedData) override; | ||
| 35 | + | ||
| 24 | 36 | void emitNotification(v8::Local<v8::Context> context, | |
| 25 | 37 | const protocol::String& event, | |
| 26 | 38 | v8::Local<v8::Object> params); | |
@@ -37,13 +49,17 @@ class NetworkAgent : public protocol::Network::Backend { | |||
| 37 | 49 | void loadingFinished(v8::Local<v8::Context> context, | |
| 38 | 50 | v8::Local<v8::Object> params); | |
| 39 | 51 | ||
| 52 | + void dataReceived(v8::Local<v8::Context> context, | ||
| 53 | + v8::Local<v8::Object> params); | ||
| 54 | + | ||
| 40 | 55 | private: | |
| 41 | 56 | NetworkInspector* inspector_; | |
| 42 | 57 | v8_inspector::V8Inspector* v8_inspector_; | |
| 43 | 58 | std::shared_ptr<protocol::Network::Frontend> frontend_; | |
| 44 | 59 | using EventNotifier = void (NetworkAgent::*)(v8::Local<v8::Context> context, | |
| 45 | 60 | v8::Local<v8::Object>); | |
| 46 | 61 | std::unordered_map<protocol::String, EventNotifier> event_notifier_map_; | |
| 62 | + std::map<protocol::String, RequestEntry> requests_; | ||
| 47 | 63 | }; | |
| 48 | 64 | ||
| 49 | 65 | } // namespace inspector | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -183,6 +183,16 @@ experimental domain Network | |||
| 183 | 183 | # Enables network tracking, network events will now be delivered to the client. | |
| 184 | 184 | command enable | |
| 185 | 185 | ||
| 186 | + # Enables streaming of the response for the given requestId. | ||
| 187 | + # If enabled, the dataReceived event contains the data that was received during streaming. | ||
| 188 | + experimental command streamResourceContent | ||
| 189 | + parameters | ||
| 190 | + # Identifier of the request to stream. | ||
| 191 | + RequestId requestId | ||
| 192 | + returns | ||
| 193 | + # Data that has been buffered until streaming is enabled. | ||
| 194 | + binary bufferedData | ||
| 195 | + | ||
| 186 | 196 | # Fired when page is about to send HTTP request. | |
| 187 | 197 | event requestWillBeSent | |
| 188 | 198 | parameters | |
@@ -227,6 +237,20 @@ experimental domain Network | |||
| 227 | 237 | # Timestamp. | |
| 228 | 238 | MonotonicTime timestamp | |
| 229 | 239 | ||
| 240 | + # Fired when data chunk was received over the network. | ||
| 241 | + event dataReceived | ||
| 242 | + parameters | ||
| 243 | + # Request identifier. | ||
| 244 | + RequestId requestId | ||
| 245 | + # Timestamp. | ||
| 246 | + MonotonicTime timestamp | ||
| 247 | + # Data chunk length. | ||
| 248 | + integer dataLength | ||
| 249 | + # Actual bytes received (might be less than dataLength for compressed encodings). | ||
| 250 | + integer encodedDataLength | ||
| 251 | + # Data that was received. | ||
| 252 | + experimental optional binary data | ||
| 253 | + | ||
| 230 | 254 | # Support for inspecting node process state. | |
| 231 | 255 | experimental domain NodeRuntime | |
| 232 | 256 | # Enable the NodeRuntime events except by `NodeRuntime.waitingForDisconnect`. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -28,6 +28,20 @@ void ProtocolTypeTraits<std::string>::Serialize(const std::string& value, | |||
| 28 | 28 | cbor::EncodeString8(SpanFrom(value), bytes); | |
| 29 | 29 | } | |
| 30 | 30 | ||
| 31 | + bool ProtocolTypeTraits<node::inspector::protocol::Binary>::Deserialize( | ||
| 32 | + DeserializerState* state, node::inspector::protocol::Binary* value) { | ||
| 33 | + CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::BINARY); | ||
| 34 | + span<uint8_t> cbor_span = state->tokenizer()->GetBinary(); | ||
| 35 | + *value = node::inspector::protocol::Binary::fromSpan(cbor_span); | ||
| 36 | + return true; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + void ProtocolTypeTraits<node::inspector::protocol::Binary>::Serialize( | ||
| 40 | + const node::inspector::protocol::Binary& value, | ||
| 41 | + std::vector<uint8_t>* bytes) { | ||
| 42 | + cbor::EncodeString8(SpanFrom(value.toBase64()), bytes); | ||
| 43 | + } | ||
| 44 | + | ||
| 31 | 45 | } // namespace crdtp | |
| 32 | 46 | ||
| 33 | 47 | namespace node { | |
@@ -93,6 +107,58 @@ size_t StringUtil::CharacterCount(const std::string_view s) { | |||
| 93 | 107 | return s.length(); | |
| 94 | 108 | } | |
| 95 | 109 | ||
| 110 | + String Binary::toBase64() const { | ||
| 111 | + MaybeStackBuffer<char> buffer; | ||
| 112 | + size_t str_len = simdutf::base64_length_from_binary(bytes_->size()); | ||
| 113 | + buffer.SetLength(str_len); | ||
| 114 | + | ||
| 115 | + size_t len = | ||
| 116 | + simdutf::binary_to_base64(reinterpret_cast<const char*>(bytes_->data()), | ||
| 117 | + bytes_->size(), | ||
| 118 | + buffer.out()); | ||
| 119 | + CHECK_EQ(len, str_len); | ||
| 120 | + return buffer.ToString(); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + // static | ||
| 124 | + Binary Binary::concat(const std::vector<Binary>& binaries) { | ||
| 125 | + size_t total_size = 0; | ||
| 126 | + for (const auto& binary : binaries) { | ||
| 127 | + total_size += binary.size(); | ||
| 128 | + } | ||
| 129 | + auto bytes = std::make_shared<std::vector<uint8_t>>(total_size); | ||
| 130 | + uint8_t* data_ptr = bytes->data(); | ||
| 131 | + for (const auto& binary : binaries) { | ||
| 132 | + memcpy(data_ptr, binary.data(), binary.size()); | ||
| 133 | + data_ptr += binary.size(); | ||
| 134 | + } | ||
| 135 | + return Binary(bytes); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + // static | ||
| 139 | + Binary Binary::fromBase64(const String& base64, bool* success) { | ||
| 140 | + Binary binary{}; | ||
| 141 | + size_t base64_len = simdutf::maximal_binary_length_from_base64( | ||
| 142 | + base64.data(), base64.length()); | ||
| 143 | + binary.bytes_->resize(base64_len); | ||
| 144 | + | ||
| 145 | + simdutf::result result; | ||
| 146 | + result = | ||
| 147 | + simdutf::base64_to_binary(base64.data(), | ||
| 148 | + base64.length(), | ||
| 149 | + reinterpret_cast<char*>(binary.bytes_->data())); | ||
| 150 | + CHECK_EQ(result.error, simdutf::error_code::SUCCESS); | ||
| 151 | + return binary; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + // static | ||
| 155 | + Binary Binary::fromUint8Array(v8::Local<v8::Uint8Array> data) { | ||
| 156 | + auto bytes = std::make_shared<std::vector<uint8_t>>(data->ByteLength()); | ||
| 157 | + size_t size = data->CopyContents(bytes->data(), data->ByteLength()); | ||
| 158 | + CHECK_EQ(size, data->ByteLength()); | ||
| 159 | + return Binary(bytes); | ||
| 160 | + } | ||
| 161 | + | ||
| 96 | 162 | } // namespace protocol | |
| 97 | 163 | } // namespace inspector | |
| 98 | 164 | } // namespace node | |
| Back | FazBrowse Home | New Git URL |
0 commit comments