mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-09 09:11:00 +08:00
fix(pipeline): classify suffix http clients correctly
Generic route-method suffix fallback treated client calls such as resty.Get('/api/products') as route registration before registry/service classification could identify the HTTP client library. Centralize suffix policy in service_patterns so generic verb suffixes require handler evidence, while route-specific APIs such as websocket/include_router/add_api_route keep handlerless route-registration support.
Validation: edge_types_probe 52 passed; parallel 30 passed; pipeline 346 passed; httplink 39 passed; lang_contract passed; product build passed; source-safety passed; escalated full ASan/UBSan suite passed with 6426 tests. Logs are recorded in the active plan and forensics ledger.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
This commit is contained in:
@@ -463,61 +463,66 @@ static const lib_pattern_t trpc_libraries[] = {
|
||||
{NULL, CBM_SVC_NONE, NULL},
|
||||
};
|
||||
|
||||
/* Method suffix type (used by both route registration and HTTP client tables) */
|
||||
typedef struct {
|
||||
const char *suffix;
|
||||
const char *method;
|
||||
} method_suffix_t;
|
||||
|
||||
typedef struct {
|
||||
const char *suffix;
|
||||
const char *method;
|
||||
bool allows_no_handler;
|
||||
} route_reg_suffix_t;
|
||||
|
||||
/* Route registration method suffixes — matched on callee name.
|
||||
* These are methods on router objects that register handlers. */
|
||||
static const method_suffix_t route_reg_suffixes[] = {
|
||||
static const route_reg_suffix_t route_reg_suffixes[] = {
|
||||
/* HTTP method registrations */
|
||||
{".GET", "GET"},
|
||||
{".Get", "GET"},
|
||||
{".get", "GET"},
|
||||
{".POST", "POST"},
|
||||
{".Post", "POST"},
|
||||
{".post", "POST"},
|
||||
{".PUT", "PUT"},
|
||||
{".Put", "PUT"},
|
||||
{".put", "PUT"},
|
||||
{".DELETE", "DELETE"},
|
||||
{".Delete", "DELETE"},
|
||||
{".delete", "DELETE"},
|
||||
{".PATCH", "PATCH"},
|
||||
{".Patch", "PATCH"},
|
||||
{".patch", "PATCH"},
|
||||
{".GET", "GET", false},
|
||||
{".Get", "GET", false},
|
||||
{".get", "GET", false},
|
||||
{".POST", "POST", false},
|
||||
{".Post", "POST", false},
|
||||
{".post", "POST", false},
|
||||
{".PUT", "PUT", false},
|
||||
{".Put", "PUT", false},
|
||||
{".put", "PUT", false},
|
||||
{".DELETE", "DELETE", false},
|
||||
{".Delete", "DELETE", false},
|
||||
{".delete", "DELETE", false},
|
||||
{".PATCH", "PATCH", false},
|
||||
{".Patch", "PATCH", false},
|
||||
{".patch", "PATCH", false},
|
||||
/* Handle/HandleFunc (Go stdlib, gorilla) */
|
||||
{".Handle", "ANY"},
|
||||
{".HandleFunc", "ANY"},
|
||||
{".handle", "ANY"},
|
||||
{".Handle", "ANY", false},
|
||||
{".HandleFunc", "ANY", false},
|
||||
{".handle", "ANY", false},
|
||||
/* Framework-specific route registration */
|
||||
{".Route", "ANY"},
|
||||
{".route", "ANY"},
|
||||
{".websocket_route", "ANY"},
|
||||
{".websocket", "ANY"},
|
||||
{"::get", "GET"},
|
||||
{"::post", "POST"},
|
||||
{"::put", "PUT"},
|
||||
{"::delete", "DELETE"},
|
||||
{"::patch", "PATCH"},
|
||||
{".Route", "ANY", false},
|
||||
{".route", "ANY", false},
|
||||
{".websocket_route", "ANY", true},
|
||||
{".websocket", "ANY", true},
|
||||
{"::get", "GET", false},
|
||||
{"::post", "POST", false},
|
||||
{"::put", "PUT", false},
|
||||
{"::delete", "DELETE", false},
|
||||
{"::patch", "PATCH", false},
|
||||
/* Minimal API (C# ASP.NET) */
|
||||
{".MapGet", "GET"},
|
||||
{".MapPost", "POST"},
|
||||
{".MapPut", "PUT"},
|
||||
{".MapDelete", "DELETE"},
|
||||
{".MapGet", "GET", false},
|
||||
{".MapPost", "POST", false},
|
||||
{".MapPut", "PUT", false},
|
||||
{".MapDelete", "DELETE", false},
|
||||
/* Router mounting / prefix registration (any method) */
|
||||
{".include_router", "ANY"},
|
||||
{".mount", "ANY"},
|
||||
{".add_url_rule", "ANY"},
|
||||
{".register_blueprint", "ANY"},
|
||||
{".use", "ANY"},
|
||||
{".register", "ANY"},
|
||||
{".add_route", "ANY"},
|
||||
{".add_api_route", "ANY"},
|
||||
{".add_api_websocket_route", "ANY"},
|
||||
{NULL, NULL},
|
||||
{".include_router", "ANY", true},
|
||||
{".mount", "ANY", false},
|
||||
{".add_url_rule", "ANY", true},
|
||||
{".register_blueprint", "ANY", true},
|
||||
{".use", "ANY", false},
|
||||
{".register", "ANY", false},
|
||||
{".add_route", "ANY", true},
|
||||
{".add_api_route", "ANY", true},
|
||||
{".add_api_websocket_route", "ANY", true},
|
||||
{NULL, NULL, false},
|
||||
};
|
||||
|
||||
/* ── HTTP method inference from function/method name suffix ───── */
|
||||
@@ -893,6 +898,20 @@ const char *cbm_service_pattern_route_method(const char *callee_name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cbm_service_pattern_route_suffix_allows_no_handler(const char *callee_name) {
|
||||
if (!callee_name) {
|
||||
return false;
|
||||
}
|
||||
size_t clen = strlen(callee_name);
|
||||
for (int i = 0; route_reg_suffixes[i].suffix != NULL; i++) {
|
||||
size_t slen = strlen(route_reg_suffixes[i].suffix);
|
||||
if (clen >= slen && strcmp(callee_name + clen - slen, route_reg_suffixes[i].suffix) == 0) {
|
||||
return route_reg_suffixes[i].allows_no_handler;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *cbm_service_pattern_broker(const char *resolved_qn) {
|
||||
if (!resolved_qn) {
|
||||
return NULL;
|
||||
|
||||
@@ -53,6 +53,11 @@ const char *cbm_service_pattern_http_method(const char *callee_name);
|
||||
* Returns NULL if not a known route registration method. */
|
||||
const char *cbm_service_pattern_route_method(const char *callee_name);
|
||||
|
||||
/* True when a route-registration suffix is specific enough to use without a
|
||||
* handler argument in suffix-only fallback. Generic HTTP verbs like .get/.Get
|
||||
* return false so HTTP client wrappers get normal resolution first. */
|
||||
bool cbm_service_pattern_route_suffix_allows_no_handler(const char *callee_name);
|
||||
|
||||
/* Classify a string literal as a genuine HTTP route path. Returns true for
|
||||
* real routes ("/api/orders", "/users/:id", "https://..."); false for file
|
||||
* paths ("/tmp/foo.md"), CLI slash-commands ("/ar:allow"), description strings
|
||||
|
||||
@@ -330,7 +330,9 @@ static int resolve_single_call(cbm_pipeline_ctx_t *ctx, CBMCall *call,
|
||||
if (cbm_service_pattern_route_method(call->callee_name) != NULL) {
|
||||
const char *handler_ref = NULL;
|
||||
const char *route_path = cbm_pipeline_call_route_path_and_handler(call, &handler_ref);
|
||||
if (route_path) {
|
||||
if (route_path &&
|
||||
((handler_ref && handler_ref[0] != '\0') ||
|
||||
cbm_service_pattern_route_suffix_allows_no_handler(call->callee_name))) {
|
||||
handle_route_registration(ctx, call, source_node, route_path, handler_ref,
|
||||
module_qn, imp_keys, imp_vals, imp_count);
|
||||
return SKIP_ONE;
|
||||
@@ -342,7 +344,9 @@ static int resolve_single_call(cbm_pipeline_ctx_t *ctx, CBMCall *call,
|
||||
if (cbm_service_pattern_route_method(call->callee_name) != NULL) {
|
||||
const char *handler_ref = NULL;
|
||||
const char *route_path = cbm_pipeline_call_route_path_and_handler(call, &handler_ref);
|
||||
if (route_path) {
|
||||
if (route_path &&
|
||||
((handler_ref && handler_ref[0] != '\0') ||
|
||||
cbm_service_pattern_route_suffix_allows_no_handler(call->callee_name))) {
|
||||
handle_route_registration(ctx, call, source_node, route_path, handler_ref, module_qn,
|
||||
imp_keys, imp_vals, imp_count);
|
||||
return SKIP_ONE;
|
||||
|
||||
@@ -1303,7 +1303,10 @@ static void emit_service_edge(cbm_gbuf_t *gbuf, const cbm_gbuf_node_t *source,
|
||||
if (svc == CBM_SVC_ROUTE_REG) {
|
||||
const char *handler_ref = NULL;
|
||||
const char *route_path = cbm_pipeline_call_route_path_and_handler(call, &handler_ref);
|
||||
if (route_path) {
|
||||
bool has_route_handler = handler_ref && handler_ref[0] != '\0';
|
||||
bool handlerless_route_api =
|
||||
cbm_service_pattern_route_suffix_allows_no_handler(call->callee_name);
|
||||
if (route_path && (!suffix_only_route_reg || has_route_handler || handlerless_route_api)) {
|
||||
emit_route_registration(gbuf, source, call, route_path, handler_ref, module_qn,
|
||||
registry, main_gbuf, imp_keys, imp_vals, imp_count);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user