Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/inspector/network_agent.cc
Line
Count
Source
1
#include "network_agent.h"
2
#include <string>
3
#include "debug_utils-inl.h"
4
#include "env-inl.h"
5
#include "inspector/network_resource_manager.h"
6
#include "inspector/protocol_helper.h"
7
#include "network_inspector.h"
8
#include "node_metadata.h"
9
#include "util-inl.h"
10
#include "uv.h"
11
#include "v8-context.h"
12
#include "v8.h"
13
14
namespace node {
15
namespace inspector {
16
17
using v8::EscapableHandleScope;
18
using v8::HandleScope;
19
using v8::Isolate;
20
using v8::Just;
21
using v8::Local;
22
using v8::Maybe;
23
using v8::MaybeLocal;
24
using v8::Nothing;
25
using v8::Object;
26
using v8::Uint8Array;
27
using v8::Value;
28
29
constexpr size_t kDefaultMaxTotalBufferSize = 100 * 1024 * 1024;  // 100MB
30
31
// Get a protocol string property from the object.
32
Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context,
33
                                                Local<Object> object,
34
0
                                                Local<v8::String> property) {
35
0
  HandleScope handle_scope(Isolate::GetCurrent());
36
0
  Local<Value> value;
37
0
  if (!object->Get(context, property).ToLocal(&value) || !value->IsString()) {
38
0
    return Nothing<protocol::String>();
39
0
  }
40
0
  Local<v8::String> str = value.As<v8::String>();
41
0
  return Just(ToProtocolString(Isolate::GetCurrent(), str));
42
0
}
43
44
// Get a protocol string property from the object.
45
Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context,
46
                                                Local<Object> object,
47
0
                                                const char* property) {
48
0
  HandleScope handle_scope(Isolate::GetCurrent());
49
0
  return ObjectGetProtocolString(
50
0
      context, object, OneByteString(Isolate::GetCurrent(), property));
51
0
}
52
53
// Get a protocol double property from the object.
54
Maybe<double> ObjectGetDouble(v8::Local<v8::Context> context,
55
                              Local<Object> object,
56
0
                              const char* property) {
57
0
  HandleScope handle_scope(Isolate::GetCurrent());
58
0
  Local<Value> value;
59
0
  if (!object->Get(context, OneByteString(Isolate::GetCurrent(), property))
60
0
           .ToLocal(&value) ||
61
0
      !value->IsNumber()) {
62
0
    return Nothing<double>();
63
0
  }
64
0
  return Just(value.As<v8::Number>()->Value());
65
0
}
66
67
// Get a protocol int property from the object.
68
Maybe<int> ObjectGetInt(v8::Local<v8::Context> context,
69
                        Local<Object> object,
70
0
                        const char* property) {
71
0
  HandleScope handle_scope(Isolate::GetCurrent());
72
0
  Local<Value> value;
73
0
  if (!object->Get(context, OneByteString(Isolate::GetCurrent(), property))
74
0
           .ToLocal(&value) ||
75
0
      !value->IsInt32()) {
76
0
    return Nothing<int>();
77
0
  }
78
0
  return Just(value.As<v8::Int32>()->Value());
79
0
}
80
81
// Get a protocol bool property from the object.
82
Maybe<bool> ObjectGetBool(v8::Local<v8::Context> context,
83
                          Local<Object> object,
84
0
                          const char* property) {
85
0
  HandleScope handle_scope(Isolate::GetCurrent());
86
0
  Local<Value> value;
87
0
  if (!object->Get(context, OneByteString(Isolate::GetCurrent(), property))
88
0
           .ToLocal(&value) ||
89
0
      !value->IsBoolean()) {
90
0
    return Nothing<bool>();
91
0
  }
92
0
  return Just(value.As<v8::Boolean>()->Value());
93
0
}
94
95
// Get an object property from the object.
96
MaybeLocal<v8::Object> ObjectGetObject(v8::Local<v8::Context> context,
97
                                       Local<Object> object,
98
0
                                       const char* property) {
99
0
  EscapableHandleScope handle_scope(Isolate::GetCurrent());
100
0
  Local<Value> value;
101
0
  if (!object->Get(context, OneByteString(Isolate::GetCurrent(), property))
102
0
           .ToLocal(&value) ||
103
0
      !value->IsObject()) {
104
0
    return {};
105
0
  }
106
0
  return handle_scope.Escape(value.As<v8::Object>());
107
0
}
108
109
// Create a protocol::Network::Headers from the v8 object.
110
std::unique_ptr<protocol::Network::Headers> createHeadersFromObject(
111
0
    v8::Local<v8::Context> context, Local<Object> headers_obj) {
112
0
  HandleScope handle_scope(Isolate::GetCurrent());
113
114
0
  std::unique_ptr<protocol::DictionaryValue> dict =
115
0
      protocol::DictionaryValue::create();
116
0
  Local<v8::Array> property_names;
117
0
  if (!headers_obj->GetOwnPropertyNames(context).ToLocal(&property_names)) {
118
0
    return {};
119
0
  }
120
121
0
  for (size_t idx = 0; idx < property_names->Length(); idx++) {
122
0
    Local<v8::Value> property_name_val;
123
0
    if (!property_names->Get(context, idx).ToLocal(&property_name_val) ||
124
0
        !property_name_val->IsString()) {
125
0
      return {};
126
0
    }
127
0
    Local<v8::String> property_name = property_name_val.As<v8::String>();
128
0
    protocol::String property_value;
129
0
    if (!ObjectGetProtocolString(context, headers_obj, property_name)
130
0
             .To(&property_value)) {
131
0
      return {};
132
0
    }
133
0
    dict->setString(ToProtocolString(Isolate::GetCurrent(), property_name),
134
0
                    property_value);
135
0
  }
136
137
0
  return std::make_unique<protocol::Network::Headers>(std::move(dict));
138
0
}
139
140
// Create a protocol::Network::Request from the v8 object.
141
std::unique_ptr<protocol::Network::Request> createRequestFromObject(
142
0
    v8::Local<v8::Context> context, Local<Object> request) {
143
0
  HandleScope handle_scope(Isolate::GetCurrent());
144
0
  protocol::String url;
145
0
  if (!ObjectGetProtocolString(context, request, "url").To(&url)) {
146
0
    return {};
147
0
  }
148
0
  protocol::String method;
149
0
  if (!ObjectGetProtocolString(context, request, "method").To(&method)) {
150
0
    return {};
151
0
  }
152
0
  Local<Object> headers_obj;
153
0
  if (!ObjectGetObject(context, request, "headers").ToLocal(&headers_obj)) {
154
0
    return {};
155
0
  }
156
0
  std::unique_ptr<protocol::Network::Headers> headers =
157
0
      createHeadersFromObject(context, headers_obj);
158
0
  if (!headers) {
159
0
    return {};
160
0
  }
161
0
  bool has_post_data =
162
0
      ObjectGetBool(context, request, "hasPostData").FromMaybe(false);
163
164
0
  return protocol::Network::Request::create()
165
0
      .setUrl(url)
166
0
      .setMethod(method)
167
0
      .setHasPostData(has_post_data)
168
0
      .setHeaders(std::move(headers))
169
0
      .build();
170
0
}
171
172
// Create a protocol::Network::Response from the v8 object.
173
std::unique_ptr<protocol::Network::Response> createResponseFromObject(
174
0
    v8::Local<v8::Context> context, Local<Object> response) {
175
0
  HandleScope handle_scope(Isolate::GetCurrent());
176
0
  protocol::String url;
177
0
  if (!ObjectGetProtocolString(context, response, "url").To(&url)) {
178
0
    return {};
179
0
  }
180
0
  int status;
181
0
  if (!ObjectGetInt(context, response, "status").To(&status)) {
182
0
    return {};
183
0
  }
184
0
  protocol::String statusText;
185
0
  if (!ObjectGetProtocolString(context, response, "statusText")
186
0
           .To(&statusText)) {
187
0
    return {};
188
0
  }
189
0
  Local<Object> headers_obj;
190
0
  if (!ObjectGetObject(context, response, "headers").ToLocal(&headers_obj)) {
191
0
    return {};
192
0
  }
193
0
  std::unique_ptr<protocol::Network::Headers> headers =
194
0
      createHeadersFromObject(context, headers_obj);
195
0
  if (!headers) {
196
0
    return {};
197
0
  }
198
199
0
  protocol::String mimeType =
200
0
      ObjectGetProtocolString(context, response, "mimeType").FromMaybe("");
201
0
  protocol::String charset =
202
0
      ObjectGetProtocolString(context, response, "charset").FromMaybe("");
203
204
0
  return protocol::Network::Response::create()
205
0
      .setUrl(url)
206
0
      .setStatus(status)
207
0
      .setStatusText(statusText)
208
0
      .setHeaders(std::move(headers))
209
0
      .setMimeType(mimeType)
210
0
      .setCharset(charset)
211
0
      .build();
212
0
}
213
214
std::unique_ptr<protocol::Network::WebSocketResponse> createWebSocketResponse(
215
0
    v8::Local<v8::Context> context, Local<Object> response) {
216
0
  HandleScope handle_scope(Isolate::GetCurrent());
217
0
  int status;
218
0
  if (!ObjectGetInt(context, response, "status").To(&status)) {
219
0
    return {};
220
0
  }
221
0
  protocol::String statusText;
222
0
  if (!ObjectGetProtocolString(context, response, "statusText")
223
0
           .To(&statusText)) {
224
0
    return {};
225
0
  }
226
0
  Local<Object> headers_obj;
227
0
  if (!ObjectGetObject(context, response, "headers").ToLocal(&headers_obj)) {
228
0
    return {};
229
0
  }
230
0
  std::unique_ptr<protocol::Network::Headers> headers =
231
0
      createHeadersFromObject(context, headers_obj);
232
0
  if (!headers) {
233
0
    return {};
234
0
  }
235
236
0
  return protocol::Network::WebSocketResponse::create()
237
0
      .setStatus(status)
238
0
      .setStatusText(statusText)
239
0
      .setHeaders(std::move(headers))
240
0
      .build();
241
0
}
242
243
NetworkAgent::NetworkAgent(
244
    NetworkInspector* inspector,
245
    v8_inspector::V8Inspector* v8_inspector,
246
    Environment* env,
247
    std::shared_ptr<NetworkResourceManager> network_resource_manager)
