mirror of https://gitee.com/bigwinds/arangodb
304 lines
8.4 KiB
C++
304 lines
8.4 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// 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
|
|
/// @author Achim Brandt
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "GeneralRequest.h"
|
|
|
|
#include "Basics/StaticStrings.h"
|
|
#include "Basics/StringBuffer.h"
|
|
#include "Basics/StringUtils.h"
|
|
#include "Basics/Utf8Helper.h"
|
|
#include "Basics/VelocyPackHelper.h"
|
|
#include "Logger/Logger.h"
|
|
|
|
using namespace arangodb;
|
|
using namespace arangodb::basics;
|
|
|
|
std::string GeneralRequest::translateVersion(ProtocolVersion version) {
|
|
switch (version) {
|
|
case ProtocolVersion::VST_1_1:
|
|
return "VST/1.1";
|
|
case ProtocolVersion::VST_1_0:
|
|
return "VST/1.0";
|
|
case ProtocolVersion::HTTP_1_1:
|
|
return "HTTP/1.1";
|
|
case ProtocolVersion::HTTP_1_0:
|
|
return "HTTP/1.0";
|
|
case ProtocolVersion::UNKNOWN:
|
|
default: { return "HTTP/1.0"; }
|
|
}
|
|
}
|
|
|
|
std::string GeneralRequest::translateMethod(RequestType method) {
|
|
switch (method) {
|
|
case RequestType::DELETE_REQ:
|
|
return "DELETE";
|
|
|
|
case RequestType::GET:
|
|
return "GET";
|
|
|
|
case RequestType::HEAD:
|
|
return "HEAD";
|
|
|
|
case RequestType::OPTIONS:
|
|
return "OPTIONS";
|
|
|
|
case RequestType::PATCH:
|
|
return "PATCH";
|
|
|
|
case RequestType::POST:
|
|
return "POST";
|
|
|
|
case RequestType::PUT:
|
|
return "PUT";
|
|
|
|
case RequestType::VSTREAM_CRED:
|
|
return "CRED";
|
|
|
|
case RequestType::VSTREAM_REGISTER:
|
|
return "REGISTER";
|
|
|
|
case RequestType::VSTREAM_STATUS:
|
|
return "STATUS";
|
|
|
|
case RequestType::ILLEGAL:
|
|
LOG_TOPIC("62a53", WARN, arangodb::Logger::FIXME)
|
|
<< "illegal http request method encountered in switch";
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
return "UNKNOWN"; // in order please MSVC
|
|
}
|
|
|
|
rest::RequestType GeneralRequest::translateMethod(std::string const& method) {
|
|
std::string const methodString = StringUtils::toupper(method);
|
|
|
|
if (methodString == "DELETE") {
|
|
return RequestType::DELETE_REQ;
|
|
} else if (methodString == "GET") {
|
|
return RequestType::GET;
|
|
} else if (methodString == "HEAD") {
|
|
return RequestType::HEAD;
|
|
} else if (methodString == "OPTIONS") {
|
|
return RequestType::OPTIONS;
|
|
} else if (methodString == "PATCH") {
|
|
return RequestType::PATCH;
|
|
} else if (methodString == "POST") {
|
|
return RequestType::POST;
|
|
} else if (methodString == "PUT") {
|
|
return RequestType::PUT;
|
|
} else if (methodString == "CRED") {
|
|
return RequestType::VSTREAM_CRED;
|
|
} else if (methodString == "REGISTER") {
|
|
return RequestType::VSTREAM_REGISTER;
|
|
} else if (methodString == "STATUS") {
|
|
return RequestType::VSTREAM_STATUS;
|
|
}
|
|
|
|
return RequestType::ILLEGAL;
|
|
}
|
|
|
|
void GeneralRequest::appendMethod(RequestType method, StringBuffer* buffer) {
|
|
// append RequestType as string value to given String buffer
|
|
buffer->appendText(translateMethod(method));
|
|
buffer->appendChar(' ');
|
|
}
|
|
|
|
rest::RequestType GeneralRequest::findRequestType(char const* ptr, size_t const length) {
|
|
switch (length) {
|
|
case 3:
|
|
if (ptr[0] == 'g' && ptr[1] == 'e' && ptr[2] == 't') {
|
|
return RequestType::GET;
|
|
}
|
|
if (ptr[0] == 'p' && ptr[1] == 'u' && ptr[2] == 't') {
|
|
return RequestType::PUT;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (ptr[0] == 'p' && ptr[1] == 'o' && ptr[2] == 's' && ptr[3] == 't') {
|
|
return RequestType::POST;
|
|
}
|
|
if (ptr[0] == 'h' && ptr[1] == 'e' && ptr[2] == 'a' && ptr[3] == 'd') {
|
|
return RequestType::HEAD;
|
|
}
|
|
if (ptr[0] == 'c' && ptr[1] == 'r' && ptr[2] == 'e' && ptr[3] == 'd') {
|
|
return RequestType::VSTREAM_CRED;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
if (ptr[0] == 'p' && ptr[1] == 'a' && ptr[2] == 't' && ptr[3] == 'c' && ptr[4] == 'h') {
|
|
return RequestType::PATCH;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
if (ptr[0] == 'd' && ptr[1] == 'e' && ptr[2] == 'l' && ptr[3] == 'e' &&
|
|
ptr[4] == 't' && ptr[5] == 'e') {
|
|
return RequestType::DELETE_REQ;
|
|
}
|
|
if (ptr[0] == 's' && ptr[1] == 't' && ptr[2] == 'a' && ptr[3] == 't' &&
|
|
ptr[4] == 'u' && ptr[5] == 's') {
|
|
return RequestType::VSTREAM_STATUS;
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
if (ptr[0] == 'o' && ptr[1] == 'p' && ptr[2] == 't' && ptr[3] == 'i' &&
|
|
ptr[4] == 'o' && ptr[5] == 'n' && ptr[6] == 's') {
|
|
return RequestType::OPTIONS;
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
if (ptr[0] == 'r' && ptr[1] == 'e' && ptr[2] == 'g' && ptr[3] == 'i' &&
|
|
ptr[4] == 's' && ptr[5] == 't' && ptr[6] == 'e' && ptr[7] == 'r') {
|
|
return RequestType::VSTREAM_REGISTER;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return RequestType::ILLEGAL;
|
|
}
|
|
|
|
GeneralRequest::~GeneralRequest() {
|
|
// only delete if we are the owner of the context
|
|
if (_requestContext != nullptr && _isRequestContextOwner) {
|
|
delete _requestContext;
|
|
}
|
|
}
|
|
|
|
void GeneralRequest::setRequestContext(RequestContext* requestContext, bool isRequestContextOwner) {
|
|
TRI_ASSERT(requestContext != nullptr);
|
|
|
|
if (_requestContext) {
|
|
// if we have a shared context, we should not have got here
|
|
TRI_ASSERT(isRequestContextOwner);
|
|
|
|
// delete any previous context
|
|
TRI_ASSERT(false);
|
|
delete _requestContext;
|
|
}
|
|
|
|
_requestContext = requestContext;
|
|
_isRequestContextOwner = isRequestContextOwner;
|
|
}
|
|
|
|
void GeneralRequest::setFullUrl(char const* begin, char const* end) {
|
|
TRI_ASSERT(begin != nullptr);
|
|
TRI_ASSERT(end != nullptr);
|
|
TRI_ASSERT(begin <= end);
|
|
|
|
_fullUrl = std::string(begin, end - begin);
|
|
}
|
|
|
|
void GeneralRequest::addSuffix(std::string part) {
|
|
// part will not be URL-decoded here!
|
|
_suffixes.emplace_back(std::move(part));
|
|
}
|
|
|
|
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::urlDecodePath(it));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string const& GeneralRequest::header(std::string const& key, bool& found) const {
|
|
auto it = _headers.find(key);
|
|
if (it == _headers.end()) {
|
|
found = false;
|
|
return StaticStrings::Empty;
|
|
}
|
|
|
|
found = true;
|
|
return it->second;
|
|
}
|
|
|
|
std::string const& GeneralRequest::header(std::string const& key) const {
|
|
bool unused = true;
|
|
return header(key, unused);
|
|
}
|
|
|
|
std::string const& GeneralRequest::value(std::string const& key, bool& found) const {
|
|
if (!_values.empty()) {
|
|
auto it = _values.find(key);
|
|
|
|
if (it != _values.end()) {
|
|
found = true;
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
found = false;
|
|
return StaticStrings::Empty;
|
|
}
|
|
|
|
std::string const& GeneralRequest::value(std::string const& key) const {
|
|
bool unused = true;
|
|
return value(key, unused);
|
|
}
|
|
|
|
// needs to be here because of a gcc bug with templates and namespaces
|
|
// https://stackoverflow.com/a/25594741/1473569
|
|
namespace arangodb {
|
|
template <>
|
|
bool GeneralRequest::parsedValue(std::string const& key, bool valueNotFound) {
|
|
bool found = false;
|
|
std::string const& val = this->value(key, found);
|
|
if (found) {
|
|
return StringUtils::boolean(val);
|
|
}
|
|
return valueNotFound;
|
|
}
|
|
|
|
template <>
|
|
uint64_t GeneralRequest::parsedValue(std::string const& key, uint64_t valueNotFound) {
|
|
bool found = false;
|
|
std::string const& val = this->value(key, found);
|
|
if (found) {
|
|
return StringUtils::uint64(val);
|
|
}
|
|
return valueNotFound;
|
|
}
|
|
|
|
template <>
|
|
double GeneralRequest::parsedValue(std::string const& key, double valueNotFound) {
|
|
bool found = false;
|
|
std::string const& val = this->value(key, found);
|
|
if (found) {
|
|
return StringUtils::doubleDecimal(val);
|
|
}
|
|
return valueNotFound;
|
|
}
|
|
|
|
std::shared_ptr<VPackBuilder> GeneralRequest::toVelocyPackBuilderPtr() {
|
|
auto* opts = VelocyPackHelper::optionsWithUniquenessCheck();
|
|
return std::make_shared<VPackBuilder>(payload(opts), opts);
|
|
};
|
|
} // namespace arangodb
|