x402_paywall/
errors.rs

1use http::{HeaderName, HeaderValue, StatusCode};
2use x402_core::{transport::PaymentRequired, types::Base64EncodedHeader};
3
4/// Represents an error response from the paywall.
5#[derive(Debug, Clone)]
6pub struct ErrorResponse {
7    pub status: StatusCode,
8    pub header: ErrorResponseHeader,
9    /// The body of the error response.
10    ///
11    /// Body is Boxed to reduce size of the struct.
12    pub body: Box<PaymentRequired>,
13}
14
15/// Represents the type of error header to include in a paywall error response.
16#[derive(Debug, Clone)]
17pub enum ErrorResponseHeader {
18    PaymentRequired(Base64EncodedHeader),
19    PaymentResponse(Base64EncodedHeader),
20}
21
22impl ErrorResponseHeader {
23    /// Get the header value to include in the response.
24    ///
25    /// Returns `None` if the header value could not be created.
26    pub fn header_value(self) -> Option<(HeaderName, HeaderValue)> {
27        match self {
28            ErrorResponseHeader::PaymentRequired(Base64EncodedHeader(s)) => {
29                HeaderValue::from_str(&s)
30                    .ok()
31                    .map(|v| (HeaderName::from_static("payment-required"), v))
32            }
33            ErrorResponseHeader::PaymentResponse(Base64EncodedHeader(s)) => {
34                HeaderValue::from_str(&s)
35                    .ok()
36                    .map(|v| (HeaderName::from_static("payment-response"), v))
37            }
38        }
39    }
40}
41
42#[cfg(feature = "axum")]
43impl axum::response::IntoResponse for ErrorResponse {
44    fn into_response(self) -> axum::response::Response {
45        let mut response = (self.status, axum::extract::Json(self.body)).into_response();
46        if let Some((name, val)) = self.header.header_value() {
47            response.headers_mut().insert(name, val);
48        }
49        response
50    }
51}