diff --git a/crates/trusted-server-core/src/integrations/prebid.rs b/crates/trusted-server-core/src/integrations/prebid.rs index 901071e4..266a31b2 100644 --- a/crates/trusted-server-core/src/integrations/prebid.rs +++ b/crates/trusted-server-core/src/integrations/prebid.rs @@ -3,12 +3,11 @@ use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; -use base64::{engine::general_purpose::STANDARD as BASE64, Engine}; use error_stack::{Report, ResultExt}; use fastly::http::{header, Method, StatusCode, Url}; use fastly::{Request, Response}; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value as Json}; +use serde_json::Value as Json; use validator::Validate; use crate::auction::provider::AuctionProvider; @@ -417,88 +416,6 @@ fn expand_trusted_server_bidders( }) .collect() } -fn transform_prebid_response( - response: &mut Json, - request_host: &str, - request_scheme: &str, -) -> Result<(), Report> { - if let Some(seatbids) = response["seatbid"].as_array_mut() { - for seatbid in seatbids { - if let Some(bids) = seatbid["bid"].as_array_mut() { - for bid in bids { - if let Some(adm) = bid["adm"].as_str() { - bid["adm"] = json!(rewrite_ad_markup(adm, request_host, request_scheme)); - } - - if let Some(nurl) = bid["nurl"].as_str() { - bid["nurl"] = json!(make_first_party_proxy_url( - nurl, - request_host, - request_scheme, - "track" - )); - } - - if let Some(burl) = bid["burl"].as_str() { - bid["burl"] = json!(make_first_party_proxy_url( - burl, - request_host, - request_scheme, - "track" - )); - } - } - } - } - } - - Ok(()) -} - -fn rewrite_ad_markup(markup: &str, request_host: &str, request_scheme: &str) -> String { - let mut content = markup.to_string(); - let cdn_patterns = [ - ("https://cdn.adsrvr.org", "adsrvr"), - ("https://ib.adnxs.com", "adnxs"), - ("https://rtb.openx.net", "openx"), - ("https://as.casalemedia.com", "casale"), - ("https://eus.rubiconproject.com", "rubicon"), - ]; - - for (cdn_url, cdn_name) in cdn_patterns { - if content.contains(cdn_url) { - let proxy_base = format!( - "{}://{}/ad-proxy/{}", - request_scheme, request_host, cdn_name - ); - content = content.replace(cdn_url, &proxy_base); - } - } - - content = content.replace( - "//cdn.adsrvr.org", - &format!("//{}/ad-proxy/adsrvr", request_host), - ); - content = content.replace( - "//ib.adnxs.com", - &format!("//{}/ad-proxy/adnxs", request_host), - ); - content -} - -fn make_first_party_proxy_url( - third_party_url: &str, - request_host: &str, - request_scheme: &str, - proxy_type: &str, -) -> String { - let encoded = BASE64.encode(third_party_url.as_bytes()); - format!( - "{}://{}/ad-proxy/{}/{}", - request_scheme, request_host, proxy_type, encoded - ) -} - /// Copies browser headers to the outgoing Prebid Server request. /// /// In [`ConsentForwardingMode::OpenrtbOnly`] mode, consent cookies are @@ -1189,7 +1106,7 @@ impl AuctionProvider for PrebidAuctionProvider { return Ok(AuctionResponse::error("prebid", response_time_ms)); } - let mut response_json: Json = + let response_json: Json = serde_json::from_slice(&body_bytes).change_context(TrustedServerError::Prebid { message: "Failed to parse Prebid response".to_string(), })?; @@ -1205,27 +1122,6 @@ impl AuctionProvider for PrebidAuctionProvider { } } - let request_host = response_json - .get("ext") - .and_then(|ext| ext.get("trusted_server")) - .and_then(|trusted_server| trusted_server.get("request_host")) - .and_then(|value| value.as_str()) - .unwrap_or("") - .to_string(); - let request_scheme = response_json - .get("ext") - .and_then(|ext| ext.get("trusted_server")) - .and_then(|trusted_server| trusted_server.get("request_scheme")) - .and_then(|value| value.as_str()) - .unwrap_or("https") - .to_string(); - - if request_host.is_empty() { - log::warn!("Prebid response missing request host; skipping URL rewrites"); - } else { - transform_prebid_response(&mut response_json, &request_host, &request_scheme)?; - } - let mut auction_response = self.parse_openrtb_response(&response_json, response_time_ms); self.enrich_response_metadata(&response_json, &mut auction_response); @@ -1570,62 +1466,6 @@ template = "{{client_ip}}:{{user_agent}}" ); } - #[test] - fn transform_prebid_response_rewrites_creatives_and_tracking() { - let mut response = json!({ - "seatbid": [{ - "bid": [{ - "adm": r#""#, - "nurl": "https://notify.example/win", - "burl": "https://notify.example/bill" - }] - }] - }); - - transform_prebid_response(&mut response, "pub.example", "https") - .expect("should rewrite response"); - - let rewritten_adm = response["seatbid"][0]["bid"][0]["adm"] - .as_str() - .expect("adm should be string"); - assert!( - rewritten_adm.contains("/ad-proxy/adsrvr"), - "creative markup should proxy CDN urls" - ); - - for url_field in ["nurl", "burl"] { - let value = response["seatbid"][0]["bid"][0][url_field] - .as_str() - .expect("should get tracking URL"); - assert!( - value.contains("/ad-proxy/track/"), - "tracking URLs should be proxied" - ); - } - } - - #[test] - fn make_first_party_proxy_url_base64_encodes_target() { - let url = "https://cdn.example/path?x=1"; - let rewritten = make_first_party_proxy_url(url, "pub.example", "https", "track"); - assert!( - rewritten.starts_with("https://pub.example/ad-proxy/track/"), - "proxy prefix should be applied" - ); - - let encoded = rewritten - .split("/ad-proxy/track/") - .nth(1) - .expect("should have encoded payload after proxy prefix"); - let decoded = BASE64 - .decode(encoded.as_bytes()) - .expect("should decode base64 proxy payload"); - assert_eq!( - String::from_utf8(decoded).expect("should be valid UTF-8"), - url - ); - } - #[test] fn matches_script_url_matches_common_variants() { let integration = PrebidIntegration::new(base_config());