GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/module_wrap.cc Lines: 411 452 90.9 %
Date: 2019-01-07 12:15:22 Branches: 193 292 66.1 %

Line Branch Exec Source
1
#include <algorithm>
2
#include <limits.h>  // PATH_MAX
3
#include <sys/stat.h>  // S_IFDIR
4
#include "module_wrap.h"
5
6
#include "env.h"
7
#include "node_errors.h"
8
#include "node_url.h"
9
#include "util-inl.h"
10
#include "node_internals.h"
11
#include "node_contextify.h"
12
#include "node_watchdog.h"
13
14
namespace node {
15
namespace loader {
16
17
using errors::TryCatchScope;
18
19
using node::contextify::ContextifyContext;
20
using node::url::URL;
21
using node::url::URL_FLAGS_FAILED;
22
using v8::Array;
23
using v8::Context;
24
using v8::Function;
25
using v8::FunctionCallbackInfo;
26
using v8::FunctionTemplate;
27
using v8::HandleScope;
28
using v8::Integer;
29
using v8::IntegrityLevel;
30
using v8::Isolate;
31
using v8::JSON;
32
using v8::Just;
33
using v8::Local;
34
using v8::Maybe;
35
using v8::MaybeLocal;
36
using v8::Module;
37
using v8::Nothing;
38
using v8::Number;
39
using v8::Object;
40
using v8::PrimitiveArray;
41
using v8::Promise;
42
using v8::ScriptCompiler;
43
using v8::ScriptOrigin;
44
using v8::String;
45
using v8::Undefined;
46
using v8::Value;
47
48
static const char* const EXTENSIONS[] = {".mjs", ".js", ".json", ".node"};
49
50
256
ModuleWrap::ModuleWrap(Environment* env,
51
                       Local<Object> object,
52
                       Local<Module> module,
53
                       Local<String> url) :
54
  BaseObject(env, object),
55
1024
  id_(env->get_next_module_id()) {
56
256
  module_.Reset(env->isolate(), module);
57
256
  url_.Reset(env->isolate(), url);
58
256
  env->id_to_module_map.emplace(id_, this);
59
256
}
60
61
1446
ModuleWrap::~ModuleWrap() {
62
241
  HandleScope scope(env()->isolate());
63
482
  Local<Module> module = module_.Get(env()->isolate());
64
241
  env()->id_to_module_map.erase(id_);
65
241
  auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
66
241
  for (auto it = range.first; it != range.second; ++it) {
67
241
    if (it->second == this) {
68
241
      env()->hash_to_module_map.erase(it);
69
241
      break;
70
    }
71
241
  }
72
482
}
73
74
203
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
75
                                      Local<Module> module) {
76
203
  auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
77
203
  for (auto it = range.first; it != range.second; ++it) {
78
406
    if (it->second->module_ == module) {
79
203
      return it->second;
80
    }
81
  }
82
  return nullptr;
83
}
84
85
9
ModuleWrap* ModuleWrap::GetFromID(Environment* env, uint32_t id) {
86
9
  auto module_wrap_it = env->id_to_module_map.find(id);
87
9
  if (module_wrap_it == env->id_to_module_map.end()) {
88
    return nullptr;
89
  }
90
9
  return module_wrap_it->second;
91
}
92
93
258
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
94
258
  Environment* env = Environment::GetCurrent(args);
95
258
  Isolate* isolate = env->isolate();
96
97
258
  CHECK(args.IsConstructCall());
98
258
  Local<Object> that = args.This();
99
100
258
  const int argc = args.Length();
101
258
  CHECK_GE(argc, 2);
102
103
774
  CHECK(args[0]->IsString());
104
516
  Local<String> source_text = args[0].As<String>();
105
106
774
  CHECK(args[1]->IsString());
107
516
  Local<String> url = args[1].As<String>();
108
109
  Local<Context> context;
110
  Local<Integer> line_offset;
111
  Local<Integer> column_offset;
112
113
258
  if (argc == 5) {
114
    // new ModuleWrap(source, url, context?, lineOffset, columnOffset)
115
165
    if (args[2]->IsUndefined()) {
116
49
      context = that->CreationContext();
117
    } else {
118
12
      CHECK(args[2]->IsObject());
119
      ContextifyContext* sandbox =
120
          ContextifyContext::ContextFromContextifiedSandbox(
121
12
              env, args[2].As<Object>());
122
6
      CHECK_NOT_NULL(sandbox);
123
6
      context = sandbox->context();
124
    }
125
126
110
    CHECK(args[3]->IsNumber());
127
110
    line_offset = args[3].As<Integer>();
128
129
110
    CHECK(args[4]->IsNumber());
130
110
    column_offset = args[4].As<Integer>();
131
  } else {
132
    // new ModuleWrap(source, url)
133
203
    context = that->CreationContext();
134
203
    line_offset = Integer::New(isolate, 0);
135
203
    column_offset = Integer::New(isolate, 0);
136
  }
137
138
258
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
139
514
  TryCatchScope try_catch(env);
140
  Local<Module> module;
141
142
  Local<PrimitiveArray> host_defined_options =
143
258
      PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
144
  host_defined_options->Set(isolate, HostDefinedOptions::kType,
145
516
                            Number::New(isolate, ScriptType::kModule));
146
147
  // compile
148
  {
149
    ScriptOrigin origin(url,
150
                        line_offset,                          // line offset
151
                        column_offset,                        // column offset
152
                        False(isolate),                       // is cross origin
153
                        Local<Integer>(),                     // script id
154
                        Local<Value>(),                       // source map URL
155
                        False(isolate),                       // is opaque (?)
156
                        False(isolate),                       // is WASM
157
                        True(isolate),                        // is ES Module
158
258
                        host_defined_options);
159
    Context::Scope context_scope(context);
160
256
    ScriptCompiler::Source source(source_text, origin);
161
516
    if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
162
2
      CHECK(try_catch.HasCaught());
163
4
      CHECK(!try_catch.Message().IsEmpty());
164
4
      CHECK(!try_catch.Exception().IsEmpty());
165
      AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
166
2
                          ErrorHandlingMode::MODULE_ERROR);
167
2
      try_catch.ReThrow();
168
2
      return;
169
256
    }
