azure_core/
request.rs

1#[cfg(not(target_arch = "wasm32"))]
2use crate::SeekableStream;
3use crate::{
4    headers::{AsHeaders, Headers},
5    to_json, Method, Url,
6};
7use bytes::Bytes;
8use serde::Serialize;
9use std::fmt::Debug;
10
11/// An HTTP Body.
12#[derive(Debug, Clone)]
13pub enum Body {
14    /// A body of a known size.
15    Bytes(bytes::Bytes),
16    /// A streaming body.
17    /// This is not currently supported on WASM targets.
18    // We cannot currently implement `Body::SeekableStream` for WASM
19    // because `reqwest::Body::wrap_stream()` is not implemented for WASM.
20    #[cfg(not(target_arch = "wasm32"))]
21    SeekableStream(Box<dyn SeekableStream>),
22}
23
24impl Body {
25    pub fn len(&self) -> usize {
26        match self {
27            Body::Bytes(bytes) => bytes.len(),
28            #[cfg(not(target_arch = "wasm32"))]
29            Body::SeekableStream(stream) => stream.len(),
30        }
31    }
32
33    pub fn is_empty(&self) -> bool {
34        self.len() == 0
35    }
36
37    pub(crate) async fn reset(&mut self) -> crate::Result<()> {
38        match self {
39            Body::Bytes(_) => Ok(()),
40            #[cfg(not(target_arch = "wasm32"))]
41            Body::SeekableStream(stream) => stream.reset().await,
42        }
43    }
44}
45
46impl<B> From<B> for Body
47where
48    B: Into<Bytes>,
49{
50    fn from(bytes: B) -> Self {
51        Self::Bytes(bytes.into())
52    }
53}
54
55#[cfg(not(target_arch = "wasm32"))]
56impl From<Box<dyn SeekableStream>> for Body {
57    fn from(seekable_stream: Box<dyn SeekableStream>) -> Self {
58        Self::SeekableStream(seekable_stream)
59    }
60}
61
62/// A pipeline request.
63///
64/// A pipeline request is composed by a destination (uri), a method, a collection of headers and a
65/// body. Policies are expected to enrich the request by mutating it.
66#[derive(Debug, Clone)]
67pub struct Request {
68    pub(crate) url: Url,
69    pub(crate) method: Method,
70    pub(crate) headers: Headers,
71    pub(crate) body: Body,
72}
73
74impl Request {
75    /// Create a new request with an empty body and no headers
76    pub fn new(url: Url, method: Method) -> Self {
77        Self {
78            url,
79            method,
80            headers: Headers::new(),
81            body: Body::Bytes(bytes::Bytes::new()),
82        }
83    }
84
85    pub fn url(&self) -> &Url {
86        &self.url
87    }
88
89    pub fn url_mut(&mut self) -> &mut Url {
90        &mut self.url
91    }
92
93    pub fn path_and_query(&self) -> String {
94        let mut result = self.url.path().to_owned();
95        if let Some(query) = self.url.query() {
96            result.push('?');
97            result.push_str(query);
98        }
99        result
100    }
101
102    pub fn method(&self) -> &Method {
103        &self.method
104    }
105
106    pub fn insert_headers<T: AsHeaders>(&mut self, headers: &T) {
107        for (name, value) in headers.as_headers() {
108            self.insert_header(name, value);
109        }
110    }
111
112    pub fn headers(&self) -> &Headers {
113        &self.headers
114    }
115
116    pub fn body(&self) -> &Body {
117        &self.body
118    }
119
120    pub fn set_json<T>(&mut self, data: &T) -> crate::Result<()>
121    where
122        T: ?Sized + Serialize,
123    {
124        self.set_body(to_json(data)?);
125        Ok(())
126    }
127
128    pub fn set_body(&mut self, body: impl Into<Body>) {
129        self.body = body.into();
130    }
131
132    pub fn insert_header<K, V>(&mut self, key: K, value: V)
133    where
134        K: Into<crate::headers::HeaderName>,
135        V: Into<crate::headers::HeaderValue>,
136    {
137        self.headers.insert(key, value);
138    }
139
140    pub fn add_optional_header<T: crate::Header>(&mut self, item: &Option<T>) {
141        if let Some(item) = item {
142            self.insert_header(item.name(), item.value());
143        }
144    }
145
146    pub fn add_mandatory_header<T: crate::Header>(&mut self, item: &T) {
147        self.insert_header(item.name(), item.value());
148    }
149}