github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/v8/lib/require_callback.cc (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see
    17  // <http://www.gnu.org/licenses/>.
    18  //
    19  #include "require_callback.h"
    20  #include "../engine.h"
    21  #include "file.h"
    22  #include "global.h"
    23  #include "logger.h"
    24  
    25  #include <assert.h>
    26  #include <stdio.h>
    27  #include <stdlib.h>
    28  #include <string.h>
    29  #include <unistd.h>
    30  #include <v8.h>
    31  
    32  using namespace v8;
    33  
    34  static char source_require_format[] =
    35      "(function(){\n"
    36      "return function (exports, module, require) {\n"
    37      "%s\n"
    38      "};\n"
    39      "})();\n";
    40  
    41  static RequireDelegate sRequireDelegate = NULL;
    42  static AttachLibVersionDelegate attachLibVersionDelegate = NULL;
    43  
    44  static int readSource(Local<Context> context, const char *filename, char **data,
    45                        size_t *lineOffset) {
    46    if (strstr(filename, "\"") != NULL) {
    47      return -1;
    48    }
    49  
    50    *lineOffset = 0;
    51  
    52    char *content = NULL;
    53  
    54    // try sRequireDelegate.
    55    if (sRequireDelegate != NULL) {
    56      V8Engine *e = GetV8EngineInstance(context);
    57      content = sRequireDelegate(e, filename, lineOffset);
    58    }
    59  
    60    if (content == NULL) {
    61      size_t file_size = 0;
    62      content = readFile(filename, &file_size);
    63      if (content == NULL) {
    64        return 1;
    65      }
    66    }
    67  
    68    asprintf(data, source_require_format, content);
    69    *lineOffset += -2;
    70    free(content);
    71  
    72    return 0;
    73  }
    74  
    75  static void attachVersion(char *out, int maxoutlen, Local<Context> context, const char *libname) {
    76  
    77    char *verlib = NULL;
    78    if (attachLibVersionDelegate != NULL) {
    79      V8Engine *e = GetV8EngineInstance(context);
    80      verlib = attachLibVersionDelegate(e, libname);
    81    }
    82    if (verlib != NULL) {
    83      strncat(out, verlib, maxoutlen - strlen(out) - 1);
    84      free(verlib);
    85    }
    86  }
    87  
    88  void NewNativeRequireFunction(Isolate *isolate,
    89                                Local<ObjectTemplate> globalTpl) {
    90    globalTpl->Set(String::NewFromUtf8(isolate, "_native_require"),
    91                   FunctionTemplate::New(isolate, RequireCallback),
    92                   static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
    93                                                  PropertyAttribute::ReadOnly));
    94  }
    95  
    96  void RequireCallback(const v8::FunctionCallbackInfo<v8::Value> &info) {
    97    Isolate *isolate = info.GetIsolate();
    98    Local<Context> context = isolate->GetCurrentContext();
    99  
   100    if (info.Length() == 0) {
   101      isolate->ThrowException(
   102          Exception::Error(String::NewFromUtf8(isolate, "require missing path")));
   103      return;
   104    }
   105  
   106    Local<Value> path = info[0];
   107    if (!path->IsString()) {
   108      isolate->ThrowException(Exception::Error(
   109          String::NewFromUtf8(isolate, "require path must be string")));
   110      return;
   111    }
   112  
   113    String::Utf8Value filename(path);
   114    if (filename.length() >= MAX_PATH_LEN) {
   115      isolate->ThrowException(Exception::Error(
   116          String::NewFromUtf8(isolate, "require path length more")));
   117      return;
   118    }
   119    char *abPath = NULL;
   120    if (strcmp(*filename, LIB_WHITE)) { // if needed, check array instead.
   121      char versionlizedPath[MAX_VERSIONED_PATH_LEN] = {0};
   122      attachVersion(versionlizedPath, MAX_VERSIONED_PATH_LEN, context, *filename);
   123      abPath = realpath(versionlizedPath, NULL);
   124      if (abPath == NULL) {
   125        isolate->ThrowException(Exception::Error(String::NewFromUtf8(
   126            isolate, "require path is invalid absolutepath")));
   127        return;
   128      }
   129      char curPath[MAX_VERSIONED_PATH_LEN] = {0};
   130      if (curPath[0] == 0x00 && !getCurAbsolute(curPath, MAX_VERSIONED_PATH_LEN)) {
   131        isolate->ThrowException(Exception::Error(
   132            String::NewFromUtf8(isolate, "invalid cwd absolutepath")));
   133        free(abPath);
   134        return;
   135      }
   136      int curLen = strlen(curPath);
   137      if (strncmp(abPath, curPath, curLen) != 0) {
   138        isolate->ThrowException(Exception::Error(
   139            String::NewFromUtf8(isolate, "require path is not in lib")));
   140        free(abPath);
   141        return;
   142      } 
   143  
   144      //free(abPath);
   145      if (!isFile(abPath)) {
   146        isolate->ThrowException(Exception::Error(
   147            String::NewFromUtf8(isolate, "require path is not file")));
   148        free(abPath);
   149        return;
   150      }
   151    }
   152    char *pFile = abPath;
   153    if (abPath == NULL) {
   154      pFile = *filename;
   155    }
   156    char *data = NULL;
   157    size_t lineOffset = 0;
   158    if (readSource(context, (const char*)pFile, &data, &lineOffset)) {
   159      char msg[512];
   160      snprintf(msg, 512, "require cannot find module '%s'", pFile);
   161      isolate->ThrowException(
   162          Exception::Error(String::NewFromUtf8(isolate, msg)));
   163      free(abPath);
   164      return;
   165    }
   166    free(abPath);
   167  
   168    ScriptOrigin sourceSrcOrigin(path, Integer::New(isolate, lineOffset));
   169    MaybeLocal<Script> script = Script::Compile(
   170        context, String::NewFromUtf8(isolate, data), &sourceSrcOrigin);
   171    if (!script.IsEmpty()) {
   172      MaybeLocal<Value> ret = script.ToLocalChecked()->Run(context);
   173      if (!ret.IsEmpty()) {
   174        Local<Value> rr = ret.ToLocalChecked();
   175        info.GetReturnValue().Set(rr);
   176      }
   177    }
   178  
   179    free(static_cast<void *>(data));
   180  }
   181  
   182  void InitializeRequireDelegate(RequireDelegate delegate, AttachLibVersionDelegate aDelegate) {
   183    sRequireDelegate = delegate;
   184    attachLibVersionDelegate = aDelegate;
   185  }