170
  }
171
172
1024
  if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
173
    return;
174
  }
175
176
256
  ModuleWrap* obj = new ModuleWrap(env, that, module, url);
177
256
  obj->context_.Reset(isolate, context);
178
179
256
  env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
180
181
  host_defined_options->Set(isolate, HostDefinedOptions::kID,
182
512
                            Number::New(isolate, obj->id()));
183
184
256
  that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
185
768
  args.GetReturnValue().Set(that);
186
}
187
188
351
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
189
351
  Environment* env = Environment::GetCurrent(args);
190
351
  Isolate* isolate = args.GetIsolate();
191
192
351
  CHECK_EQ(args.Length(), 1);
193
702
  CHECK(args[0]->IsFunction());
194
195
351
  Local<Object> that = args.This();
196
197
  ModuleWrap* obj;
198
463
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
199
200
351
  if (obj->linked_)
201
112
    return;
202
239
  obj->linked_ = true;
203
204
478
  Local<Function> resolver_arg = args[0].As<Function>();
205
206
478
  Local<Context> mod_context = obj->context_.Get(isolate);
207
478
  Local<Module> module = obj->module_.Get(isolate);
208
209
  Local<Array> promises = Array::New(isolate,
210
239
                                     module->GetModuleRequestsLength());
211
212
  // call the dependency resolve callbacks
213
744
  for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
214
133
    Local<String> specifier = module->GetModuleRequest(i);
215
133
    Utf8Value specifier_utf8(env->isolate(), specifier);
216
266
    std::string specifier_std(*specifier_utf8, specifier_utf8.length());
217
218
    Local<Value> argv[] = {
219
      specifier
220
266
    };
221
222
    MaybeLocal<Value> maybe_resolve_return_value =
223
133
        resolver_arg->Call(mod_context, that, 1, argv);
224
133
    if (maybe_resolve_return_value.IsEmpty()) {
225
      return;
226
    }