248
0
    : inspector_(inspector),
249
0
      v8_inspector_(v8_inspector),
250
0
      env_(env),
251
0
      network_resource_manager_(std::move(network_resource_manager)),
252
0
      requests_(kDefaultMaxTotalBufferSize) {
253
0
  event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent;
254
0
  event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived;
255
0
  event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed;
256
0
  event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished;
257
0
  event_notifier_map_["dataSent"] = &NetworkAgent::dataSent;
258
0
  event_notifier_map_["dataReceived"] = &NetworkAgent::dataReceived;
259
0
  event_notifier_map_["webSocketCreated"] = &NetworkAgent::webSocketCreated;
260
0
  event_notifier_map_["webSocketClosed"] = &NetworkAgent::webSocketClosed;
261
0
  event_notifier_map_["webSocketHandshakeResponseReceived"] =
262
0
      &NetworkAgent::webSocketHandshakeResponseReceived;
263
0
}
264
265
void NetworkAgent::webSocketCreated(v8::Local<v8::Context> context,
266
0
                                    v8::Local<v8::Object> params) {
267
0
  protocol::String request_id;
268
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
269
0
    return;
270
0
  }
271
0
  protocol::String url;
272
0
  if (!ObjectGetProtocolString(context, params, "url").To(&url)) {
273
0
    return;
274
0
  }
