Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cpp/fost-urlhandler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ add_library(fost-urlhandler
control.exception.cpp
control.status-condition.cpp
fost-urlhandler.cpp
fsigma.cpp
matcher.cpp
middleware.logging.cpp
middleware.request.cpp
middleware.template.cpp
mime-types.cpp
precondition.cpp
responses.cpp
responses.301.cpp
responses.302.cpp
Expand All @@ -22,6 +25,7 @@ add_library(fost-urlhandler
schema.validate.cpp
test.throw.cpp
view.cpp
view.matcher.cpp
)
target_include_directories(fost-urlhandler PUBLIC ../include)
target_link_libraries(fost-urlhandler fost-inet f5-json-schema)
Expand All @@ -33,6 +37,8 @@ if(TARGET check)
add_library(fost-urlhandler-smoke STATIC EXCLUDE_FROM_ALL
control.exception.tests.cpp
control.status-condition-tests.cpp
matcher.tests.cpp
precondition.tests.cpp
responses.tests.cpp
responses.301-tests.cpp
responses.302-tests.cpp
Expand All @@ -43,6 +49,7 @@ if(TARGET check)
schema.validate-tests.cpp
test.throw.tests.cpp
view-tests.cpp
view.matcher.tests.cpp
view.request-id.tests.cpp
)
target_link_libraries(fost-urlhandler-smoke fost-urlhandler)
Expand Down
144 changes: 144 additions & 0 deletions Cpp/fost-urlhandler/fsigma.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
Copyright 2016-2020 Red Anchor Trading Co. Ltd.

Distributed under the Boost Software License, Version 1.0.
See <http://www.boost.org/LICENSE_1_0.txt>
*/


#include <fost/fsigma.hpp>
#include <fost/push_back>


/**
## fsigma::frame
*/


fsigma::frame::frame(frame *f) : parent(f) {}


fostlib::json fsigma::frame::argument(
const fostlib::string &name,
fostlib::json::const_iterator &pos,
fostlib::json::const_iterator end) {
if (pos == end) {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "Argument not found", name);
} else {
auto result = *pos;
++pos;
return result;
}
}


fostlib::string fsigma::frame::resolve_string(const fostlib::json &code) {
if (code.isatom()) {
return fostlib::coerce<fostlib::string>(code);
} else if (code.isarray()) {
frame stack(this);
return resolve_string(call(stack, code));
} else {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "Can't resolve to a string", code);
}
}


int64_t fsigma::frame::resolve_int(const fostlib::json &code) {
if (code.isatom()) {
return fostlib::coerce<int64_t>(code);
} else {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "Can't resolve to an int", code);
}
}


fostlib::json fsigma::frame::resolve(const fostlib::json &code) {
/// S-expressions are always a JSON array. Everything else is a literal
/// and doesn't need to be resolved.
if (code.isarray()) {
frame stack(this);
return call(stack, code);
} else {
return code;
}
}


/// This is dynamic rather than lexical scoping, which is.... not great
fostlib::json fsigma::frame::lookup(const fostlib::string &name) const {
auto fnp = symbols.find(name);
if (fnp == symbols.end()) {
if (parent) {
return parent->lookup(name);
} else {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "Sumbol not found", name);
}
} else {
return fnp->second;
}
}


/// This is dynamic rather than lexical scoping, which is.... not great
fsigma::frame::builtin
fsigma::frame::lookup_function(const fostlib::string &name) const {
auto fnp = native.find(name);
if (fnp == native.end()) {
if (parent) {
return parent->lookup_function(name);
} else {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "Function not found", name);
}
} else {
return fnp->second;
}
}


/**
## fsigma::call
*/


fostlib::json fsigma::call(frame &stack, const fostlib::json &sexpr) {
if (not sexpr.isarray()) {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "Script isn't an array/s-expression",
sexpr);
} else if (sexpr.size() == 0) {
throw fostlib::exceptions::not_implemented(
__PRETTY_FUNCTION__, "The script was empty");
} else {
return call(
stack, stack.resolve_string(*sexpr.begin()), ++sexpr.begin(),
sexpr.end());
}
}


fostlib::json fsigma::call(
frame &stack,
const fostlib::string &name,
fostlib::json::const_iterator begin,
fostlib::json::const_iterator end) {
try {
frame::builtin function(stack.lookup_function(name));
return function(stack, begin, end);
} catch (fostlib::exceptions::exception &e) {
// Built a stack frame
fostlib::json sf;
fostlib::push_back(sf, name);
for (auto iter = begin; iter != end; ++iter) {
fostlib::push_back(sf, *iter);
}
// Add to the back trace
fostlib::push_back(e.data(), "fg", "backtrace", sf);
throw;
}
}
71 changes: 71 additions & 0 deletions Cpp/fost-urlhandler/matcher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
Copyright 2016-2020 Red Anchor Trading Co. Ltd.

