static void ResponseV8ToCpp(v8::Isolate* isolate, TRI_v8_global_t const* v8g,
                            GeneralRequest* request, v8::Handle<v8::Object> const res,
                            GeneralResponse* response) {
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  TRI_ASSERT(request != nullptr);

  using arangodb::Endpoint;

  // set response code
  TRI_GET_GLOBAL_STRING(ResponseCodeKey);
  if (TRI_HasProperty(context, isolate, res, ResponseCodeKey)) {
    uint64_t foxxcode = TRI_ObjectToInt64(isolate,
                                          res->Get(context,
                                                   ResponseCodeKey
                                                   ).FromMaybe(v8::Local<v8::Value>()));
    if (GeneralResponse::isValidResponseCode(foxxcode)) {
      response->setResponseCode(static_cast<rest::ResponseCode>(foxxcode));
    } else {
      response->setResponseCode(rest::ResponseCode::SERVER_ERROR);
      LOG_TOPIC("37d37", ERR, Logger::V8)
        << "invalid http status code specified " << foxxcode
        << " diverting to 500";
    }
  } else {
    response->setResponseCode(rest::ResponseCode::OK);
  }

  // string should not be used
  std::string contentType = StaticStrings::MimeTypeJsonNoEncoding;
  bool autoContent = true;
  TRI_GET_GLOBAL_STRING(ContentTypeKey);
  if (TRI_HasProperty(context, isolate, res, ContentTypeKey)) {
    contentType = TRI_ObjectToString(isolate, res->Get(context, ContentTypeKey).FromMaybe(v8::Local<v8::Value>()));

    if ((contentType.find(StaticStrings::MimeTypeJsonNoEncoding) == std::string::npos) &&
        (contentType.find(StaticStrings::MimeTypeVPack) == std::string::npos)) {
      autoContent = false;
    }
    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP:
        if (autoContent) {
          response->setContentType(rest::ContentType::JSON);
        } else {
          response->setContentType(contentType);
        }
        break;

      case Endpoint::TransportType::VST:
        if (!autoContent) {
          response->setContentType(contentType);
        } else {
          response->setHeaderNC(arangodb::StaticStrings::ContentTypeHeader, contentType);
        }
        break;

      default:
        throw std::logic_error("unknown transport type");
    }
  }

  // .........................................................................
  // body
  // .........................................................................
  //

  bool bodySet = false;
  TRI_GET_GLOBAL_STRING(BodyKey);

  if (TRI_HasProperty(context, isolate, res, BodyKey)) {
    // check if we should apply result transformations
    // transformations turn the result from one type into another
    // a JavaScript action can request transformations by
    // putting a list of transformations into the res.transformations
    // array, e.g. res.transformations = [ "base64encode" ]
    TRI_GET_GLOBAL_STRING(TransformationsKey);
    v8::Handle<v8::Value> transformArray = res->Get(context, TransformationsKey).FromMaybe(v8::Local<v8::Value>());
    v8::Handle<v8::Value> bodyVal = res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>());
    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
        //  OBI FIXME - vpack
        //  HTTP SHOULD USE vpack interface

        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        v8::Handle<v8::Array> transformations = transformArray.As<v8::Array>();
        bool setRegularBody = !transformArray->IsArray();
        if (!setRegularBody) {
          std::string out(TRI_ObjectToString(isolate, bodyVal));

          for (uint32_t i = 0; i < transformations->Length(); i++) {
            v8::Handle<v8::Value> transformator =
              transformations->Get(context, v8::Integer::New(isolate, i)).FromMaybe(v8::Local<v8::Value>());
            std::string name = TRI_ObjectToString(isolate, transformator);

            // check available transformations
            if (name == "base64encode") {
              // base64-encode the result
              out = StringUtils::encodeBase64(out);
              // set the correct content-encoding header
              response->setHeaderNC(StaticStrings::ContentEncoding, StaticStrings::Base64);
            } else if (name == "base64decode") {
              // base64-decode the result
              out = StringUtils::decodeBase64(out);
              // set the correct content-encoding header
              response->setHeaderNC(StaticStrings::ContentEncoding, StaticStrings::Binary);
            } else if (name == "gzip") {
              response->setAllowCompression(true);
              setRegularBody = true;
            } else if (name == "deflate") {
              response->setAllowCompression(true);
              setRegularBody = true;
            }
          }
          if (!setRegularBody) {
            // what type is out? always json?
            httpResponse->body().appendText(out);
            httpResponse->sealBody();
          }
        }
        if (setRegularBody) {
          if (V8Buffer::hasInstance(isolate, bodyVal)) {
            // body is a Buffer
            auto obj = bodyVal.As<v8::Object>();
            httpResponse->body().appendText(V8Buffer::data(isolate, obj),
                                            V8Buffer::length(isolate, obj));
            httpResponse->sealBody();
          } else if (autoContent && request->contentTypeResponse() == rest::ContentType::VPACK) {
            // use velocypack
            try {
              std::string json = TRI_ObjectToString(isolate, bodyVal);
              VPackBuffer<uint8_t> buffer;
              VPackBuilder builder(buffer);
              VPackParser parser(builder);
              parser.parse(json);
              httpResponse->setContentType(rest::ContentType::VPACK);
              httpResponse->setPayload(std::move(buffer));
            } catch (...) {
              httpResponse->body().appendText(TRI_ObjectToString(isolate, bodyVal));
              httpResponse->sealBody();
            }
          } else {
            // treat body as a string
            httpResponse->body().appendText(TRI_ObjectToString(isolate, bodyVal));
            httpResponse->sealBody();
          }
        }
      } break;

      case Endpoint::TransportType::VST: {
        VPackBuffer<uint8_t> buffer;
        VPackBuilder builder(buffer);
        std::string out;

        // decode and set out
        if (transformArray->IsArray()) {
          out = TRI_ObjectToString(isolate, bodyVal);  // there is one case where
                                                                 // we do not need a string
          v8::Handle<v8::Array> transformations = transformArray.As<v8::Array>();

          for (uint32_t i = 0; i < transformations->Length(); i++) {
            v8::Handle<v8::Value> transformator =
              transformations->Get(context, v8::Integer::New(isolate, i)).FromMaybe(v8::Local<v8::Value>());
            std::string name = TRI_ObjectToString(isolate, transformator);

            // we do not decode in the vst case
            // check available transformations
            if (name == "base64decode") {
              out = StringUtils::decodeBase64(out);
            } else if (name == "gzip") {
              response->setAllowCompression(true);
            } else if (name == "deflate") {
              response->setAllowCompression(true);
            }
          }
        }

        // out is not set
        if (out.empty()) {
          if (autoContent && !V8Buffer::hasInstance(isolate, bodyVal)) {
            if (bodyVal->IsString()) {
              out = TRI_ObjectToString(isolate, bodyVal);  // should get moved
            } else {
              TRI_V8ToVPack(isolate, builder, bodyVal, false);
              response->setContentType(rest::ContentType::VPACK);
            }
          } else if (V8Buffer::hasInstance(isolate,
                                           bodyVal)) {  // body form buffer - could
            // contain json or not
            // REVIEW (fc) - is this correct?
            auto obj = bodyVal.As<v8::Object>();
            out = std::string(V8Buffer::data(isolate, obj), V8Buffer::length(isolate, obj));
          } else {  // body is text - does not contain json
            out = TRI_ObjectToString(isolate, bodyVal);  // should get moved
          }
        }

        // there is a text body
        if (!out.empty()) {
          bool gotJson = false;
          if (autoContent) {  // the text body could contain an object
            try {
              VPackParser parser(builder);  // add json as vpack to the builder
              parser.parse(out, false);
              gotJson = true;
              response->setContentType(rest::ContentType::VPACK);
            } catch (...) {  // do nothing
                             // json could not be converted
                             // there was no json - change content type?
              LOG_TOPIC("32d35", DEBUG, Logger::COMMUNICATION)
                  << "failed to parse json:\n"
                  << out;
            }
          }

          if (!gotJson) {
            // don't go via the builder - when not added via parser
            buffer.reset();
            buffer.append(out);
          }
        }

        response->setPayload(std::move(buffer));
        break;
      }

      default: { throw std::logic_error("unknown transport type"); }
    }
    bodySet = true;
  }

  // .........................................................................
  // body from file
  // .........................................................................
  TRI_GET_GLOBAL_STRING(BodyFromFileKey);
  if (!bodySet && TRI_HasProperty(context, isolate, res, BodyFromFileKey)) {
    TRI_Utf8ValueNFC filename(isolate, res->Get(context, BodyFromFileKey).FromMaybe(v8::Local<v8::Value>()));
    size_t length;
    char* content = TRI_SlurpFile(*filename, &length);

    if (content == nullptr) {
      THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_FILE_NOT_FOUND,
                                     std::string("unable to read file '") +
                                         *filename + "'");
    }

    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        httpResponse->body().appendText(content, length);
        TRI_FreeString(content);
        httpResponse->sealBody();
      }
      break;

      case Endpoint::TransportType::VST: {
        response->addRawPayload(std::string_view(content, length));
        TRI_FreeString(content);
      }
      break;

      default:
        TRI_FreeString(content);
        throw std::logic_error("unknown transport type");
    }
  }

  // .........................................................................
  // headers
  // .........................................................................

  TRI_GET_GLOBAL_STRING(HeadersKey);

  if (TRI_HasProperty(context, isolate, res, HeadersKey)) {
    v8::Handle<v8::Value> val = res->Get(context, HeadersKey).FromMaybe(v8::Local<v8::Value>());
    v8::Handle<v8::Object> v8Headers = val.As<v8::Object>();

    if (v8Headers->IsObject()) {
      v8::Handle<v8::Array> props = v8Headers->GetPropertyNames(TRI_IGETC).FromMaybe(v8::Local<v8::Array>());

      for (uint32_t i = 0; i < props->Length(); i++) {
        v8::Handle<v8::Value> key = props->Get(context, v8::Integer::New(isolate, i)).FromMaybe(v8::Local<v8::Value>());
        response->setHeader(TRI_ObjectToString(isolate, key),
                            TRI_ObjectToString(isolate, v8Headers->Get(context, key).FromMaybe(v8::Local<v8::Value>())));
      }
    }
  }

  // .........................................................................
  // cookies
  // .........................................................................

  TRI_GET_GLOBAL_STRING(CookiesKey);
  if (TRI_HasProperty(context, isolate, res, CookiesKey)) {
    v8::Handle<v8::Value> val = res->Get(context, CookiesKey).FromMaybe(v8::Local<v8::Value>());
    v8::Handle<v8::Object> v8Cookies = val.As<v8::Object>();

    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        if (v8Cookies->IsArray()) {
          v8::Handle<v8::Array> v8Array = v8Cookies.As<v8::Array>();

          for (uint32_t i = 0; i < v8Array->Length(); i++) {
            v8::Handle<v8::Value> v8Cookie = v8Array->Get(context, i).FromMaybe(v8::Local<v8::Value>());
            if (v8Cookie->IsObject()) {
              AddCookie(isolate, v8g, httpResponse, v8Cookie.As<v8::Object>());
            }
          }
        } else if (v8Cookies->IsObject()) {
          // one cookie
          AddCookie(isolate, v8g, httpResponse, v8Cookies);
        }
      } break;

      case Endpoint::TransportType::VST:
        break;

      default:
        throw std::logic_error("unknown transport type");
    }
  }
}
static void ResponseV8ToCpp(v8::Isolate* isolate, TRI_v8_global_t const* v8g,
                            GeneralRequest* request, v8::Handle<v8::Object> const res,
                            GeneralResponse* response) {
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  TRI_ASSERT(request != nullptr);

  using arangodb::Endpoint;

   
  TRI_GET_GLOBAL_STRING(ResponseCodeKey);
  if (TRI_HasProperty(context, isolate, res, ResponseCodeKey)) {
    uint64_t foxxcode = TRI_ObjectToInt64(isolate,
                                          res->Get(context,
                                                   ResponseCodeKey
                                                   ).FromMaybe(v8::Local<v8::Value>()));
    if (GeneralResponse::isValidResponseCode(foxxcode)) {
      response->setResponseCode(static_cast<rest::ResponseCode>(foxxcode));
    } else {
      response->setResponseCode(rest::ResponseCode::SERVER_ERROR);
      LOG_TOPIC("37d37", ERR, Logger::V8)
        << "invalid http status code specified " << foxxcode
        << " diverting to 500";
    }
  } else {
    response->setResponseCode(rest::ResponseCode::OK);
  }

   
  std::string contentType = StaticStrings::MimeTypeJsonNoEncoding;
  bool autoContent = true;
  TRI_GET_GLOBAL_STRING(ContentTypeKey);
  if (TRI_HasProperty(context, isolate, res, ContentTypeKey)) {
    contentType = TRI_ObjectToString(isolate, res->Get(context, ContentTypeKey).FromMaybe(v8::Local<v8::Value>()));

    if ((contentType.find(StaticStrings::MimeTypeJsonNoEncoding) == std::string::npos) &&
        (contentType.find(StaticStrings::MimeTypeVPack) == std::string::npos)) {
      autoContent = false;
    }
    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP:
        if (autoContent) {
          response->setContentType(rest::ContentType::JSON);
        } else {
          response->setContentType(contentType);
        }
        break;

      case Endpoint::TransportType::VST:
        if (!autoContent) {
          response->setContentType(contentType);
        } else {
          response->setHeaderNC(arangodb::StaticStrings::ContentTypeHeader, contentType);
        }
        break;

      default:
        throw std::logic_error("unknown transport type");
    }
  }

   
   
   
   

  bool bodySet = false;
  TRI_GET_GLOBAL_STRING(BodyKey);

  if (TRI_HasProperty(context, isolate, res, BodyKey)) {
     
     
     
     
     
    TRI_GET_GLOBAL_STRING(TransformationsKey);
    v8::Handle<v8::Value> transformArray = res->Get(context, TransformationsKey).FromMaybe(v8::Local<v8::Value>());
    v8::Handle<v8::Value> bodyVal = res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>());
    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
         
         

        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        v8::Handle<v8::Array> transformations = transformArray.As<v8::Array>();
        bool setRegularBody = !transformArray->IsArray();
        if (!setRegularBody) {
          std::string out(TRI_ObjectToString(isolate, bodyVal));

          for (uint32_t i = 0; i < transformations->Length(); i++) {
            v8::Handle<v8::Value> transformator =
              transformations->Get(context, v8::Integer::New(isolate, i)).FromMaybe(v8::Local<v8::Value>());
            std::string name = TRI_ObjectToString(isolate, transformator);

             
            if (name == "base64encode") {
               
              out = StringUtils::encodeBase64(out);
               
              response->setHeaderNC(StaticStrings::ContentEncoding, StaticStrings::Base64);
            } else if (name == "base64decode") {
               
              out = StringUtils::decodeBase64(out);
               
              response->setHeaderNC(StaticStrings::ContentEncoding, StaticStrings::Binary);
            } else if (name == "gzip") {
              response->setAllowCompression(true);
              setRegularBody = true;
            } else if (name == "deflate") {
              response->setAllowCompression(true);
              setRegularBody = true;
            }
          }
          if (!setRegularBody) {
             
            httpResponse->body().appendText(out);
            httpResponse->sealBody();
          }
        }
        if (setRegularBody) {
          if (V8Buffer::hasInstance(isolate, bodyVal)) {
             
            auto obj = bodyVal.As<v8::Object>();
            httpResponse->body().appendText(V8Buffer::data(isolate, obj),
                                            V8Buffer::length(isolate, obj));
            httpResponse->sealBody();
          } else if (autoContent && request->contentTypeResponse() == rest::ContentType::VPACK) {
             
            try {
              std::string json = TRI_ObjectToString(isolate, bodyVal);
              VPackBuffer<uint8_t> buffer;
              VPackBuilder builder(buffer);
              VPackParser parser(builder);
              parser.parse(json);
              httpResponse->setContentType(rest::ContentType::VPACK);
              httpResponse->setPayload(std::move(buffer));
            } catch (...) {
              httpResponse->body().appendText(TRI_ObjectToString(isolate, bodyVal));
              httpResponse->sealBody();
            }
          } else {
             
            httpResponse->body().appendText(TRI_ObjectToString(isolate, bodyVal));
            httpResponse->sealBody();
          }
        }
      } break;

      case Endpoint::TransportType::VST: {
        VPackBuffer<uint8_t> buffer;
        VPackBuilder builder(buffer);
        std::string out;

         
        if (transformArray->IsArray()) {
          out = TRI_ObjectToString(isolate, bodyVal);   
                                                                  
          v8::Handle<v8::Array> transformations = transformArray.As<v8::Array>();

          for (uint32_t i = 0; i < transformations->Length(); i++) {
            v8::Handle<v8::Value> transformator =
              transformations->Get(context, v8::Integer::New(isolate, i)).FromMaybe(v8::Local<v8::Value>());
            std::string name = TRI_ObjectToString(isolate, transformator);

             
             
            if (name == "base64decode") {
              out = StringUtils::decodeBase64(out);
            } else if (name == "gzip") {
              response->setAllowCompression(true);
            } else if (name == "deflate") {
              response->setAllowCompression(true);
            }
          }
        }

         
        if (out.empty()) {
          if (autoContent && !V8Buffer::hasInstance(isolate, bodyVal)) {
            if (bodyVal->IsString()) {
              out = TRI_ObjectToString(isolate, bodyVal);   
            } else {
              TRI_V8ToVPack(isolate, builder, bodyVal, false);
              response->setContentType(rest::ContentType::VPACK);
            }
          } else if (V8Buffer::hasInstance(isolate,
                                           bodyVal)) {   
             
             
            auto obj = bodyVal.As<v8::Object>();
            out = std::string(V8Buffer::data(isolate, obj), V8Buffer::length(isolate, obj));
          } else {   
            out = TRI_ObjectToString(isolate, bodyVal);   
          }
        }

         
        if (!out.empty()) {
          bool gotJson = false;
          if (autoContent) {   
            try {
              VPackParser parser(builder);   
              parser.parse(out, false);
              gotJson = true;
              response->setContentType(rest::ContentType::VPACK);
            } catch (...) {   
                              
                              
              LOG_TOPIC("32d35", DEBUG, Logger::COMMUNICATION)
                  << "failed to parse json:\n"
                  << out;
            }
          }

          if (!gotJson) {
             
            buffer.reset();
            buffer.append(out);
          }
        }

        response->setPayload(std::move(buffer));
        break;
      }

      default: { throw std::logic_error("unknown transport type"); }
    }
    bodySet = true;
  }

   
   
   
  TRI_GET_GLOBAL_STRING(BodyFromFileKey);
  if (!bodySet && TRI_HasProperty(context, isolate, res, BodyFromFileKey)) {
    TRI_Utf8ValueNFC filename(isolate, res->Get(context, BodyFromFileKey).FromMaybe(v8::Local<v8::Value>()));
    size_t length;
    char* content = TRI_SlurpFile(*filename, &length);

    if (content == nullptr) {
      THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_FILE_NOT_FOUND,
                                     std::string("unable to read file '") +
                                         *filename + "'");
    }

    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        httpResponse->body().appendText(content, length);
        TRI_FreeString(content);
        httpResponse->sealBody();
      }
      break;

      case Endpoint::TransportType::VST: {
        response->addRawPayload(std::string_view(content, length));
        TRI_FreeString(content);
      }
      break;

      default:
        TRI_FreeString(content);
        throw std::logic_error("unknown transport type");
    }
  }

   
   
   

  TRI_GET_GLOBAL_STRING(HeadersKey);

  if (TRI_HasProperty(context, isolate, res, HeadersKey)) {
    v8::Handle<v8::Value> val = res->Get(context, HeadersKey).FromMaybe(v8::Local<v8::Value>());
    v8::Handle<v8::Object> v8Headers = val.As<v8::Object>();

    if (v8Headers->IsObject()) {
      v8::Handle<v8::Array> props = v8Headers->GetPropertyNames(TRI_IGETC).FromMaybe(v8::Local<v8::Array>());

      for (uint32_t i = 0; i < props->Length(); i++) {
        v8::Handle<v8::Value> key = props->Get(context, v8::Integer::New(isolate, i)).FromMaybe(v8::Local<v8::Value>());
        response->setHeader(TRI_ObjectToString(isolate, key),
                            TRI_ObjectToString(isolate, v8Headers->Get(context, key).FromMaybe(v8::Local<v8::Value>())));
      }
    }
  }

   
   
   

  TRI_GET_GLOBAL_STRING(CookiesKey);
  if (TRI_HasProperty(context, isolate, res, CookiesKey)) {
    v8::Handle<v8::Value> val = res->Get(context, CookiesKey).FromMaybe(v8::Local<v8::Value>());
    v8::Handle<v8::Object> v8Cookies = val.As<v8::Object>();

    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        if (v8Cookies->IsArray()) {
          v8::Handle<v8::Array> v8Array = v8Cookies.As<v8::Array>();

          for (uint32_t i = 0; i < v8Array->Length(); i++) {
            v8::Handle<v8::Value> v8Cookie = v8Array->Get(context, i).FromMaybe(v8::Local<v8::Value>());
            if (v8Cookie->IsObject()) {
              AddCookie(isolate, v8g, httpResponse, v8Cookie.As<v8::Object>());
            }
          }
        } else if (v8Cookies->IsObject()) {
           
          AddCookie(isolate, v8g, httpResponse, v8Cookies);
        }
      } break;

      case Endpoint::TransportType::VST:
        break;

      default:
        throw std::logic_error("unknown transport type");
    }
  }
}