opendal/services/http/
core.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::Debug;
19use std::fmt::Formatter;
20use std::sync::Arc;
21
22use http::header;
23use http::header::IF_MATCH;
24use http::header::IF_NONE_MATCH;
25use http::Request;
26use http::Response;
27
28use crate::raw::*;
29use crate::*;
30
31pub struct HttpCore {
32    pub info: Arc<AccessorInfo>,
33
34    pub endpoint: String,
35    pub root: String,
36
37    pub authorization: Option<String>,
38}
39
40impl Debug for HttpCore {
41    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42        f.debug_struct("HttpCore")
43            .field("endpoint", &self.endpoint)
44            .field("root", &self.root)
45            .finish()
46    }
47}
48
49impl HttpCore {
50    pub fn has_authorization(&self) -> bool {
51        self.authorization.is_some()
52    }
53
54    pub fn http_get_request(
55        &self,
56        path: &str,
57        range: BytesRange,
58        args: &OpRead,
59    ) -> Result<Request<Buffer>> {
60        let p = build_rooted_abs_path(&self.root, path);
61
62        let url = format!("{}{}", self.endpoint, percent_encode_path(&p));
63
64        let mut req = Request::get(&url);
65
66        if let Some(if_match) = args.if_match() {
67            req = req.header(IF_MATCH, if_match);
68        }
69
70        if let Some(if_none_match) = args.if_none_match() {
71            req = req.header(IF_NONE_MATCH, if_none_match);
72        }
73
74        if let Some(auth) = &self.authorization {
75            req = req.header(header::AUTHORIZATION, auth.clone())
76        }
77
78        if !range.is_full() {
79            req = req.header(header::RANGE, range.to_header());
80        }
81
82        req.body(Buffer::new()).map_err(new_request_build_error)
83    }
84
85    pub async fn http_get(
86        &self,
87        path: &str,
88        range: BytesRange,
89        args: &OpRead,
90    ) -> Result<Response<HttpBody>> {
91        let req = self.http_get_request(path, range, args)?;
92        self.info.http_client().fetch(req).await
93    }
94
95    pub fn http_head_request(&self, path: &str, args: &OpStat) -> Result<Request<Buffer>> {
96        let p = build_rooted_abs_path(&self.root, path);
97
98        let url = format!("{}{}", self.endpoint, percent_encode_path(&p));
99
100        let mut req = Request::head(&url);
101
102        if let Some(if_match) = args.if_match() {
103            req = req.header(IF_MATCH, if_match);
104        }
105
106        if let Some(if_none_match) = args.if_none_match() {
107            req = req.header(IF_NONE_MATCH, if_none_match);
108        }
109
110        if let Some(auth) = &self.authorization {
111            req = req.header(header::AUTHORIZATION, auth.clone())
112        }
113
114        req.body(Buffer::new()).map_err(new_request_build_error)
115    }
116
117    pub async fn http_head(&self, path: &str, args: &OpStat) -> Result<Response<Buffer>> {
118        let req = self.http_head_request(path, args)?;
119        self.info.http_client().send(req).await
120    }
121}