Distributed under the Boost Software License, Version 1.0.
See <http://www.boost.org/LICENSE_1_0.txt>
*/


#include <fost/matcher.hpp>
#include <fost/urlhandler>

#include <fost/log>
#include <fost/string>



namespace {
fostlib::nullable<fostlib::match>
check(const fostlib::json &conf, const fostlib::split_type &parts, fostlib::match_predicate mp) {
if (not conf.has_key("path")) return fostlib::null;
const fostlib::json &o = conf["path"];
if (o.size() == parts.size()) {
fostlib::match m{conf};
for (std::size_t index{0}; index < o.size(); ++index) {
auto s = fostlib::coerce<fostlib::string>(o[index]);
if (s.starts_with("/")) {
if (parts[index]
!= (static_cast<f5::u8view>(s)).substr(1)) {
return fostlib::null;
}
} else {
const auto n = fostlib::coerce<unsigned int>(o[index]);
if (n > 0) {
// We have a numeric match so this path part needs to
// be exposed as argument number n. This entails
// placing it at position (n-1) in the arguments array
if (n > m.arguments.size()) { m.arguments.resize(n); }
m.arguments[n - 1] = fostlib::coerce<fostlib::string>(
fostlib::url::filepath_string(parts[index]));
} else {
throw fostlib::exceptions::not_implemented(
__FUNCTION__,
"Path arguments numbers cannot be zero");
}
}
}
if (not mp || mp(m)) {
return m;
}
}
fostlib::log::debug(fostlib::c_fost_web_urlhandler)(
"", "Path size mismatch")("o", "size", o.size())(
"parts", "size", parts.size());
return fostlib::null;
}
}


fostlib::nullable<fostlib::match> fostlib::matcher(
fostlib::json const &configuration, fostlib::string const &path) {
auto parts = fostlib::split(path, "/");
if (configuration.isobject()) {
return check(configuration, parts);
} else if (configuration.isarray()) {
for (auto conf : configuration) {
auto m = check(conf, parts);
if (m) return m;
}
}
return fostlib::null;
}
72 changes: 72 additions & 0 deletions Cpp/fost-urlhandler/matcher.tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
Copyright 2016-2019 Red Anchor Trading Co. Ltd.

Distributed under the Boost Software License, Version 1.0.
See <http://www.boost.org/LICENSE_1_0.txt>
*/


#include <fost/matcher.hpp>
#include <fost/push_back>
#include <fost/test>


FSL_TEST_SUITE(matcher);


FSL_TEST_FUNCTION(empty) {
FSL_CHECK(not fostlib::matcher(fostlib::json(), ""));
}


FSL_TEST_FUNCTION(args_mismatch_1) {
fostlib::json config;
fostlib::push_back(config, "path", 1);
auto m = fostlib::matcher(config, "");
FSL_CHECK(not m);
}


FSL_TEST_FUNCTION(args_match_1) {
fostlib::json config;
fostlib::push_back(config, "path", 1);
auto m = fostlib::matcher(config, "first");
FSL_CHECK(m);
FSL_CHECK_EQ(m.value().arguments.size(), 1u);
FSL_CHECK_EQ(m.value().arguments[0], "first");
}


FSL_TEST_FUNCTION(args_match_2) {
fostlib::json config;
fostlib::push_back(config, "path", 2);
fostlib::push_back(config, "path", 1);
auto m = fostlib::matcher(config, "second/first/");
FSL_CHECK(m);
FSL_CHECK_EQ(m.value().arguments.size(), 2u);
FSL_CHECK_EQ(m.value().arguments[0], "first");
FSL_CHECK_EQ(m.value().arguments[1], "second");
}


FSL_TEST_FUNCTION(args_with_fixed_strings_match_1) {
fostlib::json config;
fostlib::push_back(config, "path", 1);
fostlib::push_back(config, "path", "/foo");
fostlib::push_back(config, "path", 2);
auto m = fostlib::matcher(config, "first/foo/second/");
FSL_CHECK(m);
FSL_CHECK_EQ(m.value().arguments.size(), 2u);
FSL_CHECK_EQ(m.value().arguments[0], "first");
FSL_CHECK_EQ(m.value().arguments[1], "second");
}


FSL_TEST_FUNCTION(args_with_fixed_strings_mismatch_1) {
fostlib::json config;
fostlib::push_back(config, "path", 1);
fostlib::push_back(config, "path", "/foo");
fostlib::push_back(config, "path", 2);
auto m = fostlib::matcher(config, "first/bar/second/");
FSL_CHECK(not m);
}
Loading