]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_lua_request.cc
2e971c329c8752c097a63e7e175efee7884ce539
[ceph.git] / ceph / src / rgw / rgw_lua_request.cc
1 #include <sstream>
2 #include <stdexcept>
3 #include <lua.hpp>
4 #include "common/dout.h"
5 #include "services/svc_zone.h"
6 #include "rgw_lua_utils.h"
7 #include "rgw_lua.h"
8 #include "rgw_common.h"
9 #include "rgw_log.h"
10 #include "rgw_process.h"
11 #include "rgw_zone.h"
12 #include "rgw_acl.h"
13 #include "rgw_sal_rados.h"
14
15 #define dout_subsys ceph_subsys_rgw
16
17 namespace rgw::lua::request {
18
19 // closure that perform ops log action
20 // e.g.
21 // Request.Log()
22 //
23 constexpr const char* RequestLogAction{"Log"};
24
25 int RequestLog(lua_State* L)
26 {
27 const auto rest = reinterpret_cast<RGWREST*>(lua_touserdata(L, lua_upvalueindex(1)));
28 const auto olog = reinterpret_cast<OpsLogSink*>(lua_touserdata(L, lua_upvalueindex(2)));
29 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(3)));
30 const std::string op_name(reinterpret_cast<const char*>(lua_touserdata(L, lua_upvalueindex(4))));
31 if (s) {
32 const auto rc = rgw_log_op(rest, s, op_name, olog);
33 lua_pushinteger(L, rc);
34 } else {
35 ldpp_dout(s, 1) << "Lua ERROR: missing request state, cannot use ops log" << dendl;
36 lua_pushinteger(L, -EINVAL);
37 }
38
39 return ONE_RETURNVAL;
40 }
41
42 struct ResponseMetaTable : public EmptyMetaTable {
43 static std::string TableName() {return "Response";}
44 static std::string Name() {return TableName() + "Meta";}
45
46 static int IndexClosure(lua_State* L) {
47 const auto err = reinterpret_cast<const rgw_err*>(lua_touserdata(L, lua_upvalueindex(1)));
48
49 const char* index = luaL_checkstring(L, 2);
50
51 if (strcasecmp(index, "HTTPStatusCode") == 0) {
52 lua_pushinteger(L, err->http_ret);
53 } else if (strcasecmp(index, "RGWCode") == 0) {
54 lua_pushinteger(L, err->ret);
55 } else if (strcasecmp(index, "HTTPStatus") == 0) {
56 pushstring(L, err->err_code);
57 } else if (strcasecmp(index, "Message") == 0) {
58 pushstring(L, err->message);
59 } else {
60 return error_unknown_field(L, index, TableName());
61 }
62 return ONE_RETURNVAL;
63 }
64
65 static int NewIndexClosure(lua_State* L) {
66 auto err = reinterpret_cast<rgw_err*>(lua_touserdata(L, lua_upvalueindex(1)));
67
68 const char* index = luaL_checkstring(L, 2);
69
70 if (strcasecmp(index, "HTTPStatusCode") == 0) {
71 err->http_ret = luaL_checkinteger(L, 3);
72 } else if (strcasecmp(index, "RGWCode") == 0) {
73 err->ret = luaL_checkinteger(L, 3);
74 } else if (strcasecmp(index, "HTTPStatus") == 0) {
75 err->err_code.assign(luaL_checkstring(L, 3));
76 } else if (strcasecmp(index, "Message") == 0) {
77 err->message.assign(luaL_checkstring(L, 3));
78 } else {
79 return error_unknown_field(L, index, TableName());
80 }
81 return NO_RETURNVAL;
82 }
83 };
84
85 struct QuotaMetaTable : public EmptyMetaTable {
86 static std::string TableName() {return "Quota";}
87 static std::string Name() {return TableName() + "Meta";}
88
89 static int IndexClosure(lua_State* L) {
90 const auto info = reinterpret_cast<RGWQuotaInfo*>(lua_touserdata(L, lua_upvalueindex(1)));
91
92 const char* index = luaL_checkstring(L, 2);
93
94 if (strcasecmp(index, "MaxSize") == 0) {
95 lua_pushinteger(L, info->max_size);
96 } else if (strcasecmp(index, "MaxObjects") == 0) {
97 lua_pushinteger(L, info->max_objects);
98 } else if (strcasecmp(index, "Enabled") == 0) {
99 lua_pushboolean(L, info->enabled);
100 } else if (strcasecmp(index, "Rounded") == 0) {
101 lua_pushboolean(L, !info->check_on_raw);
102 } else {
103 return error_unknown_field(L, index, TableName());
104 }
105 return ONE_RETURNVAL;
106 }
107 };
108
109 struct PlacementRuleMetaTable : public EmptyMetaTable {
110 static std::string TableName() {return "PlacementRule";}
111 static std::string Name() {return TableName() + "Meta";}
112
113 static int IndexClosure(lua_State* L) {
114 const auto rule = reinterpret_cast<rgw_placement_rule*>(lua_touserdata(L, lua_upvalueindex(1)));
115
116 const char* index = luaL_checkstring(L, 2);
117
118 if (strcasecmp(index, "Name") == 0) {
119 pushstring(L, rule->name);
120 } else if (strcasecmp(index, "StorageClass") == 0) {
121 pushstring(L, rule->storage_class);
122 } else {
123 return error_unknown_field(L, index, TableName());
124 }
125 return ONE_RETURNVAL;
126 }
127 };
128
129 struct UserMetaTable : public EmptyMetaTable {
130 static std::string TableName() {return "User";}
131 static std::string Name() {return TableName() + "Meta";}
132
133 static int IndexClosure(lua_State* L) {
134 const auto user = reinterpret_cast<const rgw_user*>(lua_touserdata(L, lua_upvalueindex(1)));
135
136 const char* index = luaL_checkstring(L, 2);
137
138 if (strcasecmp(index, "Tenant") == 0) {
139 pushstring(L, user->tenant);
140 } else if (strcasecmp(index, "Id") == 0) {
141 pushstring(L, user->id);
142 } else {
143 return error_unknown_field(L, index, TableName());
144 }
145 return ONE_RETURNVAL;
146 }
147 };
148
149 struct OwnerMetaTable : public EmptyMetaTable {
150 static std::string TableName() {return "Owner";}
151 static std::string Name() {return TableName() + "Meta";}
152
153 static int IndexClosure(lua_State* L) {
154 const auto owner = reinterpret_cast<ACLOwner*>(lua_touserdata(L, lua_upvalueindex(1)));
155
156 const char* index = luaL_checkstring(L, 2);
157
158 if (strcasecmp(index, "DisplayName") == 0) {
159 pushstring(L, owner->get_display_name());
160 } else if (strcasecmp(index, "User") == 0) {
161 create_metatable<UserMetaTable>(L, false, &(owner->get_id()));
162 } else {
163 return error_unknown_field(L, index, TableName());
164 }
165 return ONE_RETURNVAL;
166 }
167 };
168
169 struct BucketMetaTable : public EmptyMetaTable {
170 static std::string TableName() {return "Bucket";}
171 static std::string Name() {return TableName() + "Meta";}
172
173 using Type = rgw::sal::Bucket;
174
175 static int IndexClosure(lua_State* L) {
176 const auto bucket = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
177
178 const char* index = luaL_checkstring(L, 2);
179
180 if (strcasecmp(index, "Tenant") == 0) {
181 pushstring(L, bucket->get_tenant());
182 } else if (strcasecmp(index, "Name") == 0) {
183 pushstring(L, bucket->get_name());
184 } else if (strcasecmp(index, "Marker") == 0) {
185 pushstring(L, bucket->get_marker());
186 } else if (strcasecmp(index, "Id") == 0) {
187 pushstring(L, bucket->get_bucket_id());
188 } else if (strcasecmp(index, "Count") == 0) {
189 lua_pushinteger(L, bucket->get_count());
190 } else if (strcasecmp(index, "Size") == 0) {
191 lua_pushinteger(L, bucket->get_size());
192 } else if (strcasecmp(index, "ZoneGroupId") == 0) {
193 pushstring(L, bucket->get_info().zonegroup);
194 } else if (strcasecmp(index, "CreationTime") == 0) {
195 pushtime(L, bucket->get_creation_time());
196 } else if (strcasecmp(index, "MTime") == 0) {
197 pushtime(L, bucket->get_modification_time());
198 } else if (strcasecmp(index, "Quota") == 0) {
199 create_metatable<QuotaMetaTable>(L, false, &(bucket->get_info().quota));
200 } else if (strcasecmp(index, "PlacementRule") == 0) {
201 create_metatable<PlacementRuleMetaTable>(L, false, &(bucket->get_info().placement_rule));
202 } else if (strcasecmp(index, "User") == 0) {
203 create_metatable<UserMetaTable>(L, false, &(bucket->get_info().owner));
204 } else {
205 return error_unknown_field(L, index, TableName());
206 }
207 return ONE_RETURNVAL;
208 }
209 };
210
211 struct ObjectMetaTable : public EmptyMetaTable {
212 static const std::string TableName() {return "Object";}
213 static std::string Name() {return TableName() + "Meta";}
214
215 using Type = rgw::sal::Object;
216
217 static int IndexClosure(lua_State* L) {
218 const auto obj = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(1)));
219
220 const char* index = luaL_checkstring(L, 2);
221
222 if (strcasecmp(index, "Name") == 0) {
223 pushstring(L, obj->get_name());
224 } else if (strcasecmp(index, "Instance") == 0) {
225 pushstring(L, obj->get_instance());
226 } else if (strcasecmp(index, "Id") == 0) {
227 pushstring(L, obj->get_oid());
228 } else if (strcasecmp(index, "Size") == 0) {
229 lua_pushinteger(L, obj->get_obj_size());
230 } else if (strcasecmp(index, "MTime") == 0) {
231 pushtime(L, obj->get_mtime());
232 } else {
233 return error_unknown_field(L, index, TableName());
234 }
235 return ONE_RETURNVAL;
236 }
237 };
238
239 typedef int MetaTableClosure(lua_State* L);
240
241 template<typename MapType>
242 int StringMapWriteableNewIndex(lua_State* L) {
243 const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
244
245 const char* index = luaL_checkstring(L, 2);
246 const char* value = luaL_checkstring(L, 3);
247 map->insert_or_assign(index, value);
248 return NO_RETURNVAL;
249 }
250
251 template<typename MapType=std::map<std::string, std::string>,
252 MetaTableClosure NewIndex=EmptyMetaTable::NewIndexClosure>
253 struct StringMapMetaTable : public EmptyMetaTable {
254
255 static std::string TableName() {return "StringMap";}
256 static std::string Name() {return TableName() + "Meta";}
257
258 static int IndexClosure(lua_State* L) {
259 const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
260
261 const char* index = luaL_checkstring(L, 2);
262
263 const auto it = map->find(std::string(index));
264 if (it == map->end()) {
265 lua_pushnil(L);
266 } else {
267 pushstring(L, it->second);
268 }
269 return ONE_RETURNVAL;
270 }
271
272 static int NewIndexClosure(lua_State* L) {
273 return NewIndex(L);
274 }
275
276 static int PairsClosure(lua_State* L) {
277 auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
278 ceph_assert(map);
279 lua_pushlightuserdata(L, map);
280 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
281 lua_pushnil(L); // indicate this is the first call
282 // return stateless_iter, nil
283
284 return TWO_RETURNVALS;
285 }
286
287 static int stateless_iter(lua_State* L) {
288 // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
289 auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
290 typename MapType::const_iterator next_it;
291 if (lua_isnil(L, -1)) {
292 next_it = map->begin();
293 } else {
294 const char* index = luaL_checkstring(L, 2);
295 const auto it = map->find(std::string(index));
296 ceph_assert(it != map->end());
297 next_it = std::next(it);
298 }
299
300 if (next_it == map->end()) {
301 // index of the last element was provided
302 lua_pushnil(L);
303 lua_pushnil(L);
304 // return nil, nil
305 } else {
306 pushstring(L, next_it->first);
307 pushstring(L, next_it->second);
308 // return key, value
309 }
310
311 return TWO_RETURNVALS;
312 }
313
314 static int LenClosure(lua_State* L) {
315 const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
316
317 lua_pushinteger(L, map->size());
318
319 return ONE_RETURNVAL;
320 }
321 };
322
323 struct GrantMetaTable : public EmptyMetaTable {
324 static std::string TableName() {return "Grant";}
325 static std::string Name() {return TableName() + "Meta";}
326
327 static int IndexClosure(lua_State* L) {
328 const auto grant = reinterpret_cast<ACLGrant*>(lua_touserdata(L, lua_upvalueindex(1)));
329
330 const char* index = luaL_checkstring(L, 2);
331
332 if (strcasecmp(index, "Type") == 0) {
333 lua_pushinteger(L, grant->get_type().get_type());
334 } else if (strcasecmp(index, "User") == 0) {
335 const auto id_ptr = grant->get_id();
336 if (id_ptr) {
337 create_metatable<UserMetaTable>(L, false, const_cast<rgw_user*>(id_ptr));
338 } else {
339 lua_pushnil(L);
340 }
341 } else if (strcasecmp(index, "Permission") == 0) {
342 lua_pushinteger(L, grant->get_permission().get_permissions());
343 } else if (strcasecmp(index, "GroupType") == 0) {
344 lua_pushinteger(L, grant->get_group());
345 } else if (strcasecmp(index, "Referer") == 0) {
346 pushstring(L, grant->get_referer());
347 } else {
348 return error_unknown_field(L, index, TableName());
349 }
350 return ONE_RETURNVAL;
351 }
352 };
353
354 struct GrantsMetaTable : public EmptyMetaTable {
355 static std::string TableName() {return "Grants";}
356 static std::string Name() {return TableName() + "Meta";}
357
358 static int IndexClosure(lua_State* L) {
359 const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
360
361 const char* index = luaL_checkstring(L, 2);
362
363 const auto it = map->find(std::string(index));
364 if (it == map->end()) {
365 lua_pushnil(L);
366 } else {
367 create_metatable<GrantMetaTable>(L, false, &(it->second));
368 }
369 return ONE_RETURNVAL;
370 }
371
372 static int PairsClosure(lua_State* L) {
373 auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
374 ceph_assert(map);
375 lua_pushlightuserdata(L, map);
376 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
377 lua_pushnil(L); // indicate this is the first call
378 // return stateless_iter, nil
379
380 return TWO_RETURNVALS;
381 }
382
383 static int stateless_iter(lua_State* L) {
384 // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
385 auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
386 ACLGrantMap::iterator next_it;
387 if (lua_isnil(L, -1)) {
388 next_it = map->begin();
389 } else {
390 const char* index = luaL_checkstring(L, 2);
391 const auto it = map->find(std::string(index));
392 ceph_assert(it != map->end());
393 next_it = std::next(it);
394 }
395
396 if (next_it == map->end()) {
397 // index of the last element was provided
398 lua_pushnil(L);
399 lua_pushnil(L);
400 return TWO_RETURNVALS;
401 // return nil, nil
402 }
403
404 while (next_it->first.empty()) {
405 // this is a multimap and the next element does not have a unique key
406 ++next_it;
407 if (next_it == map->end()) {
408 // index of the last element was provided
409 lua_pushnil(L);
410 lua_pushnil(L);
411 return TWO_RETURNVALS;
412 // return nil, nil
413 }
414 }
415
416 pushstring(L, next_it->first);
417 create_metatable<GrantMetaTable>(L, false, &(next_it->second));
418 // return key, value
419
420 return TWO_RETURNVALS;
421 }
422
423 static int LenClosure(lua_State* L) {
424 const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
425
426 lua_pushinteger(L, map->size());
427
428 return ONE_RETURNVAL;
429 }
430 };
431
432 struct ACLMetaTable : public EmptyMetaTable {
433 static std::string TableName() {return "ACL";}
434 static std::string Name() {return TableName() + "Meta";}
435
436 using Type = RGWAccessControlPolicy;
437
438 static int IndexClosure(lua_State* L) {
439 const auto acl = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
440
441 const char* index = luaL_checkstring(L, 2);
442
443 if (strcasecmp(index, "Owner") == 0) {
444 create_metatable<OwnerMetaTable>(L, false, &(acl->get_owner()));
445 } else if (strcasecmp(index, "Grants") == 0) {
446 create_metatable<GrantsMetaTable>(L, false, &(acl->get_acl().get_grant_map()));
447 } else {
448 return error_unknown_field(L, index, TableName());
449 }
450 return ONE_RETURNVAL;
451 }
452 };
453
454 struct StatementsMetaTable : public EmptyMetaTable {
455 static std::string TableName() {return "Statements";}
456 static std::string Name() {return TableName() + "Meta";}
457
458 using Type = std::vector<rgw::IAM::Statement>;
459
460 static std::string statement_to_string(const rgw::IAM::Statement& statement) {
461 std::stringstream ss;
462 ss << statement;
463 return ss.str();
464 }
465
466 static int IndexClosure(lua_State* L) {
467 const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
468
469 const auto index = luaL_checkinteger(L, 2);
470
471 if (index >= (int)statements->size() || index < 0) {
472 lua_pushnil(L);
473 } else {
474 // TODO: policy language could be interpreted to lua and executed as such
475 pushstring(L, statement_to_string((*statements)[index]));
476 }
477 return ONE_RETURNVAL;
478 }
479
480 static int PairsClosure(lua_State* L) {
481 auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
482 ceph_assert(statements);
483 lua_pushlightuserdata(L, statements);
484 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
485 lua_pushnil(L); // indicate this is the first call
486 // return stateless_iter, nil
487
488 return TWO_RETURNVALS;
489 }
490
491 static int stateless_iter(lua_State* L) {
492 auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
493 size_t next_it;
494 if (lua_isnil(L, -1)) {
495 next_it = 0;
496 } else {
497 const auto it = luaL_checkinteger(L, -1);
498 next_it = it+1;
499 }
500
501 if (next_it >= statements->size()) {
502 // index of the last element was provided
503 lua_pushnil(L);
504 lua_pushnil(L);
505 // return nil, nil
506 } else {
507 lua_pushinteger(L, next_it);
508 pushstring(L, statement_to_string((*statements)[next_it]));
509 // return key, value
510 }
511
512 return TWO_RETURNVALS;
513 }
514
515 static int LenClosure(lua_State* L) {
516 const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
517
518 lua_pushinteger(L, statements->size());
519
520 return ONE_RETURNVAL;
521 }
522 };
523
524 struct PolicyMetaTable : public EmptyMetaTable {
525 static std::string TableName() {return "Policy";}
526 static std::string Name() {return TableName() + "Meta";}
527
528 static int IndexClosure(lua_State* L) {
529 const auto policy = reinterpret_cast<rgw::IAM::Policy*>(lua_touserdata(L, lua_upvalueindex(1)));
530
531 const char* index = luaL_checkstring(L, 2);
532
533 if (strcasecmp(index, "Text") == 0) {
534 pushstring(L, policy->text);
535 } else if (strcasecmp(index, "Id") == 0) {
536 // TODO create pushstring for std::unique_ptr
537 if (!policy->id) {
538 lua_pushnil(L);
539 } else {
540 pushstring(L, policy->id.get());
541 }
542 } else if (strcasecmp(index, "Statements") == 0) {
543 create_metatable<StatementsMetaTable>(L, &(policy->statements));
544 } else {
545 return error_unknown_field(L, index, TableName());
546 }
547 return ONE_RETURNVAL;
548 }
549 };
550
551 struct PoliciesMetaTable : public EmptyMetaTable {
552 static std::string TableName() {return "Policies";}
553 static std::string Name() {return TableName() + "Meta";}
554
555 using Type = std::vector<rgw::IAM::Policy>;
556
557 static int IndexClosure(lua_State* L) {
558 const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
559
560 const auto index = luaL_checkinteger(L, 2);
561
562 if (index >= (int)policies->size() || index < 0) {
563 lua_pushnil(L);
564 } else {
565 create_metatable<PolicyMetaTable>(L, false, &((*policies)[index]));
566 }
567 return ONE_RETURNVAL;
568 }
569
570 static int PairsClosure(lua_State* L) {
571 auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
572 ceph_assert(policies);
573 lua_pushlightuserdata(L, policies);
574 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
575 lua_pushnil(L); // indicate this is the first call
576 // return stateless_iter, nil
577
578 return TWO_RETURNVALS;
579 }
580
581 static int stateless_iter(lua_State* L) {
582 auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
583 size_t next_it;
584 if (lua_isnil(L, -1)) {
585 next_it = 0;
586 } else {
587 ceph_assert(lua_isinteger(L, -1));
588 const auto it = luaL_checkinteger(L, -1);
589 next_it = it+1;
590 }
591
592 if (next_it >= policies->size()) {
593 // index of the last element was provided
594 lua_pushnil(L);
595 lua_pushnil(L);
596 // return nil, nil
597 } else {
598 lua_pushinteger(L, next_it);
599 create_metatable<PolicyMetaTable>(L, false, &((*policies)[next_it]));
600 // return key, value
601 }
602
603 return TWO_RETURNVALS;
604 }
605
606 static int LenClosure(lua_State* L) {
607 const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
608
609 lua_pushinteger(L, policies->size());
610
611 return ONE_RETURNVAL;
612 }
613 };
614
615 struct HTTPMetaTable : public EmptyMetaTable {
616 static std::string TableName() {return "HTTP";}
617 static std::string Name() {return TableName() + "Meta";}
618
619 static int IndexClosure(lua_State* L) {
620 const auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(1)));
621
622 const char* index = luaL_checkstring(L, 2);
623
624 if (strcasecmp(index, "Parameters") == 0) {
625 create_metatable<StringMapMetaTable<>>(L, false, &(info->args.get_params()));
626 } else if (strcasecmp(index, "Resources") == 0) {
627 // TODO: add non-const api to get resources
628 create_metatable<StringMapMetaTable<>>(L, false,
629 const_cast<std::map<std::string, std::string>*>(&(info->args.get_sub_resources())));
630 } else if (strcasecmp(index, "Metadata") == 0) {
631 create_metatable<StringMapMetaTable<meta_map_t, StringMapWriteableNewIndex<meta_map_t>>>(L, false, &(info->x_meta_map));
632 } else if (strcasecmp(index, "Host") == 0) {
633 pushstring(L, info->host);
634 } else if (strcasecmp(index, "Method") == 0) {
635 pushstring(L, info->method);
636 } else if (strcasecmp(index, "URI") == 0) {
637 pushstring(L, info->request_uri);
638 } else if (strcasecmp(index, "QueryString") == 0) {
639 pushstring(L, info->request_params);
640 } else if (strcasecmp(index, "Domain") == 0) {
641 pushstring(L, info->domain);
642 } else if (strcasecmp(index, "StorageClass") == 0) {
643 pushstring(L, info->storage_class);
644 } else {
645 return error_unknown_field(L, index, TableName());
646 }
647 return ONE_RETURNVAL;
648 }
649
650 static int NewIndexClosure(lua_State* L) {
651 auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(1)));
652
653 const char* index = luaL_checkstring(L, 2);
654
655 if (strcasecmp(index, "StorageClass") == 0) {
656 info->storage_class = luaL_checkstring(L, 3);
657 } else {
658 return error_unknown_field(L, index, TableName());
659 }
660 return NO_RETURNVAL;
661 }
662 };
663
664 struct CopyFromMetaTable : public EmptyMetaTable {
665 static std::string TableName() {return "CopyFrom";}
666 static std::string Name() {return TableName() + "Meta";}
667
668 static int IndexClosure(lua_State* L) {
669 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
670
671 const char* index = luaL_checkstring(L, 2);
672
673 if (strcasecmp(index, "Tenant") == 0) {
674 pushstring(L, s->src_tenant_name);
675 } else if (strcasecmp(index, "Bucket") == 0) {
676 pushstring(L, s->src_bucket_name);
677 } else if (strcasecmp(index, "Object") == 0) {
678 create_metatable<ObjectMetaTable>(L, false, s->src_object);
679 } else {
680 return error_unknown_field(L, index, TableName());
681 }
682 return ONE_RETURNVAL;
683 }
684 };
685
686 struct ZoneGroupMetaTable : public EmptyMetaTable {
687 static std::string TableName() {return "ZoneGroup";}
688 static std::string Name() {return TableName() + "Meta";}
689
690 static int IndexClosure(lua_State* L) {
691 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
692
693 const char* index = luaL_checkstring(L, 2);
694
695 if (strcasecmp(index, "Name") == 0) {
696 pushstring(L, s->zonegroup_name);
697 } else if (strcasecmp(index, "Endpoint") == 0) {
698 pushstring(L, s->zonegroup_endpoint);
699 } else {
700 return error_unknown_field(L, index, TableName());
701 }
702 return ONE_RETURNVAL;
703 }
704 };
705
706 struct RequestMetaTable : public EmptyMetaTable {
707 static std::string TableName() {return "Request";}
708 static std::string Name() {return TableName() + "Meta";}
709
710 // __index closure that expect req_state to be captured
711 static int IndexClosure(lua_State* L) {
712 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
713 const auto op_name = reinterpret_cast<const char*>(lua_touserdata(L, lua_upvalueindex(2)));
714
715 const char* index = luaL_checkstring(L, 2);
716
717 if (strcasecmp(index, "RGWOp") == 0) {
718 pushstring(L, op_name);
719 } else if (strcasecmp(index, "DecodedURI") == 0) {
720 pushstring(L, s->decoded_uri);
721 } else if (strcasecmp(index, "ContentLength") == 0) {
722 lua_pushinteger(L, s->content_length);
723 } else if (strcasecmp(index, "GenericAttributes") == 0) {
724 create_metatable<StringMapMetaTable<>>(L, false, &(s->generic_attrs));
725 } else if (strcasecmp(index, "Response") == 0) {
726 create_metatable<ResponseMetaTable>(L, false, &(s->err));
727 } else if (strcasecmp(index, "SwiftAccountName") == 0) {
728 if (s->dialect == "swift") {
729 pushstring(L, s->account_name);
730 } else {
731 lua_pushnil(L);
732 }
733 } else if (strcasecmp(index, "Bucket") == 0) {
734 create_metatable<BucketMetaTable>(L, false, s->bucket);
735 } else if (strcasecmp(index, "Object") == 0) {
736 create_metatable<ObjectMetaTable>(L, false, s->object);
737 } else if (strcasecmp(index, "CopyFrom") == 0) {
738 if (s->op_type == RGW_OP_COPY_OBJ) {
739 create_metatable<CopyFromMetaTable>(L, s);
740 } else {
741 lua_pushnil(L);
742 }
743 } else if (strcasecmp(index, "ObjectOwner") == 0) {
744 create_metatable<OwnerMetaTable>(L, false, &(s->owner));
745 } else if (strcasecmp(index, "ZoneGroup") == 0) {
746 create_metatable<ZoneGroupMetaTable>(L, false, s);
747 } else if (strcasecmp(index, "UserACL") == 0) {
748 create_metatable<ACLMetaTable>(L, false, s->user_acl);
749 } else if (strcasecmp(index, "BucketACL") == 0) {
750 create_metatable<ACLMetaTable>(L, false, s->bucket_acl);
751 } else if (strcasecmp(index, "ObjectACL") == 0) {
752 create_metatable<ACLMetaTable>(L, false, s->object_acl);
753 } else if (strcasecmp(index, "Environment") == 0) {
754 create_metatable<StringMapMetaTable<rgw::IAM::Environment>>(L, false, &(s->env));
755 } else if (strcasecmp(index, "Policy") == 0) {
756 // TODO: create a wrapper to std::optional
757 if (!s->iam_policy) {
758 lua_pushnil(L);
759 } else {
760 create_metatable<PolicyMetaTable>(L, false, s->iam_policy.get_ptr());
761 }
762 } else if (strcasecmp(index, "UserPolicies") == 0) {
763 create_metatable<PoliciesMetaTable>(L, false, &(s->iam_user_policies));
764 } else if (strcasecmp(index, "RGWId") == 0) {
765 pushstring(L, s->host_id);
766 } else if (strcasecmp(index, "HTTP") == 0) {
767 create_metatable<HTTPMetaTable>(L, false, &(s->info));
768 } else if (strcasecmp(index, "Time") == 0) {
769 pushtime(L, s->time);
770 } else if (strcasecmp(index, "Dialect") == 0) {
771 pushstring(L, s->dialect);
772 } else if (strcasecmp(index, "Id") == 0) {
773 pushstring(L, s->req_id);
774 } else if (strcasecmp(index, "TransactionId") == 0) {
775 pushstring(L, s->trans_id);
776 } else if (strcasecmp(index, "Tags") == 0) {
777 create_metatable<StringMapMetaTable<RGWObjTags::tag_map_t>>(L, false, &(s->tagset.get_tags()));
778 } else if (strcasecmp(index, "User") == 0) {
779 if (!s->user) {
780 lua_pushnil(L);
781 } else {
782 create_metatable<UserMetaTable>(L, false, const_cast<rgw_user*>(&(s->user->get_id())));
783 }
784 } else {
785 return error_unknown_field(L, index, TableName());
786 }
787 return ONE_RETURNVAL;
788 }
789 };
790
791 int execute(
792 rgw::sal::Store* store,
793 RGWREST* rest,
794 OpsLogSink* olog,
795 req_state* s,
796 const char* op_name,
797 const std::string& script)
798
799 {
800 auto L = luaL_newstate();
801 lua_state_guard lguard(L);
802
803 open_standard_libs(L);
804 set_package_path(L, store ?
805 store->get_luarocks_path() :
806 "");
807
808 create_debug_action(L, s->cct);
809
810 create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
811
812 // add the ops log action
813 lua_getglobal(L, RequestMetaTable::TableName().c_str());
814 ceph_assert(lua_istable(L, -1));
815 pushstring(L, RequestLogAction);
816 lua_pushlightuserdata(L, rest);
817 lua_pushlightuserdata(L, olog);
818 lua_pushlightuserdata(L, s);
819 lua_pushlightuserdata(L, const_cast<char*>(op_name));
820 lua_pushcclosure(L, RequestLog, FOUR_UPVALS);
821 lua_rawset(L, -3);
822
823 try {
824 // execute the lua script
825 if (luaL_dostring(L, script.c_str()) != LUA_OK) {
826 const std::string err(lua_tostring(L, -1));
827 ldpp_dout(s, 1) << "Lua ERROR: " << err << dendl;
828 return -1;
829 }
830 } catch (const std::runtime_error& e) {
831 ldpp_dout(s, 1) << "Lua ERROR: " << e.what() << dendl;
832 return -1;
833 }
834
835 return 0;
836 }
837
838 }