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}