//////////////////////////////////////////////////////////////////////////////// /// @brief V8 utility functions /// /// @file /// /// DISCLAIMER /// /// Copyright 2004-2012 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #include "BasicsC/win-utils.h" #endif #include "v8-utils.h" #include #include #include "Basics/Dictionary.h" #include "Basics/StringUtils.h" #include "BasicsC/conversions.h" #include "BasicsC/csv.h" #include "BasicsC/files.h" #include "BasicsC/logging.h" #include "BasicsC/process-utils.h" #include "BasicsC/string-buffer.h" #include "BasicsC/strings.h" #include "BasicsC/utf8-helper.h" #include "Rest/SslInterface.h" #include "V8/v8-conv.h" #include "V8/v8-globals.h" #ifdef TRI_HAVE_ICU #include "unicode/normalizer2.h" #endif using namespace std; using namespace triagens::basics; using namespace triagens::rest; // ----------------------------------------------------------------------------- // --SECTION-- GENERAL // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup V8Utils /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief create a Javascript error object //////////////////////////////////////////////////////////////////////////////// static v8::Handle CreateErrorObject (int errorNumber, string const& message) { TRI_v8_global_t* v8g; v8::HandleScope scope; v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData(); v8::Handle errorMessage = v8::String::New(message.c_str()); v8::Handle errorObject = v8::Exception::Error(errorMessage)->ToObject(); v8::Handle proto = v8g->ErrorTempl->NewInstance(); errorObject->Set(v8::String::New("errorNum"), v8::Number::New(errorNumber)); errorObject->Set(v8::String::New("errorMessage"), errorMessage); if (! proto.IsEmpty()) { errorObject->SetPrototype(proto); } return scope.Close(errorObject); } //////////////////////////////////////////////////////////////////////////////// /// @brief reads/execute a file into/in the current context //////////////////////////////////////////////////////////////////////////////// static bool LoadJavaScriptFile (char const* filename, bool execute, bool useGlobalContext) { v8::HandleScope handleScope; char* content = TRI_SlurpFile(TRI_UNKNOWN_MEM_ZONE, filename); if (content == 0) { LOG_TRACE("cannot load java script file '%s': %s", filename, TRI_last_error()); return false; } if (useGlobalContext) { char* contentWrapper = TRI_Concatenate3StringZ(TRI_UNKNOWN_MEM_ZONE, "(function() { ", content, "/* end-of-file */ })()"); TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, content); content = contentWrapper; } v8::Handle name = v8::String::New(filename); v8::Handle source = v8::String::New(content); TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, content); v8::Handle script = v8::Script::Compile(source, name); // compilation failed, print errors that happened during compilation if (script.IsEmpty()) { return false; } if (execute) { // execute script v8::Handle result = script->Run(); if (result.IsEmpty()) { return false; } } LOG_TRACE("loaded java script file: '%s'", filename); return true; } //////////////////////////////////////////////////////////////////////////////// /// @brief reads all files from a directory into the current context //////////////////////////////////////////////////////////////////////////////// static bool LoadJavaScriptDirectory (char const* path, bool execute, bool useGlobalContext) { v8::HandleScope scope; TRI_vector_string_t files; bool result; regex_t re; size_t i; LOG_TRACE("loading JavaScript directory: '%s'", path); files = TRI_FilesDirectory(path); regcomp(&re, "^(.*)\\.js$", REG_ICASE | REG_EXTENDED); result = true; for (i = 0; i < files._length; ++i) { v8::TryCatch tryCatch; bool ok; char const* filename; char* full; filename = files._buffer[i]; if (! regexec(&re, filename, 0, 0, 0) == 0) { continue; } full = TRI_Concatenate2File(path, filename); ok = LoadJavaScriptFile(full, execute, useGlobalContext); TRI_FreeString(TRI_CORE_MEM_ZONE, full); result = result && ok; if (! ok) { TRI_LogV8Exception(&tryCatch); } } TRI_DestroyVectorString(&files); regfree(&re); return result; } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- JS functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup V8Utils /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief parse a Javascript snippet, but do not execute it /// /// @FUN{internal.parse(@FA{script})} /// /// Parses the @FA{script} code, but does not execute it. /// Will return @LIT{true} if the code does not have a parse error, and throw /// an exception otherwise. //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_Parse (v8::Arguments const& argv) { v8::HandleScope scope; v8::TryCatch tryCatch; if (argv.Length() < 1) { return scope.Close(v8::ThrowException(v8::String::New("usage: parse(