227
    Local<Value> resolve_return_value =
228
133
        maybe_resolve_return_value.ToLocalChecked();
229
133
    if (!resolve_return_value->IsPromise()) {
230
      env->ThrowError("linking error, expected resolver to return a promise");
231
    }
232
133
    Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
233
133
    obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
234
235
399
    promises->Set(mod_context, i, resolve_promise).FromJust();
236
133
  }
237
238
478
  args.GetReturnValue().Set(promises);
239
}
240
241
190
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
242
190
  Environment* env = Environment::GetCurrent(args);
243
190
  Isolate* isolate = args.GetIsolate();
244
  ModuleWrap* obj;
245
193
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
246
380
  Local<Context> context = obj->context_.Get(isolate);
247
380
  Local<Module> module = obj->module_.Get(isolate);
248
190
  TryCatchScope try_catch(env);
249
190
  Maybe<bool> ok = module->InstantiateModule(context, ResolveCallback);
250
251
  // clear resolve cache on instantiate
252
190
  obj->resolve_cache_.clear();
253
254
380
  if (!ok.FromMaybe(false)) {
255
3
    CHECK(try_catch.HasCaught());
256
6
    CHECK(!try_catch.Message().IsEmpty());
257
6
    CHECK(!try_catch.Exception().IsEmpty());
258
    AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
259
3
                        ErrorHandlingMode::MODULE_ERROR);
260
3
    try_catch.ReThrow();
261
3
    return;
262
187
  }
263
}
264
265
83
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
266
83
  Environment* env = Environment::GetCurrent(args);
267
83
  Isolate* isolate = env->isolate();
268
  ModuleWrap* obj;
269
90
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
270
166
  Local<Context> context = obj->context_.Get(isolate);
271
166
  Local<Module> module = obj->module_.Get(isolate);
272
273
  // module.evaluate(timeout, breakOnSigint)
274
83
  CHECK_EQ(args.Length(), 2);
275
276
166
  CHECK(args[0]->IsNumber());
277
332
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
278
279
166
  CHECK(args[1]->IsBoolean());
280
166
  bool break_on_sigint = args[1]->IsTrue();
281
282
83
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
283
158
  TryCatchScope try_catch(env);
284
285
83
  bool timed_out = false;
286
83
  bool received_signal = false;
287
  MaybeLocal<Value> result;
288

83
  if (break_on_sigint && timeout != -1) {
289
    Watchdog wd(isolate, timeout, &timed_out);
290
    SigintWatchdog swd(isolate, &received_signal);
291
    result = module->Evaluate(context);
292
83
  } else if (break_on_sigint) {
293
    SigintWatchdog swd(isolate, &received_signal);
294
    result = module->Evaluate(context);
295
83
  } else if (timeout != -1) {
296
1
    Watchdog wd(isolate, timeout, &timed_out);
297
1
    result = module->Evaluate(context);
298
  } else {
299
82
    result = module->Evaluate(context);
300
  }
301
302
  // Convert the termination exception into a regular exception.
303

82
  if (timed_out || received_signal) {
304
1
    env->isolate()->CancelTerminateExecution();
305
    // It is possible that execution was terminated by another timeout in
306
    // which this timeout is nested, so check whether one of the watchdogs
307
    // from this invocation is responsible for termination.
308
1
    if (timed_out) {
309
1
      THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
310
    } else if (received_signal) {
311
      THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
312
    }
313
  }
314
315
82
  if (try_catch.HasCaught()) {
316
7
    try_catch.ReThrow();
317
7
    return;
318
  }
319
320
225
  args.GetReturnValue().Set(result.ToLocalChecked());
321
}
322
323
179
void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
324
179
  Environment* env = Environment::GetCurrent(args);
325
179
  Isolate* isolate = args.GetIsolate();
326
  ModuleWrap* obj;
327
179
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
328
329
358
  Local<Module> module = obj->module_.Get(isolate);
330
331
179
  switch (module->GetStatus()) {
332
    default:
333
      return env->ThrowError(
334
          "cannot get namespace, Module has not been instantiated");
335
    case v8::Module::Status::kInstantiated:
336
    case v8::Module::Status::kEvaluating:
337
    case v8::Module::Status::kEvaluated:
338
179
      break;
339
  }
