Repository: libsql/libsql
File: libsql-server/src/http/user/db_factory.rs (Rust)

Code before:
            &parts.headers,
            state.disable_default_namespace,
            state.disable_namespaces,
        )?;
        Ok(Self(
            state
                .namespaces
                .with_authenticated(ns, auth, |ns| ns.db.connection_maker())
                .await?,
        ))
    }
}

pub fn namespace_from_headers(
    headers: &HeaderMap,
    disable_default_namespace: bool,
    disable_namespaces: bool,
) -> crate::Result<NamespaceName> {
    if disable_namespaces {
        return Ok(NamespaceName::default());
    }

    headers
        .get(NAMESPACE_METADATA_KEY)
        .ok_or(Error::InvalidNamespace)
        .and_then(|h| h.to_str().map_err(|_| Error::InvalidNamespace))
        .and_then(|n| NamespaceName::from_string(n.into()))
        .or_else(|_| {
            let host = headers
                .get("host")
                .ok_or_else(|| Error::InvalidHost("missing host header".into()))?
                .as_bytes();
            let host_str = std::str::from_utf8(host)
                .map_err(|_| Error::InvalidHost("host header is not valid UTF-8".into()))?;

            match split_namespace(host_str) {
                Ok(ns) => Ok(ns),
                Err(_) if !disable_default_namespace => Ok(NamespaceName::default()),
                Err(e) => Err(e),
            }
        })
}

pub struct MakeConnectionExtractorPath(pub Arc<dyn MakeConnection<Connection = Connection>>);
#[async_trait::async_trait]
impl FromRequestParts<AppState> for MakeConnectionExtractorPath {
    type Rejection = Error;

    async fn from_request_parts(
        parts: &mut Parts,
        state: &AppState,

Review comment (bug):
would it make sense to add a `&'static str` to this error variant to specify what failed here? Otherwise we consume the string error here and may be hard to figure out why down the line.

Code after:
            &parts.headers,
            state.disable_default_namespace,
            state.disable_namespaces,
        )?;
        Ok(Self(
            state
                .namespaces
                .with_authenticated(ns, auth, |ns| ns.db.connection_maker())
                .await?,
        ))
    }
}

pub fn namespace_from_headers(
    headers: &HeaderMap,
    disable_default_namespace: bool,
    disable_namespaces: bool,
) -> crate::Result<NamespaceName> {
    if disable_namespaces {
        return Ok(NamespaceName::default());
    }

    if let Some(from_metadata) = headers.get(NAMESPACE_METADATA_KEY) {
        try_namespace_from_metadata(from_metadata)
    } else if let Some(from_host) = headers.get("host") {
        try_namespace_from_host(from_host, disable_default_namespace)
    } else if !disable_default_namespace {
        Ok(NamespaceName::default())
    } else {
        Err(Error::InvalidHost("missing host header".into()))
    }
}

fn try_namespace_from_host(
    from_host: &axum::http::HeaderValue,
    disable_default_namespace: bool,
) -> Result<NamespaceName, Error> {
    std::str::from_utf8(from_host.as_bytes())
        .map_err(|_| Error::InvalidHost("host header is not valid UTF-8".into()))
        .and_then(|h| match split_namespace(h) {
            Err(_) if !disable_default_namespace => Ok(NamespaceName::default()),
            r => r,
        })
}

fn try_namespace_from_metadata(metadata: &axum::http::HeaderValue) -> Result<NamespaceName, Error> {
    metadata
        .to_str()
        .map_err(|s| Error::InvalidNamespaceBytes(s))
        .and_then(|ns| NamespaceName::from_string(ns.into()))
}