Skip to main content

shift_proxy/routes/
google.rs

1//! Google route handler — POST /v1beta/models/* and /v1/models/*
2//!
3//! Pure passthrough — no optimization. Google payload parsing is not yet
4//! implemented in shift-core (matches the TS proxy behavior).
5//! Query params are preserved (may contain API keys — redacted in logs).
6
7use crate::body::extract_body;
8use crate::forward::forward_request;
9use crate::ProxyState;
10use axum::body::Bytes;
11use axum::extract::State;
12use axum::http::{HeaderMap, StatusCode, Uri};
13use axum::response::{IntoResponse, Response};
14
15/// POST /v1beta/models/* or /v1/models/* — forward to Google unchanged.
16pub async fn google_handler(
17    State(state): State<ProxyState>,
18    uri: Uri,
19    headers: HeaderMap,
20    body: Bytes,
21) -> Response {
22    let body = match extract_body(&headers, body) {
23        Ok(s) => s,
24        Err(e) => {
25            return (
26                StatusCode::BAD_REQUEST,
27                axum::Json(serde_json::json!({"error": e})),
28            )
29                .into_response();
30        }
31    };
32    let base_url = &state.config.providers.google;
33    let query = uri.query().map(|q| format!("?{}", q)).unwrap_or_default();
34    let target_url = format!("{}{}{}", base_url, uri.path(), query);
35
36    if state.config.verbose {
37        // Redact query params from log output (may contain API keys)
38        tracing::info!("Google: passthrough → {}{}", base_url, uri.path());
39    }
40
41    forward_request(
42        &state.http_client,
43        "POST",
44        &target_url,
45        &headers,
46        Some(body),
47    )
48    .await
49}