340
341
179
  Local<Value> result = module->GetModuleNamespace();
342
358
  args.GetReturnValue().Set(result);
343
}
344
345
104
void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
346
104
  Isolate* isolate = args.GetIsolate();
347
  ModuleWrap* obj;
348
208
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
349
350
208
  Local<Module> module = obj->module_.Get(isolate);
351
352
312
  args.GetReturnValue().Set(module->GetStatus());
353
}
354
355
1
void ModuleWrap::GetStaticDependencySpecifiers(
356
    const FunctionCallbackInfo<Value>& args) {
357
1
  Environment* env = Environment::GetCurrent(args);
358
  ModuleWrap* obj;
359
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
360
361
2
  Local<Module> module = obj->module_.Get(env->isolate());
362
363
1
  int count = module->GetModuleRequestsLength();
364
365
1
  Local<Array> specifiers = Array::New(env->isolate(), count);
366
367
2
  for (int i = 0; i < count; i++)
368
4
    specifiers->Set(env->context(), i, module->GetModuleRequest(i)).FromJust();
369
370
2
  args.GetReturnValue().Set(specifiers);
371
}
372
373
1
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
374
1
  Isolate* isolate = args.GetIsolate();
375
  ModuleWrap* obj;
376
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
377
378
2
  Local<Module> module = obj->module_.Get(isolate);
379
380
3
  args.GetReturnValue().Set(module->GetException());
381
}
382
383
124
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
384
                                               Local<String> specifier,
385
                                               Local<Module> referrer) {
386
124
  Environment* env = Environment::GetCurrent(context);
387
124
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
388
124
  Isolate* isolate = env->isolate();
389
390
124
  ModuleWrap* dependent = GetFromModule(env, referrer);
391
124
  if (dependent == nullptr) {
392
    env->ThrowError("linking error, null dep");
393
    return MaybeLocal<Module>();
394
  }
395
396
124
  Utf8Value specifier_utf8(isolate, specifier);
397
248
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
398
399
124
  if (dependent->resolve_cache_.count(specifier_std) != 1) {
400
    env->ThrowError("linking error, not in local cache");
401
    return MaybeLocal<Module>();
402
  }
403
404
  Local<Promise> resolve_promise =
405
248
      dependent->resolve_cache_[specifier_std].Get(isolate);
406
407
124
  if (resolve_promise->State() != Promise::kFulfilled) {
408
    env->ThrowError("linking error, dependency promises must be resolved on "
409
                    "instantiate");
410
    return MaybeLocal<Module>();
411
  }
412
413
248
  Local<Object> module_object = resolve_promise->Result().As<Object>();
414

248
  if (module_object.IsEmpty() || !module_object->IsObject()) {
415
    env->ThrowError("linking error, expected a valid module object from "
416
                    "resolver");
417
    return MaybeLocal<Module>();
418
  }
419
420
  ModuleWrap* module;
421
124
  ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
422
372
  return module->module_.Get(isolate);
423
}
424
425
namespace {
426
427
// Tests whether a path starts with /, ./ or ../
428
// In WhatWG terminology, the alternative case is called a "bare" specifier
429
// (e.g. in `import "jquery"`).
430
157
inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
431
    const std::string& specifier) {
432
157
  size_t len = specifier.length();
433
157
  if (len == 0)
434
    return false;
435
157
  if (specifier[0] == '/') {
436
48
    return true;
437
109
  } else if (specifier[0] == '.') {
438

107
    if (len == 1 || specifier[1] == '/')
439
61
      return true;
440
46
    if (specifier[1] == '.') {
441

46
      if (len == 2 || specifier[2] == '/')
442
46
        return true;
443
    }
444
  }
445
2
  return false;
446
}
447
448
1
std::string ReadFile(uv_file file) {
449
1
  std::string contents;
450
  uv_fs_t req;
451
  char buffer_memory[4096];
452
1
  uv_buf_t buf = uv_buf_init(buffer_memory, sizeof(buffer_memory));
453
454
  do {
455
    const int r = uv_fs_read(uv_default_loop(),
456
                             &req,
457
                             file,
458
                             &buf,
459
                             1,
460
2
                             contents.length(),  // offset
461
2
                             nullptr);
462
2
    uv_fs_req_cleanup(&req);
463
464
2
    if (r <= 0)
465
1
      break;
466
1
    contents.append(buf.base, r);
467
  } while (true);
468
1
  return contents;
469
}
470
471
enum CheckFileOptions {
472
  LEAVE_OPEN_AFTER_CHECK,
473
  CLOSE_AFTER_CHECK
474
};
475
476
504
Maybe<uv_file> CheckFile(const std::string& path,
477
                         CheckFileOptions opt = CLOSE_AFTER_CHECK) {
478
  uv_fs_t fs_req;
479
504
  if (path.empty()) {
480
2
    return Nothing<uv_file>();
481
  }
482
483
502
  uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr);
