Skip to content

Commit

Permalink
proxy: inspector flagis
Browse files Browse the repository at this point in the history
`{ t = "flagis", flag = "L", str = "foo" }`

returns `exists, match` booleans if the flag exists and if it matches.
  • Loading branch information
dormando committed Aug 5, 2024
1 parent 320a802 commit 229a5dc
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 41 deletions.
172 changes: 132 additions & 40 deletions proxy_inspector.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum mcp_ins_steptype {
mcp_ins_step_hasflag,
mcp_ins_step_flagtoken,
mcp_ins_step_flagint,
mcp_ins_step_flagis,
};

// START STEP STRUCTS
Expand All @@ -24,22 +25,33 @@ struct mcp_ins_sepkey {
int mapref;
};

struct mcp_ins_keybegin {
struct mcp_ins_string {
unsigned int str; // arena offset for match string.
unsigned int len;
};

struct mcp_ins_flag {
char f;
uint64_t bit; // flag converted for bitmask test
char f;
};

// TODO: the pattern of all these accessors looks like just flattening the
// possibilities direclty into mcp_ins_step might be best. can also align
// things like the chars to compact the struct better.
struct mcp_ins_flagstr {
unsigned int str;
unsigned int len;
uint64_t bit; // flag bit
char f;
};

struct mcp_ins_step {
enum mcp_ins_steptype type;
union {
struct mcp_ins_sepkey sepkey;
struct mcp_ins_keybegin keybegin;
struct mcp_ins_string string;
struct mcp_ins_flag flag;
struct mcp_ins_flagstr flagstr;
} c;
};

Expand Down Expand Up @@ -93,6 +105,41 @@ static int mcp_inspector_flag_i_g(lua_State *L, int tidx, int sc, struct mcp_ins
return 0;
}

static int mcp_inspector_string_c_g(lua_State *L, int tidx) {
size_t len = 0;

if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
lua_tolstring(L, -1, &len);
if (len < 1) {
proxy_lua_ferror(L, "inspector step %d: 'str' must have nonzero length", tidx);
}
} else {
proxy_lua_ferror(L, "inspector step %d: must provide 'str' argument", tidx);
}
lua_pop(L, 1); // val or nil

return len;
}

static int mcp_inspector_string_i_g(lua_State *L, int tidx, int sc, struct mcp_inspector *ins) {
struct mcp_ins_step *s = &ins->steps[sc];
struct mcp_ins_string *c = &s->c.string;
size_t len = 0;

// store our match string in the arena space that we reserved before.
if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
const char *str = lua_tolstring(L, -1, &len);
c->str = ins->aused;
c->len = len;
char *a = ins->arena + ins->aused;
memcpy(a, str, len);
ins->aused += len;
}
lua_pop(L, 1); // val or nil

return len;
}

// END COMMMON ARG HANDLERS

// TODO:
Expand Down Expand Up @@ -207,44 +254,9 @@ static int mcp_inspector_sepkey_r(lua_State *L, struct mcp_inspector *ins, struc
return 1;
}

static int mcp_inspector_keybegin_c(lua_State *L, int tidx) {
size_t len = 0;

if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
lua_tolstring(L, -1, &len);
if (len < 1) {
proxy_lua_ferror(L, "inspector step %d: 'str' must have nonzero length", tidx);
}
} else {
proxy_lua_ferror(L, "inspector step %d: must provide 'str' argument", tidx);
}
lua_pop(L, 1); // val or nil

return len;
}

static int mcp_inspector_keybegin_i(lua_State *L, int tidx, int sc, struct mcp_inspector *ins) {
struct mcp_ins_step *s = &ins->steps[sc];
struct mcp_ins_keybegin *c = &s->c.keybegin;
size_t len = 0;

// store our match string in the arena space that we reserved before.
if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
const char *str = lua_tolstring(L, -1, &len);
c->str = ins->aused;
c->len = len;
char *a = ins->arena + ins->aused;
memcpy(a, str, len);
ins->aused += len;
}
lua_pop(L, 1); // val or nil

return len;
}

static int mcp_inspector_keybegin_r(lua_State *L, struct mcp_inspector *ins, struct mcp_ins_step *s, void *arg) {
mcp_request_t *rq = arg;
struct mcp_ins_keybegin *c = &s->c.keybegin;
struct mcp_ins_string *c = &s->c.string;

const char *key = MCP_PARSER_KEY(rq->pr);
int klen = rq->pr.klen;
Expand Down Expand Up @@ -367,6 +379,81 @@ static int mcp_inspector_flagint_r(lua_State *L, struct mcp_inspector *ins, stru
return 2;
}

static int mcp_inspector_flagstr_c(lua_State *L, int tidx) {
mcp_inspector_flag_c_g(L, tidx);
int size = mcp_inspector_string_c_g(L, tidx);
return size;
}

static int mcp_inspector_flagstr_i(lua_State *L, int tidx, int sc, struct mcp_inspector *ins) {
// TODO: if we never use mcp_ins_step we can remove it and just pass parts
// of the relevant structs down into these functions.
struct mcp_ins_step *s = &ins->steps[sc];
struct mcp_ins_flagstr *c = &s->c.flagstr;
size_t len = 0;

if (lua_getfield(L, tidx, "flag") != LUA_TNIL) {
const char *flag = lua_tostring(L, -1);
c->f = flag[0];
c->bit = (uint64_t)1 << (c->f - 65);
}
lua_pop(L, 1); // val or nil

if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
const char *str = lua_tolstring(L, -1, &len);
c->str = ins->aused;
c->len = len;
char *a = ins->arena + ins->aused;
memcpy(a, str, len);
ins->aused += len;
}
lua_pop(L, 1); // val or nil

return len;
}

