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::sync::Arc;
20
21use http::Request;
22use http::Response;
23use http::header;
24use http::header::IF_MATCH;
25use http::header::IF_NONE_MATCH;
26
27use crate::raw::*;
28use crate::*;
29
30pub struct HttpCore {
31    pub info: Arc<AccessorInfo>,
32
33    pub endpoint: String,
34    pub root: String,
35
36    pub authorization: Option<String>,
37}
38
39impl Debug for HttpCore {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        f.debug_struct("HttpCore")
42            .field("endpoint", &self.endpoint)
43            .field("root", &self.root)
44            .finish_non_exhaustive()
45    }
46}
47
48impl HttpCore {
49    pub fn has_authorization(&self) -> bool {
50        self.authorization.is_some()
51    }
52
53    pub fn http_get_request(
54        &self,
55        path: &str,
56        range: BytesRange,
57        args: &OpRead,
58    ) -> Result<Request<Buffer>> {
59        let p = build_rooted_abs_path(&self.root, path);
60
61        let url = format!("{}{}", self.endpoint, percent_encode_path(&p));
62
63        let mut req = Request::get(&url);
64
65        if let Some(if_match) = args.if_match() {
66            req = req.header(IF_MATCH, if_match);
67        }
68
69        if let Some(if_none_match) = args.if_none_match() {
70            req = req.header(IF_NONE_MATCH, if_none_match);
71        }
72
73        if let Some(auth) = &self.authorization {
74            req = req.header(header::AUTHORIZATION, auth.clone())
75        }
76
77        if !range.is_full() {
78            req = req.header(header::RANGE, range.to_header());
79        }
80
81        let req = req.extension(Operation::Read);
82
83        req.body(Buffer::new()).map_err(new_request_build_error)
84    }
85
86    pub async fn http_get(
87        &self,
88        path: &str,
89        range: BytesRange,
90        args: &OpRead,
91    ) -> Result<Response<HttpBody>> {
92        let req = self.http_get_request(path, range, args)?;
93        self.info.http_client().fetch(req).await
94    }
95
96    pub fn http_head_request(&self, path: &str, args: &OpStat) -> Result<Request<Buffer>> {
97        let p = build_rooted_abs_path(&self.root, path);
98
99        let url = format!("{}{}", self.endpoint, percent_encode_path(&p));
100
101        let mut req = Request::head(&url);
102
103        if let Some(if_match) = args.if_match() {
104            req = req.header(IF_MATCH, if_match);
105        }
106
107        if let Some(if_none_match) = args.if_none_match() {
108            req = req.header(IF_NONE_MATCH, if_none_match);
109        }
110
111        if let Some(auth) = &self.authorization {
112            req = req.header(header::AUTHORIZATION, auth.clone())
113        }
114
115        let req = req.extension(Operation::Stat);
116
117        req.body(Buffer::new()).map_err(new_request_build_error)
118    }
119
120    pub async fn http_head(&self, path: &str, args: &OpStat) -> Result<Response<Buffer>> {
121        let req = self.http_head_request(path, args)?;
122        self.info.http_client().send(req).await
123    }
124}