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

Function handle_index_start

src/ui/http_server.c:1146–1249  ·  view source on GitHub ↗

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

Source from the content-addressed store, hash-verified

1144
1145/* POST /api/index — body: {"root_path": "/abs/path", "project_name": "..."} */
1146static void handle_index_start(cbm_http_server_t *server, cbm_http_conn_t *c,
1147 const cbm_http_req_t *req) {
1148 if (!server || !server->index_executor) {
1149 cbm_http_replyf(c, 503, g_cors_json,
1150 "{\"error\":\"daemon index coordinator unavailable\"}");
1151 return;
1152 }
1153 if (req->body_len == 0 || req->body_len > 4096) {
1154 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"invalid body\"}");
1155 return;
1156 }
1157
1158 yyjson_doc *doc = yyjson_read(req->body, req->body_len, 0);
1159 if (!doc) {
1160 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"invalid json\"}");
1161 return;
1162 }
1163 yyjson_val *root = yyjson_doc_get_root(doc);
1164 yyjson_val *v_path = yyjson_obj_get(root, "root_path");
1165 if (!v_path || !yyjson_is_str(v_path)) {
1166 yyjson_doc_free(doc);
1167 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"missing root_path\"}");
1168 return;
1169 }
1170 const char *rpath = yyjson_get_str(v_path);
1171 yyjson_val *v_project_name = yyjson_obj_get(root, "project_name");
1172 const char *project_name = yyjson_is_str(v_project_name) ? yyjson_get_str(v_project_name) : "";
1173
1174 /* Check path exists */
1175 if (!cbm_is_dir(rpath)) {
1176 yyjson_doc_free(doc);
1177 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"directory not found\"}");
1178 return;
1179 }
1180
1181 /* Same workspace boundary the MCP indexing tool applies, through the same
1182 * function. This route used to check only that the path was a directory, so
1183 * it accepted roots the MCP path refused — an operator's boundary held on one
1184 * entry point and not the other. Canonicalize first: the policy is defined
1185 * over resolved paths, and a symlink would otherwise launder the verdict. */
1186 char canonical_root[4096];
1187 char boundary_err[1024];
1188 if (!cbm_canonical_path(rpath, canonical_root, sizeof(canonical_root))) {
1189 yyjson_doc_free(doc);
1190 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"cannot resolve root_path\"}");
1191 return;
1192 }
1193 if (!cbm_workspace_root_allowed(canonical_root, cbm_workspace_home_dir(),
1194 cbm_workspace_cache_dir(), getenv("CBM_ALLOWED_ROOT"),
1195 boundary_err, sizeof(boundary_err))) {
1196 yyjson_doc_free(doc);
1197 char escaped[1024];
1198 cbm_json_escape(escaped, (int)sizeof(escaped), boundary_err);
1199 cbm_http_replyf(c, 403, g_cors_json, "{\"error\":\"%s\"}", escaped);
1200 return;
1201 }
1202
1203 /* 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