275
0
  std::unique_ptr<protocol::Network::Initiator> initiator =
276
0
      protocol::Network::Initiator::create()
277
0
          .setType(protocol::Network::Initiator::TypeEnum::Script)
278
0
          .setStack(
279
0
              v8_inspector_->captureStackTrace(true)->buildInspectorObject(0))
280
0
          .build();
281
0
  frontend_->webSocketCreated(request_id, url, std::move(initiator));
282
0
}
283
284
void NetworkAgent::webSocketClosed(v8::Local<v8::Context> context,
285
0
                                   v8::Local<v8::Object> params) {
286
0
  protocol::String request_id;
287
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
288
0
    return;
289
0
  }
290
0
  double timestamp;
291
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
292
0
    return;
293
0
  }
294
0
  frontend_->webSocketClosed(request_id, timestamp);
295
0
}
296
297
void NetworkAgent::webSocketHandshakeResponseReceived(
298
0
    v8::Local<v8::Context> context, v8::Local<v8::Object> params) {
299
0
  protocol::String request_id;
300
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
301
0
    return;
302
0
  }
303
0
  double timestamp;
304
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
305
0
    return;
306
0
  }
307
0
  Local<Object> response_obj;
308
0
  if (!ObjectGetObject(context, params, "response").ToLocal(&response_obj)) {
309
0
    return;
310
0
  }