// FIXME: size_t vs int consistency for tlen would shorten the code.
static int mcp_inspector_flagis_r(lua_State *L, struct mcp_inspector *ins, struct mcp_ins_step *s, void *arg) {
struct mcp_ins_flagstr *c = &s->c.flagstr;
const char *str = ins->arena + c->str;
if (ins->type == INS_REQ) {
mcp_request_t *rq = arg;

if (rq->pr.t.meta.flags & c->bit) {
lua_pushboolean(L, 1); // flag exists
const char *tok = NULL;
size_t tlen = 0;
mcp_request_find_flag_token(rq, c->f, &tok, &tlen);
if (tlen == c->len && strncmp(tok, str, c->len) == 0) {
lua_pushboolean(L, 1);
} else {
lua_pushboolean(L, 0);
}
return 2;
}
} else {
mcp_resp_t *res = arg;
if (res->resp.type == MCMC_RESP_META) {
mcmc_tokenize_res(res->buf, res->resp.reslen, &res->tok);
if (mcmc_token_has_flag_bit(&res->tok, c->bit) == MCMC_OK) {
lua_pushboolean(L, 1); // flag exists
int tlen = 0;
const char *tok = mcmc_token_get_flag(res->buf, &res->tok, c->f, &tlen);
if (tlen == c->len && strncmp(tok, str, c->len) == 0) {
lua_pushboolean(L, 1);
} else {
lua_pushboolean(L, 0);
}
return 2;
}
}
}
lua_pushboolean(L, 0);
lua_pushnil(L);

return 2;
}

// END STEPS

typedef int (*mcp_ins_c)(lua_State *L, int tidx);
Expand All @@ -379,13 +466,15 @@ struct mcp_ins_entry {
mcp_ins_r r;
};

// TODO: add str as the first option then do a for loop search in steptype?
static const struct mcp_ins_entry mcp_ins_entries[] = {
[mcp_ins_step_none] = {NULL, NULL, NULL},
[mcp_ins_step_sepkey] = {mcp_inspector_sepkey_c, mcp_inspector_sepkey_i, mcp_inspector_sepkey_r},
[mcp_ins_step_keybegin] = {mcp_inspector_keybegin_c, mcp_inspector_keybegin_i, mcp_inspector_keybegin_r},
[mcp_ins_step_keybegin] = {mcp_inspector_string_c_g, mcp_inspector_string_i_g, mcp_inspector_keybegin_r},
[mcp_ins_step_hasflag] = {mcp_inspector_flag_c_g, mcp_inspector_flag_i_g, mcp_inspector_hasflag_r},
[mcp_ins_step_flagtoken] = {mcp_inspector_flag_c_g, mcp_inspector_flag_i_g, mcp_inspector_flagtoken_r},
[mcp_ins_step_flagint] = {mcp_inspector_flag_c_g, mcp_inspector_flag_i_g, mcp_inspector_flagint_r},
[mcp_ins_step_flagis] = {mcp_inspector_flagstr_c, mcp_inspector_flagstr_i, mcp_inspector_flagis_r},
};

// call with type string on top
Expand All @@ -402,6 +491,8 @@ static enum mcp_ins_steptype mcp_inspector_steptype(lua_State *L) {
return mcp_ins_step_flagtoken;
} else if (strcmp(type, "flagint") == 0) {
return mcp_ins_step_flagint;
} else if (strcmp(type, "flagis") == 0) {
return mcp_ins_step_flagis;
}
return mcp_ins_step_none;
}
Expand Down Expand Up @@ -530,6 +621,7 @@ int mcplib_inspector_gc(lua_State *L) {
case mcp_ins_step_hasflag:
case mcp_ins_step_flagtoken:
case mcp_ins_step_flagint:
case mcp_ins_step_flagis:
case mcp_ins_step_none:
break;
}
Expand Down
9 changes: 8 additions & 1 deletion t/proxyins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,19 @@ function mcp_config_routes(p)
{ t = "flagtoken", flag = "O" },
{ t = "flagint", flag = "t" }
)

local mgresflagis_ins = mcp.res_inspector_new(
{ t = "flagis", flag = "O", str = "baz" }
)
mgreshasf:ready({
n = "reshasflag", f = function(rctx)
return function(r)
local key = r:key()
local res = rctx:enqueue_and_wait(r, mgreshasfh)
if key == "reshasf/tokenint" then
if key == "reshasf/flagis" then
local exists, matches = mgresflagis_ins(res)
return string.format("SERVER_ERROR exists[%q] matches[%q]\r\n", exists, matches)
elseif key == "reshasf/tokenint" then
local has_O, O, has_t, t = mgresflaga_ins(res)
return string.format("SERVER_ERROR O[%q]: %s t[%q]: %d\r\n",
has_O, O, has_t, t)
Expand Down
8 changes: 8 additions & 0 deletions t/proxyins.t
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ sub test_mgres {
$t->c_recv("SERVER_ERROR O[true]: moo t[true]: 60\r\n");
$t->clear();
};

subtest 'flagis' => sub {
$t->c_send("mg reshasf/flagis Obaz\r\n");
$t->be_recv_c(0);
$t->be_send(0, "HD f Obaz\r\n");
$t->c_recv("SERVER_ERROR exists[true] matches[true]\r\n");
$t->clear();
};
}

done_testing();

0 comments on commit 229a5dc

Please sign in to comment.