MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / handle_index_start

Function handle_index_start

src/ui/http_server.c:1018–1121  ·  view source on GitHub ↗

POST /api/index — body: {"root_path": "/abs/path", "project_name": "..."} */

Source from the content-addressed store, hash-verified

1016
1017/* POST /api/index — body: {"root_path": "/abs/path", "project_name": "..."} */
1018static void handle_index_start(cbm_http_server_t *server, cbm_http_conn_t *c,
1019 const cbm_http_req_t *req) {
1020 if (!server || !server->index_executor) {
1021 cbm_http_replyf(c, 503, g_cors_json,
1022 "{\"error\":\"daemon index coordinator unavailable\"}");
1023 return;
1024 }
1025 if (req->body_len == 0 || req->body_len > 4096) {
1026 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"invalid body\"}");
1027 return;
1028 }
1029
1030 yyjson_doc *doc = yyjson_read(req->body, req->body_len, 0);
1031 if (!doc) {
1032 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"invalid json\"}");
1033 return;
1034 }
1035 yyjson_val *root = yyjson_doc_get_root(doc);
1036 yyjson_val *v_path = yyjson_obj_get(root, "root_path");
1037 if (!v_path || !yyjson_is_str(v_path)) {
1038 yyjson_doc_free(doc);
1039 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"missing root_path\"}");
1040 return;
1041 }
1042 const char *rpath = yyjson_get_str(v_path);
1043 yyjson_val *v_project_name = yyjson_obj_get(root, "project_name");
1044 const char *project_name = yyjson_is_str(v_project_name) ? yyjson_get_str(v_project_name) : "";
1045
1046 /* Check path exists */
1047 if (!cbm_is_dir(rpath)) {
1048 yyjson_doc_free(doc);
1049 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"directory not found\"}");
1050 return;
1051 }
1052
1053 /* Same workspace boundary the MCP indexing tool applies, through the same
1054 * function. This route used to check only that the path was a directory, so
1055 * it accepted roots the MCP path refused — an operator's boundary held on one
1056 * entry point and not the other. Canonicalize first: the policy is defined
1057 * over resolved paths, and a symlink would otherwise launder the verdict. */
1058 char canonical_root[4096];
1059 char boundary_err[1024];
1060 if (!cbm_canonical_path(rpath, canonical_root, sizeof(canonical_root))) {
1061 yyjson_doc_free(doc);
1062 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"cannot resolve root_path\"}");
1063 return;
1064 }
1065 if (!cbm_workspace_root_allowed(canonical_root, cbm_workspace_home_dir(),
1066 cbm_workspace_cache_dir(), getenv("CBM_ALLOWED_ROOT"),
1067 boundary_err, sizeof(boundary_err))) {
1068 yyjson_doc_free(doc);
1069 char escaped[1024];
1070 cbm_json_escape(escaped, (int)sizeof(escaped), boundary_err);
1071 cbm_http_replyf(c, 403, g_cors_json, "{\"error\":\"%s\"}", escaped);
1072 return;
1073 }
1074
1075 /* Find free job slot */

Callers 1

dispatch_requestFunction · 0.85

Calls 9

cbm_http_replyfFunction · 0.85
cbm_is_dirFunction · 0.85
cbm_canonical_pathFunction · 0.85
cbm_workspace_home_dirFunction · 0.85
cbm_workspace_cache_dirFunction · 0.85
cbm_json_escapeFunction · 0.85
cbm_thread_joinFunction · 0.85
cbm_thread_createFunction · 0.85

Tested by

no test coverage detected