311
0
  auto response = createWebSocketResponse(context, response_obj);
312
0
  if (!response) {
313
0
    return;
314
0
  }
315
0
  frontend_->webSocketHandshakeResponseReceived(
316
0
      request_id, timestamp, std::move(response));
317
0
}
318
319
void NetworkAgent::emitNotification(v8::Local<v8::Context> context,
320
                                    const protocol::String& event,
321
0
                                    v8::Local<v8::Object> params) {
322
0
  if (!inspector_->IsEnabled()) return;
323
0
  auto it = event_notifier_map_.find(event);
324
0
  if (it != event_notifier_map_.end()) {
325
0
    (this->*(it->second))(context, params);
326
0
  }
327
0
}
328
329
0
void NetworkAgent::Wire(protocol::UberDispatcher* dispatcher) {
330
0
  frontend_ =
331
0
      std::make_unique<protocol::Network::Frontend>(dispatcher->channel());
332
0
  protocol::Network::Dispatcher::wire(dispatcher, this);
333
0
}
334
335
protocol::DispatchResponse NetworkAgent::enable(
336
    std::optional<int> in_maxTotalBufferSize,
337
0
    std::optional<int> in_maxResourceBufferSize) {
338
0
  inspector_->Enable();
339
0
  requests_ = RequestsBuffer(
340
0
      in_maxTotalBufferSize.value_or(kDefaultMaxTotalBufferSize));
341
0
  if (in_maxResourceBufferSize) {
342
0
    max_resource_buffer_size_ = *in_maxResourceBufferSize;
343
0
  }
344
0
  return protocol::DispatchResponse::Success();
345
0
}
346
347
0
protocol::DispatchResponse NetworkAgent::disable() {
348
0
  inspector_->Disable();
349
0
  return protocol::DispatchResponse::Success();
350
0
}
351
352
protocol::DispatchResponse NetworkAgent::getRequestPostData(
353
0
    const protocol::String& in_requestId, protocol::String* out_postData) {
354
0
  auto request_entry = requests_.cfind(in_requestId);
355
0
  if (request_entry == requests_.end()) {
356
    // Request not found, ignore it.
357
0
    return protocol::DispatchResponse::InvalidParams("Request not found");
358
0
  }
359
360
0
  if (!request_entry->second.is_request_finished) {
361
    // Request not finished yet.
362
0
    return protocol::DispatchResponse::InvalidParams(
363
0
        "Request data is not finished yet");
364
0
  }
365
0
  if (request_entry->second.request_charset == Charset::kBinary) {
366
    // The protocol does not support binary request bodies yet.
367
0
    return protocol::DispatchResponse::ServerError(
368
0
        "Unable to serialize binary request body");
369
0
  }
370
  // If the response is UTF-8, we return it as a concatenated string.
371
0
  CHECK_EQ(request_entry->second.request_charset, Charset::kUTF8);
372
373
  // Concat response bodies.
374
0
  protocol::Binary buf =
375
0
      protocol::Binary::concat(request_entry->second.request_data_blobs());
376
0
  *out_postData = protocol::StringUtil::fromUTF8(buf.data(), buf.size());
377
0
  return protocol::DispatchResponse::Success();
378
0
}
379
380
protocol::DispatchResponse NetworkAgent::getResponseBody(
381
    const protocol::String& in_requestId,
382
    protocol::String* out_body,
383
0
    bool* out_base64Encoded) {
384
0
  auto request_entry = requests_.cfind(in_requestId);
385
0
  if (request_entry == requests_.end()) {
386
    // Request not found, ignore it.
387
0
    return protocol::DispatchResponse::InvalidParams("Request not found");
388
0
  }
389
390
0
  if (request_entry->second.is_streaming) {
391
    // Streaming request, data is not buffered.
392
0
    return protocol::DispatchResponse::InvalidParams(
393
0
        "Response body of the request is been streamed");
394
0
  }
395
396
0
  if (!request_entry->second.is_response_finished) {
397
    // Response not finished yet.
398
0
    return protocol::DispatchResponse::InvalidParams(
399
0
        "Response data is not finished yet");
400
0
  }
401
402
  // Concat response bodies.
403
0
  protocol::Binary buf =
404
0
      protocol::Binary::concat(request_entry->second.response_data_blobs());
405
0
  if (request_entry->second.response_charset == Charset::kBinary) {
406
    // If the response is binary, we return base64 encoded data.
407
0
    *out_body = buf.toBase64();
408
0
    *out_base64Encoded = true;
409
0
  } else if (request_entry->second.response_charset == Charset::kUTF8) {
410
    // If the response is UTF-8, we return it as a concatenated string.
411
0
    *out_body = protocol::StringUtil::fromUTF8(buf.data(), buf.size());
412
0
    *out_base64Encoded = false;
413
0
  } else {
414
0
    UNREACHABLE("Response charset not implemented");
415
0
  }
416
417
0
  requests_.erase(request_entry);
418
0
  return protocol::DispatchResponse::Success();
419
0
}
420
421
protocol::DispatchResponse NetworkAgent::streamResourceContent(
422
0
    const protocol::String& in_requestId, protocol::Binary* out_bufferedData) {
423
0
  bool is_response_finished = false;
424
0
  {
425
0
    auto it = requests_.find(in_requestId);
426
0
    if (it == requests_.end()) {
427
      // Request not found, ignore it.
428
0
      return protocol::DispatchResponse::InvalidParams("Request not found");
429
0
    }
430
0
    auto& request_entry = it->second;
431
432
0
    request_entry.is_streaming = true;
433
434
    // Concat response bodies.
435
0
    *out_bufferedData =
436
0
        protocol::Binary::concat(request_entry.response_data_blobs());
437
    // Clear buffered data.
438
0
    request_entry.clear_response_data_blobs();
439
0
    is_response_finished = request_entry.is_response_finished;
440
0
  }
441
442
0
  if (is_response_finished) {
443
    // If the request is finished, remove the entry.
444
0
    requests_.erase(in_requestId);
445
0
  }
446
0
  return protocol::DispatchResponse::Success();
447
0
}
448
449
protocol::DispatchResponse NetworkAgent::loadNetworkResource(
450
    const protocol::String& in_url,
451
    std::unique_ptr<protocol::Network::LoadNetworkResourcePageResult>*
452
0
        out_resource) {
453
0
  if (!env_->options()->experimental_inspector_network_resource) {
454
0
    return protocol::DispatchResponse::ServerError(
455
0
        "Network resource loading is not enabled. This feature is "
456
0
        "experimental and requires --experimental-inspector-network-resource "
457
0
        "flag to be set.");
458
0
  }
459
0
  CHECK_NOT_NULL(network_resource_manager_);
460
0
  std::string data = network_resource_manager_->Get(in_url);
461
0
  bool found = !data.empty();
462
0
  if (found) {
463
0
    auto result = protocol::Network::LoadNetworkResourcePageResult::create()
464
0
                      .setSuccess(true)
465
0
                      .setStream(in_url)
466
0
                      .build();
467
0
    *out_resource = std::move(result);
468
0
    return protocol::DispatchResponse::Success();
469
0
  } else {
470
0
    auto result = protocol::Network::LoadNetworkResourcePageResult::create()
471
0
                      .setSuccess(false)
472
0
                      .build();
473
0
    *out_resource = std::move(result);
474
0
    return protocol::DispatchResponse::Success();
475
0
  }
476
0
}
477
478
void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context,
479
0
                                     v8::Local<v8::Object> params) {
480
0
  protocol::String request_id;
481
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
482
0
    return;
483
0
  }
