Class HandlerContext

Class Documentation

class HandlerContext

Shared context for all HTTP handlers.

Provides access to gateway node, configuration, and common utilities that handlers need to process requests.

Public Functions

inline HandlerContext(GatewayNode *node, const CorsConfig &cors_config, const AuthConfig &auth_config, const TlsConfig &tls_config, AuthManager *auth_manager, BulkDataStore *bulk_data_store = nullptr)
inline GatewayNode *node() const

Get gateway node.

inline const CorsConfig &cors_config() const

Get CORS configuration.

inline const AuthConfig &auth_config() const

Get authentication configuration.

inline const TlsConfig &tls_config() const

Get TLS configuration.

inline AuthManager *auth_manager() const

Get authentication manager (may be nullptr if auth disabled)

inline BulkDataStore *bulk_data_store() const

Get bulk data store (may be nullptr if not configured)

inline void set_aggregation_manager(AggregationManager *mgr)

Set the aggregation manager (non-owning, null when aggregation disabled)

inline AggregationManager *aggregation_manager() const

Get the aggregation manager (may be nullptr if aggregation disabled)

tl::expected<void, std::string> validate_entity_id(const std::string &entity_id) const

Validate entity ID (component_id, area_id, etc.)

Parameters:

entity_id – The ID to validate

Returns:

Empty if valid, error message otherwise

tl::expected<std::string, std::string> get_component_namespace_path(const std::string &component_id) const

Get namespace path for a component.

Deprecated:

Use get_entity_info instead for unified entity handling

Parameters:

component_idComponent ID

Returns:

Namespace path or error message

EntityInfo get_entity_info(const std::string &entity_id, SovdEntityType expected_type = SovdEntityType::UNKNOWN) const

Get information about any entity (Component, App, Area, Function)

If expected_type is specified, searches ONLY in that collection. If expected_type is UNKNOWN (default), searches all types in order: Component, App, Area, Function - returns the first match found.

Parameters:
  • entity_id – Entity ID to look up

  • expected_type – Optional: restrict search to specific entity type

Returns:

EntityInfo with resolved details, or EntityInfo with UNKNOWN type if not found

tl::expected<void, ErrorInfo> validate_lock_access(const http::TypedRequest &req, const EntityInfo &entity, const std::string &collection)

Validate lock access for a mutating operation.

Two-phase check:

  1. If locking disabled (no LockManager), allows access.

  2. Extracts X-Client-Id header, checks LockManager::check_access().

On denial, returns a populated ErrorInfo (HTTP 409 with either ERR_LOCK_BROKEN or ERR_INVALID_REQUEST). The method never touches an httplib::Response; the typed router serializes the ErrorInfo onto the wire. Locking is always local, so there is no Forwarded variant.

Parameters:
  • req – Typed HTTP request (for X-Client-Id header).

  • entity – Entity being accessed.

  • collection – Resource collection being mutated (e.g. “configurations”).

Returns:

Empty success on allow, ErrorInfo on denial.

http::ValidatorResult<EntityInfo> validate_entity_for_route(const http::TypedRequest &req, const std::string &entity_id) const

Validate entity exists and matches expected route type (typed variant).

Unified validation helper that:

  1. Validates the entity ID format.

  2. Looks up the entity in the expected collection (based on route path).

  3. For remote entities (aggregation), forwards the request to the peer gateway, writes the proxied response to the underlying httplib::Response, and returns Forwarded so the caller knows the wire is committed.

  4. On local failure, returns a populated ErrorInfo without touching the response. The typed router serializes the error.

The success branch carries the resolved EntityInfo. The error branch is a variant of:

  • ErrorInfo - local validation failure (400 invalid-parameter, 404 entity-not-found). Caller serializes via write_generic_error.

  • Forwarded - request was proxied to a peer; the response is already written and the caller must return immediately without touching the response further.

The Forwarded path is the one place the validator still mutates the underlying httplib::Response. Aggregation could not be modeled cleanly any other way without either (a) returning the proxied bytes as a buffered payload (loses streaming and headers) or (b) exposing the response object to the caller (defeats the typed surface). Keeping the proxy write inside the validator preserves the historical aggregation behavior bit-for-bit.

