| 1474 | } |
| 1475 | |
| 1476 | void DataStorageController::HandleGET_nodes_uid_data(const httplib::Request& req, httplib::Response& res) |
| 1477 | { |
| 1478 | if (!m_Bridge.HasDataStorage()) |
| 1479 | { |
| 1480 | this->SendErrorResponse(res, 503, ErrorResponse::DataStorageNotAvailable(req.path)); |
| 1481 | return; |
| 1482 | } |
| 1483 | |
| 1484 | const std::string uid = req.path_params.at("uid"); |
| 1485 | if (!ValidateUid(uid)) |
| 1486 | { |
| 1487 | this->SendErrorResponse(res, 400, ErrorResponse::InvalidRequest("Invalid UID format", req.path)); |
| 1488 | return; |
| 1489 | } |
| 1490 | |
| 1491 | // Determine transfer mode (header is a closed enum -- strict). Validate the |
| 1492 | // request shape before any resource lookup so a malformed header is rejected |
| 1493 | // without first cloning the node's data only to discard it. |
| 1494 | std::string transferMode; |
| 1495 | try |
| 1496 | { |
| 1497 | transferMode = this->DetermineTransferMode(req); |
| 1498 | } |
| 1499 | catch (const InvalidTransferModeHeader& e) |
| 1500 | { |
| 1501 | this->SendErrorResponse(res, 406, ErrorResponse::TransferModeNotAvailable( |
| 1502 | e.mode, {TRANSFER_MODE_FILE_REFERENCE, TRANSFER_MODE_DIRECT}, req.path)); |
| 1503 | return; |
| 1504 | } |
| 1505 | |
| 1506 | // Get a clone of the node's data for thread-safe serialization |
| 1507 | // The result distinguishes between "node not found" and "node has no data" |
| 1508 | const auto dataResult = m_Bridge.GetNodeData(uid); |
| 1509 | |
| 1510 | if (!dataResult.nodeFound) |
| 1511 | { |
| 1512 | this->SendErrorResponse(res, 404, ErrorResponse::NodeNotFound(uid, req.path)); |
| 1513 | return; |
| 1514 | } |
| 1515 | |
| 1516 | if (dataResult.data.IsNull()) |
| 1517 | { |
| 1518 | this->SendErrorResponse(res, 404, ErrorResponse::NoData(uid, req.path)); |
| 1519 | return; |
| 1520 | } |
| 1521 | |
| 1522 | // Use the cloned data for all subsequent operations |
| 1523 | const auto* const baseData = dataResult.data.GetPointer(); |
| 1524 | |
| 1525 | // Get node info for the filename hint (we know node exists at this point) |
| 1526 | const auto nodeJson = m_Bridge.GetNode(uid); |
| 1527 | |
| 1528 | // Find appropriate serializer using ITK ObjectFactory |
| 1529 | const std::string serializerName = std::string(baseData->GetNameOfClass()) + "Serializer"; |
| 1530 | const auto instances = itk::ObjectFactoryBase::CreateAllInstance(serializerName.c_str()); |
| 1531 | |
| 1532 | if (instances.empty()) |
| 1533 | { |