r402_http/server/
receipt.rs1use axum_core::body::Body;
4use axum_core::response::Response;
5use http::header::CONTENT_TYPE;
6use http::{HeaderValue, StatusCode};
7use r402_protocol::payment::SettleResponse;
8use r402_server::{
9 CompletedSettlement, SkipHandlerDirective, WirePaymentPayload,
10 build_failure_path_settlement_response,
11};
12
13use super::fail::GateError;
14use crate::headers::{PAYMENT_RESPONSE, ensure_expose_headers, merge_private};
15
16pub fn settlement_to_header(settlement: &SettleResponse) -> Result<HeaderValue, GateError> {
22 let encoded = settlement
23 .encode_base64()
24 .ok_or_else(|| GateError::SettlementAborted("cannot encode error settlement".to_owned()))?;
25 HeaderValue::from_bytes(encoded.as_ref())
26 .map_err(|e| GateError::SettlementAborted(e.to_string()))
27}
28
29pub(crate) fn attach_payment_response(
30 response: &mut Response,
31 settlement: &SettleResponse,
32) -> Result<(), GateError> {
33 let header_value = settlement_to_header(settlement)?;
34 let _ = response
35 .headers_mut()
36 .insert(PAYMENT_RESPONSE, header_value);
37 ensure_expose_headers(response.headers_mut());
38 merge_private(response.headers_mut());
39 Ok(())
40}
41
42pub(crate) fn attach_failure_path_settlement(
43 response: &mut Response,
44 cancel_settlement: Option<&SettleResponse>,
45 before_handler: Option<&CompletedSettlement>,
46 payment_payload: Option<&WirePaymentPayload>,
47) -> Result<(), GateError> {
48 let Some(receipt) =
49 build_failure_path_settlement_response(cancel_settlement, before_handler, payment_payload)
50 else {
51 return Ok(());
52 };
53 let encoded = receipt.encode_base64_any().ok_or_else(|| {
54 GateError::SettlementAborted("cannot encode failure-path settlement".to_owned())
55 })?;
56 let header_value = HeaderValue::from_bytes(encoded.as_ref())
57 .map_err(|e| GateError::SettlementAborted(e.to_string()))?;
58 let _ = response
59 .headers_mut()
60 .insert(PAYMENT_RESPONSE, header_value);
61 ensure_expose_headers(response.headers_mut());
62 Ok(())
63}
64
65pub(crate) fn skip_handler_response(
66 directive: &SkipHandlerDirective,
67 settlement: &SettleResponse,
68) -> Result<Response, GateError> {
69 let content_type = directive
70 .content_type
71 .as_deref()
72 .unwrap_or("application/json");
73 let body_bytes = directive.body.as_ref().map_or_else(
74 || b"null".to_vec(),
75 |value| serde_json::to_vec(value).unwrap_or_else(|_| b"null".to_vec()),
76 );
77 let header_value = settlement_to_header(settlement)?;
78 let mut response = Response::new(Body::from(body_bytes));
79 *response.status_mut() = StatusCode::OK;
80 if let Ok(ct) = HeaderValue::from_str(content_type) {
81 let _ = response.headers_mut().insert(CONTENT_TYPE, ct);
82 }
83 let _ = response
84 .headers_mut()
85 .insert(PAYMENT_RESPONSE, header_value);
86 ensure_expose_headers(response.headers_mut());
87 merge_private(response.headers_mut());
88 Ok(response)
89}