firstpass_proxy/
upstream.rs1use axum::http::{HeaderMap, StatusCode, header};
8use bytes::Bytes;
9
10use crate::error::ProxyError;
11
12const FORWARDED_REQUEST_HEADERS: &[&str] = &[
15 "x-api-key",
16 "authorization",
17 "anthropic-version",
18 "anthropic-beta",
19 "content-type",
20];
21
22fn build_request(
26 client: &reqwest::Client,
27 base: &str,
28 path: &str,
29 headers: &HeaderMap,
30 body: Bytes,
31) -> reqwest::RequestBuilder {
32 let url = format!("{}{path}", base.trim_end_matches('/'));
33 let mut req = client.post(url);
34 for name in FORWARDED_REQUEST_HEADERS {
35 if let Some(value) = headers.get(*name) {
36 req = req.header(*name, value.clone());
37 }
38 }
39 req.body(body)
40}
41
42fn passthrough_headers(response: &reqwest::Response) -> HeaderMap {
44 let mut out = HeaderMap::new();
47 if let Some(content_type) = response.headers().get(header::CONTENT_TYPE) {
48 out.insert(header::CONTENT_TYPE, content_type.clone());
49 }
50 out
51}
52
53pub async fn forward_anthropic(
61 client: &reqwest::Client,
62 base: &str,
63 headers: &HeaderMap,
64 body: Bytes,
65) -> Result<(StatusCode, HeaderMap, Bytes), ProxyError> {
66 let response = build_request(client, base, "/v1/messages", headers, body)
67 .send()
68 .await?;
69 let status = response.status();
70 let out_headers = passthrough_headers(&response);
71 let body = response.bytes().await?;
72 Ok((status, out_headers, body))
73}
74
75pub async fn forward_anthropic_streaming(
82 client: &reqwest::Client,
83 base: &str,
84 headers: &HeaderMap,
85 body: Bytes,
86) -> Result<(StatusCode, HeaderMap, reqwest::Response), ProxyError> {
87 let response = build_request(client, base, "/v1/messages", headers, body)
88 .send()
89 .await?;
90 let status = response.status();
91 let out_headers = passthrough_headers(&response);
92 Ok((status, out_headers, response))
93}
94
95pub async fn forward_openai(
101 client: &reqwest::Client,
102 base: &str,
103 headers: &HeaderMap,
104 body: Bytes,
105) -> Result<(StatusCode, HeaderMap, Bytes), ProxyError> {
106 let response = build_request(client, base, "/v1/chat/completions", headers, body)
107 .send()
108 .await?;
109 let status = response.status();
110 let out_headers = passthrough_headers(&response);
111 let body = response.bytes().await?;
112 Ok((status, out_headers, body))
113}
114
115pub async fn forward_openai_streaming(
120 client: &reqwest::Client,
121 base: &str,
122 headers: &HeaderMap,
123 body: Bytes,
124) -> Result<(StatusCode, HeaderMap, reqwest::Response), ProxyError> {
125 let response = build_request(client, base, "/v1/chat/completions", headers, body)
126 .send()
127 .await?;
128 let status = response.status();
129 let out_headers = passthrough_headers(&response);
130 Ok((status, out_headers, response))
131}