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 }