484
502
  uv_fs_req_cleanup(&fs_req);
485
486
502
  if (fd < 0) {
487
340
    return Nothing<uv_file>();
488
  }
489
490
162
  uv_fs_fstat(nullptr, &fs_req, fd, nullptr);
491
162
  uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR;
492
162
  uv_fs_req_cleanup(&fs_req);
493
494
162
  if (is_directory) {
495
26
    CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
496
26
    uv_fs_req_cleanup(&fs_req);
497
26
    return Nothing<uv_file>();
498
  }
499
500
136
  if (opt == CLOSE_AFTER_CHECK) {
501
135
    CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
502
135
    uv_fs_req_cleanup(&fs_req);
503
  }
504
505
136
  return Just(fd);
506
}
507
508
using Exists = PackageConfig::Exists;
509
using IsValid = PackageConfig::IsValid;
510
using HasMain = PackageConfig::HasMain;
511
512
46
const PackageConfig& GetPackageConfig(Environment* env,
513
                                      const std::string& path) {
514
46
  auto existing = env->package_json_cache.find(path);
515
46
  if (existing != env->package_json_cache.end()) {
516
1
    return existing->second;
517
  }
518
45
  Maybe<uv_file> check = CheckFile(path, LEAVE_OPEN_AFTER_CHECK);
519
45
  if (check.IsNothing()) {
520
    auto entry = env->package_json_cache.emplace(path,
521
44
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
522
44
    return entry.first->second;
523
  }
524
525
1
  Isolate* isolate = env->isolate();
526
1
  v8::HandleScope handle_scope(isolate);
527
528
2
  std::string pkg_src = ReadFile(check.FromJust());
529
  uv_fs_t fs_req;
530
1
  CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, check.FromJust(), nullptr));
531
1
  uv_fs_req_cleanup(&fs_req);
532
533
  Local<String> src;
534
2
  if (!String::NewFromUtf8(isolate,
535
                           pkg_src.c_str(),
536
                           v8::NewStringType::kNormal,
537
3
                           pkg_src.length()).ToLocal(&src)) {
538
    auto entry = env->package_json_cache.emplace(path,
539
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
540
    return entry.first->second;
541
  }
542
543
  Local<Value> pkg_json_v;
544
  Local<Object> pkg_json;
545
546


5
  if (!JSON::Parse(env->context(), src).ToLocal(&pkg_json_v) ||
547
4
      !pkg_json_v->ToObject(env->context()).ToLocal(&pkg_json)) {
548
    auto entry = env->package_json_cache.emplace(path,
549
        PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "" });
550
    return entry.first->second;
551
  }
552
553
  Local<Value> pkg_main;
554
1
  HasMain has_main = HasMain::No;
555
2
  std::string main_std;
556
4
  if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) {
557
1
    has_main = HasMain::Yes;
558
1
    Utf8Value main_utf8(isolate, pkg_main);
559
1
    main_std.assign(std::string(*main_utf8, main_utf8.length()));
560
  }
561
562
  auto entry = env->package_json_cache.emplace(path,
563
1
      PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std });
564
2
  return entry.first->second;
