mirror of https://gitee.com/bigwinds/arangodb
added fillBody
This commit is contained in:
parent
2d9f384043
commit
9dbba248de
|
@ -23,19 +23,17 @@
|
||||||
|
|
||||||
#include "RestBaseHandler.h"
|
#include "RestBaseHandler.h"
|
||||||
|
|
||||||
#include "Basics/StaticStrings.h"
|
|
||||||
#include "Basics/StringUtils.h"
|
|
||||||
#include "Basics/VelocyPackDumper.h"
|
|
||||||
#include "Basics/VPackStringBufferAdapter.h"
|
|
||||||
#include "Rest/HttpRequest.h"
|
|
||||||
#include "Rest/HttpResponse.h"
|
|
||||||
#include "Utils/TransactionContext.h"
|
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
#include <velocypack/Builder.h>
|
||||||
#include <velocypack/Dumper.h>
|
#include <velocypack/Dumper.h>
|
||||||
#include <velocypack/Options.h>
|
#include <velocypack/Options.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
#include "Basics/StaticStrings.h"
|
||||||
|
#include "Basics/StringUtils.h"
|
||||||
|
#include "Rest/HttpRequest.h"
|
||||||
|
#include "Rest/HttpResponse.h"
|
||||||
|
#include "Utils/TransactionContext.h"
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
using namespace arangodb::rest;
|
using namespace arangodb::rest;
|
||||||
|
@ -52,7 +50,6 @@ void RestBaseHandler::handleError(Exception const& ex) {
|
||||||
|
|
||||||
void RestBaseHandler::generateResult(GeneralResponse::ResponseCode code,
|
void RestBaseHandler::generateResult(GeneralResponse::ResponseCode code,
|
||||||
VPackSlice const& slice) {
|
VPackSlice const& slice) {
|
||||||
|
|
||||||
createResponse(code);
|
createResponse(code);
|
||||||
writeResult(slice, VPackOptions::Defaults);
|
writeResult(slice, VPackOptions::Defaults);
|
||||||
}
|
}
|
||||||
|
@ -61,9 +58,9 @@ void RestBaseHandler::generateResult(GeneralResponse::ResponseCode code,
|
||||||
/// @brief generates a result from VelocyPack
|
/// @brief generates a result from VelocyPack
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RestBaseHandler::generateResult(GeneralResponse::ResponseCode code,
|
void RestBaseHandler::generateResult(
|
||||||
VPackSlice const& slice,
|
GeneralResponse::ResponseCode code, VPackSlice const& slice,
|
||||||
std::shared_ptr<TransactionContext> context) {
|
std::shared_ptr<TransactionContext> context) {
|
||||||
createResponse(code);
|
createResponse(code);
|
||||||
writeResult(slice, *(context->getVPackOptions()));
|
writeResult(slice, *(context->getVPackOptions()));
|
||||||
}
|
}
|
||||||
|
@ -116,7 +113,8 @@ void RestBaseHandler::generateError(GeneralResponse::ResponseCode code,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RestBaseHandler::generateOOMError() {
|
void RestBaseHandler::generateOOMError() {
|
||||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
|
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||||
|
TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -124,43 +122,23 @@ void RestBaseHandler::generateOOMError() {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RestBaseHandler::generateCanceled() {
|
void RestBaseHandler::generateCanceled() {
|
||||||
return generateError(GeneralResponse::ResponseCode::GONE, TRI_ERROR_REQUEST_CANCELED);
|
return generateError(GeneralResponse::ResponseCode::GONE,
|
||||||
}
|
TRI_ERROR_REQUEST_CANCELED);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief checks if velocypack is expected as answer
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool RestBaseHandler::returnVelocypack() const {
|
|
||||||
std::string const& result = _request->header(StaticStrings::Accept);
|
|
||||||
return (std::string::npos != result.find(StaticStrings::MimeTypeVPack));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief writes volocypack or json to response
|
/// @brief writes volocypack or json to response
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RestBaseHandler::writeResult(arangodb::velocypack::Slice const& slice,
|
void RestBaseHandler::writeResult(arangodb::velocypack::Slice const& slice,
|
||||||
VPackOptions const& options) {
|
VPackOptions const& options) {
|
||||||
if (returnVelocypack()) {
|
|
||||||
_response->setContentType(HttpResponse::CONTENT_TYPE_VPACK);
|
|
||||||
_response->body().appendText(slice.startAs<const char>(), static_cast<size_t>(slice.byteSize()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON
|
|
||||||
|
|
||||||
_response->setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
|
||||||
try {
|
try {
|
||||||
arangodb::basics::VelocyPackDumper dumper(&(_response->body()), &options);
|
_response->fillBody(_request, slice, true, options);
|
||||||
dumper.dumpValue(slice);
|
|
||||||
//VPackStringBufferAdapter buffer(_response->body().stringBuffer());
|
|
||||||
//VPackDumper dumper(&buffer, &options);
|
|
||||||
//dumper.dump(slice);
|
|
||||||
} catch (std::exception const& ex) {
|
} 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 (...) {
|
} catch (...) {
|
||||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
|
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||||
"cannot generate output");
|
TRI_ERROR_INTERNAL, "cannot generate output");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#ifndef ARANGOD_REST_HANDLER_REST_BASE_HANDLER_H
|
#ifndef ARANGOD_REST_HANDLER_REST_BASE_HANDLER_H
|
||||||
#define ARANGOD_REST_HANDLER_REST_BASE_HANDLER_H 1
|
#define ARANGOD_REST_HANDLER_REST_BASE_HANDLER_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
|
||||||
#include "HttpServer/HttpHandler.h"
|
#include "HttpServer/HttpHandler.h"
|
||||||
|
|
||||||
#include "Rest/HttpResponse.h"
|
#include "Rest/HttpResponse.h"
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
@ -36,71 +36,36 @@ struct Options;
|
||||||
class Slice;
|
class Slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief default handler for error handling and json in-/output
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class RestBaseHandler : public rest::HttpHandler {
|
class RestBaseHandler : public rest::HttpHandler {
|
||||||
public:
|
public:
|
||||||
explicit RestBaseHandler(HttpRequest* request);
|
explicit RestBaseHandler(HttpRequest* request);
|
||||||
|
|
||||||
void handleError(basics::Exception const&) override;
|
void handleError(basics::Exception const&) override;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
public:
|
||||||
/// @brief generates a result from VelocyPack
|
// generates a result from VelocyPack
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void generateResult(GeneralResponse::ResponseCode,
|
void generateResult(GeneralResponse::ResponseCode,
|
||||||
arangodb::velocypack::Slice const& slice);
|
arangodb::velocypack::Slice const& slice);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
// generates a result from VelocyPack
|
||||||
/// @brief generates a result from VelocyPack
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void generateResult(GeneralResponse::ResponseCode,
|
void generateResult(GeneralResponse::ResponseCode,
|
||||||
arangodb::velocypack::Slice const& slice,
|
arangodb::velocypack::Slice const& slice,
|
||||||
std::shared_ptr<arangodb::TransactionContext> context);
|
std::shared_ptr<arangodb::TransactionContext> context);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
// generates an error
|
||||||
/// @brief generates an error
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void generateError(GeneralResponse::ResponseCode, int);
|
void generateError(GeneralResponse::ResponseCode, int);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
// generates an error
|
||||||
/// @brief generates an error
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void generateError(GeneralResponse::ResponseCode, int, std::string const&);
|
void generateError(GeneralResponse::ResponseCode, int, std::string const&);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
// generates an out of memory error
|
||||||
/// @brief generates an out of memory error
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void generateOOMError();
|
void generateOOMError();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
// generates a canceled message
|
||||||
/// @brief generates a canceled message
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void generateCanceled();
|
void generateCanceled();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief dumps the response as JSON into the response string buffer
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// write result back to client
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief checks if velocypack is expected as answer
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool returnVelocypack() const;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief write result back to client
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void writeResult(arangodb::velocypack::Slice const& slice,
|
void writeResult(arangodb::velocypack::Slice const& slice,
|
||||||
arangodb::velocypack::Options const& options);
|
arangodb::velocypack::Options const& options);
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,8 @@ void RestVocbaseBaseHandler::generateSaved(
|
||||||
VPackBuilder errorBuilder;
|
VPackBuilder errorBuilder;
|
||||||
errorBuilder.openObject();
|
errorBuilder.openObject();
|
||||||
for (auto const& it : result.countErrorCodes) {
|
for (auto const& it : result.countErrorCodes) {
|
||||||
errorBuilder.add(basics::StringUtils::itoa(it.first), VPackValue(it.second));
|
errorBuilder.add(basics::StringUtils::itoa(it.first),
|
||||||
|
VPackValue(it.second));
|
||||||
}
|
}
|
||||||
errorBuilder.close();
|
errorBuilder.close();
|
||||||
_response->setHeaderNC(StaticStrings::ErrorCodes, errorBuilder.toJson());
|
_response->setHeaderNC(StaticStrings::ErrorCodes, errorBuilder.toJson());
|
||||||
|
@ -204,21 +205,21 @@ void RestVocbaseBaseHandler::generateDeleted(
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RestVocbaseBaseHandler::generate20x(
|
void RestVocbaseBaseHandler::generate20x(
|
||||||
arangodb::OperationResult const& result,
|
arangodb::OperationResult const& result, std::string const& collectionName,
|
||||||
std::string const& collectionName,
|
TRI_col_type_e type, VPackOptions const* options) {
|
||||||
TRI_col_type_e type,
|
|
||||||
VPackOptions const* options) {
|
|
||||||
|
|
||||||
VPackSlice slice = result.slice();
|
VPackSlice slice = result.slice();
|
||||||
TRI_ASSERT(slice.isObject() || slice.isArray());
|
TRI_ASSERT(slice.isObject() || slice.isArray());
|
||||||
if (slice.isObject()) {
|
if (slice.isObject()) {
|
||||||
_response->setHeaderNC(StaticStrings::Etag, "\"" + slice.get(StaticStrings::RevString).copyString() + "\"");
|
_response->setHeaderNC(
|
||||||
|
StaticStrings::Etag,
|
||||||
|
"\"" + slice.get(StaticStrings::RevString).copyString() + "\"");
|
||||||
// pre 1.4 location headers withdrawn for >= 3.0
|
// pre 1.4 location headers withdrawn for >= 3.0
|
||||||
std::string escapedHandle(assembleDocumentId(
|
std::string escapedHandle(assembleDocumentId(
|
||||||
collectionName, slice.get(StaticStrings::KeyString).copyString(), true));
|
collectionName, slice.get(StaticStrings::KeyString).copyString(),
|
||||||
|
true));
|
||||||
_response->setHeaderNC(StaticStrings::Location,
|
_response->setHeaderNC(StaticStrings::Location,
|
||||||
std::string("/_db/" + _request->databaseName() +
|
std::string("/_db/" + _request->databaseName() +
|
||||||
DOCUMENT_PATH + "/" + escapedHandle));
|
DOCUMENT_PATH + "/" + escapedHandle));
|
||||||
}
|
}
|
||||||
|
|
||||||
writeResult(slice, *options);
|
writeResult(slice, *options);
|
||||||
|
@ -248,26 +249,28 @@ void RestVocbaseBaseHandler::generateForbidden() {
|
||||||
|
|
||||||
void RestVocbaseBaseHandler::generatePreconditionFailed(
|
void RestVocbaseBaseHandler::generatePreconditionFailed(
|
||||||
VPackSlice const& slice) {
|
VPackSlice const& slice) {
|
||||||
|
|
||||||
createResponse(GeneralResponse::ResponseCode::PRECONDITION_FAILED);
|
createResponse(GeneralResponse::ResponseCode::PRECONDITION_FAILED);
|
||||||
|
|
||||||
if (slice.isObject()) { // single document case
|
if (slice.isObject()) { // single document case
|
||||||
std::string const rev = VelocyPackHelper::getStringValue(slice, StaticStrings::KeyString, "");
|
std::string const rev =
|
||||||
|
VelocyPackHelper::getStringValue(slice, StaticStrings::KeyString, "");
|
||||||
_response->setHeaderNC(StaticStrings::Etag, "\"" + rev + "\"");
|
_response->setHeaderNC(StaticStrings::Etag, "\"" + rev + "\"");
|
||||||
}
|
}
|
||||||
VPackBuilder builder;
|
VPackBuilder builder;
|
||||||
{
|
{
|
||||||
VPackObjectBuilder guard(&builder);
|
VPackObjectBuilder guard(&builder);
|
||||||
builder.add("error", VPackValue(true));
|
builder.add("error", VPackValue(true));
|
||||||
builder.add(
|
builder.add("code",
|
||||||
"code",
|
VPackValue(static_cast<int32_t>(
|
||||||
VPackValue(static_cast<int32_t>(GeneralResponse::ResponseCode::PRECONDITION_FAILED)));
|
GeneralResponse::ResponseCode::PRECONDITION_FAILED)));
|
||||||
builder.add("errorNum", VPackValue(TRI_ERROR_ARANGO_CONFLICT));
|
builder.add("errorNum", VPackValue(TRI_ERROR_ARANGO_CONFLICT));
|
||||||
builder.add("errorMessage", VPackValue("precondition failed"));
|
builder.add("errorMessage", VPackValue("precondition failed"));
|
||||||
if (slice.isObject()) {
|
if (slice.isObject()) {
|
||||||
builder.add(StaticStrings::IdString, slice.get(StaticStrings::IdString));
|
builder.add(StaticStrings::IdString, slice.get(StaticStrings::IdString));
|
||||||
builder.add(StaticStrings::KeyString, slice.get(StaticStrings::KeyString));
|
builder.add(StaticStrings::KeyString,
|
||||||
builder.add(StaticStrings::RevString, slice.get(StaticStrings::RevString));
|
slice.get(StaticStrings::KeyString));
|
||||||
|
builder.add(StaticStrings::RevString,
|
||||||
|
slice.get(StaticStrings::RevString));
|
||||||
} else {
|
} else {
|
||||||
builder.add("result", slice);
|
builder.add("result", slice);
|
||||||
}
|
}
|
||||||
|
@ -282,11 +285,12 @@ void RestVocbaseBaseHandler::generatePreconditionFailed(
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RestVocbaseBaseHandler::generatePreconditionFailed(
|
void RestVocbaseBaseHandler::generatePreconditionFailed(
|
||||||
std::string const& collectionName, std::string const& key, TRI_voc_rid_t rev) {
|
std::string const& collectionName, std::string const& key,
|
||||||
|
TRI_voc_rid_t rev) {
|
||||||
VPackBuilder builder;
|
VPackBuilder builder;
|
||||||
builder.openObject();
|
builder.openObject();
|
||||||
builder.add(StaticStrings::IdString, VPackValue(assembleDocumentId(collectionName, key, false)));
|
builder.add(StaticStrings::IdString,
|
||||||
|
VPackValue(assembleDocumentId(collectionName, key, false)));
|
||||||
builder.add(StaticStrings::KeyString, VPackValue(std::to_string(rev)));
|
builder.add(StaticStrings::KeyString, VPackValue(std::to_string(rev)));
|
||||||
builder.add(StaticStrings::RevString, VPackValue(key));
|
builder.add(StaticStrings::RevString, VPackValue(key));
|
||||||
builder.close();
|
builder.close();
|
||||||
|
@ -300,7 +304,8 @@ void RestVocbaseBaseHandler::generatePreconditionFailed(
|
||||||
|
|
||||||
void RestVocbaseBaseHandler::generateNotModified(TRI_voc_rid_t rid) {
|
void RestVocbaseBaseHandler::generateNotModified(TRI_voc_rid_t rid) {
|
||||||
createResponse(GeneralResponse::ResponseCode::NOT_MODIFIED);
|
createResponse(GeneralResponse::ResponseCode::NOT_MODIFIED);
|
||||||
_response->setHeaderNC(StaticStrings::Etag, "\"" + StringUtils::itoa(rid) + "\"");
|
_response->setHeaderNC(StaticStrings::Etag,
|
||||||
|
"\"" + StringUtils::itoa(rid) + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -314,43 +319,23 @@ void RestVocbaseBaseHandler::generateDocument(VPackSlice const& input,
|
||||||
|
|
||||||
std::string rev;
|
std::string rev;
|
||||||
if (document.isObject()) {
|
if (document.isObject()) {
|
||||||
rev = VelocyPackHelper::getStringValue(document, StaticStrings::RevString, "");
|
rev = VelocyPackHelper::getStringValue(document, StaticStrings::RevString,
|
||||||
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// and generate a response
|
// and generate a response
|
||||||
createResponse(GeneralResponse::ResponseCode::OK);
|
createResponse(GeneralResponse::ResponseCode::OK);
|
||||||
|
|
||||||
|
// set ETAG header
|
||||||
if (!rev.empty()) {
|
if (!rev.empty()) {
|
||||||
_response->setHeaderNC(StaticStrings::Etag, "\"" + rev + "\"");
|
_response->setHeaderNC(StaticStrings::Etag, "\"" + rev + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (generateBody) {
|
try {
|
||||||
writeResult(document, *options);
|
_response->fillBody(_request, document, generateBody, *options);
|
||||||
return;
|
} catch (...) {
|
||||||
}
|
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||||
|
TRI_ERROR_INTERNAL, "cannot generate output");
|
||||||
// no body, i.e. a HEAD response
|
|
||||||
if (returnVelocypack()) {
|
|
||||||
_response->setContentType(HttpResponse::CONTENT_TYPE_VPACK);
|
|
||||||
_response->headResponse(static_cast<size_t>(document.byteSize()));
|
|
||||||
} else {
|
|
||||||
_response->setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
|
||||||
|
|
||||||
// TODO can we optimize this?
|
|
||||||
// Just dump some where else to find real length
|
|
||||||
StringBuffer tmp(TRI_UNKNOWN_MEM_ZONE, false);
|
|
||||||
// convert object to string
|
|
||||||
VPackStringBufferAdapter buffer(tmp.stringBuffer());
|
|
||||||
|
|
||||||
//usual dumping - but not to the response body
|
|
||||||
VPackDumper dumper(&buffer, options);
|
|
||||||
try {
|
|
||||||
dumper.dump(document);
|
|
||||||
} catch (...) {
|
|
||||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
|
|
||||||
"cannot generate output");
|
|
||||||
}
|
|
||||||
// set the length of what would have been written
|
|
||||||
_response->headResponse(tmp.length());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,11 +376,13 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD:
|
case TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD:
|
||||||
generateError(GeneralResponse::ResponseCode::BAD, res, "invalid document handle");
|
generateError(GeneralResponse::ResponseCode::BAD, res,
|
||||||
|
"invalid document handle");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE:
|
case TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE:
|
||||||
generateError(GeneralResponse::ResponseCode::BAD, res, "invalid edge attribute");
|
generateError(GeneralResponse::ResponseCode::BAD, res,
|
||||||
|
"invalid edge attribute");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_OUT_OF_KEYS:
|
case TRI_ERROR_ARANGO_OUT_OF_KEYS:
|
||||||
|
@ -417,8 +404,8 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_CONFLICT:
|
case TRI_ERROR_ARANGO_CONFLICT:
|
||||||
generatePreconditionFailed(collectionName,
|
generatePreconditionFailed(collectionName, key.empty() ? "unknown" : key,
|
||||||
key.empty() ? "unknown" : key, rev);
|
rev);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_CLUSTER_SHARD_GONE:
|
case TRI_ERROR_CLUSTER_SHARD_GONE:
|
||||||
|
@ -485,19 +472,23 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD:
|
case TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD:
|
||||||
generateError(GeneralResponse::ResponseCode::BAD, result.code, "invalid document key");
|
generateError(GeneralResponse::ResponseCode::BAD, result.code,
|
||||||
|
"invalid document key");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD:
|
case TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD:
|
||||||
generateError(GeneralResponse::ResponseCode::BAD, result.code, "invalid document handle");
|
generateError(GeneralResponse::ResponseCode::BAD, result.code,
|
||||||
|
"invalid document handle");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE:
|
case TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE:
|
||||||
generateError(GeneralResponse::ResponseCode::BAD, result.code, "invalid edge attribute");
|
generateError(GeneralResponse::ResponseCode::BAD, result.code,
|
||||||
|
"invalid edge attribute");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_OUT_OF_KEYS:
|
case TRI_ERROR_ARANGO_OUT_OF_KEYS:
|
||||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, result.code, "out of keys");
|
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, result.code,
|
||||||
|
"out of keys");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TRI_ERROR_ARANGO_DOCUMENT_KEY_UNEXPECTED:
|
case TRI_ERROR_ARANGO_DOCUMENT_KEY_UNEXPECTED:
|
||||||
|
@ -535,7 +526,8 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
||||||
}
|
}
|
||||||
|
|
||||||
case TRI_ERROR_CLUSTER_UNSUPPORTED: {
|
case TRI_ERROR_CLUSTER_UNSUPPORTED: {
|
||||||
generateError(GeneralResponse::ResponseCode::NOT_IMPLEMENTED, result.code);
|
generateError(GeneralResponse::ResponseCode::NOT_IMPLEMENTED,
|
||||||
|
result.code);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,8 +552,6 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief extracts the revision
|
/// @brief extracts the revision
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -648,12 +638,13 @@ bool RestVocbaseBaseHandler::extractBooleanParameter(char const* name,
|
||||||
std::shared_ptr<VPackBuilder> RestVocbaseBaseHandler::parseVelocyPackBody(
|
std::shared_ptr<VPackBuilder> RestVocbaseBaseHandler::parseVelocyPackBody(
|
||||||
VPackOptions const* options, bool& success) {
|
VPackOptions const* options, bool& success) {
|
||||||
bool found;
|
bool found;
|
||||||
std::string const& contentType = _request->header(StaticStrings::ContentTypeHeader, found);
|
std::string const& contentType =
|
||||||
|
_request->header(StaticStrings::ContentTypeHeader, found);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
if (found && contentType.size() == StaticStrings::MimeTypeVPack.size() &&
|
if (found && contentType.size() == StaticStrings::MimeTypeVPack.size() &&
|
||||||
contentType == StaticStrings::MimeTypeVPack) {
|
contentType == StaticStrings::MimeTypeVPack) {
|
||||||
VPackSlice slice{_request->body().c_str()};
|
VPackSlice slice{_request->body().c_str()};
|
||||||
auto builder = std::make_shared<VPackBuilder>(options);
|
auto builder = std::make_shared<VPackBuilder>(options);
|
||||||
|
@ -685,7 +676,8 @@ void RestVocbaseBaseHandler::prepareExecute() {
|
||||||
std::string const& shardId = _request->header("x-arango-nolock", found);
|
std::string const& shardId = _request->header("x-arango-nolock", found);
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
_nolockHeaderSet = new std::unordered_set<std::string>{ std::string(shardId) };
|
_nolockHeaderSet =
|
||||||
|
new std::unordered_set<std::string>{std::string(shardId)};
|
||||||
arangodb::Transaction::_makeNolockHeaders = _nolockHeaderSet;
|
arangodb::Transaction::_makeNolockHeaders = _nolockHeaderSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
/// @author Michael Hackstein
|
/// @author Michael Hackstein
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ARANGODB_BASICS_VPACKSTRING_H
|
||||||
|
#define ARANGODB_BASICS_VPACKSTRING_H
|
||||||
|
|
||||||
#include "Basics/StringBuffer.h"
|
#include "Basics/StringBuffer.h"
|
||||||
#include "Basics/Exceptions.h"
|
#include "Basics/Exceptions.h"
|
||||||
|
|
||||||
|
@ -74,3 +77,5 @@ class VPackStringBufferAdapter final : public VPackSink {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -258,3 +258,7 @@ void GeneralRequest::setArrayValue(char* key, size_t length, char const* value)
|
||||||
_arrayValues[std::string(key, length)].emplace_back(value);
|
_arrayValues[std::string(key, length)].emplace_back(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GeneralRequest::velocyPackResponse () const {
|
||||||
|
std::string const& result = header(StaticStrings::Accept);
|
||||||
|
return (std::string::npos != result.find(StaticStrings::MimeTypeVPack));
|
||||||
|
}
|
||||||
|
|
|
@ -158,6 +158,8 @@ class GeneralRequest {
|
||||||
}
|
}
|
||||||
void setArrayValue(std::string const& key, std::string const& value);
|
void setArrayValue(std::string const& key, std::string const& value);
|
||||||
|
|
||||||
|
bool velocyPackResponse () const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setValue(char const* key, char const* value);
|
void setValue(char const* key, char const* value);
|
||||||
void setArrayValue(char* key, size_t length, char const* value);
|
void setArrayValue(char* key, size_t length, char const* value);
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
namespace velocypack {
|
||||||
|
struct Options;
|
||||||
|
class Slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeneralRequest;
|
||||||
|
|
||||||
class GeneralResponse {
|
class GeneralResponse {
|
||||||
GeneralResponse() = delete;
|
GeneralResponse() = delete;
|
||||||
GeneralResponse(GeneralResponse const&) = delete;
|
GeneralResponse(GeneralResponse const&) = delete;
|
||||||
|
@ -110,23 +117,32 @@ class GeneralResponse {
|
||||||
_responseCode = responseCode;
|
_responseCode = responseCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> headers() const { return _headers; }
|
std::unordered_map<std::string, std::string> headers() const {
|
||||||
|
return _headers;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief adds a header. the header field name will be lower-cased
|
// adds a header. the header field name will be lower-cased
|
||||||
void setHeader(std::string const& key, std::string const& value) {
|
void setHeader(std::string const& key, std::string const& value) {
|
||||||
_headers[basics::StringUtils::tolower(key)] = value;
|
_headers[basics::StringUtils::tolower(key)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief adds a header. the header field name must be lower-cased
|
// adds a header. the header field name must be lower-cased
|
||||||
void setHeaderNC(std::string const& key, std::string const& value) {
|
void setHeaderNC(std::string const& key, std::string const& value) {
|
||||||
_headers[key] = value;
|
_headers[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief adds a header. the header field name must be lower-cased
|
// adds a header. the header field name must be lower-cased
|
||||||
void setHeaderNC(std::string const& key, std::string&& value) {
|
void setHeaderNC(std::string const& key, std::string&& value) {
|
||||||
_headers[key] = std::move(value);
|
_headers[key] = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// generates the response body, sets the content type; this might
|
||||||
|
// throw an error
|
||||||
|
virtual void fillBody(GeneralRequest const*,
|
||||||
|
arangodb::velocypack::Slice const&, bool generateBody,
|
||||||
|
arangodb::velocypack::Options const&) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ResponseCode _responseCode;
|
ResponseCode _responseCode;
|
||||||
std::unordered_map<std::string, std::string> _headers;
|
std::unordered_map<std::string, std::string> _headers;
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
|
||||||
HttpRequest::HttpRequest(ConnectionInfo const& connectionInfo,
|
HttpRequest::HttpRequest(ConnectionInfo const& connectionInfo,
|
||||||
char const* header, size_t length,
|
char const* header, size_t length,
|
||||||
bool allowMethodOverride)
|
bool allowMethodOverride)
|
||||||
|
@ -46,7 +46,6 @@ HttpRequest::HttpRequest(ConnectionInfo const& connectionInfo,
|
||||||
_contentLength(0),
|
_contentLength(0),
|
||||||
_header(nullptr),
|
_header(nullptr),
|
||||||
_allowMethodOverride(allowMethodOverride) {
|
_allowMethodOverride(allowMethodOverride) {
|
||||||
|
|
||||||
if (0 < length) {
|
if (0 < length) {
|
||||||
_header = new char[length + 1];
|
_header = new char[length + 1];
|
||||||
memcpy(_header, header, length);
|
memcpy(_header, header, length);
|
||||||
|
@ -55,9 +54,7 @@ HttpRequest::HttpRequest(ConnectionInfo const& connectionInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequest::~HttpRequest() {
|
HttpRequest::~HttpRequest() { delete[] _header; }
|
||||||
delete[] _header;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpRequest::parseHeader(size_t length) {
|
void HttpRequest::parseHeader(size_t length) {
|
||||||
char* start = _header;
|
char* start = _header;
|
||||||
|
@ -363,7 +360,8 @@ void HttpRequest::parseHeader(size_t length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyBegin < keyEnd) {
|
if (keyBegin < keyEnd) {
|
||||||
setHeader(keyBegin, keyEnd - keyBegin, valueBegin, valueEnd - valueBegin);
|
setHeader(keyBegin, keyEnd - keyBegin, valueBegin,
|
||||||
|
valueEnd - valueBegin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,8 +506,8 @@ void HttpRequest::setHeader(char const* key, size_t keyLength,
|
||||||
_contentLength = StringUtils::int64(value, valueLength);
|
_contentLength = StringUtils::int64(value, valueLength);
|
||||||
// do not store this header
|
// do not store this header
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyLength == 6 &&
|
if (keyLength == 6 &&
|
||||||
memcmp(key, "cookie", keyLength) == 0) { // 6 = strlen("cookie")
|
memcmp(key, "cookie", keyLength) == 0) { // 6 = strlen("cookie")
|
||||||
parseCookies(value, valueLength);
|
parseCookies(value, valueLength);
|
||||||
|
@ -522,10 +520,9 @@ void HttpRequest::setHeader(char const* key, size_t keyLength,
|
||||||
|
|
||||||
// override HTTP method?
|
// override HTTP method?
|
||||||
if ((keyLength == 13 && memcmp(key, "x-http-method", keyLength) == 0) ||
|
if ((keyLength == 13 && memcmp(key, "x-http-method", keyLength) == 0) ||
|
||||||
(keyLength == 17 &&
|
(keyLength == 17 && memcmp(key, "x-method-override", keyLength) == 0) ||
|
||||||
memcmp(key, "x-method-override", keyLength) == 0) ||
|
|
||||||
(keyLength == 22 &&
|
(keyLength == 22 &&
|
||||||
memcmp(key, "x-http-method-override", keyLength) == 0)) {
|
memcmp(key, "x-http-method-override", keyLength) == 0)) {
|
||||||
std::string overriddenType(value, valueLength);
|
std::string overriddenType(value, valueLength);
|
||||||
StringUtils::tolowerInPlace(&overriddenType);
|
StringUtils::tolowerInPlace(&overriddenType);
|
||||||
|
|
||||||
|
@ -657,21 +654,20 @@ std::string const& HttpRequest::cookieValue(std::string const& key) const {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& HttpRequest::cookieValue(std::string const& key, bool& found) const {
|
std::string const& HttpRequest::cookieValue(std::string const& key,
|
||||||
|
bool& found) const {
|
||||||
auto it = _cookies.find(key);
|
auto it = _cookies.find(key);
|
||||||
|
|
||||||
if (it == _cookies.end()) {
|
if (it == _cookies.end()) {
|
||||||
found = false;
|
found = false;
|
||||||
return StaticStrings::Empty;
|
return StaticStrings::Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& HttpRequest::body() const {
|
std::string const& HttpRequest::body() const { return _body; }
|
||||||
return _body;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpRequest::setBody(char const* body, size_t length) {
|
void HttpRequest::setBody(char const* body, size_t length) {
|
||||||
_body = std::string(body, length);
|
_body = std::string(body, length);
|
||||||
|
@ -683,4 +679,3 @@ std::shared_ptr<VPackBuilder> HttpRequest::toVelocyPack(
|
||||||
parser.parse(body());
|
parser.parse(body());
|
||||||
return parser.steal();
|
return parser.steal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,18 @@
|
||||||
|
|
||||||
#include "HttpResponse.h"
|
#include "HttpResponse.h"
|
||||||
|
|
||||||
|
#include <velocypack/Builder.h>
|
||||||
|
#include <velocypack/Dumper.h>
|
||||||
|
#include <velocypack/Options.h>
|
||||||
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
#include "Basics/Exceptions.h"
|
#include "Basics/Exceptions.h"
|
||||||
#include "Basics/StringBuffer.h"
|
#include "Basics/StringBuffer.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
|
#include "Basics/VPackStringBufferAdapter.h"
|
||||||
|
#include "Basics/VelocyPackDumper.h"
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
|
#include "Rest/GeneralRequest.h"
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
@ -41,10 +49,9 @@ HttpResponse::HttpResponse(ResponseCode code)
|
||||||
_isHeadResponse(false),
|
_isHeadResponse(false),
|
||||||
_body(TRI_UNKNOWN_MEM_ZONE, false),
|
_body(TRI_UNKNOWN_MEM_ZONE, false),
|
||||||
_bodySize(0) {
|
_bodySize(0) {
|
||||||
|
|
||||||
if (_body.c_str() == nullptr) {
|
if (_body.c_str() == nullptr) {
|
||||||
// no buffer could be reserved. out of memory!
|
// no buffer could be reserved. out of memory!
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +128,7 @@ void HttpResponse::writeHeader(StringBuffer* output) {
|
||||||
output->appendText(TRI_CHAR_LENGTH_PAIR("HTTP/1.1 "));
|
output->appendText(TRI_CHAR_LENGTH_PAIR("HTTP/1.1 "));
|
||||||
output->appendText(responseString(_responseCode));
|
output->appendText(responseString(_responseCode));
|
||||||
output->appendText("\r\n", 2);
|
output->appendText("\r\n", 2);
|
||||||
|
|
||||||
bool seenServerHeader = false;
|
bool seenServerHeader = false;
|
||||||
bool seenConnectionHeader = false;
|
bool seenConnectionHeader = false;
|
||||||
bool seenTransferEncodingHeader = false;
|
bool seenTransferEncodingHeader = false;
|
||||||
|
@ -145,20 +152,21 @@ void HttpResponse::writeHeader(StringBuffer* output) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyLength == 6 && key[0] == 's' &&
|
if (keyLength == 6 && key[0] == 's' &&
|
||||||
memcmp(key.c_str(), "server", keyLength) == 0) {
|
memcmp(key.c_str(), "server", keyLength) == 0) {
|
||||||
// this ensures we don't print two "Server" headers
|
// this ensures we don't print two "Server" headers
|
||||||
seenServerHeader = true;
|
seenServerHeader = true;
|
||||||
// go on and use the user-defined "Server" header value
|
// go on and use the user-defined "Server" header value
|
||||||
} else if (keyLength == 10 && key[0] == 'c' &&
|
} else if (keyLength == 10 && key[0] == 'c' &&
|
||||||
memcmp(key.c_str(), "connection", keyLength) == 0) {
|
memcmp(key.c_str(), "connection", keyLength) == 0) {
|
||||||
// this ensures we don't print two "Connection" headers
|
// this ensures we don't print two "Connection" headers
|
||||||
seenConnectionHeader = true;
|
seenConnectionHeader = true;
|
||||||
// go on and use the user-defined "Connection" header value
|
// go on and use the user-defined "Connection" header value
|
||||||
}
|
}
|
||||||
|
|
||||||
// reserve enough space for header name + ": " + value + "\r\n"
|
// reserve enough space for header name + ": " + value + "\r\n"
|
||||||
if (output->reserve(keyLength + 2 + it.second.size() + 2) != TRI_ERROR_NO_ERROR) {
|
if (output->reserve(keyLength + 2 + it.second.size() + 2) !=
|
||||||
|
TRI_ERROR_NO_ERROR) {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +198,7 @@ void HttpResponse::writeHeader(StringBuffer* output) {
|
||||||
output->appendTextUnsafe(it.second);
|
output->appendTextUnsafe(it.second);
|
||||||
output->appendTextUnsafe("\r\n", 2);
|
output->appendTextUnsafe("\r\n", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add "Server" response header
|
// add "Server" response header
|
||||||
if (!seenServerHeader && !HIDE_PRODUCT_HEADER) {
|
if (!seenServerHeader && !HIDE_PRODUCT_HEADER) {
|
||||||
output->appendText("Server: ArangoDB\r\n");
|
output->appendText("Server: ArangoDB\r\n");
|
||||||
|
@ -214,23 +222,29 @@ void HttpResponse::writeHeader(StringBuffer* output) {
|
||||||
// add "Content-Type" header
|
// add "Content-Type" header
|
||||||
switch (_contentType) {
|
switch (_contentType) {
|
||||||
case CONTENT_TYPE_JSON:
|
case CONTENT_TYPE_JSON:
|
||||||
output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Type: application/json; charset=utf-8\r\n"));
|
output->appendText(TRI_CHAR_LENGTH_PAIR(
|
||||||
|
"Content-Type: application/json; charset=utf-8\r\n"));
|
||||||
break;
|
break;
|
||||||
case CONTENT_TYPE_VPACK:
|
case CONTENT_TYPE_VPACK:
|
||||||
output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Type: application/x-velocypack\r\n"));
|
output->appendText(
|
||||||
|
TRI_CHAR_LENGTH_PAIR("Content-Type: application/x-velocypack\r\n"));
|
||||||
break;
|
break;
|
||||||
case CONTENT_TYPE_TEXT:
|
case CONTENT_TYPE_TEXT:
|
||||||
output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Type: text/plain; charset=utf-8\r\n"));
|
output->appendText(
|
||||||
|
TRI_CHAR_LENGTH_PAIR("Content-Type: text/plain; charset=utf-8\r\n"));
|
||||||
break;
|
break;
|
||||||
case CONTENT_TYPE_HTML:
|
case CONTENT_TYPE_HTML:
|
||||||
output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Type: text/html; charset=utf-8\r\n"));
|
output->appendText(
|
||||||
|
TRI_CHAR_LENGTH_PAIR("Content-Type: text/html; charset=utf-8\r\n"));
|
||||||
break;
|
break;
|
||||||
case CONTENT_TYPE_DUMP:
|
case CONTENT_TYPE_DUMP:
|
||||||
output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Type: application/x-arango-dump; charset=utf-8\r\n"));
|
output->appendText(TRI_CHAR_LENGTH_PAIR(
|
||||||
|
"Content-Type: application/x-arango-dump; charset=utf-8\r\n"));
|
||||||
break;
|
break;
|
||||||
case CONTENT_TYPE_CUSTOM: {
|
case CONTENT_TYPE_CUSTOM: {
|
||||||
// intentionally don't print anything here
|
// intentionally don't print anything here
|
||||||
// the header should have been in _headers already, and should have been handled above
|
// the header should have been in _headers already, and should have been
|
||||||
|
// handled above
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,3 +287,41 @@ void HttpResponse::writeHeader(StringBuffer* output) {
|
||||||
// end of header, body to follow
|
// end of header, body to follow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpResponse::fillBody(GeneralRequest const* request,
|
||||||
|
arangodb::velocypack::Slice const& slice,
|
||||||
|
bool generateBody, VPackOptions const& options) {
|
||||||
|
// VELOCYPACK
|
||||||
|
if (request->velocyPackResponse()) {
|
||||||
|
setContentType(HttpResponse::CONTENT_TYPE_VPACK);
|
||||||
|
size_t length = static_cast<size_t>(slice.byteSize());
|
||||||
|
|
||||||
|
if (generateBody) {
|
||||||
|
_body.appendText(slice.startAs<const char>(), length);
|
||||||
|
} else {
|
||||||
|
headResponse(length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON
|
||||||
|
else {
|
||||||
|
setContentType(HttpResponse::CONTENT_TYPE_JSON);
|
||||||
|
|
||||||
|
if (generateBody) {
|
||||||
|
arangodb::basics::VelocyPackDumper dumper(&_body, &options);
|
||||||
|
dumper.dumpValue(slice);
|
||||||
|
} else {
|
||||||
|
// TODO can we optimize this?
|
||||||
|
// Just dump some where else to find real length
|
||||||
|
StringBuffer tmp(TRI_UNKNOWN_MEM_ZONE, false);
|
||||||
|
|
||||||
|
// convert object to string
|
||||||
|
VPackStringBufferAdapter buffer(tmp.stringBuffer());
|
||||||
|
|
||||||
|
// usual dumping - but not to the response body
|
||||||
|
VPackDumper dumper(&buffer, &options);
|
||||||
|
dumper.dump(slice);
|
||||||
|
|
||||||
|
headResponse(tmp.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,14 +45,14 @@ class HttpResponse : public GeneralResponse {
|
||||||
CONNECTION_KEEP_ALIVE,
|
CONNECTION_KEEP_ALIVE,
|
||||||
CONNECTION_CLOSE
|
CONNECTION_CLOSE
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ContentType {
|
enum ContentType {
|
||||||
CONTENT_TYPE_CUSTOM, // use Content-Type from _headers
|
CONTENT_TYPE_CUSTOM, // use Content-Type from _headers
|
||||||
CONTENT_TYPE_JSON, // application/json
|
CONTENT_TYPE_JSON, // application/json
|
||||||
CONTENT_TYPE_VPACK, // application/x-velocypack
|
CONTENT_TYPE_VPACK, // application/x-velocypack
|
||||||
CONTENT_TYPE_TEXT, // text/plain
|
CONTENT_TYPE_TEXT, // text/plain
|
||||||
CONTENT_TYPE_HTML, // text/html
|
CONTENT_TYPE_HTML, // text/html
|
||||||
CONTENT_TYPE_DUMP // application/x-arango-dump
|
CONTENT_TYPE_DUMP // application/x-arango-dump
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -76,7 +76,7 @@ class HttpResponse : public GeneralResponse {
|
||||||
|
|
||||||
/// @brief set type of connection
|
/// @brief set type of connection
|
||||||
void setConnectionType(ConnectionType type) { _connectionType = type; }
|
void setConnectionType(ConnectionType type) { _connectionType = type; }
|
||||||
|
|
||||||
/// @brief set content-type
|
/// @brief set content-type
|
||||||
void setContentType(ContentType type) { _contentType = type; }
|
void setContentType(ContentType type) { _contentType = type; }
|
||||||
|
|
||||||
|
@ -86,15 +86,21 @@ class HttpResponse : public GeneralResponse {
|
||||||
_headers[arangodb::StaticStrings::ContentTypeHeader] = contentType;
|
_headers[arangodb::StaticStrings::ContentTypeHeader] = contentType;
|
||||||
_contentType = CONTENT_TYPE_CUSTOM;
|
_contentType = CONTENT_TYPE_CUSTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setContentType(std::string&& contentType) {
|
void setContentType(std::string&& contentType) {
|
||||||
_headers[arangodb::StaticStrings::ContentTypeHeader] = std::move(contentType);
|
_headers[arangodb::StaticStrings::ContentTypeHeader] =
|
||||||
|
std::move(contentType);
|
||||||
_contentType = CONTENT_TYPE_CUSTOM;
|
_contentType = CONTENT_TYPE_CUSTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
// you should call writeHeader only after the body has been created
|
// you should call writeHeader only after the body has been created
|
||||||
void writeHeader(basics::StringBuffer*);
|
void writeHeader(basics::StringBuffer*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void fillBody(GeneralRequest const*, arangodb::velocypack::Slice const&,
|
||||||
|
bool generateBody,
|
||||||
|
arangodb::velocypack::Options const&) override final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// the body must already be set. deflate is then run on the existing body
|
// the body must already be set. deflate is then run on the existing body
|
||||||
int deflate(size_t = 16384);
|
int deflate(size_t = 16384);
|
||||||
|
|
Loading…
Reference in New Issue