1
0
Fork 0

forward port branch feature-3.3/allow-jwt-in-arangosh (#5009)

This commit is contained in:
Jan 2018-04-03 17:37:01 +02:00 committed by GitHub
parent 167dfcdf7f
commit 8b9eb13925
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 360 additions and 209 deletions

View File

@ -66,7 +66,8 @@ auth::TokenCache::~TokenCache() {
void auth::TokenCache::setJwtSecret(std::string const& jwtSecret) {
WRITE_LOCKER(writeLocker, _jwtLock);
LOG_TOPIC(DEBUG, Logger::AUTHENTICATION) << "Setting jwt secret " << jwtSecret;
LOG_TOPIC(DEBUG, Logger::AUTHENTICATION)
<< "Setting jwt secret " << jwtSecret;
_jwtSecret = jwtSecret;
_jwtCache.clear();
generateJwtToken();
@ -171,7 +172,7 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(
_jwtCache.remove(jwt);
} catch (std::range_error const&) {
}
LOG_TOPIC(TRACE, Logger::AUTHENTICATION) << "JWT Token expired";
LOG_TOPIC(TRACE, Logger::AUTHENTICATION) << "JWT Token expired";
return auth::TokenCache::Entry(); // unauthorized
}
// LDAP rights might need to be refreshed
@ -180,11 +181,11 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(
} catch (std::range_error const&) {
// mop: not found
}
std::vector<std::string> const parts = StringUtils::split(jwt, '.');
if (parts.size() != 3) {
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "Secret contains "
<< parts.size() << " parts";
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "Secret contains " << parts.size() << " parts";
return auth::TokenCache::Entry();
}
@ -208,8 +209,8 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(
std::string const message = header + "." + body;
if (!validateJwtHMAC256Signature(message, signature)) {
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
<< "Couldn't validate jwt signature " << signature
<< " against " << _jwtSecret;
<< "Couldn't validate jwt signature " << signature << " against "
<< _jwtSecret;
return auth::TokenCache::Entry();
}
@ -226,11 +227,11 @@ std::shared_ptr<VPackBuilder> auth::TokenCache::parseJson(
parser.parse(str);
result = parser.steal();
} catch (std::bad_alloc const&) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Out of memory parsing " << hint
<< "!";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "Out of memory parsing " << hint << "!";
} catch (VPackException const& ex) {
LOG_TOPIC(DEBUG, arangodb::Logger::FIXME) << "Couldn't parse " << hint
<< ": " << ex.what();
LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
<< "Couldn't parse " << hint << ": " << ex.what();
} catch (...) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "Got unknown exception trying to parse " << hint;
@ -292,14 +293,12 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(
VPackSlice const issSlice = bodySlice.get("iss");
if (!issSlice.isString()) {
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
<< "missing iss value";
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION) << "missing iss value";
return authResult; // unauthenticated
}
if (issSlice.copyString() != "arangodb") {
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
<< "invalid iss value";
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION) << "invalid iss value";
return authResult; // unauthenticated
}
@ -314,7 +313,7 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(
// authResult._username = "root";
} else {
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
<< "Lacking preferred_username or server_id";
<< "Lacking preferred_username or server_id";
return authResult; // unauthenticated
}
@ -363,7 +362,8 @@ std::string auth::TokenCache::generateRawJwt(VPackSlice const& body) const {
std::string fullMessage(StringUtils::encodeBase64(headerBuilder.toJson()) +
"." + StringUtils::encodeBase64(body.toJson()));
if (_jwtSecret.empty()) {
LOG_TOPIC(INFO, Logger::AUTHENTICATION) << "Using cluster without JWT Token";
LOG_TOPIC(INFO, Logger::AUTHENTICATION)
<< "Using cluster without JWT Token";
}
std::string signature =

View File

@ -23,13 +23,13 @@
#include "AuthenticationFeature.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Auth/Common.h"
#include "Auth/Handler.h"
#include "Cluster/ServerState.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "Random/RandomGenerator.h"
#include "RestServer/QueryRegistryFeature.h"
#include "Auth/Common.h"
#if USE_ENTERPRISE
#include "Enterprise/Ldap/LdapAuthenticationHandler.h"
@ -87,13 +87,15 @@ void AuthenticationFeature::collectOptions(
"enable or disable authentication for ALL client requests",
new BooleanParameter(&_active));
options->addOption("--server.authentication-timeout",
"timeout for the authentication cache in seconds (0 = indefinitely)",
new DoubleParameter(&_authenticationTimeout));
options->addOption(
"--server.authentication-timeout",
"timeout for the authentication cache in seconds (0 = indefinitely)",
new DoubleParameter(&_authenticationTimeout));
options->addOption("--server.local-authentication",
"enable or disable authentication using the local user database",
new BooleanParameter(&_localAuthentication));
options->addOption(
"--server.local-authentication",
"enable or disable authentication using the local user database",
new BooleanParameter(&_localAuthentication));
options->addOption(
"--server.authentication-system-only",
@ -123,30 +125,33 @@ void AuthenticationFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
void AuthenticationFeature::prepare() {
TRI_ASSERT(isEnabled());
TRI_ASSERT(_userManager == nullptr);
TRI_ASSERT(_userManager == nullptr);
#if USE_ENTERPRISE
if (application_features::ApplicationServer::getFeature<LdapFeature>("Ldap")
->isEnabled()) {
_userManager = new auth::UserManager(std::make_unique<LdapAuthenticationHandler>());
} else {
_userManager = new auth::UserManager();
}
#else
if (application_features::ApplicationServer::getFeature<LdapFeature>("Ldap")
->isEnabled()) {
_userManager =
new auth::UserManager(std::make_unique<LdapAuthenticationHandler>());
} else {
_userManager = new auth::UserManager();
}
#else
_userManager = new auth::UserManager();
#endif
TRI_ASSERT(_authCache == nullptr);
TRI_ASSERT(_authCache == nullptr);
_authCache = new auth::TokenCache(_userManager, _authenticationTimeout);
std::string jwtSecret = _jwtSecretProgramOption;
if (jwtSecret.empty()) {
LOG_TOPIC(INFO, Logger::AUTHENTICATION) << "Jwt secret not specified, generating...";
LOG_TOPIC(INFO, Logger::AUTHENTICATION)
<< "Jwt secret not specified, generating...";
uint16_t m = 254;
for (size_t i = 0; i < _maxSecretLength; i++) {
jwtSecret += (1 + RandomGenerator::interval(m));
}
}
_authCache->setJwtSecret(jwtSecret);
INSTANCE = this;
}
@ -158,8 +163,8 @@ void AuthenticationFeature::start() {
out << "Authentication is turned " << (_active ? "on" : "off");
auto queryRegistryFeature =
application_features::ApplicationServer::getFeature<
QueryRegistryFeature>("QueryRegistry");
application_features::ApplicationServer::getFeature<QueryRegistryFeature>(
"QueryRegistry");
_userManager->setQueryRegistry(queryRegistryFeature->queryRegistry());
if (_active && _authenticationSystemOnly) {
@ -167,12 +172,11 @@ void AuthenticationFeature::start() {
}
#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
out << ", authentication for unix sockets is turned "
<< (_authenticationUnixSockets ? "on" : "off");
out << ", authentication for unix sockets is turned "
<< (_authenticationUnixSockets ? "on" : "off");
#endif
LOG_TOPIC(INFO, arangodb::Logger::AUTHENTICATION) << out.str();
}
void AuthenticationFeature::unprepare() { INSTANCE = nullptr; }

View File

@ -56,7 +56,7 @@ int main(int argc, char* argv[]) {
int ret;
server.addFeature(new BenchFeature(&server, &ret));
server.addFeature(new ClientFeature(&server));
server.addFeature(new ClientFeature(&server, false));
server.addFeature(new ConfigFeature(&server, "arangobench"));
server.addFeature(new LoggerFeature(&server, false));
server.addFeature(new RandomFeature(&server));

View File

@ -58,7 +58,7 @@ int main(int argc, char* argv[]) {
int ret;
server.addFeature(new ClientFeature(&server));
server.addFeature(new ClientFeature(&server, false));
server.addFeature(new ConfigFeature(&server, "arangodump"));
server.addFeature(new DumpFeature(&server, ret));
server.addFeature(new LoggerFeature(&server, false));

View File

@ -53,7 +53,7 @@ int main(int argc, char* argv[]) {
int ret;
server.addFeature(new ClientFeature(&server));
server.addFeature(new ClientFeature(&server, false));
server.addFeature(new ConfigFeature(&server, "arangoexport"));
server.addFeature(new ExportFeature(&server, &ret));
server.addFeature(new LoggerFeature(&server, false));

View File

@ -53,7 +53,7 @@ int main(int argc, char* argv[]) {
int ret;
server.addFeature(new ClientFeature(&server));
server.addFeature(new ClientFeature(&server, false));
server.addFeature(new ConfigFeature(&server, "arangoimport"));
server.addFeature(new ImportFeature(&server, &ret));
server.addFeature(new LoggerFeature(&server, false));

View File

@ -58,7 +58,7 @@ int main(int argc, char* argv[]) {
int ret;
server.addFeature(new ClientFeature(&server));
server.addFeature(new ClientFeature(&server, false));
server.addFeature(new ConfigFeature(&server, "arangorestore"));
server.addFeature(new LoggerFeature(&server, false));
server.addFeature(new RandomFeature(&server));

View File

@ -42,21 +42,25 @@ using namespace arangodb::httpclient;
using namespace arangodb::options;
ClientFeature::ClientFeature(application_features::ApplicationServer* server,
double connectionTimeout, double requestTimeout)
bool allowJwtSecret, double connectionTimeout,
double requestTimeout)
: ApplicationFeature(server, "Client"),
_databaseName("_system"),
_authentication(true),
_askJwtSecret(false),
_endpoint(Endpoint::defaultEndpoint(Endpoint::TransportType::HTTP)),
_username("root"),
_password(""),
_jwtSecret(""),
_connectionTimeout(connectionTimeout),
_requestTimeout(requestTimeout),
_maxPacketSize(128 * 1024 * 1024),
_sslProtocol(TLS_V12),
_allowJwtSecret(allowJwtSecret),
_retries(DEFAULT_RETRIES),
_warn(false),
_warnConnect(true),
_haveServerPassword(false){
_haveServerPassword(false) {
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("Logger");
@ -70,11 +74,11 @@ void ClientFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
new StringParameter(&_databaseName));
options->addOption("--server.authentication",
"require authentication credentials when connecting (does not affect the server-side authentication settings)",
"require authentication credentials when connecting (does "
"not affect the server-side authentication settings)",
new BooleanParameter(&_authentication));
options->addOption("--server.username",
"username to use when connecting",
options->addOption("--server.username", "username to use when connecting",
new StringParameter(&_username));
options->addOption(
@ -88,23 +92,37 @@ void ClientFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
"for a password",
new StringParameter(&_password));
if (_allowJwtSecret) {
// currently the option is only present for arangosh, but none
// of the other client tools
options->addHiddenOption(
"--server.ask-jwt-secret",
"if this option is specified, the user will be prompted "
"for a JWT secret. This option is not compatible with "
"--server.username or --server.password. If specified, it will be used for all "
"connections - even when a new connection to another server is "
"created",
new BooleanParameter(&_askJwtSecret));
}
options->addOption("--server.connection-timeout",
"connection timeout in seconds",
new DoubleParameter(&_connectionTimeout));
options->addOption("--server.request-timeout",
"request timeout in seconds",
options->addOption("--server.request-timeout", "request timeout in seconds",
new DoubleParameter(&_requestTimeout));
options->addHiddenOption("--server.max-packet-size",
"maximum packet size (in bytes) for client/server communication",
new UInt64Parameter(&_maxPacketSize));
options->addHiddenOption(
"--server.max-packet-size",
"maximum packet size (in bytes) for client/server communication",
new UInt64Parameter(&_maxPacketSize));
std::unordered_set<uint64_t> sslProtocols = {1, 2, 3, 4, 5};
options->addSection("ssl", "Configure SSL communication");
options->addOption("--ssl.protocol",
"ssl protocol (1 = SSLv2, 2 = SSLv2 or SSLv3 (negotiated), 3 = SSLv3, 4 = "
"ssl protocol (1 = SSLv2, 2 = SSLv2 or SSLv3 "
"(negotiated), 3 = SSLv3, 4 = "
"TLSv1, 5 = TLSV1.2)",
new DiscreteValuesParameter<UInt64Parameter>(
&_sslProtocol, sslProtocols));
@ -116,6 +134,10 @@ void ClientFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
_authentication = true;
}
if (_askJwtSecret) {
_authentication = false;
}
// check timeouts
if (_connectionTimeout < 0.0) {
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "invalid value for --server.connect-timeout, must be >= 0";
@ -144,30 +166,70 @@ void ClientFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
_haveServerPassword = !options->processingResult().touched("server.password");
if (_askJwtSecret && options->processingResult().touched("server.password")) {
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
<< "cannot specify both --server.password and --server.ask-jwt-token";
FATAL_ERROR_EXIT();
}
if (_askJwtSecret && options->processingResult().touched("server.username")) {
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
<< "cannot specify both --server.username and --server.ask-jwt-token";
FATAL_ERROR_EXIT();
}
SimpleHttpClientParams::setDefaultMaxPacketSize(_maxPacketSize);
}
void ClientFeature::prepare() {
// ask for a password
if (_authentication &&
isEnabled() &&
_haveServerPassword) {
std::this_thread::sleep_for(std::chrono::microseconds(10 * 1000));
void ClientFeature::readPassword() {
usleep(10 * 1000);
try {
ConsoleFeature* console =
ApplicationServer::getFeature<ConsoleFeature>("Console");
try {
ConsoleFeature* console =
ApplicationServer::getFeature<ConsoleFeature>("Console");
if (console->isEnabled()) {
_password = console->readPassword("Please specify a password: ");
return;
}
} catch (...) {
if (console->isEnabled()) {
_password = console->readPassword("Please specify a password: ");
return;
}
} catch (...) {
}
std::cout << "Please specify a password: " << std::flush;
_password = ConsoleFeature::readPassword();
std::cout << std::endl << std::flush;
std::cout << "Please specify a password: " << std::flush;
_password = ConsoleFeature::readPassword();
std::cout << std::endl << std::flush;
}
void ClientFeature::readJwtSecret() {
usleep(10 * 1000);
try {
ConsoleFeature* console =
ApplicationServer::getFeature<ConsoleFeature>("Console");
if (console->isEnabled()) {
_jwtSecret = console->readPassword("Please specify the JWT secret: ");
return;
}
} catch (...) {
}
std::cout << "Please specify the JWT secret: " << std::flush;
_jwtSecret = ConsoleFeature::readPassword();
std::cout << std::endl << std::flush;
}
void ClientFeature::prepare() {
if (!isEnabled()) {
return;
}
if (_askJwtSecret) {
// ask for a jwt secret
readJwtSecret();
} else if (_authentication && _haveServerPassword) {
// ask for a password
readPassword();
}
}
@ -180,7 +242,8 @@ std::unique_ptr<GeneralClientConnection> ClientFeature::createConnection(
std::unique_ptr<Endpoint> endpoint(Endpoint::clientFactory(definition));
if (endpoint.get() == nullptr) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "invalid value for --server.endpoint ('" << definition << "')";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "invalid value for --server.endpoint ('" << definition << "')";
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
@ -196,24 +259,27 @@ std::unique_ptr<SimpleHttpClient> ClientFeature::createHttpClient() const {
return createHttpClient(_endpoint);
}
std::unique_ptr<SimpleHttpClient> ClientFeature::createHttpClient(std::string const& definition) const {
return createHttpClient(definition, SimpleHttpClientParams(_requestTimeout, _warn));
std::unique_ptr<SimpleHttpClient> ClientFeature::createHttpClient(
std::string const& definition) const {
return createHttpClient(definition,
SimpleHttpClientParams(_requestTimeout, _warn));
}
std::unique_ptr<httpclient::SimpleHttpClient> ClientFeature::createHttpClient(
std::string const& definition,
SimpleHttpClientParams const& params) const {
std::string const& definition, SimpleHttpClientParams const& params) const {
std::unique_ptr<Endpoint> endpoint(Endpoint::clientFactory(definition));
if (endpoint.get() == nullptr) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "invalid value for --server.endpoint ('" << definition << "')";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "invalid value for --server.endpoint ('" << definition << "')";
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
std::unique_ptr<GeneralClientConnection> connection(GeneralClientConnection::factory(endpoint, _requestTimeout,
_connectionTimeout, _retries,
_sslProtocol));
std::unique_ptr<GeneralClientConnection> connection(
GeneralClientConnection::factory(endpoint, _requestTimeout,
_connectionTimeout, _retries,
_sslProtocol));
return std::make_unique<SimpleHttpClient>(connection, params);
}
@ -224,21 +290,23 @@ std::vector<std::string> ClientFeature::httpEndpoints() {
return {};
}
return { http };
return {http};
}
int ClientFeature::runMain(int argc, char* argv[],
std::function<int(int argc, char* argv[])> const& mainFunc) {
int ClientFeature::runMain(
int argc, char* argv[],
std::function<int(int argc, char* argv[])> const& mainFunc) {
try {
return mainFunc(argc, argv);
} catch (std::exception const& ex) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< argv[0] << " terminated because of an unhandled exception: "
<< ex.what();
<< argv[0]
<< " terminated because of an unhandled exception: " << ex.what();
return EXIT_FAILURE;
} catch (...) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< argv[0] << " terminated because of an unhandled exception of unknown type";
<< argv[0]
<< " terminated because of an unhandled exception of unknown type";
return EXIT_FAILURE;
}
}

View File

@ -33,7 +33,7 @@ namespace httpclient {
class GeneralClientConnection;
class SimpleHttpClient;
struct SimpleHttpClientParams;
}
} // namespace httpclient
class ClientFeature final : public application_features::ApplicationFeature,
public HttpEndpointProvider {
@ -45,6 +45,7 @@ class ClientFeature final : public application_features::ApplicationFeature,
public:
ClientFeature(application_features::ApplicationServer* server,
bool allowJwtSecret,
double connectionTimeout = DEFAULT_CONNECTION_TIMEOUT,
double requestTimeout = DEFAULT_REQUEST_TIMEOUT);
@ -62,6 +63,7 @@ class ClientFeature final : public application_features::ApplicationFeature,
void setUsername(std::string const& value) { _username = value; }
std::string const& password() const { return _password; }
void setPassword(std::string const& value) { _password = value; }
std::string const& jwtSecret() const { return _jwtSecret; }
double connectionTimeout() const { return _connectionTimeout; }
double requestTimeout() const { return _requestTimeout; }
uint64_t maxPacketSize() const { return _maxPacketSize; }
@ -75,7 +77,8 @@ class ClientFeature final : public application_features::ApplicationFeature,
std::unique_ptr<httpclient::SimpleHttpClient> createHttpClient(
std::string const& definition) const;
std::unique_ptr<httpclient::SimpleHttpClient> createHttpClient(
std::string const& definition, httpclient::SimpleHttpClientParams const&) const;
std::string const& definition,
httpclient::SimpleHttpClientParams const&) const;
std::vector<std::string> httpEndpoints() override;
void setDatabaseName(std::string const& databaseName) {
@ -92,26 +95,34 @@ class ClientFeature final : public application_features::ApplicationFeature,
bool getWarnConnect() { return _warnConnect; }
static int runMain(int argc, char* argv[],
std::function<int(int argc, char* argv[])> const& mainFunc);
static int runMain(
int argc, char* argv[],
std::function<int(int argc, char* argv[])> const& mainFunc);
private:
void readPassword();
void readJwtSecret();
private:
std::string _databaseName;
bool _authentication;
bool _askJwtSecret;
std::string _endpoint;
std::string _username;
std::string _password;
std::string _jwtSecret;
double _connectionTimeout;
double _requestTimeout;
uint64_t _maxPacketSize;
uint64_t _sslProtocol;
private:
bool _allowJwtSecret;
size_t _retries;
bool _warn;
bool _warnConnect;
bool _haveServerPassword;
};
}
} // namespace arangodb
#endif

View File

@ -24,8 +24,8 @@
#include "V8ClientConnection.h"
#include <iostream>
#include <v8.h>
#include <iostream>
#include "Basics/FileUtils.h"
#include "Basics/StringUtils.h"
@ -38,6 +38,7 @@
#include "SimpleHttpClient/GeneralClientConnection.h"
#include "SimpleHttpClient/SimpleHttpClient.h"
#include "SimpleHttpClient/SimpleHttpResult.h"
#include "Ssl/SslInterface.h"
#include "V8/v8-conv.h"
#include "V8/v8-json.h"
#include "V8/v8-utils.h"
@ -48,6 +49,35 @@ using namespace arangodb::basics;
using namespace arangodb::httpclient;
using namespace arangodb::import;
std::string V8ClientConnection::JWT_SECRET = "";
std::string V8ClientConnection::jwtToken(std::string const& secret) {
VPackBuilder headerBuilder;
{
VPackObjectBuilder h(&headerBuilder);
headerBuilder.add("alg", VPackValue("HS256"));
headerBuilder.add("typ", VPackValue("JWT"));
}
VPackBuilder bodyBuilder;
{
VPackObjectBuilder p(&bodyBuilder);
bodyBuilder.add("server_id", VPackValue("arangosh"));
bodyBuilder.add("iss", VPackValue("arangodb"));
bodyBuilder.add("iat", VPackValue(TRI_microtime() / 1000));
}
std::string fullMessage(StringUtils::encodeBase64(headerBuilder.toJson()) +
"." +
StringUtils::encodeBase64(bodyBuilder.toJson()));
std::string signature = sslHMAC(
secret.c_str(), secret.length(), fullMessage.c_str(),
fullMessage.length(), rest::SslInterface::Algorithm::ALGORITHM_SHA256);
return fullMessage + "." + StringUtils::encodeBase64U(signature);
}
V8ClientConnection::V8ClientConnection(
std::unique_ptr<GeneralClientConnection>& connection,
std::string const& database, std::string const& username,
@ -65,8 +95,9 @@ V8ClientConnection::V8ClientConnection(
V8ClientConnection::~V8ClientConnection() {}
void V8ClientConnection::init(
std::unique_ptr<GeneralClientConnection>& connection, std::string const& username,
std::string const& password, std::string const& databaseName) {
std::unique_ptr<GeneralClientConnection>& connection,
std::string const& username, std::string const& password,
std::string const& databaseName) {
_username = username;
_password = password;
_databaseName = databaseName;
@ -74,13 +105,18 @@ void V8ClientConnection::init(
SimpleHttpClientParams params(_requestTimeout, false);
params.setLocationRewriter(this, &rewriteLocation);
params.setUserNamePassword("/", _username, _password);
if (!JWT_SECRET.empty()) {
params.setJwt(jwtToken(JWT_SECRET));
}
_client.reset(new SimpleHttpClient(connection, params));
// connect to server and get version number
std::unordered_map<std::string, std::string> headerFields;
std::unique_ptr<SimpleHttpResult> result(
_client->request(rest::RequestType::GET,
"/_api/version?details=true", nullptr, 0, headerFields));
_client->request(rest::RequestType::GET, "/_api/version?details=true",
nullptr, 0, headerFields));
if (result.get() == nullptr || !result->isComplete()) {
// save error message
@ -89,7 +125,8 @@ void V8ClientConnection::init(
} else {
_lastHttpReturnCode = result->getHttpReturnCode();
if (result->getHttpReturnCode() == static_cast<int>(rest::ResponseCode::OK)) {
if (result->getHttpReturnCode() ==
static_cast<int>(rest::ResponseCode::OK)) {
try {
std::shared_ptr<VPackBuilder> parsedBody = result->getBodyVelocyPack();
VPackSlice const body = parsedBody->slice();
@ -109,11 +146,13 @@ void V8ClientConnection::init(
}
std::string const versionString =
VelocyPackHelper::getStringValue(body, "version", "");
std::pair<int, int> version = rest::Version::parseVersionString(versionString);
std::pair<int, int> version =
rest::Version::parseVersionString(versionString);
if (version.first < 3) {
// major version of server is too low
_client->disconnect();
_lastErrorMessage = "Server version number ('" + versionString + "') is too low. Expecting 3.0 or higher";
_lastErrorMessage = "Server version number ('" + versionString +
"') is too low. Expecting 3.0 or higher";
return;
}
}
@ -172,7 +211,8 @@ void V8ClientConnection::reconnect(ClientFeature* client) {
try {
std::unique_ptr<GeneralClientConnection> connection =
client->createConnection(client->endpoint());
init(connection, client->username(), client->password(), client->databaseName());
init(connection, client->username(), client->password(),
client->databaseName());
} catch (...) {
std::string errorMessage = "error in '" + client->endpoint() + "'";
throw errorMessage;
@ -180,16 +220,17 @@ void V8ClientConnection::reconnect(ClientFeature* client) {
if (isConnected() &&
_lastHttpReturnCode == static_cast<int>(rest::ResponseCode::OK)) {
LOG_TOPIC(INFO, arangodb::Logger::FIXME) << "Connected to ArangoDB "
<< "'" << endpointSpecification() << "', "
<< "version " << _version << " [" << _mode << "], "
<< "database '" << _databaseName << "', "
<< "username: '" << _username << "'";
LOG_TOPIC(INFO, arangodb::Logger::FIXME)
<< "Connected to ArangoDB "
<< "'" << endpointSpecification() << "', "
<< "version " << _version << " [" << _mode << "], "
<< "database '" << _databaseName << "', "
<< "username: '" << _username << "'";
} else {
if (client->getWarnConnect()) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "Could not connect to endpoint '" << client->endpoint()
<< "', username: '" << client->username() << "'";
<< "Could not connect to endpoint '" << client->endpoint()
<< "', username: '" << client->username() << "'";
}
std::string errorMsg = "could not connect";
@ -274,8 +315,7 @@ static V8ClientConnection* CreateV8ClientConnection(
////////////////////////////////////////////////////////////////////////////////
static void ClientConnection_DestructorCallback(
const v8::WeakCallbackInfo<v8::Persistent<v8::External>>&
data) {
const v8::WeakCallbackInfo<v8::Persistent<v8::External>>& data) {
auto persistent = data.GetParameter();
auto myConnection =
v8::Local<v8::External>::New(data.GetIsolate(), *persistent);
@ -335,14 +375,14 @@ static void ClientConnection_ConstructorCallback(
CreateV8ClientConnection(connection, client));
if (v8connection->isConnected() &&
v8connection->lastHttpReturnCode() ==
(int)rest::ResponseCode::OK) {
LOG_TOPIC(INFO, arangodb::Logger::FIXME) << "Connected to ArangoDB "
<< "'" << v8connection->endpointSpecification() << "', "
<< "version " << v8connection->version() << " ["
<< v8connection->mode() << "], "
<< "database '" << v8connection->databaseName() << "', "
<< "username: '" << v8connection->username() << "'";
v8connection->lastHttpReturnCode() == (int)rest::ResponseCode::OK) {
LOG_TOPIC(INFO, arangodb::Logger::FIXME)
<< "Connected to ArangoDB "
<< "'" << v8connection->endpointSpecification() << "', "
<< "version " << v8connection->version() << " [" << v8connection->mode()
<< "], "
<< "database '" << v8connection->databaseName() << "', "
<< "username: '" << v8connection->username() << "'";
} else {
std::string errorMessage =
@ -394,7 +434,7 @@ static void ClientConnection_reconnect(
std::string password;
if (args.Length() < 4) {
ConsoleFeature* console =
ConsoleFeature* console =
ApplicationServer::getFeature<ConsoleFeature>("Console");
if (console->isEnabled()) {
@ -428,9 +468,10 @@ static void ClientConnection_reconnect(
TRI_V8_THROW_EXCEPTION_PARAMETER(errorMessage.c_str());
}
TRI_ExecuteJavaScriptString(isolate, isolate->GetCurrentContext(),
TRI_V8_STRING(isolate, "require('internal').db._flushCache();"),
TRI_V8_ASCII_STRING(isolate, "reload db object"), false);
TRI_ExecuteJavaScriptString(
isolate, isolate->GetCurrentContext(),
TRI_V8_STRING(isolate, "require('internal').db._flushCache();"),
TRI_V8_ASCII_STRING(isolate, "reload db object"), false);
TRI_V8_RETURN_TRUE();
TRI_V8_TRY_CATCH_END
@ -956,7 +997,8 @@ static void ClientConnection_importCsv(
}
// extract the options
v8::Handle<v8::String> separatorKey = TRI_V8_ASCII_STRING(isolate, "separator");
v8::Handle<v8::String> separatorKey =
TRI_V8_ASCII_STRING(isolate, "separator");
v8::Handle<v8::String> quoteKey = TRI_V8_ASCII_STRING(isolate, "quote");
std::string separator = ",";
@ -1025,7 +1067,7 @@ static void ClientConnection_importCsv(
for (std::string const& msg : ih.getErrorMessages()) {
error.append(msg + ";\t");
}
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
TRI_V8_TRY_CATCH_END
}
@ -1089,7 +1131,7 @@ static void ClientConnection_importJson(
TRI_V8_RETURN(result);
}
std::string error = "error messages:";
for (std::string const& msg : ih.getErrorMessages()) {
error.append(msg + ";\t");
@ -1174,7 +1216,7 @@ static void ClientConnection_isConnected(
if (v8connection->isConnected()) {
TRI_V8_RETURN_TRUE();
}
}
TRI_V8_RETURN_FALSE();
TRI_V8_TRY_CATCH_END
}
@ -1411,7 +1453,7 @@ v8::Handle<v8::Value> V8ClientConnection::requestDataRaw(
_httpResult->setHttpReturnCode(500);
_httpResult->setResultType(SimpleHttpResult::COULD_NOT_CONNECT);
}
v8::Handle<v8::Object> result = v8::Object::New(isolate);
TRI_ASSERT(_httpResult != nullptr);
@ -1452,7 +1494,7 @@ v8::Handle<v8::Value> V8ClientConnection::requestDataRaw(
}
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
v8::Boolean::New(isolate, true));
v8::Boolean::New(isolate, true));
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorNum),
v8::Integer::New(isolate, errorNumber));
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorMessage),
@ -1473,14 +1515,14 @@ v8::Handle<v8::Value> V8ClientConnection::requestDataRaw(
std::string returnMessage(_httpResult->getHttpReturnMessage());
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
v8::Boolean::New(isolate, true));
v8::Boolean::New(isolate, true));
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorNum),
v8::Integer::New(isolate, _lastHttpReturnCode));
v8::Integer::New(isolate, _lastHttpReturnCode));
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorMessage),
TRI_V8_STD_STRING(isolate, returnMessage));
TRI_V8_STD_STRING(isolate, returnMessage));
} else {
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
v8::Boolean::New(isolate, false));
v8::Boolean::New(isolate, false));
}
// got a body, copy it into the result
@ -1609,7 +1651,8 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> connection_templ =
v8::FunctionTemplate::New(isolate);
connection_templ->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoConnection"));
connection_templ->SetClassName(
TRI_V8_ASCII_STRING(isolate, "ArangoConnection"));
v8::Local<v8::ObjectTemplate> connection_proto =
connection_templ->PrototypeTemplate();
@ -1622,8 +1665,9 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
isolate, "DELETE_RAW",
v8::FunctionTemplate::New(isolate, ClientConnection_httpDeleteRaw));
connection_proto->Set(isolate, "GET", v8::FunctionTemplate::New(
isolate, ClientConnection_httpGet));
connection_proto->Set(
isolate, "GET",
v8::FunctionTemplate::New(isolate, ClientConnection_httpGet));
connection_proto->Set(
isolate, "GET_RAW",
@ -1661,8 +1705,9 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
isolate, "POST_RAW",
v8::FunctionTemplate::New(isolate, ClientConnection_httpPostRaw));
connection_proto->Set(isolate, "PUT", v8::FunctionTemplate::New(
isolate, ClientConnection_httpPut));
connection_proto->Set(
isolate, "PUT",
v8::FunctionTemplate::New(isolate, ClientConnection_httpPut));
connection_proto->Set(
isolate, "PUT_RAW",
v8::FunctionTemplate::New(isolate, ClientConnection_httpPutRaw));
@ -1690,10 +1735,10 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
connection_proto->Set(
isolate, "reconnect",
v8::FunctionTemplate::New(isolate, ClientConnection_reconnect, v8client));
connection_proto->Set(
isolate, "connectedUser",
v8::FunctionTemplate::New(isolate, ClientConnection_connectedUser, v8client));
connection_proto->Set(isolate, "connectedUser",
v8::FunctionTemplate::New(
isolate, ClientConnection_connectedUser, v8client));
connection_proto->Set(
isolate, "toString",

View File

@ -38,7 +38,7 @@ namespace httpclient {
class GeneralClientConnection;
class SimpleHttpClient;
class SimpleHttpResult;
}
} // namespace httpclient
////////////////////////////////////////////////////////////////////////////////
/// @brief class for http requests
@ -48,6 +48,13 @@ class V8ClientConnection {
V8ClientConnection(V8ClientConnection const&) = delete;
V8ClientConnection& operator=(V8ClientConnection const&) = delete;
public:
static void setJwtSecret(std::string const& jwtSecret) { JWT_SECRET = jwtSecret; }
static std::string jwtToken(std::string const& secret);
private:
static std::string JWT_SECRET;
public:
V8ClientConnection(
std::unique_ptr<httpclient::GeneralClientConnection>& connection,
@ -104,7 +111,8 @@ class V8ClientConnection {
static std::string rewriteLocation(void*, std::string const&);
private:
void init(std::unique_ptr<httpclient::GeneralClientConnection>&, std::string const&, std::string const&, std::string const&);
void init(std::unique_ptr<httpclient::GeneralClientConnection>&,
std::string const&, std::string const&, std::string const&);
v8::Handle<v8::Value> requestData(
v8::Isolate* isolate, rest::RequestType method,
@ -132,6 +140,6 @@ class V8ClientConnection {
std::string _version;
std::string _mode;
};
}
} // namespace arangodb
#endif

View File

@ -27,8 +27,8 @@
#include "Basics/ArangoGlobalContext.h"
#include "Basics/FileUtils.h"
#include "Basics/StringUtils.h"
#include "Basics/terminal-utils.h"
#include "Basics/Utf8Helper.h"
#include "Basics/terminal-utils.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
@ -101,13 +101,13 @@ void V8ShellFeature::validateOptions(
FATAL_ERROR_EXIT();
}
LOG_TOPIC(DEBUG, Logger::V8) << "using Javascript startup files at '"
<< _startupDirectory << "'";
LOG_TOPIC(DEBUG, Logger::V8)
<< "using Javascript startup files at '" << _startupDirectory << "'";
if (!_moduleDirectory.empty()) {
LOG_TOPIC(DEBUG, Logger::V8) << "using Javascript modules at '"
<< StringUtils::join(_moduleDirectory, ";")
<< "'";
LOG_TOPIC(DEBUG, Logger::V8)
<< "using Javascript modules at '"
<< StringUtils::join(_moduleDirectory, ";") << "'";
}
}
@ -281,6 +281,12 @@ V8ClientConnection* V8ShellFeature::setup(
client = dynamic_cast<ClientFeature*>(server()->feature("Client"));
if (client != nullptr && client->isEnabled()) {
auto jwtSecret = client->jwtSecret();
if (!jwtSecret.empty()) {
V8ClientConnection::setJwtSecret(jwtSecret);
}
auto connection = client->createConnection();
v8connection = std::make_unique<V8ClientConnection>(
connection, client->databaseName(), client->username(),
@ -354,7 +360,8 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
std::string input =
v8LineEditor.prompt(prompt._colored, prompt._plain, eof);
if (eof == ShellBase::EOF_FORCE_ABORT || (eof == ShellBase::EOF_ABORT && lastEmpty)) {
if (eof == ShellBase::EOF_FORCE_ABORT ||
(eof == ShellBase::EOF_ABORT && lastEmpty)) {
break;
}
@ -444,7 +451,7 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
V8PlatformFeature::resetOutOfMemory(_isolate);
}
}
if (!_console->quiet()) {
_console->printLine("");
_console->printByeBye();
@ -473,7 +480,8 @@ bool V8ShellFeature::runScript(std::vector<std::string> const& files,
for (auto const& file : files) {
if (!FileUtils::exists(file)) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error: Javascript file not found: '" << file << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "error: Javascript file not found: '" << file << "'";
ok = false;
continue;
}
@ -598,7 +606,8 @@ bool V8ShellFeature::jslint(std::vector<std::string> const& files) {
uint32_t i = 0;
for (auto& file : files) {
if (!FileUtils::exists(file)) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error: Javascript file not found: '" << file << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "error: Javascript file not found: '" << file << "'";
ok = false;
continue;
}
@ -610,9 +619,8 @@ bool V8ShellFeature::jslint(std::vector<std::string> const& files) {
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"),
sysTestFiles);
context->Global()->Set(
TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
v8::True(_isolate));
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
v8::True(_isolate));
// run tests
auto input = TRI_V8_ASCII_STRING(
@ -624,7 +632,8 @@ bool V8ShellFeature::jslint(std::vector<std::string> const& files) {
TRI_ExecuteJavaScriptString(_isolate, context, input, name, true);
if (tryCatch.HasCaught()) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << TRI_StringifyV8Exception(_isolate, &tryCatch);
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< TRI_StringifyV8Exception(_isolate, &tryCatch);
ok = false;
} else {
bool res = TRI_ObjectToBoolean(context->Global()->Get(
@ -660,7 +669,8 @@ bool V8ShellFeature::runUnitTests(std::vector<std::string> const& files,
for (auto const& file : files) {
if (!FileUtils::exists(file)) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error: Javascript file not found: '" << file << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "error: Javascript file not found: '" << file << "'";
ok = false;
continue;
}
@ -669,15 +679,13 @@ bool V8ShellFeature::runUnitTests(std::vector<std::string> const& files,
++i;
}
TRI_AddGlobalVariableVocbase(_isolate,
TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"),
sysTestFiles);
TRI_AddGlobalVariableVocbase(
_isolate, TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"), sysTestFiles);
// do not use TRI_AddGlobalVariableVocBase because it creates read-only
// variables!!
context->Global()->Set(
TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
v8::True(_isolate));
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
v8::True(_isolate));
// run tests
auto input = TRI_V8_ASCII_STRING(
@ -866,19 +874,19 @@ void V8ShellFeature::initGlobals() {
v8::FunctionTemplate::New(_isolate, JS_CompareString)->GetFunction());
TRI_AddGlobalVariableVocbase(
_isolate,
TRI_V8_ASCII_STRING(_isolate, "ARANGODB_CLIENT_VERSION"),
_isolate, TRI_V8_ASCII_STRING(_isolate, "ARANGODB_CLIENT_VERSION"),
v8::FunctionTemplate::New(_isolate, JS_VersionClient)->GetFunction());
// is quite
TRI_AddGlobalVariableVocbase(_isolate,
TRI_AddGlobalVariableVocbase(_isolate,
TRI_V8_ASCII_STRING(_isolate, "ARANGO_QUIET"),
v8::Boolean::New(_isolate, _console->quiet()));
auto ctx = ArangoGlobalContext::CONTEXT;
if (ctx == nullptr) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "failed to get global context. ";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "failed to get global context. ";
FATAL_ERROR_EXIT();
}
@ -1002,15 +1010,17 @@ void V8ShellFeature::loadModules(ShellFeature::RunMode runMode) {
for (size_t i = 0; i < files.size(); ++i) {
switch (loader.loadScript(_isolate, context, files[i], nullptr)) {
case JSLoader::eSuccess:
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loaded JavaScript file '" << files[i] << "'";
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "loaded JavaScript file '" << files[i] << "'";
break;
case JSLoader::eFailLoad:
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "cannot load JavaScript file '" << files[i] << "'";
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
<< "cannot load JavaScript file '" << files[i] << "'";
FATAL_ERROR_EXIT();
break;
case JSLoader::eFailExecute:
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "error during execution of JavaScript file '" << files[i]
<< "'";
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
<< "error during execution of JavaScript file '" << files[i] << "'";
FATAL_ERROR_EXIT();
break;
}

View File

@ -60,7 +60,7 @@ int main(int argc, char* argv[]) {
int ret = EXIT_SUCCESS;
try {
server.addFeature(new ClientFeature(&server));
server.addFeature(new ClientFeature(&server, true));
server.addFeature(new ConfigFeature(&server, name));
server.addFeature(new ConsoleFeature(&server));
server.addFeature(new LanguageFeature(&server));

View File

@ -96,7 +96,7 @@ SimpleHttpClient::~SimpleHttpClient() {
// -----------------------------------------------------------------------------
// public methods
// -----------------------------------------------------------------------------
void SimpleHttpClient::setAborted(bool value) noexcept {
_aborted.store(value, std::memory_order_release);
setInterrupted(value);
@ -160,7 +160,7 @@ SimpleHttpResult* SimpleHttpClient::retryRequest(
std::unordered_map<std::string, std::string> const& headers) {
SimpleHttpResult* result = nullptr;
size_t tries = 0;
while (true) {
TRI_ASSERT(result == nullptr);
@ -174,18 +174,19 @@ SimpleHttpResult* SimpleHttpClient::retryRequest(
result = nullptr;
if (tries++ >= _params._maxRetries) {
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT) << "" << _params._retryMessage
<< " - no retries left";
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT)
<< "" << _params._retryMessage << " - no retries left";
break;
}
if (isAborted()) {
break;
}
if (!_params._retryMessage.empty() && (_params._maxRetries - tries) > 0) {
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT) << "" << _params._retryMessage
<< " - retries left: " << (_params._maxRetries - tries);
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT)
<< "" << _params._retryMessage
<< " - retries left: " << (_params._maxRetries - tries);
}
// 1 microsecond == 10^-6 seconds
@ -352,7 +353,8 @@ SimpleHttpResult* SimpleHttpClient::doRequest(
// progress is made (but without an error), this then means
// that the server has closed the connection and we must
// process the body one more time:
_result->setContentLength(_readBuffer.length() - _readBufferOffset);
_result->setContentLength(_readBuffer.length() -
_readBufferOffset);
}
processBody();
}
@ -530,9 +532,11 @@ void SimpleHttpClient::setRequest(
// append hostname
std::string hostname = _connection->getEndpoint()->host();
LOG_TOPIC(DEBUG, Logger::HTTPCLIENT) << "request to " << hostname << ": " << GeneralRequest::translateMethod(method) << ' ' << *l;
LOG_TOPIC(DEBUG, Logger::HTTPCLIENT)
<< "request to " << hostname << ": "
<< GeneralRequest::translateMethod(method) << ' ' << *l;
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Host: "));
_writeBuffer.appendText(hostname);
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
@ -554,15 +558,14 @@ void SimpleHttpClient::setRequest(
}
// do basic authorization
if (!_params._basicAuth.empty()) {
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: Basic "));
_writeBuffer.appendText(_params._basicAuth);
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
}
if (!_params._jwt.empty()) {
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: bearer "));
_writeBuffer.appendText(_params._jwt);
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
} else if (!_params._basicAuth.empty()) {
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: Basic "));
_writeBuffer.appendText(_params._basicAuth);
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
}
for (auto const& header : headers) {
@ -682,8 +685,11 @@ void SimpleHttpClient::processHeader() {
// found content-length header in response
else if (_result->hasContentLength() && _result->getContentLength() > 0) {
if (_result->getContentLength() > _params._maxPacketSize) {
std::string errorMessage("ignoring HTTP response with 'Content-Length' bigger than max packet size (");
errorMessage += std::to_string(_result->getContentLength()) + " > " + std::to_string(_params._maxPacketSize) + ")";
std::string errorMessage(
"ignoring HTTP response with 'Content-Length' bigger than max "
"packet size (");
errorMessage += std::to_string(_result->getContentLength()) + " > " +
std::to_string(_params._maxPacketSize) + ")";
setErrorMessage(errorMessage, true);
// reset connection
@ -725,7 +731,6 @@ void SimpleHttpClient::processHeader() {
TRI_ASSERT(ptr == _readBuffer.c_str() + _readBufferOffset);
TRI_ASSERT(remain == _readBuffer.length() - _readBufferOffset);
pos = static_cast<char const*>(memchr(ptr, '\n', remain));
}
}
}
@ -830,8 +835,11 @@ void SimpleHttpClient::processChunkedHeader() {
// failed: too many bytes
if (contentLength > _params._maxPacketSize) {
std::string errorMessage("ignoring HTTP response with 'Content-Length' bigger than max packet size (");
errorMessage += std::to_string(contentLength) + " > " + std::to_string(_params._maxPacketSize) + ")";
std::string errorMessage(
"ignoring HTTP response with 'Content-Length' bigger than max packet "
"size (");
errorMessage += std::to_string(contentLength) + " > " +
std::to_string(_params._maxPacketSize) + ")";
setErrorMessage(errorMessage, true);
// reset connection
this->close();
@ -883,7 +891,7 @@ void SimpleHttpClient::processChunkedBody() {
}
_readBufferOffset += (size_t)_nextChunkedSize + 2;
_state = IN_READ_CHUNKED_HEADER;
processChunkedHeader();
}
@ -987,5 +995,5 @@ std::string SimpleHttpClient::getServerVersion(int* errorCode) {
return "";
}
}
}
} // namespace httpclient
} // namespace arangodb

View File

@ -93,10 +93,7 @@ struct SimpleHttpClientParams {
void setJwt(std::string const& jwt) { _jwt = jwt; }
////////////////////////////////////////////////////////////////////////////////
/// @brief sets username and password
////////////////////////////////////////////////////////////////////////////////
// sets username and password
void setUserNamePassword(char const* prefix,
std::string const& username,
std::string const& password) {