relay_server/endpoints/
forward.rs1use std::future::Future;
7use std::sync::LazyLock;
8
9use axum::body::Body;
10use axum::extract::Request;
11use axum::handler::Handler;
12use axum::http::{HeaderMap, HeaderValue, StatusCode, Uri};
13use axum::response::{IntoResponse, Response};
14use relay_common::glob2::GlobMatcher;
15use relay_config::Config;
16use tower_http::limit::RequestBodyLimitLayer;
17
18use crate::extractors::ForwardedFor;
19use crate::service::ServiceState;
20use crate::services::upstream::Method;
21use crate::utils::ForwardRequest;
22
23const API_PATH: &str = "/api/";
25
26async fn handle(
28 state: ServiceState,
29 forwarded_for: ForwardedFor,
30 method: Method,
31 uri: Uri,
32 headers: HeaderMap<HeaderValue>,
33 data: Body,
34) -> impl IntoResponse {
35 if !state.config().http_forward() {
36 return StatusCode::NOT_FOUND.into_response();
37 }
38
39 if uri.path() == API_PATH || !uri.path().starts_with(API_PATH) {
42 return StatusCode::NOT_FOUND.into_response();
43 }
44
45 ForwardRequest::builder(method, uri.to_string())
46 .with_name("forward")
47 .with_headers(headers)
48 .with_forwarded_for(forwarded_for)
49 .with_body(data)
50 .with_config(state.config())
51 .send_to(state.upstream_relay())
52 .await
53 .into_response()
54}
55
56#[derive(Clone, Copy, Debug)]
58enum SpecialRoute {
59 FileUpload,
60 ChunkUpload,
61}
62
63static SPECIAL_ROUTES: LazyLock<GlobMatcher<SpecialRoute>> = LazyLock::new(|| {
65 let mut m = GlobMatcher::new();
66 m.add(
68 "/api/0/projects/*/*/releases/*/files/",
69 SpecialRoute::FileUpload,
70 );
71 m.add(
72 "/api/0/projects/*/*/releases/*/dsyms/",
73 SpecialRoute::FileUpload,
74 );
75 m.add(
77 "/api/0/organizations/*/chunk-upload/",
78 SpecialRoute::ChunkUpload,
79 );
80 m
81});
82
83fn get_limit_for_path(path: &str, config: &Config) -> usize {
85 match SPECIAL_ROUTES.test(path) {
86 Some(SpecialRoute::FileUpload) => config.max_api_file_upload_size(),
87 Some(SpecialRoute::ChunkUpload) => config.max_api_chunk_upload_size(),
88 None => config.max_api_payload_size(),
89 }
90}
91
92pub fn forward(state: ServiceState, req: Request) -> impl Future<Output = Response> {
105 let limit = get_limit_for_path(req.uri().path(), state.config());
106 handle
107 .layer(RequestBodyLimitLayer::new(limit))
109 .call(req, state)
110}