Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rapidjson parity #205

Merged
merged 17 commits into from
Nov 30, 2016
4 changes: 2 additions & 2 deletions docs/install/requirements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ Envoy has the following requirements:
* `libevent <http://libevent.org/>`_ (last tested with 2.0.22)
* `tclap <http://tclap.sourceforge.net/>`_ (last tested with 1.2.1)
* `gperftools <https://github.com/gperftools/gperftools>`_ (last tested with 2.5.0)
* `jansson <https://github.com/akheron/jansson>`_ (last tesed with 2.7)
* `openssl <https://www.openssl.org/>`_ (last tesed with 1.0.2i)
* `openssl <https://www.openssl.org/>`_ (last tested with 1.0.2i)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove everything related to jansson with the pr for Jira 615

* `protobuf <https://github.com/google/protobuf>`_ (last tested with 3.0.0)
* `lightstep-tracer-cpp <https://github.com/lightstep/lightstep-tracer-cpp/>`_ (last tested with 0.16)
* `rapidjson <https://github.com/miloyip/rapidjson/>`_ (last tested with 1.1.0)

In order to compile and run the tests the following is required:

Expand Down
132 changes: 132 additions & 0 deletions include/envoy/json/json_object.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#pragma once

#include "envoy/common/exception.h"
#include "envoy/common/pure.h"

