|
1 | 1 | #include "network_agent.h" |
2 | 2 | #include <string> |
| 3 | +#include "crdtp/cbor.h" |
3 | 4 | #include "debug_utils-inl.h" |
4 | 5 | #include "env-inl.h" |
5 | 6 | #include "inspector/inspector_object_utils.h" |
@@ -37,93 +38,88 @@ static void ThrowEventError(v8::Isolate* isolate, const std::string& message) { |
37 | 38 | v8::String::NewFromUtf8(isolate, message.c_str()).ToLocalChecked())); |
38 | 39 | } |
39 | 40 |
|
40 | | -static std::unique_ptr<protocol::Value> V8ToProtocolValue( |
41 | | - Isolate* isolate, |
42 | | - Local<Context> context, |
43 | | - Local<Value> value, |
44 | | - LocalVector<Object>* ancestors) { |
| 41 | +// Encode directly into the format consumed by the imported V8 StackTrace |
| 42 | +// parser, avoiding an intermediate tree of protocol::Value allocations. |
| 43 | +static bool EncodeV8Value(Isolate* isolate, |
| 44 | + Local<Context> context, |
| 45 | + Local<Value> value, |
| 46 | + LocalVector<Object>* ancestors, |
| 47 | + std::vector<uint8_t>* bytes, |
| 48 | + bool* has_call_frames = nullptr) { |
| 49 | + namespace cbor = crdtp::cbor; |
45 | 50 | if (value->IsNullOrUndefined()) { |
46 | | - return protocol::Value::null(); |
| 51 | + bytes->push_back(cbor::EncodeNull()); |
| 52 | + return true; |
47 | 53 | } |
48 | 54 | if (value->IsBoolean()) { |
49 | | - return protocol::FundamentalValue::create(value.As<Boolean>()->Value()); |
| 55 | + bytes->push_back(value.As<Boolean>()->Value() ? cbor::EncodeTrue() |
| 56 | + : cbor::EncodeFalse()); |
| 57 | + return true; |
50 | 58 | } |
51 | 59 | if (value->IsInt32()) { |
52 | | - return protocol::FundamentalValue::create(value.As<Int32>()->Value()); |
| 60 | + cbor::EncodeInt32(value.As<Int32>()->Value(), bytes); |
| 61 | + return true; |
53 | 62 | } |
54 | 63 | if (value->IsNumber()) { |
55 | | - return protocol::FundamentalValue::create(value.As<Number>()->Value()); |
| 64 | + cbor::EncodeDouble(value.As<Number>()->Value(), bytes); |
| 65 | + return true; |
56 | 66 | } |
57 | 67 | if (value->IsString()) { |
58 | | - return protocol::StringValue::create(ToProtocolString(isolate, value)); |
59 | | - } |
60 | | - |
61 | | - if (!value->IsObject()) { |
62 | | - return nullptr; |
| 68 | + Utf8Value string(isolate, value); |
| 69 | + cbor::EncodeString8( |
| 70 | + crdtp::span<uint8_t>(reinterpret_cast<const uint8_t*>(*string), |
| 71 | + string.length()), |
| 72 | + bytes); |
| 73 | + return true; |
63 | 74 | } |
| 75 | + if (!value->IsObject()) return false; |
64 | 76 |
|
65 | 77 | Local<Object> object = value.As<Object>(); |
66 | | - if (ancestors->size() >= kMaxProtocolValueDepth) { |
67 | | - return nullptr; |
68 | | - } |
| 78 | + if (ancestors->size() >= kMaxProtocolValueDepth) return false; |
69 | 79 | for (const auto& ancestor : *ancestors) { |
70 | | - if (ancestor == object) { |
71 | | - return nullptr; |
72 | | - } |
| 80 | + if (ancestor == object) return false; |
73 | 81 | } |
74 | 82 | ancestors->push_back(object); |
75 | 83 | auto pop_ancestor = OnScopeLeave([ancestors]() { ancestors->pop_back(); }); |
76 | | - |
| 84 | + cbor::EnvelopeEncoder envelope; |
| 85 | + envelope.EncodeStart(bytes); |
77 | 86 | if (value->IsArray()) { |
78 | 87 | Local<Array> array = value.As<Array>(); |
79 | | - std::unique_ptr<protocol::ListValue> list = protocol::ListValue::create(); |
80 | | - list->reserve(array->Length()); |
| 88 | + bytes->push_back(cbor::EncodeIndefiniteLengthArrayStart()); |
81 | 89 | for (uint32_t i = 0; i < array->Length(); i++) { |
82 | 90 | Local<Value> element; |
83 | | - if (!array->Get(context, i).ToLocal(&element)) { |
84 | | - return nullptr; |
85 | | - } |
86 | | - std::unique_ptr<protocol::Value> protocol_value = |
87 | | - V8ToProtocolValue(isolate, context, element, ancestors); |
88 | | - if (!protocol_value) { |
89 | | - return nullptr; |
| 91 | + if (!array->Get(context, i).ToLocal(&element) || |
| 92 | + !EncodeV8Value(isolate, context, element, ancestors, bytes)) { |
| 93 | + return false; |
90 | 94 | } |
91 | | - list->pushValue(std::move(protocol_value)); |
92 | | - } |
93 | | - return list; |
94 | | - } |
95 | | - |
96 | | - Local<Array> property_names; |
97 | | - if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) { |
98 | | - return nullptr; |
99 | | - } |
100 | | - std::unique_ptr<protocol::DictionaryValue> dict = |
101 | | - protocol::DictionaryValue::create(); |
102 | | - for (uint32_t i = 0; i < property_names->Length(); i++) { |
103 | | - Local<Value> property_name; |
104 | | - if (!property_names->Get(context, i).ToLocal(&property_name) || |
105 | | - !property_name->IsString()) { |
106 | | - return nullptr; |
107 | 95 | } |
108 | | - Local<Value> property; |
109 | | - if (!object->Get(context, property_name).ToLocal(&property)) { |
110 | | - return nullptr; |
| 96 | + } else { |
| 97 | + Local<Array> property_names; |
| 98 | + if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) { |
| 99 | + return false; |
111 | 100 | } |
112 | | - std::unique_ptr<protocol::Value> protocol_value = |
113 | | - V8ToProtocolValue(isolate, context, property, ancestors); |
114 | | - if (!protocol_value) { |
115 | | - return nullptr; |
| 101 | + bytes->push_back(cbor::EncodeIndefiniteLengthMapStart()); |
| 102 | + for (uint32_t i = 0; i < property_names->Length(); i++) { |
| 103 | + Local<Value> property_name; |
| 104 | + if (!property_names->Get(context, i).ToLocal(&property_name) || |
| 105 | + !property_name->IsString()) { |
| 106 | + return false; |
| 107 | + } |
| 108 | + if (has_call_frames != nullptr && |
| 109 | + property_name.As<v8::String>()->StringEquals( |
| 110 | + FIXED_ONE_BYTE_STRING(isolate, "callFrames"))) { |
| 111 | + *has_call_frames = true; |
| 112 | + } |
| 113 | + Local<Value> property; |
| 114 | + if (!object->Get(context, property_name).ToLocal(&property) || |
| 115 | + !EncodeV8Value(isolate, context, property_name, ancestors, bytes) || |
| 116 | + !EncodeV8Value(isolate, context, property, ancestors, bytes)) { |
| 117 | + return false; |
| 118 | + } |
116 | 119 | } |
117 | | - dict->setValue(ToProtocolString(isolate, property_name), |
118 | | - std::move(protocol_value)); |
119 | 120 | } |
120 | | - return dict; |
121 | | -} |
122 | | - |
123 | | -static std::unique_ptr<protocol::Value> V8ToProtocolValue( |
124 | | - Isolate* isolate, Local<Context> context, Local<Value> value) { |
125 | | - LocalVector<Object> ancestors(isolate); |
126 | | - return V8ToProtocolValue(isolate, context, value, &ancestors); |
| 121 | + bytes->push_back(cbor::EncodeStop()); |
| 122 | + return envelope.EncodeStop(bytes); |
127 | 123 | } |
128 | 124 |
|
129 | 125 | // Create a protocol::Network::Headers from the v8 object. |
@@ -179,25 +175,21 @@ NetworkAgent::createInitiatorFromObject(v8::Local<v8::Context> context, |
179 | 175 |
|
180 | 176 | Local<Object> stack_obj; |
181 | 177 | if (ObjectGetObject(context, initiator_obj, "stack").ToLocal(&stack_obj)) { |
182 | | - std::unique_ptr<protocol::Value> stack_value = |
183 | | - V8ToProtocolValue(isolate, context, stack_obj); |
184 | | - if (!stack_value) { |
| 178 | + LocalVector<Object> ancestors(isolate); |
| 179 | + std::vector<uint8_t> bytes; |
| 180 | + bool has_call_frames = false; |
| 181 | + if (!EncodeV8Value(isolate, |
| 182 | + context, |
| 183 | + stack_obj, |
| 184 | + &ancestors, |
| 185 | + &bytes, |
| 186 | + &has_call_frames) || |
| 187 | + !has_call_frames) { |
185 | 188 | ThrowEventError(isolate, "Invalid initiator.stack in event"); |
186 | 189 | return {}; |
187 | 190 | } |
188 | | - |
189 | | - protocol::DictionaryValue* stack_dict = |
190 | | - protocol::DictionaryValue::cast(stack_value.get()); |
191 | | - if (!stack_dict || stack_dict->get("callFrames") == nullptr) { |
192 | | - ThrowEventError(isolate, "Invalid initiator.stack in event"); |
193 | | - return {}; |
194 | | - } |
195 | | - |
196 | | - protocol::ErrorSupport errors; |
197 | | - std::unique_ptr<v8_inspector::protocol::Runtime::API::StackTrace> stack = |
198 | | - protocol::ValueConversions<v8_inspector::protocol::Runtime::API:: |
199 | | - StackTrace>::fromValue(stack_value.get(), |
200 | | - &errors); |
| 191 | + auto stack = v8_inspector::protocol::Runtime::API::StackTrace::fromBinary( |
| 192 | + bytes.data(), bytes.size()); |
201 | 193 | if (!stack) { |
202 | 194 | ThrowEventError(isolate, "Invalid initiator.stack in event"); |
203 | 195 | return {}; |
|
0 commit comments