1
0
Fork 0

Merge branch 'dotdot' into devel

This commit is contained in:
Alan Plum 2016-11-15 18:10:17 +01:00
commit d1c52e696c
No known key found for this signature in database
GPG Key ID: 8ED72A9A323B6EFD
34 changed files with 415 additions and 192 deletions

View File

@ -3,6 +3,8 @@ devel
* added option -D to define a configuration file environment key=value
* Foxx request URL suffix is no longer unescaped
v3.1.1 (XXXX-XX-XX)
-------------------

View File

@ -119,7 +119,9 @@ The request object specifies the following properties:
* **suffix**: `string`
The trailing path relative to the current route if the current route ends in a wildcard.
The trailing path relative to the current route if the current route ends in a wildcard (e.g. `/something/*`).
**Note**: Starting with ArangoDB 3.2 is passed into the service as-is, i.e. percentage escape sequences like `%2F` will no longer be unescaped. Also note that the suffix may contain path segments like `..` which may have special meaning if the suffix is used to build filesystem paths.
* **trustProxy**: `boolean`

View File

@ -113,10 +113,10 @@ TRI_action_t* TRI_DefineActionVocBase(std::string const& name,
TRI_action_t* TRI_LookupActionVocBase(arangodb::GeneralRequest* request) {
// check if we know a callback
std::vector<std::string> suffix = request->suffix();
std::vector<std::string> suffixes = request->decodedSuffixes();
// find a direct match
std::string name = StringUtils::join(suffix, '/');
std::string name = StringUtils::join(suffixes, '/');
READ_LOCKER(readLocker, ActionsLock);
std::map<std::string, TRI_action_t*>::iterator i = Actions.find(name);
@ -127,18 +127,18 @@ TRI_action_t* TRI_LookupActionVocBase(arangodb::GeneralRequest* request) {
// find longest prefix match
while (true) {
name = StringUtils::join(suffix, '/');
i = PrefixActions.find(name);
if (i != PrefixActions.end()) {
return i->second;
}
if (suffix.empty()) {
if (suffixes.empty()) {
break;
}
suffix.pop_back();
suffixes.pop_back();
name = StringUtils::join(suffixes, '/');
}
return nullptr;

View File

@ -66,7 +66,7 @@ inline RestStatus RestAgencyHandler::reportTooManySuffices() {
inline RestStatus RestAgencyHandler::reportUnknownMethod() {
LOG_TOPIC(WARN, Logger::AGENCY) << "Public REST interface has no method "
<< _request->suffix()[0];
<< _request->suffixes()[0];
generateError(rest::ResponseCode::NOT_FOUND, 405);
return RestStatus::DONE;
}
@ -330,26 +330,27 @@ inline RestStatus RestAgencyHandler::reportMethodNotAllowed() {
RestStatus RestAgencyHandler::execute() {
try {
if (_request->suffix().size() == 0) { // Empty request
auto const& suffixes = _request->suffixes();
if (suffixes.empty()) { // Empty request
return reportErrorEmptyRequest();
} else if (_request->suffix().size() > 1) { // path size >= 2
} else if (suffixes.size() > 1) { // path size >= 2
return reportTooManySuffices();
} else {
if (_request->suffix()[0] == "write") {
if (suffixes[0] == "write") {
return handleWrite();
} else if (_request->suffix()[0] == "read") {
} else if (suffixes[0] == "read") {
return handleRead();
} else if (_request->suffix()[0] == "config") {
} else if (suffixes[0] == "config") {
if (_request->requestType() != rest::RequestType::GET) {
return reportMethodNotAllowed();
}
return handleConfig();
} else if (_request->suffix()[0] == "state") {
} else if (suffixes[0] == "state") {
if (_request->requestType() != rest::RequestType::GET) {
return reportMethodNotAllowed();
}
return handleState();
} else if (_request->suffix()[0] == "stores") {
} else if (suffixes[0] == "stores") {
return handleStores();
} else {
return reportUnknownMethod();

View File

@ -85,16 +85,19 @@ RestStatus RestAgencyPrivHandler::execute() {
VPackBuilder result;
result.add(VPackValue(VPackValueType::Object));
arangodb::velocypack::Options opts;
if (_request->suffix().size() == 0) { // empty request
auto const& suffixes = _request->suffixes();
if (suffixes.empty()) { // empty request
return reportErrorEmptyRequest();
} else if (_request->suffix().size() > 1) { // request too long
} else if (suffixes.size() > 1) { // request too long
return reportTooManySuffices();
} else {
term_t term = 0;
term_t prevLogTerm = 0;
std::string id; // leaderId for appendEntries, cadidateId for requestVote
arangodb::consensus::index_t prevLogIndex, leaderCommit;
if (_request->suffix()[0] == "appendEntries") { // appendEntries
if (suffixes[0] == "appendEntries") { // appendEntries
if (_request->requestType() != rest::RequestType::POST) {
return reportMethodNotAllowed();
}
@ -109,7 +112,7 @@ RestStatus RestAgencyPrivHandler::execute() {
} else {
return reportBadQuery(); // bad query
}
} else if (_request->suffix()[0] == "requestVote") { // requestVote
} else if (suffixes[0] == "requestVote") { // requestVote
if (readValue("term", term) && readValue("candidateId", id) &&
readValue("prevLogIndex", prevLogIndex) &&
readValue("prevLogTerm", prevLogTerm)) {
@ -118,7 +121,7 @@ RestStatus RestAgencyPrivHandler::execute() {
result.add("term", VPackValue(ret.term));
result.add("voteGranted", VPackValue(ret.success));
}
} else if (_request->suffix()[0] == "notifyAll") { // notify
} else if (suffixes[0] == "notifyAll") { // notify
if (_request->requestType() != rest::RequestType::POST) {
return reportMethodNotAllowed();
}
@ -130,7 +133,7 @@ RestStatus RestAgencyPrivHandler::execute() {
} else {
return reportBadQuery(); // bad query
}
} else if (_request->suffix()[0] == "activate") { // notify
} else if (suffixes[0] == "activate") { // notify
if (_request->requestType() != rest::RequestType::POST) {
return reportMethodNotAllowed();
}
@ -151,7 +154,7 @@ RestStatus RestAgencyPrivHandler::execute() {
LOG_TOPIC(ERR, Logger::AGENCY) << "Activation failed: " << e.what();
}
} else if (_request->suffix()[0] == "gossip") {
} else if (suffixes[0] == "gossip") {
if (_request->requestType() != rest::RequestType::POST) {
return reportMethodNotAllowed();
}
@ -165,7 +168,7 @@ RestStatus RestAgencyPrivHandler::execute() {
} catch (std::exception const& e) {
return reportBadQuery(e.what());
}
} else if (_request->suffix()[0] == "measure") {
} else if (suffixes[0] == "measure") {
if (_request->requestType() != rest::RequestType::POST) {
return reportMethodNotAllowed();
}
@ -176,7 +179,7 @@ RestStatus RestAgencyPrivHandler::execute() {
} catch (std::exception const& e) {
return reportBadQuery(e.what());
}
} else if (_request->suffix()[0] == "activeAgents") {
} else if (suffixes[0] == "activeAgents") {
if (_request->requestType() != rest::RequestType::GET) {
return reportMethodNotAllowed();
}
@ -184,7 +187,7 @@ RestStatus RestAgencyPrivHandler::execute() {
result.add("active",
_agent->config().activeAgentsToBuilder()->slice());
}
} else if (_request->suffix()[0] == "inform") {
} else if (suffixes[0] == "inform") {
arangodb::velocypack::Options options;
query_t query = _request->toVelocyPackBuilderPtr(&options);
try {

View File

@ -565,7 +565,7 @@ RestStatus RestAqlHandler::execute() {
// " << arangodb::ServerState::instance()->getId() << ": " <<
// _request->fullUrl() << ": " << _request->body() << "\n\n";
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
// extract the sub-request type
rest::RequestType type = _request->requestType();
@ -573,16 +573,16 @@ RestStatus RestAqlHandler::execute() {
// execute one of the CRUD methods
switch (type) {
case rest::RequestType::POST: {
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_HTTP_NOT_FOUND);
} else if (suffix[0] == "instantiate") {
} else if (suffixes[0] == "instantiate") {
createQueryFromVelocyPack();
} else if (suffix[0] == "parse") {
} else if (suffixes[0] == "parse") {
parseQuery();
} else if (suffix[0] == "explain") {
} else if (suffixes[0] == "explain") {
explainQuery();
} else if (suffix[0] == "query") {
} else if (suffixes[0] == "query") {
createQueryFromString();
} else {
LOG(ERR) << "Unknown API";
@ -592,21 +592,22 @@ RestStatus RestAqlHandler::execute() {
break;
}
case rest::RequestType::PUT: {
if (suffix.size() != 2) {
if (suffixes.size() != 2) {
LOG(ERR) << "unknown PUT API";
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_HTTP_NOT_FOUND);
} else {
useQuery(suffix[0], suffix[1]);
useQuery(suffixes[0], suffixes[1]);
}
break;
}
case rest::RequestType::GET: {
if (suffix.size() != 2) {
if (suffixes.size() != 2) {
LOG(ERR) << "Unknown GET API";
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_HTTP_NOT_FOUND);
} else {
getInfoQuery(suffix[0], suffix[1]);
getInfoQuery(suffixes[0], suffixes[1]);
}
break;
}

View File

@ -1859,7 +1859,7 @@ int modifyDocumentOnCoordinator(
requests.emplace_back(
"shard:" + it.first, reqType,
baseUrl + StringUtils::urlEncode(it.first) + "/" +
slice.get(StaticStrings::KeyString).copyString() + optsUrlPart,
StringUtils::urlEncode(slice.get(StaticStrings::KeyString).copyString()) + optsUrlPart,
body);
} else {
reqBuilder.clear();

View File

@ -39,9 +39,9 @@ RestAgencyCallbacksHandler::RestAgencyCallbacksHandler(GeneralRequest* request,
bool RestAgencyCallbacksHandler::isDirect() const { return false; }
RestStatus RestAgencyCallbacksHandler::execute() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid callback");
return RestStatus::DONE;
@ -67,7 +67,7 @@ RestStatus RestAgencyCallbacksHandler::execute() {
}
try {
std::stringstream ss(suffix.at(0));
std::stringstream ss(suffixes.at(0));
uint32_t index;
ss >> index;

View File

@ -82,8 +82,8 @@ RestStatus InternalRestTraverserHandler::execute() {
}
void InternalRestTraverserHandler::createEngine() {
std::vector<std::string> const& suffix = _request->suffix();
if (!suffix.empty()) {
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (!suffixes.empty()) {
// POST does not allow path parameters
generateError(ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
@ -111,8 +111,8 @@ void InternalRestTraverserHandler::createEngine() {
}
void InternalRestTraverserHandler::queryEngine() {
std::vector<std::string> const& suffix = _request->suffix();
size_t count = suffix.size();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
size_t count = suffixes.size();
if (count < 2 || count > 3) {
generateError(
ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
@ -120,8 +120,8 @@ void InternalRestTraverserHandler::queryEngine() {
return;
}
std::string const& option = suffix[0];
auto engineId = static_cast<traverser::TraverserEngineID>(basics::StringUtils::uint64(suffix[1]));
std::string const& option = suffixes[0];
auto engineId = static_cast<traverser::TraverserEngineID>(basics::StringUtils::uint64(suffixes[1]));
if (engineId == 0) {
generateError(
ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
@ -149,7 +149,7 @@ void InternalRestTraverserHandler::queryEngine() {
"expected PUT " + INTERNAL_TRAVERSER_PATH + "/lock/<TraverserEngineId>/<shardId>");
return;
}
if (!engine->lockCollection(suffix[2])) {
if (!engine->lockCollection(suffixes[2])) {
generateError(ResponseCode::SERVER_ERROR,
TRI_ERROR_HTTP_SERVER_ERROR, "lock lead to an exception");
return;
@ -237,8 +237,8 @@ void InternalRestTraverserHandler::queryEngine() {
}
void InternalRestTraverserHandler::destroyEngine() {
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 1) {
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffixes.size() != 1) {
// DELETE requires the id as path parameter
generateError(
ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
@ -246,7 +246,7 @@ void InternalRestTraverserHandler::destroyEngine() {
return;
}
traverser::TraverserEngineID id = basics::StringUtils::uint64(suffix[0]);
traverser::TraverserEngineID id = basics::StringUtils::uint64(suffixes[0]);
_registry->destroy(id);
generateResult(ResponseCode::OK,
arangodb::basics::VelocyPackHelper::TrueValue());

View File

@ -43,7 +43,7 @@ RestAdminLogHandler::RestAdminLogHandler(GeneralRequest* request,
bool RestAdminLogHandler::isDirect() const { return true; }
RestStatus RestAdminLogHandler::execute() {
size_t const len = _request->suffix().size();
size_t const len = _request->suffixes().size();
if (len == 0) {
reportLogs();
@ -257,12 +257,12 @@ void RestAdminLogHandler::reportLogs() {
}
void RestAdminLogHandler::setLogLevel() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
// was validated earlier
TRI_ASSERT(suffix.size() > 0);
TRI_ASSERT(!suffixes.empty());
if (suffix[0] != "level") {
if (suffixes[0] != "level") {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting /_admin/log/level");

View File

@ -396,9 +396,9 @@ void RestCursorHandler::createCursor() {
return;
}
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 0) {
if (!suffixes.empty()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting POST /_api/cursor");
return;
@ -426,15 +426,15 @@ void RestCursorHandler::createCursor() {
////////////////////////////////////////////////////////////////////////////////
void RestCursorHandler::modifyCursor() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/cursor/<cursor-id>");
return;
}
std::string const& id = suffix[0];
std::string const& id = suffixes[0];
auto cursors = _vocbase->cursorRepository();
TRI_ASSERT(cursors != nullptr);
@ -479,15 +479,15 @@ void RestCursorHandler::modifyCursor() {
////////////////////////////////////////////////////////////////////////////////
void RestCursorHandler::deleteCursor() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/cursor/<cursor-id>");
return;
}
std::string const& id = suffix[0];
std::string const& id = suffixes[0];
auto cursors = _vocbase->cursorRepository();
TRI_ASSERT(cursors != nullptr);

View File

@ -40,13 +40,13 @@ bool RestDebugHandler::isDirect() const { return false; }
RestStatus RestDebugHandler::execute() {
// extract the sub-request type
auto const type = _request->requestType();
size_t const len = _request->suffix().size();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
size_t const len = suffixes.size();
if (len == 0 || len > 2 || !(_request->suffix()[0] == "failat")) {
if (len == 0 || len > 2 || suffixes[0] != "failat") {
generateNotImplemented("ILLEGAL /_admin/debug/failat");
return RestStatus::DONE;
}
std::vector<std::string> const& suffix = _request->suffix();
// execute one of the CRUD methods
switch (type) {
@ -54,12 +54,12 @@ RestStatus RestDebugHandler::execute() {
if (len == 1) {
TRI_ClearFailurePointsDebugging();
} else {
TRI_RemoveFailurePointDebugging(suffix[1].c_str());
TRI_RemoveFailurePointDebugging(suffixes[1].c_str());
}
break;
case rest::RequestType::PUT:
if (len == 2) {
TRI_AddFailurePointDebugging(suffix[1].c_str());
TRI_AddFailurePointDebugging(suffixes[1].c_str());
} else {
generateNotImplemented("ILLEGAL /_admin/debug/failat");
}

View File

@ -75,9 +75,9 @@ RestStatus RestDocumentHandler::execute() {
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::createDocument() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() > 1) {
if (suffixes.size() > 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + DOCUMENT_PATH +
@ -87,8 +87,8 @@ bool RestDocumentHandler::createDocument() {
bool found;
std::string collectionName;
if (suffix.size() == 1) {
collectionName = suffix[0];
if (suffixes.size() == 1) {
collectionName = suffixes[0];
found = true;
} else {
collectionName = _request->value("collection", found);
@ -168,7 +168,7 @@ bool RestDocumentHandler::createDocument() {
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::readDocument() {
size_t const len = _request->suffix().size();
size_t const len = _request->suffixes().size();
switch (len) {
case 0:
@ -193,11 +193,11 @@ bool RestDocumentHandler::readDocument() {
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::readSingleDocument(bool generateBody) {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
// split the document reference
std::string const& collection = suffix[0];
std::string const& key = suffix[1];
std::string const& collection = suffixes[0];
std::string const& key = suffixes[1];
// check for an etag
bool isValidRevision;
@ -288,9 +288,9 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::checkDocument() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() != 2) {
if (suffixes.size() != 2) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting URI /_api/document/<document-handle>");
@ -324,9 +324,9 @@ bool RestDocumentHandler::updateDocument() { return modifyDocument(true); }
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::modifyDocument(bool isPatch) {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() > 2) {
if (suffixes.size() > 2) {
std::string msg("expecting ");
msg.append(isPatch ? "PATCH" : "PUT");
msg.append(
@ -338,15 +338,15 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
return false;
}
bool isArrayCase = suffix.size() <= 1;
bool isArrayCase = suffixes.size() <= 1;
std::string collectionName;
std::string key;
if (isArrayCase) {
bool found;
if (suffix.size() == 1) {
collectionName = suffix[0];
if (suffixes.size() == 1) {
collectionName = suffixes[0];
found = true;
} else {
collectionName = _request->value("collection", found);
@ -360,8 +360,8 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
return false;
}
} else {
collectionName = suffix[0];
key = suffix[1];
collectionName = suffixes[0];
key = suffixes[1];
}
bool parseSuccess = true;
@ -477,9 +477,9 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::deleteDocument() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() < 1 || suffix.size() > 2) {
if (suffixes.size() < 1 || suffixes.size() > 2) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/document/<document-handle> or "
@ -488,15 +488,15 @@ bool RestDocumentHandler::deleteDocument() {
}
// split the document reference
std::string const& collectionName = suffix[0];
std::string const& collectionName = suffixes[0];
std::string key;
if (suffix.size() == 2) {
key = suffix[1];
if (suffixes.size() == 2) {
key = suffixes[1];
}
// extract the revision if single document case
TRI_voc_rid_t revision = 0;
if (suffix.size() == 2) {
if (suffixes.size() == 2) {
bool isValidRevision = false;
revision = extractRevision("if-match", nullptr, isValidRevision);
if (!isValidRevision) {
@ -518,7 +518,7 @@ bool RestDocumentHandler::deleteDocument() {
VPackSlice search;
std::shared_ptr<VPackBuilder> builderPtr;
if (suffix.size() == 2) {
if (suffixes.size() == 2) {
{
VPackObjectBuilder guard(&builder);
builder.add(StaticStrings::KeyString, VPackValue(key));
@ -551,7 +551,7 @@ bool RestDocumentHandler::deleteDocument() {
SingleCollectionTransaction trx(transactionContext, collectionName,
TRI_TRANSACTION_WRITE);
if (suffix.size() == 2 || !search.isArray()) {
if (suffixes.size() == 2 || !search.isArray()) {
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
}
@ -587,9 +587,9 @@ bool RestDocumentHandler::deleteDocument() {
////////////////////////////////////////////////////////////////////////////////
bool RestDocumentHandler::readManyDocuments() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/document/<collection> with a BODY");
@ -597,7 +597,7 @@ bool RestDocumentHandler::readManyDocuments() {
}
// split the document reference
std::string const& collectionName = suffix[0];
std::string const& collectionName = suffixes[0];
OperationOptions opOptions;
opOptions.ignoreRevs = extractBooleanParameter("ignoreRevs", true);

View File

@ -151,9 +151,9 @@ bool RestEdgesHandler::getEdgesForVertex(
// read in- or outbound edges
bool RestEdgesHandler::readEdges() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expected GET " + EDGES_PATH +
@ -162,7 +162,7 @@ bool RestEdgesHandler::readEdges() {
return false;
}
std::string collectionName = suffix[0];
std::string collectionName = suffixes[0];
CollectionNameResolver resolver(_vocbase);
TRI_col_type_e colType = resolver.getCollectionTypeCluster(collectionName);
if (colType == TRI_COL_TYPE_UNKNOWN) {
@ -295,9 +295,9 @@ bool RestEdgesHandler::readEdges() {
// Not publicly documented on purpose.
// NOTE: It ONLY except _id strings. Nothing else
bool RestEdgesHandler::readEdgesForMultipleVertices() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expected POST " + EDGES_PATH +
@ -326,7 +326,7 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() {
return false;
}
std::string collectionName = suffix[0];
std::string collectionName = suffixes[0];
CollectionNameResolver resolver(_vocbase);
TRI_col_type_e colType = resolver.getCollectionTypeCluster(collectionName);

View File

@ -177,9 +177,9 @@ VPackBuilder RestExportHandler::buildOptions(VPackSlice const& slice) {
////////////////////////////////////////////////////////////////////////////////
void RestExportHandler::createCursor() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 0) {
if (!suffixes.empty()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting POST /_api/export");
return;
@ -290,15 +290,15 @@ void RestExportHandler::createCursor() {
}
void RestExportHandler::modifyCursor() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/export/<cursor-id>");
return;
}
std::string const& id = suffix[0];
std::string const& id = suffixes[0];
auto cursors = _vocbase->cursorRepository();
TRI_ASSERT(cursors != nullptr);
@ -341,15 +341,15 @@ void RestExportHandler::modifyCursor() {
}
void RestExportHandler::deleteCursor() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/export/<cursor-id>");
return;
}
std::string const& id = suffix[0];
std::string const& id = suffixes[0];
auto cursors = _vocbase->cursorRepository();
TRI_ASSERT(cursors != nullptr);

View File

@ -281,9 +281,9 @@ bool RestImportHandler::createFromJson(std::string const& type) {
RestImportResult result;
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 0) {
if (!suffixes.empty()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + IMPORT_PATH +
"?collection=<identifier>");
@ -534,9 +534,9 @@ bool RestImportHandler::createFromVPack(std::string const& type) {
RestImportResult result;
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 0) {
if (!suffixes.empty()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + IMPORT_PATH +
"?collection=<identifier>");
@ -642,9 +642,9 @@ bool RestImportHandler::createFromKeyValueList() {
RestImportResult result;
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 0) {
if (!suffixes.empty()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + IMPORT_PATH +
"?collection=<identifier>");

View File

@ -52,11 +52,11 @@ RestStatus RestJobHandler::execute() {
if (type == rest::RequestType::GET) {
getJob();
} else if (type == rest::RequestType::PUT) {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() == 1) {
if (suffixes.size() == 1) {
putJob();
} else if (suffix.size() == 2) {
} else if (suffixes.size() == 2) {
putJobMethod();
} else {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER);
@ -72,8 +72,8 @@ RestStatus RestJobHandler::execute() {
}
void RestJobHandler::putJob() {
std::vector<std::string> const& suffix = _request->suffix();
std::string const& value = suffix[0];
std::vector<std::string> const& suffixes = _request->suffixes();
std::string const& value = suffixes[0];
uint64_t jobId = StringUtils::uint64(value);
AsyncJobResult::Status status;
@ -103,9 +103,9 @@ void RestJobHandler::putJob() {
}
void RestJobHandler::putJobMethod() {
std::vector<std::string> const& suffix = _request->suffix();
std::string const& value = suffix[0];
std::string const& method = suffix[1];
std::vector<std::string> const& suffixes = _request->suffixes();
std::string const& value = suffixes[0];
std::string const& method = suffixes[1];
uint64_t jobId = StringUtils::uint64(value);
if (method == "cancel") {
@ -130,14 +130,14 @@ void RestJobHandler::putJobMethod() {
}
void RestJobHandler::getJob() {
std::vector<std::string> const suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER);
return;
}
std::string const type = suffix[0];
std::string const type = suffixes[0];
if (!type.empty() && type[0] >= '1' && type[0] <= '9') {
getJobById(type);
@ -201,14 +201,14 @@ void RestJobHandler::getJobByType(std::string const& type) {
}
void RestJobHandler::deleteJob() {
std::vector<std::string> const suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER);
return;
}
std::string const& value = suffix[0];
std::string const& value = suffixes[0];
if (value == "all") {
_jobManager->deleteJobResults();

View File

@ -93,9 +93,9 @@ bool RestQueryCacheHandler::readProperties() {
////////////////////////////////////////////////////////////////////////////////
bool RestQueryCacheHandler::replaceProperties() {
auto const& suffix = _request->suffix();
auto const& suffixes = _request->suffixes();
if (suffix.size() != 1 || suffix[0] != "properties") {
if (suffixes.size() != 1 || suffixes[0] != "properties") {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/query-cache/properties");

View File

@ -131,16 +131,16 @@ bool RestQueryHandler::readQuery(bool slow) {
////////////////////////////////////////////////////////////////////////////////
bool RestQueryHandler::readQuery() {
const auto& suffix = _request->suffix();
auto const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting GET /_api/query/<type>");
return true;
}
auto const& name = suffix[0];
auto const& name = suffixes[0];
if (name == "slow") {
return readQuery(true);
@ -200,16 +200,16 @@ bool RestQueryHandler::deleteQuery(std::string const& name) {
////////////////////////////////////////////////////////////////////////////////
bool RestQueryHandler::deleteQuery() {
const auto& suffix = _request->suffix();
auto const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/query/<id> or /_api/query/slow");
return true;
}
auto const& name = suffix[0];
auto const& name = suffixes[0];
if (name == "slow") {
return deleteQuerySlow();
@ -218,9 +218,9 @@ bool RestQueryHandler::deleteQuery() {
}
bool RestQueryHandler::replaceProperties() {
const auto& suffix = _request->suffix();
auto const& suffixes = _request->suffixes();
if (suffix.size() != 1 || suffix[0] != "properties") {
if (suffixes.size() != 1 || suffixes[0] != "properties") {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/query/properties");
@ -286,9 +286,9 @@ bool RestQueryHandler::replaceProperties() {
}
bool RestQueryHandler::parseQuery() {
const auto& suffix = _request->suffix();
auto const& suffixes = _request->suffixes();
if (!suffix.empty()) {
if (!suffixes.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "expecting POST /_api/query");
return true;

View File

@ -77,12 +77,12 @@ RestReplicationHandler::~RestReplicationHandler() {}
RestStatus RestReplicationHandler::execute() {
// extract the request type
auto const type = _request->requestType();
auto const& suffix = _request->suffix();
auto const& suffixes = _request->suffixes();
size_t const len = suffix.size();
size_t const len = suffixes.size();
if (len >= 1) {
std::string const& command = suffix[0];
std::string const& command = suffixes[0];
if (command == "logger-state") {
if (type != rest::RequestType::GET) {
@ -523,8 +523,8 @@ void RestReplicationHandler::handleCommandLoggerFirstTick() {
void RestReplicationHandler::handleCommandBatch() {
// extract the request type
auto const type = _request->requestType();
auto const& suffix = _request->suffix();
size_t const len = suffix.size();
auto const& suffixes = _request->suffixes();
size_t const len = suffixes.size();
TRI_ASSERT(len >= 1);
@ -562,7 +562,7 @@ void RestReplicationHandler::handleCommandBatch() {
if (type == rest::RequestType::PUT && len >= 2) {
// extend an existing blocker
TRI_voc_tick_t id =
static_cast<TRI_voc_tick_t>(StringUtils::uint64(suffix[1]));
static_cast<TRI_voc_tick_t>(StringUtils::uint64(suffixes[1]));
auto input = _request->toVelocyPackBuilderPtr(&VPackOptions::Defaults);
@ -591,7 +591,7 @@ void RestReplicationHandler::handleCommandBatch() {
if (type == rest::RequestType::DELETE_REQ && len >= 2) {
// delete an existing blocker
TRI_voc_tick_t id =
static_cast<TRI_voc_tick_t>(StringUtils::uint64(suffix[1]));
static_cast<TRI_voc_tick_t>(StringUtils::uint64(suffixes[1]));
StorageEngine* engine = EngineSelectorFeature::ENGINE;
int res = engine->removeCompactionBlocker(_vocbase, id);
@ -616,8 +616,8 @@ void RestReplicationHandler::handleCommandBatch() {
void RestReplicationHandler::handleCommandBarrier() {
// extract the request type
auto const type = _request->requestType();
std::vector<std::string> const& suffix = _request->suffix();
size_t const len = suffix.size();
std::vector<std::string> const& suffixes = _request->suffixes();
size_t const len = suffixes.size();
TRI_ASSERT(len >= 1);
@ -667,7 +667,7 @@ void RestReplicationHandler::handleCommandBarrier() {
if (type == rest::RequestType::PUT && len >= 2) {
// extend an existing barrier
TRI_voc_tick_t id = StringUtils::uint64(suffix[1]);
TRI_voc_tick_t id = StringUtils::uint64(suffixes[1]);
std::shared_ptr<VPackBuilder> input =
_request->toVelocyPackBuilderPtr(&VPackOptions::Defaults);
@ -703,7 +703,7 @@ void RestReplicationHandler::handleCommandBarrier() {
if (type == rest::RequestType::DELETE_REQ && len >= 2) {
// delete an existing barrier
TRI_voc_tick_t id = StringUtils::uint64(suffix[1]);
TRI_voc_tick_t id = StringUtils::uint64(suffixes[1]);
if (arangodb::wal::LogfileManager::instance()->removeLogfileBarrier(id)) {
resetResponse(rest::ResponseCode::NO_CONTENT);
@ -2751,9 +2751,9 @@ void RestReplicationHandler::handleCommandCreateKeys() {
////////////////////////////////////////////////////////////////////////////////
void RestReplicationHandler::handleCommandGetKeys() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 2) {
if (suffixes.size() != 2) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting GET /_api/replication/keys/<keys-id>");
return;
@ -2775,7 +2775,7 @@ void RestReplicationHandler::handleCommandGetKeys() {
}
}
std::string const& id = suffix[1];
std::string const& id = suffixes[1];
auto keysRepository = _vocbase->collectionKeys();
TRI_ASSERT(keysRepository != nullptr);
@ -2829,9 +2829,9 @@ void RestReplicationHandler::handleCommandGetKeys() {
////////////////////////////////////////////////////////////////////////////////
void RestReplicationHandler::handleCommandFetchKeys() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 2) {
if (suffixes.size() != 2) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/replication/keys/<keys-id>");
return;
@ -2874,7 +2874,7 @@ void RestReplicationHandler::handleCommandFetchKeys() {
return;
}
std::string const& id = suffix[1];
std::string const& id = suffixes[1];
auto keysRepository = _vocbase->collectionKeys();
TRI_ASSERT(keysRepository != nullptr);
@ -2928,15 +2928,15 @@ void RestReplicationHandler::handleCommandFetchKeys() {
}
void RestReplicationHandler::handleCommandRemoveKeys() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 2) {
if (suffixes.size() != 2) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/replication/keys/<keys-id>");
return;
}
std::string const& id = suffix[1];
std::string const& id = suffixes[1];
auto keys = _vocbase->collectionKeys();
TRI_ASSERT(keys != nullptr);

View File

@ -35,15 +35,15 @@ RestWalHandler::RestWalHandler(
: RestVocbaseBaseHandler(request, response) {}
RestStatus RestWalHandler::execute() {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffix.size() != 1) {
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting /_admin/wal/<operation>");
return RestStatus::DONE;
}
std::string const& operation = suffix[0];
std::string const& operation = suffixes[0];
// extract the sub-request type
auto const type = _request->requestType();

View File

@ -42,8 +42,8 @@ WorkMonitorHandler::WorkMonitorHandler(GeneralRequest* request,
bool WorkMonitorHandler::isDirect() const { return true; }
RestStatus WorkMonitorHandler::execute() {
auto suffix = _request->suffix();
size_t const len = suffix.size();
auto const& suffixes = _request->suffixes();
size_t const len = suffixes.size();
auto const type = _request->requestType();
if (type == rest::RequestType::GET) {
@ -70,7 +70,7 @@ RestStatus WorkMonitorHandler::execute() {
return RestStatus::DONE;
}
uint64_t id = StringUtils::uint64(suffix[0]);
uint64_t id = StringUtils::uint64(suffixes[0]);
WorkMonitor::cancelWork(id);
VPackBuilder b;

View File

@ -838,15 +838,15 @@ static TRI_action_result_t ExecuteActionVocbase(
// copy suffix, which comes from the action:
std::string path = request->prefix();
v8::Handle<v8::Array> suffixArray = v8::Array::New(isolate);
std::vector<std::string> const& suffix = request->suffix();
std::vector<std::string> const& suffixes = request->suffixes();
uint32_t index = 0;
char const* sep = "";
for (size_t s = action->_urlParts; s < suffix.size(); ++s) {
suffixArray->Set(index++, TRI_V8_STD_STRING(suffix[s]));
for (size_t s = action->_urlParts; s < suffixes.size(); ++s) {
suffixArray->Set(index++, TRI_V8_STD_STRING(suffixes[s]));
path += sep + suffix[s];
path += sep + suffixes[s];
sep = "/";
}

View File

@ -0,0 +1,189 @@
/*jshint globalstrict:false, strict:false, maxlen: 5000 */
/*global arango, assertEqual */
////////////////////////////////////////////////////////////////////////////////
/// @brief test the document interface
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 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 triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var arangodb = require("@arangodb");
var db = arangodb.db;
function CollectionDocumentKeysSuite () {
'use strict';
var cn = "UnitTestsCollection";
var collection = null;
var keys = [
":", "-", "_", "@", ".", "..", "...", "a@b", "a@b.c", "a-b-c", "_a", "@a", "@a-b", ":80", ":_", "@:_",
"0", "1", "123456", "0123456", "true", "false", "a", "A", "a1", "A1", "01ab01", "01AB01",
"abcd-efgh", "abcd_efgh", "Abcd_Efgh", "@@", "abc@foo.bar", "@..abc-@-foo__bar",
".foobar", "-foobar", "_foobar", "@foobar", "(valid)", "%valid", "$valid",
"$$bill,y'all", "'valid", "'a-key-is-a-key-is-a-key'", "m+ller", ";valid", ",valid", "!valid!",
":::", ":-:-:", ";", ";;;;;;;;;;", "(", ")", "()xoxo()", "%", ".::.", "::::::::........",
"%-%-%-%", ":-)", "!", "!!!!", "'", "''''", "this-key's-valid.", "=",
"==================================================", "-=-=-=___xoxox-",
"*", "(*)", "****", "--", "__"
];
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
db._drop(cn);
collection = db._create(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
collection.drop();
collection = null;
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create document w/ special keys
////////////////////////////////////////////////////////////////////////////////
testSaveSpecialKeysInUrls : function () {
keys.forEach(function(key, index) {
var doc = { _key: key, value: "test" };
// create document
var result = arango.POST_RAW("/_api/document/" + encodeURIComponent(cn), JSON.stringify(doc));
assertEqual(202, result.code);
// read document back
result = arango.GET_RAW("/_api/document/" + encodeURIComponent(cn) + "/" + encodeURIComponent(key));
assertEqual(200, result.code);
assertEqual(index + 1, collection.count());
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief get document w/ special keys
////////////////////////////////////////////////////////////////////////////////
testGetSpecialKeysInUrls : function () {
keys.forEach(function(key, index) {
var doc = { _key: key, value: "test" };
// create document
var result = arango.POST_RAW("/_api/document/" + encodeURIComponent(cn), JSON.stringify(doc));
assertEqual(202, result.code);
// read document back
result = arango.HEAD_RAW("/_api/document/" + encodeURIComponent(cn) + "/" + encodeURIComponent(key));
assertEqual(200, result.code);
assertEqual(index + 1, collection.count());
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief update document w/ special keys
////////////////////////////////////////////////////////////////////////////////
testUpdateSpecialKeysInUrls : function () {
keys.forEach(function(key, index) {
var doc = { _key: key, value: "test" };
// create document
var result = arango.POST_RAW("/_api/document/" + encodeURIComponent(cn), JSON.stringify(doc));
assertEqual(202, result.code);
// update document
doc.test = "testmann";
doc.value = 12345;
result = arango.PATCH_RAW("/_api/document/" + encodeURIComponent(cn) + "/" + encodeURIComponent(key), JSON.stringify(doc));
assertEqual(202, result.code);
assertEqual(index + 1, collection.count());
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief replace document w/ special keys
////////////////////////////////////////////////////////////////////////////////
testReplaceSpecialKeysInUrls : function () {
keys.forEach(function(key, index) {
var doc = { _key: key, value: "test" };
// create document
var result = arango.POST_RAW("/_api/document/" + encodeURIComponent(cn), JSON.stringify(doc));
assertEqual(202, result.code);
// update document
doc.test = "testmann";
doc.value = 12345;
result = arango.PUT_RAW("/_api/document/" + encodeURIComponent(cn) + "/" + encodeURIComponent(key), JSON.stringify(doc));
assertEqual(202, result.code);
assertEqual(index + 1, collection.count());
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief remove document w/ special keys
////////////////////////////////////////////////////////////////////////////////
testRemoveSpecialKeysInUrls : function () {
keys.forEach(function(key, index) {
var doc = { _key: key, value: "test" };
// create document
var result = arango.POST_RAW("/_api/document/" + encodeURIComponent(cn), JSON.stringify(doc));
assertEqual(202, result.code);
// remove document
result = arango.DELETE_RAW("/_api/document/" + encodeURIComponent(cn) + "/" + encodeURIComponent(key));
assertEqual(202, result.code);
assertEqual(0, collection.count());
});
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(CollectionDocumentKeysSuite);
return jsunity.done();

View File

@ -307,15 +307,15 @@ function CollectionDocumentSuite () {
////////////////////////////////////////////////////////////////////////////////
testSaveSpecialCharsDocumentKey : function () {
[ ":", "-", "_", "@", "a@b", "a@b.c", "a-b-c", "_a", "@a", "@a-b", ":80", ":_", "@:_",
[ ":", "-", "_", "@", ".", "..", "...", "a@b", "a@b.c", "a-b-c", "_a", "@a", "@a-b", ":80", ":_", "@:_",
"0", "1", "123456", "0123456", "true", "false", "a", "A", "a1", "A1", "01ab01", "01AB01",
"abcd-efgh", "abcd_efgh", "Abcd_Efgh", "@", "@@", "abc@foo.bar", "@..abc-@-foo__bar",
"abcd-efgh", "abcd_efgh", "Abcd_Efgh", "@@", "abc@foo.bar", "@..abc-@-foo__bar",
".foobar", "-foobar", "_foobar", "@foobar", "(valid)", "%valid", "$valid",
"$$bill,y'all", "'valid", "'a-key-is-a-key-is-a-key'", "m+ller", ";valid", ",valid", "!valid!",
":", ":::", ":-:-:", ";", ";;;;;;;;;;", "(", ")", "()xoxo()", "%",
":::", ":-:-:", ";", ";;;;;;;;;;", "(", ")", "()xoxo()", "%",
"%-%-%-%", ":-)", "!", "!!!!", "'", "''''", "this-key's-valid.", "=",
"==================================================", "-=-=-=___xoxox-",
"*", "(*)", "****", ".", "...", "-", "--", "_", "__" ].forEach(function (key) {
"*", "(*)", "****", "--", "__" ].forEach(function (key) {
var doc1 = collection.save({ _key: key, value: key });
assertEqual(key, doc1._key);
assertEqual(cn + "/" + key, doc1._id);

View File

@ -2018,7 +2018,7 @@ function pathHandler (req, res, options, next) {
'use strict';
var filepath, root, filename, encodedFilename;
filepath = req.suffix.length ? path.resolve(path.sep, ...req.suffix) : '';
filepath = req.suffix.length ? path.resolve(path.sep, ...req.suffix.map((part) => decodeURIComponent(part))) : '';
root = options.path;
if (options.root) {

View File

@ -25,6 +25,7 @@
var _ = require('lodash');
var fs = require('fs');
var joinPath = require('path').join;
var resolvePath = require('path').resolve;
var internal = require('internal');
var ArangoError = require('@arangodb').ArangoError;
var errors = require('@arangodb').errors;
@ -93,12 +94,10 @@ function createSwaggerRouteHandler (defaultAppPath, opts) {
}
function swaggerPath (path, basePath) {
if (path.charAt(0) === '/') {
return path;
}
if (!basePath) {
basePath = joinPath(internal.startupPath, 'server', 'assets', 'swagger');
}
path = resolvePath('/', path);
return joinPath(basePath, path);
}

View File

@ -427,7 +427,7 @@ function * findRoutes (node, result, suffix, path) {
);
}
} else {
const part = suffix[0];
const part = decodeURIComponent(suffix[0]);
const path2 = path.concat(part);
const suffix2 = suffix.slice(1);
for (const childNode of [node.get(part), node.get(tokenize.PARAM)]) {

View File

@ -25,6 +25,7 @@
const NotFound = require('http-errors').NotFound;
const fs = require('fs');
const joinPath = require('path').join;
const resolvePath = require('path').resolve;
const internal = require('internal');
const errors = require('@arangodb').errors;
const FoxxManager = require('@arangodb/foxx/manager');
@ -101,7 +102,8 @@ module.exports = function createSwaggerRouteHandler (foxxMount, opts) {
} else if (path === 'index.html') {
path = indexFile;
}
const filePath = path.charAt(0) === '/' ? path : joinPath(swaggerRoot, path);
path = resolvePath('/', path);
const filePath = joinPath(swaggerRoot, path);
if (!fs.isFile(filePath)) {
throw new NotFound(`unknown path "${req._raw.url}"`);
}

View File

@ -1236,7 +1236,7 @@ std::string urlEncode(char const* src, size_t const len) {
result.push_back(*src);
}
else if (*src == '-' || *src == '_' || *src == '.' || *src == '~') {
else if (*src == '-' || *src == '_' || *src == '~') {
result.push_back(*src);
}

View File

@ -169,10 +169,10 @@ std::vector<std::string> split(std::string const& source,
template <typename C>
std::string join(C const& source, std::string const& delim = ",") {
std::string result = "";
std::string result;
bool first = true;
for (auto c : source) {
for (auto const& c : source) {
if (first) {
first = false;
} else {
@ -187,8 +187,20 @@ std::string join(C const& source, std::string const& delim = ",") {
template <typename C>
std::string join(C const& source, char delim = ',') {
std::string delimStr(1, delim);
return join(source, delimStr);
std::string result;
bool first = true;
for (auto const& c : source) {
if (first) {
first = false;
} else {
result.push_back(delim);
}
result += c;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -214,17 +214,23 @@ void GeneralRequest::setFullUrl(char const* begin, char const* end) {
_fullUrl = std::string(begin, end - begin);
}
void GeneralRequest::setFullUrl(std::string url) {
TRI_ASSERT(!url.empty());
_fullUrl = std::move(url);
std::vector<std::string> GeneralRequest::decodedSuffixes() const {
std::vector<std::string> result;
result.reserve(_suffixes.size());
for (auto const& it : _suffixes) {
result.emplace_back(StringUtils::urlDecode(it));
}
return result;
}
void GeneralRequest::addSuffix(std::string&& part) {
_suffix.emplace_back(StringUtils::urlDecode(part));
// part will not be URL-decoded here!
_suffixes.emplace_back(std::move(part));
}
bool GeneralRequest::velocyPackResponse() const {
// needs only to be used in http case?!
std::string const& result = header(StaticStrings::Accept);
return (std::string::npos != result.find(StaticStrings::MimeTypeVPack));
return (result.compare(StaticStrings::MimeTypeVPack) == 0);
}

View File

@ -120,7 +120,6 @@ class GeneralRequest {
std::string const& fullUrl() const { return _fullUrl; }
void setFullUrl(char const* begin, char const* end);
void setFullUrl(std::string url);
// consists of the URL without the host and without any parameters.
std::string const& requestPath() const { return _requestPath; }
@ -136,7 +135,13 @@ class GeneralRequest {
void setPrefix(std::string const& prefix) { _prefix = prefix; }
void setPrefix(std::string&& prefix) { _prefix = std::move(prefix); }
std::vector<std::string> const& suffix() const { return _suffix; }
// Returns the request path suffixes in non-URL-decoded form
std::vector<std::string> const& suffixes() const { return _suffixes; }
// Returns the request path suffixes in URL-decoded form. Note: this will
// re-compute the suffix list on every call!
std::vector<std::string> decodedSuffixes() const;
void addSuffix(std::string&& part);
// VIRTUAL //////////////////////////////////////////////
@ -207,7 +212,7 @@ class GeneralRequest {
std::string _fullUrl;
std::string _requestPath;
std::string _prefix; // part of path matched by rest route
std::vector<std::string> _suffix;
std::vector<std::string> _suffixes;
ContentType _contentType; // UNSET, VPACK, JSON
ContentType _contentTypeResponse;
};

View File

@ -87,6 +87,7 @@ struct CurlHandle {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
curl_easy_setopt(_handle, CURLOPT_PRIVATE, _rip.get());
curl_easy_setopt(_handle, CURLOPT_PATH_AS_IS, 1L);
}
~CurlHandle() {
if (_handle != nullptr) {