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 node::contextify::ContextifyContext;
18 using node::url::URL;
19 using node::url::URL_FLAGS_FAILED;
20 using v8::Array;
21 using v8::Context;
22 using v8::Function;
23 using v8::FunctionCallbackInfo;
24 using v8::FunctionTemplate;
25 using v8::HandleScope;
26 using v8::Integer;
27 using v8::IntegrityLevel;
28 using v8::Isolate;
29 using v8::JSON;
30 using v8::Just;
31 using v8::Local;
32 using v8::Maybe;
33 using v8::MaybeLocal;
34 using v8::Module;
35 using v8::Nothing;
36 using v8::Number;
37 using v8::Object;
38 using v8::PrimitiveArray;
39 using v8::Promise;
40 using v8::ScriptCompiler;
41 using v8::ScriptOrigin;
42 using v8::String;
43 using v8::TryCatch;
44 using v8::Undefined;
45 using v8::Value;
46 
47 static const char* const EXTENSIONS[] = {".mjs", ".js", ".json", ".node"};
48 
ModuleWrap(Environment * env,Local<Object> object,Local<Module> module,Local<String> url)49 ModuleWrap::ModuleWrap(Environment* env,
50                        Local<Object> object,
51                        Local<Module> module,
52                        Local<String> url) :
53   BaseObject(env, object),
54   id_(env->get_next_module_id()) {
55   module_.Reset(env->isolate(), module);
56   url_.Reset(env->isolate(), url);
57   env->id_to_module_map.emplace(id_, this);
58 }
59 
~ModuleWrap()60 ModuleWrap::~ModuleWrap() {
61   HandleScope scope(env()->isolate());
62   Local<Module> module = module_.Get(env()->isolate());
63   env()->id_to_module_map.erase(id_);
64   auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
65   for (auto it = range.first; it != range.second; ++it) {
66     if (it->second == this) {
67       env()->hash_to_module_map.erase(it);
68       break;
69     }
70   }
71 }
72 
GetFromModule(Environment * env,Local<Module> module)73 ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
74                                       Local<Module> module) {
75   auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
76   for (auto it = range.first; it != range.second; ++it) {
77     if (it->second->module_ == module) {
78       return it->second;
79     }
80   }
81   return nullptr;
82 }
83 
GetFromID(Environment * env,uint32_t id)84 ModuleWrap* ModuleWrap::GetFromID(Environment* env, uint32_t id) {
85   auto module_wrap_it = env->id_to_module_map.find(id);
86   if (module_wrap_it == env->id_to_module_map.end()) {
87     return nullptr;
88   }
89   return module_wrap_it->second;
90 }
91 
New(const FunctionCallbackInfo<Value> & args)92 void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
93   Environment* env = Environment::GetCurrent(args);
94   Isolate* isolate = env->isolate();
95 
96   CHECK(args.IsConstructCall());
97   Local<Object> that = args.This();
98 
99   const int argc = args.Length();
100   CHECK_GE(argc, 2);
101 
102   CHECK(args[0]->IsString());
103   Local<String> source_text = args[0].As<String>();
104 
105   CHECK(args[1]->IsString());
106   Local<String> url = args[1].As<String>();
107 
108   Local<Context> context;
109   Local<Integer> line_offset;
110   Local<Integer> column_offset;
111 
112   if (argc == 5) {
113     // new ModuleWrap(source, url, context?, lineOffset, columnOffset)
114     if (args[2]->IsUndefined()) {
115       context = that->CreationContext();
116     } else {
117       CHECK(args[2]->IsObject());
118       ContextifyContext* sandbox =
119           ContextifyContext::ContextFromContextifiedSandbox(
120               env, args[2].As<Object>());
121       CHECK_NOT_NULL(sandbox);
122       context = sandbox->context();
123     }
124 
125     CHECK(args[3]->IsNumber());
126     line_offset = args[3].As<Integer>();
127 
128     CHECK(args[4]->IsNumber());
129     column_offset = args[4].As<Integer>();
130   } else {
131     // new ModuleWrap(source, url)
132     context = that->CreationContext();
133     line_offset = Integer::New(isolate, 0);
134     column_offset = Integer::New(isolate, 0);
135   }
136 
137   Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
138   TryCatch try_catch(isolate);
139   Local<Module> module;
140 
141   Local<PrimitiveArray> host_defined_options =
142       PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
143   host_defined_options->Set(isolate, HostDefinedOptions::kType,
144                             Number::New(isolate, ScriptType::kModule));
145 
146   // compile
147   {
148     ScriptOrigin origin(url,
149                         line_offset,                          // line offset
150                         column_offset,                        // column offset
151                         False(isolate),                       // is cross origin
152                         Local<Integer>(),                     // script id
153                         Local<Value>(),                       // source map URL
154                         False(isolate),                       // is opaque (?)
155                         False(isolate),                       // is WASM
156                         True(isolate),                        // is ES Module
157                         host_defined_options);
158     Context::Scope context_scope(context);
159     ScriptCompiler::Source source(source_text, origin);
160     if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
161       CHECK(try_catch.HasCaught());
162       CHECK(!try_catch.Message().IsEmpty());
163       CHECK(!try_catch.Exception().IsEmpty());
164       AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
165                           ErrorHandlingMode::MODULE_ERROR);
166       try_catch.ReThrow();
167       return;
168     }
169   }
170 
171   if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
172     return;
173   }
174 
175   ModuleWrap* obj = new ModuleWrap(env, that, module, url);
176   obj->context_.Reset(isolate, context);
177 
178   env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
179 
180   host_defined_options->Set(isolate, HostDefinedOptions::kID,
181                             Number::New(isolate, obj->id()));
182 
183   that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
184   args.GetReturnValue().Set(that);
185 }
186 
Link(const FunctionCallbackInfo<Value> & args)187 void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
188   Environment* env = Environment::GetCurrent(args);
189   Isolate* isolate = args.GetIsolate();
190 
191   CHECK_EQ(args.Length(), 1);
192   CHECK(args[0]->IsFunction());
193 
194   Local<Object> that = args.This();
195 
196   ModuleWrap* obj;
197   ASSIGN_OR_RETURN_UNWRAP(&obj, that);
198 
199   if (obj->linked_)
200     return;
201   obj->linked_ = true;
202 
203   Local<Function> resolver_arg = args[0].As<Function>();
204 
205   Local<Context> mod_context = obj->context_.Get(isolate);
206   Local<Module> module = obj->module_.Get(isolate);
207 
208   Local<Array> promises = Array::New(isolate,
209                                      module->GetModuleRequestsLength());
210 
211   // call the dependency resolve callbacks
212   for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
213     Local<String> specifier = module->GetModuleRequest(i);
214     Utf8Value specifier_utf8(env->isolate(), specifier);
215     std::string specifier_std(*specifier_utf8, specifier_utf8.length());
216 
217     Local<Value> argv[] = {
218       specifier
219     };
220 
221     MaybeLocal<Value> maybe_resolve_return_value =
222         resolver_arg->Call(mod_context, that, 1, argv);
223     if (maybe_resolve_return_value.IsEmpty()) {
224       return;
225     }
226     Local<Value> resolve_return_value =
227         maybe_resolve_return_value.ToLocalChecked();
228     if (!resolve_return_value->IsPromise()) {
229       env->ThrowError("linking error, expected resolver to return a promise");
230     }
231     Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
232     obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
233 
234     promises->Set(mod_context, i, resolve_promise).FromJust();
235   }
236 
237   args.GetReturnValue().Set(promises);
238 }
239 
Instantiate(const FunctionCallbackInfo<Value> & args)240 void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
241   Environment* env = Environment::GetCurrent(args);
242   Isolate* isolate = args.GetIsolate();
243   ModuleWrap* obj;
244   ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
245   Local<Context> context = obj->context_.Get(isolate);
246   Local<Module> module = obj->module_.Get(isolate);
247   TryCatch try_catch(isolate);
248   Maybe<bool> ok = module->InstantiateModule(context, ResolveCallback);
249 
250   // clear resolve cache on instantiate
251   obj->resolve_cache_.clear();
252 
253   if (!ok.FromMaybe(false)) {
254     CHECK(try_catch.HasCaught());
255     CHECK(!try_catch.Message().IsEmpty());
256     CHECK(!try_catch.Exception().IsEmpty());
257     AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
258                         ErrorHandlingMode::MODULE_ERROR);
259     try_catch.ReThrow();
260     return;
261   }
262 }
263 
Evaluate(const FunctionCallbackInfo<Value> & args)264 void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
265   Environment* env = Environment::GetCurrent(args);
266   Isolate* isolate = env->isolate();
267   ModuleWrap* obj;
268   ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
269   Local<Context> context = obj->context_.Get(isolate);
270   Local<Module> module = obj->module_.Get(isolate);
271 
272   // module.evaluate(timeout, breakOnSigint)
273   CHECK_EQ(args.Length(), 2);
274 
275   CHECK(args[0]->IsNumber());
276   int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
277 
278   CHECK(args[1]->IsBoolean());
279   bool break_on_sigint = args[1]->IsTrue();
280 
281   Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
282   TryCatch try_catch(isolate);
283 
284   bool timed_out = false;
285   bool received_signal = false;
286   MaybeLocal<Value> result;
287   if (break_on_sigint && timeout != -1) {
288     Watchdog wd(isolate, timeout, &timed_out);
289     SigintWatchdog swd(isolate, &received_signal);
290     result = module->Evaluate(context);
291   } else if (break_on_sigint) {
292     SigintWatchdog swd(isolate, &received_signal);
293     result = module->Evaluate(context);
294   } else if (timeout != -1) {
295     Watchdog wd(isolate, timeout, &timed_out);
296     result = module->Evaluate(context);
297   } else {
298     result = module->Evaluate(context);
299   }
300 
301   // Convert the termination exception into a regular exception.
302   if (timed_out || received_signal) {
303     env->isolate()->CancelTerminateExecution();
304     // It is possible that execution was terminated by another timeout in
305     // which this timeout is nested, so check whether one of the watchdogs
306     // from this invocation is responsible for termination.
307     if (timed_out) {
308       env->ThrowError("Script execution timed out.");
309     } else if (received_signal) {
310       env->ThrowError("Script execution interrupted.");
311     }
312   }
313 
314   if (try_catch.HasCaught()) {
315     try_catch.ReThrow();
316     return;
317   }
318 
319   args.GetReturnValue().Set(result.ToLocalChecked());
320 }
321 
Namespace(const FunctionCallbackInfo<Value> & args)322 void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
323   Environment* env = Environment::GetCurrent(args);
324   Isolate* isolate = args.GetIsolate();
325   ModuleWrap* obj;
326   ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
327 
328   Local<Module> module = obj->module_.Get(isolate);
329 
330   switch (module->GetStatus()) {
331     default:
332       return env->ThrowError(
333           "cannot get namespace, Module has not been instantiated");
334     case v8::Module::Status::kInstantiated:
335     case v8::Module::Status::kEvaluating:
336     case v8::Module::Status::kEvaluated:
337       break;
338   }
339 
340   Local<Value> result = module->GetModuleNamespace();
341   args.GetReturnValue().Set(result);
342 }
343 
GetStatus(const FunctionCallbackInfo<Value> & args)344 void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
345   Isolate* isolate = args.GetIsolate();
346   ModuleWrap* obj;
347   ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
348 
349   Local<Module> module = obj->module_.Get(isolate);
350 
351   args.GetReturnValue().Set(module->GetStatus());
352 }
353 
GetStaticDependencySpecifiers(const FunctionCallbackInfo<Value> & args)354 void ModuleWrap::GetStaticDependencySpecifiers(
355     const FunctionCallbackInfo<Value>& args) {
356   Environment* env = Environment::GetCurrent(args);
357   ModuleWrap* obj;
358   ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
359 
360   Local<Module> module = obj->module_.Get(env->isolate());
361 
362   int count = module->GetModuleRequestsLength();
363 
364   Local<Array> specifiers = Array::New(env->isolate(), count);
365 
366   for (int i = 0; i < count; i++)
367     specifiers->Set(env->context(), i, module->GetModuleRequest(i)).FromJust();
368 
369   args.GetReturnValue().Set(specifiers);
370 }
371 
GetError(const FunctionCallbackInfo<Value> & args)372 void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
373   Isolate* isolate = args.GetIsolate();
374   ModuleWrap* obj;
375   ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
376 
377   Local<Module> module = obj->module_.Get(isolate);
378 
379   args.GetReturnValue().Set(module->GetException());
380 }
381 
ResolveCallback(Local<Context> context,Local<String> specifier,Local<Module> referrer)382 MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
383                                                Local<String> specifier,
384                                                Local<Module> referrer) {
385   Environment* env = Environment::GetCurrent(context);
386   CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
387   Isolate* isolate = env->isolate();
388 
389   ModuleWrap* dependent = GetFromModule(env, referrer);
390   if (dependent == nullptr) {
391     env->ThrowError("linking error, null dep");
392     return MaybeLocal<Module>();
393   }
394 
395   Utf8Value specifier_utf8(isolate, specifier);
396   std::string specifier_std(*specifier_utf8, specifier_utf8.length());
397 
398   if (dependent->resolve_cache_.count(specifier_std) != 1) {
399     env->ThrowError("linking error, not in local cache");
400     return MaybeLocal<Module>();
401   }
402 
403   Local<Promise> resolve_promise =
404       dependent->resolve_cache_[specifier_std].Get(isolate);
405 
406   if (resolve_promise->State() != Promise::kFulfilled) {
407     env->ThrowError("linking error, dependency promises must be resolved on "
408                     "instantiate");
409     return MaybeLocal<Module>();
410   }
411 
412   Local<Object> module_object = resolve_promise->Result().As<Object>();
413   if (module_object.IsEmpty() || !module_object->IsObject()) {
414     env->ThrowError("linking error, expected a valid module object from "
415                     "resolver");
416     return MaybeLocal<Module>();
417   }
418 
419   ModuleWrap* module;
420   ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
421   return module->module_.Get(isolate);
422 }
423 
424 namespace {
425 
426 // Tests whether a path starts with /, ./ or ../
427 // In WhatWG terminology, the alternative case is called a "bare" specifier
428 // (e.g. in `import "jquery"`).
ShouldBeTreatedAsRelativeOrAbsolutePath(const std::string & specifier)429 inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
430     const std::string& specifier) {
431   size_t len = specifier.length();
432   if (len == 0)
433     return false;
434   if (specifier[0] == '/') {
435     return true;
436   } else if (specifier[0] == '.') {
437     if (len == 1 || specifier[1] == '/')
438       return true;
439     if (specifier[1] == '.') {
440       if (len == 2 || specifier[2] == '/')
441         return true;
442     }
443   }
444   return false;
445 }
446 
ReadFile(uv_file file)447 std::string ReadFile(uv_file file) {
448   std::string contents;
449   uv_fs_t req;
450   char buffer_memory[4096];
451   uv_buf_t buf = uv_buf_init(buffer_memory, sizeof(buffer_memory));
452 
453   do {
454     const int r = uv_fs_read(uv_default_loop(),
455                              &req,
456                              file,
457                              &buf,
458                              1,
459                              contents.length(),  // offset
460                              nullptr);
461     uv_fs_req_cleanup(&req);
462 
463     if (r <= 0)
464       break;
465     contents.append(buf.base, r);
466   } while (true);
467   return contents;
468 }
469 
470 enum CheckFileOptions {
471   LEAVE_OPEN_AFTER_CHECK,
472   CLOSE_AFTER_CHECK
473 };
474 
CheckFile(const std::string & path,CheckFileOptions opt=CLOSE_AFTER_CHECK)475 Maybe<uv_file> CheckFile(const std::string& path,
476                          CheckFileOptions opt = CLOSE_AFTER_CHECK) {
477   uv_fs_t fs_req;
478   if (path.empty()) {
479     return Nothing<uv_file>();
480   }
481 
482   uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr);
483   uv_fs_req_cleanup(&fs_req);
484 
485   if (fd < 0) {
486     return Nothing<uv_file>();
487   }
488 
489   uv_fs_fstat(nullptr, &fs_req, fd, nullptr);
490   uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR;
491   uv_fs_req_cleanup(&fs_req);
492 
493   if (is_directory) {
494     CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
495     uv_fs_req_cleanup(&fs_req);
496     return Nothing<uv_file>();
497   }
498 
499   if (opt == CLOSE_AFTER_CHECK) {
500     CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
501     uv_fs_req_cleanup(&fs_req);
502   }
503 
504   return Just(fd);
505 }
506 
507 using Exists = PackageConfig::Exists;
508 using IsValid = PackageConfig::IsValid;
509 using HasMain = PackageConfig::HasMain;
510 
GetPackageConfig(Environment * env,const std::string & path)511 const PackageConfig& GetPackageConfig(Environment* env,
512                                       const std::string& path) {
513   auto existing = env->package_json_cache.find(path);
514   if (existing != env->package_json_cache.end()) {
515     return existing->second;
516   }
517   Maybe<uv_file> check = CheckFile(path, LEAVE_OPEN_AFTER_CHECK);
518   if (check.IsNothing()) {
519     auto entry = env->package_json_cache.emplace(path,
520         PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
521     return entry.first->second;
522   }
523 
524   Isolate* isolate = env->isolate();
525   v8::HandleScope handle_scope(isolate);
526 
527   std::string pkg_src = ReadFile(check.FromJust());
528   uv_fs_t fs_req;
529   CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, check.FromJust(), nullptr));
530   uv_fs_req_cleanup(&fs_req);
531 
532   Local<String> src;
533   if (!String::NewFromUtf8(isolate,
534                            pkg_src.c_str(),
535                            v8::NewStringType::kNormal,
536                            pkg_src.length()).ToLocal(&src)) {
537     auto entry = env->package_json_cache.emplace(path,
538         PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
539     return entry.first->second;
540   }
541 
542   Local<Value> pkg_json_v;
543   Local<Object> pkg_json;
544 
545   if (!JSON::Parse(env->context(), src).ToLocal(&pkg_json_v) ||
546       !pkg_json_v->ToObject(env->context()).ToLocal(&pkg_json)) {
547     auto entry = env->package_json_cache.emplace(path,
548         PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "" });
549     return entry.first->second;
550   }
551 
552   Local<Value> pkg_main;
553   HasMain has_main = HasMain::No;
554   std::string main_std;
555   if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) {
556     has_main = HasMain::Yes;
557     Utf8Value main_utf8(isolate, pkg_main);
558     main_std.assign(std::string(*main_utf8, main_utf8.length()));
559   }
560 
561   auto entry = env->package_json_cache.emplace(path,
562       PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std });
563   return entry.first->second;
564 }
565 
566 enum ResolveExtensionsOptions {
567   TRY_EXACT_NAME,
568   ONLY_VIA_EXTENSIONS
569 };
570 
571 template <ResolveExtensionsOptions options>
ResolveExtensions(const URL & search)572 Maybe<URL> ResolveExtensions(const URL& search) {
573   if (options == TRY_EXACT_NAME) {
574     std::string filePath = search.ToFilePath();
575     Maybe<uv_file> check = CheckFile(filePath);
576     if (!check.IsNothing()) {
577       return Just(search);
578     }
579   }
580 
581   for (const char* extension : EXTENSIONS) {
582     URL guess(search.path() + extension, &search);
583     Maybe<uv_file> check = CheckFile(guess.ToFilePath());
584     if (!check.IsNothing()) {
585       return Just(guess);
586     }
587   }
588 
589   return Nothing<URL>();
590 }
591 
ResolveIndex(const URL & search)592 inline Maybe<URL> ResolveIndex(const URL& search) {
593   return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL("index", search));
594 }
595 
ResolveMain(Environment * env,const URL & search)596 Maybe<URL> ResolveMain(Environment* env, const URL& search) {
597   URL pkg("package.json", &search);
598 
599   const PackageConfig& pjson =
600       GetPackageConfig(env, pkg.ToFilePath());
601   // Note invalid package.json should throw in resolver
602   // currently we silently ignore which is incorrect
603   if (pjson.exists == Exists::No ||
604       pjson.is_valid == IsValid::No ||
605       pjson.has_main == HasMain::No) {
606     return Nothing<URL>();
607   }
608   if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) {
609     return Resolve(env, "./" + pjson.main, search, IgnoreMain);
610   }
611   return Resolve(env, pjson.main, search, IgnoreMain);
612 }
613 
ResolveModule(Environment * env,const std::string & specifier,const URL & base)614 Maybe<URL> ResolveModule(Environment* env,
615                          const std::string& specifier,
616                          const URL& base) {
617   URL parent(".", base);
618   URL dir("");
619   do {
620     dir = parent;
621     Maybe<URL> check =
622         Resolve(env, "./node_modules/" + specifier, dir, CheckMain);
623     if (!check.IsNothing()) {
624       const size_t limit = specifier.find('/');
625       const size_t spec_len =
626           limit == std::string::npos ? specifier.length() :
627                                        limit + 1;
628       std::string chroot =
629           dir.path() + "node_modules/" + specifier.substr(0, spec_len);
630       if (check.FromJust().path().substr(0, chroot.length()) != chroot) {
631         return Nothing<URL>();
632       }
633       return check;
634     } else {
635       // TODO(bmeck) PREVENT FALLTHROUGH
636     }
637     parent = URL("..", &dir);
638   } while (parent.path() != dir.path());
639   return Nothing<URL>();
640 }
641 
ResolveDirectory(Environment * env,const URL & search,PackageMainCheck check_pjson_main)642 Maybe<URL> ResolveDirectory(Environment* env,
643                             const URL& search,
644                             PackageMainCheck check_pjson_main) {
645   if (check_pjson_main) {
646     Maybe<URL> main = ResolveMain(env, search);
647     if (!main.IsNothing())
648       return main;
649   }
650   return ResolveIndex(search);
651 }
652 
653 }  // anonymous namespace
654 
Resolve(Environment * env,const std::string & specifier,const URL & base,PackageMainCheck check_pjson_main)655 Maybe<URL> Resolve(Environment* env,
656                    const std::string& specifier,
657                    const URL& base,
658                    PackageMainCheck check_pjson_main) {
659   URL pure_url(specifier);
660   if (!(pure_url.flags() & URL_FLAGS_FAILED)) {
661     // just check existence, without altering
662     Maybe<uv_file> check = CheckFile(pure_url.ToFilePath());
663     if (check.IsNothing()) {
664       return Nothing<URL>();
665     }
666     return Just(pure_url);
667   }
668   if (specifier.length() == 0) {
669     return Nothing<URL>();
670   }
671   if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
672     URL resolved(specifier, base);
673     Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
674     if (!file.IsNothing())
675       return file;
676     if (specifier.back() != '/') {
677       resolved = URL(specifier + "/", base);
678     }
679     return ResolveDirectory(env, resolved, check_pjson_main);
680   } else {
681     return ResolveModule(env, specifier, base);
682   }
683 }
684 
Resolve(const FunctionCallbackInfo<Value> & args)685 void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
686   Environment* env = Environment::GetCurrent(args);
687 
688   // module.resolve(specifier, url)
689   CHECK_EQ(args.Length(), 2);
690 
691   CHECK(args[0]->IsString());
692   Utf8Value specifier_utf8(env->isolate(), args[0]);
693   std::string specifier_std(*specifier_utf8, specifier_utf8.length());
694 
695   CHECK(args[1]->IsString());
696   Utf8Value url_utf8(env->isolate(), args[1]);
697   URL url(*url_utf8, url_utf8.length());
698 
699   if (url.flags() & URL_FLAGS_FAILED) {
700     return node::THROW_ERR_INVALID_ARG_TYPE(
701         env, "second argument is not a URL string");
702   }
703 
704   Maybe<URL> result = node::loader::Resolve(env, specifier_std, url);
705   if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) {
706     std::string msg = "Cannot find module " + specifier_std;
707     return node::THROW_ERR_MISSING_MODULE(env, msg.c_str());
708   }
709 
710   args.GetReturnValue().Set(result.FromJust().ToObject(env));
711 }
712 
ImportModuleDynamically(Local<Context> context,Local<v8::ScriptOrModule> referrer,Local<String> specifier)713 static MaybeLocal<Promise> ImportModuleDynamically(
714     Local<Context> context,
715     Local<v8::ScriptOrModule> referrer,
716     Local<String> specifier) {
717   Isolate* iso = context->GetIsolate();
718   Environment* env = Environment::GetCurrent(context);
719   CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
720   v8::EscapableHandleScope handle_scope(iso);
721 
722   Local<Function> import_callback =
723     env->host_import_module_dynamically_callback();
724 
725   Local<PrimitiveArray> options = referrer->GetHostDefinedOptions();
726   if (options->Length() != HostDefinedOptions::kLength) {
727     Local<Promise::Resolver> resolver =
728         Promise::Resolver::New(context).ToLocalChecked();
729     resolver
730         ->Reject(context,
731                  v8::Exception::TypeError(FIXED_ONE_BYTE_STRING(
732                      context->GetIsolate(), "Invalid host defined options")))
733         .ToChecked();
734     return handle_scope.Escape(resolver->GetPromise());
735   }
736 
737   Local<Value> object;
738 
739   int type = options->Get(iso, HostDefinedOptions::kType)
740                  .As<Number>()
741                  ->Int32Value(context)
742                  .ToChecked();
743   uint32_t id = options->Get(iso, HostDefinedOptions::kID)
744                     .As<Number>()
745                     ->Uint32Value(context)
746                     .ToChecked();
747   if (type == ScriptType::kScript) {
748     contextify::ContextifyScript* wrap = env->id_to_script_map.find(id)->second;
749     object = wrap->object();
750   } else if (type == ScriptType::kModule) {
751     ModuleWrap* wrap = ModuleWrap::GetFromID(env, id);
752     object = wrap->object();
753   } else if (type == ScriptType::kFunction) {
754     object = env->id_to_function_map.find(id)->second.Get(iso);
755   } else {
756     UNREACHABLE();
757   }
758 
759   Local<Value> import_args[] = {
760     object,
761     Local<Value>(specifier),
762   };
763 
764   Local<Value> result;
765   if (import_callback->Call(
766         context,
767         v8::Undefined(iso),
768         arraysize(import_args),
769         import_args).ToLocal(&result)) {
770     CHECK(result->IsPromise());
771     return handle_scope.Escape(result.As<Promise>());
772   }
773 
774   return MaybeLocal<Promise>();
775 }
776 
SetImportModuleDynamicallyCallback(const FunctionCallbackInfo<Value> & args)777 void ModuleWrap::SetImportModuleDynamicallyCallback(
778     const FunctionCallbackInfo<Value>& args) {
779   Isolate* iso = args.GetIsolate();
780   Environment* env = Environment::GetCurrent(args);
781   HandleScope handle_scope(iso);
782 
783   CHECK_EQ(args.Length(), 1);
784   CHECK(args[0]->IsFunction());
785   Local<Function> import_callback = args[0].As<Function>();
786   env->set_host_import_module_dynamically_callback(import_callback);
787 
788   iso->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
789 }
790 
HostInitializeImportMetaObjectCallback(Local<Context> context,Local<Module> module,Local<Object> meta)791 void ModuleWrap::HostInitializeImportMetaObjectCallback(
792     Local<Context> context, Local<Module> module, Local<Object> meta) {
793   Environment* env = Environment::GetCurrent(context);
794   CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
795   ModuleWrap* module_wrap = GetFromModule(env, module);
796 
797   if (module_wrap == nullptr) {
798     return;
799   }
800 
801   Local<Object> wrap = module_wrap->object();
802   Local<Function> callback =
803       env->host_initialize_import_meta_object_callback();
804   Local<Value> args[] = { wrap, meta };
805   callback->Call(context, Undefined(env->isolate()), arraysize(args), args)
806       .ToLocalChecked();
807 }
808 
SetInitializeImportMetaObjectCallback(const FunctionCallbackInfo<Value> & args)809 void ModuleWrap::SetInitializeImportMetaObjectCallback(
810     const FunctionCallbackInfo<Value>& args) {
811   Environment* env = Environment::GetCurrent(args);
812   Isolate* isolate = env->isolate();
813 
814   CHECK_EQ(args.Length(), 1);
815   CHECK(args[0]->IsFunction());
816   Local<Function> import_meta_callback = args[0].As<Function>();
817   env->set_host_initialize_import_meta_object_callback(import_meta_callback);
818 
819   isolate->SetHostInitializeImportMetaObjectCallback(
820       HostInitializeImportMetaObjectCallback);
821 }
822 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context)823 void ModuleWrap::Initialize(Local<Object> target,
824                             Local<Value> unused,
825                             Local<Context> context) {
826   Environment* env = Environment::GetCurrent(context);
827   Isolate* isolate = env->isolate();
828 
829   Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
830   tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
831   tpl->InstanceTemplate()->SetInternalFieldCount(1);
832 
833   env->SetProtoMethod(tpl, "link", Link);
834   env->SetProtoMethod(tpl, "instantiate", Instantiate);
835   env->SetProtoMethod(tpl, "evaluate", Evaluate);
836   env->SetProtoMethodNoSideEffect(tpl, "namespace", Namespace);
837   env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
838   env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
839   env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
840                                   GetStaticDependencySpecifiers);
841 
842   target->Set(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"),
843               tpl->GetFunction(context).ToLocalChecked());
844   env->SetMethod(target, "resolve", Resolve);
845   env->SetMethod(target,
846                  "setImportModuleDynamicallyCallback",
847                  SetImportModuleDynamicallyCallback);
848   env->SetMethod(target,
849                  "setInitializeImportMetaObjectCallback",
850                  SetInitializeImportMetaObjectCallback);
851 
852 #define V(name)                                                                \
853     target->Set(context,                                                       \
854       FIXED_ONE_BYTE_STRING(env->isolate(), #name),                            \
855       Integer::New(env->isolate(), Module::Status::name))                      \
856         .FromJust()
857     V(kUninstantiated);
858     V(kInstantiating);
859     V(kInstantiated);
860     V(kEvaluating);
861     V(kEvaluated);
862     V(kErrored);
863 #undef V
864 }
865 
866 }  // namespace loader
867 }  // namespace node
868 
869 NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
870                                    node::loader::ModuleWrap::Initialize)
871