GET /api/adr?project=X — get ADR content for a project */
| 843 | |
| 844 | /* GET /api/adr?project=X — get ADR content for a project */ |
| 845 | static void handle_adr_get(cbm_http_conn_t *c, const cbm_http_req_t *req) { |
| 846 | char name[256] = {0}; |
| 847 | if (!cbm_http_query_param(req->query, "project", name, (int)sizeof(name)) || name[0] == '\0') { |
| 848 | cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"missing project\"}"); |
| 849 | return; |
| 850 | } |
| 851 | |
| 852 | char db_path[1024]; |
| 853 | db_path_for_project(name, db_path, sizeof(db_path)); |
| 854 | |
| 855 | cbm_store_t *store = cbm_store_open_path_query(db_path); |
| 856 | if (!store) { |
| 857 | cbm_http_replyf(c, 200, g_cors_json, "{\"has_adr\":false}"); |
| 858 | return; |
| 859 | } |
| 860 | |
| 861 | cbm_adr_t adr; |
| 862 | memset(&adr, 0, sizeof(adr)); |
| 863 | if (cbm_store_adr_get(store, name, &adr) == CBM_STORE_OK && adr.content) { |
| 864 | /* Escape content for JSON — simple: replace quotes and newlines */ |
| 865 | size_t clen = strlen(adr.content); |
| 866 | size_t buf_size = clen * 2 + 256; |
| 867 | char *buf = malloc(buf_size); |
| 868 | if (buf) { |
| 869 | int pos = snprintf(buf, buf_size, "{\"has_adr\":true,\"content\":\""); |
| 870 | for (size_t i = 0; i < clen && (size_t)pos < buf_size - 10; i++) { |
| 871 | char ch = adr.content[i]; |
| 872 | if (ch == '"') { |
| 873 | buf[pos++] = '\\'; |
| 874 | buf[pos++] = '"'; |
| 875 | } else if (ch == '\\') { |
| 876 | buf[pos++] = '\\'; |
| 877 | buf[pos++] = '\\'; |
| 878 | } else if (ch == '\n') { |
| 879 | buf[pos++] = '\\'; |
| 880 | buf[pos++] = 'n'; |
| 881 | } else if (ch == '\r') { /* skip */ |
| 882 | } else if (ch == '\t') { |
| 883 | buf[pos++] = '\\'; |
| 884 | buf[pos++] = 't'; |
| 885 | } else { |
| 886 | buf[pos++] = ch; |
| 887 | } |
| 888 | } |
| 889 | http_appendf(buf, buf_size, &pos, "\",\"updated_at\":\"%s\"}", |
| 890 | adr.updated_at ? adr.updated_at : ""); |
| 891 | cbm_http_replyf(c, 200, g_cors_json, "%s", buf); |
| 892 | free(buf); |
| 893 | } else { |
| 894 | cbm_http_replyf(c, 500, g_cors, "oom"); |
| 895 | } |
| 896 | cbm_store_adr_free(&adr); |
| 897 | } else { |
| 898 | cbm_http_replyf(c, 200, g_cors_json, "{\"has_adr\":false}"); |
| 899 | } |
| 900 | cbm_store_close(store); |
| 901 | } |
| 902 |
no test coverage detected