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>());

    switch (response->transportType()) {
      case Endpoint::TransportType::HTTP: {
        //  OBI FIXME - vpack
        //  HTTP SHOULD USE vpack interface

        HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
        if (transformArray->IsArray()) {
          TRI_GET_GLOBAL_STRING(BodyKey);
          std::string out(TRI_ObjectToString(
              isolate,
              res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>())));
          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);

            // 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);
            }
          }

          // what type is out? always json?
          httpResponse->body().appendText(out);
          httpResponse->sealBody();
        } else {
          TRI_GET_GLOBAL_STRING(BodyKey);
          v8::Handle<v8::Value> b =
              res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>());
          if (V8Buffer::hasInstance(isolate, b)) {
            // body is a Buffer
            auto obj = b.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,
                  res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>()));
              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, res->Get(context, BodyKey)
                               .FromMaybe(v8::Local<v8::Value>())));
              httpResponse->sealBody();
            }
          } else {
            // treat body as a string
            httpResponse->body().appendText(TRI_ObjectToString(
                isolate,
                res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>())));
            httpResponse->sealBody();
          }
        }
      } break;

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

        v8::Handle<v8::Value> v8Body =
            res->Get(context, BodyKey).FromMaybe(v8::Local<v8::Value>());
        std::string out;

        // decode and set out
        if (transformArray->IsArray()) {
          TRI_GET_GLOBAL_STRING(BodyKey);
          out = TRI_ObjectToString(
              isolate,
              res->Get(context, BodyKey)
                  .FromMaybe(
                      v8::Local<v8::Value>()));  // 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);
            }
          }
        }

        // out is not set
        if (out.empty()) {
          if (autoContent && !V8Buffer::hasInstance(isolate, v8Body)) {
            if (v8Body->IsString()) {
              out = TRI_ObjectToString(
                  isolate,
                  res->Get(context, BodyKey)
                      .FromMaybe(v8::Local<v8::Value>()));  // should get moved
            } else {
              TRI_V8ToVPack(isolate, builder, v8Body, false);
              response->setContentType(rest::ContentType::VPACK);
            }
          } else if (V8Buffer::hasInstance(
                         isolate,
                         v8Body)) {  // body form buffer - could
                                     // contain json or not
            // REVIEW (fc) - is this correct?
            auto obj = v8Body.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,
                res->Get(context, BodyKey)
                    .FromMaybe(v8::Local<v8::Value>()));  // 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(velocypack::StringRef(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");
    }
  }
}