+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
| ``Request.HTTP.Resources`` | table | string to string resource map | yes | no | no |
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
-| ``Request.HTTP.Metadata`` | table | string to string metadata map | yes | no | no |
+| ``Request.HTTP.Metadata`` | table | string to string metadata map | yes | yes | no |
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
| ``Request.HTTP.Host`` | string | host name | no | no | no |
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
- Use of operations log only in case of errors:
.. code-block:: lua
-
if Request.Response.HTTPStatusCode ~= 200 then
RGWDebugLog("request is bad, use ops log")
Request.Response.Message = "<Message> something bad happened :-( </Message>"
end
+- Add metadata to objects that was not originally sent by the client:
+
+In the `preRequest` context we should add:
+
+.. code-block:: lua
+
+ if Request.RGWOp == 'put_obj' then
+ Request.HTTP.Metadata["x-amz-meta-mydata"] = "my value"
+ end
+
+In the `postRequest` context we look at the metadata:
+
+.. code-block:: lua
+
+ RGWDebugLog("number of metadata entries is: " .. #Request.HTTP.Metadata)
+ for k, v in pairs(Request.HTTP.Metadata) do
+ RGWDebugLog("key=" .. k .. ", " .. "value=" .. v)
+ end
+
} else {
throw_unknown_field(index, TableName());
}
- return ONE_RETURNVAL;
+ return NO_RETURNVAL;
}
};
}
};
-template<typename MapType=std::map<std::string, std::string>>
+typedef int MetaTableClosure(lua_State* L);
+
+template<typename MapType>
+int StringMapWriteableNewIndex(lua_State* L) {
+ const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
+
+ ceph_assert(lua_isstring(L, -1));
+ ceph_assert(lua_isstring(L, -2));
+ const char* value = lua_tostring(L, -1);
+ const char* index = lua_tostring(L, -2);
+ map->insert_or_assign(index, value);
+ return NO_RETURNVAL;
+}
+
+template<typename MapType=std::map<std::string, std::string>,
+ MetaTableClosure NewIndex=EmptyMetaTable::NewIndexClosure>
struct StringMapMetaTable : public EmptyMetaTable {
static std::string TableName() {return "StringMap";}
return ONE_RETURNVAL;
}
+ static int NewIndexClosure(lua_State* L) {
+ return NewIndex(L);
+ }
+
static int PairsClosure(lua_State* L) {
auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
ceph_assert(map);
create_metatable<StringMapMetaTable<>>(L, false,
const_cast<std::map<std::string, std::string>*>(&(info->args.get_sub_resources())));
} else if (strcasecmp(index, "Metadata") == 0) {
- create_metatable<StringMapMetaTable<meta_map_t>>(L, false, &(info->x_meta_map));
+ create_metatable<StringMapMetaTable<meta_map_t, StringMapWriteableNewIndex<meta_map_t>>>(L, false, &(info->x_meta_map));
} else if (strcasecmp(index, "Host") == 0) {
pushstring(L, info->host);
} else if (strcasecmp(index, "Method") == 0) {
constexpr auto FOUR_UPVALS = 4;
constexpr auto FIVE_UPVALS = 5;
+constexpr auto NO_RETURNVAL = 0;
constexpr auto ONE_RETURNVAL = 1;
constexpr auto TWO_RETURNVALS = 2;
constexpr auto THREE_RETURNVALS = 3;
// to change, overload this function in the derived
static int NewIndexClosure(lua_State* L) {
throw std::runtime_error("trying to write to readonly field");
- return 1;
+ return NO_RETURNVAL;
}
// by default nothing is iterable
// to change, overload this function in the derived
static int PairsClosure(lua_State* L) {
throw std::runtime_error("trying to iterate over non-iterable field");
- return 1;
+ return ONE_RETURNVAL;
}
// by default nothing is iterable
// to change, overload this function in the derived
static int LenClosure(lua_State* L) {
throw std::runtime_error("trying to get length of non-iterable field");
- return 1;
+ return ONE_RETURNVAL;
}
static void throw_unknown_field(const std::string& index, const std::string& table) {
ASSERT_EQ(rc, 0);
}
+TEST(TestRGWLua, TagsNotWriteable)
+{
+ const std::string script = R"(
+ Request.Tags["hello"] = "goodbye"
+ )";
+
+ DEFINE_REQ_STATE;
+ s.tagset.add_tag("hello", "world");
+
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ ASSERT_NE(rc, 0);
+}
+
+TEST(TestRGWLua, Metadata)
+{
+ const std::string script = R"(
+ print("number of metadata entries is: " .. #Request.HTTP.Metadata)
+ for k, v in pairs(Request.HTTP.Metadata) do
+ print("key=" .. k .. ", " .. "value=" .. v)
+ end
+ print("value of 'hello' is:")
+ print(Request.HTTP.Metadata["hello"])
+ print("value of 'kaboom' is:")
+ print(Request.HTTP.Metadata["kaboom"])
+ Request.HTTP.Metadata["hello"] = "goodbye"
+ Request.HTTP.Metadata["kaboom"] = "boom"
+ print("new number of metadata entries is: " .. #Request.HTTP.Metadata)
+ print("new value of 'hello' is:")
+ print(Request.HTTP.Metadata["hello"])
+ print("new value of 'kaboom' is:")
+ print(Request.HTTP.Metadata["kaboom"])
+ )";
+
+ DEFINE_REQ_STATE;
+ s.info.x_meta_map["hello"] = "world";
+ s.info.x_meta_map["foo"] = "bar";
+ s.info.x_meta_map["ka"] = "boom";
+
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ ASSERT_EQ(rc, 0);
+}
+
TEST(TestRGWLua, Acl)
{
const std::string script = R"(