From 30272924a907b4d557e45932bf3cc3d392d5e85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 16 Jul 2018 14:20:09 +0200 Subject: [node] capture invalid input data as `ParseError` objects This allows us to distinguish them from other types of errors --- platform/node/src/node_map.cpp | 37 ++++++++++++++++++++++++++++++++----- platform/node/src/node_map.hpp | 3 +++ 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'platform/node/src') diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index 0cc93d7e95..7dbccfcf41 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -47,6 +47,7 @@ struct NodeMap::RenderOptions { }; Nan::Persistent NodeMap::constructor; +Nan::Persistent NodeMap::parseError; static const char* releasedMessage() { return "Map resources have already been released"; @@ -57,6 +58,20 @@ void NodeMapObserver::onDidFailLoadingMap(std::exception_ptr error) { } void NodeMap::Init(v8::Local target) { + // Define a custom error class for parse errors + auto script = Nan::New(Nan::New(R"JS( +class ParseError extends Error { + constructor(...params) { + super(...params); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, ParseError); + } + } +} +ParseError)JS").ToLocalChecked()).ToLocalChecked(); + parseError.Reset(Nan::To(Nan::RunScript(script).ToLocalChecked()).ToLocalChecked()); + Nan::Set(target, Nan::New("ParseError").ToLocalChecked(), Nan::New(parseError)); + v8::Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("Map").ToLocalChecked()); @@ -216,6 +231,8 @@ void NodeMap::Load(const Nan::FunctionCallbackInfo& info) { try { nodeMap->map->getStyle().loadJSON(style); + } catch (const mbgl::util::StyleParseException& ex) { + return Nan::ThrowError(ParseError(ex.what())); } catch (const std::exception &ex) { return Nan::ThrowError(ex.what()); } @@ -408,9 +425,11 @@ void NodeMap::Render(const Nan::FunctionCallbackInfo& info) { nodeMap->req = std::make_unique(Nan::To(info[1]).ToLocalChecked()); nodeMap->startRender(std::move(options)); - } catch (mbgl::style::conversion::Error& err) { + } catch (const mbgl::style::conversion::Error& err) { return Nan::ThrowTypeError(err.message.c_str()); - } catch (mbgl::util::Exception &ex) { + } catch (const mbgl::util::StyleParseException& ex) { + return Nan::ThrowError(ParseError(ex.what())); + } catch (const mbgl::util::Exception &ex) { return Nan::ThrowError(ex.what()); } @@ -459,6 +478,11 @@ void NodeMap::startRender(NodeMap::RenderOptions options) { uv_ref(reinterpret_cast(async)); } +v8::Local NodeMap::ParseError(const char* msg) { + v8::Local argv[] = { Nan::New(msg).ToLocalChecked() }; + return Nan::CallAsConstructor(Nan::New(parseError), 1, argv).ToLocalChecked(); +} + void NodeMap::renderFinished() { assert(req); @@ -480,16 +504,19 @@ void NodeMap::renderFinished() { v8::Local target = Nan::New(); if (error) { - std::string errorMessage; + v8::Local err; try { std::rethrow_exception(error); + assert(false); + } catch (const mbgl::util::StyleParseException& ex) { + err = ParseError(ex.what()); } catch (const std::exception& ex) { - errorMessage = ex.what(); + err = Nan::Error(ex.what()); } v8::Local argv[] = { - Nan::Error(errorMessage.c_str()) + err }; // This must be empty to be prepared for the next render call. diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 19df095481..52fc1ef659 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -37,6 +37,7 @@ public: ~NodeMap(); static Nan::Persistent constructor; + static Nan::Persistent parseError; static void Init(v8::Local); @@ -67,6 +68,8 @@ public: static void DumpDebugLogs(const Nan::FunctionCallbackInfo&); static void QueryRenderedFeatures(const Nan::FunctionCallbackInfo&); + static v8::Local ParseError(const char* msg); + void startRender(RenderOptions options); void renderFinished(); -- cgit v1.2.1