Skip to content

Commit da7ee62

Browse files
committed
os: expose guessHandleType
Exposes the internal `guessHandleType` function, which can be used to see if a handle has a specific type, regardless of the OS it is on. This helps out with detecting, for example, if standard input is piped into the process, instead of relying on file system calls. Refs: #57603
1 parent 2fe23af commit da7ee62

File tree

4 files changed

+76
-33
lines changed

4 files changed

+76
-33
lines changed

doc/api/os.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,48 @@ On POSIX systems, the operating system release is determined by calling
509509
available, `GetVersionExW()` will be used. See
510510
<https://en.wikipedia.org/wiki/Uname#Examples> for more information.
511511

512+
## `os.guessHandleType(handle)`
513+
514+
<!-- YAML
515+
added: REPLACEME
516+
-->
517+
518+
* `handle` {integer} The handle number to try and guess the type of.
519+
520+
* Returns: {string}
521+
522+
Returns the type of the handle passed in, or `'INVALID'` if the provided handle
523+
is invalid.
524+
525+
Currently, the following types for a handle can be returned:
526+
527+
<table>
528+
<tr>
529+
<th>Constant</th>
530+
</tr>
531+
<tr>
532+
<td><code>TCP</code></td>
533+
</tr>
534+
<tr>
535+
<td><code>TTY</code></td>
536+
</tr>
537+
<tr>
538+
<td><code>UDP</code></td>
539+
</tr>
540+
<tr>
541+
<td><code>FILE</code></td>
542+
</tr>
543+
<tr>
544+
<td><code>PIPE</code></td>
545+
</tr>
546+
<tr>
547+
<td><code>UNKNOWN</code></td>
548+
</tr>
549+
<tr>
550+
<td><code>INVALID</code></td>
551+
</tr>
552+
</table>
553+
512554
## OS constants
513555

514556
The following constants are exported by `os.constants`.

lib/internal/util.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,8 @@ function getCIDR(address, netmask, family) {
864864
}
865865

866866
const handleTypes = ['TCP', 'TTY', 'UDP', 'FILE', 'PIPE', 'UNKNOWN'];
867+
handleTypes[-1] = 'INVALID';
868+
867869
function guessHandleType(fd) {
868870
const type = _guessHandleType(fd);
869871
return handleTypes[type];

lib/os.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const {
3939
},
4040
hideStackFrames,
4141
} = require('internal/errors');
42-
const { getCIDR } = require('internal/util');
42+
const { getCIDR, guessHandleType: _guessHandleType } = require('internal/util');
4343
const { validateInt32 } = require('internal/validators');
4444