484
0
  double timestamp;
485
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
486
0
    return;
487
0
  }
488
0
  double wall_time;
489
0
  if (!ObjectGetDouble(context, params, "wallTime").To(&wall_time)) {
490
0
    return;
491
0
  }
492
0
  protocol::String charset =
493
0
      ObjectGetProtocolString(context, params, "charset").FromMaybe("");
494
0
  Local<v8::Object> request_obj;
495
0
  if (!ObjectGetObject(context, params, "request").ToLocal(&request_obj)) {
496
0
    return;
497
0
  }
498
0
  std::unique_ptr<protocol::Network::Request> request =
499
0
      createRequestFromObject(context, request_obj);
500
0
  if (!request) {
501
0
    return;
502
0
  }
503
504
0
  std::unique_ptr<protocol::Network::Initiator> initiator =
505
0
      protocol::Network::Initiator::create()
506
0
          .setType(protocol::Network::Initiator::TypeEnum::Script)
507
0
          .setStack(
508
0
              v8_inspector_->captureStackTrace(true)->buildInspectorObject(0))
509
0
          .build();
510
511
0
  if (requests_.contains(request_id)) {
512
    // Duplicate entry, ignore it.
513
0
    return;
514
0
  }
515
516
0
  auto request_charset = charset == "utf-8" ? Charset::kUTF8 : Charset::kBinary;
