diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 33d79689d0993f..c70deafb08842e 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -38,8 +38,6 @@ function startup() { // Do this good and early, since it handles errors. setupProcessFatal(); - setupProcessICUVersions(); - setupGlobalVariables(); // Bootstrappers for all threads, including worker threads and main thread @@ -638,25 +636,6 @@ function setupProcessFatal() { }; } -function setupProcessICUVersions() { - const icu = internalBinding('config').hasIntl ? - internalBinding('icu') : undefined; - if (!icu) return; // no Intl/ICU: nothing to add here. - // With no argument, getVersion() returns a comma separated list - // of possible types. - const versionTypes = icu.getVersion().split(','); - - for (var n = 0; n < versionTypes.length; n++) { - const name = versionTypes[n]; - const version = icu.getVersion(name); - Object.defineProperty(process.versions, name, { - writable: false, - enumerable: true, - value: version - }); - } -} - function wrapForBreakOnFirstLine(source) { if (!process._breakFirstLine) return source; diff --git a/src/node.cc b/src/node.cc index 58722f23b31253..6ae0753f405b24 100644 --- a/src/node.cc +++ b/src/node.cc @@ -877,7 +877,10 @@ void SetupProcessObject(Environment* env, READONLY_PROPERTY(process, "versions", versions); #define V(key) \ - READONLY_STRING_PROPERTY(versions, #key, per_process::metadata.versions.key); + if (!per_process::metadata.versions.key.empty()) { \ + READONLY_STRING_PROPERTY( \ + versions, #key, per_process::metadata.versions.key); \ + } NODE_VERSIONS_KEYS(V) #undef V @@ -1664,6 +1667,7 @@ void Init(std::vector* argv, argv->at(0).c_str()); exit(9); } + per_process::metadata.versions.InitializeIntlVersions(); #endif // We should set node_is_initialized here instead of in node::Start, diff --git a/src/node_crypto.cc b/src/node_crypto.cc index c8401bec54b8f1..011506a34eb34e 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5842,21 +5842,6 @@ void Initialize(Local target, #endif // OPENSSL_NO_SCRYPT } -constexpr int search(const char* s, int n, int c) { - return *s == c ? n : search(s + 1, n + 1, c); -} - -std::string GetOpenSSLVersion() { - // sample openssl version string format - // for reference: "OpenSSL 1.1.0i 14 Aug 2018" - char buf[128]; - const int start = search(OPENSSL_VERSION_TEXT, 0, ' ') + 1; - const int end = search(OPENSSL_VERSION_TEXT + start, start, ' '); - const int len = end - start; - snprintf(buf, sizeof(buf), "%.*s", len, &OPENSSL_VERSION_TEXT[start]); - return std::string(buf); -} - } // namespace crypto } // namespace node diff --git a/src/node_crypto.h b/src/node_crypto.h index 0ee45cf9ea2c02..dd22c9eae4b564 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -94,7 +94,6 @@ extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx); extern void UseExtraCaCerts(const std::string& file); void InitCryptoOnce(); -std::string GetOpenSSLVersion(); class SecureContext : public BaseObject { public: diff --git a/src/node_http_parser_llhttp.cc b/src/node_http_parser_llhttp.cc index 8728fa2b677403..423fb5e104bc50 100644 --- a/src/node_http_parser_llhttp.cc +++ b/src/node_http_parser_llhttp.cc @@ -1,16 +1,18 @@ #define NODE_EXPERIMENTAL_HTTP 1 #include "node_http_parser_impl.h" +#include "node_metadata.h" namespace node { +namespace per_process { const char* const llhttp_version = NODE_STRINGIFY(LLHTTP_VERSION_MAJOR) "." NODE_STRINGIFY(LLHTTP_VERSION_MINOR) "." NODE_STRINGIFY(LLHTTP_VERSION_PATCH); - +} // namespace per_process } // namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser_llhttp, diff --git a/src/node_http_parser_traditional.cc b/src/node_http_parser_traditional.cc index 2ea452239a0a1d..89ef65979ca78b 100644 --- a/src/node_http_parser_traditional.cc +++ b/src/node_http_parser_traditional.cc @@ -3,16 +3,17 @@ #endif #include "node_http_parser_impl.h" +#include "node_metadata.h" namespace node { - +namespace per_process { const char* const http_parser_version = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) "." NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) "." NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); - +} // namespace per_process } // namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser) diff --git a/src/node_i18n.cc b/src/node_i18n.cc index d3e1b96616b5a1..c081bde93bec2a 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -510,67 +510,6 @@ void ICUErrorName(const FunctionCallbackInfo& args) { NewStringType::kNormal).ToLocalChecked()); } -#define TYPE_ICU "icu" -#define TYPE_UNICODE "unicode" -#define TYPE_CLDR "cldr" -#define TYPE_TZ "tz" - -/** - * This is the workhorse function that deals with the actual version info. - * Get an ICU version. - * @param type the type of version to get. One of VERSION_TYPES - * @param buf optional buffer for result - * @param status ICU error status. If failure, assume result is undefined. - * @return version number, or NULL. May or may not be buf. - */ -const char* GetVersion(const char* type, - char buf[U_MAX_VERSION_STRING_LENGTH], - UErrorCode* status) { - if (!strcmp(type, TYPE_ICU)) { - return U_ICU_VERSION; - } else if (!strcmp(type, TYPE_UNICODE)) { - return U_UNICODE_VERSION; - } else if (!strcmp(type, TYPE_TZ)) { - return icu::TimeZone::getTZDataVersion(*status); - } else if (!strcmp(type, TYPE_CLDR)) { - UVersionInfo versionArray; - ulocdata_getCLDRVersion(versionArray, status); - if (U_SUCCESS(*status)) { - u_versionToString(versionArray, buf); - return buf; - } - } - // Fall through - unknown type or error case - return nullptr; -} - -void GetVersion(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - if ( args.Length() == 0 ) { - // With no args - return a comma-separated list of allowed values - args.GetReturnValue().Set( - String::NewFromUtf8(env->isolate(), - TYPE_ICU "," - TYPE_UNICODE "," - TYPE_CLDR "," - TYPE_TZ, NewStringType::kNormal).ToLocalChecked()); - } else { - CHECK_GE(args.Length(), 1); - CHECK(args[0]->IsString()); - Utf8Value val(env->isolate(), args[0]); - UErrorCode status = U_ZERO_ERROR; - char buf[U_MAX_VERSION_STRING_LENGTH] = ""; // Possible output buffer. - const char* versionString = GetVersion(*val, buf, &status); - - if (U_SUCCESS(status) && versionString) { - // Success. - args.GetReturnValue().Set( - String::NewFromUtf8(env->isolate(), - versionString, NewStringType::kNormal).ToLocalChecked()); - } - } -} - } // anonymous namespace bool InitializeICUDirectory(const std::string& path) { @@ -868,7 +807,6 @@ void Initialize(Local target, env->SetMethod(target, "toUnicode", ToUnicode); env->SetMethod(target, "toASCII", ToASCII); env->SetMethod(target, "getStringWidth", GetStringWidth); - env->SetMethod(target, "getVersion", GetVersion); // One-shot converters env->SetMethod(target, "icuErrName", ICUErrorName); diff --git a/src/node_internals.h b/src/node_internals.h index 2c6aad5b967c3d..03017fb4f5185e 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -698,9 +698,6 @@ static inline const char* errno_string(int errorno) { extern double prog_start_time; -extern const char* const llhttp_version; -extern const char* const http_parser_version; - void Abort(const v8::FunctionCallbackInfo& args); void Chdir(const v8::FunctionCallbackInfo& args); void CPUUsage(const v8::FunctionCallbackInfo& args); diff --git a/src/node_metadata.cc b/src/node_metadata.cc index 822b6a490d13d2..ff8d408f5bdc68 100644 --- a/src/node_metadata.cc +++ b/src/node_metadata.cc @@ -2,15 +2,21 @@ #include "ares.h" #include "nghttp2/nghttp2ver.h" #include "node.h" -#include "node_internals.h" #include "util.h" #include "uv.h" #include "v8.h" #include "zlib.h" #if HAVE_OPENSSL -#include "node_crypto.h" -#endif +#include +#endif // HAVE_OPENSSL + +#ifdef NODE_HAVE_I18N_SUPPORT +#include +#include +#include +#include +#endif // NODE_HAVE_I18N_SUPPORT namespace node { @@ -18,6 +24,42 @@ namespace per_process { Metadata metadata; } +#if HAVE_OPENSSL +constexpr int search(const char* s, int n, int c) { + return *s == c ? n : search(s + 1, n + 1, c); +} + +std::string GetOpenSSLVersion() { + // sample openssl version string format + // for reference: "OpenSSL 1.1.0i 14 Aug 2018" + char buf[128]; + const int start = search(OPENSSL_VERSION_TEXT, 0, ' ') + 1; + const int end = search(OPENSSL_VERSION_TEXT + start, start, ' '); + const int len = end - start; + snprintf(buf, sizeof(buf), "%.*s", len, &OPENSSL_VERSION_TEXT[start]); + return std::string(buf); +} +#endif // HAVE_OPENSSL + +#ifdef NODE_HAVE_I18N_SUPPORT +void Metadata::Versions::InitializeIntlVersions() { + UErrorCode status = U_ZERO_ERROR; + + const char* tz_version = icu::TimeZone::getTZDataVersion(status); + if (U_SUCCESS(status)) { + tz = tz_version; + } + + char buf[U_MAX_VERSION_STRING_LENGTH]; + UVersionInfo versionArray; + ulocdata_getCLDRVersion(versionArray, &status); + if (U_SUCCESS(status)) { + u_versionToString(versionArray, buf); + cldr = buf; + } +} +#endif // NODE_HAVE_I18N_SUPPORT + Metadata::Versions::Versions() { node = NODE_VERSION_STRING; v8 = v8::V8::GetVersion(); @@ -27,12 +69,17 @@ Metadata::Versions::Versions() { modules = NODE_STRINGIFY(NODE_MODULE_VERSION); nghttp2 = NGHTTP2_VERSION; napi = NODE_STRINGIFY(NAPI_VERSION); - llhttp = llhttp_version; - http_parser = http_parser_version; + llhttp = per_process::llhttp_version; + http_parser = per_process::http_parser_version; #if HAVE_OPENSSL - openssl = crypto::GetOpenSSLVersion(); + openssl = GetOpenSSLVersion(); #endif + +#ifdef NODE_HAVE_I18N_SUPPORT + icu = U_ICU_VERSION; + unicode = U_UNICODE_VERSION; +#endif // NODE_HAVE_I18N_SUPPORT } } // namespace node diff --git a/src/node_metadata.h b/src/node_metadata.h index 9f383be5f8bade..3c3a430dd73584 100644 --- a/src/node_metadata.h +++ b/src/node_metadata.h @@ -25,14 +25,38 @@ namespace node { #define NODE_VERSIONS_KEY_CRYPTO(V) #endif +#ifdef NODE_HAVE_I18N_SUPPORT +#define NODE_VERSIONS_KEY_INTL(V) \ + V(cldr) \ + V(icu) \ + V(tz) \ + V(unicode) +#else +#define NODE_VERSIONS_KEY_INTL(V) +#endif // NODE_HAVE_I18N_SUPPORT + #define NODE_VERSIONS_KEYS(V) \ NODE_VERSIONS_KEYS_BASE(V) \ - NODE_VERSIONS_KEY_CRYPTO(V) + NODE_VERSIONS_KEY_CRYPTO(V) \ + NODE_VERSIONS_KEY_INTL(V) class Metadata { public: + Metadata() = default; + Metadata(Metadata&) = delete; + Metadata(Metadata&&) = delete; + Metadata operator=(Metadata&) = delete; + Metadata operator=(Metadata&&) = delete; + struct Versions { Versions(); + +#ifdef NODE_HAVE_I18N_SUPPORT + // Must be called on the main thread after + // i18n::InitializeICUDirectory() + void InitializeIntlVersions(); +#endif // NODE_HAVE_I18N_SUPPORT + #define V(key) std::string key; NODE_VERSIONS_KEYS(V) #undef V @@ -44,6 +68,8 @@ class Metadata { // Per-process global namespace per_process { extern Metadata metadata; +extern const char* const llhttp_version; +extern const char* const http_parser_version; } } // namespace node