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

Function handle_browse

src/ui/http_server.c:667–756  ·  view source on GitHub ↗

GET /api/browse?path=/some/dir — list subdirectories for file picker */

Source from the content-addressed store, hash-verified

665
666/* GET /api/browse?path=/some/dir — list subdirectories for file picker */
667static void handle_browse(cbm_http_conn_t *c, const cbm_http_req_t *req) {
668 char path[1024] = {0};
669 const char *home = cbm_get_home_dir();
670 if (!cbm_http_query_param(req->query, "path", path, (int)sizeof(path)) || path[0] == '\0') {
671 /* Default to home directory */
672 if (home)
673 snprintf(path, sizeof(path), "%s", home);
674 else
675 snprintf(path, sizeof(path), "/");
676 }
677
678 /* The browser UI may send Windows backslash separators (e.g.
679 * "D:\projects\demo"). Normalize to forward slashes before the cbm_is_dir
680 * gate, exactly as the MCP repo_path handler and cbm_project_name_from_path
681 * already do — otherwise a real D:/ directory is rejected (#548). */
682 cbm_normalize_path_sep(path);
683
684 if (!cbm_is_dir(path)) {
685 cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"not a directory\"}");
686 return;
687 }
688
689 DIR *dir = opendir(path);
690 if (!dir) {
691 cbm_http_replyf(c, 403, g_cors_json, "{\"error\":\"cannot open directory\"}");
692 return;
693 }
694
695 /* Build JSON response */
696 char buf[32768];
697 int pos = 0;
698 http_appendf(buf, sizeof(buf), &pos, "{\"path\":\"%s\",\"dirs\":[", path);
699
700 struct dirent *ent;
701 int count = 0;
702 while ((ent = readdir(dir)) != NULL) {
703 /* Skip hidden dirs and . / .. */
704 if (ent->d_name[0] == '.')
705 continue;
706
707 /* Check if it's actually a directory */
708 char full[2048];
709 snprintf(full, sizeof(full), "%s/%s", path, ent->d_name);
710 if (!cbm_is_dir(full))
711 continue;
712
713 if (count > 0)
714 buf[pos++] = ',';
715 /* Escape directory name to prevent XSS (e.g., names with quotes/angle brackets) */
716 {
717 char esc[512];
718 cbm_json_escape(esc, (int)sizeof(esc), ent->d_name);
719 http_appendf(buf, sizeof(buf), &pos, "\"%s\"", esc);
720 }
721 if (pos >= (int)sizeof(buf)) {
722 pos = (int)sizeof(buf) - 1;
723 }
724 count++;

Callers 1

dispatch_requestFunction · 0.85

Calls 8

cbm_get_home_dirFunction · 0.85
cbm_http_query_paramFunction · 0.85
cbm_normalize_path_sepFunction · 0.85
cbm_is_dirFunction · 0.85
cbm_http_replyfFunction · 0.85
http_appendfFunction · 0.85
cbm_json_escapeFunction · 0.85
append_roots_jsonFunction · 0.85

Tested by

no test coverage detected