517
0
  requests_.emplace(request_id,
518
0
                    RequestEntry(timestamp,
519
0
                                 request_charset,
520
0
                                 request->getHasPostData(),
521
0
                                 max_resource_buffer_size_));
522
0
  frontend_->requestWillBeSent(request_id,
523
0
                               std::move(request),
524
0
                               std::move(initiator),
525
0
                               timestamp,
526
0
                               wall_time);
527
0
}
528
529
void NetworkAgent::responseReceived(v8::Local<v8::Context> context,
530
0
                                    v8::Local<v8::Object> params) {
531
0
  protocol::String request_id;
532
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
533
0
    return;
534
0
  }
535
0
  double timestamp;
536
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
537
0
    return;
538
0
  }
539
0
  protocol::String type;
540
0
  if (!ObjectGetProtocolString(context, params, "type").To(&type)) {
541
0
    return;
542
0
  }
543
0
  Local<Object> response_obj;
544
0
  if (!ObjectGetObject(context, params, "response").ToLocal(&response_obj)) {
545
0
    return;
546
0
  }
547
0
  auto response = createResponseFromObject(context, response_obj);
548
0
  if (!response) {
549
0
    return;
550
0
  }
551
552
0
  auto request_entry = requests_.find(request_id);
553
0
  if (request_entry == requests_.end()) {
554
    // No entry found. Ignore it.
555
0
    return;
556
0
  }
557
0
  request_entry->second.response_charset =
558
0
      response->getCharset() == "utf-8" ? Charset::kUTF8 : Charset::kBinary;
559
0
  frontend_->responseReceived(request_id, timestamp, type, std::move(response));
560
0
}
561
562
void NetworkAgent::loadingFailed(v8::Local<v8::Context> context,
563
0
                                 v8::Local<v8::Object> params) {
564
0
  protocol::String request_id;
565
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
566
0
    return;
567
0
  }
568
0
  double timestamp;
569
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
570
0
    return;
571
0
  }
572
0
  protocol::String type;
573
0
  if (!ObjectGetProtocolString(context, params, "type").To(&type)) {
574
0
    return;
575
0
  }
576
0
  protocol::String error_text;
577
0
  if (!ObjectGetProtocolString(context, params, "errorText").To(&error_text)) {
578
0
    return;
579
0
  }