565
}
566
567
enum ResolveExtensionsOptions {
568
  TRY_EXACT_NAME,
569
  ONLY_VIA_EXTENSIONS
570
};
571
572
template <ResolveExtensionsOptions options>
573
200
Maybe<URL> ResolveExtensions(const URL& search) {
574
  if (options == TRY_EXACT_NAME) {
575
155
    std::string filePath = search.ToFilePath();
576
155
    Maybe<uv_file> check = CheckFile(filePath);
577
155
    if (!check.IsNothing()) {
578
99
      return Just(search);
579
56
    }
580
  }
581
582

367
  for (const char* extension : EXTENSIONS) {
583
301
    URL guess(search.path() + extension, &search);
584
301
    Maybe<uv_file> check = CheckFile(guess.ToFilePath());
585

301
    if (!check.IsNothing()) {
586

35
      return Just(guess);
587
    }
588
  }
589
590
66
  return Nothing<URL>();
591
}
592
593
45
inline Maybe<URL> ResolveIndex(const URL& search) {
594
45
  return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL("index", search));
595
}
596
597
46
Maybe<URL> ResolveMain(Environment* env, const URL& search) {
598
46
  URL pkg("package.json", &search);
599
600
  const PackageConfig& pjson =
601
46
      GetPackageConfig(env, pkg.ToFilePath());
602
  // Note invalid package.json should throw in resolver
603
  // currently we silently ignore which is incorrect
604

47
  if (pjson.exists == Exists::No ||
605
2
      pjson.is_valid == IsValid::No ||
606
1
      pjson.has_main == HasMain::No) {
607
45
    return Nothing<URL>();
608
  }
609
1
  if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) {
610
1
    return Resolve(env, "./" + pjson.main, search, IgnoreMain);
611
  }
612
  return Resolve(env, pjson.main, search, IgnoreMain);
613
}
614
615
1
Maybe<URL> ResolveModule(Environment* env,
616
                         const std::string& specifier,
617
                         const URL& base) {
618
1
  URL parent(".", base);
619
2
  URL dir("");
620
22
  do {
621
11
    dir = parent;
622
    Maybe<URL> check =
623
11
        Resolve(env, "./node_modules/" + specifier, dir, CheckMain);
624
11
    if (!check.IsNothing()) {
625
      const size_t limit = specifier.find('/');
626
      const size_t spec_len =
627
          limit == std::string::npos ? specifier.length() :
628
                                       limit + 1;
629
      std::string chroot =
630
          dir.path() + "node_modules/" + specifier.substr(0, spec_len);
631
      if (check.FromJust().path().substr(0, chroot.length()) != chroot) {
632
        return Nothing<URL>();
633
      }
634
      return check;
635
    } else {
636
      // TODO(bmeck) PREVENT FALLTHROUGH
637
    }
638
11
    parent = URL("..", &dir);
639
22
  } while (parent.path() != dir.path());
640
2
  return Nothing<URL>();
641
}
642
643
46
Maybe<URL> ResolveDirectory(Environment* env,
644
                            const URL& search,
645
                            PackageMainCheck check_pjson_main) {
646
46
  if (check_pjson_main) {
647
46
    Maybe<URL> main = ResolveMain(env, search);
648
46
    if (!main.IsNothing())
649
1
      return main;
650
  }
651
45
  return ResolveIndex(search);
652
}
653
654
}  // anonymous namespace
655
656
159
Maybe<URL> Resolve(Environment* env,
657
                   const std::string& specifier,
658
                   const URL& base,
659
                   PackageMainCheck check_pjson_main) {
660
159
  URL pure_url(specifier);
661
159
  if (!(pure_url.flags() & URL_FLAGS_FAILED)) {
662
    // just check existence, without altering
663
3
    Maybe<uv_file> check = CheckFile(pure_url.ToFilePath());
664
3
    if (check.IsNothing()) {
665
2
      return Nothing<URL>();
666
    }
667
1
    return Just(pure_url);
668
  }
669
156
  if (specifier.length() == 0) {
670
    return Nothing<URL>();
671
  }
672
156
  if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
673
155
    URL resolved(specifier, base);
674
310
    Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
675
155
    if (!file.IsNothing())
676
109
      return file;
677
46
    if (specifier.back() != '/') {
678
46
      resolved = URL(specifier + "/", base);
679
    }
680
201
    return ResolveDirectory(env, resolved, check_pjson_main);
681
  } else {
682
1
    return ResolveModule(env, specifier, base);
683
159
  }
