1
0
Fork 0

fix arangosh error message handling. (#10486)

This commit is contained in:
Wilfried Goesgens 2019-11-20 17:57:51 +01:00 committed by Jan
parent c2346c15ad
commit 3c9947d9a8
2 changed files with 72 additions and 49 deletions

View File

@ -70,15 +70,17 @@ V8ClientConnection::V8ClientConnection(application_features::ApplicationServer&
_role("UNKNOWN"),
_loop(1),
_vpackOptions(VPackOptions::Defaults),
_forceJson(false) {
_forceJson(false),
_setCustomError(false) {
_vpackOptions.buildUnindexedObjects = true;
_vpackOptions.buildUnindexedArrays = true;
_builder.onFailure([this](fuerte::Error error, std::string const& msg) {
std::unique_lock<std::recursive_mutex> guard(_lock, std::try_to_lock);
if (guard) {
if (guard && !_setCustomError) {
_lastHttpReturnCode = 503;
_lastErrorMessage = msg;
}
_setCustomError = false;
});
}
@ -97,20 +99,6 @@ std::shared_ptr<fuerte::Connection> V8ClientConnection::createConnection() {
auto res = newConnection->sendRequest(std::move(req));
_lastHttpReturnCode = res->statusCode();
if (_lastHttpReturnCode >= 400) {
auto const& headers = res->messageHeader().meta();
auto it = headers.find("http/1.1");
if (it != headers.end()) {
_lastErrorMessage = (*it).second;
}
}
if (_lastHttpReturnCode != 200) {
return nullptr;
}
std::lock_guard<std::recursive_mutex> guard(_lock);
_connection = newConnection;
std::shared_ptr<VPackBuilder> parsedBody;
VPackSlice body;
@ -122,11 +110,35 @@ std::shared_ptr<fuerte::Connection> V8ClientConnection::createConnection() {
res->payload().size());
body = parsedBody->slice();
}
if (!body.isObject()) {
_lastErrorMessage = "invalid response";
_lastHttpReturnCode = 503;
if (_lastHttpReturnCode >= 400) {
auto const& headers = res->messageHeader().meta();
auto it = headers.find("http/1.1");
if (it != headers.end()) {
std::string errorMessage = (*it).second;
if (body.isObject()) {
std::string const msg =
VelocyPackHelper::getStringValue(body, StaticStrings::ErrorMessage, "");
if (!msg.empty()) {
errorMessage = msg;
}
}
setCustomError(_lastHttpReturnCode, errorMessage);
return nullptr;
}
}
if (!body.isObject()) {
std::string msg("invalid response: '");
msg += std::string(reinterpret_cast<char const*>(res->payload().data()),
res->payload().size());
msg += "'";
setCustomError(503, msg);
return nullptr;
}
std::lock_guard<std::recursive_mutex> guard(_lock);
_connection = newConnection;
std::string const server =
VelocyPackHelper::getStringValue(body, "server", "");
@ -157,15 +169,16 @@ std::shared_ptr<fuerte::Connection> V8ClientConnection::createConnection() {
// major version of server is too low
//_client->disconnect();
shutdownConnection();
_lastErrorMessage = "Server version number ('" + versionString +
"') is too low. Expecting 3.0 or higher";
std::string msg("Server version number ('" + versionString +
"') is too low. Expecting 3.0 or higher");;
setCustomError(500, msg);
return newConnection;
}
}
return _connection;
} catch (fuerte::Error const& e) { // connection error
_lastErrorMessage = fuerte::to_string(e);
_lastHttpReturnCode = 503;
std::string msg(fuerte::to_string(e));
setCustomError(503, msg);
return nullptr;
}
}
@ -280,7 +293,8 @@ void V8ClientConnection::reconnect(ClientFeature* client) {
if (client->getWarnConnect()) {
LOG_TOPIC("9d7ea", ERR, arangodb::Logger::FIXME)
<< "Could not connect to endpoint '" << client->endpoint()
<< "', username: '" << client->username() << "'";
<< "', username: '" << client->username() << "' - Server message: " <<
_lastErrorMessage;
}
std::string errorMsg = "could not connect";
@ -427,7 +441,7 @@ static void ClientConnection_reconnect(v8::FunctionCallbackInfo<v8::Value> const
ClientFeature* client = static_cast<ClientFeature*>(wrap->Value());
if (v8connection == nullptr || client == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("reconnect() must be invoked on an arango connection object instance.");
}
if (args.Length() < 2) {
@ -511,7 +525,7 @@ static void ClientConnection_connectedUser(v8::FunctionCallbackInfo<v8::Value> c
v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast(args.Data());
ClientFeature* client = static_cast<ClientFeature*>(wrap->Value());
if (client == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("connectedUser() must be invoked on an arango connection object instance.");
}
TRI_V8_RETURN(TRI_V8_STD_STRING(isolate, client->username()));
@ -532,7 +546,7 @@ static void ClientConnection_httpGetAny(v8::FunctionCallbackInfo<v8::Value> cons
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("get() must be invoked on an arango connection object instance.");
}
// check params
@ -583,7 +597,7 @@ static void ClientConnection_httpHeadAny(v8::FunctionCallbackInfo<v8::Value> con
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("head() must be invoked on an arango connection object instance.");
}
// check params
@ -635,7 +649,7 @@ static void ClientConnection_httpDeleteAny(v8::FunctionCallbackInfo<v8::Value> c
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("delete() must be invoked on an arango connection object instance.");
}
// check params
@ -691,7 +705,7 @@ static void ClientConnection_httpOptionsAny(v8::FunctionCallbackInfo<v8::Value>
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("options() must be invoked on an arango connection object instance.");
}
// check params
@ -743,7 +757,7 @@ static void ClientConnection_httpPostAny(v8::FunctionCallbackInfo<v8::Value> con
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("post() must be invoked on an arango connection object instance.");
}
// check params
@ -794,7 +808,7 @@ static void ClientConnection_httpPutAny(v8::FunctionCallbackInfo<v8::Value> cons
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("put() must be invoked on an arango connection object instance.");
}
// check params
@ -846,7 +860,7 @@ static void ClientConnection_httpPatchAny(v8::FunctionCallbackInfo<v8::Value> co
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("patch() must be invoked on an arango connection object instance.");
}
// check params
@ -896,7 +910,7 @@ static void ClientConnection_httpSendFile(v8::FunctionCallbackInfo<v8::Value> co
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("sendFile() must be invoked on an arango connection object instance.");
}
// check params
@ -953,7 +967,7 @@ static void ClientConnection_getEndpoint(v8::FunctionCallbackInfo<v8::Value> con
ClientFeature* client = static_cast<ClientFeature*>(wrap->Value());
if (v8connection == nullptr || client == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("getEndpoint() must be invoked on an arango connection object instance.");
}
// check params
@ -1151,7 +1165,7 @@ static void ClientConnection_lastHttpReturnCode(v8::FunctionCallbackInfo<v8::Val
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("lastHttpReturnCode() must be invoked on an arango connection object instance.");
}
// check params
@ -1176,7 +1190,7 @@ static void ClientConnection_lastErrorMessage(v8::FunctionCallbackInfo<v8::Value
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("lastErrorMessage() must be invoked on an arango connection object instance.");
}
// check params
@ -1201,7 +1215,7 @@ static void ClientConnection_isConnected(v8::FunctionCallbackInfo<v8::Value> con
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("isConnected() must be invoked on an arango connection object instance.");
}
if (args.Length() != 0) {
@ -1228,7 +1242,7 @@ static void ClientConnection_forceJson(v8::FunctionCallbackInfo<v8::Value> const
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("forceJson() must be invoked on an arango connection object instance.");
}
if (args.Length() != 1) {
@ -1238,7 +1252,7 @@ static void ClientConnection_forceJson(v8::FunctionCallbackInfo<v8::Value> const
v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast(args.Data());
ClientFeature* client = static_cast<ClientFeature*>(wrap->Value());
if (client == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("forceJson() unable to get client instance");
}
bool forceJson = TRI_ObjectToBoolean(isolate, args[0]);
@ -1261,7 +1275,7 @@ static void ClientConnection_timeout(v8::FunctionCallbackInfo<v8::Value> const&
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("timeout() must be invoked on an arango connection object instance.");
}
if (args.Length() == 0) {
@ -1274,7 +1288,7 @@ static void ClientConnection_timeout(v8::FunctionCallbackInfo<v8::Value> const&
ClientFeature* client = static_cast<ClientFeature*>(wrap->Value());
if (client == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("timeout() unable to get client instance");
}
client->requestTimeout(value);
@ -1298,7 +1312,10 @@ static void ClientConnection_toString(v8::FunctionCallbackInfo<v8::Value> const&
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
// when invoking ArangoConnection.toString() we end here, i.e. printObject does this.
// be silent about this.
isolate->ThrowException(v8::Object::New(isolate));
return;
}
if (args.Length() != 0) {
@ -1331,7 +1348,7 @@ static void ClientConnection_getVersion(v8::FunctionCallbackInfo<v8::Value> cons
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("getVersion() must be invoked on an arango connection object instance.");
}
if (args.Length() != 0) {
@ -1355,7 +1372,7 @@ static void ClientConnection_getMode(v8::FunctionCallbackInfo<v8::Value> const&
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("getMode() must be invoked on an arango connection object instance.");
}
if (args.Length() != 0) {
@ -1379,7 +1396,7 @@ static void ClientConnection_getRole(v8::FunctionCallbackInfo<v8::Value> const&
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("getRole() must be invoked on an arango connection object instance.");
}
if (args.Length() != 0) {
@ -1403,7 +1420,7 @@ static void ClientConnection_getDatabaseName(v8::FunctionCallbackInfo<v8::Value>
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION, TRI_IGETC);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("getDatabaseName() must be invoked on an arango connection object instance.");
}
if (args.Length() != 0) {
@ -1430,7 +1447,7 @@ static void ClientConnection_setDatabaseName(v8::FunctionCallbackInfo<v8::Value>
ClientFeature* client = static_cast<ClientFeature*>(wrap->Value());
if (v8connection == nullptr || client == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
TRI_V8_THROW_EXCEPTION_INTERNAL("setDatabaseName() must be invoked on an arango connection object instance.");
}
if (args.Length() != 1 || !args[0]->IsString()) {
@ -1966,7 +1983,7 @@ void V8ClientConnection::initServer(v8::Isolate* isolate, v8::Local<v8::Context>
v8::FunctionTemplate::New(isolate, ClientConnection_timeout, v8client));
connection_proto->Set(isolate, "toString",
v8::FunctionTemplate::New(isolate, ClientConnection_toString));
v8::FunctionTemplate::New(isolate, ClientConnection_toString, v8client));
connection_proto->Set(isolate, "getVersion",
v8::FunctionTemplate::New(isolate, ClientConnection_getVersion));

View File

@ -146,6 +146,11 @@ class V8ClientConnection {
/// to a nullptr
void shutdownConnection();
void setCustomError(int httpCode, std::string const& msg) {
_setCustomError = true;
_lastHttpReturnCode = httpCode;
_lastErrorMessage = msg;
}
private:
application_features::ApplicationServer& _server;
@ -164,6 +169,7 @@ class V8ClientConnection {
std::shared_ptr<fuerte::Connection> _connection;
velocypack::Options _vpackOptions;
bool _forceJson;
bool _setCustomError;
};
} // namespace arangodb