Skip to main content

rialo_types/
headers.rs

1// Copyright (c) Subzero Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::fmt;
5
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9use crate::oracle::OracleValue;
10
11type HeadersInnerType = std::collections::BTreeMap<String, OracleValue>;
12
13/// A structure representing the headers of an HTTP request.
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
15pub struct Headers(HeadersInnerType);
16
17#[derive(Error, Debug)]
18pub enum HeadersError {
19    #[error("Failed to decode {encoding} for parameter '{param}': {reason}")]
20    DecodeError {
21        param: String,
22        encoding: String,
23        reason: String,
24    },
25
26    #[error("JSON parsing error: {reason}")]
27    JsonError { reason: String },
28}
29
30impl Headers {
31    /// Creates a new Headers instance from the provided HeadersType map.
32    ///
33    /// # Arguments
34    /// * `headers` - A HeadersInnerType containing header key-value pairs
35    ///
36    /// # Returns
37    /// A new Headers instance wrapping the provided map
38    pub fn new(headers: HeadersInnerType) -> Self {
39        Headers(headers)
40    }
41
42    /// Inserts a plain text header value into the headers map.
43    ///
44    /// This method adds a header with a plain (unencrypted) value to the headers collection.
45    ///
46    /// # Arguments
47    /// * `key` - The header name
48    /// * `value` - The plain text header value
49    pub fn insert_plain(&mut self, key: String, value: String) {
50        self.0.insert(key, OracleValue::Plain(value));
51    }
52
53    /// Inserts an encrypted header value into the headers map.
54    ///
55    /// This method adds a header with an encrypted value to the headers collection.
56    /// The encrypted value should be base64-encoded ciphertext that can be decrypted
57    /// within the TEE using the stored secret key.
58    ///
59    /// # Arguments
60    /// * `key` - The header name
61    /// * `encrypted_value` - The base64-encoded encrypted header value
62    pub fn insert_encrypted(&mut self, key: String, encrypted_value: String) {
63        self.0.insert(key, OracleValue::Encrypted(encrypted_value));
64    }
65
66    /// Provide a public accessor to move out the inner map.
67    /// This enables other crates to consume the headers safely.
68    ///
69    /// # Returns
70    /// The inner HeadersInnerType map, consuming the Headers instance
71    pub fn into_inner(self) -> HeadersInnerType {
72        self.0
73    }
74
75    /// Parses base64-encoded headers string into a Headers instance.
76    ///
77    /// This method decodes a base64-encoded string containing JSON headers data
78    /// and deserializes it into a Headers structure.
79    ///
80    /// # Arguments
81    /// * `headers_b64` - Base64-encoded string containing JSON headers
82    ///
83    /// # Returns
84    /// * `Ok(Headers)` - Successfully parsed headers
85    /// * `Err(HeadersError)` - If base64 decoding, UTF-8 conversion, or JSON parsing fails
86    #[cfg(feature = "non-pdk")]
87    pub fn parse_b64(headers_b64: &str) -> Result<Self, HeadersError> {
88        use fastcrypto::{encoding, encoding::Encoding};
89        let headers_bytes =
90            encoding::Base64::decode(headers_b64).map_err(|err| HeadersError::DecodeError {
91                param: "headers".to_string(),
92                encoding: "base64".to_string(),
93                reason: err.to_string(),
94            })?;
95
96        let headers_str =
97            std::str::from_utf8(&headers_bytes).map_err(|err| HeadersError::DecodeError {
98                param: "headers".to_string(),
99                encoding: "utf-8".to_string(),
100                reason: err.to_string(),
101            })?;
102
103        let parsed_headers: Headers =
104            serde_json::from_str(headers_str).map_err(|error| HeadersError::JsonError {
105                reason: format!("Invalid headers JSON: {error}"),
106            })?;
107
108        Ok(parsed_headers)
109    }
110}
111
112impl std::str::FromStr for Headers {
113    type Err = String;
114
115    fn from_str(s: &str) -> Result<Self, Self::Err> {
116        let headers: HeadersInnerType = serde_json::from_str(s).map_err(|e| e.to_string())?;
117        Ok(Headers(headers))
118    }
119}
120
121impl fmt::Display for Headers {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        write!(f, "{}", serde_json::to_string(&self.0).unwrap())
124    }
125}