diff --git a/arangod/RestHandler/RestBaseHandler.cpp b/arangod/RestHandler/RestBaseHandler.cpp index 6526e0ade6..298421855f 100644 --- a/arangod/RestHandler/RestBaseHandler.cpp +++ b/arangod/RestHandler/RestBaseHandler.cpp @@ -43,16 +43,17 @@ void RestBaseHandler::handleError(Exception const& ex) { generateError(GeneralResponse::responseCode(ex.code()), ex.code(), ex.what()); } + + //////////////////////////////////////////////////////////////////////////////// /// @brief generates a result from VelocyPack //////////////////////////////////////////////////////////////////////////////// void RestBaseHandler::generateResult(GeneralResponse::ResponseCode code, VPackSlice const& slice) { - createResponse(code); - _response->setContentType("application/json; charset=utf-8"); - dumpResponse(slice, &VPackOptions::Defaults); + createResponse(code); + writeResult(slice, VPackOptions::Defaults); } //////////////////////////////////////////////////////////////////////////////// @@ -63,9 +64,7 @@ void RestBaseHandler::generateResult(GeneralResponse::ResponseCode code, VPackSlice const& slice, std::shared_ptr context) { createResponse(code); - _response->setContentType("application/json; charset=utf-8"); - - dumpResponse(slice, context->getVPackOptions()); + writeResult(slice,*(context->getVPackOptions())); } //////////////////////////////////////////////////////////////////////////////// @@ -90,7 +89,6 @@ void RestBaseHandler::generateError(GeneralResponse::ResponseCode code, void RestBaseHandler::generateError(GeneralResponse::ResponseCode code, int errorCode, std::string const& message) { createResponse(code); - _response->setContentType("application/json; charset=utf-8"); VPackBuilder builder; try { @@ -106,7 +104,7 @@ void RestBaseHandler::generateError(GeneralResponse::ResponseCode code, builder.add("errorNum", VPackValue(errorCode)); builder.close(); - dumpResponse(builder.slice(), &VPackOptions::Defaults); + writeResult(builder.slice(), VPackOptions::Defaults); } catch (...) { // Building the error response failed } @@ -147,3 +145,28 @@ void RestBaseHandler::dumpResponse(VPackSlice const& slice, } } +////////////////////////////////////////////////////////////////////////////// +/// @brief checks if velocypack is expected as answer +////////////////////////////////////////////////////////////////////////////// + +bool RestBaseHandler::returnVelocypack() const { + auto accept = std::string(_request->header("accept")); + if (std::string::npos == accept.find("application/x-velocypack")) { + return false; + } + return true; +} + +////////////////////////////////////////////////////////////////////////////// +/// @brief writes volocypack or json to response +////////////////////////////////////////////////////////////////////////////// + +void RestBaseHandler::writeResult(arangodb::velocypack::Slice const& slice, VPackOptions const& options){ + if(returnVelocypack()) { + _response->setContentType("application/x-velocypack"); + _response->body().appendText(slice.startAs(),slice.byteSize()); + } else { + _response->setContentType("application/json; charset=utf-8"); + dumpResponse(slice, &options); + } +} diff --git a/arangod/RestHandler/RestBaseHandler.h b/arangod/RestHandler/RestBaseHandler.h index c2d19a2856..1b65f80074 100644 --- a/arangod/RestHandler/RestBaseHandler.h +++ b/arangod/RestHandler/RestBaseHandler.h @@ -44,18 +44,15 @@ class RestBaseHandler : public rest::HttpHandler { public: explicit RestBaseHandler(HttpRequest* request); - public: void handleError(basics::Exception const&) override; - public: - ////////////////////////////////////////////////////////////////////////////// /// @brief generates a result from VelocyPack ////////////////////////////////////////////////////////////////////////////// void generateResult(GeneralResponse::ResponseCode, arangodb::velocypack::Slice const& slice); - + ////////////////////////////////////////////////////////////////////////////// /// @brief generates a result from VelocyPack ////////////////////////////////////////////////////////////////////////////// @@ -81,7 +78,7 @@ class RestBaseHandler : public rest::HttpHandler { ////////////////////////////////////////////////////////////////////////////// void generateOOMError(); - + ////////////////////////////////////////////////////////////////////////////// /// @brief generates a canceled message ////////////////////////////////////////////////////////////////////////////// @@ -92,6 +89,19 @@ class RestBaseHandler : public rest::HttpHandler { /// @brief dumps the response as JSON into the response string buffer ////////////////////////////////////////////////////////////////////////////// + protected: + ////////////////////////////////////////////////////////////////////////////// + /// @brief checks if velocypack is expected as answer + ////////////////////////////////////////////////////////////////////////////// + + bool returnVelocypack() const; + + ////////////////////////////////////////////////////////////////////////////// + /// @brief write result back to client + ////////////////////////////////////////////////////////////////////////////// + void writeResult(arangodb::velocypack::Slice const& slice, VPackOptions const& options); + + private: void dumpResponse(arangodb::velocypack::Slice const& slice, arangodb::velocypack::Options const* options); }; diff --git a/arangod/RestHandler/RestVocbaseBaseHandler.cpp b/arangod/RestHandler/RestVocbaseBaseHandler.cpp index 511998007b..ececfcf92b 100644 --- a/arangod/RestHandler/RestVocbaseBaseHandler.cpp +++ b/arangod/RestHandler/RestVocbaseBaseHandler.cpp @@ -236,7 +236,6 @@ void RestVocbaseBaseHandler::generate20x( VPackSlice slice = result.slice(); TRI_ASSERT(slice.isObject() || slice.isArray()); - _response->setContentType("application/json; charset=utf-8"); if (slice.isObject()) { _response->setHeaderNC("etag", "\"" + slice.get(TRI_VOC_ATTRIBUTE_REV).copyString() + "\""); // pre 1.4 location headers withdrawn for >= 3.0 @@ -246,14 +245,9 @@ void RestVocbaseBaseHandler::generate20x( std::string("/_db/" + _request->databaseName() + DOCUMENT_PATH + "/" + escapedHandle)); } - VPackStringBufferAdapter buffer(_response->body().stringBuffer()); - VPackDumper dumper(&buffer, options); - try { - dumper.dump(slice); - } catch (...) { - generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, - "cannot generate output"); - } + + writeResult(slice, *options); + } //////////////////////////////////////////////////////////////////////////////// @@ -282,8 +276,7 @@ void RestVocbaseBaseHandler::generatePreconditionFailed( VPackSlice const& slice) { createResponse(GeneralResponse::ResponseCode::PRECONDITION_FAILED); - _response->setContentType("application/json; charset=utf-8"); - + if (slice.isObject()) { // single document case std::string const rev = VelocyPackHelper::getStringValue(slice, TRI_VOC_ATTRIBUTE_REV, ""); _response->setHeaderNC("etag", "\"" + rev + "\""); @@ -306,16 +299,8 @@ void RestVocbaseBaseHandler::generatePreconditionFailed( } } - VPackStringBufferAdapter buffer(_response->body().stringBuffer()); auto transactionContext(StandaloneTransactionContext::Create(_vocbase)); - VPackDumper dumper(&buffer, transactionContext->getVPackOptions()); - - try { - dumper.dump(builder.slice()); - } catch (...) { - generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, - "cannot generate output"); - } + writeResult(builder.slice(), *(transactionContext->getVPackOptions())); } //////////////////////////////////////////////////////////////////////////////// @@ -362,34 +347,37 @@ void RestVocbaseBaseHandler::generateDocument(VPackSlice const& document, // and generate a response createResponse(GeneralResponse::ResponseCode::OK); - _response->setContentType("application/json; charset=utf-8"); if (!rev.empty()) { _response->setHeaderNC("etag", "\"" + rev + "\""); } if (generateBody) { - VPackStringBufferAdapter buffer(_response->body().stringBuffer()); - VPackDumper dumper(&buffer, options); - try { - dumper.dump(document); - } catch (...) { - generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, - "cannot generate output"); - } + writeResult(document, *options); } else { - // TODO can we optimize this? - // Just dump some where else to find real length - StringBuffer tmp(TRI_UNKNOWN_MEM_ZONE); - // convert object to string - VPackStringBufferAdapter buffer(tmp.stringBuffer()); - VPackDumper dumper(&buffer, options); - try { - dumper.dump(document); - } catch (...) { - generateError(GeneralResponse::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, - "cannot generate output"); + if(returnVelocypack()){ + //TODO REVIEW + _response->setContentType("application/x-velocypack"); + _response->headResponse(document.byteSize()); + } else { + _response->setContentType("application/json; charset=utf-8"); + + // TODO can we optimize this? + // Just dump some where else to find real length + StringBuffer tmp(TRI_UNKNOWN_MEM_ZONE); + // 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()); } - _response->headResponse(tmp.length()); } } @@ -489,9 +477,9 @@ void RestVocbaseBaseHandler::generateTransactionError( generateError(GeneralResponse::ResponseCode::FORBIDDEN, res); return; } - - case TRI_ERROR_OUT_OF_MEMORY: - case TRI_ERROR_LOCK_TIMEOUT: + + case TRI_ERROR_OUT_OF_MEMORY: + case TRI_ERROR_LOCK_TIMEOUT: case TRI_ERROR_DEBUG: case TRI_ERROR_LOCKED: case TRI_ERROR_DEADLOCK: { @@ -517,7 +505,7 @@ void RestVocbaseBaseHandler::generateTransactionError( generateError(GeneralResponse::ResponseCode::FORBIDDEN, result.code, "collection is read-only"); return; - + case TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED: generateError(GeneralResponse::ResponseCode::CONFLICT, result.code, "cannot create document, unique constraint violated"); @@ -576,14 +564,14 @@ void RestVocbaseBaseHandler::generateTransactionError( generateError(GeneralResponse::ResponseCode::NOT_IMPLEMENTED, result.code); return; } - + case TRI_ERROR_FORBIDDEN: { generateError(GeneralResponse::ResponseCode::FORBIDDEN, result.code); return; } - - case TRI_ERROR_OUT_OF_MEMORY: - case TRI_ERROR_LOCK_TIMEOUT: + + case TRI_ERROR_OUT_OF_MEMORY: + case TRI_ERROR_LOCK_TIMEOUT: case TRI_ERROR_DEBUG: case TRI_ERROR_LOCKED: case TRI_ERROR_DEADLOCK: { diff --git a/arangod/RestHandler/RestVocbaseBaseHandler.h b/arangod/RestHandler/RestVocbaseBaseHandler.h index 51176df2a4..13cdd952d0 100644 --- a/arangod/RestHandler/RestVocbaseBaseHandler.h +++ b/arangod/RestHandler/RestVocbaseBaseHandler.h @@ -249,7 +249,7 @@ class RestVocbaseBaseHandler : public RestBaseHandler { ////////////////////////////////////////////////////////////////////////////// /// @brief generate an error message for a transaction error ////////////////////////////////////////////////////////////////////////////// - + void generateTransactionError(OperationResult const&); //////////////////////////////////////////////////////////////////////////////