| 1229 | // ─── Client thread ────────────────────────────────────────────────────── |
| 1230 | |
| 1231 | void HttpServer::handle_client(int fd) { |
| 1232 | HttpRequest hr; |
| 1233 | if (!read_http_request(fd, hr)) { |
| 1234 | send_error(fd, 400, "bad HTTP request"); |
| 1235 | socket_close(fd); |
| 1236 | return; |
| 1237 | } |
| 1238 | |
| 1239 | // CORS preflight. |
| 1240 | if (hr.method == "OPTIONS") { |
| 1241 | send_response(fd, 204, "", ""); |
| 1242 | socket_close(fd); |
| 1243 | return; |
| 1244 | } |
| 1245 | |
| 1246 | // Health check. |
| 1247 | if (hr.method == "GET" && (hr.path == "/health" || hr.path == "/")) { |
| 1248 | send_response(fd, 200, "application/json", "{\"status\":\"ok\"}\n"); |
| 1249 | socket_close(fd); |
| 1250 | return; |
| 1251 | } |
| 1252 | |
| 1253 | // Introspection: server config + cache stats + arch + capabilities. |
| 1254 | if (hr.method == "GET" && hr.path == "/props") { |
| 1255 | json body = build_props_body(config_, prefix_cache_, tool_memory_); |
| 1256 | send_response(fd, 200, "application/json", body.dump() + "\n"); |
| 1257 | socket_close(fd); |
| 1258 | return; |
| 1259 | } |
| 1260 | |
| 1261 | // Status page: serve HTML file from disk. |
| 1262 | if (hr.method == "GET" && hr.path == "/status") { |
| 1263 | if (status_html_path_.empty()) { |
| 1264 | send_error(fd, 404, |
| 1265 | "status.html not found. Set DFLASH_SHARE_DIR or place it in share/status.html"); |
| 1266 | socket_close(fd); |
| 1267 | return; |
| 1268 | } |
| 1269 | std::ifstream ifs(status_html_path_); |
| 1270 | if (!ifs.is_open()) { |
| 1271 | send_error(fd, 500, "failed to open status.html"); |
| 1272 | socket_close(fd); |
| 1273 | return; |
| 1274 | } |
| 1275 | std::ostringstream oss; |
| 1276 | oss << ifs.rdbuf(); |
| 1277 | send_response(fd, 200, "text/html; charset=utf-8", oss.str()); |
| 1278 | socket_close(fd); |
| 1279 | return; |
| 1280 | } |
| 1281 | |
| 1282 | // Status JSON snapshot (for non-SSE clients / debugging). |
| 1283 | if (hr.method == "GET" && hr.path == "/status/json") { |
| 1284 | send_response(fd, 200, "application/json", |
| 1285 | status_.to_json().dump(-1, ' ', false, json::error_handler_t::replace) + "\n"); |
| 1286 | socket_close(fd); |
| 1287 | return; |
| 1288 | } |
nothing calls this directly
no test coverage detected