@@ -5,15 +5,15 @@ use fastly::{Request, Response};
55use log;
66
77/// Handles Didomi CMP reverse proxy requests
8- ///
8+ ///
99/// This module implements the reverse proxy functionality for Didomi CMP
1010/// according to their self-hosting documentation:
1111/// https://developers.didomi.io/api-and-platform/domains/self-hosting
1212pub struct DidomiProxy ;
1313
1414impl DidomiProxy {
1515 /// Handle requests to /consent/* paths
16- ///
16+ ///
1717 /// Routes requests to either SDK or API origins based on path:
1818 /// - /consent/api/* → api.privacy-center.org
1919 /// - /consent/* → sdk.privacy-center.org
@@ -22,17 +22,17 @@ impl DidomiProxy {
2222 req : Request ,
2323 ) -> Result < Response , error_stack:: Report < TrustedServerError > > {
2424 let path = req. get_path ( ) ;
25-
25+
2626 log:: info!( "Didomi proxy handling request: {}" , path) ;
2727 // Force redeploy to fix intermittent issue
28-
28+
2929 log:: info!( "DEBUG: Starting path extraction" ) ;
30-
30+
3131 // Extract the consent path (remove /consent prefix)
3232 let consent_path = path. strip_prefix ( "/consent" ) . unwrap_or ( path) ;
33-
33+
3434 log:: info!( "DEBUG: consent_path = {}" , consent_path) ;
35-
35+
3636 // Determine which origin to use
3737 let ( backend_name, origin_path) = if consent_path. starts_with ( "/api/" ) {
3838 // API calls go to api.privacy-center.org with no caching
@@ -41,77 +41,93 @@ impl DidomiProxy {
4141 // SDK files go to sdk.privacy-center.org with geo-based caching
4242 ( "didomi_sdk" , consent_path)
4343 } ;
44-
45- log:: info!( "DEBUG: backend_name = {}, origin_path = {}" , backend_name, origin_path) ;
46-
47- log:: info!( "Routing to backend: {} with path: {}" , backend_name, origin_path) ;
48-
44+
45+ log:: info!(
46+ "DEBUG: backend_name = {}, origin_path = {}" ,
47+ backend_name,
48+ origin_path
49+ ) ;
50+
51+ log:: info!(
52+ "Routing to backend: {} with path: {}" ,
53+ backend_name,
54+ origin_path
55+ ) ;
56+
4957 log:: info!( "DEBUG: About to create proxy request" ) ;
50-
58+
5159 // Create the full URL for the request
5260 let backend_host = match backend_name {
5361 "didomi_sdk" => "sdk.privacy-center.org" ,
5462 "didomi_api" => "api.privacy-center.org" ,
55- _ => return Ok ( Response :: from_status ( fastly:: http:: StatusCode :: INTERNAL_SERVER_ERROR )
56- . with_header ( header:: CONTENT_TYPE , "text/plain" )
57- . with_body ( "Unknown backend" ) ) ,
63+ _ => {
64+ return Ok (
65+ Response :: from_status ( fastly:: http:: StatusCode :: INTERNAL_SERVER_ERROR )
66+ . with_header ( header:: CONTENT_TYPE , "text/plain" )
67+ . with_body ( "Unknown backend" ) ,
68+ )
69+ }
5870 } ;
59-
71+
6072 let full_url = format ! ( "https://{}{}" , backend_host, origin_path) ;
6173 log:: info!( "Full URL constructed: {}" , full_url) ;
62-
74+
6375 // Create the proxy request using Request::new like prebid module
6476 let mut proxy_req = Request :: new ( req. get_method ( ) . clone ( ) , full_url) ;
65-
77+
6678 log:: info!( "Created proxy request with method: {:?}" , req. get_method( ) ) ;
67-
79+
6880 // Copy query string
6981 if let Some ( query) = req. get_query_str ( ) {
7082 proxy_req. set_query_str ( query) ;
7183 }
72-
84+
7385 // Set required headers according to Didomi documentation
7486 Self :: set_proxy_headers ( & mut proxy_req, & req, backend_name) ;
75-
87+
7688 // Send the request
77- log:: info!( "Sending request to backend: {} with path: {}" , backend_name, origin_path) ;
78-
89+ log:: info!(
90+ "Sending request to backend: {} with path: {}" ,
91+ backend_name,
92+ origin_path
93+ ) ;
94+
7995 // Copy request body for POST/PUT requests
8096 if matches ! ( req. get_method( ) , & Method :: POST | & Method :: PUT ) {
8197 proxy_req. set_body ( req. into_body ( ) ) ;
8298 }
83-
99+
84100 match proxy_req. send ( backend_name) {
85101 Ok ( mut response) => {
86- log:: info!( "Received response from {}: {}" , backend_name, response. get_status( ) ) ;
87-
102+ log:: info!(
103+ "Received response from {}: {}" ,
104+ backend_name,
105+ response. get_status( )
106+ ) ;
107+
88108 // Process the response according to Didomi requirements
89109 Self :: process_response ( & mut response, backend_name) ;
90-
110+
91111 Ok ( response)
92112 }
93113 Err ( e) => {
94114 log:: error!( "Error proxying request to {}: {:?}" , backend_name, e) ;
95- Err ( error_stack:: Report :: new ( TrustedServerError :: FastlyError {
96- message : format ! ( "Proxy error to {}: {}" , backend_name, e)
115+ Err ( error_stack:: Report :: new ( TrustedServerError :: FastlyError {
116+ message : format ! ( "Proxy error to {}: {}" , backend_name, e) ,
97117 } ) )
98118 }
99119 }
100120 }
101-
121+
102122 /// Set proxy headers according to Didomi documentation
103- fn set_proxy_headers (
104- proxy_req : & mut Request ,
105- original_req : & Request ,
106- backend_name : & str ,
107- ) {
123+ fn set_proxy_headers ( proxy_req : & mut Request , original_req : & Request , backend_name : & str ) {
108124 // Host header is automatically set when using full URLs
109-
125+
110126 // Forward user IP in X-Forwarded-For header
111127 if let Some ( client_ip) = original_req. get_client_ip_addr ( ) {
112128 proxy_req. set_header ( "X-Forwarded-For" , client_ip. to_string ( ) ) ;
113129 }
114-
130+
115131 // Forward geographic information for SDK requests (for geo-based caching)
116132 if backend_name == "didomi_sdk" {
117133 // Copy geographic headers from Fastly
@@ -120,14 +136,14 @@ impl DidomiProxy {
120136 ( "X-Geo-Region" , "FastlyGeo-Region" ) ,
121137 ( "CloudFront-Viewer-Country" , "FastlyGeo-CountryCode" ) ,
122138 ] ;
123-
139+
124140 for ( header_name, fastly_header) in geo_headers {
125141 if let Some ( value) = original_req. get_header ( fastly_header) {
126142 proxy_req. set_header ( header_name, value) ;
127143 }
128144 }
129145 }
130-
146+
131147 // Forward essential headers
132148 let headers_to_forward = [
133149 header:: ACCEPT ,
@@ -138,26 +154,26 @@ impl DidomiProxy {
138154 header:: ORIGIN ,
139155 header:: AUTHORIZATION ,
140156 ] ;
141-
157+
142158 for header_name in headers_to_forward {
143159 if let Some ( value) = original_req. get_header ( & header_name) {
144160 proxy_req. set_header ( & header_name, value) ;
145161 }
146162 }
147-
163+
148164 // DO NOT forward cookies (as per Didomi documentation)
149165 // proxy_req.remove_header(header::COOKIE);
150-
166+
151167 // Set content type for POST/PUT requests
152168 if matches ! ( original_req. get_method( ) , & Method :: POST | & Method :: PUT ) {
153169 if let Some ( content_type) = original_req. get_header ( header:: CONTENT_TYPE ) {
154170 proxy_req. set_header ( header:: CONTENT_TYPE , content_type) ;
155171 }
156172 }
157-
173+
158174 log:: info!( "Proxy headers set for {}" , backend_name) ;
159175 }
160-
176+
161177 /// Process response according to Didomi requirements
162178 fn process_response ( response : & mut Response , backend_name : & str ) {
163179 // Add CORS headers for SDK requests
@@ -172,45 +188,48 @@ impl DidomiProxy {
172188 "GET, POST, PUT, DELETE, OPTIONS" ,
173189 ) ;
174190 }
175-
191+
176192 // Log cache headers for debugging
177193 if let Some ( cache_control) = response. get_header ( header:: CACHE_CONTROL ) {
178194 log:: info!( "Cache-Control from {}: {:?}" , backend_name, cache_control) ;
179195 }
180-
196+
181197 // Ensure cache headers are preserved (they will be returned to the client)
182198 // This is important for Didomi's caching requirements
183-
199+
184200 log:: info!( "Response processed for {}" , backend_name) ;
185201 }
186202}
187203
188204#[ cfg( test) ]
189205mod tests {
190206 use super :: * ;
191-
207+
192208 #[ test]
193209 fn test_consent_path_extraction ( ) {
194210 let path = "/consent/api/events" ;
195211 let consent_path = path. strip_prefix ( "/consent" ) . unwrap_or ( path) ;
196212 assert_eq ! ( consent_path, "/api/events" ) ;
197-
213+
198214 let path = "/consent/24cd3901-9da4-4643-96a3-9b1c573b5264/loader.js" ;
199215 let consent_path = path. strip_prefix ( "/consent" ) . unwrap_or ( path) ;
200- assert_eq ! ( consent_path, "/24cd3901-9da4-4643-96a3-9b1c573b5264/loader.js" ) ;
216+ assert_eq ! (
217+ consent_path,
218+ "/24cd3901-9da4-4643-96a3-9b1c573b5264/loader.js"
219+ ) ;
201220 }
202-
221+
203222 #[ test]
204223 fn test_backend_selection ( ) {
205224 // API requests
206225 let api_path = "/api/events" ;
207226 assert ! ( api_path. starts_with( "/api/" ) ) ;
208-
227+
209228 // SDK requests
210229 let sdk_path = "/24cd3901-9da4-4643-96a3-9b1c573b5264/loader.js" ;
211230 assert ! ( !sdk_path. starts_with( "/api/" ) ) ;
212-
231+
213232 let sdk_path2 = "/sdk/version/core.js" ;
214233 assert ! ( !sdk_path2. starts_with( "/api/" ) ) ;
215234 }
216- }
235+ }
0 commit comments