summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2022-07-29 18:38:15 -0700
committerdormando <dormando@rydia.net>2022-08-03 11:53:29 -0700
commit2389436317fe9d74d390d0adfe4a2679c693375e (patch)
treebd49936324871903bf3c2f2a10014e174638f41c
parent4f07a597bbd0367d6458ed4c65f47ec9ca3910cd (diff)
downloadmemcached-2389436317fe9d74d390d0adfe4a2679c693375e.tar.gz
proxy: mcp.request improvements
- errors if a string value is missing the "\r\n" terminator - properly uses a value from a response object - allows passing in a request object for the value as well - also adds r:vlen() for recovering the value length of a response think this still needs r:flags() or similar?
-rw-r--r--proxy_lua.c18
-rw-r--r--proxy_request.c20
-rw-r--r--t/startfile.lua7
3 files changed, 40 insertions, 5 deletions
diff --git a/proxy_lua.c b/proxy_lua.c
index 5f5707c..383f747 100644
--- a/proxy_lua.c
+++ b/proxy_lua.c
@@ -32,6 +32,23 @@ static int mcplib_response_hit(lua_State *L) {
return 1;
}
+// Caller needs to discern if a vlen is 0 because of a failed response or an
+// OK response that was actually zero. So we always return an integer value
+// here.
+static int mcplib_response_vlen(lua_State *L) {
+ mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
+
+ // We do remove the "\r\n" from the value length, so if you're actually
+ // processing the value nothing breaks.
+ if (r->resp.vlen >= 2) {
+ lua_pushinteger(L, r->resp.vlen-2);
+ } else {
+ lua_pushinteger(L, 0);
+ }
+
+ return 1;
+}
+
static int mcplib_response_gc(lua_State *L) {
mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
@@ -773,6 +790,7 @@ int proxy_register_libs(LIBEVENT_THREAD *t, void *ctx) {
const struct luaL_Reg mcplib_response_m[] = {
{"ok", mcplib_response_ok},
{"hit", mcplib_response_hit},
+ {"vlen", mcplib_response_vlen},
{"__gc", mcplib_response_gc},
{NULL, NULL}
};
diff --git a/proxy_request.c b/proxy_request.c
index 259ec90..9918499 100644
--- a/proxy_request.c
+++ b/proxy_request.c
@@ -529,13 +529,23 @@ int mcplib_request(lua_State *L) {
int type = lua_type(L, 2);
if (type == LUA_TSTRING) {
val = luaL_optlstring(L, 2, NULL, &vlen);
+ if (vlen < 2 || memcmp(val+vlen-2, "\r\n", 2) != 0) {
+ proxy_lua_error(L, "value passed to mcp.request must end with \\r\\n");
+ }
} else if (type == LUA_TUSERDATA) {
- mcp_resp_t *r = luaL_checkudata(L, 2, "mcp.response");
- if (r->buf) {
- val = r->buf;
- vlen = r->blen;
+ // vlen for requests and responses include the "\r\n" already.
+ mcp_resp_t *r = luaL_testudata(L, 2, "mcp.response");
+ if (r != NULL) {
+ if (r->resp.value) {
+ val = r->resp.value;
+ vlen = r->resp.vlen_read; // paranoia, so we can't overread into memory.
+ }
} else {
- // TODO (v2): other response modes unhandled.
+ mcp_request_t *rq = luaL_testudata(L, 2, "mcp.request");
+ if (rq->pr.vbuf) {
+ val = rq->pr.vbuf;
+ vlen = rq->pr.vlen;
+ }
}
}
diff --git a/t/startfile.lua b/t/startfile.lua
index c8e3806..c204d49 100644
--- a/t/startfile.lua
+++ b/t/startfile.lua
@@ -151,6 +151,10 @@ function failover_factory(zones, local_zone)
end
return restable[1], "failover_backup_miss"
end
+ -- example of making a new set request on the side.
+ -- local nr = mcp.request("set /foo/asdf 0 0 " .. res:vlen() .. "\r\n", res)
+ -- local nr = mcp.request("set /foo/asdf 0 0 2\r\n", "mo\r\n")
+ -- near_zone(nr)
return res, "failover_hit" -- send result back to client
end
end
@@ -172,6 +176,9 @@ function setinvalidate_factory(zones, local_zone)
if res:ok() == true then
-- create a new delete request
local dr = new_req("delete /testing/" .. r:key() .. "\r\n")
+ -- example of new request from existing request
+ -- note this isn't trimming the key so it'll make a weird one.
+ -- local dr = new_req("set /bar/" .. r:key() .. " 0 0 " .. r:token(5) .. "\r\n", r)
for _, zone in pairs(far_zones) do
-- NOTE: can check/do things on the specific response here.
zone(dr)