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