Parse a request frame and dispatch to the Data Plane.
(
&mut self,
request_id: RequestId,
payload: &[u8],
)
| 360 | |
| 361 | /// Parse a request frame and dispatch to the Data Plane. |
| 362 | async fn handle_frame( |
| 363 | &mut self, |
| 364 | request_id: RequestId, |
| 365 | payload: &[u8], |
| 366 | ) -> crate::Result<Vec<u8>> { |
| 367 | // Parse the JSON request body. |
| 368 | let body: serde_json::Value = |
| 369 | sonic_rs::from_slice(payload).map_err(|e| crate::Error::BadRequest { |
| 370 | detail: format!("invalid JSON: {e}"), |
| 371 | })?; |
| 372 | |
| 373 | let op = body["op"] |
| 374 | .as_str() |
| 375 | .ok_or_else(|| crate::Error::BadRequest { |
| 376 | detail: "missing 'op' field".into(), |
| 377 | })?; |
| 378 | |
| 379 | // Auth handshake: must be first frame. |
| 380 | if op == "auth" { |
| 381 | let (identity, warning) = super::session_auth::authenticate( |
| 382 | &self.state, |
| 383 | &self.auth_mode, |
| 384 | &body, |
| 385 | &self.peer_addr.to_string(), |
| 386 | ) |
| 387 | .await?; |
| 388 | |
| 389 | // Optional `"database"` field in the auth payload — bind the session |
| 390 | // database at handshake time. If absent, falls back to the resolution |
| 391 | // chain (user-default → tenant-default → DatabaseId::DEFAULT) below. |
| 392 | let explicit_db = if let Some(db_name) = body["database"].as_str() { |
| 393 | if db_name.is_empty() { |
| 394 | None |
| 395 | } else { |
| 396 | // Validate the database name against the catalog. |
| 397 | let resolved = if let Some(cat) = self.state.credentials.catalog().as_ref() { |
| 398 | cat.get_database_id_by_name(db_name).ok().flatten() |
| 399 | } else { |
| 400 | None |
| 401 | }; |
| 402 | match resolved { |
| 403 | Some(db_id) => Some(db_id), |
| 404 | None => { |
| 405 | let msg = format!( |
| 406 | r#"{{"status":"error","code":"DATABASE_NOT_FOUND","error":"database '{db_name}' does not exist"}}"# |
| 407 | ); |
| 408 | return Ok(msg.into_bytes()); |
| 409 | } |
| 410 | } |
| 411 | } |
| 412 | } else { |
| 413 | None |
| 414 | }; |
| 415 | |
| 416 | let resolved_db = Self::resolve_database(&identity, explicit_db); |
| 417 | |
| 418 | // Enforce accessible_databases at session bind. Superusers bypass |
| 419 | // this check (can_access_database returns true for all databases). |
no test coverage detected