Skip to content

Commit 2282db5

Browse files
authored
refactor: Migrate http service to context based http client (#5879)
* refactor: Introduce HttpCore for improved service structure * refactor: Migrate http service to context based http client
1 parent 4c79568 commit 2282db5

File tree

3 files changed

+186
-142
lines changed

3 files changed

+186
-142
lines changed

core/src/services/http/backend.rs

+63-142
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,20 @@ use std::fmt::Debug;
1919
use std::fmt::Formatter;
2020
use std::sync::Arc;
2121

22-
use http::header;
23-
use http::header::IF_MATCH;
24-
use http::header::IF_NONE_MATCH;
25-
use http::Request;
2622
use http::Response;
2723
use http::StatusCode;
2824
use log::debug;
2925

26+
use super::core::HttpCore;
3027
use super::error::parse_error;
3128
use crate::raw::*;
3229
use crate::services::HttpConfig;
3330
use crate::*;
3431

3532
impl Configurator for HttpConfig {
3633
type Builder = HttpBuilder;
34+
35+
#[allow(deprecated)]
3736
fn into_builder(self) -> Self::Builder {
3837
HttpBuilder {
3938
config: self,
@@ -47,6 +46,8 @@ impl Configurator for HttpConfig {
4746
#[derive(Default)]
4847
pub struct HttpBuilder {
4948
config: HttpConfig,
49+
50+
#[deprecated(since = "0.53.0", note = "Use `Operator::update_http_client` instead")]
5051
http_client: Option<HttpClient>,
5152
}
5253

@@ -119,6 +120,8 @@ impl HttpBuilder {
119120
///
120121
/// This API is part of OpenDAL's Raw API. `HttpClient` could be changed
121122
/// during minor updates.
123+
#[deprecated(since = "0.53.0", note = "Use `Operator::update_http_client` instead")]
124+
#[allow(deprecated)]
122125
pub fn http_client(mut self, client: HttpClient) -> Self {
123126
self.http_client = Some(client);
124127
self
@@ -143,15 +146,6 @@ impl Builder for HttpBuilder {
143146
let root = normalize_root(&self.config.root.unwrap_or_default());
144147
debug!("backend use root {}", root);
145148

146-
let client = if let Some(client) = self.http_client {
147-
client
148-
} else {
149-
HttpClient::new().map_err(|err| {
150-
err.with_operation("Builder::build")
151-
.with_context("service", Scheme::Http)
152-
})?
153-
};
154-
155149
let mut auth = None;
156150
if let Some(username) = &self.config.username {
157151
auth = Some(format_authorization_by_basic(
@@ -163,67 +157,66 @@ impl Builder for HttpBuilder {
163157
auth = Some(format_authorization_by_bearer(token)?)
164158
}
165159

166-
Ok(HttpBackend {
167-
info: {
168-
let ma = AccessorInfo::default();
169-
ma.set_scheme(Scheme::Http)
170-
.set_root(&root)
171-
.set_native_capability(Capability {
172-
stat: true,
173-
stat_with_if_match: true,
174-
stat_with_if_none_match: true,
175-
stat_has_cache_control: true,
176-
stat_has_content_length: true,
177-
stat_has_content_type: true,
178-
stat_has_content_encoding: true,
179-
stat_has_content_range: true,
180-
stat_has_etag: true,
181-
stat_has_content_md5: true,
182-
stat_has_last_modified: true,
183-
stat_has_content_disposition: true,
184-
185-
read: true,
186-
187-
read_with_if_match: true,
188-
read_with_if_none_match: true,
189-
190-
presign: auth.is_none(),
191-
presign_read: auth.is_none(),
192-
presign_stat: auth.is_none(),
193-
194-
shared: true,
195-
196-
..Default::default()
197-
});
198-
199-
ma.into()
200-
},
160+
let info = AccessorInfo::default();
161+
info.set_scheme(Scheme::Http)
162+
.set_root(&root)
163+
.set_native_capability(Capability {
164+
stat: true,
165+
stat_with_if_match: true,
166+
stat_with_if_none_match: true,
167+
stat_has_cache_control: true,
168+
stat_has_content_length: true,
169+
stat_has_content_type: true,
170+
stat_has_content_encoding: true,
171+
stat_has_content_range: true,
172+
stat_has_etag: true,
173+
stat_has_content_md5: true,
174+
stat_has_last_modified: true,
175+
stat_has_content_disposition: true,
176+
177+
read: true,
178+
179+
read_with_if_match: true,
180+
read_with_if_none_match: true,
181+
182+
presign: auth.is_none(),
183+
presign_read: auth.is_none(),
184+
presign_stat: auth.is_none(),
185+
186+
shared: true,
187+
188+
..Default::default()
189+
});
190+
191+
// allow deprecated api here for compatibility
192+
#[allow(deprecated)]
193+
if let Some(client) = self.http_client {
194+
info.update_http_client(|_| client);
195+
}
196+
197+
let accessor_info = Arc::new(info);
198+
199+
let core = Arc::new(HttpCore {
200+
info: accessor_info,
201201
endpoint: endpoint.to_string(),
202-
authorization: auth,
203202
root,
204-
client,
205-
})
203+
authorization: auth,
204+
});
205+
206+
Ok(HttpBackend { core })
206207
}
207208
}
208209

209210
/// Backend is used to serve `Accessor` support for http.
210211
#[derive(Clone)]
211212
pub struct HttpBackend {
212-
info: Arc<AccessorInfo>,
213-
214-
endpoint: String,
215-
root: String,
216-
client: HttpClient,
217-
218-
authorization: Option<String>,
213+
core: Arc<HttpCore>,
219214
}
220215

221216
impl Debug for HttpBackend {
222217
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
223-
f.debug_struct("Backend")
224-
.field("endpoint", &self.endpoint)
225-
.field("root", &self.root)
226-
.field("client", &self.client)
218+
f.debug_struct("HttpBackend")
219+
.field("core", &self.core)
227220
.finish()
228221
}
229222
}
@@ -239,7 +232,7 @@ impl Access for HttpBackend {
239232
type BlockingDeleter = ();
240233

241234
fn info(&self) -> Arc<AccessorInfo> {
242-
self.info.clone()
235+
self.core.info.clone()
243236
}
244237

245238
async fn stat(&self, path: &str, args: OpStat) -> Result<RpStat> {
@@ -248,7 +241,7 @@ impl Access for HttpBackend {
248241
return Ok(RpStat::new(Metadata::new(EntryMode::DIR)));
249242
}
250243

251-
let resp = self.http_head(path, &args).await?;
244+
let resp = self.core.http_head(path, &args).await?;
252245

253246
let status = resp.status();
254247

@@ -264,7 +257,7 @@ impl Access for HttpBackend {
264257
}
265258

266259
async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
267-
let resp = self.http_get(path, args.range(), &args).await?;
260+
let resp = self.core.http_get(path, args.range(), &args).await?;
268261

269262
let status = resp.status();
270263

@@ -281,16 +274,18 @@ impl Access for HttpBackend {
281274
}
282275

283276
async fn presign(&self, path: &str, args: OpPresign) -> Result<RpPresign> {
284-
if self.has_authorization() {
277+
if self.core.has_authorization() {
285278
return Err(Error::new(
286279
ErrorKind::Unsupported,
287280
"Http doesn't support presigned request on backend with authorization",
288281
));
289282
}
290283

291284
let req = match args.operation() {
292-
PresignOperation::Stat(v) => self.http_head_request(path, v)?,
293-
PresignOperation::Read(v) => self.http_get_request(path, BytesRange::default(), v)?,
285+
PresignOperation::Stat(v) => self.core.http_head_request(path, v)?,
286+
PresignOperation::Read(v) => {
287+
self.core.http_get_request(path, BytesRange::default(), v)?
288+
}
294289
_ => {
295290
return Err(Error::new(
296291
ErrorKind::Unsupported,
@@ -308,77 +303,3 @@ impl Access for HttpBackend {
308303
)))
309304
}
310305
}
311-
312-
impl HttpBackend {
313-
pub fn has_authorization(&self) -> bool {
314-
self.authorization.is_some()
315-
}
316-
317-
pub fn http_get_request(
318-
&self,
319-
path: &str,
320-
range: BytesRange,
321-
args: &OpRead,
322-
) -> Result<Request<Buffer>> {
323-
let p = build_rooted_abs_path(&self.root, path);
324-
325-
let url = format!("{}{}", self.endpoint, percent_encode_path(&p));
326-
327-
let mut req = Request::get(&url);
328-
329-
if let Some(if_match) = args.if_match() {
330-
req = req.header(IF_MATCH, if_match);
331-
}
332-
333-
if let Some(if_none_match) = args.if_none_match() {
334-
req = req.header(IF_NONE_MATCH, if_none_match);
335-
}
336-
337-
if let Some(auth) = &self.authorization {
338-
req = req.header(header::AUTHORIZATION, auth.clone())
339-
}
340-
341-
if !range.is_full() {
342-
req = req.header(header::RANGE, range.to_header());
343-
}
344-
345-
req.body(Buffer::new()).map_err(new_request_build_error)
346-
}
347-
348-
pub async fn http_get(
349-
&self,
350-
path: &str,
351-
range: BytesRange,
352-
args: &OpRead,
353-
) -> Result<Response<HttpBody>> {
354-
let req = self.http_get_request(path, range, args)?;
355-
self.client.fetch(req).await
356-
}
357-
358-
pub fn http_head_request(&self, path: &str, args: &OpStat) -> Result<Request<Buffer>> {
359-
let p = build_rooted_abs_path(&self.root, path);
360-
361-
let url = format!("{}{}", self.endpoint, percent_encode_path(&p));
362-
363-
let mut req = Request::head(&url);
364-
365-
if let Some(if_match) = args.if_match() {
366-
req = req.header(IF_MATCH, if_match);
367-
}
368-
369-
if let Some(if_none_match) = args.if_none_match() {
370-
req = req.header(IF_NONE_MATCH, if_none_match);
371-
}
372-
373-
if let Some(auth) = &self.authorization {
374-
req = req.header(header::AUTHORIZATION, auth.clone())
375-
}
376-
377-
req.body(Buffer::new()).map_err(new_request_build_error)
378-
}
379-
380-
async fn http_head(&self, path: &str, args: &OpStat) -> Result<Response<Buffer>> {
381-
let req = self.http_head_request(path, args)?;
382-
self.client.send(req).await
383-
}
384-
}

0 commit comments

Comments
 (0)