580
581
0
  frontend_->loadingFailed(request_id, timestamp, type, error_text);
582
583
0
  requests_.erase(request_id);
584
0
}
585
586
void NetworkAgent::loadingFinished(v8::Local<v8::Context> context,
587
0
                                   Local<v8::Object> params) {
588
0
  protocol::String request_id;
589
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
590
0
    return;
591
0
  }
592
0
  double timestamp;
593
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
594
0
    return;
595
0
  }
596
597
0
  frontend_->loadingFinished(request_id, timestamp);
598
599
0
  auto request_entry = requests_.cfind(request_id);
600
0
  if (request_entry == requests_.end()) {
601
    // No entry found. Ignore it.
602
0
    return;
603
0
  }
604
605
0
  if (request_entry->second.is_streaming) {
606
    // Streaming finished, remove the entry.
607
0
    requests_.erase(request_id);
608
0
  } else {
609
0
    requests_.find(request_id)->second.is_response_finished = true;
610
0
  }
611
0
}
612
613
void NetworkAgent::dataSent(v8::Local<v8::Context> context,
614
0
                            v8::Local<v8::Object> params) {
615
0
  protocol::String request_id;
616
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
617
0
    return;
618
0
  }
619
620
0
  auto request_entry = requests_.find(request_id);
621
0
  if (request_entry == requests_.end()) {
622
    // No entry found. Ignore it.
623
0
    return;
624
0
  }
625
626
0
  bool is_finished =
627
0
      ObjectGetBool(context, params, "finished").FromMaybe(false);
628
0
  if (is_finished) {
629
0
    request_entry->second.is_request_finished = true;
630
0
    return;
631
0
  }
632
633
0
  double timestamp;
634
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
635
0
    return;
636
0
  }
637
0
  int data_length;
638
0
  if (!ObjectGetInt(context, params, "dataLength").To(&data_length)) {
639
0
    return;
640
0
  }
641
0
  Local<Object> data_obj;
642
0
  if (!ObjectGetObject(context, params, "data").ToLocal(&data_obj)) {
643
0
    return;
644
0
  }
645
0
  if (!data_obj->IsUint8Array()) {
646
0
    return;
647
0
  }
648
0
  Local<Uint8Array> data = data_obj.As<Uint8Array>();
649
0
  auto data_bin = protocol::Binary::fromUint8Array(data);
650
0
  request_entry->second.push_request_data_blob(data_bin);
651
0
}
652
653
void NetworkAgent::dataReceived(v8::Local<v8::Context> context,
654
0
                                v8::Local<v8::Object> params) {
655
0
  protocol::String request_id;
656
0
  if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
657
0
    return;
658
0
  }
659
0
  double timestamp;
660
0
  if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
661
0
    return;
662
0
  }
663
0
  int data_length;
664
0
  if (!ObjectGetInt(context, params, "dataLength").To(&data_length)) {
665
0
    return;
666
0
  }
667
0
  int encoded_data_length;
668
0
  if (!ObjectGetInt(context, params, "encodedDataLength")
669
0
           .To(&encoded_data_length)) {
670
0
    return;
671
0
  }
672
0
  Local<Object> data_obj;
673
0
  if (!ObjectGetObject(context, params, "data").ToLocal(&data_obj)) {
674
0
    return;
675
0
  }
676
0
  if (!data_obj->IsUint8Array()) {
677
0
    return;
678
0
  }
679
0
  Local<Uint8Array> data = data_obj.As<Uint8Array>();
680
0
  auto data_bin = protocol::Binary::fromUint8Array(data);
681
682
0
  auto it = requests_.find(request_id);
683
0
  if (it == requests_.end()) {
684
    // No entry found. Ignore it.
685
0
    return;
686
0
  }
687
0
  auto& request_entry = it->second;
688
0
  if (request_entry.is_streaming) {
689
0
    frontend_->dataReceived(
690
0
        request_id, timestamp, data_length, encoded_data_length, data_bin);
691
0
  } else {
692
0
    request_entry.push_response_data_blob(data_bin);
693
0
  }
694
0
}
695
696
}  // namespace inspector
697
}  // namespace node