mirror of https://gitee.com/bigwinds/arangodb
WIP
This commit is contained in:
parent
9dbba248de
commit
806fce1dec
|
@ -33,8 +33,7 @@ using namespace arangodb;
|
|||
using namespace arangodb::basics;
|
||||
using namespace arangodb::rest;
|
||||
|
||||
RestActionHandler::RestActionHandler(HttpRequest* request,
|
||||
action_options_t* data)
|
||||
RestActionHandler::RestActionHandler(HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request),
|
||||
_action(nullptr),
|
||||
_dataLock(),
|
||||
|
@ -44,7 +43,7 @@ RestActionHandler::RestActionHandler(HttpRequest* request,
|
|||
|
||||
bool RestActionHandler::isDirect() const { return _action == nullptr; }
|
||||
|
||||
HttpHandler::status_t RestActionHandler::execute() {
|
||||
RestHandler::status RestActionHandler::execute() {
|
||||
TRI_action_result_t result;
|
||||
|
||||
// check the request path
|
||||
|
@ -85,7 +84,8 @@ HttpHandler::status_t RestActionHandler::execute() {
|
|||
}
|
||||
|
||||
// handler has finished, generate result
|
||||
return status_t(result.isValid ? HANDLER_DONE : HANDLER_FAILED);
|
||||
return result.isValid ? RestHandler::status::DONE
|
||||
: RestHandler::status::FAILED;
|
||||
}
|
||||
|
||||
bool RestActionHandler::cancel() { return _action->cancel(&_dataLock, &_data); }
|
||||
|
|
|
@ -31,55 +31,27 @@
|
|||
class TRI_action_t;
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief action request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestActionHandler : public RestVocbaseBaseHandler {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor options
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct action_options_t {
|
||||
TRI_vocbase_t* _vocbase;
|
||||
};
|
||||
|
||||
public:
|
||||
RestActionHandler(HttpRequest*, action_options_t*);
|
||||
RestActionHandler(HttpRequest*);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
|
||||
status execute() override;
|
||||
bool cancel() override;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes an action
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// executes an action
|
||||
TRI_action_result_t executeAction();
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief action
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// action
|
||||
TRI_action_t* _action;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief data lock
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// data lock
|
||||
Mutex _dataLock;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief data for cancelation
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// data for cancelation
|
||||
void* _data;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/GeneralRequest.h"
|
||||
|
||||
using namespace arangodb::basics;
|
||||
|
||||
|
@ -111,7 +111,7 @@ TRI_action_t* TRI_DefineActionVocBase(std::string const& name,
|
|||
/// @brief looks up an action
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_action_t* TRI_LookupActionVocBase(arangodb::HttpRequest* request) {
|
||||
TRI_action_t* TRI_LookupActionVocBase(arangodb::GeneralRequest* request) {
|
||||
// check if we know a callback
|
||||
std::vector<std::string> suffix = request->suffix();
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
struct TRI_vocbase_t;
|
||||
|
||||
namespace arangodb {
|
||||
class HttpRequest;
|
||||
class HttpResponse;
|
||||
class GeneralRequest;
|
||||
class GeneralResponse;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -54,7 +54,7 @@ class TRI_action_result_t {
|
|||
bool isValid;
|
||||
bool canceled;
|
||||
|
||||
arangodb::HttpResponse* response;
|
||||
arangodb::GeneralResponse* response;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -73,7 +73,7 @@ class TRI_action_t {
|
|||
virtual ~TRI_action_t() {}
|
||||
|
||||
virtual TRI_action_result_t execute(TRI_vocbase_t*,
|
||||
arangodb::HttpRequest*,
|
||||
arangodb::GeneralRequest*,
|
||||
arangodb::Mutex* dataLock,
|
||||
void** data) = 0;
|
||||
|
||||
|
@ -99,7 +99,7 @@ TRI_action_t* TRI_DefineActionVocBase(std::string const& name,
|
|||
/// @brief looks up an action
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_action_t* TRI_LookupActionVocBase(arangodb::HttpRequest* request);
|
||||
TRI_action_t* TRI_LookupActionVocBase(arangodb::GeneralRequest* request);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief deletes all defined actions
|
||||
|
|
|
@ -47,25 +47,25 @@ RestAgencyHandler::RestAgencyHandler(HttpRequest* request, Agent* agent)
|
|||
|
||||
bool RestAgencyHandler::isDirect() const { return false; }
|
||||
|
||||
inline HttpHandler::status_t RestAgencyHandler::reportErrorEmptyRequest() {
|
||||
inline RestHandler::status RestAgencyHandler::reportErrorEmptyRequest() {
|
||||
LOG_TOPIC(WARN, Logger::AGENCY)
|
||||
<< "Empty request to public agency interface.";
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND, 404);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
inline HttpHandler::status_t RestAgencyHandler::reportTooManySuffices() {
|
||||
inline RestHandler::status RestAgencyHandler::reportTooManySuffices() {
|
||||
LOG_TOPIC(WARN, Logger::AGENCY)
|
||||
<< "Too many suffixes. Agency public interface takes one path.";
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND, 404);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
inline HttpHandler::status_t RestAgencyHandler::reportUnknownMethod() {
|
||||
inline RestHandler::status RestAgencyHandler::reportUnknownMethod() {
|
||||
LOG_TOPIC(WARN, Logger::AGENCY) << "Public REST interface has no method "
|
||||
<< _request->suffix()[0];
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND, 405);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
void RestAgencyHandler::redirectRequest(arangodb::consensus::id_t leaderId) {
|
||||
|
@ -83,7 +83,7 @@ void RestAgencyHandler::redirectRequest(arangodb::consensus::id_t leaderId) {
|
|||
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestAgencyHandler::handleStores () {
|
||||
RestHandler::status RestAgencyHandler::handleStores () {
|
||||
if (_request->requestType() == GeneralRequest::RequestType::GET) {
|
||||
Builder body;
|
||||
body.openObject();
|
||||
|
@ -98,10 +98,10 @@ HttpHandler::status_t RestAgencyHandler::handleStores () {
|
|||
} else {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, 400);
|
||||
}
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestAgencyHandler::handleWrite () {
|
||||
RestHandler::status RestAgencyHandler::handleWrite () {
|
||||
arangodb::velocypack::Options options; // TODO: User not wait.
|
||||
if (_request->requestType() == GeneralRequest::RequestType::POST) {
|
||||
query_t query;
|
||||
|
@ -115,7 +115,7 @@ HttpHandler::status_t RestAgencyHandler::handleWrite () {
|
|||
body.add("message", VPackValue(e.what()));
|
||||
body.close();
|
||||
generateResult(GeneralResponse::ResponseCode::BAD, body.slice());
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
write_ret_t ret = _agent->write(query);
|
||||
|
@ -162,16 +162,16 @@ HttpHandler::status_t RestAgencyHandler::handleWrite () {
|
|||
} else { // Unknown method
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED, 405);
|
||||
}
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
/*inline HttpHandler::status_t RestAgencyHandler::handleReplicate () {
|
||||
/*inline RestHandler::status RestAgencyHandler::handleReplicate () {
|
||||
if (_request->requestType() == GeneralRequest::RequestType::POST) {
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
inline HttpHandler::status_t RestAgencyHandler::handleRead() {
|
||||
inline RestHandler::status RestAgencyHandler::handleRead() {
|
||||
arangodb::velocypack::Options options;
|
||||
if (_request->requestType() == GeneralRequest::RequestType::POST) {
|
||||
query_t query;
|
||||
|
@ -180,7 +180,7 @@ inline HttpHandler::status_t RestAgencyHandler::handleRead() {
|
|||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, Logger::AGENCY) << e.what();
|
||||
generateError(GeneralResponse::ResponseCode::BAD, 400);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
read_ret_t ret = _agent->read (query);
|
||||
|
||||
|
@ -192,16 +192,16 @@ inline HttpHandler::status_t RestAgencyHandler::handleRead() {
|
|||
}
|
||||
} else { // Redirect to leader
|
||||
redirectRequest(ret.redirect);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
} else {
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED, 405);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestAgencyHandler::handleConfig() {
|
||||
RestHandler::status RestAgencyHandler::handleConfig() {
|
||||
Builder body;
|
||||
body.add(VPackValue(VPackValueType::Object));
|
||||
body.add("term", Value(_agent->term()));
|
||||
|
@ -209,10 +209,10 @@ HttpHandler::status_t RestAgencyHandler::handleConfig() {
|
|||
body.add("configuration", _agent->config().toBuilder()->slice());
|
||||
body.close();
|
||||
generateResult(GeneralResponse::ResponseCode::OK, body.slice());
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestAgencyHandler::handleState() {
|
||||
RestHandler::status RestAgencyHandler::handleState() {
|
||||
Builder body;
|
||||
body.add(VPackValue(VPackValueType::Array));
|
||||
for (auto const& i : _agent->state().get()) {
|
||||
|
@ -225,15 +225,15 @@ HttpHandler::status_t RestAgencyHandler::handleState() {
|
|||
}
|
||||
body.close();
|
||||
generateResult(GeneralResponse::ResponseCode::OK, body.slice());
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
inline HttpHandler::status_t RestAgencyHandler::reportMethodNotAllowed() {
|
||||
inline RestHandler::status RestAgencyHandler::reportMethodNotAllowed() {
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED, 405);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestAgencyHandler::execute() {
|
||||
RestHandler::status RestAgencyHandler::execute() {
|
||||
try {
|
||||
if (_request->suffix().size() == 0) { // Empty request
|
||||
return reportErrorEmptyRequest();
|
||||
|
@ -263,5 +263,5 @@ HttpHandler::status_t RestAgencyHandler::execute() {
|
|||
} catch (...) {
|
||||
// Ignore this error
|
||||
}
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
|
|
@ -37,20 +37,20 @@ class RestAgencyHandler : public RestBaseHandler {
|
|||
public:
|
||||
RestAgencyHandler(HttpRequest*, consensus::Agent*);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
|
||||
private:
|
||||
status_t reportErrorEmptyRequest();
|
||||
status_t reportTooManySuffices();
|
||||
status_t reportUnknownMethod();
|
||||
status_t handleStores();
|
||||
status_t handleRead();
|
||||
status_t handleWrite();
|
||||
status_t handleConfig();
|
||||
status_t reportMethodNotAllowed();
|
||||
status_t handleState();
|
||||
status reportErrorEmptyRequest();
|
||||
status reportTooManySuffices();
|
||||
status reportUnknownMethod();
|
||||
status handleStores();
|
||||
status handleRead();
|
||||
status handleWrite();
|
||||
status handleConfig();
|
||||
status reportMethodNotAllowed();
|
||||
status handleState();
|
||||
|
||||
void redirectRequest(arangodb::consensus::id_t leaderId);
|
||||
consensus::Agent* _agent;
|
||||
|
|
|
@ -49,29 +49,29 @@ RestAgencyPrivHandler::RestAgencyPrivHandler(HttpRequest* request, Agent* agent)
|
|||
|
||||
bool RestAgencyPrivHandler::isDirect() const { return false; }
|
||||
|
||||
inline HttpHandler::status_t RestAgencyPrivHandler::reportErrorEmptyRequest() {
|
||||
inline RestHandler::status RestAgencyPrivHandler::reportErrorEmptyRequest() {
|
||||
LOG(WARN) << "Empty request to agency!";
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND, 404);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
inline HttpHandler::status_t RestAgencyPrivHandler::reportTooManySuffices() {
|
||||
inline RestHandler::status RestAgencyPrivHandler::reportTooManySuffices() {
|
||||
LOG(WARN) << "Agency handles a single suffix: vote, log or configure";
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND, 404);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
inline HttpHandler::status_t RestAgencyPrivHandler::reportBadQuery() {
|
||||
inline RestHandler::status RestAgencyPrivHandler::reportBadQuery() {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, 400);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
inline HttpHandler::status_t RestAgencyPrivHandler::reportMethodNotAllowed() {
|
||||
inline RestHandler::status RestAgencyPrivHandler::reportMethodNotAllowed() {
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED, 405);
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestAgencyPrivHandler::execute() {
|
||||
RestHandler::status RestAgencyPrivHandler::execute() {
|
||||
try {
|
||||
VPackBuilder result;
|
||||
result.add(VPackValue(VPackValueType::Object));
|
||||
|
@ -124,7 +124,7 @@ HttpHandler::status_t RestAgencyPrivHandler::execute() {
|
|||
} else {
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND,
|
||||
404); // nothing else here
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
}
|
||||
result.close();
|
||||
|
@ -133,5 +133,5 @@ HttpHandler::status_t RestAgencyPrivHandler::execute() {
|
|||
} catch (...) {
|
||||
// Ignore this error
|
||||
}
|
||||
return HttpHandler::status_t(HANDLER_DONE);
|
||||
return RestHandler::status::DONE;
|
||||
}
|
||||
|
|
|
@ -36,11 +36,11 @@ namespace arangodb {
|
|||
|
||||
class RestAgencyPrivHandler : public arangodb::RestBaseHandler {
|
||||
public:
|
||||
explicit RestAgencyPrivHandler(HttpRequest*, consensus::Agent*);
|
||||
RestAgencyPrivHandler(HttpRequest*, consensus::Agent*);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
|
@ -63,10 +63,10 @@ class RestAgencyPrivHandler : public arangodb::RestBaseHandler {
|
|||
return true;
|
||||
}
|
||||
|
||||
status_t reportErrorEmptyRequest();
|
||||
status_t reportTooManySuffices();
|
||||
status_t reportBadQuery();
|
||||
status_t reportMethodNotAllowed();
|
||||
status reportErrorEmptyRequest();
|
||||
status reportTooManySuffices();
|
||||
status reportBadQuery();
|
||||
status reportMethodNotAllowed();
|
||||
|
||||
consensus::Agent* _agent;
|
||||
};
|
||||
|
|
|
@ -59,14 +59,14 @@ RestAqlHandler::RestAqlHandler(arangodb::HttpRequest* request,
|
|||
TRI_ASSERT(_queryRegistry != nullptr);
|
||||
}
|
||||
|
||||
/// @brief returns the queue name
|
||||
// returns the queue name
|
||||
size_t RestAqlHandler::queue() const { return Dispatcher::AQL_QUEUE; }
|
||||
|
||||
bool RestAqlHandler::isDirect() const { return false; }
|
||||
|
||||
/// @brief POST method for /_api/aql/instantiate (internal)
|
||||
/// The body is a VelocyPack with attributes "plan" for the execution plan and
|
||||
/// "options" for the options, all exactly as in AQL_EXECUTEJSON.
|
||||
// POST method for /_api/aql/instantiate (internal)
|
||||
// The body is a VelocyPack with attributes "plan" for the execution plan and
|
||||
// "options" for the options, all exactly as in AQL_EXECUTEJSON.
|
||||
void RestAqlHandler::createQueryFromVelocyPack() {
|
||||
std::shared_ptr<VPackBuilder> queryBuilder = parseVelocyPackBody();
|
||||
if (queryBuilder == nullptr) {
|
||||
|
@ -143,11 +143,11 @@ void RestAqlHandler::createQueryFromVelocyPack() {
|
|||
query->trx()->transactionContext().get());
|
||||
}
|
||||
|
||||
/// @brief POST method for /_api/aql/parse (internal)
|
||||
/// The body is a Json with attributes "query" for the query string,
|
||||
/// "parameters" for the query parameters and "options" for the options.
|
||||
/// This does the same as AQL_PARSE with exactly these parameters and
|
||||
/// does not keep the query hanging around.
|
||||
// POST method for /_api/aql/parse (internal)
|
||||
// The body is a Json with attributes "query" for the query string,
|
||||
// "parameters" for the query parameters and "options" for the options.
|
||||
// This does the same as AQL_PARSE with exactly these parameters and
|
||||
// does not keep the query hanging around.
|
||||
void RestAqlHandler::parseQuery() {
|
||||
std::shared_ptr<VPackBuilder> bodyBuilder = parseVelocyPackBody();
|
||||
if (bodyBuilder == nullptr) {
|
||||
|
@ -165,9 +165,9 @@ void RestAqlHandler::parseQuery() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto query = new Query(false, _vocbase, queryString.c_str(),
|
||||
queryString.size(), std::shared_ptr<VPackBuilder>(),
|
||||
nullptr, PART_MAIN);
|
||||
auto query =
|
||||
new Query(false, _vocbase, queryString.c_str(), queryString.size(),
|
||||
std::shared_ptr<VPackBuilder>(), nullptr, PART_MAIN);
|
||||
QueryResult res = query->parse();
|
||||
if (res.code != TRI_ERROR_NO_ERROR) {
|
||||
LOG(ERR) << "failed to instantiate the Query: " << res.details;
|
||||
|
@ -210,11 +210,11 @@ void RestAqlHandler::parseQuery() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief POST method for /_api/aql/explain (internal)
|
||||
/// The body is a Json with attributes "query" for the query string,
|
||||
/// "parameters" for the query parameters and "options" for the options.
|
||||
/// This does the same as AQL_EXPLAIN with exactly these parameters and
|
||||
/// does not keep the query hanging around.
|
||||
// POST method for /_api/aql/explain (internal)
|
||||
// The body is a Json with attributes "query" for the query string,
|
||||
// "parameters" for the query parameters and "options" for the options.
|
||||
// This does the same as AQL_EXPLAIN with exactly these parameters and
|
||||
// does not keep the query hanging around.
|
||||
void RestAqlHandler::explainQuery() {
|
||||
std::shared_ptr<VPackBuilder> bodyBuilder = parseVelocyPackBody();
|
||||
if (bodyBuilder == nullptr) {
|
||||
|
@ -237,9 +237,9 @@ void RestAqlHandler::explainQuery() {
|
|||
auto options = std::make_shared<VPackBuilder>(
|
||||
VPackBuilder::clone(querySlice.get("options")));
|
||||
|
||||
auto query = std::make_unique<Query>(false, _vocbase,
|
||||
queryString.c_str(), queryString.size(),
|
||||
bindVars, options, PART_MAIN);
|
||||
auto query =
|
||||
std::make_unique<Query>(false, _vocbase, queryString.c_str(),
|
||||
queryString.size(), bindVars, options, PART_MAIN);
|
||||
QueryResult res = query->explain();
|
||||
if (res.code != TRI_ERROR_NO_ERROR) {
|
||||
LOG(ERR) << "failed to instantiate the Query: " << res.details;
|
||||
|
@ -270,12 +270,12 @@ void RestAqlHandler::explainQuery() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief POST method for /_api/aql/query (internal)
|
||||
/// The body is a Json with attributes "query" for the query string,
|
||||
/// "parameters" for the query parameters and "options" for the options.
|
||||
/// This sets up the query as as AQL_EXECUTE would, but does not use
|
||||
/// the cursor API yet. Rather, the query is stored in the query registry
|
||||
/// for later use by PUT requests.
|
||||
// POST method for /_api/aql/query (internal)
|
||||
// The body is a Json with attributes "query" for the query string,
|
||||
// "parameters" for the query parameters and "options" for the options.
|
||||
// This sets up the query as as AQL_EXECUTE would, but does not use
|
||||
// the cursor API yet. Rather, the query is stored in the query registry
|
||||
// for later use by PUT requests.
|
||||
void RestAqlHandler::createQueryFromString() {
|
||||
std::shared_ptr<VPackBuilder> queryBuilder = parseVelocyPackBody();
|
||||
if (queryBuilder == nullptr) {
|
||||
|
@ -338,63 +338,70 @@ void RestAqlHandler::createQueryFromString() {
|
|||
return;
|
||||
}
|
||||
|
||||
createResponse(GeneralResponse::ResponseCode::ACCEPTED);
|
||||
_response->setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||
arangodb::basics::Json answerBody(arangodb::basics::Json::Object, 2);
|
||||
answerBody("queryId",
|
||||
arangodb::basics::Json(arangodb::basics::StringUtils::itoa(_qId)))(
|
||||
"ttl", arangodb::basics::Json(ttl));
|
||||
_response->body().appendText(answerBody.toString());
|
||||
VPackBuilder answerBody;
|
||||
try {
|
||||
VPackObjectBuilder guard(&answerBody);
|
||||
answerBody.add("queryId",
|
||||
VPackValue(arangodb::basics::StringUtils::itoa(_qId)));
|
||||
answerBody.add("ttl", VPackValue(ttl));
|
||||
} catch (...) {
|
||||
LOG(ERR) << "could not keep query in registry";
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
sendResponse(GeneralResponse::ResponseCode::ACCEPTED, answerBody.slice(),
|
||||
query->trx()->transactionContext().get());
|
||||
}
|
||||
|
||||
/// @brief PUT method for /_api/aql/<operation>/<queryId>, (internal)
|
||||
/// this is using the part of the cursor API with side effects.
|
||||
/// <operation>: can be "lock" or "getSome" or "skip" or "initializeCursor" or
|
||||
/// "shutdown".
|
||||
/// The body must be a Json with the following attributes:
|
||||
/// For the "getSome" operation one has to give:
|
||||
/// "atLeast":
|
||||
/// "atMost": both must be positive integers, the cursor returns never
|
||||
/// more than "atMost" items and tries to return at least
|
||||
/// "atLeast". Note that it is possible to return fewer than
|
||||
/// "atLeast", for example if there are only fewer items
|
||||
/// left. However, the implementation may return fewer items
|
||||
/// than "atLeast" for internal reasons, for example to avoid
|
||||
/// excessive copying. The result is the JSON representation of an
|
||||
/// AqlItemBlock.
|
||||
/// If "atLeast" is not given it defaults to 1, if "atMost" is not
|
||||
/// given it defaults to ExecutionBlock::DefaultBatchSize.
|
||||
/// For the "skipSome" operation one has to give:
|
||||
/// "atLeast":
|
||||
/// "atMost": both must be positive integers, the cursor skips never
|
||||
/// more than "atMost" items and tries to skip at least
|
||||
/// "atLeast". Note that it is possible to skip fewer than
|
||||
/// "atLeast", for example if there are only fewer items
|
||||
/// left. However, the implementation may skip fewer items
|
||||
/// than "atLeast" for internal reasons, for example to avoid
|
||||
/// excessive copying. The result is a JSON object with a
|
||||
/// single attribute "skipped" containing the number of
|
||||
/// skipped items.
|
||||
/// If "atLeast" is not given it defaults to 1, if "atMost" is not
|
||||
/// given it defaults to ExecutionBlock::DefaultBatchSize.
|
||||
/// For the "skip" operation one should give:
|
||||
/// "number": must be a positive integer, the cursor skips as many items,
|
||||
/// possibly exhausting the cursor.
|
||||
/// The result is a JSON with the attributes "error" (boolean),
|
||||
/// "errorMessage" (if applicable) and "exhausted" (boolean)
|
||||
/// to indicate whether or not the cursor is exhausted.
|
||||
/// If "number" is not given it defaults to 1.
|
||||
/// For the "initializeCursor" operation, one has to bind the following
|
||||
/// attributes:
|
||||
/// "items": This is a serialized AqlItemBlock with usually only one row
|
||||
/// and the correct number of columns.
|
||||
/// "pos": The number of the row in "items" to take, usually 0.
|
||||
/// For the "shutdown" and "lock" operations no additional arguments are
|
||||
/// required and an empty JSON object in the body is OK.
|
||||
/// All operations allow to set the HTTP header "Shard-ID:". If this is
|
||||
/// set, then the root block of the stored query must be a ScatterBlock
|
||||
/// and the shard ID is given as an additional argument to the ScatterBlock's
|
||||
/// special API.
|
||||
// PUT method for /_api/aql/<operation>/<queryId>, (internal)
|
||||
// this is using the part of the cursor API with side effects.
|
||||
// <operation>: can be "lock" or "getSome" or "skip" or "initializeCursor" or
|
||||
// "shutdown".
|
||||
// The body must be a Json with the following attributes:
|
||||
// For the "getSome" operation one has to give:
|
||||
// "atLeast":
|
||||
// "atMost": both must be positive integers, the cursor returns never
|
||||
// more than "atMost" items and tries to return at least
|
||||
// "atLeast". Note that it is possible to return fewer than
|
||||
// "atLeast", for example if there are only fewer items
|
||||
// left. However, the implementation may return fewer items
|
||||
// than "atLeast" for internal reasons, for example to avoid
|
||||
// excessive copying. The result is the JSON representation of an
|
||||
// AqlItemBlock.
|
||||
// If "atLeast" is not given it defaults to 1, if "atMost" is not
|
||||
// given it defaults to ExecutionBlock::DefaultBatchSize.
|
||||
// For the "skipSome" operation one has to give:
|
||||
// "atLeast":
|
||||
// "atMost": both must be positive integers, the cursor skips never
|
||||
// more than "atMost" items and tries to skip at least
|
||||
// "atLeast". Note that it is possible to skip fewer than
|
||||
// "atLeast", for example if there are only fewer items
|
||||
// left. However, the implementation may skip fewer items
|
||||
// than "atLeast" for internal reasons, for example to avoid
|
||||
// excessive copying. The result is a JSON object with a
|
||||
// single attribute "skipped" containing the number of
|
||||
// skipped items.
|
||||
// If "atLeast" is not given it defaults to 1, if "atMost" is not
|
||||
// given it defaults to ExecutionBlock::DefaultBatchSize.
|
||||
// For the "skip" operation one should give:
|
||||
// "number": must be a positive integer, the cursor skips as many items,
|
||||
// possibly exhausting the cursor.
|
||||
// The result is a JSON with the attributes "error" (boolean),
|
||||
// "errorMessage" (if applicable) and "exhausted" (boolean)
|
||||
// to indicate whether or not the cursor is exhausted.
|
||||
// If "number" is not given it defaults to 1.
|
||||
// For the "initializeCursor" operation, one has to bind the following
|
||||
// attributes:
|
||||
// "items": This is a serialized AqlItemBlock with usually only one row
|
||||
// and the correct number of columns.
|
||||
// "pos": The number of the row in "items" to take, usually 0.
|
||||
// For the "shutdown" and "lock" operations no additional arguments are
|
||||
// required and an empty JSON object in the body is OK.
|
||||
// All operations allow to set the HTTP header "Shard-ID:". If this is
|
||||
// set, then the root block of the stored query must be a ScatterBlock
|
||||
// and the shard ID is given as an additional argument to the ScatterBlock's
|
||||
// special API.
|
||||
void RestAqlHandler::useQuery(std::string const& operation,
|
||||
std::string const& idString) {
|
||||
// the PUT verb
|
||||
|
@ -442,23 +449,22 @@ void RestAqlHandler::useQuery(std::string const& operation,
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief GET method for /_api/aql/<operation>/<queryId>, (internal)
|
||||
/// this is using
|
||||
/// the part of the cursor API without side effects. The operation must
|
||||
/// be one of "count", "remaining" and "hasMore". The result is a Json
|
||||
/// with, depending on the operation, the following attributes:
|
||||
/// for "count": the result has the attributes "error" (set to false)
|
||||
/// and "count" set to the total number of documents.
|
||||
/// for "remaining": the result has the attributes "error" (set to false)
|
||||
/// and "remaining" set to the total number of documents.
|
||||
/// for "hasMore": the result has the attributes "error" (set to false)
|
||||
/// and "hasMore" set to a boolean value.
|
||||
/// Note that both "count" and "remaining" may return "unknown" if the
|
||||
/// internal cursor API returned -1.
|
||||
// GET method for /_api/aql/<operation>/<queryId>, (internal)
|
||||
// this is using
|
||||
// the part of the cursor API without side effects. The operation must
|
||||
// be one of "count", "remaining" and "hasMore". The result is a Json
|
||||
// with, depending on the operation, the following attributes:
|
||||
// for "count": the result has the attributes "error" (set to false)
|
||||
// and "count" set to the total number of documents.
|
||||
// for "remaining": the result has the attributes "error" (set to false)
|
||||
// and "remaining" set to the total number of documents.
|
||||
// for "hasMore": the result has the attributes "error" (set to false)
|
||||
// and "hasMore" set to a boolean value.
|
||||
// Note that both "count" and "remaining" may return "unknown" if the
|
||||
// internal cursor API returned -1.
|
||||
|
||||
void RestAqlHandler::getInfoQuery(std::string const& operation,
|
||||
std::string const& idString) {
|
||||
// the GET verb
|
||||
|
||||
bool found;
|
||||
std::string shardId;
|
||||
std::string const& shardIdCharP = _request->header("shard-id", found);
|
||||
|
@ -474,19 +480,18 @@ void RestAqlHandler::getInfoQuery(std::string const& operation,
|
|||
|
||||
TRI_ASSERT(_qId > 0);
|
||||
|
||||
arangodb::basics::Json answerBody(arangodb::basics::Json::Object, 2);
|
||||
|
||||
TRI_ASSERT(query->engine() != nullptr);
|
||||
|
||||
VPackBuilder answerBody;
|
||||
try {
|
||||
VPackObjectBuilder guard(&answerBody);
|
||||
|
||||
int64_t number;
|
||||
|
||||
if (operation == "count") {
|
||||
number = query->engine()->count();
|
||||
if (number == -1) {
|
||||
answerBody("count", arangodb::basics::Json("unknown"));
|
||||
answerBody.add("count", VPackValue("unknown"));
|
||||
} else {
|
||||
answerBody("count",
|
||||
arangodb::basics::Json(static_cast<double>(number)));
|
||||
answerBody.add("count", VPackValue(number));
|
||||
}
|
||||
} else if (operation == "remaining") {
|
||||
if (shardId.empty()) {
|
||||
|
@ -500,10 +505,9 @@ void RestAqlHandler::getInfoQuery(std::string const& operation,
|
|||
number = block->remainingForShard(shardId);
|
||||
}
|
||||
if (number == -1) {
|
||||
answerBody("remaining", arangodb::basics::Json("unknown"));
|
||||
answerBody.add("remaining", VPackValue("unknown"));
|
||||
} else {
|
||||
answerBody("remaining",
|
||||
arangodb::basics::Json(static_cast<double>(number)));
|
||||
answerBody.add("remaining", VPackValue(number));
|
||||
}
|
||||
} else if (operation == "hasMore") {
|
||||
bool hasMore;
|
||||
|
@ -518,7 +522,7 @@ void RestAqlHandler::getInfoQuery(std::string const& operation,
|
|||
hasMore = block->hasMoreForShard(shardId);
|
||||
}
|
||||
|
||||
answerBody("hasMore", arangodb::basics::Json(hasMore));
|
||||
answerBody.add("hasMore", VPackValue(hasMore));
|
||||
} else {
|
||||
_queryRegistry->close(_vocbase, _qId);
|
||||
LOG(ERR) << "referenced query not found";
|
||||
|
@ -526,6 +530,8 @@ void RestAqlHandler::getInfoQuery(std::string const& operation,
|
|||
TRI_ERROR_HTTP_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
answerBody.add("error", VPackValue(false));
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
_queryRegistry->close(_vocbase, _qId);
|
||||
LOG(ERR) << "failed during use of query: " << ex.message();
|
||||
|
@ -549,16 +555,14 @@ void RestAqlHandler::getInfoQuery(std::string const& operation,
|
|||
|
||||
_queryRegistry->close(_vocbase, _qId);
|
||||
|
||||
createResponse(GeneralResponse::ResponseCode::OK);
|
||||
_response->setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||
answerBody("error", arangodb::basics::Json(false));
|
||||
_response->body().appendText(answerBody.toString());
|
||||
sendResponse(GeneralResponse::ResponseCode::OK, answerBody.slice(),
|
||||
query->trx()->transactionContext().get());
|
||||
}
|
||||
|
||||
/// @brief executes the handler
|
||||
arangodb::rest::HttpHandler::status_t RestAqlHandler::execute() {
|
||||
// executes the handler
|
||||
RestHandler::status RestAqlHandler::execute() {
|
||||
// std::cout << "GOT INCOMING REQUEST: " <<
|
||||
// arangodb::rest::HttpRequest::translateMethod(_request->requestType()) << ",
|
||||
// HttpRequest::translateMethod(_request->requestType()) << ",
|
||||
// " << arangodb::ServerState::instance()->getId() << ": " <<
|
||||
// _request->fullUrl() << ": " << _request->body() << "\n\n";
|
||||
|
||||
|
@ -627,10 +631,10 @@ arangodb::rest::HttpHandler::status_t RestAqlHandler::execute() {
|
|||
// _request->fullUrl() << ": " << _response->responseCode() << ",
|
||||
// CONTENT-LENGTH: " << _response->contentLength() << "\n";
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
/// @brief dig out the query from ID, handle errors
|
||||
// dig out the query from ID, handle errors
|
||||
bool RestAqlHandler::findQuery(std::string const& idString, Query*& query) {
|
||||
_qId = arangodb::basics::StringUtils::uint64(idString);
|
||||
query = nullptr;
|
||||
|
@ -668,7 +672,7 @@ bool RestAqlHandler::findQuery(std::string const& idString, Query*& query) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// @brief handle for useQuery
|
||||
// handle for useQuery
|
||||
void RestAqlHandler::handleUseQuery(std::string const& operation, Query* query,
|
||||
VPackSlice const querySlice) {
|
||||
bool found;
|
||||
|
@ -686,7 +690,7 @@ void RestAqlHandler::handleUseQuery(std::string const& operation, Query* query,
|
|||
VPackObjectBuilder guard(&answerBuilder);
|
||||
if (operation == "lock") {
|
||||
// Mark current thread as potentially blocking:
|
||||
auto currentThread = arangodb::rest::DispatcherThread::current();
|
||||
auto currentThread = DispatcherThread::current();
|
||||
|
||||
if (currentThread != nullptr) {
|
||||
currentThread->block();
|
||||
|
@ -869,7 +873,7 @@ void RestAqlHandler::handleUseQuery(std::string const& operation, Query* query,
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief extract the VelocyPack from the request
|
||||
// extract the VelocyPack from the request
|
||||
std::shared_ptr<VPackBuilder> RestAqlHandler::parseVelocyPackBody() {
|
||||
try {
|
||||
std::shared_ptr<VPackBuilder> body =
|
||||
|
@ -897,20 +901,10 @@ std::shared_ptr<VPackBuilder> RestAqlHandler::parseVelocyPackBody() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/// @brief Send slice as result with the given response type.
|
||||
// Send slice as result with the given response type.
|
||||
void RestAqlHandler::sendResponse(
|
||||
GeneralResponse::ResponseCode code, VPackSlice const slice,
|
||||
arangodb::TransactionContext* transactionContext) {
|
||||
// TODO: use RestBaseHandler
|
||||
createResponse(code);
|
||||
_response->setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||
arangodb::basics::VPackStringBufferAdapter buffer(
|
||||
_response->body().stringBuffer());
|
||||
VPackDumper dumper(&buffer, transactionContext->getVPackOptions());
|
||||
try {
|
||||
dumper.dump(slice);
|
||||
} catch (...) {
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_INTERNAL, "cannot generate output");
|
||||
}
|
||||
writeResult(slice, *(transactionContext->getVPackOptions()));
|
||||
}
|
||||
|
|
|
@ -39,101 +39,97 @@ namespace aql {
|
|||
/// @brief shard control request handler
|
||||
class RestAqlHandler : public RestVocbaseBaseHandler {
|
||||
public:
|
||||
RestAqlHandler(HttpRequest* request,
|
||||
QueryRegistry* queryRegistry);
|
||||
RestAqlHandler(HttpRequest* request, QueryRegistry* queryRegistry);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
size_t queue() const override;
|
||||
status execute() override;
|
||||
|
||||
/// @brief executes the handler
|
||||
status_t execute() override;
|
||||
|
||||
/// @brief POST method for /_api/aql/instantiate
|
||||
/// The body is a VelocyPack with attributes "plan" for the execution plan and
|
||||
/// "options" for the options, all exactly as in AQL_EXECUTEJSON.
|
||||
public:
|
||||
// POST method for /_api/aql/instantiate
|
||||
// The body is a VelocyPack with attributes "plan" for the execution plan and
|
||||
// "options" for the options, all exactly as in AQL_EXECUTEJSON.
|
||||
void createQueryFromVelocyPack();
|
||||
|
||||
/// @brief POST method for /_api/aql/parse
|
||||
/// The body is a Json with attributes "query" for the query string,
|
||||
/// "parameters" for the query parameters and "options" for the options.
|
||||
/// This does the same as AQL_PARSE with exactly these parameters and
|
||||
/// does not keep the query hanging around.
|
||||
// POST method for /_api/aql/parse
|
||||
// The body is a Json with attributes "query" for the query string,
|
||||
// "parameters" for the query parameters and "options" for the options.
|
||||
// This does the same as AQL_PARSE with exactly these parameters and
|
||||
// does not keep the query hanging around.
|
||||
void parseQuery();
|
||||
|
||||
/// @brief POST method for /_api/aql/explain
|
||||
/// The body is a Json with attributes "query" for the query string,
|
||||
/// "parameters" for the query parameters and "options" for the options.
|
||||
/// This does the same as AQL_EXPLAIN with exactly these parameters and
|
||||
/// does not keep the query hanging around.
|
||||
// POST method for /_api/aql/explain
|
||||
// The body is a Json with attributes "query" for the query string,
|
||||
// "parameters" for the query parameters and "options" for the options.
|
||||
// This does the same as AQL_EXPLAIN with exactly these parameters and
|
||||
// does not keep the query hanging around.
|
||||
void explainQuery();
|
||||
|
||||
/// @brief POST method for /_api/aql/query
|
||||
/// The body is a Json with attributes "query" for the query string,
|
||||
/// "parameters" for the query parameters and "options" for the options.
|
||||
/// This sets up the query as as AQL_EXECUTE would, but does not use
|
||||
/// the cursor API yet. Rather, the query is stored in the query registry
|
||||
/// for later use by PUT requests.
|
||||
// POST method for /_api/aql/query
|
||||
// The body is a Json with attributes "query" for the query string,
|
||||
// "parameters" for the query parameters and "options" for the options.
|
||||
// This sets up the query as as AQL_EXECUTE would, but does not use
|
||||
// the cursor API yet. Rather, the query is stored in the query registry
|
||||
// for later use by PUT requests.
|
||||
void createQueryFromString();
|
||||
|
||||
/// @brief PUT method for /_api/aql/<operation>/<queryId>, this is using
|
||||
/// the part of the cursor API with side effects.
|
||||
/// <operation>: can be "getSome" or "skip".
|
||||
/// The body must be a Json with the following attributes:
|
||||
/// For the "getSome" operation one has to give:
|
||||
/// "atLeast":
|
||||
/// "atMost": both must be positive integers, the cursor returns never
|
||||
/// more than "atMost" items and tries to return at least
|
||||
/// "atLeast". Note that it is possible to return fewer than
|
||||
/// "atLeast", for example if there are only fewer items
|
||||
/// left. However, the implementation may return fewer items
|
||||
/// than "atLeast" for internal reasons, for example to avoid
|
||||
/// excessive copying. The result is the JSON representation of an
|
||||
/// AqlItemBlock.
|
||||
/// For the "skip" operation one has to give:
|
||||
/// "number": must be a positive integer, the cursor skips as many items,
|
||||
/// possibly exhausting the cursor.
|
||||
/// The result is a JSON with the attributes "error" (boolean),
|
||||
/// "errorMessage" (if applicable) and "exhausted" (boolean)
|
||||
/// to indicate whether or not the cursor is exhausted.
|
||||
// PUT method for /_api/aql/<operation>/<queryId>, this is using
|
||||
// the part of the cursor API with side effects.
|
||||
// <operation>: can be "getSome" or "skip".
|
||||
// The body must be a Json with the following attributes:
|
||||
// For the "getSome" operation one has to give:
|
||||
// "atLeast":
|
||||
// "atMost": both must be positive integers, the cursor returns never
|
||||
// more than "atMost" items and tries to return at least
|
||||
// "atLeast". Note that it is possible to return fewer than
|
||||
// "atLeast", for example if there are only fewer items
|
||||
// left. However, the implementation may return fewer items
|
||||
// than "atLeast" for internal reasons, for example to avoid
|
||||
// excessive copying. The result is the JSON representation of an
|
||||
// AqlItemBlock.
|
||||
// For the "skip" operation one has to give:
|
||||
// "number": must be a positive integer, the cursor skips as many items,
|
||||
// possibly exhausting the cursor.
|
||||
// The result is a JSON with the attributes "error" (boolean),
|
||||
// "errorMessage" (if applicable) and "exhausted" (boolean)
|
||||
// to indicate whether or not the cursor is exhausted.
|
||||
void useQuery(std::string const& operation, std::string const& idString);
|
||||
|
||||
/// @brief GET method for /_api/aql/<queryId>
|
||||
// GET method for /_api/aql/<queryId>
|
||||
void getInfoQuery(std::string const& operation, std::string const& idString);
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Send slice as result with the given response type.
|
||||
// Send slice as result with the given response type.
|
||||
void sendResponse(GeneralResponse::ResponseCode,
|
||||
arangodb::velocypack::Slice const,
|
||||
TransactionContext*);
|
||||
arangodb::velocypack::Slice const, TransactionContext*);
|
||||
|
||||
/// @brief handle for useQuery
|
||||
// handle for useQuery
|
||||
void handleUseQuery(std::string const&, Query*,
|
||||
arangodb::velocypack::Slice const);
|
||||
|
||||
/// @brief parseVelocyPackBody, returns a nullptr and produces an error response if
|
||||
/// parse was not successful.
|
||||
// parseVelocyPackBody, returns a nullptr and produces an error
|
||||
// response if
|
||||
// parse was not successful.
|
||||
std::shared_ptr<arangodb::velocypack::Builder> parseVelocyPackBody();
|
||||
|
||||
private:
|
||||
/// @brief dig out vocbase from context and query from ID, handle errors
|
||||
// dig out vocbase from context and query from ID, handle errors
|
||||
bool findQuery(std::string const& idString, Query*& query);
|
||||
|
||||
/// @brief name of the queue
|
||||
// name of the queue
|
||||
static std::string const QUEUE_NAME;
|
||||
|
||||
/// @brief request context
|
||||
// request context
|
||||
VocbaseContext* _context;
|
||||
|
||||
/// @brief the vocbase
|
||||
// the vocbase
|
||||
TRI_vocbase_t* _vocbase;
|
||||
|
||||
/// @brief our query registry
|
||||
// our query registry
|
||||
QueryRegistry* _queryRegistry;
|
||||
|
||||
/// @brief id of current query
|
||||
// id of current query
|
||||
QueryId _qId;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -182,13 +182,13 @@ add_executable(${BIN_ARANGOD}
|
|||
GeoIndex/GeoIndex.cpp
|
||||
HttpServer/AsyncJobManager.cpp
|
||||
HttpServer/HttpCommTask.cpp
|
||||
HttpServer/HttpHandler.cpp
|
||||
HttpServer/HttpHandlerFactory.cpp
|
||||
HttpServer/HttpListenTask.cpp
|
||||
HttpServer/HttpServer.cpp
|
||||
HttpServer/HttpServerJob.cpp
|
||||
HttpServer/HttpsCommTask.cpp
|
||||
HttpServer/HttpsServer.cpp
|
||||
HttpServer/RestHandler.cpp
|
||||
HttpServer/RestHandlerFactory.cpp
|
||||
HttpServer/PathHandler.cpp
|
||||
Indexes/EdgeIndex.cpp
|
||||
Indexes/FulltextIndex.cpp
|
||||
|
|
|
@ -41,7 +41,7 @@ using namespace arangodb;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void arangodb::ClusterCommRestCallback(std::string& coordinator,
|
||||
arangodb::HttpResponse* response) {
|
||||
GeneralResponse* response) {
|
||||
ClusterComm::instance()->asyncAnswer(coordinator, response);
|
||||
}
|
||||
|
||||
|
@ -775,7 +775,7 @@ void ClusterComm::drop(ClientTransactionID const& clientTransactionID,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClusterComm::asyncAnswer(std::string& coordinatorHeader,
|
||||
arangodb::HttpResponse* responseToSend) {
|
||||
GeneralResponse* responseToSend) {
|
||||
// First take apart the header to get the coordinatorID:
|
||||
ServerID coordinatorID;
|
||||
size_t start = 0;
|
||||
|
@ -783,16 +783,19 @@ void ClusterComm::asyncAnswer(std::string& coordinatorHeader,
|
|||
|
||||
LOG(DEBUG) << "In asyncAnswer, seeing " << coordinatorHeader;
|
||||
pos = coordinatorHeader.find(":", start);
|
||||
|
||||
if (pos == std::string::npos) {
|
||||
LOG(ERR) << "Could not find coordinator ID in X-Arango-Coordinator";
|
||||
return;
|
||||
}
|
||||
|
||||
coordinatorID = coordinatorHeader.substr(start, pos - start);
|
||||
|
||||
// Now find the connection to which the request goes from the coordinatorID:
|
||||
httpclient::ConnectionManager* cm = httpclient::ConnectionManager::instance();
|
||||
std::string endpoint =
|
||||
ClusterInfo::instance()->getServerEndpoint(coordinatorID);
|
||||
|
||||
if (endpoint == "") {
|
||||
if (logConnectionErrors()) {
|
||||
LOG(ERR) << "asyncAnswer: cannot find endpoint for server '"
|
||||
|
@ -806,6 +809,7 @@ void ClusterComm::asyncAnswer(std::string& coordinatorHeader,
|
|||
|
||||
httpclient::ConnectionManager::SingleServerConnection* connection =
|
||||
cm->leaseConnection(endpoint);
|
||||
|
||||
if (nullptr == connection) {
|
||||
LOG(ERR) << "asyncAnswer: cannot create connection to server '"
|
||||
<< coordinatorID << "'";
|
||||
|
@ -852,7 +856,7 @@ void ClusterComm::asyncAnswer(std::string& coordinatorHeader,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string ClusterComm::processAnswer(std::string& coordinatorHeader,
|
||||
arangodb::HttpRequest* answer) {
|
||||
GeneralRequest* answer) {
|
||||
TRI_ASSERT(answer != nullptr);
|
||||
// First take apart the header to get the operaitonID:
|
||||
OperationID operationID;
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "VocBase/voc-types.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
class ClusterCommThread;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -177,7 +176,7 @@ struct ClusterCommOperation {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClusterCommRestCallback(std::string& coordinator,
|
||||
HttpResponse* response);
|
||||
GeneralResponse* response);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief used to let ClusterComm send a set of requests and look after them
|
||||
|
@ -331,14 +330,14 @@ class ClusterComm {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string processAnswer(std::string& coordinatorHeader,
|
||||
HttpRequest* answer);
|
||||
GeneralRequest* answer);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief send an answer HTTP request to a coordinator
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void asyncAnswer(std::string& coordinatorHeader,
|
||||
HttpResponse* responseToSend);
|
||||
GeneralResponse* responseToSend);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief this method performs the given requests described by the vector
|
||||
|
|
|
@ -37,13 +37,13 @@ RestAgencyCallbacksHandler::RestAgencyCallbacksHandler(arangodb::HttpRequest* re
|
|||
|
||||
bool RestAgencyCallbacksHandler::isDirect() const { return false; }
|
||||
|
||||
arangodb::rest::HttpHandler::status_t RestAgencyCallbacksHandler::execute() {
|
||||
RestHandler::status RestAgencyCallbacksHandler::execute() {
|
||||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() != 1) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid callback");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
// extract the sub-request type
|
||||
|
@ -51,7 +51,7 @@ arangodb::rest::HttpHandler::status_t RestAgencyCallbacksHandler::execute() {
|
|||
if (type != GeneralRequest::RequestType::POST) {
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
bool parseSuccess = true;
|
||||
|
@ -62,7 +62,7 @@ arangodb::rest::HttpHandler::status_t RestAgencyCallbacksHandler::execute() {
|
|||
if (!parseSuccess) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid JSON");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -78,5 +78,5 @@ arangodb::rest::HttpHandler::status_t RestAgencyCallbacksHandler::execute() {
|
|||
// mop: not found...expected
|
||||
createResponse(arangodb::GeneralResponse::ResponseCode::NOT_FOUND);
|
||||
}
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -42,12 +42,8 @@ class RestAgencyCallbacksHandler : public RestVocbaseBaseHandler {
|
|||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
status execute() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t execute() override;
|
||||
private:
|
||||
AgencyCallbackRegistry* _agencyCallbackRegistry;
|
||||
};
|
||||
|
|
|
@ -33,20 +33,20 @@ using namespace arangodb;
|
|||
using namespace arangodb::rest;
|
||||
|
||||
RestShardHandler::RestShardHandler(arangodb::HttpRequest* request)
|
||||
: RestBaseHandler(request) {
|
||||
}
|
||||
: RestBaseHandler(request) {}
|
||||
|
||||
bool RestShardHandler::isDirect() const { return true; }
|
||||
|
||||
arangodb::rest::HttpHandler::status_t RestShardHandler::execute() {
|
||||
RestHandler::status RestShardHandler::execute() {
|
||||
bool found;
|
||||
std::string const& _coordinator = _request->header(StaticStrings::Coordinator, found);
|
||||
std::string const& _coordinator =
|
||||
_request->header(StaticStrings::Coordinator, found);
|
||||
|
||||
if (!found) {
|
||||
generateError(arangodb::GeneralResponse::ResponseCode::BAD,
|
||||
(int)arangodb::GeneralResponse::ResponseCode::BAD,
|
||||
"header 'X-Arango-Coordinator' is missing");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
std::string coordinatorHeader = _coordinator;
|
||||
|
@ -57,8 +57,9 @@ arangodb::rest::HttpHandler::status_t RestShardHandler::execute() {
|
|||
createResponse(arangodb::GeneralResponse::ResponseCode::ACCEPTED);
|
||||
} else {
|
||||
generateError(arangodb::GeneralResponse::ResponseCode::BAD,
|
||||
(int)arangodb::GeneralResponse::ResponseCode::BAD, result.c_str());
|
||||
(int)arangodb::GeneralResponse::ResponseCode::BAD,
|
||||
result.c_str());
|
||||
}
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -42,12 +42,7 @@ class RestShardHandler : public RestBaseHandler {
|
|||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/HttpServerJob.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
|
||||
|
|
|
@ -27,11 +27,13 @@
|
|||
#include "Basics/MutexLocker.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/StringBuffer.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
#include "HttpServer/HttpServer.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "HttpServer/RestHandlerFactory.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "RestServer/RestServerFeature.h"
|
||||
#include "Scheduler/Scheduler.h"
|
||||
#include "Scheduler/SchedulerFeature.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::basics;
|
||||
|
@ -41,9 +43,9 @@ using namespace arangodb::rest;
|
|||
/// @brief static initializers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t const HttpCommTask::MaximalHeaderSize = 1 * 1024 * 1024; // 1 MB
|
||||
size_t const HttpCommTask::MaximalBodySize = 512 * 1024 * 1024; // 512 MB
|
||||
size_t const HttpCommTask::MaximalPipelineSize = 512 * 1024 * 1024; // 512 MB
|
||||
size_t const HttpCommTask::MaximalHeaderSize = 1 * 1024 * 1024; // 1 MB
|
||||
size_t const HttpCommTask::MaximalBodySize = 512 * 1024 * 1024; // 512 MB
|
||||
size_t const HttpCommTask::MaximalPipelineSize = 512 * 1024 * 1024; // 512 MB
|
||||
size_t const HttpCommTask::RunCompactEvery = 500;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -56,6 +58,7 @@ HttpCommTask::HttpCommTask(HttpServer* server, TRI_socket_t socket,
|
|||
SocketTask(socket, keepAliveTimeout),
|
||||
_connectionInfo(std::move(info)),
|
||||
_server(server),
|
||||
_allowMethodOverride(server->allowMethodOverride()),
|
||||
_writeBuffers(),
|
||||
_writeBuffersStats(),
|
||||
_readPosition(0),
|
||||
|
@ -83,7 +86,7 @@ HttpCommTask::HttpCommTask(HttpServer* server, TRI_socket_t socket,
|
|||
<< _connectionInfo.serverPort << ", client ip "
|
||||
<< _connectionInfo.clientAddress << ", client port "
|
||||
<< _connectionInfo.clientPort;
|
||||
|
||||
|
||||
connectionStatisticsAgentSetHttp();
|
||||
}
|
||||
|
||||
|
@ -119,6 +122,42 @@ void HttpCommTask::handleResponse(HttpResponse* response) {
|
|||
addResponse(response);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles simple error response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpCommTask::handleSimpleError(GeneralResponse::ResponseCode code) {
|
||||
HttpResponse response(code);
|
||||
|
||||
resetState(true);
|
||||
addResponse(&response);
|
||||
}
|
||||
|
||||
void HttpCommTask::handleSimpleError(HttpRequest* request,
|
||||
GeneralResponse::ResponseCode responseCode,
|
||||
int errorNum,
|
||||
std::string const& errorMessage) {
|
||||
HttpResponse response(responseCode);
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
builder.add(StaticStrings::Error, VPackValue(true));
|
||||
builder.add(StaticStrings::ErrorNum, VPackValue(errorNum));
|
||||
builder.add(StaticStrings::ErrorMessage, VPackValue(errorMessage));
|
||||
builder.add(StaticStrings::Code, VPackValue((int)responseCode));
|
||||
builder.close();
|
||||
|
||||
try {
|
||||
response->fillBody(request, builder.slice(), true, VPackOptions::Defaults);
|
||||
|
||||
clearRequest();
|
||||
handleResponse(&response);
|
||||
} catch (...) {
|
||||
resetState(true);
|
||||
addResponse(&response);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads data from the socket
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -146,7 +185,7 @@ bool HttpCommTask::processRead() {
|
|||
|
||||
#if USE_DEV_TIMERS
|
||||
if (RequestStatisticsAgent::_statistics != nullptr) {
|
||||
RequestStatisticsAgent::_statistics->_id = (void*) this;
|
||||
RequestStatisticsAgent::_statistics->_id = (void*)this;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -187,14 +226,8 @@ bool HttpCommTask::processRead() {
|
|||
<< ", request header size is " << headerLength;
|
||||
|
||||
// header is too large
|
||||
HttpResponse response(
|
||||
handleSimpleError(
|
||||
GeneralResponse::ResponseCode::REQUEST_HEADER_FIELDS_TOO_LARGE);
|
||||
|
||||
// we need to close the connection, because there is no way we
|
||||
// know what to remove and then continue
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,21 +242,17 @@ bool HttpCommTask::processRead() {
|
|||
// check that we know, how to serve this request and update the connection
|
||||
// information, i. e. client and server addresses and ports and create a
|
||||
// request context for that request
|
||||
_request = _server->handlerFactory()->createRequest(
|
||||
_request = new HttpRequest(
|
||||
_connectionInfo, _readBuffer->c_str() + _startPosition,
|
||||
_readPosition - _startPosition);
|
||||
_readPosition - _startPosition, _allowMethodOverride);
|
||||
|
||||
RestServerFeature::HANDLER_FACTORY->setRequestContext(_request);
|
||||
|
||||
if (_request == nullptr) {
|
||||
LOG(ERR) << "cannot generate request";
|
||||
|
||||
// internal server error
|
||||
HttpResponse response(GeneralResponse::ResponseCode::SERVER_ERROR);
|
||||
|
||||
// we need to close the connection, because there is no way we
|
||||
// know how to remove the body and then continue
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
handleSimpleError(GeneralResponse::ResponseCode::SERVER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -234,14 +263,8 @@ bool HttpCommTask::processRead() {
|
|||
|
||||
if (_httpVersion != GeneralRequest::ProtocolVersion::HTTP_1_0 &&
|
||||
_httpVersion != GeneralRequest::ProtocolVersion::HTTP_1_1) {
|
||||
HttpResponse response(
|
||||
handleSimpleError(
|
||||
GeneralResponse::ResponseCode::HTTP_VERSION_NOT_SUPPORTED);
|
||||
|
||||
// we need to close the connection, because there is no way we
|
||||
// know what to remove and then continue
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -249,14 +272,7 @@ bool HttpCommTask::processRead() {
|
|||
_fullUrl = _request->fullUrl();
|
||||
|
||||
if (_fullUrl.size() > 16384) {
|
||||
HttpResponse response(
|
||||
GeneralResponse::ResponseCode::REQUEST_URI_TOO_LONG);
|
||||
|
||||
// we need to close the connection, because there is no way we
|
||||
// know what to remove and then continue
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
handleSimpleError(GeneralResponse::ResponseCode::REQUEST_URI_TOO_LONG);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -278,8 +294,8 @@ bool HttpCommTask::processRead() {
|
|||
if (!_origin.empty()) {
|
||||
// check for Access-Control-Allow-Credentials header
|
||||
bool found;
|
||||
std::string const& allowCredentials =
|
||||
_request->header(StaticStrings::AccessControlAllowCredentials, found);
|
||||
std::string const& allowCredentials = _request->header(
|
||||
StaticStrings::AccessControlAllowCredentials, found);
|
||||
|
||||
if (found) {
|
||||
_denyCredentials = !StringUtils::boolean(allowCredentials);
|
||||
|
@ -332,25 +348,12 @@ bool HttpCommTask::processRead() {
|
|||
<< std::string(_readBuffer->c_str() + _startPosition, l)
|
||||
<< "'";
|
||||
|
||||
// bad request, method not allowed
|
||||
HttpResponse response(
|
||||
GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED);
|
||||
|
||||
// we need to close the connection, because there is no way we
|
||||
// know what to remove and then continue
|
||||
resetState(true);
|
||||
|
||||
// force a socket close, response will be ignored!
|
||||
TRI_CLOSE_SOCKET(_commSocket);
|
||||
TRI_invalidatesocket(&_commSocket);
|
||||
|
||||
// might delete this
|
||||
// note that as we closed the socket above, the response will not make
|
||||
// it to
|
||||
// the client! will result in a "Empty reply from server" error in
|
||||
// curl etc.
|
||||
handleResponse(&response);
|
||||
|
||||
// bad request, method not allowed
|
||||
handleSimpleError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -359,28 +362,21 @@ bool HttpCommTask::processRead() {
|
|||
// check if server is active
|
||||
// .............................................................................
|
||||
|
||||
Scheduler const* scheduler =
|
||||
_server->scheduler(); // TODO(fc) this is singleton now
|
||||
Scheduler const* scheduler = SchedulerFeature::SCHEDULER;
|
||||
|
||||
if (scheduler != nullptr && !scheduler->isActive()) {
|
||||
// server is inactive and will intentionally respond with HTTP 503
|
||||
LOG(TRACE) << "cannot serve request - server is inactive";
|
||||
|
||||
HttpResponse response(
|
||||
GeneralResponse::ResponseCode::SERVICE_UNAVAILABLE);
|
||||
|
||||
// we need to close the connection, because there is no way we
|
||||
// know what to remove and then continue
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
handleSimpleError(GeneralResponse::ResponseCode::SERVICE_UNAVAILABLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for a 100-continue
|
||||
if (_readRequestBody) {
|
||||
bool found;
|
||||
std::string const& expect = _request->header(StaticStrings::Expect, found);
|
||||
std::string const& expect =
|
||||
_request->header(StaticStrings::Expect, found);
|
||||
|
||||
if (found && StringUtils::trim(expect) == "100-continue") {
|
||||
LOG(TRACE) << "received a 100-continue request";
|
||||
|
@ -479,7 +475,7 @@ bool HttpCommTask::processRead() {
|
|||
// .............................................................................
|
||||
|
||||
GeneralResponse::ResponseCode authResult =
|
||||
_server->handlerFactory()->authenticateRequest(_request);
|
||||
RestServerFeature::HANDLER_FACTORY->authenticateRequest(_request);
|
||||
|
||||
// authenticated or an OPTIONS request. OPTIONS requests currently go
|
||||
// unauthenticated
|
||||
|
@ -494,46 +490,25 @@ bool HttpCommTask::processRead() {
|
|||
|
||||
// not found
|
||||
else if (authResult == GeneralResponse::ResponseCode::NOT_FOUND) {
|
||||
HttpResponse response(authResult);
|
||||
response.setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||
|
||||
response.body()
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR("{\"error\":true,\"errorMessage\":\""))
|
||||
.appendText(TRI_errno_string(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND))
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR("\",\"code\":"))
|
||||
.appendInteger((int)authResult)
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR(",\"errorNum\":"))
|
||||
.appendInteger(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND)
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR("}"));
|
||||
|
||||
clearRequest();
|
||||
handleResponse(&response);
|
||||
handleSimpleError(_request, authResult, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND,
|
||||
TRI_errno_string(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND));
|
||||
}
|
||||
|
||||
// forbidden
|
||||
else if (authResult == GeneralResponse::ResponseCode::FORBIDDEN) {
|
||||
HttpResponse response(authResult);
|
||||
response.setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||
|
||||
response.body()
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR(
|
||||
"{\"error\":true,\"errorMessage\":\"change password\",\"code\":"))
|
||||
.appendInteger((int)authResult)
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR(",\"errorNum\":"))
|
||||
.appendInteger(TRI_ERROR_USER_CHANGE_PASSWORD)
|
||||
.appendText(TRI_CHAR_LENGTH_PAIR("}"));
|
||||
|
||||
clearRequest();
|
||||
handleResponse(&response);
|
||||
handleSimpleError(_request, authResult, TRI_ERROR_USER_CHANGE_PASSWORD,
|
||||
"change password");
|
||||
}
|
||||
|
||||
// not authenticated
|
||||
else {
|
||||
HttpResponse response(GeneralResponse::ResponseCode::UNAUTHORIZED);
|
||||
|
||||
if (sendWwwAuthenticateHeader()) {
|
||||
std::string realm =
|
||||
"basic realm=\"" +
|
||||
_server->handlerFactory()->authenticationRealm(_request) + "\"";
|
||||
RestServerFeature::HANDLER_FACTORY->authenticationRealm(_request) +
|
||||
"\"";
|
||||
|
||||
response.setHeaderNC(StaticStrings::WwwAuthenticate, std::move(realm));
|
||||
}
|
||||
|
@ -615,7 +590,9 @@ void HttpCommTask::addResponse(HttpResponse* response) {
|
|||
|
||||
// set "connection" header
|
||||
// keep-alive is the default
|
||||
response->setConnectionType(_closeRequested ? HttpResponse::CONNECTION_CLOSE : HttpResponse::CONNECTION_KEEP_ALIVE);
|
||||
response->setConnectionType(_closeRequested
|
||||
? HttpResponse::CONNECTION_CLOSE
|
||||
: HttpResponse::CONNECTION_KEEP_ALIVE);
|
||||
|
||||
size_t const responseBodyLength = response->bodySize();
|
||||
|
||||
|
@ -696,11 +673,7 @@ bool HttpCommTask::checkContentLength(bool expectContentLength) {
|
|||
|
||||
if (bodyLength < 0) {
|
||||
// bad request, body length is < 0. this is a client error
|
||||
HttpResponse response(GeneralResponse::ResponseCode::LENGTH_REQUIRED);
|
||||
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
handleSimpleError(GeneralResponse::ResponseCode::LENGTH_REQUIRED);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -717,12 +690,7 @@ bool HttpCommTask::checkContentLength(bool expectContentLength) {
|
|||
<< ", request body size is " << bodyLength;
|
||||
|
||||
// request entity too large
|
||||
HttpResponse response(
|
||||
GeneralResponse::ResponseCode::REQUEST_ENTITY_TOO_LARGE);
|
||||
|
||||
resetState(true);
|
||||
handleResponse(&response);
|
||||
|
||||
handleSimpleError(GeneralResponse::ResponseCode::REQUEST_ENTITY_TOO_LARGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -773,7 +741,8 @@ void HttpCommTask::processCorsOptions() {
|
|||
|
||||
// send back which HTTP methods are allowed for the resource
|
||||
// we'll allow all
|
||||
response.setHeaderNC(StaticStrings::AccessControlAllowMethods, StaticStrings::CorsMethods);
|
||||
response.setHeaderNC(StaticStrings::AccessControlAllowMethods,
|
||||
StaticStrings::CorsMethods);
|
||||
|
||||
if (!allowHeaders.empty()) {
|
||||
// allow all extra headers the client requested
|
||||
|
@ -788,7 +757,8 @@ void HttpCommTask::processCorsOptions() {
|
|||
}
|
||||
|
||||
// set caching time (hard-coded value)
|
||||
response.setHeaderNC(StaticStrings::AccessControlMaxAge, StaticStrings::N1800);
|
||||
response.setHeaderNC(StaticStrings::AccessControlMaxAge,
|
||||
StaticStrings::N1800);
|
||||
}
|
||||
|
||||
clearRequest();
|
||||
|
@ -819,20 +789,19 @@ void HttpCommTask::processRequest() {
|
|||
<< "\"";
|
||||
|
||||
// check for an async request
|
||||
std::string const& asyncExecution = _request->header(StaticStrings::Async, found);
|
||||
std::string const& asyncExecution =
|
||||
_request->header(StaticStrings::Async, found);
|
||||
|
||||
// create handler, this will take over the request
|
||||
WorkItem::uptr<HttpHandler> handler(
|
||||
_server->handlerFactory()->createHandler(_request));
|
||||
WorkItem::uptr<RestHandler> handler(
|
||||
RestServerFeature::HANDLER_FACTORY->createHandler(_request));
|
||||
|
||||
if (handler == nullptr) {
|
||||
LOG(TRACE) << "no handler is known, giving up";
|
||||
|
||||
HttpResponse response(GeneralResponse::ResponseCode::NOT_FOUND);
|
||||
|
||||
clearRequest();
|
||||
handleResponse(&response);
|
||||
|
||||
handleSimpleError(GeneralResponse::ResponseCode::NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -886,8 +855,7 @@ void HttpCommTask::processRequest() {
|
|||
}
|
||||
|
||||
if (!ok) {
|
||||
HttpResponse response(GeneralResponse::ResponseCode::SERVER_ERROR);
|
||||
handleResponse(&response);
|
||||
handleSimpleError(GeneralResponse::ResponseCode::SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -912,6 +880,7 @@ void HttpCommTask::resetState(bool close) {
|
|||
clearRequest();
|
||||
|
||||
_requestPending = false;
|
||||
_isChunked = false;
|
||||
_closeRequested = true;
|
||||
|
||||
_readPosition = 0;
|
||||
|
@ -993,8 +962,16 @@ void HttpCommTask::signalTask(TaskData* data) {
|
|||
// data response
|
||||
if (data->_type == TaskData::TASK_DATA_RESPONSE) {
|
||||
data->RequestStatisticsAgent::transferTo(this);
|
||||
handleResponse(data->_response.get());
|
||||
processRead();
|
||||
|
||||
HttpResponse* response = dynamic_cast<HttpResponse*>(data->_response.get());
|
||||
|
||||
if (response != nullptr) {
|
||||
handleResponse(data->_response.get());
|
||||
processRead();
|
||||
}
|
||||
else {
|
||||
handleSimpleError(GeneralResponse::Response::SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// data chunk
|
||||
|
|
|
@ -38,13 +38,8 @@ class HttpRequest;
|
|||
class HttpResponse;
|
||||
|
||||
namespace rest {
|
||||
class HttpCommTask;
|
||||
class HttpServer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief http communication
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpCommTask : public SocketTask, public RequestStatisticsAgent {
|
||||
HttpCommTask(HttpCommTask const&) = delete;
|
||||
HttpCommTask const& operator=(HttpCommTask const&) = delete;
|
||||
|
@ -56,262 +51,145 @@ class HttpCommTask : public SocketTask, public RequestStatisticsAgent {
|
|||
static size_t const RunCompactEvery;
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpCommTask(HttpServer*, TRI_socket_t, ConnectionInfo&&,
|
||||
double keepAliveTimeout);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
~HttpCommTask();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// handles response
|
||||
void handleResponse(HttpResponse*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads data from the socket
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// handles simple errors
|
||||
void handleSimpleError(GeneralResponse::ResponseCode);
|
||||
void handleSimpleError(GeneralResponse::ResponseCode, int code,
|
||||
std::string const& errorMessage);
|
||||
|
||||
// reads data from the socket
|
||||
bool processRead();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sends more chunked data
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// sends more chunked data
|
||||
void sendChunk(basics::StringBuffer*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief chunking is finished
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// chunking is finished
|
||||
void finishedChunked();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief task set up complete
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// task set up complete
|
||||
void setupDone();
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads data from the socket
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// reads data from the socket
|
||||
void addResponse(HttpResponse*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// check the content-length header of a request and fail it is broken
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool checkContentLength(bool expectContentLength);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief fills the write buffer
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// fills the write buffer
|
||||
void fillWriteBuffer();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles CORS options
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// handles CORS options
|
||||
void processCorsOptions();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief processes a request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// processes a request
|
||||
void processRequest();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clears the request object
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// clears the request object
|
||||
void clearRequest();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief resets the internal state
|
||||
// resets the internal state
|
||||
///
|
||||
/// this method can be called to clean up when the request handling aborts
|
||||
/// prematurely
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void resetState(bool close);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief decides whether or not we should send back a www-authenticate
|
||||
// decides whether or not we should send back a www-authenticate
|
||||
/// header
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool sendWwwAuthenticateHeader() const;
|
||||
|
||||
protected:
|
||||
bool setup(Scheduler* scheduler, EventLoop loop) override;
|
||||
|
||||
void cleanup() override;
|
||||
|
||||
bool handleEvent(EventToken token, EventType events) override;
|
||||
|
||||
void signalTask(TaskData*) override;
|
||||
|
||||
protected:
|
||||
bool handleRead() override;
|
||||
|
||||
void completedWriteBuffer() override;
|
||||
|
||||
void handleTimeout() override;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief connection info
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// connection info
|
||||
ConnectionInfo _connectionInfo;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the underlying server
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// the underlying server
|
||||
HttpServer* const _server;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief write buffers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// allow method override
|
||||
bool _allowMethodOverride;
|
||||
|
||||
private:
|
||||
// write buffers
|
||||
std::deque<basics::StringBuffer*> _writeBuffers;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief statistics buffers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// statistics buffers
|
||||
std::deque<TRI_request_statistics_t*> _writeBuffersStats;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief current read position
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// current read position
|
||||
size_t _readPosition;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start of the body position
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// start of the body position
|
||||
size_t _bodyPosition;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief body length
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// body length
|
||||
size_t _bodyLength;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief true if request is complete but not handled
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// true if request is complete but not handled
|
||||
bool _requestPending;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief true if a close has been requested by the client
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// true if a close has been requested by the client
|
||||
bool _closeRequested;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief true if reading the request body
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// true if reading the request body
|
||||
bool _readRequestBody;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not to allow credentialed requests
|
||||
///
|
||||
/// this is only used for CORS
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// whether or not to allow credentialed requests (only CORS)
|
||||
bool _denyCredentials;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether the client accepts deflate algorithm
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// whether the client accepts deflate algorithm
|
||||
bool _acceptDeflate;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief new request started
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// new request started
|
||||
bool _newRequest;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief true if within a chunked response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// true if within a chunked response
|
||||
bool _isChunked;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the request with possible incomplete body
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// the request with possible incomplete body
|
||||
HttpRequest* _request;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief http version number used
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// http version number used
|
||||
GeneralRequest::ProtocolVersion _httpVersion;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type of request (GET, POST, ...)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// type of request (GET, POST, ...)
|
||||
GeneralRequest::RequestType _requestType;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief value of requested URL
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// value of requested URL
|
||||
std::string _fullUrl;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief value of the HTTP origin header the client sent (if any).
|
||||
///
|
||||
/// this is only used for CORS
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// value of the HTTP origin header the client sent (if any, CORS only)
|
||||
std::string _origin;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start position of current request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// start position of current request
|
||||
size_t _startPosition;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief number of requests since last compactification
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// number of requests since last compactification
|
||||
size_t _sinceCompactification;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief original body length
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// original body length
|
||||
size_t _originalBodyLength;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief task ready
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// task ready
|
||||
std::atomic<bool> _setupDone;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HttpHandler.h"
|
||||
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::basics;
|
||||
using namespace arangodb::rest;
|
||||
|
||||
namespace {
|
||||
std::atomic_uint_fast64_t NEXT_HANDLER_ID(
|
||||
static_cast<uint64_t>(TRI_microtime() * 100000.0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::HttpHandler(HttpRequest* request)
|
||||
: _handlerId(NEXT_HANDLER_ID.fetch_add(1, std::memory_order_seq_cst)),
|
||||
_taskId(0),
|
||||
_request(request),
|
||||
_response(nullptr),
|
||||
_server(nullptr) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::~HttpHandler() {
|
||||
delete _request;
|
||||
delete _response;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the queue id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t HttpHandler::queue() const {
|
||||
#if 0
|
||||
// feature currently disabled because it is neither documented nor used
|
||||
bool found;
|
||||
std::string const& queue = _request->header(StaticStrings::Queue, found);
|
||||
|
||||
if (found) {
|
||||
uint32_t n = StringUtils::uint32(queue);
|
||||
|
||||
if (n == 0) {
|
||||
return Dispatcher::STANDARD_QUEUE;
|
||||
}
|
||||
|
||||
return n + (Dispatcher::SYSTEM_QUEUE_SIZE - 1);
|
||||
}
|
||||
#endif
|
||||
return Dispatcher::STANDARD_QUEUE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prepares for execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::prepareExecute() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finalize the execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::finalizeExecute() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HttpHandler::cancel() { return false; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::addResponse(HttpHandler*) {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the id of the underlying task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t HttpHandler::taskId() const { return _taskId; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the event loop of the underlying task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventLoop HttpHandler::eventLoop() const { return _loop; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the id of the underlying task or 0 to dettach
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::setTaskId(uint64_t id, EventLoop loop) {
|
||||
_taskId = id;
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execution cycle including error handling and prepare
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::status_t HttpHandler::executeFull() {
|
||||
HttpHandler::status_t status(HttpHandler::HANDLER_FAILED);
|
||||
|
||||
requestStatisticsAgentSetRequestStart();
|
||||
|
||||
#ifdef USE_DEV_TIMERS
|
||||
TRI_request_statistics_t::STATS = _statistics;
|
||||
#endif
|
||||
|
||||
try {
|
||||
prepareExecute();
|
||||
|
||||
try {
|
||||
status = execute();
|
||||
} catch (Exception const& ex) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
handleError(ex);
|
||||
} catch (std::bad_alloc const& ex) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
Exception err(TRI_ERROR_OUT_OF_MEMORY, ex.what(), __FILE__, __LINE__);
|
||||
handleError(err);
|
||||
} catch (std::exception const& ex) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
Exception err(TRI_ERROR_INTERNAL, ex.what(), __FILE__, __LINE__);
|
||||
handleError(err);
|
||||
} catch (...) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
Exception err(TRI_ERROR_INTERNAL, __FILE__, __LINE__);
|
||||
handleError(err);
|
||||
}
|
||||
|
||||
finalizeExecute();
|
||||
|
||||
if (status._status != HANDLER_ASYNC && _response == nullptr) {
|
||||
Exception err(TRI_ERROR_INTERNAL, "no response received from handler",
|
||||
__FILE__, __LINE__);
|
||||
|
||||
handleError(err);
|
||||
}
|
||||
} catch (Exception const& ex) {
|
||||
status = HANDLER_FAILED;
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
LOG(ERR) << "caught exception: " << DIAGNOSTIC_INFORMATION(ex);
|
||||
} catch (std::exception const& ex) {
|
||||
status = HANDLER_FAILED;
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
LOG(ERR) << "caught exception: " << ex.what();
|
||||
} catch (...) {
|
||||
status = HANDLER_FAILED;
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
LOG(ERR) << "caught exception";
|
||||
}
|
||||
|
||||
if (status._status != HANDLER_ASYNC && _response == nullptr) {
|
||||
_response = new HttpResponse(GeneralResponse::ResponseCode::SERVER_ERROR);
|
||||
}
|
||||
|
||||
requestStatisticsAgentSetRequestEnd();
|
||||
|
||||
#ifdef USE_DEV_TIMERS
|
||||
TRI_request_statistics_t::STATS = nullptr;
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register the server object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::setServer(HttpHandlerFactory* server) { _server = server; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a pointer to the request
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest const* HttpHandler::getRequest() const { return _request; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief steal the request
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest* HttpHandler::stealRequest() {
|
||||
HttpRequest* tmp = _request;
|
||||
_request = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpResponse* HttpHandler::getResponse() const { return _response; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief steal the response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpResponse* HttpHandler::stealResponse() {
|
||||
HttpResponse* tmp = _response;
|
||||
_response = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a new HTTP response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::createResponse(GeneralResponse::ResponseCode code) {
|
||||
// avoid having multiple responses. this would be a memleak
|
||||
delete _response;
|
||||
_response = nullptr;
|
||||
|
||||
// create a "standard" (standalone) Http response
|
||||
_response = new HttpResponse(code);
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_HTTP_SERVER_HTTP_HANDLER_H
|
||||
#define ARANGOD_HTTP_SERVER_HTTP_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Basics/WorkMonitor.h"
|
||||
#include "Dispatcher/Job.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "Scheduler/events.h"
|
||||
#include "Statistics/StatisticsAgent.h"
|
||||
|
||||
namespace arangodb {
|
||||
class HttpRequest;
|
||||
|
||||
namespace rest {
|
||||
class Dispatcher;
|
||||
class HttpHandlerFactory;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abstract class for http handlers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpHandler : public RequestStatisticsAgent, public arangodb::WorkItem {
|
||||
HttpHandler(HttpHandler const&) = delete;
|
||||
HttpHandler& operator=(HttpHandler const&) = delete;
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new handler
|
||||
///
|
||||
/// Note that the handler owns the request and the response. It is its
|
||||
/// responsibility to destroy them both. See also the two steal methods.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
explicit HttpHandler(HttpRequest*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
~HttpHandler();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief status of execution
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum status_e { HANDLER_DONE, HANDLER_FAILED, HANDLER_ASYNC };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief result of execution
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class status_t {
|
||||
public:
|
||||
status_t() : status_t(HANDLER_FAILED) {}
|
||||
explicit status_t(status_e status) : _status(status) {}
|
||||
void operator=(status_e status) { _status = status; }
|
||||
status_e _status;
|
||||
};
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true if a handler is executed directly
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool isDirect() const = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the queue name
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual size_t queue() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prepares execution of a handler, has to be called before execute
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void prepareExecute();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes a handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual status_t execute() = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finalizes execution of a handler, has to be called after execute
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void finalizeExecute();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool cancel();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles error
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void handleError(basics::Exception const&) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void addResponse(HttpHandler*);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the id of the underlying task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t taskId() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the event loop of the underlying task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventLoop eventLoop() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the id of the underlying task or 0 if dettach
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setTaskId(uint64_t id, EventLoop);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execution cycle including error handling and prepare
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t executeFull();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register the server object
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setServer(HttpHandlerFactory* server);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a pointer to the request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest const* getRequest() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief steal the pointer to the request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest* stealRequest();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpResponse* getResponse() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief steal the response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpResponse* stealResponse();
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a new HTTP response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void createResponse(GeneralResponse::ResponseCode);
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handler id
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t const _handlerId;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief task id or 0
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t _taskId;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief event loop
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventLoop _loop;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest* _request;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpResponse* _response;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the server
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandlerFactory* _server;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,197 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_HTTP_SERVER_HTTP_HANDLER_FACTORY_H
|
||||
#define ARANGOD_HTTP_SERVER_HTTP_HANDLER_FACTORY_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Basics/Mutex.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
|
||||
namespace arangodb {
|
||||
class HttpRequest;
|
||||
class HttpResponse;
|
||||
struct ConnectionInfo;
|
||||
|
||||
namespace rest {
|
||||
class HttpHandler;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handler factory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpHandlerFactory {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef HttpHandler GeneralHandler;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef HttpRequest GeneralRequest;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief response
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef HttpResponse GeneralResponse;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handler creator
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef HttpHandler* (*create_fptr)(HttpRequest*, void*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief context handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef bool (*context_fptr)(HttpRequest*, void*);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new handler factory
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandlerFactory(std::string const&, bool, context_fptr, void*);
|
||||
|
||||
HttpHandlerFactory(HttpHandlerFactory const&) = delete;
|
||||
HttpHandlerFactory& operator=(HttpHandlerFactory const&) = delete;
|
||||
|
||||
~HttpHandlerFactory();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets maintenance mode
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void setMaintenance(bool);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief authenticates a new request, wrapper method
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralResponse::ResponseCode authenticateRequest(HttpRequest*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set request context, wrapper method
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool setRequestContext(HttpRequest*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the authentication realm
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string authenticationRealm(HttpRequest*) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a new request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest* createRequest(ConnectionInfo const&, char const*, size_t);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a new handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler* createHandler(HttpRequest*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a path and constructor to the factory
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addHandler(std::string const& path, create_fptr, void* data = 0);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a prefix path and constructor to the factory
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addPrefixHandler(std::string const& path, create_fptr, void* data = 0);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a path and constructor to the factory
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addNotFoundHandler(create_fptr);
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief authentication realm
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string _authenticationRealm;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief allow overriding HTTP request method with custom headers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _allowMethodOverride;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set context callback
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
context_fptr _setContext;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set context data
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* _setContextData;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of constructors
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<std::string, create_fptr> _constructors;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of data pointers for constructors
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<std::string, void*> _datas;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of prefix handlers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> _prefixes;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor for a not-found handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
create_fptr _notFound;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -27,13 +27,15 @@
|
|||
#include "Basics/MutexLocker.h"
|
||||
#include "Basics/WorkMonitor.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "Dispatcher/DispatcherFeature.h"
|
||||
#include "Endpoint/EndpointList.h"
|
||||
#include "HttpServer/AsyncJobManager.h"
|
||||
#include "HttpServer/HttpCommTask.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/HttpListenTask.h"
|
||||
#include "HttpServer/HttpServerJob.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "RestServer/RestServerFeature.h"
|
||||
#include "Scheduler/ListenTask.h"
|
||||
#include "Scheduler/Scheduler.h"
|
||||
#include "Scheduler/SchedulerFeature.h"
|
||||
|
@ -63,14 +65,8 @@ int HttpServer::sendChunk(uint64_t taskId, std::string const& data) {
|
|||
/// @brief constructs a new general server with dispatcher and job manager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpServer::HttpServer(Scheduler* scheduler, Dispatcher* dispatcher,
|
||||
HttpHandlerFactory* handlerFactory,
|
||||
AsyncJobManager* jobManager, double keepAliveTimeout)
|
||||
: _scheduler(scheduler),
|
||||
_dispatcher(dispatcher),
|
||||
_handlerFactory(handlerFactory),
|
||||
_jobManager(jobManager),
|
||||
_listenTasks(),
|
||||
HttpServer::HttpServer(double keepAliveTimeout)
|
||||
: _listenTasks(),
|
||||
_endpointList(nullptr),
|
||||
_commTasks(),
|
||||
_keepAliveTimeout(keepAliveTimeout) {}
|
||||
|
@ -107,7 +103,8 @@ void HttpServer::startListening() {
|
|||
_endpointList->matching(Endpoint::TransportType::HTTP, encryptionType());
|
||||
|
||||
for (auto& it : endpoints) {
|
||||
LOG(TRACE) << "trying to bind to endpoint '" << it.first << "' for requests";
|
||||
LOG(TRACE) << "trying to bind to endpoint '" << it.first
|
||||
<< "' for requests";
|
||||
|
||||
bool ok = openEndpoint(it.second);
|
||||
|
||||
|
@ -116,7 +113,8 @@ void HttpServer::startListening() {
|
|||
} else {
|
||||
LOG(FATAL) << "failed to bind to endpoint '" << it.first
|
||||
<< "'. Please check whether another instance is already "
|
||||
"running using this endpint and review your endpoints configuration.";
|
||||
"running using this endpint and review your endpoints "
|
||||
"configuration.";
|
||||
FATAL_ERROR_EXIT();
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +126,7 @@ void HttpServer::startListening() {
|
|||
|
||||
void HttpServer::stopListening() {
|
||||
for (auto& task : _listenTasks) {
|
||||
_scheduler->destroyTask(task);
|
||||
SchedulerFeature::SCHEDULER->destroyTask(task);
|
||||
}
|
||||
|
||||
_listenTasks.clear();
|
||||
|
@ -153,7 +151,7 @@ void HttpServer::stop() {
|
|||
_commTasks.erase(task);
|
||||
}
|
||||
|
||||
_scheduler->destroyTask(task);
|
||||
SchedulerFeature::SCHEDULER->destroyTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +173,7 @@ void HttpServer::handleConnected(TRI_socket_t s, ConnectionInfo&& info) {
|
|||
|
||||
// registers the task and get the number of the scheduler thread
|
||||
ssize_t n;
|
||||
_scheduler->registerTask(task, &n);
|
||||
SchedulerFeature::SCHEDULER->registerTask(task, &n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -201,11 +199,12 @@ void HttpServer::handleCommunicationFailure(HttpCommTask* task) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HttpServer::handleRequestAsync(HttpCommTask* task,
|
||||
WorkItem::uptr<HttpHandler>& handler,
|
||||
WorkItem::uptr<RestHandler>& handler,
|
||||
uint64_t* jobId) {
|
||||
// extract the coordinator flag
|
||||
bool found;
|
||||
std::string const& hdrStr = handler->getRequest()->header(StaticStrings::Coordinator, found);
|
||||
std::string const& hdrStr =
|
||||
handler->request()->header(StaticStrings::Coordinator, found);
|
||||
char const* hdr = found ? hdrStr.c_str() : nullptr;
|
||||
|
||||
// execute the handler using the dispatcher
|
||||
|
@ -215,12 +214,13 @@ bool HttpServer::handleRequestAsync(HttpCommTask* task,
|
|||
|
||||
// register the job with the job manager
|
||||
if (jobId != nullptr) {
|
||||
_jobManager->initAsyncJob(static_cast<HttpServerJob*>(job.get()), hdr);
|
||||
RestServerFeature::JOB_MANAGER->initAsyncJob(
|
||||
static_cast<HttpServerJob*>(job.get()), hdr);
|
||||
*jobId = job->jobId();
|
||||
}
|
||||
|
||||
// execute the handler using the dispatcher
|
||||
int res = _dispatcher->addJob(job);
|
||||
int res = DispatcherFeature::DISPATCHER->addJob(job);
|
||||
|
||||
// could not add job to job queue
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
|
@ -243,11 +243,11 @@ bool HttpServer::handleRequestAsync(HttpCommTask* task,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HttpServer::handleRequest(HttpCommTask* task,
|
||||
WorkItem::uptr<HttpHandler>& handler) {
|
||||
WorkItem::uptr<RestHandler>& handler) {
|
||||
// direct handlers
|
||||
if (handler->isDirect()) {
|
||||
HandlerWorkStack work(handler);
|
||||
handleRequestDirectly(task, work.handler());
|
||||
handleRequestDirectly(work.handler(), task);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ bool HttpServer::handleRequest(HttpCommTask* task,
|
|||
<< (void*)job.get();
|
||||
|
||||
// add the job to the dispatcher
|
||||
int res = _dispatcher->addJob(job);
|
||||
int res = DispatcherFeature::DISPATCHER->addJob(job);
|
||||
|
||||
// job is in queue now
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
|
@ -283,7 +283,7 @@ bool HttpServer::openEndpoint(Endpoint* endpoint) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int res = _scheduler->registerTask(task);
|
||||
int res = SchedulerFeature::SCHEDULER->registerTask(task);
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
_listenTasks.emplace_back(task);
|
||||
|
@ -297,19 +297,19 @@ bool HttpServer::openEndpoint(Endpoint* endpoint) {
|
|||
/// @brief handle request directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpServer::handleRequestDirectly(HttpCommTask* task,
|
||||
HttpHandler* handler) {
|
||||
void HttpServer::handleRequestDirectly(RestHandler* handler,
|
||||
HttpCommTask* task) {
|
||||
task->RequestStatisticsAgent::transferTo(handler);
|
||||
HttpHandler::status_t status = handler->executeFull();
|
||||
RestHandler::status result = handler->executeFull();
|
||||
handler->RequestStatisticsAgent::transferTo(task);
|
||||
|
||||
switch (status._status) {
|
||||
case HttpHandler::HANDLER_FAILED:
|
||||
case HttpHandler::HANDLER_DONE:
|
||||
switch (result) {
|
||||
case RestHandler::status::FAILED:
|
||||
case RestHandler::status::DONE:
|
||||
task->handleResponse(handler->getResponse());
|
||||
break;
|
||||
|
||||
case HttpHandler::HANDLER_ASYNC:
|
||||
case RestHandler::status::ASYNC:
|
||||
// do nothing, just wait
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -26,10 +26,11 @@
|
|||
#ifndef ARANGOD_HTTP_SERVER_HTTP_SERVER_H
|
||||
#define ARANGOD_HTTP_SERVER_HTTP_SERVER_H 1
|
||||
|
||||
#include "Scheduler/TaskManager.h"
|
||||
|
||||
#include "Basics/Mutex.h"
|
||||
#include "Endpoint/ConnectionInfo.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "Scheduler/TaskManager.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
class EndpointList;
|
||||
|
@ -38,226 +39,101 @@ namespace rest {
|
|||
|
||||
class AsyncJobManager;
|
||||
class Dispatcher;
|
||||
class HttpServerJob;
|
||||
class HttpCommTask;
|
||||
class HttpHandlerFactory;
|
||||
class HttpServerJob;
|
||||
class Job;
|
||||
class ListenTask;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief general server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class RestHandlerFactory;
|
||||
|
||||
class HttpServer : protected TaskManager {
|
||||
HttpServer(HttpServer const&) = delete;
|
||||
HttpServer const& operator=(HttpServer const&) = delete;
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys an endpoint server
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// destroys an endpoint server
|
||||
static int sendChunk(uint64_t, std::string const&);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new general server with dispatcher and job manager
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpServer(Scheduler*, Dispatcher*, HttpHandlerFactory*, AsyncJobManager*,
|
||||
double keepAliveTimeout);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a general server
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
explicit HttpServer(double keepAliveTimeout);
|
||||
virtual ~HttpServer();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the protocol
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// returns the protocol
|
||||
virtual char const* protocol() const { return "http"; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the encryption to be used
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// returns the encryption to be used
|
||||
virtual Endpoint::EncryptionType encryptionType() const {
|
||||
return Endpoint::EncryptionType::NONE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generates a suitable communication task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// check, if we allow a method override
|
||||
bool allowMethodOverride();
|
||||
|
||||
// generates a suitable communication task
|
||||
virtual HttpCommTask* createCommTask(TRI_socket_t, ConnectionInfo&&);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the scheduler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Scheduler* scheduler() const { return _scheduler; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the dispatcher
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Dispatcher* dispatcher() const { return _dispatcher; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the dispatcher
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AsyncJobManager* jobManager() const { return _jobManager; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the handler factory
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandlerFactory* handlerFactory() const { return _handlerFactory; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds the endpoint list
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// adds the endpoint list
|
||||
void setEndpointList(const EndpointList* list);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief starts listening
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// starts listening
|
||||
void startListening();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stops listining
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// stops listining
|
||||
void stopListening();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes all listen and comm tasks
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// removes all listen and comm tasks
|
||||
void stop();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles connection request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// handles connection request
|
||||
void handleConnected(TRI_socket_t s, ConnectionInfo&& info);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles a connection close
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// handles a connection close
|
||||
void handleCommunicationClosed(HttpCommTask*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles a connection failure
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// handles a connection failure
|
||||
void handleCommunicationFailure(HttpCommTask*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a job for asynchronous execution
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// creates a job for asynchronous execution
|
||||
bool handleRequestAsync(HttpCommTask*,
|
||||
arangodb::WorkItem::uptr<HttpHandler>&,
|
||||
arangodb::WorkItem::uptr<RestHandler>&,
|
||||
uint64_t* jobId);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the handler directly or add it to the queue
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool handleRequest(HttpCommTask*, arangodb::WorkItem::uptr<HttpHandler>&);
|
||||
// executes the handler directly or add it to the queue
|
||||
bool handleRequest(HttpCommTask*, arangodb::WorkItem::uptr<RestHandler>&);
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Handler, Job, and Task tuple
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Handler, Job, and Task tuple
|
||||
struct handler_task_job_t {
|
||||
HttpHandler* _handler;
|
||||
RestHandler* _handler;
|
||||
HttpCommTask* _task;
|
||||
HttpServerJob* _job;
|
||||
};
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief opens a listen port
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// opens a listen port
|
||||
bool openEndpoint(Endpoint* endpoint);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handle request directly
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// handle request directly
|
||||
void handleRequestDirectly(RestHandler* handler, HttpCommTask* task);
|
||||
|
||||
void handleRequestDirectly(HttpCommTask* task, HttpHandler* handler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief registers a task
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void registerHandler(HttpHandler* handler, HttpCommTask* task);
|
||||
// registers a task
|
||||
void registerHandler(RestHandler* handler, HttpCommTask* task);
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the scheduler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Scheduler* _scheduler; // TODO (fc) XXX make this a singleton
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the dispatcher
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Dispatcher* _dispatcher; // TODO (fc) XXX make this a singleton
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the handler factory
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandlerFactory* _handlerFactory;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the job manager
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AsyncJobManager* _jobManager; // TODO (fc) XXX make this a singleton
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief active listen tasks
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// active listen tasks
|
||||
std::vector<ListenTask*> _listenTasks;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief defined ports and addresses
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// defined ports and addresses
|
||||
const EndpointList* _endpointList;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief mutex for comm tasks
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// mutex for comm tasks
|
||||
arangodb::Mutex _commTasksLock;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief active comm tasks
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// active comm tasks
|
||||
std::unordered_set<HttpCommTask*> _commTasks;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief keep-alive timeout
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// keep-alive timeout
|
||||
double _keepAliveTimeout;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,9 +28,10 @@
|
|||
#include "Dispatcher/DispatcherQueue.h"
|
||||
#include "HttpServer/AsyncJobManager.h"
|
||||
#include "HttpServer/HttpCommTask.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/HttpServer.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "RestServer/RestServerFeature.h"
|
||||
#include "Scheduler/Scheduler.h"
|
||||
#include "Scheduler/SchedulerFeature.h"
|
||||
|
||||
|
@ -42,7 +43,7 @@ using namespace arangodb::rest;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpServerJob::HttpServerJob(HttpServer* server,
|
||||
WorkItem::uptr<HttpHandler>& handler, bool isAsync)
|
||||
WorkItem::uptr<RestHandler>& handler, bool isAsync)
|
||||
: Job("HttpServerJob"),
|
||||
_server(server),
|
||||
_workDesc(nullptr),
|
||||
|
@ -80,7 +81,8 @@ void HttpServerJob::work() {
|
|||
|
||||
if (_isAsync) {
|
||||
_handler->RequestStatisticsAgent::release();
|
||||
_server->jobManager()->finishAsyncJob(_jobId, _handler->stealResponse());
|
||||
RestServerFeature::JOB_MANAGER->finishAsyncJob(_jobId,
|
||||
_handler->stealResponse());
|
||||
} else {
|
||||
auto data = std::make_unique<TaskData>();
|
||||
|
||||
|
|
|
@ -32,72 +32,33 @@
|
|||
|
||||
namespace arangodb {
|
||||
namespace rest {
|
||||
class HttpHandler;
|
||||
class RestHandler;
|
||||
class HttpServer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief general server job
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpServerJob : public Job {
|
||||
HttpServerJob(HttpServerJob const&) = delete;
|
||||
HttpServerJob& operator=(HttpServerJob const&) = delete;
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new server job
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpServerJob(HttpServer*, arangodb::WorkItem::uptr<HttpHandler>&,
|
||||
HttpServerJob(HttpServer*, arangodb::WorkItem::uptr<RestHandler>&,
|
||||
bool isAsync = false);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a server job
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~HttpServerJob();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the underlying handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler* handler() const { return _handler.get(); }
|
||||
RestHandler* handler() const { return _handler.get(); }
|
||||
|
||||
public:
|
||||
size_t queue() const override;
|
||||
|
||||
void work() override;
|
||||
|
||||
bool cancel() override;
|
||||
|
||||
void cleanup(DispatcherQueue*) override;
|
||||
|
||||
void handleError(basics::Exception const&) override;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief general server
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpServer* _server;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::WorkItem::uptr<HttpHandler> _handler;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief work description we need to destroy
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::WorkItem::uptr<RestHandler> _handler;
|
||||
arangodb::WorkDescription* _workDesc;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief async request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _isAsync;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,12 +32,8 @@ using namespace arangodb::rest;
|
|||
/// @brief constructs a new http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServer::HttpsServer(Scheduler* scheduler, Dispatcher* dispatcher,
|
||||
HttpHandlerFactory* handlerFactory,
|
||||
AsyncJobManager* jobManager, double keepAliveTimeout,
|
||||
SSL_CTX* ctx)
|
||||
: HttpServer(scheduler, dispatcher, handlerFactory, jobManager,
|
||||
keepAliveTimeout),
|
||||
HttpsServer::HttpsServer(double keepAliveTimeout, SSL_CTX* ctx)
|
||||
: HttpServer(keepAliveTimeout),
|
||||
_ctx(ctx),
|
||||
_verificationMode(SSL_VERIFY_NONE),
|
||||
_verificationCallback(0) {}
|
||||
|
|
|
@ -31,32 +31,16 @@
|
|||
namespace arangodb {
|
||||
namespace rest {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpsServer : public HttpServer {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new http server
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServer(Scheduler*, Dispatcher*, HttpHandlerFactory*, AsyncJobManager*,
|
||||
double keepAliveTimeout, SSL_CTX*);
|
||||
|
||||
HttpsServer(double keepAliveTimeout, SSL_CTX*);
|
||||
~HttpsServer();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the verification mode
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// sets the verification mode
|
||||
void setVerificationMode(int mode);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the verification callback
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// sets the verification callback
|
||||
void setVerificationCallback(int (*func)(int, X509_STORE_CTX*));
|
||||
|
||||
public:
|
||||
|
@ -69,22 +53,8 @@ class HttpsServer : public HttpServer {
|
|||
HttpCommTask* createCommTask(TRI_socket_t, ConnectionInfo&&) override;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ssl context
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSL_CTX* _ctx;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief verification mode
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _verificationMode;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief verification callback
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int (*_verificationCallback)(int, X509_STORE_CTX*);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace rest {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
PathHandler::PathHandler(HttpRequest* request, Options const* options)
|
||||
: HttpHandler(request),
|
||||
: RestHandler(request),
|
||||
path(options->path),
|
||||
contentType(options->contentType),
|
||||
allowSymbolicLink(options->allowSymbolicLink),
|
||||
|
@ -65,7 +65,7 @@ PathHandler::PathHandler(HttpRequest* request, Options const* options)
|
|||
// Handler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
HttpHandler::status_t PathHandler::execute() {
|
||||
RestHandler::status PathHandler::execute() {
|
||||
std::vector<std::string> const& names = _request->suffix();
|
||||
std::string name = path;
|
||||
std::string last;
|
||||
|
@ -91,7 +91,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
_response->body().appendText(url);
|
||||
_response->body().appendText("</a>.</p></body></html>");
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator j = names.begin();
|
||||
|
@ -103,7 +103,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
createResponse(GeneralResponse::ResponseCode::FORBIDDEN);
|
||||
_response->body().appendText("path contains '.'");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (next == "..") {
|
||||
|
@ -111,7 +111,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
createResponse(GeneralResponse::ResponseCode::FORBIDDEN);
|
||||
_response->body().appendText("path contains '..'");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
std::string::size_type sc = next.find_first_not_of(AllowedChars);
|
||||
|
@ -122,7 +122,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
createResponse(GeneralResponse::ResponseCode::FORBIDDEN);
|
||||
_response->body().appendText("path contains illegal character '" +
|
||||
std::string(1, next[sc]) + "'");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (!path.empty()) {
|
||||
|
@ -131,7 +131,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
createResponse(GeneralResponse::ResponseCode::NOT_FOUND);
|
||||
_response->body().appendText("file not found");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
createResponse(GeneralResponse::ResponseCode::FORBIDDEN);
|
||||
_response->body().appendText("symbolic links are not allowed");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
createResponse(GeneralResponse::ResponseCode::NOT_FOUND);
|
||||
_response->body().appendText("file not found");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
createResponse(GeneralResponse::ResponseCode::OK);
|
||||
|
@ -164,7 +164,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
createResponse(GeneralResponse::ResponseCode::NOT_FOUND);
|
||||
_response->body().appendText("file not readable");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
// check if we should use caching and this is an HTTP GET request
|
||||
|
@ -186,7 +186,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
if (mimetype != nullptr) {
|
||||
_response->setContentType(mimetype);
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
} else {
|
||||
// note: changed the log level to debug. an unknown content-type does not
|
||||
|
@ -197,7 +197,7 @@ HttpHandler::status_t PathHandler::execute() {
|
|||
|
||||
_response->setContentType(contentType);
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
void PathHandler::handleError(const Exception&) {
|
||||
|
|
|
@ -24,22 +24,12 @@
|
|||
#ifndef ARANGOD_HTTP_SERVER_PATH_HANDLER_H
|
||||
#define ARANGOD_HTTP_SERVER_PATH_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace rest {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief path handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PathHandler : public HttpHandler {
|
||||
class PathHandler : public RestHandler {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief path options
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Options {
|
||||
Options() : allowSymbolicLink(false), cacheMaxAge(0) {}
|
||||
|
||||
|
@ -63,11 +53,7 @@ class PathHandler : public HttpHandler {
|
|||
};
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief factory methods
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static HttpHandler* create(HttpRequest* request, void* data) {
|
||||
static RestHandler* create(HttpRequest* request, void* data) {
|
||||
Options* options = static_cast<Options*>(data);
|
||||
|
||||
return new PathHandler(request, options);
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RestHandler.h"
|
||||
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Rest/GeneralRequest.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::basics;
|
||||
using namespace arangodb::rest;
|
||||
|
||||
namespace {
|
||||
std::atomic_uint_fast64_t NEXT_HANDLER_ID(
|
||||
static_cast<uint64_t>(TRI_microtime() * 100000.0));
|
||||
}
|
||||
|
||||
RestHandler::RestHandler(GeneralRequest* request, GeneralResponse* response)
|
||||
: _handlerId(NEXT_HANDLER_ID.fetch_add(1, std::memory_order_seq_cst)),
|
||||
_taskId(0),
|
||||
_request(request),
|
||||
_response(response) {}
|
||||
|
||||
RestHandler::~RestHandler() {
|
||||
delete _request;
|
||||
delete _response;
|
||||
}
|
||||
|
||||
void RestHandler::setTaskId(uint64_t id, EventLoop loop) {
|
||||
_taskId = id;
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
RestHandler::status RestHandler::executeFull() {
|
||||
RestHandler::status result = status::FAILED;
|
||||
|
||||
requestStatisticsAgentSetRequestStart();
|
||||
|
||||
#ifdef USE_DEV_TIMERS
|
||||
TRI_request_statistics_t::STATS = _statistics;
|
||||
#endif
|
||||
|
||||
try {
|
||||
prepareExecute();
|
||||
|
||||
try {
|
||||
result = execute();
|
||||
} catch (Exception const& ex) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
handleError(ex);
|
||||
} catch (std::bad_alloc const& ex) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
Exception err(TRI_ERROR_OUT_OF_MEMORY, ex.what(), __FILE__, __LINE__);
|
||||
handleError(err);
|
||||
} catch (std::exception const& ex) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
Exception err(TRI_ERROR_INTERNAL, ex.what(), __FILE__, __LINE__);
|
||||
handleError(err);
|
||||
} catch (...) {
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
Exception err(TRI_ERROR_INTERNAL, __FILE__, __LINE__);
|
||||
handleError(err);
|
||||
}
|
||||
|
||||
finalizeExecute();
|
||||
|
||||
if (result != status::ASYNC && _response == nullptr) {
|
||||
Exception err(TRI_ERROR_INTERNAL, "no response received from handler",
|
||||
__FILE__, __LINE__);
|
||||
|
||||
handleError(err);
|
||||
}
|
||||
} catch (Exception const& ex) {
|
||||
result = status::FAILED;
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
LOG(ERR) << "caught exception: " << DIAGNOSTIC_INFORMATION(ex);
|
||||
} catch (std::exception const& ex) {
|
||||
result = status::FAILED;
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
LOG(ERR) << "caught exception: " << ex.what();
|
||||
} catch (...) {
|
||||
result = status::FAILED;
|
||||
requestStatisticsAgentSetExecuteError();
|
||||
LOG(ERR) << "caught exception";
|
||||
}
|
||||
|
||||
requestStatisticsAgentSetRequestEnd();
|
||||
|
||||
#ifdef USE_DEV_TIMERS
|
||||
TRI_request_statistics_t::STATS = nullptr;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GeneralRequest* RestHandler::stealRequest() {
|
||||
GeneralRequest* tmp = _request;
|
||||
_request = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
GeneralResponse* RestHandler::stealResponse() {
|
||||
GeneralResponse* tmp = _response;
|
||||
_response = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void RestHandler::createResponse(GeneralResponse::ResponseCode code) {
|
||||
_response->reset(code);
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_HTTP_SERVER_REST_HANDLER_H
|
||||
#define ARANGOD_HTTP_SERVER_REST_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Basics/WorkMonitor.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "Dispatcher/Job.h"
|
||||
#include "Rest/GeneralResponse.h"
|
||||
#include "Scheduler/events.h"
|
||||
#include "Statistics/StatisticsAgent.h"
|
||||
|
||||
namespace arangodb {
|
||||
class GeneralRequest;
|
||||
|
||||
namespace rest {
|
||||
class RestHandlerFactory;
|
||||
|
||||
class RestHandler : public RequestStatisticsAgent, public arangodb::WorkItem {
|
||||
RestHandler(RestHandler const&) = delete;
|
||||
RestHandler& operator=(RestHandler const&) = delete;
|
||||
|
||||
public:
|
||||
explicit RestHandler(GeneralRequest*, GeneralResponse*);
|
||||
|
||||
protected:
|
||||
~RestHandler();
|
||||
|
||||
public:
|
||||
enum class status { DONE, FAILED, ASYNC };
|
||||
|
||||
public:
|
||||
// returns true if a handler is executed directly
|
||||
virtual bool isDirect() const = 0;
|
||||
|
||||
// returns the queue name
|
||||
virtual size_t queue() const {
|
||||
return Dispatcher::STANDARD_QUEUE;
|
||||
}
|
||||
|
||||
// prepares execution of a handler, has to be called before execute
|
||||
virtual void prepareExecute() {}
|
||||
|
||||
// executes a handler
|
||||
virtual status execute() = 0;
|
||||
|
||||
// finalizes execution of a handler, has to be called after execute
|
||||
virtual void finalizeExecute() {}
|
||||
|
||||
// tries to cancel an execution
|
||||
virtual bool cancel() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// handles error
|
||||
virtual void handleError(basics::Exception const&) = 0;
|
||||
|
||||
// adds a response
|
||||
virtual void addResponse(RestHandler*) {}
|
||||
|
||||
public:
|
||||
// returns the id of the underlying task
|
||||
uint64_t taskId() const {
|
||||
return _taskId;
|
||||
}
|
||||
|
||||
// returns the event loop of the underlying task
|
||||
EventLoop eventLoop() const {
|
||||
return _loop;
|
||||
}
|
||||
|
||||
// sets the id of the underlying task or 0 if dettach
|
||||
void setTaskId(uint64_t id, EventLoop);
|
||||
|
||||
// execution cycle including error handling and prepare
|
||||
status executeFull();
|
||||
|
||||
// return a pointer to the request
|
||||
GeneralRequest const* request() const {
|
||||
return _request;
|
||||
}
|
||||
|
||||
// steal the pointer to the request
|
||||
GeneralRequest* stealRequest();
|
||||
|
||||
// returns the response
|
||||
GeneralResponse* response() const {
|
||||
return _response;
|
||||
}
|
||||
|
||||
// steal the response
|
||||
GeneralResponse* stealResponse();
|
||||
|
||||
protected:
|
||||
// create a new REST response
|
||||
void createResponse(GeneralResponse::ResponseCode);
|
||||
|
||||
protected:
|
||||
// handler id
|
||||
uint64_t const _handlerId;
|
||||
|
||||
// task id or 0
|
||||
uint64_t _taskId;
|
||||
|
||||
// event loop
|
||||
EventLoop _loop;
|
||||
|
||||
// the request
|
||||
GeneralRequest* _request;
|
||||
|
||||
// the response
|
||||
GeneralResponse* _response;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -21,10 +21,10 @@
|
|||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HttpHandlerFactory.h"
|
||||
#include "RestHandlerFactory.h"
|
||||
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/RequestContext.h"
|
||||
|
@ -32,7 +32,7 @@
|
|||
using namespace arangodb;
|
||||
using namespace arangodb::basics;
|
||||
using namespace arangodb::rest;
|
||||
|
||||
|
||||
static std::string const ROOT_PATH = "/";
|
||||
|
||||
namespace {
|
||||
|
@ -40,16 +40,16 @@ sig_atomic_t MaintenanceMode = 0;
|
|||
}
|
||||
|
||||
namespace {
|
||||
class MaintenanceHandler : public HttpHandler {
|
||||
class MaintenanceHandler : public RestHandler {
|
||||
public:
|
||||
explicit MaintenanceHandler(HttpRequest* request) : HttpHandler(request){};
|
||||
explicit MaintenanceHandler(HttpRequest* request) : RestHandler(request){};
|
||||
|
||||
bool isDirect() const override { return true; };
|
||||
|
||||
status_t execute() override {
|
||||
status execute() override {
|
||||
createResponse(GeneralResponse::ResponseCode::SERVICE_UNAVAILABLE);
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
};
|
||||
|
||||
void handleError(const Exception& error) override {
|
||||
|
@ -62,27 +62,19 @@ class MaintenanceHandler : public HttpHandler {
|
|||
/// @brief constructs a new handler factory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandlerFactory::HttpHandlerFactory(std::string const& authenticationRealm,
|
||||
bool allowMethodOverride,
|
||||
RestHandlerFactory::RestHandlerFactory(std::string const& authenticationRealm,
|
||||
context_fptr setContext,
|
||||
void* setContextData)
|
||||
: _authenticationRealm(authenticationRealm),
|
||||
_allowMethodOverride(allowMethodOverride),
|
||||
_setContext(setContext),
|
||||
_setContextData(setContextData),
|
||||
_notFound(nullptr) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a handler factory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandlerFactory::~HttpHandlerFactory() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets maintenance mode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandlerFactory::setMaintenance(bool value) {
|
||||
void RestHandlerFactory::setMaintenance(bool value) {
|
||||
MaintenanceMode = value ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -92,7 +84,7 @@ void HttpHandlerFactory::setMaintenance(bool value) {
|
|||
/// wrapper method that will consider disabled authentication etc.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralResponse::ResponseCode HttpHandlerFactory::authenticateRequest(
|
||||
GeneralResponse::ResponseCode RestHandlerFactory::authenticateRequest(
|
||||
HttpRequest* request) {
|
||||
auto context = request->requestContext();
|
||||
|
||||
|
@ -113,7 +105,7 @@ GeneralResponse::ResponseCode HttpHandlerFactory::authenticateRequest(
|
|||
/// @brief set request context, wrapper method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HttpHandlerFactory::setRequestContext(HttpRequest* request) {
|
||||
bool RestHandlerFactory::setRequestContext(HttpRequest* request) {
|
||||
return _setContext(request, _setContextData);
|
||||
}
|
||||
|
||||
|
@ -121,52 +113,37 @@ bool HttpHandlerFactory::setRequestContext(HttpRequest* request) {
|
|||
/// @brief returns the authentication realm
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string HttpHandlerFactory::authenticationRealm(
|
||||
std::string RestHandlerFactory::authenticationRealm(
|
||||
HttpRequest* request) const {
|
||||
auto context = request->requestContext();
|
||||
|
||||
if (context != nullptr) {
|
||||
auto realm = context->realm();
|
||||
|
||||
if (! realm.empty()) {
|
||||
if (!realm.empty()) {
|
||||
return _authenticationRealm + "/" + std::string(realm);
|
||||
}
|
||||
}
|
||||
return _authenticationRealm;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a new request
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpRequest* HttpHandlerFactory::createRequest(ConnectionInfo const& info,
|
||||
char const* ptr, size_t length) {
|
||||
HttpRequest* request = new HttpRequest(info, ptr, length, _allowMethodOverride);
|
||||
|
||||
if (request != nullptr) {
|
||||
setRequestContext(request);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a new handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler* HttpHandlerFactory::createHandler(HttpRequest* request) {
|
||||
RestHandler* RestHandlerFactory::createHandler(GeneralRequest* request,
|
||||
GeneralResponse* response) {
|
||||
std::string const& path = request->requestPath();
|
||||
|
||||
// In the bootstrap phase, we would like that coordinators answer the
|
||||
// In the bootstrap phase, we would like that coordinators answer the
|
||||
// following to endpoints, but not yet others:
|
||||
if (MaintenanceMode &&
|
||||
(!ServerState::instance()->isCoordinator() ||
|
||||
(path != "/_api/shard-comm" &&
|
||||
(path != "/_api/shard-comm" &&
|
||||
path.find("/_api/agency/agency-callbacks") == std::string::npos &&
|
||||
path.find("/_api/aql") == std::string::npos))) {
|
||||
LOG(DEBUG) << "Maintenance mode: refused path: "
|
||||
<< path;
|
||||
return new MaintenanceHandler(request);
|
||||
path.find("/_api/aql") == std::string::npos))) {
|
||||
LOG(DEBUG) << "Maintenance mode: refused path: " << path;
|
||||
return new MaintenanceHandler(request, response);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, create_fptr> const& ii = _constructors;
|
||||
|
@ -236,7 +213,7 @@ HttpHandler* HttpHandlerFactory::createHandler(HttpRequest* request) {
|
|||
}
|
||||
|
||||
modifiedPath = &prefix;
|
||||
|
||||
|
||||
i = ii.find(prefix);
|
||||
request->setPrefix(prefix);
|
||||
}
|
||||
|
@ -247,7 +224,7 @@ HttpHandler* HttpHandlerFactory::createHandler(HttpRequest* request) {
|
|||
|
||||
if (i == ii.end()) {
|
||||
if (_notFound != nullptr) {
|
||||
HttpHandler* notFoundHandler = _notFound(request, data);
|
||||
RestHandler* notFoundHandler = _notFound(request, response, data);
|
||||
notFoundHandler->setServer(this);
|
||||
|
||||
return notFoundHandler;
|
||||
|
@ -257,7 +234,8 @@ HttpHandler* HttpHandlerFactory::createHandler(HttpRequest* request) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// look up data
|
||||
// look up data
|
||||
#warning TODO remove datas
|
||||
{
|
||||
auto const& it = _datas.find(*modifiedPath);
|
||||
|
||||
|
@ -267,8 +245,8 @@ HttpHandler* HttpHandlerFactory::createHandler(HttpRequest* request) {
|
|||
}
|
||||
|
||||
LOG(TRACE) << "found handler for path '" << *modifiedPath << "'";
|
||||
HttpHandler* handler = i->second(request, data);
|
||||
|
||||
RestHandler* handler = i->second(request, response, data);
|
||||
handler->setServer(this);
|
||||
|
||||
return handler;
|
||||
|
@ -278,7 +256,7 @@ HttpHandler* HttpHandlerFactory::createHandler(HttpRequest* request) {
|
|||
/// @brief adds a path and constructor to the factory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandlerFactory::addHandler(std::string const& path, create_fptr func,
|
||||
void RestHandlerFactory::addHandler(std::string const& path, create_fptr func,
|
||||
void* data) {
|
||||
_constructors[path] = func;
|
||||
_datas[path] = data;
|
||||
|
@ -288,7 +266,7 @@ void HttpHandlerFactory::addHandler(std::string const& path, create_fptr func,
|
|||
/// @brief adds a prefix path and constructor to the factory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandlerFactory::addPrefixHandler(std::string const& path,
|
||||
void RestHandlerFactory::addPrefixHandler(std::string const& path,
|
||||
create_fptr func, void* data) {
|
||||
_constructors[path] = func;
|
||||
_datas[path] = data;
|
||||
|
@ -299,6 +277,6 @@ void HttpHandlerFactory::addPrefixHandler(std::string const& path,
|
|||
/// @brief adds a path and constructor to the factory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandlerFactory::addNotFoundHandler(create_fptr func) {
|
||||
void RestHandlerFactory::addNotFoundHandler(create_fptr func) {
|
||||
_notFound = func;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_HTTP_SERVER_HTTP_HANDLER_FACTORY_H
|
||||
#define ARANGOD_HTTP_SERVER_HTTP_HANDLER_FACTORY_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Basics/Mutex.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
|
||||
namespace arangodb {
|
||||
class GeneralRequest;
|
||||
class GeneralResponse;
|
||||
struct ConnectionInfo;
|
||||
|
||||
namespace rest {
|
||||
class RestHandler;
|
||||
|
||||
class RestHandlerFactory {
|
||||
RestHandlerFactory(RestHandlerFactory const&) = delete;
|
||||
RestHandlerFactory& operator=(RestHandlerFactory const&) = delete;
|
||||
|
||||
public:
|
||||
// handler creator
|
||||
typedef RestHandler* (*create_fptr)(GeneralRequest*, void*);
|
||||
|
||||
// context handler
|
||||
typedef bool (*context_fptr)(GeneralRequest*, void*);
|
||||
|
||||
public:
|
||||
RestHandlerFactory(std::string const&, bool, context_fptr, void*);
|
||||
|
||||
public:
|
||||
// sets maintenance mode
|
||||
static void setMaintenance(bool);
|
||||
|
||||
public:
|
||||
// authenticates a new request, wrapper method
|
||||
GeneralResponse::ResponseCode authenticateRequest(GeneralRequest*);
|
||||
|
||||
// set request context, wrapper method
|
||||
bool setRequestContext(GeneralRequest*);
|
||||
|
||||
// returns the authentication realm
|
||||
std::string authenticationRealm(GeneralRequest*) const;
|
||||
|
||||
// creates a new handler
|
||||
RestHandler* createHandler(GeneralRequest*);
|
||||
|
||||
// adds a path and constructor to the factory
|
||||
void addHandler(std::string const& path, create_fptr, void* data = 0);
|
||||
|
||||
// adds a prefix path and constructor to the factory
|
||||
void addPrefixHandler(std::string const& path, create_fptr, void* data = 0);
|
||||
|
||||
// adds a path and constructor to the factory
|
||||
void addNotFoundHandler(create_fptr);
|
||||
|
||||
private:
|
||||
// authentication realm
|
||||
#warning TODO
|
||||
std::string _authenticationRealm;
|
||||
|
||||
// set context callback
|
||||
context_fptr _setContext;
|
||||
|
||||
// set context data
|
||||
void* _contextData;
|
||||
|
||||
// list of constructors
|
||||
std::unordered_map<std::string, create_fptr> _constructors;
|
||||
|
||||
// list of data pointers for constructors
|
||||
std::unordered_map<std::string, void*> _datas;
|
||||
|
||||
// list of prefix handlers
|
||||
std::vector<std::string> _prefixes;
|
||||
|
||||
// constructor for a not-found handler
|
||||
create_fptr _notFound;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -44,7 +44,7 @@ bool RestAdminLogHandler::isDirect() const { return true; }
|
|||
/// @brief was docuBlock JSF_get_admin_modules_flush
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::status_t RestAdminLogHandler::execute() {
|
||||
RestHandler::status RestAdminLogHandler::execute() {
|
||||
// check the maximal log level to report
|
||||
bool found1;
|
||||
std::string const& upto =
|
||||
|
@ -85,7 +85,7 @@ HttpHandler::status_t RestAdminLogHandler::execute() {
|
|||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
std::string("unknown '") + (found2 ? "level" : "upto") +
|
||||
"' log level: '" + logLevel + "'");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,5 +246,5 @@ HttpHandler::status_t RestAdminLogHandler::execute() {
|
|||
// So ignore again
|
||||
}
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class RestAdminLogHandler : public RestBaseHandler {
|
|||
/// @brief returns the log files (inheritDoc)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ using namespace arangodb;
|
|||
using namespace arangodb::basics;
|
||||
using namespace arangodb::rest;
|
||||
|
||||
RestBaseHandler::RestBaseHandler(HttpRequest* request) : HttpHandler(request) {}
|
||||
RestBaseHandler::RestBaseHandler(HttpRequest* request) : RestHandler(request) {}
|
||||
|
||||
void RestBaseHandler::handleError(Exception const& ex) {
|
||||
generateError(GeneralResponse::responseCode(ex.code()), ex.code(), ex.what());
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#ifndef ARANGOD_REST_HANDLER_REST_BASE_HANDLER_H
|
||||
#define ARANGOD_REST_HANDLER_REST_BASE_HANDLER_H 1
|
||||
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
|
||||
#include "Rest/HttpResponse.h"
|
||||
|
||||
|
@ -36,7 +36,7 @@ struct Options;
|
|||
class Slice;
|
||||
}
|
||||
|
||||
class RestBaseHandler : public rest::HttpHandler {
|
||||
class RestBaseHandler : public rest::RestHandler {
|
||||
public:
|
||||
explicit RestBaseHandler(HttpRequest* request);
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
#include "HttpServer/HttpServer.h"
|
||||
#include "HttpServer/RestHandlerFactory.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
|
||||
using namespace arangodb;
|
||||
|
@ -43,7 +43,7 @@ RestBatchHandler::~RestBatchHandler() {}
|
|||
/// @brief was docuBlock JSF_batch_processing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::status_t RestBatchHandler::execute() {
|
||||
RestHandler::status RestBatchHandler::execute() {
|
||||
// extract the request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -51,7 +51,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
type != GeneralRequest::RequestType::PUT) {
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
std::string boundary;
|
||||
|
@ -61,7 +61,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid content-type or boundary received");
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status(RestHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
LOG(TRACE) << "boundary of multipart-message is '" << boundary << "'";
|
||||
|
@ -94,7 +94,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
"invalid multipart message received");
|
||||
LOG(WARN) << "received a corrupted multipart message";
|
||||
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status(RestHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
// split part into header & body
|
||||
|
@ -138,7 +138,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status(RestHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
// we do not have a client task id here
|
||||
|
@ -161,7 +161,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
authorization.c_str(), authorization.size());
|
||||
}
|
||||
|
||||
HttpHandler* handler = _server->createHandler(request);
|
||||
RestHandler* handler = _server->createHandler(request);
|
||||
|
||||
if (handler == nullptr) {
|
||||
delete request;
|
||||
|
@ -169,19 +169,19 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_INTERNAL,
|
||||
"could not create handler for batch part processing");
|
||||
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status(RestHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
// start to work for this handler
|
||||
{
|
||||
HandlerWorkStack work(handler);
|
||||
HttpHandler::status_t status = handler->executeFull();
|
||||
RestHandler::status status = handler->executeFull();
|
||||
|
||||
if (status._status == HttpHandler::HANDLER_FAILED) {
|
||||
if (status._status == RestHandler::HANDLER_FAILED) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_INTERNAL,
|
||||
"executing a handler for batch part failed");
|
||||
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status(RestHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
HttpResponse* partResponse = handler->getResponse();
|
||||
|
@ -190,7 +190,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_INTERNAL,
|
||||
"could not create a response for batch part request");
|
||||
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status(RestHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
GeneralResponse::ResponseCode const code = partResponse->responseCode();
|
||||
|
@ -239,7 +239,7 @@ HttpHandler::status_t RestBatchHandler::execute() {
|
|||
}
|
||||
|
||||
// success
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -61,10 +61,6 @@ struct SearchHelper {
|
|||
bool containsMore;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief batch request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestBatchHandler : public RestVocbaseBaseHandler {
|
||||
public:
|
||||
explicit RestBatchHandler(HttpRequest*);
|
||||
|
@ -72,31 +68,19 @@ class RestBatchHandler : public RestVocbaseBaseHandler {
|
|||
~RestBatchHandler();
|
||||
|
||||
public:
|
||||
HttpHandler::status_t execute() override;
|
||||
RestHandler::status execute() override;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the boundary from the body of a multipart message
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// extract the boundary from the body of a multipart message
|
||||
bool getBoundaryBody(std::string*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the boundary from the HTTP header of a multipart message
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// extract the boundary from the HTTP header of a multipart message
|
||||
bool getBoundaryHeader(std::string*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the boundary of a multipart message
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// extract the boundary of a multipart message
|
||||
bool getBoundary(std::string*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the next part from a multipart message
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// extract the next part from a multipart message
|
||||
bool extractPart(SearchHelper*);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -48,28 +48,28 @@ RestCursorHandler::RestCursorHandler(
|
|||
_query(nullptr),
|
||||
_queryKilled(false) {}
|
||||
|
||||
HttpHandler::status_t RestCursorHandler::execute() {
|
||||
RestHandler::status RestCursorHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
if (type == GeneralRequest::RequestType::POST) {
|
||||
createCursor();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (type == GeneralRequest::RequestType::PUT) {
|
||||
modifyCursor();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (type == GeneralRequest::RequestType::DELETE_REQ) {
|
||||
deleteCursor();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
bool RestCursorHandler::cancel() { return cancelQuery(); }
|
||||
|
|
|
@ -56,7 +56,7 @@ class RestCursorHandler : public RestVocbaseBaseHandler {
|
|||
arangodb::aql::QueryRegistry*);
|
||||
|
||||
public:
|
||||
virtual status_t execute() override;
|
||||
virtual status execute() override;
|
||||
|
||||
bool cancel() override;
|
||||
|
||||
|
|
|
@ -40,14 +40,14 @@ RestDebugHandler::RestDebugHandler(HttpRequest* request)
|
|||
|
||||
bool RestDebugHandler::isDirect() const { return false; }
|
||||
|
||||
HttpHandler::status_t RestDebugHandler::execute() {
|
||||
RestHandler::status RestDebugHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
size_t const len = _request->suffix().size();
|
||||
|
||||
if (len == 0 || len > 2 || !(_request->suffix()[0] == "failat")) {
|
||||
generateNotImplemented("ILLEGAL /_admin/debug/failat");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
|
@ -69,7 +69,7 @@ HttpHandler::status_t RestDebugHandler::execute() {
|
|||
break;
|
||||
default:
|
||||
generateNotImplemented("ILLEGAL /_admin/debug/failat");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
try {
|
||||
VPackBuilder result;
|
||||
|
@ -78,5 +78,5 @@ HttpHandler::status_t RestDebugHandler::execute() {
|
|||
} catch (...) {
|
||||
// Ignore this error
|
||||
}
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -27,19 +27,13 @@
|
|||
#include "RestHandler/RestVocbaseBaseHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief version request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestDebugHandler : public arangodb::RestVocbaseBaseHandler {
|
||||
public:
|
||||
explicit RestDebugHandler(HttpRequest*);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ using namespace arangodb::rest;
|
|||
RestDocumentHandler::RestDocumentHandler(HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request) {}
|
||||
|
||||
HttpHandler::status_t RestDocumentHandler::execute() {
|
||||
RestHandler::status RestDocumentHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -63,13 +63,11 @@ HttpHandler::status_t RestDocumentHandler::execute() {
|
|||
case GeneralRequest::RequestType::PATCH:
|
||||
updateDocument();
|
||||
break;
|
||||
default: {
|
||||
generateNotImplemented("ILLEGAL " + DOCUMENT_PATH);
|
||||
}
|
||||
default: { generateNotImplemented("ILLEGAL " + DOCUMENT_PATH); }
|
||||
}
|
||||
|
||||
// this handler is done
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -80,7 +78,8 @@ bool RestDocumentHandler::createDocument() {
|
|||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() > 1) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
||||
"superfluous suffix, expecting " + DOCUMENT_PATH +
|
||||
"?collection=<identifier>");
|
||||
return false;
|
||||
|
@ -112,9 +111,9 @@ bool RestDocumentHandler::createDocument() {
|
|||
if (!parseSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
VPackSlice body = parsedBody->slice();
|
||||
|
||||
|
||||
arangodb::OperationOptions opOptions;
|
||||
opOptions.isRestore = extractBooleanParameter("isRestore", false);
|
||||
opOptions.waitForSync = extractBooleanParameter("waitForSync", false);
|
||||
|
@ -123,8 +122,8 @@ bool RestDocumentHandler::createDocument() {
|
|||
|
||||
// find and load collection given by name or identifier
|
||||
auto transactionContext(StandaloneTransactionContext::Create(_vocbase));
|
||||
SingleCollectionTransaction trx(transactionContext,
|
||||
collectionName, TRI_TRANSACTION_WRITE);
|
||||
SingleCollectionTransaction trx(transactionContext, collectionName,
|
||||
TRI_TRANSACTION_WRITE);
|
||||
bool const isMultiple = body.isArray();
|
||||
if (!isMultiple) {
|
||||
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
|
||||
|
@ -137,7 +136,8 @@ bool RestDocumentHandler::createDocument() {
|
|||
return false;
|
||||
}
|
||||
|
||||
arangodb::OperationResult result = trx.insert(collectionName, body, opOptions);
|
||||
arangodb::OperationResult result =
|
||||
trx.insert(collectionName, body, opOptions);
|
||||
|
||||
// Will commit if no error occured.
|
||||
// or abort if an error occured.
|
||||
|
@ -173,14 +173,16 @@ bool RestDocumentHandler::readDocument() {
|
|||
switch (len) {
|
||||
case 0:
|
||||
case 1:
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND, TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
|
||||
generateError(GeneralResponse::ResponseCode::NOT_FOUND,
|
||||
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
|
||||
"expecting GET /_api/document/<document-handle>");
|
||||
return false;
|
||||
case 2:
|
||||
return readSingleDocument(true);
|
||||
|
||||
default:
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
||||
"expecting GET /_api/document/<document-handle>");
|
||||
return false;
|
||||
}
|
||||
|
@ -202,8 +204,8 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
|
|||
TRI_voc_rid_t const ifNoneRid =
|
||||
extractRevision("if-none-match", nullptr, isValidRevision);
|
||||
if (!isValidRevision) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid revision number");
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid revision number");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -213,8 +215,8 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
|
|||
TRI_voc_rid_t const ifRid =
|
||||
extractRevision("if-match", nullptr, isValidRevision);
|
||||
if (!isValidRevision) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid revision number");
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid revision number");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -231,8 +233,8 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
|
|||
|
||||
// find and load collection given by name or identifier
|
||||
auto transactionContext(StandaloneTransactionContext::Create(_vocbase));
|
||||
SingleCollectionTransaction trx(transactionContext,
|
||||
collection, TRI_TRANSACTION_READ);
|
||||
SingleCollectionTransaction trx(transactionContext, collection,
|
||||
TRI_TRANSACTION_READ);
|
||||
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
|
||||
|
||||
// ...........................................................................
|
||||
|
@ -274,7 +276,7 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// use default options
|
||||
generateDocument(result.slice(), generateBody,
|
||||
transactionContext->getVPackOptions());
|
||||
|
@ -289,7 +291,8 @@ bool RestDocumentHandler::checkDocument() {
|
|||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() != 2) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expecting URI /_api/document/<document-handle>");
|
||||
return false;
|
||||
}
|
||||
|
@ -301,7 +304,7 @@ bool RestDocumentHandler::checkDocument() {
|
|||
/// @brief was docuBlock REST_DOCUMENT_REPLACE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool RestDocumentHandler::replaceDocument() {
|
||||
bool RestDocumentHandler::replaceDocument() {
|
||||
bool found;
|
||||
_request->value("onlyget", found);
|
||||
if (found) {
|
||||
|
@ -326,9 +329,12 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
|
|||
if (suffix.size() > 2) {
|
||||
std::string msg("expecting ");
|
||||
msg.append(isPatch ? "PATCH" : "PUT");
|
||||
msg.append(" /_api/document/<collectionname> or /_api/document/<document-handle> or /_api/document and query parameter 'collection'");
|
||||
msg.append(
|
||||
" /_api/document/<collectionname> or /_api/document/<document-handle> "
|
||||
"or /_api/document and query parameter 'collection'");
|
||||
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, msg);
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -346,8 +352,11 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
|
|||
collectionName = _request->value("collection", found);
|
||||
}
|
||||
if (!found) {
|
||||
std::string msg("collection must be given in URL path or query parameter 'collection' must be specified");
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, msg);
|
||||
std::string msg(
|
||||
"collection must be given in URL path or query parameter "
|
||||
"'collection' must be specified");
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, msg);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -364,8 +373,7 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
|
|||
|
||||
VPackSlice body = parsedBody->slice();
|
||||
|
||||
if ((!isArrayCase && !body.isObject()) ||
|
||||
(isArrayCase && !body.isArray())) {
|
||||
if ((!isArrayCase && !body.isObject()) || (isArrayCase && !body.isArray())) {
|
||||
generateTransactionError(collectionName,
|
||||
TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID, "");
|
||||
return false;
|
||||
|
@ -386,8 +394,8 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
|
|||
bool isValidRevision;
|
||||
revision = extractRevision("if-match", nullptr, isValidRevision);
|
||||
if (!isValidRevision) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid revision number");
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid revision number");
|
||||
return false;
|
||||
}
|
||||
VPackSlice keyInBody = body.get(StaticStrings::KeyString);
|
||||
|
@ -414,8 +422,8 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
|
|||
|
||||
// find and load collection given by name or identifier
|
||||
auto transactionContext(StandaloneTransactionContext::Create(_vocbase));
|
||||
SingleCollectionTransaction trx(transactionContext,
|
||||
collectionName, TRI_TRANSACTION_WRITE);
|
||||
SingleCollectionTransaction trx(transactionContext, collectionName,
|
||||
TRI_TRANSACTION_WRITE);
|
||||
if (!isArrayCase) {
|
||||
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
|
||||
}
|
||||
|
@ -472,7 +480,8 @@ bool RestDocumentHandler::deleteDocument() {
|
|||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() < 1 || suffix.size() > 2) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expecting DELETE /_api/document/<document-handle> or "
|
||||
"/_api/document/<collection> with a BODY");
|
||||
return false;
|
||||
|
@ -491,8 +500,8 @@ bool RestDocumentHandler::deleteDocument() {
|
|||
bool isValidRevision = false;
|
||||
revision = extractRevision("if-match", nullptr, isValidRevision);
|
||||
if (!isValidRevision) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"invalid revision number");
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid revision number");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -515,24 +524,28 @@ bool RestDocumentHandler::deleteDocument() {
|
|||
builder.add(StaticStrings::KeyString, VPackValue(key));
|
||||
if (revision != 0) {
|
||||
opOptions.ignoreRevs = false;
|
||||
builder.add(StaticStrings::RevString, VPackValue(std::to_string(revision)));
|
||||
builder.add(StaticStrings::RevString,
|
||||
VPackValue(std::to_string(revision)));
|
||||
}
|
||||
}
|
||||
search = builder.slice();
|
||||
} else {
|
||||
try {
|
||||
TRI_ASSERT(_request != nullptr);
|
||||
builderPtr = _request->toVelocyPack(transactionContext->getVPackOptions());
|
||||
builderPtr =
|
||||
_request->toVelocyPack(transactionContext->getVPackOptions());
|
||||
} catch (...) {
|
||||
// If an error occurs here the body is not parsable. Fail with bad parameter
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "Request body not parseable");
|
||||
// If an error occurs here the body is not parsable. Fail with bad
|
||||
// parameter
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER, "Request body not parseable");
|
||||
return false;
|
||||
}
|
||||
search = builderPtr->slice();
|
||||
}
|
||||
|
||||
SingleCollectionTransaction trx(transactionContext,
|
||||
collectionName, TRI_TRANSACTION_WRITE);
|
||||
SingleCollectionTransaction trx(transactionContext, collectionName,
|
||||
TRI_TRANSACTION_WRITE);
|
||||
if (suffix.size() == 2 || !search.isArray()) {
|
||||
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
|
||||
}
|
||||
|
@ -572,7 +585,8 @@ bool RestDocumentHandler::readManyDocuments() {
|
|||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() != 1) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expecting PUT /_api/document/<collection> with a BODY");
|
||||
return false;
|
||||
}
|
||||
|
@ -584,8 +598,8 @@ bool RestDocumentHandler::readManyDocuments() {
|
|||
opOptions.ignoreRevs = extractBooleanParameter("ignoreRevs", true);
|
||||
|
||||
auto transactionContext(StandaloneTransactionContext::Create(_vocbase));
|
||||
SingleCollectionTransaction trx(transactionContext,
|
||||
collectionName, TRI_TRANSACTION_READ);
|
||||
SingleCollectionTransaction trx(transactionContext, collectionName,
|
||||
TRI_TRANSACTION_READ);
|
||||
|
||||
// ...........................................................................
|
||||
// inside read transaction
|
||||
|
@ -599,7 +613,8 @@ bool RestDocumentHandler::readManyDocuments() {
|
|||
}
|
||||
|
||||
TRI_ASSERT(_request != nullptr);
|
||||
auto builderPtr = _request->toVelocyPack(transactionContext->getVPackOptions());
|
||||
auto builderPtr =
|
||||
_request->toVelocyPack(transactionContext->getVPackOptions());
|
||||
VPackSlice search = builderPtr->slice();
|
||||
|
||||
OperationResult result = trx.document(collectionName, search, opOptions);
|
||||
|
@ -616,8 +631,6 @@ bool RestDocumentHandler::readManyDocuments() {
|
|||
return false;
|
||||
}
|
||||
|
||||
generateDocument(result.slice(), true,
|
||||
transactionContext->getVPackOptions());
|
||||
generateDocument(result.slice(), true, transactionContext->getVPackOptions());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,79 +28,43 @@
|
|||
#include "RestHandler/RestVocbaseBaseHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief document request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestDocumentHandler : public RestVocbaseBaseHandler {
|
||||
public:
|
||||
explicit RestDocumentHandler(HttpRequest*);
|
||||
|
||||
public:
|
||||
status_t execute() override final;
|
||||
status execute() override final;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get collection type
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual TRI_col_type_e getCollectionType() const {
|
||||
return TRI_COL_TYPE_DOCUMENT;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a document
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// creates a document
|
||||
virtual bool createDocument();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads a single or all documents
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// reads a single or all documents
|
||||
bool readDocument();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads a single document
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// reads a single document
|
||||
bool readSingleDocument(bool generateBody);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads multiple documents
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// reads multiple documents
|
||||
bool readManyDocuments();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads a single document head
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// reads a single document head
|
||||
bool checkDocument();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replaces a document
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// replaces a document
|
||||
bool replaceDocument();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief updates a document
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// updates a document
|
||||
bool updateDocument();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function for replace and update
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// helper function for replace and update
|
||||
bool modifyDocument(bool);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief deletes a document
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// deletes a document
|
||||
bool deleteDocument();
|
||||
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ using namespace arangodb::rest;
|
|||
RestEchoHandler::RestEchoHandler(HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request) {}
|
||||
|
||||
HttpHandler::status_t RestEchoHandler::execute() {
|
||||
RestHandler::status RestEchoHandler::execute() {
|
||||
bool parseSuccess = true;
|
||||
std::shared_ptr<VPackBuilder> parsedBody =
|
||||
parseVelocyPackBody(&VPackOptions::Defaults, parseSuccess);
|
||||
|
@ -46,5 +46,5 @@ HttpHandler::status_t RestEchoHandler::execute() {
|
|||
generateResult(GeneralResponse::ResponseCode::OK, parsedBody->slice());
|
||||
}
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class RestEchoHandler : public arangodb::RestVocbaseBaseHandler {
|
|||
|
||||
public:
|
||||
bool isDirect() const override { return true; }
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ using namespace arangodb::rest;
|
|||
RestEdgesHandler::RestEdgesHandler(HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request) {}
|
||||
|
||||
HttpHandler::status_t RestEdgesHandler::execute() {
|
||||
RestHandler::status RestEdgesHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -62,15 +62,18 @@ HttpHandler::status_t RestEdgesHandler::execute() {
|
|||
break;
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
generateError(GeneralResponse::responseCode(ex.code()), ex.code(), ex.what());
|
||||
generateError(GeneralResponse::responseCode(ex.code()), ex.code(),
|
||||
ex.what());
|
||||
} catch (std::exception const& ex) {
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, ex.what());
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_INTERNAL, ex.what());
|
||||
} catch (...) {
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL);
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
// this handler is done
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
bool RestEdgesHandler::getEdgesForVertexList(
|
||||
|
@ -79,23 +82,23 @@ bool RestEdgesHandler::getEdgesForVertexList(
|
|||
TRI_edge_direction_e direction, SingleCollectionTransaction& trx,
|
||||
VPackBuilder& result, size_t& scannedIndex, size_t& filtered) {
|
||||
TRI_ASSERT(ids.isArray());
|
||||
trx.orderDitch(trx.cid()); // will throw when it fails
|
||||
|
||||
std::string const collectionName
|
||||
= trx.resolver()->getCollectionName(trx.cid());
|
||||
trx.orderDitch(trx.cid()); // will throw when it fails
|
||||
|
||||
std::string const collectionName =
|
||||
trx.resolver()->getCollectionName(trx.cid());
|
||||
Transaction::IndexHandle indexId = trx.edgeIndexHandle(collectionName);
|
||||
|
||||
|
||||
VPackBuilder searchValueBuilder;
|
||||
EdgeIndex::buildSearchValueFromArray(direction, ids, searchValueBuilder);
|
||||
VPackSlice search = searchValueBuilder.slice();
|
||||
|
||||
std::shared_ptr<OperationCursor> cursor = trx.indexScan(
|
||||
collectionName, arangodb::Transaction::CursorType::INDEX, indexId,
|
||||
search, 0, UINT64_MAX, 1000, false);
|
||||
|
||||
std::shared_ptr<OperationCursor> cursor =
|
||||
trx.indexScan(collectionName, arangodb::Transaction::CursorType::INDEX,
|
||||
indexId, search, 0, UINT64_MAX, 1000, false);
|
||||
if (cursor->failed()) {
|
||||
THROW_ARANGO_EXCEPTION(cursor->code);
|
||||
}
|
||||
|
||||
|
||||
auto opRes = std::make_shared<OperationResult>(TRI_ERROR_NO_ERROR);
|
||||
while (cursor->hasMore()) {
|
||||
cursor->getMore(opRes);
|
||||
|
@ -112,8 +115,7 @@ bool RestEdgesHandler::getEdgesForVertexList(
|
|||
bool add = true;
|
||||
if (!expressions.empty()) {
|
||||
for (auto& exp : expressions) {
|
||||
if (exp->isEdgeAccess &&
|
||||
!exp->matchesCheck(&trx, edge)) {
|
||||
if (exp->isEdgeAccess && !exp->matchesCheck(&trx, edge)) {
|
||||
++filtered;
|
||||
add = false;
|
||||
break;
|
||||
|
@ -131,27 +133,25 @@ bool RestEdgesHandler::getEdgesForVertexList(
|
|||
}
|
||||
|
||||
bool RestEdgesHandler::getEdgesForVertex(
|
||||
std::string const& id,
|
||||
std::string const& collectionName,
|
||||
std::string const& id, std::string const& collectionName,
|
||||
std::vector<traverser::TraverserExpression*> const& expressions,
|
||||
TRI_edge_direction_e direction, SingleCollectionTransaction& trx,
|
||||
VPackBuilder& result, size_t& scannedIndex, size_t& filtered) {
|
||||
|
||||
trx.orderDitch(trx.cid()); // will throw when it fails
|
||||
|
||||
trx.orderDitch(trx.cid()); // will throw when it fails
|
||||
|
||||
Transaction::IndexHandle indexId = trx.edgeIndexHandle(collectionName);
|
||||
|
||||
|
||||
VPackBuilder searchValueBuilder;
|
||||
EdgeIndex::buildSearchValue(direction, id, searchValueBuilder);
|
||||
VPackSlice search = searchValueBuilder.slice();
|
||||
|
||||
std::shared_ptr<OperationCursor> cursor = trx.indexScan(
|
||||
collectionName, arangodb::Transaction::CursorType::INDEX, indexId,
|
||||
search, 0, UINT64_MAX, 1000, false);
|
||||
|
||||
std::shared_ptr<OperationCursor> cursor =
|
||||
trx.indexScan(collectionName, arangodb::Transaction::CursorType::INDEX,
|
||||
indexId, search, 0, UINT64_MAX, 1000, false);
|
||||
if (cursor->failed()) {
|
||||
THROW_ARANGO_EXCEPTION(cursor->code);
|
||||
}
|
||||
|
||||
|
||||
auto opRes = std::make_shared<OperationResult>(TRI_ERROR_NO_ERROR);
|
||||
while (cursor->hasMore()) {
|
||||
cursor->getMore(opRes);
|
||||
|
@ -168,8 +168,7 @@ bool RestEdgesHandler::getEdgesForVertex(
|
|||
bool add = true;
|
||||
if (!expressions.empty()) {
|
||||
for (auto& exp : expressions) {
|
||||
if (exp->isEdgeAccess &&
|
||||
!exp->matchesCheck(&trx, edge)) {
|
||||
if (exp->isEdgeAccess && !exp->matchesCheck(&trx, edge)) {
|
||||
++filtered;
|
||||
add = false;
|
||||
break;
|
||||
|
@ -195,7 +194,8 @@ bool RestEdgesHandler::readEdges(
|
|||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() != 1) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expected GET " + EDGES_PATH +
|
||||
"/<collection-identifier>?vertex=<vertex-handle>&"
|
||||
"direction=<direction>");
|
||||
|
@ -209,10 +209,11 @@ bool RestEdgesHandler::readEdges(
|
|||
generateError(GeneralResponse::ResponseCode::NOT_FOUND,
|
||||
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (colType != TRI_COL_TYPE_EDGE) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -233,7 +234,8 @@ bool RestEdgesHandler::readEdges(
|
|||
} else if (dirString == "in" || dirString == "inbound") {
|
||||
direction = TRI_EDGE_IN;
|
||||
} else {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"<direction> must by any, in, or out, not: " + dirString);
|
||||
return false;
|
||||
}
|
||||
|
@ -241,7 +243,8 @@ bool RestEdgesHandler::readEdges(
|
|||
std::string const& startVertex = _request->value("vertex", found);
|
||||
|
||||
if (!found || startVertex.empty()) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
|
||||
"illegal document handle");
|
||||
return false;
|
||||
}
|
||||
|
@ -260,7 +263,7 @@ bool RestEdgesHandler::readEdges(
|
|||
generateError(responseCode, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
resultDocument.add("error", VPackValue(false));
|
||||
resultDocument.add("code", VPackValue(200));
|
||||
resultDocument.close();
|
||||
|
@ -271,8 +274,9 @@ bool RestEdgesHandler::readEdges(
|
|||
}
|
||||
|
||||
// find and load collection given by name or identifier
|
||||
SingleCollectionTransaction trx(StandaloneTransactionContext::Create(_vocbase),
|
||||
collectionName, TRI_TRANSACTION_READ);
|
||||
SingleCollectionTransaction trx(
|
||||
StandaloneTransactionContext::Create(_vocbase), collectionName,
|
||||
TRI_TRANSACTION_READ);
|
||||
|
||||
// .............................................................................
|
||||
// inside read transaction
|
||||
|
@ -284,14 +288,13 @@ bool RestEdgesHandler::readEdges(
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
size_t filtered = 0;
|
||||
size_t scannedIndex = 0;
|
||||
|
||||
|
||||
VPackBuilder resultBuilder;
|
||||
resultBuilder.openObject();
|
||||
// build edges
|
||||
resultBuilder.add(VPackValue("edges")); // only key
|
||||
resultBuilder.add(VPackValue("edges")); // only key
|
||||
resultBuilder.openArray();
|
||||
// NOTE: collecitonName is the shard-name in DBServer case
|
||||
bool ok =
|
||||
|
@ -307,8 +310,8 @@ bool RestEdgesHandler::readEdges(
|
|||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (ServerState::instance()->isDBServer()) {
|
||||
// If we are a DBserver, we want to use the cluster-wide collection
|
||||
// name for error reporting:
|
||||
// If we are a DBserver, we want to use the cluster-wide collection
|
||||
// name for error reporting:
|
||||
collectionName = trx.resolver()->getCollectionName(trx.cid());
|
||||
}
|
||||
generateTransactionError(collectionName, res, "");
|
||||
|
@ -320,11 +323,12 @@ bool RestEdgesHandler::readEdges(
|
|||
resultBuilder.add("stats", VPackValue(VPackValueType::Object));
|
||||
resultBuilder.add("scannedIndex", VPackValue(scannedIndex));
|
||||
resultBuilder.add("filtered", VPackValue(filtered));
|
||||
resultBuilder.close(); // inner object
|
||||
resultBuilder.close(); // inner object
|
||||
resultBuilder.close();
|
||||
|
||||
// and generate a response
|
||||
generateResult(GeneralResponse::ResponseCode::OK, resultBuilder.slice(), trx.transactionContext());
|
||||
generateResult(GeneralResponse::ResponseCode::OK, resultBuilder.slice(),
|
||||
trx.transactionContext());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -339,7 +343,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
std::vector<std::string> const& suffix = _request->suffix();
|
||||
|
||||
if (suffix.size() != 1) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expected POST " + EDGES_PATH +
|
||||
"/<collection-identifier>?direction=<direction>");
|
||||
return false;
|
||||
|
@ -350,7 +355,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
parseVelocyPackBody(&VPackOptions::Defaults, parseSuccess);
|
||||
|
||||
if (!parseSuccess) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expected POST " + EDGES_PATH +
|
||||
"/<collection-identifier>?direction=<direction>");
|
||||
// A body is required
|
||||
|
@ -359,7 +365,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
VPackSlice body = parsedBody->slice();
|
||||
|
||||
if (!body.isArray()) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"Expected an array of vertex _id's in body parameter");
|
||||
return false;
|
||||
}
|
||||
|
@ -373,7 +380,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
return false;
|
||||
} else if (colType != TRI_COL_TYPE_EDGE) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -393,7 +401,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
} else if (dirString == "in" || dirString == "inbound") {
|
||||
direction = TRI_EDGE_IN;
|
||||
} else {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"<direction> must by any, in, or out, not: " + dirString);
|
||||
return false;
|
||||
}
|
||||
|
@ -410,8 +419,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
std::string vertexString(it.copyString());
|
||||
|
||||
int res = getFilteredEdgesOnCoordinator(
|
||||
_vocbase->_name, collectionName, vertexString, direction, expressions,
|
||||
responseCode, contentType, resultDocument);
|
||||
_vocbase->_name, collectionName, vertexString, direction,
|
||||
expressions, responseCode, contentType, resultDocument);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
generateError(responseCode, res);
|
||||
return false;
|
||||
|
@ -427,8 +436,9 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
}
|
||||
|
||||
// find and load collection given by name or identifier
|
||||
SingleCollectionTransaction trx(StandaloneTransactionContext::Create(_vocbase),
|
||||
collectionName, TRI_TRANSACTION_READ);
|
||||
SingleCollectionTransaction trx(
|
||||
StandaloneTransactionContext::Create(_vocbase), collectionName,
|
||||
TRI_TRANSACTION_READ);
|
||||
|
||||
// .............................................................................
|
||||
// inside read transaction
|
||||
|
@ -452,7 +462,7 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
VPackBuilder resultBuilder;
|
||||
resultBuilder.openObject();
|
||||
// build edges
|
||||
resultBuilder.add(VPackValue("edges")); // only key
|
||||
resultBuilder.add(VPackValue("edges")); // only key
|
||||
resultBuilder.openArray();
|
||||
|
||||
bool ok = getEdgesForVertexList(body, expressions, direction, trx,
|
||||
|
@ -475,8 +485,8 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
|||
resultBuilder.add("stats", VPackValue(VPackValueType::Object));
|
||||
resultBuilder.add("scannedIndex", VPackValue(scannedIndex));
|
||||
resultBuilder.add("filtered", VPackValue(filtered));
|
||||
resultBuilder.close(); // inner object
|
||||
resultBuilder.close();
|
||||
resultBuilder.close(); // inner object
|
||||
resultBuilder.close();
|
||||
|
||||
// and generate a response
|
||||
generateResult(GeneralResponse::ResponseCode::OK, resultBuilder.slice(),
|
||||
|
|
|
@ -41,7 +41,7 @@ class RestEdgesHandler : public RestVocbaseBaseHandler {
|
|||
explicit RestEdgesHandler(HttpRequest*);
|
||||
|
||||
public:
|
||||
status_t execute() override final;
|
||||
status execute() override final;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -44,12 +44,12 @@ using namespace arangodb::rest;
|
|||
RestExportHandler::RestExportHandler(HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request), _restrictions() {}
|
||||
|
||||
HttpHandler::status_t RestExportHandler::execute() {
|
||||
RestHandler::status RestExportHandler::execute() {
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
generateError(GeneralResponse::ResponseCode::NOT_IMPLEMENTED,
|
||||
TRI_ERROR_CLUSTER_UNSUPPORTED,
|
||||
"'/_api/export' is not yet supported in a cluster");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
// extract the sub-request type
|
||||
|
@ -57,22 +57,22 @@ HttpHandler::status_t RestExportHandler::execute() {
|
|||
|
||||
if (type == GeneralRequest::RequestType::POST) {
|
||||
createCursor();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (type == GeneralRequest::RequestType::PUT) {
|
||||
modifyCursor();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (type == GeneralRequest::RequestType::DELETE_REQ) {
|
||||
deleteCursor();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -30,22 +30,22 @@ namespace arangodb {
|
|||
class HttpRequest;
|
||||
|
||||
namespace rest {
|
||||
class HttpHandler;
|
||||
class RestHandler;
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
class RestHandlerCreator : public H {
|
||||
public:
|
||||
static rest::HttpHandler* create(HttpRequest* request, void* data) {
|
||||
static rest::RestHandler* create(HttpRequest* request, void* data) {
|
||||
return new H(request, data);
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
static rest::HttpHandler* createData(HttpRequest* request, void* data) {
|
||||
static rest::RestHandler* createData(HttpRequest* request, void* data) {
|
||||
return new H(request, (D)data);
|
||||
}
|
||||
|
||||
static rest::HttpHandler* createNoData(HttpRequest* request, void*) {
|
||||
static rest::RestHandler* createNoData(HttpRequest* request, void*) {
|
||||
return new H(request);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -49,12 +49,12 @@ using namespace arangodb::rest;
|
|||
RestImportHandler::RestImportHandler(HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request), _onDuplicateAction(DUPLICATE_ERROR) {}
|
||||
|
||||
HttpHandler::status_t RestImportHandler::execute() {
|
||||
RestHandler::status RestImportHandler::execute() {
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
generateError(GeneralResponse::ResponseCode::NOT_IMPLEMENTED,
|
||||
TRI_ERROR_CLUSTER_UNSUPPORTED,
|
||||
"'/_api/import' is not yet supported in a cluster");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
// set default value for onDuplicate
|
||||
|
@ -113,7 +113,7 @@ HttpHandler::status_t RestImportHandler::execute() {
|
|||
}
|
||||
|
||||
// this handler is done
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -65,7 +65,7 @@ class RestImportHandler : public RestVocbaseBaseHandler {
|
|||
explicit RestImportHandler(HttpRequest*);
|
||||
|
||||
public:
|
||||
status_t execute() override final;
|
||||
status execute() override final;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ RestJobHandler::RestJobHandler(HttpRequest* request,
|
|||
|
||||
bool RestJobHandler::isDirect() const { return true; }
|
||||
|
||||
HttpHandler::status_t RestJobHandler::execute() {
|
||||
RestHandler::status RestJobHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -69,7 +69,7 @@ HttpHandler::status_t RestJobHandler::execute() {
|
|||
(int)GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -49,7 +49,7 @@ class RestJobHandler : public RestBaseHandler {
|
|||
/// @brief executes the handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief put handler
|
||||
|
|
|
@ -28,11 +28,11 @@ using namespace arangodb::basics;
|
|||
using namespace arangodb::rest;
|
||||
|
||||
RestPleaseUpgradeHandler::RestPleaseUpgradeHandler(HttpRequest* request)
|
||||
: HttpHandler(request) {}
|
||||
: RestHandler(request) {}
|
||||
|
||||
bool RestPleaseUpgradeHandler::isDirect() const { return true; }
|
||||
|
||||
HttpHandler::status_t RestPleaseUpgradeHandler::execute() {
|
||||
RestHandler::status RestPleaseUpgradeHandler::execute() {
|
||||
createResponse(GeneralResponse::ResponseCode::OK);
|
||||
_response->setContentType(HttpResponse::CONTENT_TYPE_TEXT);
|
||||
|
||||
|
@ -47,7 +47,7 @@ HttpHandler::status_t RestPleaseUpgradeHandler::execute() {
|
|||
buffer.appendText(" /etc/init.d/arangodb start\r\n\r\n");
|
||||
buffer.appendText("Please check the log file for details.\r\n");
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
void RestPleaseUpgradeHandler::handleError(const Exception&) {}
|
||||
|
|
|
@ -24,18 +24,16 @@
|
|||
#ifndef ARANGOD_REST_HANDLER_REST_PLEASE_UPGRADE_HANDLER_H
|
||||
#define ARANGOD_REST_HANDLER_REST_PLEASE_UPGRADE_HANDLER_H 1
|
||||
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
class RestPleaseUpgradeHandler : public rest::HttpHandler {
|
||||
class RestPleaseUpgradeHandler : public rest::RestHandler {
|
||||
public:
|
||||
explicit RestPleaseUpgradeHandler(HttpRequest*);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
|
||||
status execute() override;
|
||||
void handleError(const basics::Exception&) override;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ RestQueryCacheHandler::RestQueryCacheHandler(HttpRequest* request)
|
|||
|
||||
bool RestQueryCacheHandler::isDirect() const { return false; }
|
||||
|
||||
HttpHandler::status_t RestQueryCacheHandler::execute() {
|
||||
RestHandler::status RestQueryCacheHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -55,7 +55,7 @@ HttpHandler::status_t RestQueryCacheHandler::execute() {
|
|||
}
|
||||
|
||||
// this handler is done
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -39,8 +39,7 @@ class RestQueryCacheHandler : public RestVocbaseBaseHandler {
|
|||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -51,7 +51,7 @@ bool RestQueryHandler::isDirect() const {
|
|||
return _request->requestType() != GeneralRequest::RequestType::POST;
|
||||
}
|
||||
|
||||
HttpHandler::status_t RestQueryHandler::execute() {
|
||||
RestHandler::status RestQueryHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -86,7 +86,7 @@ HttpHandler::status_t RestQueryHandler::execute() {
|
|||
}
|
||||
|
||||
// this handler is done
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
bool RestQueryHandler::readQueryProperties() {
|
||||
|
|
|
@ -39,8 +39,7 @@ class RestQueryHandler : public RestVocbaseBaseHandler {
|
|||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -67,7 +67,7 @@ RestReplicationHandler::RestReplicationHandler(HttpRequest* request)
|
|||
|
||||
RestReplicationHandler::~RestReplicationHandler() {}
|
||||
|
||||
HttpHandler::status_t RestReplicationHandler::execute() {
|
||||
RestHandler::status RestReplicationHandler::execute() {
|
||||
// extract the request type
|
||||
auto const type = _request->requestType();
|
||||
auto const& suffix = _request->suffix();
|
||||
|
@ -87,7 +87,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
goto BAD_CALL;
|
||||
}
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
handleCommandLoggerTickRanges();
|
||||
} else if (command == "logger-first-tick") {
|
||||
|
@ -95,7 +95,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
goto BAD_CALL;
|
||||
}
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
handleCommandLoggerFirstTick();
|
||||
} else if (command == "logger-follow") {
|
||||
|
@ -104,7 +104,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
goto BAD_CALL;
|
||||
}
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
handleCommandLoggerFollow();
|
||||
} else if (command == "determine-open-transactions") {
|
||||
|
@ -120,7 +120,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
}
|
||||
} else if (command == "barrier") {
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
handleCommandBarrier();
|
||||
} else if (command == "inventory") {
|
||||
|
@ -141,7 +141,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
if (type == GeneralRequest::RequestType::POST) {
|
||||
|
@ -191,7 +191,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
handleCommandSync();
|
||||
|
@ -201,7 +201,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
handleCommandMakeSlave();
|
||||
|
@ -225,7 +225,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
handleCommandApplierStart();
|
||||
|
@ -235,7 +235,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
handleCommandApplierStop();
|
||||
|
@ -273,7 +273,7 @@ HttpHandler::status_t RestReplicationHandler::execute() {
|
|||
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid command");
|
||||
}
|
||||
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
BAD_CALL:
|
||||
|
@ -286,7 +286,7 @@ BAD_CALL:
|
|||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -46,7 +46,7 @@ class RestReplicationHandler : public RestVocbaseBaseHandler {
|
|||
~RestReplicationHandler();
|
||||
|
||||
public:
|
||||
HttpHandler::status_t execute();
|
||||
RestHandler::status execute();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -41,7 +41,7 @@ bool RestShutdownHandler::isDirect() const { return true; }
|
|||
/// @brief was docuBlock JSF_get_api_initiate
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::status_t RestShutdownHandler::execute() {
|
||||
RestHandler::status RestShutdownHandler::execute() {
|
||||
ApplicationServer::server->beginShutdown();
|
||||
|
||||
try {
|
||||
|
@ -52,5 +52,5 @@ HttpHandler::status_t RestShutdownHandler::execute() {
|
|||
// Ignore the error
|
||||
}
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class RestShutdownHandler : public RestBaseHandler {
|
|||
/// @brief initiates the shutdown process
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ RestSimpleHandler::RestSimpleHandler(
|
|||
_query(nullptr),
|
||||
_queryKilled(false) {}
|
||||
|
||||
HttpHandler::status_t RestSimpleHandler::execute() {
|
||||
RestHandler::status RestSimpleHandler::execute() {
|
||||
// extract the request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -60,7 +60,7 @@ HttpHandler::status_t RestSimpleHandler::execute() {
|
|||
parseVelocyPackBody(&VPackOptions::Defaults, parsingSuccess);
|
||||
|
||||
if (!parsingSuccess) {
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
VPackSlice body = parsedBody.get()->slice();
|
||||
|
@ -68,7 +68,7 @@ HttpHandler::status_t RestSimpleHandler::execute() {
|
|||
if (!body.isObject()) {
|
||||
generateError(GeneralResponse::ResponseCode::BAD, TRI_ERROR_TYPE_ERROR,
|
||||
"expecting JSON object body");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
std::string const& prefix = _request->requestPath();
|
||||
|
@ -82,12 +82,12 @@ HttpHandler::status_t RestSimpleHandler::execute() {
|
|||
"unsupported value for <operation>");
|
||||
}
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
bool RestSimpleHandler::cancel() { return cancelQuery(); }
|
||||
|
|
|
@ -44,8 +44,7 @@ class RestSimpleHandler : public RestVocbaseBaseHandler {
|
|||
RestSimpleHandler(HttpRequest*, arangodb::aql::QueryRegistry*);
|
||||
|
||||
public:
|
||||
status_t execute() override final;
|
||||
|
||||
status execute() override final;
|
||||
bool cancel() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -41,7 +41,7 @@ RestSimpleQueryHandler::RestSimpleQueryHandler(
|
|||
arangodb::aql::QueryRegistry* queryRegistry)
|
||||
: RestCursorHandler(request, queryRegistry) {}
|
||||
|
||||
HttpHandler::status_t RestSimpleQueryHandler::execute() {
|
||||
RestHandler::status RestSimpleQueryHandler::execute() {
|
||||
// extract the sub-request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -50,18 +50,18 @@ HttpHandler::status_t RestSimpleQueryHandler::execute() {
|
|||
if (prefix == RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_PATH) {
|
||||
// all query
|
||||
allDocuments();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
if (prefix == RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_KEYS_PATH) {
|
||||
// all-keys query
|
||||
allDocumentKeys();
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
}
|
||||
|
||||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -32,32 +32,16 @@ namespace aql {
|
|||
class QueryRegistry;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief cursor request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestSimpleQueryHandler : public RestCursorHandler {
|
||||
public:
|
||||
RestSimpleQueryHandler(
|
||||
HttpRequest*,
|
||||
arangodb::aql::QueryRegistry*);
|
||||
RestSimpleQueryHandler(HttpRequest*, arangodb::aql::QueryRegistry*);
|
||||
|
||||
public:
|
||||
status_t execute() override final;
|
||||
status execute() override final;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a cursor with all documents from the collection
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void allDocuments();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a cursor with all document keys from the collection
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void allDocumentKeys();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ RestUploadHandler::RestUploadHandler(HttpRequest* request)
|
|||
|
||||
RestUploadHandler::~RestUploadHandler() {}
|
||||
|
||||
HttpHandler::status_t RestUploadHandler::execute() {
|
||||
RestHandler::status RestUploadHandler::execute() {
|
||||
// extract the request type
|
||||
auto const type = _request->requestType();
|
||||
|
||||
|
@ -48,7 +48,7 @@ HttpHandler::status_t RestUploadHandler::execute() {
|
|||
generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
char* filename = nullptr;
|
||||
|
@ -60,7 +60,7 @@ HttpHandler::status_t RestUploadHandler::execute() {
|
|||
errorMessage = "could not generate temp file: " + errorMessage;
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_INTERNAL, errorMessage);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status::FAILED;
|
||||
}
|
||||
|
||||
char* relative = TRI_GetFilename(filename);
|
||||
|
@ -84,7 +84,7 @@ HttpHandler::status_t RestUploadHandler::execute() {
|
|||
TRI_Free(TRI_CORE_MEM_ZONE, filename);
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_INTERNAL, "invalid multipart request");
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status::HANDLER_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ HttpHandler::status_t RestUploadHandler::execute() {
|
|||
TRI_Free(TRI_CORE_MEM_ZONE, filename);
|
||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||
TRI_ERROR_INTERNAL, "could not save file");
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
return status::HANDLER_FAILED;
|
||||
}
|
||||
|
||||
char* fullName = TRI_Concatenate2File("uploads", relative);
|
||||
|
@ -117,8 +117,9 @@ HttpHandler::status_t RestUploadHandler::execute() {
|
|||
VPackSlice s = b.slice();
|
||||
|
||||
generateResult(GeneralResponse::ResponseCode::CREATED, s);
|
||||
|
||||
// success
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -37,7 +37,7 @@ class RestUploadHandler : public RestVocbaseBaseHandler {
|
|||
~RestUploadHandler();
|
||||
|
||||
public:
|
||||
HttpHandler::status_t execute();
|
||||
RestHandler::status execute();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parses a multi-part request body and determines the boundaries of
|
||||
|
|
|
@ -43,7 +43,7 @@ RestVersionHandler::RestVersionHandler(HttpRequest* request)
|
|||
|
||||
bool RestVersionHandler::isDirect() const { return true; }
|
||||
|
||||
HttpHandler::status_t RestVersionHandler::execute() {
|
||||
RestHandler::status RestVersionHandler::execute() {
|
||||
try {
|
||||
VPackBuilder result;
|
||||
result.add(VPackValue(VPackValueType::Object));
|
||||
|
@ -71,5 +71,5 @@ HttpHandler::status_t RestVersionHandler::execute() {
|
|||
} catch (...) {
|
||||
// Ignore this error
|
||||
}
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -27,19 +27,13 @@
|
|||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief version request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestVersionHandler : public arangodb::RestBaseHandler {
|
||||
public:
|
||||
explicit RestVersionHandler(arangodb::HttpRequest*);
|
||||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "WorkMonitorHandler.h"
|
||||
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "velocypack/Builder.h"
|
||||
#include "velocypack/velocypack-aliases.h"
|
||||
|
@ -33,14 +33,14 @@ using namespace arangodb::basics;
|
|||
using namespace arangodb::rest;
|
||||
|
||||
using arangodb::HttpRequest;
|
||||
using arangodb::rest::HttpHandler;
|
||||
using arangodb::rest::RestHandler;
|
||||
|
||||
WorkMonitorHandler::WorkMonitorHandler(HttpRequest* request)
|
||||
: RestBaseHandler(request) {}
|
||||
|
||||
bool WorkMonitorHandler::isDirect() const { return true; }
|
||||
|
||||
HttpHandler::status_t WorkMonitorHandler::execute() {
|
||||
RestHandler::status WorkMonitorHandler::execute() {
|
||||
auto suffix = _request->suffix();
|
||||
size_t const len = suffix.size();
|
||||
auto const type = _request->requestType();
|
||||
|
@ -50,11 +50,11 @@ HttpHandler::status_t WorkMonitorHandler::execute() {
|
|||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expecting GET /_admin/work-monitor");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
WorkMonitor::requestWorkOverview(_taskId);
|
||||
return status_t(HANDLER_ASYNC);
|
||||
return status::ASYNC;
|
||||
}
|
||||
|
||||
if (type == GeneralRequest::RequestType::DELETE_REQ) {
|
||||
|
@ -63,7 +63,7 @@ HttpHandler::status_t WorkMonitorHandler::execute() {
|
|||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expecting DELETE /_admin/work-monitor/<id>");
|
||||
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
uint64_t id = StringUtils::uint64(suffix[0]);
|
||||
|
@ -77,10 +77,10 @@ HttpHandler::status_t WorkMonitorHandler::execute() {
|
|||
VPackSlice s(b.start());
|
||||
|
||||
generateResult(GeneralResponse::ResponseCode::OK, s);
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
||||
generateError(GeneralResponse::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED, "expecting GET or DELETE");
|
||||
return status_t(HANDLER_DONE);
|
||||
return status::DONE;
|
||||
}
|
||||
|
|
|
@ -32,8 +32,7 @@ class WorkMonitorHandler : public arangodb::RestBaseHandler {
|
|||
|
||||
public:
|
||||
bool isDirect() const override;
|
||||
|
||||
status_t execute() override;
|
||||
status execute() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "Cluster/AgencyComm.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
#include "HttpServer/RestHandlerFactory.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Rest/GeneralResponse.h"
|
||||
#include "Rest/Version.h"
|
||||
|
@ -145,7 +145,7 @@ void BootstrapFeature::start() {
|
|||
}
|
||||
|
||||
// Start service properly:
|
||||
arangodb::rest::HttpHandlerFactory::setMaintenance(false);
|
||||
rest::RestHandlerFactory::setMaintenance(false);
|
||||
LOG(INFO) << "ArangoDB (version " << ARANGODB_VERSION_FULL
|
||||
<< ") is ready for business. Have fun!";
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
#include "Cluster/RestAgencyCallbacksHandler.h"
|
||||
#include "Cluster/RestShardHandler.h"
|
||||
#include "Dispatcher/DispatcherFeature.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
#include "HttpServer/HttpServer.h"
|
||||
#include "HttpServer/HttpsServer.h"
|
||||
#include "HttpServer/RestHandlerFactory.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
#include "ProgramOptions/Section.h"
|
||||
#include "Rest/Version.h"
|
||||
|
@ -182,7 +182,7 @@ static bool SetRequestContext(HttpRequest* request, void* data) {
|
|||
}
|
||||
|
||||
void RestServerFeature::prepare() {
|
||||
HttpHandlerFactory::setMaintenance(true);
|
||||
RestHandlerFactory::setMaintenance(true);
|
||||
}
|
||||
|
||||
void RestServerFeature::start() {
|
||||
|
@ -190,7 +190,7 @@ void RestServerFeature::start() {
|
|||
|
||||
_httpOptions._vocbase = DatabaseFeature::DATABASE->vocbase();
|
||||
|
||||
_handlerFactory.reset(new HttpHandlerFactory(
|
||||
_handlerFactory.reset(new RestHandlerFactory(
|
||||
_authenticationRealm, _allowMethodOverride,
|
||||
&SetRequestContext, DatabaseServerFeature::SERVER));
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
namespace arangodb {
|
||||
namespace rest {
|
||||
class AsyncJobManager;
|
||||
class HttpHandlerFactory;
|
||||
class RestHandlerFactory;
|
||||
class HttpServer;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,10 @@ class RestServerThread;
|
|||
|
||||
class RestServerFeature final
|
||||
: public application_features::ApplicationFeature {
|
||||
public:
|
||||
static rest::RestHandlerFactory* HANDLER_FACTORY;
|
||||
static rest::AsyncJobManager* JOB_MANAGER;
|
||||
|
||||
public:
|
||||
RestServerFeature(application_features::ApplicationServer*,
|
||||
std::string const&);
|
||||
|
@ -67,10 +71,9 @@ class RestServerFeature final
|
|||
void defineHandlers();
|
||||
|
||||
private:
|
||||
std::unique_ptr<rest::HttpHandlerFactory> _handlerFactory;
|
||||
std::unique_ptr<rest::RestHandlerFactory> _handlerFactory;
|
||||
std::unique_ptr<rest::AsyncJobManager> _jobManager;
|
||||
std::vector<rest::HttpServer*> _servers;
|
||||
RestActionHandler::action_options_t _httpOptions;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
namespace arangodb {
|
||||
namespace rest {
|
||||
class HttpHandlerFactory;
|
||||
class RestHandlerFactory;
|
||||
class AsyncJobManager;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ class TaskData : public RequestStatisticsAgent {
|
|||
EventLoop _loop;
|
||||
uint64_t _type;
|
||||
std::string _data;
|
||||
std::unique_ptr<HttpResponse> _response;
|
||||
std::unique_ptr<GeneralResponse> _response;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "Aql/QueryList.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/StringBuffer.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/RestHandler.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Scheduler/Scheduler.h"
|
||||
#include "Scheduler/SchedulerFeature.h"
|
||||
|
@ -44,7 +44,7 @@ using namespace arangodb::rest;
|
|||
/// @brief pushes a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void WorkMonitor::pushHandler(HttpHandler* handler) {
|
||||
void WorkMonitor::pushHandler(RestHandler* handler) {
|
||||
TRI_ASSERT(handler != nullptr);
|
||||
WorkDescription* desc = createWorkDescription(WorkType::HANDLER);
|
||||
desc->_data.handler = handler;
|
||||
|
@ -57,7 +57,7 @@ void WorkMonitor::pushHandler(HttpHandler* handler) {
|
|||
/// @brief pops and releases a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WorkDescription* WorkMonitor::popHandler(HttpHandler* handler, bool free) {
|
||||
WorkDescription* WorkMonitor::popHandler(RestHandler* handler, bool free) {
|
||||
WorkDescription* desc = deactivateWorkDescription();
|
||||
|
||||
TRI_ASSERT(desc != nullptr);
|
||||
|
@ -123,8 +123,8 @@ void WorkMonitor::deleteHandler(WorkDescription* desc) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void WorkMonitor::vpackHandler(VPackBuilder* b, WorkDescription* desc) {
|
||||
HttpHandler* handler = desc->_data.handler;
|
||||
const HttpRequest* request = handler->getRequest();
|
||||
RestHandler* handler = desc->_data.handler;
|
||||
GeneralRequest const* request = handler->getRequest();
|
||||
|
||||
b->add("type", VPackValue("http-handler"));
|
||||
b->add("protocol", VPackValue(request->protocol()));
|
||||
|
@ -158,10 +158,6 @@ void WorkMonitor::vpackHandler(VPackBuilder* b, WorkDescription* desc) {
|
|||
b->close();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sends the overview
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void WorkMonitor::sendWorkOverview(uint64_t taskId, std::string const& data) {
|
||||
auto response = std::make_unique<HttpResponse>(GeneralResponse::ResponseCode::OK);
|
||||
|
||||
|
@ -179,11 +175,11 @@ void WorkMonitor::sendWorkOverview(uint64_t taskId, std::string const& data) {
|
|||
SchedulerFeature::SCHEDULER->signalTask(answer);
|
||||
}
|
||||
|
||||
HandlerWorkStack::HandlerWorkStack(HttpHandler* handler) : _handler(handler) {
|
||||
HandlerWorkStack::HandlerWorkStack(RestHandler* handler) : _handler(handler) {
|
||||
WorkMonitor::pushHandler(_handler);
|
||||
}
|
||||
|
||||
HandlerWorkStack::HandlerWorkStack(WorkItem::uptr<HttpHandler>& handler) {
|
||||
HandlerWorkStack::HandlerWorkStack(WorkItem::uptr<RestHandler>& handler) {
|
||||
_handler = handler.release();
|
||||
WorkMonitor::pushHandler(_handler);
|
||||
}
|
||||
|
|
|
@ -37,36 +37,50 @@ std::string const StaticStrings::RevString("_rev");
|
|||
std::string const StaticStrings::FromString("_from");
|
||||
std::string const StaticStrings::ToString("_to");
|
||||
|
||||
// database and collection names
|
||||
// database and collection names
|
||||
std::string const StaticStrings::SystemDatabase("_system");
|
||||
|
||||
// HTTP headers
|
||||
std::string const StaticStrings::Accept("accept");
|
||||
std::string const StaticStrings::AcceptEncoding("accept-encoding");
|
||||
std::string const StaticStrings::AccessControlAllowCredentials("access-control-allow-credentials");
|
||||
std::string const StaticStrings::AccessControlAllowHeaders("access-control-allow-headers");
|
||||
std::string const StaticStrings::AccessControlAllowMethods("access-control-allow-methods");
|
||||
std::string const StaticStrings::AccessControlAllowOrigin("access-control-allow-origin");
|
||||
std::string const StaticStrings::AccessControlExposeHeaders("access-control-expose-headers");
|
||||
std::string const StaticStrings::AccessControlAllowCredentials(
|
||||
"access-control-allow-credentials");
|
||||
std::string const StaticStrings::AccessControlAllowHeaders(
|
||||
"access-control-allow-headers");
|
||||
std::string const StaticStrings::AccessControlAllowMethods(
|
||||
"access-control-allow-methods");
|
||||
std::string const StaticStrings::AccessControlAllowOrigin(
|
||||
"access-control-allow-origin");
|
||||
std::string const StaticStrings::AccessControlExposeHeaders(
|
||||
"access-control-expose-headers");
|
||||
std::string const StaticStrings::AccessControlMaxAge("access-control-max-age");
|
||||
std::string const StaticStrings::AccessControlRequestHeaders("access-control-request-headers");
|
||||
std::string const StaticStrings::AccessControlRequestHeaders(
|
||||
"access-control-request-headers");
|
||||
std::string const StaticStrings::Allow("allow");
|
||||
std::string const StaticStrings::Async("x-arango-async");
|
||||
std::string const StaticStrings::AsyncId("x-arango-async-id");
|
||||
std::string const StaticStrings::Authorization("authorization");
|
||||
std::string const StaticStrings::BatchContentType("application/x-arango-batchpart");
|
||||
std::string const StaticStrings::BatchContentType(
|
||||
"application/x-arango-batchpart");
|
||||
std::string const StaticStrings::CacheControl("cache-control");
|
||||
std::string const StaticStrings::Close("Close");
|
||||
std::string const StaticStrings::Code("code");
|
||||
std::string const StaticStrings::Connection("connection");
|
||||
std::string const StaticStrings::ContentEncoding("content-encoding");
|
||||
std::string const StaticStrings::ContentTypeHeader("content-type");
|
||||
std::string const StaticStrings::Coordinator("x-arango-coordinator");
|
||||
std::string const StaticStrings::CorsMethods("DELETE, GET, HEAD, PATCH, POST, PUT");
|
||||
std::string const StaticStrings::CorsMethods(
|
||||
"DELETE, GET, HEAD, PATCH, POST, PUT");
|
||||
std::string const StaticStrings::Error("error");
|
||||
std::string const StaticStrings::ErrorMessage("errorMessage");
|
||||
std::string const StaticStrings::ErrorNum("errorNum");
|
||||
std::string const StaticStrings::Errors("x-arango-errors");
|
||||
std::string const StaticStrings::ErrorCodes("x-arango-error-codes");
|
||||
std::string const StaticStrings::Etag("etag");
|
||||
std::string const StaticStrings::Expect("expect");
|
||||
std::string const StaticStrings::ExposedCorsHeaders("etag, content-encoding, content-length, location, server, x-arango-errors, x-arango-async-id");
|
||||
std::string const StaticStrings::ExposedCorsHeaders(
|
||||
"etag, content-encoding, content-length, location, server, "
|
||||
"x-arango-errors, x-arango-async-id");
|
||||
std::string const StaticStrings::KeepAlive("Keep-Alive");
|
||||
std::string const StaticStrings::Location("location");
|
||||
std::string const StaticStrings::MultiPartContentType("multipart/form-data");
|
||||
|
@ -75,10 +89,9 @@ std::string const StaticStrings::Origin("origin");
|
|||
std::string const StaticStrings::Queue("x-arango-queue");
|
||||
std::string const StaticStrings::Server("server");
|
||||
std::string const StaticStrings::WwwAuthenticate("www-authenticate");
|
||||
|
||||
|
||||
// mime types
|
||||
std::string const StaticStrings::MimeTypeJson("application/json; charset=utf-8");
|
||||
std::string const StaticStrings::MimeTypeJson(
|
||||
"application/json; charset=utf-8");
|
||||
std::string const StaticStrings::MimeTypeText("text/plain; charset=utf-8");
|
||||
std::string const StaticStrings::MimeTypeVPack("application/x-velocypack");
|
||||
|
||||
|
|
|
@ -63,11 +63,15 @@ class StaticStrings {
|
|||
static std::string const BatchContentType;
|
||||
static std::string const CacheControl;
|
||||
static std::string const Close;
|
||||
static std::string const Code;
|
||||
static std::string const Connection;
|
||||
static std::string const ContentEncoding;
|
||||
static std::string const ContentTypeHeader;
|
||||
static std::string const Coordinator;
|
||||
static std::string const CorsMethods;
|
||||
static std::string const Error;
|
||||
static std::string const ErrorMessage;
|
||||
static std::string const ErrorNum;
|
||||
static std::string const Errors;
|
||||
static std::string const ErrorCodes;
|
||||
static std::string const Etag;
|
||||
|
|
|
@ -30,7 +30,7 @@ struct TRI_vocbase_t;
|
|||
|
||||
namespace arangodb {
|
||||
namespace rest {
|
||||
class HttpHandler;
|
||||
class RestHandler;
|
||||
}
|
||||
|
||||
class Thread;
|
||||
|
@ -67,7 +67,7 @@ struct WorkDescription {
|
|||
|
||||
char text[256];
|
||||
Thread* thread;
|
||||
arangodb::rest::HttpHandler* handler;
|
||||
rest::RestHandler* handler;
|
||||
} _data;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -363,12 +363,12 @@ void WorkMonitor::run() {
|
|||
}
|
||||
|
||||
while (WORK_OVERVIEW.pop(taskId)) {
|
||||
VPackBuilder b;
|
||||
VPackBuilder builder;
|
||||
|
||||
b.add(VPackValue(VPackValueType::Object));
|
||||
builder.add(VPackValue(VPackValueType::Object));
|
||||
|
||||
b.add("time", VPackValue(TRI_microtime()));
|
||||
b.add("work", VPackValue(VPackValueType::Array));
|
||||
builder.add("time", VPackValue(TRI_microtime()));
|
||||
builder.add("work", VPackValue(VPackValueType::Array));
|
||||
|
||||
{
|
||||
MUTEX_LOCKER(guard, THREADS_LOCK);
|
||||
|
@ -377,9 +377,9 @@ void WorkMonitor::run() {
|
|||
WorkDescription* desc = thread->workDescription();
|
||||
|
||||
if (desc != nullptr) {
|
||||
b.add(VPackValue(VPackValueType::Object));
|
||||
vpackWorkDescription(&b, desc);
|
||||
b.close();
|
||||
builder.add(VPackValue(VPackValueType::Object));
|
||||
vpackWorkDescription(&builder, desc);
|
||||
builder.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,18 +387,7 @@ void WorkMonitor::run() {
|
|||
b.close();
|
||||
b.close();
|
||||
|
||||
VPackSlice s(b.start());
|
||||
|
||||
VPackOptions options;
|
||||
options.prettyPrint = true;
|
||||
|
||||
std::string buffer;
|
||||
VPackStringSink sink(&buffer);
|
||||
|
||||
VPackDumper dumper(&sink, &options);
|
||||
dumper.dump(s);
|
||||
|
||||
sendWorkOverview(taskId, buffer);
|
||||
sendWorkOverview(taskId, b);
|
||||
}
|
||||
} catch (...) {
|
||||
// must prevent propagation of exceptions from here
|
||||
|
|
|
@ -56,8 +56,8 @@ class WorkMonitor : public Thread {
|
|||
static void pushCustom(char const* type, char const* text, size_t length);
|
||||
static void pushCustom(char const* type, uint64_t id);
|
||||
static void popCustom();
|
||||
static void pushHandler(arangodb::rest::HttpHandler*);
|
||||
static WorkDescription* popHandler(arangodb::rest::HttpHandler*, bool free);
|
||||
static void pushHandler(rest::RestHandler*);
|
||||
static WorkDescription* popHandler(rest::RestHandler*, bool free);
|
||||
static void requestWorkOverview(uint64_t taskId);
|
||||
static void cancelWork(uint64_t id);
|
||||
|
||||
|
@ -68,7 +68,7 @@ class WorkMonitor : public Thread {
|
|||
static void sendWorkOverview(uint64_t, std::string const&);
|
||||
static bool cancelAql(WorkDescription*);
|
||||
static void deleteHandler(WorkDescription* desc);
|
||||
static void vpackHandler(arangodb::velocypack::Builder*,
|
||||
static void vpackHandler(velocypack::Builder*,
|
||||
WorkDescription* desc);
|
||||
|
||||
static WorkDescription* createWorkDescription(WorkType);
|
||||
|
@ -80,7 +80,7 @@ class WorkMonitor : public Thread {
|
|||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief auto push and pop for HttpHandler
|
||||
/// @brief auto push and pop for RestHandler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HandlerWorkStack {
|
||||
|
@ -88,9 +88,9 @@ class HandlerWorkStack {
|
|||
HandlerWorkStack& operator=(const HandlerWorkStack&) = delete;
|
||||
|
||||
public:
|
||||
explicit HandlerWorkStack(arangodb::rest::HttpHandler*);
|
||||
explicit HandlerWorkStack(rest::RestHandler*);
|
||||
|
||||
explicit HandlerWorkStack(WorkItem::uptr<arangodb::rest::HttpHandler>&);
|
||||
explicit HandlerWorkStack(WorkItem::uptr<rest::RestHandler>&);
|
||||
|
||||
~HandlerWorkStack();
|
||||
|
||||
|
@ -99,14 +99,14 @@ class HandlerWorkStack {
|
|||
/// @brief returns the handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::rest::HttpHandler* handler() const { return _handler; }
|
||||
rest::RestHandler* handler() const { return _handler; }
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handler
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::rest::HttpHandler* _handler;
|
||||
rest::RestHandler* _handler;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
#include "Endpoint/ConnectionInfo.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
class Builder;
|
||||
struct Options;
|
||||
}
|
||||
|
||||
class RequestContext;
|
||||
|
||||
class GeneralRequest {
|
||||
|
@ -48,7 +53,7 @@ class GeneralRequest {
|
|||
// VSTREAM_STATUS: Returns STATUS code and message for a given
|
||||
// request
|
||||
enum class RequestType {
|
||||
DELETE_REQ = 0, // windows redefines DELETE
|
||||
DELETE_REQ = 0, // windows redefines DELETE
|
||||
GET,
|
||||
HEAD,
|
||||
OPTIONS,
|
||||
|
@ -145,7 +150,9 @@ class GeneralRequest {
|
|||
// The key must be lowercase.
|
||||
std::string const& header(std::string const& key) const;
|
||||
std::string const& header(std::string const& key, bool& found) const;
|
||||
std::unordered_map<std::string, std::string> const& headers() const { return _headers; }
|
||||
std::unordered_map<std::string, std::string> const& headers() const {
|
||||
return _headers;
|
||||
}
|
||||
|
||||
std::string const& value(std::string const& key) const;
|
||||
std::string const& value(std::string const& key, bool& found) const;
|
||||
|
@ -153,12 +160,17 @@ class GeneralRequest {
|
|||
return _values;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::string>> arrayValues() const {
|
||||
std::unordered_map<std::string, std::vector<std::string>> arrayValues()
|
||||
const {
|
||||
return _arrayValues;
|
||||
}
|
||||
void setArrayValue(std::string const& key, std::string const& value);
|
||||
|
||||
bool velocyPackResponse () const;
|
||||
bool velocyPackResponse() const;
|
||||
|
||||
// the request body as VelocyPackBuilder
|
||||
virtual std::shared_ptr<arangodb::velocypack::Builder> toVelocyPack(
|
||||
arangodb::velocypack::Options const*) = 0;
|
||||
|
||||
protected:
|
||||
void setValue(char const* key, char const* value);
|
||||
|
|
|
@ -97,6 +97,15 @@ class GeneralResponse {
|
|||
NOT_EXTENDED = 510
|
||||
};
|
||||
|
||||
enum class ContentType {
|
||||
CUSTOM, // use Content-Type from _headers
|
||||
JSON, // application/json
|
||||
VPACK, // application/x-velocypack
|
||||
TEXT, // text/plain
|
||||
HTML, // text/html
|
||||
DUMP // application/x-arango-dump
|
||||
};
|
||||
|
||||
public:
|
||||
// converts the response code to a string for delivering to a http client.
|
||||
static std::string responseString(ResponseCode);
|
||||
|
@ -107,8 +116,10 @@ class GeneralResponse {
|
|||
// response code from integer error code
|
||||
static ResponseCode responseCode(int);
|
||||
|
||||
public:
|
||||
protected:
|
||||
explicit GeneralResponse(ResponseCode);
|
||||
|
||||
public:
|
||||
virtual ~GeneralResponse() {}
|
||||
|
||||
public:
|
||||
|
|
|
@ -31,14 +31,22 @@
|
|||
#include "Endpoint/ConnectionInfo.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace rest {
|
||||
class HttpCommTask;
|
||||
}
|
||||
|
||||
namespace velocypack {
|
||||
class Builder;
|
||||
struct Options;
|
||||
}
|
||||
|
||||
class HttpRequest : public GeneralRequest {
|
||||
public:
|
||||
friend class HttpCommTask;
|
||||
|
||||
private:
|
||||
HttpRequest(ConnectionInfo const&, char const*, size_t, bool);
|
||||
|
||||
public:
|
||||
~HttpRequest();
|
||||
|
||||
public:
|
||||
|
@ -54,17 +62,20 @@ class HttpRequest : public GeneralRequest {
|
|||
|
||||
std::string const& cookieValue(std::string const& key) const;
|
||||
std::string const& cookieValue(std::string const& key, bool& found) const;
|
||||
std::unordered_map<std::string, std::string> cookieValues() const { return _cookies; }
|
||||
std::unordered_map<std::string, std::string> cookieValues() const {
|
||||
return _cookies;
|
||||
}
|
||||
|
||||
std::string const& body() const;
|
||||
void setBody(char const* body, size_t length);
|
||||
|
||||
// the request body as VelocyPackBuilder
|
||||
std::shared_ptr<arangodb::velocypack::Builder> toVelocyPack(
|
||||
arangodb::velocypack::Options const*);
|
||||
|
||||
arangodb::velocypack::Options const*) override final;
|
||||
|
||||
/// @brief sets a key/value header
|
||||
void setHeader(char const* key, size_t keyLength, char const* value, size_t valueLength);
|
||||
void setHeader(char const* key, size_t keyLength, char const* value,
|
||||
size_t valueLength);
|
||||
/// @brief sets a key-only header
|
||||
void setHeader(char const* key, size_t keyLength);
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ bool HttpResponse::HIDE_PRODUCT_HEADER = false;
|
|||
HttpResponse::HttpResponse(ResponseCode code)
|
||||
: GeneralResponse(code),
|
||||
_connectionType(CONNECTION_KEEP_ALIVE),
|
||||
_contentType(CONTENT_TYPE_TEXT),
|
||||
_contentType(ContentType::TEXT),
|
||||
_isHeadResponse(false),
|
||||
_body(TRI_UNKNOWN_MEM_ZONE, false),
|
||||
_bodySize(0) {
|
||||
|
@ -55,6 +55,17 @@ HttpResponse::HttpResponse(ResponseCode code)
|
|||
}
|
||||
}
|
||||
|
||||
void HttpResponse::reset(ResponseCode code) {
|
||||
_responseCode = code;
|
||||
_headers.clear();
|
||||
|
||||
_connectionType = CONNECTION_KEEP_ALIVE;
|
||||
_contentType = ContentType::TEXT;
|
||||
_isHeadResponse = false;
|
||||
_body.clear();
|
||||
_bodySize = 0;
|
||||
}
|
||||
|
||||
void HttpResponse::setCookie(std::string const& name, std::string const& value,
|
||||
int lifeTimeSeconds, std::string const& path,
|
||||
std::string const& domain, bool secure,
|
||||
|
@ -221,27 +232,27 @@ void HttpResponse::writeHeader(StringBuffer* output) {
|
|||
|
||||
// add "Content-Type" header
|
||||
switch (_contentType) {
|
||||
case CONTENT_TYPE_JSON:
|
||||
case ContentType::JSON:
|
||||
output->appendText(TRI_CHAR_LENGTH_PAIR(
|
||||
"Content-Type: application/json; charset=utf-8\r\n"));
|
||||
break;
|
||||
case CONTENT_TYPE_VPACK:
|
||||
case ContentType::VPACK:
|
||||
output->appendText(
|
||||
TRI_CHAR_LENGTH_PAIR("Content-Type: application/x-velocypack\r\n"));
|
||||
break;
|
||||
case CONTENT_TYPE_TEXT:
|
||||
case ContentType::TEXT:
|
||||
output->appendText(
|
||||
TRI_CHAR_LENGTH_PAIR("Content-Type: text/plain; charset=utf-8\r\n"));
|
||||
break;
|
||||
case CONTENT_TYPE_HTML:
|
||||
case ContentType::HTML:
|
||||
output->appendText(
|
||||
TRI_CHAR_LENGTH_PAIR("Content-Type: text/html; charset=utf-8\r\n"));
|
||||
break;
|
||||
case CONTENT_TYPE_DUMP:
|
||||
case ContentType::DUMP:
|
||||
output->appendText(TRI_CHAR_LENGTH_PAIR(
|
||||
"Content-Type: application/x-arango-dump; charset=utf-8\r\n"));
|
||||
break;
|
||||
case CONTENT_TYPE_CUSTOM: {
|
||||
case ContentType::CUSTOM: {
|
||||
// intentionally don't print anything here
|
||||
// the header should have been in _headers already, and should have been
|
||||
// handled above
|
||||
|
@ -292,7 +303,7 @@ void HttpResponse::fillBody(GeneralRequest const* request,
|
|||
bool generateBody, VPackOptions const& options) {
|
||||
// VELOCYPACK
|
||||
if (request->velocyPackResponse()) {
|
||||
setContentType(HttpResponse::CONTENT_TYPE_VPACK);
|
||||
setContentType(HttpResponse::ContentType::VPACK);
|
||||
size_t length = static_cast<size_t>(slice.byteSize());
|
||||
|
||||
if (generateBody) {
|
||||
|
@ -304,7 +315,7 @@ void HttpResponse::fillBody(GeneralRequest const* request,
|
|||
|
||||
// JSON
|
||||
else {
|
||||
setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||
setContentType(HttpResponse::ContentType::JSON);
|
||||
|
||||
if (generateBody) {
|
||||
arangodb::basics::VelocyPackDumper dumper(&_body, &options);
|
||||
|
|
|
@ -30,11 +30,17 @@
|
|||
#include "Basics/StringBuffer.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace rest {
|
||||
class HttpCommTask;
|
||||
}
|
||||
|
||||
class HttpResponse : public GeneralResponse {
|
||||
friend class HttpCommTask;
|
||||
|
||||
public:
|
||||
static bool HIDE_PRODUCT_HEADER;
|
||||
|
||||
public:
|
||||
private:
|
||||
explicit HttpResponse(ResponseCode code);
|
||||
|
||||
public:
|
||||
|
@ -46,17 +52,8 @@ class HttpResponse : public GeneralResponse {
|
|||
CONNECTION_CLOSE
|
||||
};
|
||||
|
||||
enum ContentType {
|
||||
CONTENT_TYPE_CUSTOM, // use Content-Type from _headers
|
||||
CONTENT_TYPE_JSON, // application/json
|
||||
CONTENT_TYPE_VPACK, // application/x-velocypack
|
||||
CONTENT_TYPE_TEXT, // text/plain
|
||||
CONTENT_TYPE_HTML, // text/html
|
||||
CONTENT_TYPE_DUMP // application/x-arango-dump
|
||||
};
|
||||
|
||||
public:
|
||||
using GeneralResponse::setHeader;
|
||||
void reset(ResponseCode code);
|
||||
|
||||
void setCookie(std::string const& name, std::string const& value,
|
||||
int lifeTimeSeconds, std::string const& path,
|
||||
|
@ -84,13 +81,13 @@ class HttpResponse : public GeneralResponse {
|
|||
/// cases when the content-type is user-defined
|
||||
void setContentType(std::string const& contentType) {
|
||||
_headers[arangodb::StaticStrings::ContentTypeHeader] = contentType;
|
||||
_contentType = CONTENT_TYPE_CUSTOM;
|
||||
_contentType = ContentType::CUSTOM;
|
||||
}
|
||||
|
||||
void setContentType(std::string&& contentType) {
|
||||
_headers[arangodb::StaticStrings::ContentTypeHeader] =
|
||||
std::move(contentType);
|
||||
_contentType = CONTENT_TYPE_CUSTOM;
|
||||
_contentType = ContentType::CUSTOM;
|
||||
}
|
||||
|
||||
// you should call writeHeader only after the body has been created
|
||||
|
|
Loading…
Reference in New Issue