684
}
685
686
147
void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
687
147
  Environment* env = Environment::GetCurrent(args);
688
689
  // module.resolve(specifier, url)
690
147
  CHECK_EQ(args.Length(), 2);
691
692
441
  CHECK(args[0]->IsString());
693
147
  Utf8Value specifier_utf8(env->isolate(), args[0]);
694
282
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
695
696
441
  CHECK(args[1]->IsString());
697
282
  Utf8Value url_utf8(env->isolate(), args[1]);
698
282
  URL url(*url_utf8, url_utf8.length());
699
700
147
  if (url.flags() & URL_FLAGS_FAILED) {
701
    return node::THROW_ERR_INVALID_ARG_TYPE(
702
        env, "second argument is not a URL string");
703
  }
704
705
282
  Maybe<URL> result = node::loader::Resolve(env, specifier_std, url);
706


429
  if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) {
707
12
    std::string msg = "Cannot find module " + specifier_std;
708
12
    return node::THROW_ERR_MISSING_MODULE(env, msg.c_str());
709
  }
710
711
135
  MaybeLocal<Value> obj = result.FromJust().ToObject(env);
712
135
  if (!obj.IsEmpty())
713
405
    args.GetReturnValue().Set(obj.ToLocalChecked());
714
}
715
716
22
static MaybeLocal<Promise> ImportModuleDynamically(
717
    Local<Context> context,
718
    Local<v8::ScriptOrModule> referrer,
719
    Local<String> specifier) {
720
22
  Isolate* iso = context->GetIsolate();
721
22
  Environment* env = Environment::GetCurrent(context);
722
22
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
723
22
  v8::EscapableHandleScope handle_scope(iso);
724
725
  Local<Function> import_callback =
726
22
    env->host_import_module_dynamically_callback();
727
728
22
  Local<PrimitiveArray> options = referrer->GetHostDefinedOptions();
729
22
  if (options->Length() != HostDefinedOptions::kLength) {
730
    Local<Promise::Resolver> resolver =
731
        Promise::Resolver::New(context).ToLocalChecked();
732
    resolver
733
        ->Reject(context,
734
                 v8::Exception::TypeError(FIXED_ONE_BYTE_STRING(
735
                     context->GetIsolate(), "Invalid host defined options")))
736
        .ToChecked();
737
    return handle_scope.Escape(resolver->GetPromise());
738
  }
739
740
  Local<Value> object;
741
742
22
  int type = options->Get(iso, HostDefinedOptions::kType)
743
44
                 .As<Number>()
744
66
                 ->Int32Value(context)
745
44
                 .ToChecked();
746
22
  uint32_t id = options->Get(iso, HostDefinedOptions::kID)
747
44
                    .As<Number>()
748
66
                    ->Uint32Value(context)
749
44
                    .ToChecked();
750
22
  if (type == ScriptType::kScript) {
751
13
    contextify::ContextifyScript* wrap = env->id_to_script_map.find(id)->second;
752
26
    object = wrap->object();
753
9
  } else if (type == ScriptType::kModule) {
754
9
    ModuleWrap* wrap = ModuleWrap::GetFromID(env, id);
755
18
    object = wrap->object();
756
  } else {
757
    UNREACHABLE();
758
  }
759
760
  Local<Value> import_args[] = {
761
    object,
762
    Local<Value>(specifier),
763
44
  };
764
765
  Local<Value> result;
766
44
  if (import_callback->Call(
767
        context,
768
        v8::Undefined(iso),
769
22
        arraysize(import_args),
770
66
        import_args).ToLocal(&result)) {
771
22
    CHECK(result->IsPromise());
772
22
    return handle_scope.Escape(result.As<Promise>());
773
  }
774
775
  return MaybeLocal<Promise>();
776
}
777
778
59
void ModuleWrap::SetImportModuleDynamicallyCallback(
779
    const FunctionCallbackInfo<Value>& args) {
780
59
  Isolate* iso = args.GetIsolate();
781
59
  Environment* env = Environment::GetCurrent(args);
782
59
  HandleScope handle_scope(iso);
783
784
59
  CHECK_EQ(args.Length(), 1);
785
118
  CHECK(args[0]->IsFunction());
786
118
  Local<Function> import_callback = args[0].As<Function>();
787
59
  env->set_host_import_module_dynamically_callback(import_callback);
788
789
59
  iso->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
790
59
}
791
792
79
void ModuleWrap::HostInitializeImportMetaObjectCallback(
793
    Local<Context> context, Local<Module> module, Local<Object> meta) {
794
79
  Environment* env = Environment::GetCurrent(context);
795
79
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
796
79
  ModuleWrap* module_wrap = GetFromModule(env, module);
797
798
79
  if (module_wrap == nullptr) {
799
79
    return;
800
  }
801
802
79
  Local<Object> wrap = module_wrap->object();
803
  Local<Function> callback =
804
79
      env->host_initialize_import_meta_object_callback();
805
237
  Local<Value> args[] = { wrap, meta };
806
237
  callback->Call(context, Undefined(env->isolate()), arraysize(args), args)
807
158
      .ToLocalChecked();
808
}
809
810
59
void ModuleWrap::SetInitializeImportMetaObjectCallback(
811
    const FunctionCallbackInfo<Value>& args) {
812
59
  Environment* env = Environment::GetCurrent(args);
813
59
  Isolate* isolate = env->isolate();
814
815
59
  CHECK_EQ(args.Length(), 1);
816
118
  CHECK(args[0]->IsFunction());
817
118
  Local<Function> import_meta_callback = args[0].As<Function>();
818
59
  env->set_host_initialize_import_meta_object_callback(import_meta_callback);
819
820
  isolate->SetHostInitializeImportMetaObjectCallback(
821
59
      HostInitializeImportMetaObjectCallback);
822
59
}
823
824
3671
void ModuleWrap::Initialize(Local<Object> target,
825
                            Local<Value> unused,
826
                            Local<Context> context,
827
                            void* priv) {
828
3671
  Environment* env = Environment::GetCurrent(context);
829
3671
  Isolate* isolate = env->isolate();
830
831
3671
  Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
832
7342
  tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
833
7342
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
834
835
3671
  env->SetProtoMethod(tpl, "link", Link);
836
3671
  env->SetProtoMethod(tpl, "instantiate", Instantiate);
837
3671
  env->SetProtoMethod(tpl, "evaluate", Evaluate);
838
3671
  env->SetProtoMethodNoSideEffect(tpl, "namespace", Namespace);
839
3671
  env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
840
3671
  env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
841
  env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
842
3671
                                  GetStaticDependencySpecifiers);
843
844
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"),
845
18355
              tpl->GetFunction(context).ToLocalChecked()).FromJust();
846
3671
  env->SetMethod(target, "resolve", Resolve);
847
  env->SetMethod(target,
848
                 "setImportModuleDynamicallyCallback",
849
3671
                 SetImportModuleDynamicallyCallback);
850
  env->SetMethod(target,
851
                 "setInitializeImportMetaObjectCallback",
852
3671
                 SetInitializeImportMetaObjectCallback);
853
854
#define V(name)                                                                \
855
    target->Set(context,                                                       \
856
      FIXED_ONE_BYTE_STRING(env->isolate(), #name),                            \
857
      Integer::New(env->isolate(), Module::Status::name))                      \
858
        .FromJust()
859
14684
    V(kUninstantiated);
860
14684
    V(kInstantiating);
861
14684
    V(kInstantiated);
862
14684
    V(kEvaluating);
863
14684
    V(kEvaluated);
864
14684
    V(kErrored);
865
#undef V
866
3671
}
867
868
}  // namespace loader
869
}  // namespace node
870
871
3596
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
872
                                   node::loader::ModuleWrap::Initialize)