GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#include "stream_base.h" // NOLINT(build/include_inline) |
||
2 |
#include "stream_base-inl.h" |
||
3 |
#include "stream_wrap.h" |
||
4 |
|||
5 |
#include "node.h" |
||
6 |
#include "node_buffer.h" |
||
7 |
#include "node_errors.h" |
||
8 |
#include "env-inl.h" |
||
9 |
#include "js_stream.h" |
||
10 |
#include "string_bytes.h" |
||
11 |
#include "util-inl.h" |
||
12 |
#include "v8.h" |
||
13 |
|||
14 |
#include <climits> // INT_MAX |
||
15 |
|||
16 |
namespace node { |
||
17 |
|||
18 |
using v8::Array; |
||
19 |
using v8::ArrayBuffer; |
||
20 |
using v8::Context; |
||
21 |
using v8::DontDelete; |
||
22 |
using v8::DontEnum; |
||
23 |
using v8::External; |
||
24 |
using v8::Function; |
||
25 |
using v8::FunctionCallbackInfo; |
||
26 |
using v8::HandleScope; |
||
27 |
using v8::Integer; |
||
28 |
using v8::Local; |
||
29 |
using v8::MaybeLocal; |
||
30 |
using v8::Object; |
||
31 |
using v8::ReadOnly; |
||
32 |
using v8::String; |
||
33 |
using v8::Value; |
||
34 |
|||
35 |
template int StreamBase::WriteString<ASCII>( |
||
36 |
const FunctionCallbackInfo<Value>& args); |
||
37 |
template int StreamBase::WriteString<UTF8>( |
||
38 |
const FunctionCallbackInfo<Value>& args); |
||
39 |
template int StreamBase::WriteString<UCS2>( |
||
40 |
const FunctionCallbackInfo<Value>& args); |
||
41 |
template int StreamBase::WriteString<LATIN1>( |
||
42 |
const FunctionCallbackInfo<Value>& args); |
||
43 |
|||
44 |
|||
45 |
74856 |
int StreamBase::ReadStartJS(const FunctionCallbackInfo<Value>& args) { |
|
46 |
74856 |
return ReadStart(); |
|
47 |
} |
||
48 |
|||
49 |
|||
50 |
2038 |
int StreamBase::ReadStopJS(const FunctionCallbackInfo<Value>& args) { |
|
51 |
2038 |
return ReadStop(); |
|
52 |
} |
||
53 |
|||
54 |
6 |
int StreamBase::UseUserBuffer(const FunctionCallbackInfo<Value>& args) { |
|
55 |
✗✓ | 6 |
CHECK(Buffer::HasInstance(args[0])); |
56 |
|||
57 |
12 |
uv_buf_t buf = uv_buf_init(Buffer::Data(args[0]), Buffer::Length(args[0])); |
|
58 |
6 |
PushStreamListener(new CustomBufferJSListener(buf)); |
|
59 |
6 |
return 0; |
|
60 |
} |
||
61 |
|||
62 |
56064 |
int StreamBase::Shutdown(const FunctionCallbackInfo<Value>& args) { |
|
63 |
✗✓ | 112128 |
CHECK(args[0]->IsObject()); |
64 |
112128 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
65 |
|||
66 |
56064 |
return Shutdown(req_wrap_obj); |
|
67 |
} |
||
68 |
|||
69 |
854232 |
void StreamBase::SetWriteResult(const StreamWriteResult& res) { |
|
70 |
854232 |
env_->stream_base_state()[kBytesWritten] = res.bytes; |
|
71 |
854232 |
env_->stream_base_state()[kLastWriteWasAsync] = res.async; |
|
72 |
854232 |
} |
|
73 |
|||
74 |
113611 |
int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) { |
|
75 |
113611 |
Environment* env = Environment::GetCurrent(args); |
|
76 |
|||
77 |
✗✓ | 227222 |
CHECK(args[0]->IsObject()); |
78 |
✗✓ | 227222 |
CHECK(args[1]->IsArray()); |
79 |
|||
80 |
227222 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
81 |
227222 |
Local<Array> chunks = args[1].As<Array>(); |
|
82 |
227222 |
bool all_buffers = args[2]->IsTrue(); |
|
83 |
|||
84 |
size_t count; |
||
85 |
✓✓ | 113611 |
if (all_buffers) |
86 |
295 |
count = chunks->Length(); |
|
87 |
else |
||
88 |
113316 |
count = chunks->Length() >> 1; |
|
89 |
|||
90 |
113611 |
MaybeStackBuffer<uv_buf_t, 16> bufs(count); |
|
91 |
|||
92 |
113611 |
size_t storage_size = 0; |
|
93 |
size_t offset; |
||
94 |
|||
95 |
✓✓ | 113611 |
if (!all_buffers) { |
96 |
// Determine storage size first |
||
97 |
✓✓ | 628385 |
for (size_t i = 0; i < count; i++) { |
98 |
1545207 |
Local<Value> chunk = chunks->Get(env->context(), i * 2).ToLocalChecked(); |
|
99 |
|||
100 |
✓✓ | 515069 |
if (Buffer::HasInstance(chunk)) |
101 |
43266 |
continue; |
|
102 |
// Buffer chunk, no additional storage required |
||
103 |
|||
104 |
// String chunk |
||
105 |
1415409 |
Local<String> string = chunk->ToString(env->context()).ToLocalChecked(); |
|
106 |
enum encoding encoding = ParseEncoding(env->isolate(), |
||
107 |
1415409 |
chunks->Get(env->context(), i * 2 + 1).ToLocalChecked()); |
|
108 |
size_t chunk_size; |
||
109 |
✓✓✓✓ ✗✓✗✓ |
1698232 |
if (encoding == UTF8 && string->Length() > 65535 && |
110 |
✓✓✓✓ |
471815 |
!StringBytes::Size(env->isolate(), string, encoding).To(&chunk_size)) |
111 |
return 0; |
||
112 |
✗✓ | 1415409 |
else if (!StringBytes::StorageSize(env->isolate(), string, encoding) |
113 |
1415409 |
.To(&chunk_size)) |
|
114 |
return 0; |
||
115 |
471803 |
storage_size += chunk_size; |
|
116 |
} |
||
117 |
|||
118 |
✗✓ | 113316 |
if (storage_size > INT_MAX) |
119 |
return UV_ENOBUFS; |
||
120 |
} else { |
||
121 |
✓✓ | 136700 |
for (size_t i = 0; i < count; i++) { |
122 |
409215 |
Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked(); |
|
123 |
136405 |
bufs[i].base = Buffer::Data(chunk); |
|
124 |
136405 |
bufs[i].len = Buffer::Length(chunk); |
|
125 |
} |
||
126 |
} |
||
127 |
|||
128 |
227222 |
AllocatedBuffer storage; |
|
129 |
✓✓ | 113611 |
if (storage_size > 0) |
130 |
113270 |
storage = env->AllocateManaged(storage_size); |
|
131 |
|||
132 |
113611 |
offset = 0; |
|
133 |
✓✓ | 113611 |
if (!all_buffers) { |
134 |
✓✓ | 628385 |
for (size_t i = 0; i < count; i++) { |
135 |
1545207 |
Local<Value> chunk = chunks->Get(env->context(), i * 2).ToLocalChecked(); |
|
136 |
|||
137 |
// Write buffer |
||
138 |
✓✓ | 515069 |
if (Buffer::HasInstance(chunk)) { |
139 |
43266 |
bufs[i].base = Buffer::Data(chunk); |
|
140 |
43266 |
bufs[i].len = Buffer::Length(chunk); |
|
141 |
43266 |
continue; |
|
142 |
} |
||
143 |
|||
144 |
// Write string |
||
145 |
✗✓ | 471803 |
CHECK_LE(offset, storage_size); |
146 |
471803 |
char* str_storage = storage.data() + offset; |
|
147 |
471803 |
size_t str_size = storage.size() - offset; |
|
148 |
|||
149 |
1415409 |
Local<String> string = chunk->ToString(env->context()).ToLocalChecked(); |
|
150 |
enum encoding encoding = ParseEncoding(env->isolate(), |
||
151 |
1415409 |
chunks->Get(env->context(), i * 2 + 1).ToLocalChecked()); |
|
152 |
str_size = StringBytes::Write(env->isolate(), |
||
153 |
str_storage, |
||
154 |
str_size, |
||
155 |
string, |
||
156 |
471803 |
encoding); |
|
157 |
471803 |
bufs[i].base = str_storage; |
|
158 |
471803 |
bufs[i].len = str_size; |
|
159 |
471803 |
offset += str_size; |
|
160 |
} |
||
161 |
} |
||
162 |
|||
163 |
113611 |
StreamWriteResult res = Write(*bufs, count, nullptr, req_wrap_obj); |
|
164 |
113611 |
SetWriteResult(res); |
|
165 |
✓✓✓✓ |
113611 |
if (res.wrap != nullptr && storage_size > 0) { |
166 |
344 |
res.wrap->SetAllocatedStorage(std::move(storage)); |
|
167 |
} |
||
168 |
227222 |
return res.err; |
|
169 |
} |
||
170 |
|||
171 |
|||
172 |
51134 |
int StreamBase::WriteBuffer(const FunctionCallbackInfo<Value>& args) { |
|
173 |
✗✓ | 102268 |
CHECK(args[0]->IsObject()); |
174 |
|||
175 |
51134 |
Environment* env = Environment::GetCurrent(args); |
|
176 |
|||
177 |
✓✓ | 102268 |
if (!args[1]->IsUint8Array()) { |
178 |
1 |
node::THROW_ERR_INVALID_ARG_TYPE(env, "Second argument must be a buffer"); |
|
179 |
1 |
return 0; |
|
180 |
} |
||
181 |
|||
182 |
102266 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
183 |
|||
184 |
uv_buf_t buf; |
||
185 |
51133 |
buf.base = Buffer::Data(args[1]); |
|
186 |
51133 |
buf.len = Buffer::Length(args[1]); |
|
187 |
|||
188 |
51133 |
StreamWriteResult res = Write(&buf, 1, nullptr, req_wrap_obj); |
|
189 |
51133 |
SetWriteResult(res); |
|
190 |
|||
191 |
51133 |
return res.err; |
|
192 |
} |
||
193 |
|||
194 |
|||
195 |
template <enum encoding enc> |
||
196 |
689488 |
int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) { |
|
197 |
689488 |
Environment* env = Environment::GetCurrent(args); |
|
198 |
✗✓✗✓ ✗✓✗✓ |
1378976 |
CHECK(args[0]->IsObject()); |
199 |
✗✓✗✓ ✗✓✗✓ |
2068464 |
CHECK(args[1]->IsString()); |
200 |
|||
201 |
1378976 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
202 |
1378976 |
Local<String> string = args[1].As<String>(); |
|
203 |
Local<Object> send_handle_obj; |
||
204 |
✗✓✗✓ ✓✓✗✓ |
1378976 |
if (args[2]->IsObject()) |
205 |
206 |
send_handle_obj = args[2].As<Object>(); |
|
206 |
|||
207 |
// Compute the size of the storage that the string will be flattened into. |
||
208 |
// For UTF8 strings that are very long, go ahead and take the hit for |
||
209 |
// computing their actual size, rather than tripling the storage. |
||
210 |
size_t storage_size; |
||
211 |
✓✓✗✓ ✗✓ |
2707006 |
if (enc == UTF8 && string->Length() > 65535 && |
212 |
✓✓✓✓ |
676823 |
!StringBytes::Size(env->isolate(), string, enc).To(&storage_size)) |
213 |
return 0; |
||
214 |
✗✓✗✓ ✗✓✗✓ |
2068464 |
else if (!StringBytes::StorageSize(env->isolate(), string, enc) |
215 |
2068464 |
.To(&storage_size)) |
|
216 |
return 0; |
||
217 |
|||
218 |
✗✓✗✓ ✗✓✗✓ |
689488 |
if (storage_size > INT_MAX) |
219 |
return UV_ENOBUFS; |
||
220 |
|||
221 |
// Try writing immediately if write size isn't too big |
||
222 |
char stack_storage[16384]; // 16kb |
||
223 |
size_t data_size; |
||
224 |
689488 |
size_t synchronously_written = 0; |
|
225 |
uv_buf_t buf; |
||
226 |
|||
227 |
bool try_write = storage_size <= sizeof(stack_storage) && |
||
228 |
✓✓✗✓ ✗✗✓✗ ✗✓✗✗ ✓✓✓✓ ✓✓✓✗ ✗✓✗✗ |
691340 |
(!IsIPCPipe() || send_handle_obj.IsEmpty()); |
229 |
✓✓✓✗ ✓✓✓✗ |
689488 |
if (try_write) { |
230 |
688333 |
data_size = StringBytes::Write(env->isolate(), |
|
231 |
stack_storage, |
||
232 |
storage_size, |
||
233 |
string, |
||
234 |
1376666 |
enc); |
|
235 |
688333 |
buf = uv_buf_init(stack_storage, data_size); |
|
236 |
|||
237 |
688333 |
uv_buf_t* bufs = &buf; |
|
238 |
688333 |
size_t count = 1; |
|
239 |
688333 |
const int err = DoTryWrite(&bufs, &count); |
|
240 |
// Keep track of the bytes written here, because we're taking a shortcut |
||
241 |
// by using `DoTryWrite()` directly instead of using the utilities |
||
242 |
// provided by `Write()`. |
||
243 |
✓✓✓✗ ✓✓✓✓ |
688333 |
synchronously_written = count == 0 ? data_size : data_size - buf.len; |
244 |
688333 |
bytes_written_ += synchronously_written; |
|
245 |
|||
246 |
// Immediate failure or success |
||
247 |
✓✗✓✓ ✓✗✗✓ ✓✓✓✓ ✓✗✓✓ |
688333 |
if (err != 0 || count == 0) { |
248 |
686541 |
SetWriteResult(StreamWriteResult { false, err, nullptr, data_size }); |
|
249 |
686541 |
return err; |
|
250 |
} |
||
251 |
|||
252 |
// Partial write |
||
253 |
✗✓✗✓ ✗✓✗✓ |
1792 |
CHECK_EQ(count, 1); |
254 |
} |
||
255 |
|||
256 |
2947 |
AllocatedBuffer data; |
|
257 |
|||
258 |
✓✓✓✗ ✓✓✓✗ |
2947 |
if (try_write) { |
259 |
// Copy partial data |
||
260 |
1792 |
data = env->AllocateManaged(buf.len); |
|
261 |
1792 |
memcpy(data.data(), buf.base, buf.len); |
|
262 |
1792 |
data_size = buf.len; |
|
263 |
} else { |
||
264 |
// Write it |
||
265 |
1155 |
data = env->AllocateManaged(storage_size); |
|
266 |
1155 |
data_size = StringBytes::Write(env->isolate(), |
|
267 |
data.data(), |
||
268 |
storage_size, |
||
269 |
string, |
||
270 |
2310 |
enc); |
|
271 |
} |
||
272 |
|||
273 |
✗✓✗✓ ✗✓✗✓ |
2947 |
CHECK_LE(data_size, storage_size); |
274 |
|||
275 |
2947 |
buf = uv_buf_init(data.data(), data_size); |
|
276 |
|||
277 |
2947 |
uv_stream_t* send_handle = nullptr; |
|
278 |
|||
279 |
✗✓✗✗ ✗✓✗✓ ✗✗✗✓ ✓✓✓✓ ✓✓✗✓ ✗✗✗✓ |
3051 |
if (IsIPCPipe() && !send_handle_obj.IsEmpty()) { |
280 |
HandleWrap* wrap; |
||
281 |
✗✗✗✗ ✗✓✗✗ |
103 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, send_handle_obj, UV_EINVAL); |
282 |
103 |
send_handle = reinterpret_cast<uv_stream_t*>(wrap->GetHandle()); |
|
283 |
// Reference LibuvStreamWrap instance to prevent it from being garbage |
||
284 |
// collected before `AfterWrite` is called. |
||
285 |
req_wrap_obj->Set(env->context(), |
||
286 |
env->handle_string(), |
||
287 |
412 |
send_handle_obj).Check(); |
|
288 |
} |
||
289 |
|||
290 |
2947 |
StreamWriteResult res = Write(&buf, 1, send_handle, req_wrap_obj); |
|
291 |
2947 |
res.bytes += synchronously_written; |
|
292 |
|||
293 |
2947 |
SetWriteResult(res); |
|
294 |
✓✓✓✗ ✓✓✓✗ |
2947 |
if (res.wrap != nullptr) { |
295 |
2922 |
res.wrap->SetAllocatedStorage(std::move(data)); |
|
296 |
} |
||
297 |
|||
298 |
2947 |
return res.err; |
|
299 |
} |
||
300 |
|||
301 |
|||
302 |
381035 |
MaybeLocal<Value> StreamBase::CallJSOnreadMethod(ssize_t nread, |
|
303 |
Local<ArrayBuffer> ab, |
||
304 |
size_t offset, |
||
305 |
StreamBaseJSChecks checks) { |
||
306 |
381035 |
Environment* env = env_; |
|
307 |
|||
308 |
DCHECK_EQ(static_cast<int32_t>(nread), nread); |
||
309 |
DCHECK_LE(offset, INT32_MAX); |
||
310 |
|||
311 |
✓✓ | 381035 |
if (checks == DONT_SKIP_NREAD_CHECKS) { |
312 |
381009 |
if (ab.IsEmpty()) { |
|
313 |
DCHECK_EQ(offset, 0); |
||
314 |
DCHECK_LE(nread, 0); |
||
315 |
} else { |
||
316 |
DCHECK_GE(nread, 0); |
||
317 |
} |
||
318 |
} |
||
319 |
|||
320 |
381035 |
env->stream_base_state()[kReadBytesOrError] = nread; |
|
321 |
381035 |
env->stream_base_state()[kArrayBufferOffset] = offset; |
|
322 |
|||
323 |
Local<Value> argv[] = { |
||
324 |
✓✓ | 906478 |
ab.IsEmpty() ? Undefined(env->isolate()).As<Value>() : ab.As<Value>() |
325 |
✓✓ | 1905175 |
}; |
326 |
|||
327 |
381035 |
AsyncWrap* wrap = GetAsyncWrap(); |
|
328 |
✗✓ | 381035 |
CHECK_NOT_NULL(wrap); |
329 |
1143105 |
Local<Value> onread = wrap->object()->GetInternalField(kOnReadFunctionField); |
|
330 |
✗✓ | 381035 |
CHECK(onread->IsFunction()); |
331 |
762070 |
return wrap->MakeCallback(onread.As<Function>(), arraysize(argv), argv); |
|
332 |
} |
||
333 |
|||
334 |
|||
335 |
3277 |
bool StreamBase::IsIPCPipe() { |
|
336 |
3277 |
return false; |
|
337 |
} |
||
338 |
|||
339 |
|||
340 |
int StreamBase::GetFD() { |
||
341 |
return -1; |
||
342 |
} |
||
343 |
|||
344 |
|||
345 |
74384 |
Local<Object> StreamBase::GetObject() { |
|
346 |
74384 |
return GetAsyncWrap()->object(); |
|
347 |
} |
||
348 |
|||
349 |
44944 |
void StreamBase::AddMethod(Environment* env, |
|
350 |
Local<Signature> signature, |
||
351 |
enum PropertyAttribute attributes, |
||
352 |
Local<FunctionTemplate> t, |
||
353 |
JSMethodFunction* stream_method, |
||
354 |
Local<String> string) { |
||
355 |
Local<FunctionTemplate> templ = |
||
356 |
env->NewFunctionTemplate(stream_method, |
||
357 |
signature, |
||
358 |
v8::ConstructorBehavior::kThrow, |
||
359 |
44944 |
v8::SideEffectType::kHasNoSideEffect); |
|
360 |
134832 |
t->PrototypeTemplate()->SetAccessorProperty( |
|
361 |
89888 |
string, templ, Local<FunctionTemplate>(), attributes); |
|
362 |
44944 |
} |
|
363 |
|||
364 |
11236 |
void StreamBase::AddMethods(Environment* env, Local<FunctionTemplate> t) { |
|
365 |
11236 |
HandleScope scope(env->isolate()); |
|
366 |
|||
367 |
enum PropertyAttribute attributes = |
||
368 |
11236 |
static_cast<PropertyAttribute>(ReadOnly | DontDelete | DontEnum); |
|
369 |
11236 |
Local<Signature> sig = Signature::New(env->isolate(), t); |
|
370 |
|||
371 |
11236 |
AddMethod(env, sig, attributes, t, GetFD, env->fd_string()); |
|
372 |
AddMethod( |
||
373 |
11236 |
env, sig, attributes, t, GetExternal, env->external_stream_string()); |
|
374 |
11236 |
AddMethod(env, sig, attributes, t, GetBytesRead, env->bytes_read_string()); |
|
375 |
AddMethod( |
||
376 |
11236 |
env, sig, attributes, t, GetBytesWritten, env->bytes_written_string()); |
|
377 |
11236 |
env->SetProtoMethod(t, "readStart", JSMethod<&StreamBase::ReadStartJS>); |
|
378 |
11236 |
env->SetProtoMethod(t, "readStop", JSMethod<&StreamBase::ReadStopJS>); |
|
379 |
11236 |
env->SetProtoMethod(t, "shutdown", JSMethod<&StreamBase::Shutdown>); |
|
380 |
env->SetProtoMethod(t, |
||
381 |
"useUserBuffer", |
||
382 |
11236 |
JSMethod<&StreamBase::UseUserBuffer>); |
|
383 |
11236 |
env->SetProtoMethod(t, "writev", JSMethod<&StreamBase::Writev>); |
|
384 |
11236 |
env->SetProtoMethod(t, "writeBuffer", JSMethod<&StreamBase::WriteBuffer>); |
|
385 |
env->SetProtoMethod( |
||
386 |
11236 |
t, "writeAsciiString", JSMethod<&StreamBase::WriteString<ASCII>>); |
|
387 |
env->SetProtoMethod( |
||
388 |
11236 |
t, "writeUtf8String", JSMethod<&StreamBase::WriteString<UTF8>>); |
|
389 |
env->SetProtoMethod( |
||
390 |
11236 |
t, "writeUcs2String", JSMethod<&StreamBase::WriteString<UCS2>>); |
|
391 |
env->SetProtoMethod( |
||
392 |
11236 |
t, "writeLatin1String", JSMethod<&StreamBase::WriteString<LATIN1>>); |
|
393 |
33708 |
t->PrototypeTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), |
|
394 |
"isStreamBase"), |
||
395 |
44944 |
True(env->isolate())); |
|
396 |
11236 |
t->PrototypeTemplate()->SetAccessor( |
|
397 |
FIXED_ONE_BYTE_STRING(env->isolate(), "onread"), |
||
398 |
BaseObject::InternalFieldGet<kOnReadFunctionField>, |
||
399 |
33708 |
BaseObject::InternalFieldSet<kOnReadFunctionField, &Value::IsFunction>); |
|
400 |
11236 |
} |
|
401 |
|||
402 |
195 |
void StreamBase::GetFD(const FunctionCallbackInfo<Value>& args) { |
|
403 |
// Mimic implementation of StreamBase::GetFD() and UDPWrap::GetFD(). |
||
404 |
390 |
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>()); |
|
405 |
✗✓ | 195 |
if (wrap == nullptr) return args.GetReturnValue().Set(UV_EINVAL); |
406 |
|||
407 |
✗✓ | 195 |
if (!wrap->IsAlive()) return args.GetReturnValue().Set(UV_EINVAL); |
408 |
|||
409 |
585 |
args.GetReturnValue().Set(wrap->GetFD()); |
|
410 |
} |
||
411 |
|||
412 |
63178 |
void StreamBase::GetBytesRead(const FunctionCallbackInfo<Value>& args) { |
|
413 |
126356 |
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>()); |
|
414 |
✓✓ | 126358 |
if (wrap == nullptr) return args.GetReturnValue().Set(0); |
415 |
|||
416 |
// uint64_t -> double. 53bits is enough for all real cases. |
||
417 |
189531 |
args.GetReturnValue().Set(static_cast<double>(wrap->bytes_read_)); |
|
418 |
} |
||
419 |
|||
420 |
63178 |
void StreamBase::GetBytesWritten(const FunctionCallbackInfo<Value>& args) { |
|
421 |
126356 |
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>()); |
|
422 |
✗✓ | 126356 |
if (wrap == nullptr) return args.GetReturnValue().Set(0); |
423 |
|||
424 |
// uint64_t -> double. 53bits is enough for all real cases. |
||
425 |
189534 |
args.GetReturnValue().Set(static_cast<double>(wrap->bytes_written_)); |
|
426 |
} |
||
427 |
|||
428 |
2 |
void StreamBase::GetExternal(const FunctionCallbackInfo<Value>& args) { |
|
429 |
4 |
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>()); |
|
430 |
✗✓ | 4 |
if (wrap == nullptr) return; |
431 |
|||
432 |
2 |
Local<External> ext = External::New(args.GetIsolate(), wrap); |
|
433 |
4 |
args.GetReturnValue().Set(ext); |
|
434 |
} |
||
435 |
|||
436 |
template <int (StreamBase::*Method)(const FunctionCallbackInfo<Value>& args)> |
||
437 |
987198 |
void StreamBase::JSMethod(const FunctionCallbackInfo<Value>& args) { |
|
438 |
1974396 |
StreamBase* wrap = StreamBase::FromObject(args.Holder().As<Object>()); |
|
439 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
987199 |
if (wrap == nullptr) return; |
440 |
|||
441 |
✗✓✗✓ ✓✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
987200 |
if (!wrap->IsAlive()) return args.GetReturnValue().Set(UV_EINVAL); |
442 |
|||
443 |
987197 |
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(wrap->GetAsyncWrap()); |
|
444 |
2961591 |
args.GetReturnValue().Set((wrap->*Method)(args)); |
|
445 |
} |
||
446 |
|||
447 |
7667 |
int StreamResource::DoTryWrite(uv_buf_t** bufs, size_t* count) { |
|
448 |
// No TryWrite by default |
||
449 |
7667 |
return 0; |
|
450 |
} |
||
451 |
|||
452 |
|||
453 |
96894 |
const char* StreamResource::Error() const { |
|
454 |
96894 |
return nullptr; |
|
455 |
} |
||
456 |
|||
457 |
|||
458 |
void StreamResource::ClearError() { |
||
459 |
// No-op |
||
460 |
} |
||
461 |
|||
462 |
|||
463 |
325727 |
uv_buf_t EmitToJSStreamListener::OnStreamAlloc(size_t suggested_size) { |
|
464 |
✗✓ | 325727 |
CHECK_NOT_NULL(stream_); |
465 |
325727 |
Environment* env = static_cast<StreamBase*>(stream_)->stream_env(); |
|
466 |
325727 |
return env->AllocateManaged(suggested_size).release(); |
|
467 |
} |
||
468 |
|||
469 |
368347 |
void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { |
|
470 |
✗✓ | 368347 |
CHECK_NOT_NULL(stream_); |
471 |
368347 |
StreamBase* stream = static_cast<StreamBase*>(stream_); |
|
472 |
368347 |
Environment* env = stream->stream_env(); |
|
473 |
368347 |
HandleScope handle_scope(env->isolate()); |
|
474 |
✓✓ | 688519 |
Context::Scope context_scope(env->context()); |
475 |
688519 |
AllocatedBuffer buf(env, buf_); |
|
476 |
|||
477 |
✓✓ | 368347 |
if (nread <= 0) { |
478 |
✓✓ | 48129 |
if (nread < 0) |
479 |
48110 |
stream->CallJSOnreadMethod(nread, Local<ArrayBuffer>()); |
|
480 |
416372 |
return; |
|
481 |
} |
||
482 |
|||
483 |
✗✓ | 320218 |
CHECK_LE(static_cast<size_t>(nread), buf.size()); |
484 |
320218 |
buf.Resize(nread); |
|
485 |
|||
486 |
✓✓ | 640390 |
stream->CallJSOnreadMethod(nread, buf.ToArrayBuffer()); |
487 |
} |
||
488 |
|||
489 |
|||
490 |
26 |
uv_buf_t CustomBufferJSListener::OnStreamAlloc(size_t suggested_size) { |
|
491 |
26 |
return buffer_; |
|
492 |
} |
||
493 |
|||
494 |
|||
495 |
26 |
void CustomBufferJSListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf) { |
|
496 |
✗✓ | 26 |
CHECK_NOT_NULL(stream_); |
497 |
✗✓ | 26 |
CHECK_EQ(buf.base, buffer_.base); |
498 |
|||
499 |
26 |
StreamBase* stream = static_cast<StreamBase*>(stream_); |
|
500 |
26 |
Environment* env = stream->stream_env(); |
|
501 |
26 |
HandleScope handle_scope(env->isolate()); |
|
502 |
26 |
Context::Scope context_scope(env->context()); |
|
503 |
|||
504 |
MaybeLocal<Value> ret = stream->CallJSOnreadMethod(nread, |
||
505 |
Local<ArrayBuffer>(), |
||
506 |
0, |
||
507 |
26 |
StreamBase::SKIP_NREAD_CHECKS); |
|
508 |
Local<Value> next_buf_v; |
||
509 |
✓✗✓✓ ✓✓ |
78 |
if (ret.ToLocal(&next_buf_v) && !next_buf_v->IsUndefined()) { |
510 |
12 |
buffer_.base = Buffer::Data(next_buf_v); |
|
511 |
12 |
buffer_.len = Buffer::Length(next_buf_v); |
|
512 |
26 |
} |
|
513 |
26 |
} |
|
514 |
|||
515 |
|||
516 |
37619 |
void ReportWritesToJSStreamListener::OnStreamAfterReqFinished( |
|
517 |
StreamReq* req_wrap, int status) { |
||
518 |
37619 |
StreamBase* stream = static_cast<StreamBase*>(stream_); |
|
519 |
37619 |
Environment* env = stream->stream_env(); |
|
520 |
37619 |
AsyncWrap* async_wrap = req_wrap->GetAsyncWrap(); |
|
521 |
37619 |
HandleScope handle_scope(env->isolate()); |
|
522 |
37619 |
Context::Scope context_scope(env->context()); |
|
523 |
✗✓ | 75238 |
CHECK(!async_wrap->persistent().IsEmpty()); |
524 |
37619 |
Local<Object> req_wrap_obj = async_wrap->object(); |
|
525 |
|||
526 |
Local<Value> argv[] = { |
||
527 |
Integer::New(env->isolate(), status), |
||
528 |
37619 |
stream->GetObject(), |
|
529 |
Undefined(env->isolate()) |
||
530 |
188095 |
}; |
|
531 |
|||
532 |
37619 |
const char* msg = stream->Error(); |
|
533 |
✗✓ | 37619 |
if (msg != nullptr) { |
534 |
argv[2] = OneByteString(env->isolate(), msg); |
||
535 |
stream->ClearError(); |
||
536 |
} |
||
537 |
|||
538 |
✓✓ | 150476 |
if (req_wrap_obj->Has(env->context(), env->oncomplete_string()).FromJust()) |
539 |
75234 |
async_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv); |
|
540 |
37617 |
} |
|
541 |
|||
542 |
4807 |
void ReportWritesToJSStreamListener::OnStreamAfterWrite( |
|
543 |
WriteWrap* req_wrap, int status) { |
||
544 |
4807 |
OnStreamAfterReqFinished(req_wrap, status); |
|
545 |
4805 |
} |
|
546 |
|||
547 |
32812 |
void ReportWritesToJSStreamListener::OnStreamAfterShutdown( |
|
548 |
ShutdownWrap* req_wrap, int status) { |
||
549 |
32812 |
OnStreamAfterReqFinished(req_wrap, status); |
|
550 |
32812 |
} |
|
551 |
|||
552 |
|||
553 |
} // namespace node |
Generated by: GCOVR (Version 3.4) |