namespace Json {
class Object;

typedef std::unique_ptr<Object> ObjectPtr;

// @return false if immediate exit from iteration required.
typedef std::function<bool(const std::string&, const Object&)> ObjectCallback;

/**
* Exception thrown when a JSON error occurs.
*/
class Exception : public EnvoyException {
public:
Exception(const std::string& message) : EnvoyException(message) {}
};

/**
* Wraps an individual JSON node.
*/
class Object {
public:
virtual ~Object() {}

/**
* Convert a generic object into an array of objects. This is useful for dealing
* with arrays of arrays.
* @return std::vector<ObjectPtr> the converted object.
*/
virtual std::vector<ObjectPtr> asObjectArray() const PURE;

/**
* Get a boolean value by name.
* @param name supplies the key name.
* @return bool the value.
*/
virtual bool getBoolean(const std::string& name) const PURE;

/**
* Get a boolean value by name.
* @param name supplies the key name.
* @param default_value supplies the value to return if the name does not exist.
* @return bool the value.
*/
virtual bool getBoolean(const std::string& name, bool default_value) const PURE;

/**
* Get an integer value by name.
* @param name supplies the key name.
* @return int64_t the value.
*/
virtual int64_t getInteger(const std::string& name) const PURE;

/**
* Get an integer value by name or return a default if name does not exist.
* @param name supplies the key name.
* @param default_value supplies the value to return if name does not exist.
* @return int64_t the value.
*/
virtual int64_t getInteger(const std::string& name, int64_t default_value) const PURE;

/**
* Get a sub-object by name.
* @param name supplies the key name.
* @param allow_empty supplies whether to return an empty object if the key does not
* exist.
* @return ObjectObjectPtr the sub-object.
*/
virtual ObjectPtr getObject(const std::string& name, bool allow_empty = false) const PURE;

/**
* Get an array by name.
* @param name supplies the key name.
* @return std::vector<ObjectPtr> the array of JSON objects.
*/
virtual std::vector<ObjectPtr> getObjectArray(const std::string& name) const PURE;

/**
* Get a string value by name.
* @param name supplies the key name.
* @return std::string the value.
*/
virtual std::string getString(const std::string& name) const PURE;

/**
* Get a string value by name or return a default if name does not exist.
* @param name supplies the key name.
* @param default_value supplies the value to return if name does not exist.
* @return std::string the value.
*/
virtual std::string getString(const std::string& name,
const std::string& default_value) const PURE;

/**
* Get a string array by name.
* @param name supplies the key name.
* @return std::vector<std::string> the array of strings.
*/
virtual std::vector<std::string> getStringArray(const std::string& name) const PURE;

/**
* Get a double value by name.
* @param name supplies the key name.
* @return double the value.
*/
virtual double getDouble(const std::string& name) const PURE;

/**
* Get a double value by name.
* @param name supplies the key name.
* @param default_value supplies the value to return if name does not exist.
* @return double the value.
*/
virtual double getDouble(const std::string& name, double default_value) const PURE;

/**
* Iterate over key-value pairs in an Object and call callback on each pair.
*/
virtual void iterate(const ObjectCallback& callback) const PURE;

/**
* @return TRUE if the Object contains the key.
* @param name supplies the key name to lookup.
*/
virtual bool hasObject(const std::string& name) const PURE;
};

} // Json
1 change: 1 addition & 0 deletions source/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ add_library(

include_directories(SYSTEM ${ENVOY_HTTP_PARSER_INCLUDE_DIR})
include_directories(${ENVOY_JANSSON_INCLUDE_DIR})
include_directories(${ENVOY_RAPIDJSON_INCLUDE_DIR})

if (NOT ENVOY_SANITIZE)
include_directories(${ENVOY_GPERFTOOLS_INCLUDE_DIR})
Expand Down
12 changes: 6 additions & 6 deletions source/common/dynamo/dynamo_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ void DynamoFilter::onDecodeComplete(const Buffer::Instance& data) {
std::string body = buildBody(decoder_callbacks_->decodingBuffer(), data);
if (!body.empty()) {
try {
Json::StringLoader json_body(body);
table_descriptor_ = RequestParser::parseTable(operation_, json_body);
Json::ObjectPtr json_body = Json::Factory::LoadFromString(body);
table_descriptor_ = RequestParser::parseTable(operation_, *json_body);
} catch (const Json::Exception& jsonEx) {
// Body parsing failed. This should not happen, just put a stat for that.
stats_.counter(fmt::format("{}invalid_req_body", stat_prefix_)).inc();
Expand All @@ -64,17 +64,17 @@ void DynamoFilter::onEncodeComplete(const Buffer::Instance& data) {
std::string body = buildBody(encoder_callbacks_->encodingBuffer(), data);
if (!body.empty()) {
try {
Json::StringLoader json_body(body);
chargeTablePartitionIdStats(json_body);
Json::ObjectPtr json_body = Json::Factory::LoadFromString(body);
chargeTablePartitionIdStats(*json_body);

if (Http::CodeUtility::is4xx(status)) {
chargeFailureSpecificStats(json_body);
chargeFailureSpecificStats(*json_body);
}
// Batch Operations will always return status 200 for a partial or full success. Check
// unprocessed keys to determine partial success.
// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.BatchOperations
if (RequestParser::isBatchOperation(operation_)) {
chargeUnProcessedKeysStats(json_body);
chargeUnProcessedKeysStats(*json_body);
}
} catch (const Json::Exception&) {
// Body parsing failed. This should not happen, just put a stat for that.
Expand Down
18 changes: 9 additions & 9 deletions source/common/dynamo/dynamo_request_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ RequestParser::TableDescriptor RequestParser::parseTable(const std::string& oper
table.table_name = json_data.getString("TableName", "");
} else if (find(BATCH_OPERATIONS.begin(), BATCH_OPERATIONS.end(), operation) !=
BATCH_OPERATIONS.end()) {
Json::Object tables = json_data.getObject("RequestItems", true);
tables.iterate([&table](const std::string& key, const Json::Object&) {
Json::ObjectPtr tables = json_data.getObject("RequestItems", true);
tables->iterate([&table](const std::string& key, const Json::Object&) {
if (table.table_name.empty()) {
table.table_name = key;
} else {
Expand All @@ -88,8 +88,8 @@ RequestParser::TableDescriptor RequestParser::parseTable(const std::string& oper
}
std::vector<std::string> RequestParser::parseBatchUnProcessedKeys(const Json::Object& json_data) {
std::vector<std::string> unprocessed_tables;
Json::Object tables = json_data.getObject("UnprocessedKeys", true);
tables.iterate([&unprocessed_tables](const std::string& key, const Json::Object&) {
Json::ObjectPtr tables = json_data.getObject("UnprocessedKeys", true);
tables->iterate([&unprocessed_tables](const std::string& key, const Json::Object&) {
unprocessed_tables.emplace_back(key);
return true;
});
Expand Down Expand Up @@ -120,15 +120,15 @@ std::vector<RequestParser::PartitionDescriptor>
RequestParser::parsePartitions(const Json::Object& json_data) {
std::vector<RequestParser::PartitionDescriptor> partition_descriptors;

Json::Object partitions =
json_data.getObject("ConsumedCapacity", true).getObject("Partitions", true);
partitions.iterate([&partition_descriptors, &partitions](const std::string& key,
const Json::Object&) {
Json::ObjectPtr partitions =
json_data.getObject("ConsumedCapacity", true)->getObject("Partitions", true);
partitions->iterate([&partition_descriptors, &partitions](const std::string& key,
const Json::Object&) {
// For a given partition id, the amount of capacity used is returned in the body as a double.
// A stat will be created to track the capacity consumed for the operation, table and partition.
// Stats counter only increments by whole numbers, capacity is round up to the nearest integer
// to account for this.
uint64_t capacity_integer = static_cast<uint64_t>(std::ceil(partitions.getDouble(key, 0.0)));
uint64_t capacity_integer = static_cast<uint64_t>(std::ceil(partitions->getDouble(key, 0.0)));
partition_descriptors.emplace_back(key, capacity_integer);
return true;
});
Expand Down
6 changes: 3 additions & 3 deletions source/common/filter/auth/client_ssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ GlobalStats Config::generateStats(Stats::Store& store, const std::string& prefix

AllowedPrincipalsPtr Config::parseAuthResponse(Http::Message& message) {
AllowedPrincipalsPtr new_principals(new AllowedPrincipals());
Json::StringLoader loader(message.bodyAsString());
for (const Json::Object& certificate : loader.getObjectArray("certificates")) {
new_principals->add(certificate.getString("fingerprint_sha256"));
Json::ObjectPtr loader = Json::Factory::LoadFromString(message.bodyAsString());
for (const Json::ObjectPtr& certificate : loader->getObjectArray("certificates")) {
new_principals->add(certificate->getString("fingerprint_sha256"));
}

return new_principals;
Expand Down
6 changes: 3 additions & 3 deletions source/common/filter/ratelimit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ Config::Config(const Json::Object& config, Stats::Store& stats_store, Runtime::L
: domain_(config.getString("domain")),
stats_(generateStats(config.getString("stat_prefix"), stats_store)), runtime_(runtime) {

for (const Json::Object& descriptor : config.getObjectArray("descriptors")) {
for (const Json::ObjectPtr& descriptor : config.getObjectArray("descriptors")) {
Descriptor new_descriptor;
for (const Json::Object& entry : descriptor.asObjectArray()) {
new_descriptor.entries_.push_back({entry.getString("key"), entry.getString("value")});
for (const Json::ObjectPtr& entry : descriptor->asObjectArray()) {
new_descriptor.entries_.push_back({entry->getString("key"), entry->getString("value")});
}
descriptors_.push_back(new_descriptor);
}
Expand Down
10 changes: 5 additions & 5 deletions source/common/http/access_log/access_log_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@ bool RuntimeFilter::evaluate(const RequestInfo&, const HeaderMap& request_header

OperatorFilter::OperatorFilter(const Json::Object& json, Runtime::Loader& runtime) {
if (json.hasObject("filters")) {
std::vector<Json::Object> filters = json.getObjectArray("filters");
std::vector<Json::ObjectPtr> filters = json.getObjectArray("filters");
if (filters.size() < 2) {
throw EnvoyException(fmt::format("Filter list must have at least 2 filters, {} filters given",
filters.size()));
}

for (Json::Object& filter : filters) {
filters_.emplace_back(FilterImpl::fromJson(filter, runtime));
for (Json::ObjectPtr& filter : filters) {
filters_.emplace_back(FilterImpl::fromJson(*filter, runtime));
}
} else {
throw EnvoyException(fmt::format("Filter list cannot be empty in OperatorFilter"));
Expand Down Expand Up @@ -174,8 +174,8 @@ InstancePtr InstanceImpl::fromJson(Json::Object& json, Api::Api& api, Event::Dis

FilterPtr filter;
if (json.hasObject("filter")) {
Json::Object filterObject = json.getObject("filter");
filter = FilterImpl::fromJson(filterObject, runtime);
Json::ObjectPtr filterObject = json.getObject("filter");
filter = FilterImpl::fromJson(*filterObject, runtime);
}

FormatterPtr formatter;
Expand Down
24 changes: 12 additions & 12 deletions source/common/http/filter/fault_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ FaultFilterConfig::FaultFilterConfig(const Json::Object& json_config, Runtime::L
: runtime_(runtime), stats_{ALL_FAULT_FILTER_STATS(POOL_COUNTER_PREFIX(stats, stat_prefix))} {

if (json_config.hasObject("abort")) {
const Json::Object& abort = json_config.getObject("abort");
abort_percent_ = static_cast<uint64_t>(abort.getInteger("abort_percent", 0));
const Json::ObjectPtr& abort = json_config.getObject("abort");
abort_percent_ = static_cast<uint64_t>(abort->getInteger("abort_percent", 0));

if (abort_percent_ > 0) {
if (abort_percent_ > 100) {
Expand All @@ -28,19 +28,19 @@ FaultFilterConfig::FaultFilterConfig(const Json::Object& json_config, Runtime::L
}

// TODO: Throw error if invalid return code is provided
if (abort.hasObject("http_status")) {
http_status_ = static_cast<uint64_t>(abort.getInteger("http_status"));
if (abort->hasObject("http_status")) {
http_status_ = static_cast<uint64_t>(abort->getInteger("http_status"));
} else {
throw EnvoyException("missing http_status in abort config");
}
}

if (json_config.hasObject("delay")) {
const Json::Object& delay = json_config.getObject("delay");
const std::string type = delay.getString("type", "empty");
const Json::ObjectPtr& delay = json_config.getObject("delay");
const std::string type = delay->getString("type", "empty");
if (type == "fixed") {
fixed_delay_percent_ = static_cast<uint64_t>(delay.getInteger("fixed_delay_percent", 0));
fixed_duration_ms_ = static_cast<uint64_t>(delay.getInteger("fixed_duration_ms", 0));
fixed_delay_percent_ = static_cast<uint64_t>(delay->getInteger("fixed_delay_percent", 0));
fixed_duration_ms_ = static_cast<uint64_t>(delay->getInteger("fixed_duration_ms", 0));

if (fixed_delay_percent_ > 0) {
if (fixed_delay_percent_ > 100) {
Expand All @@ -56,11 +56,11 @@ FaultFilterConfig::FaultFilterConfig(const Json::Object& json_config, Runtime::L
}

if (json_config.hasObject("headers")) {
std::vector<Json::Object> config_headers = json_config.getObjectArray("headers");
for (const Json::Object& header_map : config_headers) {
std::vector<Json::ObjectPtr> config_headers = json_config.getObjectArray("headers");
for (const Json::ObjectPtr& header_map : config_headers) {
// allow header value to be empty, allows matching to be only based on header presence.
fault_filter_headers_.emplace_back(Http::LowerCaseString(header_map.getString("name")),
header_map.getString("value", EMPTY_STRING));
fault_filter_headers_.emplace_back(Http::LowerCaseString(header_map->getString("name")),
header_map->getString("value", EMPTY_STRING));
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions source/common/http/filter/ratelimit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ FilterConfig::FilterConfig(const Json::Object& config, const std::string& local_
Stats::Store& stats_store, Runtime::Loader& runtime)
: domain_(config.getString("domain")), local_service_cluster_(local_service_cluster),
stats_store_(stats_store), runtime_(runtime) {
for (const Json::Object& action : config.getObjectArray("actions")) {
std::string type = action.getString("type");
for (const Json::ObjectPtr& action : config.getObjectArray("actions")) {
std::string type = action->getString("type");
if (type == "service_to_service") {
actions_.emplace_back(new ServiceToServiceAction());
} else if (type == "request_headers") {
actions_.emplace_back(new RequestHeadersAction(action));
actions_.emplace_back(new RequestHeadersAction(*action));
} else if (type == "remote_address") {
actions_.emplace_back(new RemoteAddressAction());
} else {
Expand Down
Loading