4545
const {
@@ -328,6 +328,7 @@ module.exports = {
328328
uptime: getUptime,
329329
version: getOSVersion,
330330
machine: getMachine,
331+
guessHandleType: _guessHandleType,
331332
};
332333

333334
ObjectDefineProperties(module.exports, {

src/node_util.cc

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ CHAR_TEST(16, IsUnicodeSurrogate, (ch & 0xF800) == 0xD800)
4949
// If a UTF-16 surrogate is a low/trailing one.
5050
CHAR_TEST(16, IsUnicodeSurrogateTrail, (ch & 0x400) != 0)
5151

52-
static void GetOwnNonIndexProperties(
53-
const FunctionCallbackInfo<Value>& args) {
52+
static void GetOwnNonIndexProperties(const FunctionCallbackInfo<Value>& args) {
5453
Environment* env = Environment::GetCurrent(args);
5554
Local<Context> context = env->context();
5655

@@ -62,20 +61,20 @@ static void GetOwnNonIndexProperties(
6261
Local<Array> properties;
6362

6463
PropertyFilter filter =
65-
static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
66-
67-
if (!object->GetPropertyNames(
68-
context, KeyCollectionMode::kOwnOnly,
69-
filter,
70-
IndexFilter::kSkipIndices)
71-
.ToLocal(&properties)) {
64+
static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
65+
66+
if (!object
67+
->GetPropertyNames(context,
68+
KeyCollectionMode::kOwnOnly,
69+
filter,
70+
IndexFilter::kSkipIndices)
71+
.ToLocal(&properties)) {
7272
return;
7373
}
7474
args.GetReturnValue().Set(properties);
7575
}
7676

77-
static void GetConstructorName(
78-
const FunctionCallbackInfo<Value>& args) {
77+
static void GetConstructorName(const FunctionCallbackInfo<Value>& args) {
7978
CHECK(args[0]->IsObject());
8079

8180
Local<Object> object = args[0].As<Object>();
@@ -84,8 +83,7 @@ static void GetConstructorName(
8483
args.GetReturnValue().Set(name);
8584
}
8685

87-
static void GetExternalValue(
88-
const FunctionCallbackInfo<Value>& args) {
86+
static void GetExternalValue(const FunctionCallbackInfo<Value>& args) {
8987
CHECK(args[0]->IsExternal());
9088
Isolate* isolate = args.GetIsolate();
9189
Local<External> external = args[0].As<External>();
@@ -98,15 +96,14 @@ static void GetExternalValue(
9896

9997
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
10098
// Return undefined if it's not a Promise.
101-
if (!args[0]->IsPromise())
102-
return;
99+
if (!args[0]->IsPromise()) return;
103100

104101
auto isolate = args.GetIsolate();
105102

106103
Local<Promise> promise = args[0].As<Promise>();
107104

108105
int state = promise->State();
109-
Local<Value> values[2] = { Integer::New(isolate, state) };
106+
Local<Value> values[2] = {Integer::New(isolate, state)};
110107
size_t number_of_values = 1;
111108
if (state != Promise::PromiseState::kPending)
112109
values[number_of_values++] = promise->Result();
@@ -116,19 +113,15 @@ static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
116113

117114
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
118115
// Return undefined if it's not a proxy.
119-
if (!args[0]->IsProxy())
120-
return;
116+
if (!args[0]->IsProxy()) return;
121117

122118
Local<Proxy> proxy = args[0].As<Proxy>();
123119

124120
// TODO(BridgeAR): Remove the length check as soon as we prohibit access to
125121
// the util binding layer. It's accessed in the wild and `esm` would break in
126122
// case the check is removed.
127123
if (args.Length() == 1 || args[1]->IsTrue()) {
128-
Local<Value> ret[] = {
129-
proxy->GetTarget(),
130-
proxy->GetHandler()
131-
};
124+
Local<Value> ret[] = {proxy->GetTarget(), proxy->GetHandler()};
132125

133126
args.GetReturnValue().Set(
134127
Array::New(args.GetIsolate(), ret, arraysize(ret)));
@@ -164,22 +157,17 @@ static void GetCallerLocation(const FunctionCallbackInfo<Value>& args) {
164157
}
165158

166159
static void PreviewEntries(const FunctionCallbackInfo<Value>& args) {
167-
if (!args[0]->IsObject())
168-
return;
160+
if (!args[0]->IsObject()) return;
169161

170162
Environment* env = Environment::GetCurrent(args);
171163
bool is_key_value;
172164
Local<Array> entries;
173165
if (!args[0].As<Object>()->PreviewEntries(&is_key_value).ToLocal(&entries))
174166
return;
175167
// Fast path for WeakMap and WeakSet.
176-
if (args.Length() == 1)
177-
return args.GetReturnValue().Set(entries);
168+
if (args.Length() == 1) return args.GetReturnValue().Set(entries);
178169

179-
Local<Value> ret[] = {
180-
entries,
181-
Boolean::New(env->isolate(), is_key_value)
182-
};
170+
Local<Value> ret[] = {entries, Boolean::New(env->isolate(), is_key_value)};
183171
return args.GetReturnValue().Set(
184172
Array::New(env->isolate(), ret, arraysize(ret)));
185173
}
@@ -216,15 +204,25 @@ static uint32_t GetUVHandleTypeCode(const uv_handle_type type) {
216204
case UV_UNKNOWN_HANDLE:
217205
return 5;
218206
default:
219-
ABORT();
207+
// For an unhandled handle type, we want to return `UNKNOWN` instead of
208+
// `INVALID` since the type is "known" by UV, just not exposed further to
209+
// JS land
210+
return 5;
220211
}
221212
}
222213

223214
static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
224215
Environment* env = Environment::GetCurrent(args);
216+
225217
int fd;
226218
if (!args[0]->Int32Value(env->context()).To(&fd)) return;
227-
CHECK_GE(fd, 0);
219+
220+
// If the provided file descriptor is not valid, we return `-1`, which in JS
221+
// land will be marked as "INVALID"
222+
if (fd < 0) [[unlikely]] {
223+
args.GetReturnValue().Set(-1);
224+
return;
225+
}
228226

229227
uv_handle_type t = uv_guess_handle(fd);
230228
args.GetReturnValue().Set(GetUVHandleTypeCode(t));

0 commit comments

Comments
 (0)