proxy_request.c C 724 lines View on github.com → Search inside
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */23#include "proxy.h"4#include "proto_parser.h"56// FIXME (v2): any reason to pass in command/cmdlen separately?7mcp_request_t *mcp_new_request(lua_State *L, mcp_parser_t *pr, const char *command, size_t cmdlen) {8    mcp_request_t *rq = lua_newuserdatauv(L, sizeof(mcp_request_t) + MCP_REQUEST_MAXLEN, 0);9    // TODO (v2): memset only the non-data part? as the rest gets memcpy'd10    // over.11    memset(rq, 0, sizeof(mcp_request_t));12    memcpy(&rq->pr, pr, sizeof(*pr));1314    memcpy(rq->request, command, cmdlen);15    rq->pr.request = rq->request;16    rq->pr.reqlen = cmdlen;1718    luaL_getmetatable(L, "mcp.request");19    lua_setmetatable(L, -2);2021    // at this point we should know if we have to bounce through _nread to22    // get item data or not.23    return rq;24}2526// fill a preallocated request object.27void mcp_set_request(mcp_parser_t *pr, mcp_request_t *rq, const char *command, size_t cmdlen) {28    memset(rq, 0, sizeof(mcp_request_t));29    memcpy(&rq->pr, pr, sizeof(*pr));3031    memcpy(rq->request, command, cmdlen);32    rq->pr.request = rq->request;33    rq->pr.reqlen = cmdlen;34}3536// Replaces a token inside a request and re-parses.37// Note that this has some optimization opportunities. Delaying until38// required.39// We should not guarantee order when updating meta flags, which would allow40// blanking tokens and appending new ones.41// TODO (v2): much of the length is the key, avoid copying it.42int mcp_request_render(mcp_request_t *rq, int idx, const char flag, const char *tok, size_t len) {43    char temp[MCP_REQUEST_MAXLEN+1];44    char *p = temp;45    mcp_parser_t *pr = &rq->pr;4647    if (pr->reqlen + len + 2 > MCP_REQUEST_MAXLEN) {48        return -1;49    }50    // Cannot add/append tokens yet.51    if (idx >= pr->tok.ntokens) {52        return -1;53    }5455    // FIXME: should use an accessor macro, at least.56    memcpy(p, pr->request, pr->tok.tokens[idx]);57    p += pr->tok.tokens[idx];5859    if (flag) {60        *p = flag;61        p++;62    }63    if (tok) {64        memcpy(p, tok, len);65        p += len;66    }6768    // Add a space and copy more tokens if there were more.69    if (idx+1 < pr->tok.ntokens) {70        if (flag || len != 0) {71            // Only pre-space if not deleting the token.72            *p = ' ';73            p++;74        }75        memcpy(p, &pr->request[pr->tok.tokens[idx+1]], pr->tok.tokens[pr->tok.ntokens] - pr->tok.tokens[idx+1]);76        p += pr->tok.tokens[pr->tok.ntokens] - pr->tok.tokens[idx+1];77    } else {78        // If we removed something from the end we might've left some spaces.79        while (p > temp && *(p-1) == ' ') {80            p--;81        }82    }8384    memcpy(p, "\r\n\0", 3);85    p += 2;8687    memcpy(rq->request, temp, p - temp);8889    // Hold the vlen/vbuf and restore after re-parsing. Since we can only edit90    // the command line, not the value here, we would otherwise allow sending91    // arbitrary memory over the network if someone modifies a SET.92    void *vbuf = pr->vbuf;93    int vlen = pr->vlen;9495    memset(pr, 0, sizeof(mcp_parser_t)); // TODO: required?96    int ret = process_request(pr, rq->request, p - temp);97    pr->vbuf = vbuf;98    pr->vlen = vlen;99100    if (ret != 0) {101        return ret;102    }103    return 0;104}105106int mcp_request_append(mcp_request_t *rq, const char flag, const char *tok, size_t len) {107    mcp_parser_t *pr = &rq->pr;108    const char *start = pr->request;109    char *p = (char *)pr->request + pr->reqlen - 2; // start at the \r110    assert(*p == '\r');111112    if (pr->reqlen + len + 2 >= MCP_REQUEST_MAXLEN) {113        return -1;114    }115116    *p = ' ';117    p++;118119    if (flag) {120        *p = flag;121        p++;122    }123    if (tok) {124        memcpy(p, tok, len);125        p += len;126    }127128    memcpy(p, "\r\n\0", 3);129    p += 2;130131    // See note on mcp_request_render()132    void *vbuf = pr->vbuf;133    int vlen = pr->vlen;134135    memset(pr, 0, sizeof(mcp_parser_t)); // TODO: required?136    int ret = process_request(pr, rq->request, p - start);137    pr->vbuf = vbuf;138    pr->vlen = vlen;139    if (ret != 0) {140        return ret;141    }142143    return 0;144}145146void mcp_request_attach(mcp_request_t *rq, io_pending_proxy_t *p) {147    mcp_parser_t *pr = &rq->pr;148    char *r = (char *) pr->request;149    size_t len = pr->reqlen;150151    // The stringified request. This is also referencing into the coroutine152    // stack, which should be safe from gc.153    p->iov[0].iov_base = r;154    p->iov[0].iov_len = len;155    p->iovcnt = 1;156    p->iovbytes = len;157    if (pr->vlen != 0) {158        p->iov[1].iov_base = pr->vbuf;159        p->iov[1].iov_len = pr->vlen;160        p->iovcnt = 2;161        p->iovbytes += pr->vlen;162    }163}164165// second argument is optional, for building set requests.166// TODO: append the \r\n for the VAL?167int mcplib_request(lua_State *L) {168    LIBEVENT_THREAD *t = PROXY_GET_THR(L);169    size_t len = 0;170    size_t vlen = 0;171    mcp_parser_t pr = {0};172    const char *cmd = luaL_checklstring(L, 1, &len);173    const char *val = NULL;174    int type = lua_type(L, 2);175    if (type == LUA_TSTRING) {176        val = luaL_optlstring(L, 2, NULL, &vlen);177        if (vlen < 2 || memcmp(val+vlen-2, "\r\n", 2) != 0) {178            proxy_lua_error(L, "value passed to mcp.request must end with \\r\\n");179        }180    } else if (type == LUA_TUSERDATA) {181        // vlen for requests and responses include the "\r\n" already.182        mcp_resp_t *r = luaL_testudata(L, 2, "mcp.response");183        if (r != NULL) {184            if (r->resp.value) {185                val = r->resp.value;186                vlen = r->resp.vlen_read; // paranoia, so we can't overread into memory.187            }188        } else {189            mcp_request_t *rq = luaL_testudata(L, 2, "mcp.request");190            if (rq->pr.vbuf) {191                val = rq->pr.vbuf;192                vlen = rq->pr.vlen;193            }194        }195    }196197    if (len > MCP_REQUEST_MAXLEN) {198        proxy_lua_error(L, "request length too long");199        return 0;200    }201202    if (memcmp(cmd+len-2, "\r\n", 2) != 0) {203        proxy_lua_error(L, "request must end with \r\n");204        return 0;205    }206207    // FIXME (v2): if we inline the userdata we can avoid memcpy'ing the parser208    // structure from the stack? but causes some code duplication.209    if (process_request(&pr, cmd, len) != 0) {210        proxy_lua_error(L, "failed to parse request");211        return 0;212    }213    mcp_request_t *rq = mcp_new_request(L, &pr, cmd, len);214215    if (val != NULL) {216        rq->pr.vlen = vlen;217        rq->pr.vbuf = malloc(vlen);218        if (rq->pr.vbuf == NULL) {219            // Note: without *c we can't tick the appropriate counter.220            // However, in practice raw malloc's are nearly never going to221            // fail.222            // TODO(v2): we can stack values into the request objects or use223            // the slabber memory, so this isn't necessary anyway.224            proxy_lua_error(L, "failed to allocate value memory for request object");225        }226        memcpy(rq->pr.vbuf, val, vlen);227        // Note: Not enforcing the memory limit here is deliberate:228        // - if we're over the memory limit, it'll get caught very soon after229        // this, but we won't be causing some lua to bail mid-flight, which is230        // more graceful to the end user.231        t->proxy_buffer_memory_used += rq->pr.vlen;232    }233234    // rq is now created, parsed, and on the stack.235    return 1;236}237238int mcplib_request_key(lua_State *L) {239    mcp_request_t *rq = luaL_checkudata(L, -1, "mcp.request");240    lua_pushlstring(L, MCP_PARSER_KEY(&rq->pr), rq->pr.klen);241    return 1;242}243244// NOTE: I've mixed up const/non-const strings in the request. During parsing245// we want it to be const, but after that's done the request is no longer246// const. It might be better to just remove the const higher up the chain, but247// I'd rather not. So for now these functions will be dumping the const to248// modify the string.249int mcplib_request_ltrimkey(lua_State *L) {250    mcp_request_t *rq = luaL_checkudata(L, -2, "mcp.request");251    int totrim = luaL_checkinteger(L, -1);252    char *key = (char *) MCP_PARSER_KEY(&rq->pr);253254    if (totrim > rq->pr.klen) {255        proxy_lua_error(L, "ltrimkey cannot zero out key");256        return 0;257    } else {258        memset(key, ' ', totrim);259        rq->pr.klen -= totrim;260        rq->pr.tok.tokens[rq->pr.keytoken] += totrim;261    }262    return 1;263}264265int mcplib_request_rtrimkey(lua_State *L) {266    mcp_request_t *rq = luaL_checkudata(L, -2, "mcp.request");267    int totrim = luaL_checkinteger(L, -1);268    char *key = (char *) MCP_PARSER_KEY(&rq->pr);269270    if (totrim > rq->pr.klen) {271        proxy_lua_error(L, "rtrimkey cannot zero out key");272        return 0;273    } else {274        memset(key + (rq->pr.klen - totrim), ' ', totrim);275        rq->pr.klen -= totrim;276        // don't need to change the key token.277    }278    return 1;279}280281int mcplib_request_raw_line(lua_State *L) {282    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");283    lua_pushlstring(L, rq->pr.request, rq->pr.reqlen-2);284    return 1;285}286287int mcplib_request_raw_value(lua_State *L) {288    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");289    if (rq->pr.vbuf) {290        lua_pushlstring(L, rq->pr.vbuf, rq->pr.vlen);291    } else {292        lua_pushnil(L);293    }294    return 1;295}296297// Virtual table operations on the request.298int mcplib_request_token(lua_State *L) {299    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");300    int argc = lua_gettop(L);301302    if (argc == 1) {303        lua_pushnil(L);304        return 1;305    }306307    int token = luaL_checkinteger(L, 2);308309    if (token < 1 || token > rq->pr.tok.ntokens) {310        // maybe an error?311        lua_pushnil(L);312        return 1;313    }314315    if (argc > 2) {316        // overwriting a token.317        size_t newlen = 0;318        const char *newtok = lua_tolstring(L, 3, &newlen);319        if (mcp_request_render(rq, token-1, 0, newtok, newlen) != 0) {320            proxy_lua_error(L, "token(): request malformed after edit");321            return 0;322        }323        return 0;324    } else {325        // fetching a token.326        mcp_parser_t *pr = &rq->pr;327        int vlen = 0;328        const char *start = mcmc_token_get(pr->request, &pr->tok, pr->keytoken, &vlen);329330        P_DEBUG("%s: pushing token of len: %lu\n", __func__, vlen);331        lua_pushlstring(L, start, vlen);332        return 1;333    }334335    return 0;336}337338// Fetch only.339int mcplib_request_token_int(lua_State *L) {340    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");341    int argc = lua_gettop(L);342343    if (argc == 1) {344        lua_pushnil(L);345        return 1;346    }347348    int x = luaL_checkinteger(L, 2);349350    if (x < 1 || x > rq->pr.tok.ntokens) {351        // maybe an error?352        lua_pushnil(L);353        return 1;354    }355356    int64_t token = 0;357    if (mcmc_token_get_64(rq->pr.request, &rq->pr.tok, x-1, &token) != MCMC_OK) {358        lua_pushnil(L);359    } else {360        lua_pushinteger(L, token);361    }362    return 1;363}364365int mcplib_request_ntokens(lua_State *L) {366    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");367    lua_pushinteger(L, rq->pr.tok.ntokens);368    return 1;369}370371int mcplib_request_command(lua_State *L) {372    mcp_request_t *rq = luaL_checkudata(L, -1, "mcp.request");373    lua_pushinteger(L, rq->pr.command);374    return 1;375}376377int mcplib_request_has_flag(lua_State *L) {378    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");379    size_t len = 0;380    const char *flagstr = luaL_checklstring(L, 2, &len);381    if (len != 1) {382        proxy_lua_error(L, "has_flag(): meta flag must be a single character");383        return 0;384    }385386    int status = mcmc_token_has_flag(rq->pr.request, &rq->pr.tok, flagstr[0]);387    if (status == MCMC_ERR) {388        proxy_lua_error(L, "has_flag(): invalid flag, must be A-Z,a-z");389        return 0;390    } else if (status == MCMC_OK) {391        lua_pushboolean(L, 1);392    } else {393        lua_pushboolean(L, 0);394    }395396    return 1;397}398399// req:flag_token("F") -> (bool, nil|token)400// req:flag_token("O", "Onewopauqe") -> (bool, oldtoken)401int mcplib_request_flag_token(lua_State *L) {402    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");403    size_t len = 0;404    const char *flagstr = luaL_checklstring(L, 2, &len);405    bool replace = false;406    if (len != 1) {407        proxy_lua_error(L, "has_flag(): meta flag must be a single character");408        return 0;409    }410    if (lua_isstring(L, 3)) {411        // overwriting a flag/token with the third argument.412        replace = true;413    }414415    int status = mcmc_token_has_flag(rq->pr.request, &rq->pr.tok, flagstr[0]);416    int ret = 1;417    if (status == MCMC_ERR) {418        proxy_lua_error(L, "has_flag(): invalid flag, must be A-Z,a-z");419        return 0;420    } else if (status == MCMC_OK) {421        // The flag definitely exists, but sadly we need to scan for the422        // actual flag to see if it has a token.423        lua_pushboolean(L, 1);424        int vlen = 0;425        // TODO: too much logic here since we also need to find the token426        // offset for the replace mode...427        // I think all this stuff can safely be long-term deprecated since we428        // have the mutator now so maybe I'll leave it.429        for (int x = rq->pr.keytoken+1; x < rq->pr.tok.ntokens; x++) {430            const char *s = mcmc_token_get(rq->pr.request, &rq->pr.tok, x, &vlen);431            if (s[0] == flagstr[0]) {432                if (vlen > 1) {433                    // strip the flag off the token and return.434                    lua_pushlstring(L, s+1, vlen-1);435                    ret = 2;436                }437438                // Have something to replace the flag/token with.439                if (replace) {440                    size_t newlen = 0;441                    const char *newtok = lua_tolstring(L, 3, &newlen);442                    if (mcp_request_render(rq, x, 0, newtok, newlen) != 0) {443                        proxy_lua_error(L, "token(): request malformed after edit");444                        return 0;445                    }446                }447                break;448            }449        }450451    } else {452        lua_pushboolean(L, 0);453    }454455    return ret;456}457458// returns bool, int459// bool results if flag exists or not460// if int conversion fails, int is nil461int mcplib_request_flag_token_int(lua_State *L) {462    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");463    size_t len = 0;464    const char *flagstr = luaL_checklstring(L, 2, &len);465    if (len != 1) {466        proxy_lua_error(L, "has_flag(): meta flag must be a single character");467        return 0;468    }469470    int64_t val = 0;471    int status = mcmc_token_get_flag_64(rq->pr.request, &rq->pr.tok, flagstr[0], &val);472    int ret = 1;473    if (status == MCMC_NOK) {474        // explicitly token not found.475        lua_pushboolean(L, 0);476    } else {477        // token found, but conversion may have failed.478        lua_pushboolean(L, 1);479        if (status == MCMC_OK) {480            lua_pushinteger(L, val);481            ret = 2;482        }483    }484    return ret;485}486487// these functions take token as string or number488// if number, internally convert it to avoid creating garbage489static inline char _mcp_request_get_arg_flag(lua_State *L, int idx) {490    size_t len = 0;491    const char *flagstr = luaL_checklstring(L, idx, &len);492493    if (len != 1) {494        proxy_lua_error(L, "request: meta flag must be a single character");495        return 0;496    }497    if (flagstr[0] < 65 || flagstr[0] > 122) {498        proxy_lua_error(L, "request: invalid flag, must be A-Z,a-z");499        return 0;500    }501502    return flagstr[0];503}504505// *tostring must be large enough to hold a 64bit number as a string.506static inline const char * _mcp_request_check_flag_token(lua_State *L, int idx, char *tostring, size_t *tlen) {507    const char *token = NULL;508    *tlen = 0;509    if (lua_isstring(L, idx)) {510        token = lua_tolstring(L, idx, tlen);511    } else if (lua_isnumber(L, idx)) {512        int isnum = 0;513        lua_Integer n = lua_tointegerx(L, idx, &isnum);514        if (isnum) {515            char *end = itoa_64(n, tostring);516            token = tostring;517            *tlen = end - tostring;518        } else {519            proxy_lua_error(L, "request: invalid flag argument");520            return NULL;521        }522    } else if (lua_isnoneornil(L, idx)) {523        // no token, just add the flag.524    } else {525        proxy_lua_error(L, "request: invalid flag argument");526        return NULL;527    }528529    return token;530}531532// req:flag_add("F", token) -> (bool)533// if token is "example", appends "Fexample" to request534int mcplib_request_flag_add(lua_State *L) {535    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");536    char flag = _mcp_request_get_arg_flag(L, 2);537    char tostring[30];538539    if (mcmc_token_has_flag(rq->pr.request, &rq->pr.tok, flag) == MCMC_OK) {540        // fail, flag already exists.541        lua_pushboolean(L, 0);542        return 1;543    }544545    size_t tlen = 0;546    const char *token = _mcp_request_check_flag_token(L, 3, tostring, &tlen);547548    if (mcp_request_append(rq, flag, token, tlen) == 0) {549        lua_pushboolean(L, 1);550    } else {551        lua_pushboolean(L, 0);552    }553554    return 1;555}556557// req:flag_set("F", token) -> (bool) [overwrites if exists]558// if token is "example", appends "Fexample" to request559int mcplib_request_flag_set(lua_State *L) {560    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");561    char flag = _mcp_request_get_arg_flag(L, 2);562    char tostring[30];563564    int x = mcmc_token_get_flag_idx(rq->pr.request, &rq->pr.tok, flag);565    size_t tlen = 0;566    const char *token = _mcp_request_check_flag_token(L, 3, tostring, &tlen);567568    if (x > 0) {569        // TODO: do nothing if:570        // flag exists in request, without token, and we're not setting a571        // token.572        if (mcp_request_render(rq, x, flag, token, tlen) != 0) {573            lua_pushboolean(L, 0);574            return 1;575        }576    } else {577        if (mcp_request_append(rq, flag, token, tlen) != 0) {578            lua_pushboolean(L, 0);579            return 1;580        }581    }582583    lua_pushboolean(L, 1);584    return 1;585}586587// allows replacing a flag with a different flag588// req:flag_replace("F", "N", token) -> (bool)589// if token is "example", appends "Nexample" to request590int mcplib_request_flag_replace(lua_State *L) {591    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");592    char flag = _mcp_request_get_arg_flag(L, 2);593    char newflag = _mcp_request_get_arg_flag(L, 3);594    char tostring[30];595596    int x = mcmc_token_get_flag_idx(rq->pr.request, &rq->pr.tok, flag);597    size_t tlen = 0;598    const char *token = _mcp_request_check_flag_token(L, 4, tostring, &tlen);599600    if (x > 0) {601        if (mcp_request_render(rq, x, newflag, token, tlen) != 0) {602            lua_pushboolean(L, 0);603            return 1;604        }605    } else {606        if (mcp_request_append(rq, newflag, token, tlen) != 0) {607            lua_pushboolean(L, 0);608            return 1;609        }610    }611612    lua_pushboolean(L, 1);613    return 1;614}615616// req:flag_del("F") -> (bool)617// remove a flag if exists618int mcplib_request_flag_del(lua_State *L) {619    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");620    char flag = _mcp_request_get_arg_flag(L, 2);621622    int x = mcmc_token_get_flag_idx(rq->pr.request, &rq->pr.tok, flag);623624    if (x > 0) {625        if (mcp_request_render(rq, x, 0, NULL, 0) != 0) {626            lua_pushboolean(L, 0);627            return 1;628        }629    } else {630        // nothing there, didn't delete anything.631        lua_pushboolean(L, 0);632        return 1;633    }634635    lua_pushboolean(L, 1);636    return 1;637}638639// local match, token = req:match_res(res)640// checks if req has `k` or `O`. If so, checks response for `K` or `O`641// returns true, nil if matches642// returns false, res token if not match.643static inline int _mcplib_request_match_check(lua_State *L, const char *rq, int rql, const char *rs, int rsl) {644    return (rql == rsl && memcmp(rq, rs, rsl) == 0);645}646647// TODO: re-evaluate tests.648int mcplib_request_match_res(lua_State *L) {649    mcp_request_t *rq = luaL_checkudata(L, 1, "mcp.request");650    mcp_resp_t *rs = luaL_checkudata(L, 2, "mcp.response");651652    // FIXME: we reparse the buffer because it may have changed if the old API653    // was in use? Can we skip this step now or in the future?654    mcmc_resp_t reresp;655656    // requests all have keys. check for an opaque.657    int opaque_len = 0;658    const char *opaque_token = mcmc_token_get_flag(rq->pr.request, &rq->pr.tok, 'O', &opaque_len);659    if (mcmc_parse_buf(rs->buf, rs->blen, &reresp) != MCMC_OK) {660        lua_pushboolean(L, 0);661        lua_pushstring(L, "failed to parse response");662        return 2;663    }664    mcmc_tokenize_res(rs->buf, reresp.reslen, &rs->tok);665666    int matched = 0;667    int rs_len = 0;668669    if (mcmc_token_has_flag(rs->buf, &rs->tok, 'k') == MCMC_OK) {670        const char *rs_token = mcmc_token_get_flag(rs->buf, &rs->tok, 'k', &rs_len);671        matched = _mcplib_request_match_check(L, MCP_PARSER_KEY(&rq->pr), rq->pr.klen,672                rs_token, rs_len);673        if (!matched) {674            lua_pushboolean(L, 0);675            // TODO: format string to include the keys? or at least partial?676            lua_pushstring(L, "key in response does not match request key");677            return 2;678        }679    }680    if (opaque_token) {681        if (mcmc_token_has_flag(rs->buf, &rs->tok, 'O') == MCMC_OK) {682            const char *rs_token = mcmc_token_get_flag(rs->buf, &rs->tok, 'O', &rs_len);683            matched = _mcplib_request_match_check(L, opaque_token, opaque_len,684                    rs_token, rs_len);685            if (!matched) {686                lua_pushboolean(L, 0);687                lua_pushstring(L, "request opaque does not match response opaque");688                return 2;689            }690        } else {691            lua_pushboolean(L, 0);692            // would be nice to include the opaque.693            // TODO: format string response here.694            lua_pushstring(L, "opaque in request but not in response");695            return 2;696        }697    }698699    lua_pushboolean(L, matched);700    lua_pushnil(L);701    return 2;702}703704void mcp_request_cleanup(LIBEVENT_THREAD *t, mcp_request_t *rq) {705    // During nread c->item is the malloc'ed buffer. not yet put into706    // rq->buf - this gets freed because we've also set c->item_malloced if707    // the connection closes before finishing nread.708    if (rq->pr.vbuf != NULL) {709        t->proxy_buffer_memory_used -= rq->pr.vlen;710        free(rq->pr.vbuf);711        // need to ensure we NULL this out now, since we can call the cleanup712        // routine independent of GC, and a later GC would double-free.713        rq->pr.vbuf = NULL;714    }715}716717int mcplib_request_gc(lua_State *L) {718    LIBEVENT_THREAD *t = PROXY_GET_THR(L);719    mcp_request_t *rq = luaL_checkudata(L, -1, "mcp.request");720    mcp_request_cleanup(t, rq);721722    return 0;723}

Code quality findings 3

Info: memset() followed by a complete overwrite may be unnecessary. Verify that the memset is required (e.g., for security zeroing) and not redundant.
info performance unnecessary-memset
memset(rq, 0, sizeof(mcp_request_t));
Info: memset() followed by a complete overwrite may be unnecessary. Verify that the memset is required (e.g., for security zeroing) and not redundant.
info performance unnecessary-memset
memset(rq, 0, sizeof(mcp_request_t));
Info: Magic number detected in condition or control flow. Use named constants via #define or const for better readability and maintainability.
info maintainability magic-number
if (flagstr[0] < 65 || flagstr[0] > 122) {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings