1use bytes::Bytes;
11use serde::Serialize;
12use tokio::io::{AsyncWrite, AsyncWriteExt};
13use url::Url;
14
15use crate::client::{Client, Response};
16use crate::error::Error;
17use crate::form::FormResponse;
18use crate::http::{HeaderMap, Method};
19use crate::operation::Operation;
20use crate::security::is_same_origin;
21
22impl Client {
23 pub async fn get(&self, path: &str) -> Result<Response, Error> {
25 self.execute(self.raw(Method::GET, path)?).await
26 }
27
28 pub async fn get_html(&self, path: &str) -> Result<Response, Error> {
30 let mut operation = self.raw(Method::GET, path)?;
31 operation.accept("text/html");
32 self.execute(operation).await
33 }
34
35 pub async fn get_csv(&self, path: &str) -> Result<Response, Error> {
37 self.execute(self.csv(path)?).await
38 }
39
40 pub fn csv(&self, path: &str) -> Result<Operation, Error> {
45 let mut operation = self.raw(Method::GET, path)?;
46 operation.accept("text/csv");
47 Ok(operation)
48 }
49
50 pub async fn get_blob(&self, path: &str) -> Result<Response, Error> {
53 self.execute(self.blob(path)?).await
54 }
55
56 pub async fn download_blob(
60 &self,
61 path: &str,
62 destination: &mut (impl AsyncWrite + Unpin),
63 ) -> Result<(u64, HeaderMap), Error> {
64 let deadline = self.deadline();
65 let response = self.stream(self.blob(path)?, deadline).await?;
66 let headers = response.headers().clone();
67 let mut body = response.into_body();
68 let written = self
71 .within_deadline(deadline, async {
72 let mut written = 0;
73 while let Some(chunk) = body.chunk().await? {
74 destination
75 .write_all(&chunk)
76 .await
77 .map_err(Error::from_std)?;
78 written += chunk.len() as u64;
79 }
80 Ok(written)
81 })
82 .await?;
83 Ok((written, headers))
84 }
85
86 pub async fn post(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
88 self.send_json(Method::POST, path, body, "application/json")
89 .await
90 }
91
92 pub async fn post_mutation(
94 &self,
95 path: &str,
96 body: &impl Serialize,
97 ) -> Result<Response, Error> {
98 self.send_json(Method::POST, path, body, "*/*").await
99 }
100
101 pub async fn put(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
103 self.send_json(Method::PUT, path, body, "application/json")
104 .await
105 }
106
107 pub async fn patch(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
109 self.send_json(Method::PATCH, path, body, "application/json")
110 .await
111 }
112
113 pub async fn patch_mutation(
115 &self,
116 path: &str,
117 body: &impl Serialize,
118 ) -> Result<Response, Error> {
119 self.send_json(Method::PATCH, path, body, "*/*").await
120 }
121
122 pub async fn delete(&self, path: &str) -> Result<Response, Error> {
124 self.execute(self.raw(Method::DELETE, path)?).await
125 }
126
127 pub async fn post_form(
135 &self,
136 path: &str,
137 fields: &[(&str, &str)],
138 ) -> Result<FormResponse, Error> {
139 let mut operation = self.form(Method::POST, path)?;
140 operation.form(fields);
141 self.send_form(operation).await
142 }
143
144 pub async fn patch_form(
146 &self,
147 path: &str,
148 fields: &[(&str, &str)],
149 ) -> Result<FormResponse, Error> {
150 let mut operation = self.form(Method::PATCH, path)?;
151 operation.form(fields);
152 self.send_form(operation).await
153 }
154
155 pub async fn delete_form(&self, path: &str) -> Result<FormResponse, Error> {
158 self.send_form(self.form(Method::DELETE, path)?).await
159 }
160
161 pub async fn post_multipart(
163 &self,
164 path: &str,
165 content_type: String,
166 body: Bytes,
167 ) -> Result<FormResponse, Error> {
168 let mut operation = self.form(Method::POST, path)?;
169 operation.multipart(content_type, body);
170 self.send_form(operation).await
171 }
172
173 pub(crate) fn raw(&self, method: Method, path: &str) -> Result<Operation, Error> {
177 let mut operation = match self.absolute(path)? {
178 Some(url) => Operation::at(method, url),
179 None => Operation::raw(method, path.to_string()),
180 };
181 operation.without_json_suffix();
182 Ok(operation)
183 }
184
185 fn absolute(&self, path: &str) -> Result<Option<Url>, Error> {
189 if path.starts_with("https://") || path.starts_with("http://") {
190 let url = Url::parse(path)?;
191 if url.scheme() == "https" || is_same_origin(&url, self.base_url()) {
192 Ok(Some(url))
193 } else {
194 Err(Error::usage(format!("URL must use HTTPS, got: {path}")))
195 }
196 } else {
197 Ok(None)
198 }
199 }
200
201 fn blob(&self, path: &str) -> Result<Operation, Error> {
205 let mut operation = self.raw(Method::GET, path)?;
206 if let Some(url) = &operation.url
207 && !is_same_origin(url, self.base_url())
208 {
209 return Err(Error::usage("a blob URL must start on the HEY origin"));
210 }
211 operation.accept("*/*").no_cache();
212 Ok(operation)
213 }
214
215 async fn send_json(
216 &self,
217 method: Method,
218 path: &str,
219 body: &impl Serialize,
220 accept: &'static str,
221 ) -> Result<Response, Error> {
222 let mut operation = self.raw(method, path)?;
223 operation.json(body)?.accept(accept);
224 self.execute(operation).await
225 }
226}