Parameters:
  • req – Typed HTTP request (used to extract expected type from path and to drive the forward proxy).

  • entity_id – Entity ID to validate.

Returns:

EntityInfo on local success, or an error variant indicating local failure (ErrorInfo) vs. peer forwarding completed (Forwarded).

void set_cors_headers(httplib::Response &res, const std::string &origin) const

Set CORS headers on response if origin is allowed.

Parameters:
  • res – HTTP response

  • origin – Origin header value

bool is_origin_allowed(const std::string &origin) const

Check if origin is allowed by CORS config.

Parameters:

origin – Origin header value

Returns:

true if allowed

Public Static Functions

static tl::expected<void, ErrorInfo> validate_collection_access_typed(const EntityInfo &entity, ResourceCollection collection)

Validate that entity supports a resource collection (typed variant).

Returns a populated ErrorInfo (HTTP 400, ERR_COLLECTION_NOT_SUPPORTED) when the entity type does not support the collection. The typed router serializes the error onto the wire; this method never touches an httplib::Response.

Parameters:
  • entity – Entity information (from get_entity_info)

  • collection – Resource collection to validate

Returns:

Empty success on support, ErrorInfo on rejection.

static inline ErrorInfo forwarded_sentinel_error()

Build the framework-internal sentinel error that typed handlers return after the validator’s Forwarded path already committed the proxied wire response.

Typed handlers use this helper so the typed Result<T> shape can propagate the validator’s Forwarded variant without re-rendering the body. The wrapper in RouteRegistry detects the sentinel via its error code (ERR_X_INTERNAL_FORWARDED) and skips error rendering.

Returns:

ErrorInfo with the sentinel code and http_status == 0.

static inline rclcpp::Logger logger()

Get logger for handlers.

static std::vector<std::string> resolve_app_host_fqns(const ThreadSafeEntityCache &cache, const std::vector<std::string> &app_ids)

Resolve a list of app IDs to their non-empty effective FQNs.

Apps that are missing from the cache or that have an empty effective_fqn() are skipped silently. The returned vector preserves the input app_ids order (minus skipped entries) and may be empty. Apps whose effective_fqn() is already present in the result are skipped, so duplicates from manifest / runtime double-binds do not produce repeated downstream queries.

Used by log_handlers and bulkdata_handlers to aggregate per-component / per-function resource queries from the entity’s hosted apps. Static + public to enable direct unit testing without standing up a full GatewayNode fixture.

Parameters:
  • cache – Entity cache to look up apps in

  • app_idsApp IDs to resolve

Returns:

Effective FQNs for the apps that resolved

static std::set<std::string> resolve_entity_source_fqns(const ThreadSafeEntityCache &cache, const EntityInfo &entity)

Resolve an entity to the set of source FQNs it owns.

Returns the FQNs of every ROS 2 node within the entity’s scope. Used by fault handlers to filter reporting_sources so that per-entity routes never expose faults reported from outside the addressed entity.

Mapping per entity type:

  • App: the app’s effective_fqn() (single entry, or empty set if unbound or if ros_binding.namespace_pattern is a wildcard - by design effective_fqn() returns “” for those, so the entity simply has no addressable ROS node and the scope check excludes every fault).

  • Component: effective_fqn() of every hosted app via get_apps_for_component().

  • Area: effective_fqn() of every app under the area, walking get_subareas() recursively so nested areas (e.g. powertrain -> engine) resolve to the union of their descendants’ apps.

  • Function: effective_fqn() of every app the function hosts directly plus, for hosts that are component IDs, the apps inside those components.

  • Unknown: empty set.

Apps whose effective_fqn() is empty are silently dropped from the set so the scope check cannot match arbitrary FQNs against an empty prefix.

An empty result means “no apps are in scope” and callers must NEVER interpret that as “no filter” - any fault must be treated as out of scope. The exact response (404 for per-fault routes, an empty items array for collection lists, 204 for collection clears) is up to the caller.

Parameters:
  • cache – Entity cache for lookups

  • entity – Resolved entity info (from validate_entity_for_route)

Returns:

Set of FQNs that uniquely scopes faults to this entity