• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2024 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use cxx::SharedPtr;
15 
16 use crate::error::{HttpClientError, HttpErrorCode};
17 use crate::request::RequestCallback;
18 use crate::response::{Response, ResponseCode};
19 use crate::task::{RequestTask, TaskStatus};
20 
21 pub struct CallbackWrapper {
22     inner: Box<dyn RequestCallback>,
23 }
24 
25 impl CallbackWrapper {
from_callback(inner: impl RequestCallback + 'static) -> Self26     pub(crate) fn from_callback(inner: impl RequestCallback + 'static) -> Self {
27         Self {
28             inner: Box::new(inner),
29         }
30     }
31 }
32 
33 impl CallbackWrapper {
on_success(&mut self, response: &ffi::HttpClientResponse)34     fn on_success(&mut self, response: &ffi::HttpClientResponse) {
35         let response = Response::from_ffi(response);
36         if (response.status().clone() as u32 >= 300) || (response.status().clone() as u32) < 200 {
37             let error =
38                 HttpClientError::new(HttpErrorCode::HttpNoneErr, response.status().to_string());
39             self.inner.on_fail(error);
40         } else {
41             self.inner.on_success(response);
42         }
43     }
44 
on_fail(&mut self, error: &ffi::HttpClientError)45     fn on_fail(&mut self, error: &ffi::HttpClientError) {
46         let error = HttpClientError::from_ffi(error);
47         if *error.code() == HttpErrorCode::HttpWriteError {
48             self.inner.on_cancel();
49         } else {
50             self.inner.on_fail(error);
51         }
52     }
53 
on_cancel(&mut self, _response: &ffi::HttpClientResponse)54     fn on_cancel(&mut self, _response: &ffi::HttpClientResponse) {
55         self.inner.on_cancel();
56     }
on_data_receive( &mut self, task: SharedPtr<ffi::HttpClientTask>, data: *const u8, size: usize, )57     fn on_data_receive(
58         &mut self,
59         task: SharedPtr<ffi::HttpClientTask>,
60         data: *const u8,
61         size: usize,
62     ) {
63         let data = unsafe { std::slice::from_raw_parts(data, size) };
64         let task = RequestTask::from_ffi(task);
65         self.inner.on_data_receive(data, task);
66     }
on_progress(&mut self, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64)67     fn on_progress(&mut self, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64) {
68         self.inner.on_progress(dl_total, dl_now, ul_total, ul_now);
69     }
70 }
71 
72 #[allow(unused_unsafe)]
73 #[cxx::bridge(namespace = "OHOS::Request")]
74 pub(crate) mod ffi {
75     extern "Rust" {
76         type CallbackWrapper;
on_success(self: &mut CallbackWrapper, response: &HttpClientResponse)77         fn on_success(self: &mut CallbackWrapper, response: &HttpClientResponse);
on_fail(self: &mut CallbackWrapper, error: &HttpClientError)78         fn on_fail(self: &mut CallbackWrapper, error: &HttpClientError);
on_cancel(self: &mut CallbackWrapper, response: &HttpClientResponse)79         fn on_cancel(self: &mut CallbackWrapper, response: &HttpClientResponse);
on_data_receive( self: &mut CallbackWrapper, task: SharedPtr<HttpClientTask>, data: *const u8, size: usize, )80         unsafe fn on_data_receive(
81             self: &mut CallbackWrapper,
82             task: SharedPtr<HttpClientTask>,
83             data: *const u8,
84             size: usize,
85         );
on_progress( self: &mut CallbackWrapper, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64, )86         fn on_progress(
87             self: &mut CallbackWrapper,
88             dl_total: u64,
89             dl_now: u64,
90             ul_total: u64,
91             ul_now: u64,
92         );
93     }
94 
95     unsafe extern "C++" {
96         include!("http_client_request.h");
97         include!("wrapper.h");
98         include!("http_client_task.h");
99 
100         #[namespace = "OHOS::NetStack::HttpClient"]
101         type TaskStatus;
102 
103         #[namespace = "OHOS::NetStack::HttpClient"]
104         type ResponseCode;
105 
106         #[namespace = "OHOS::NetStack::HttpClient"]
107         type HttpClientRequest;
108 
109         #[namespace = "OHOS::NetStack::HttpClient"]
110         type HttpErrorCode;
111 
NewHttpClientRequest() -> UniquePtr<HttpClientRequest>112         fn NewHttpClientRequest() -> UniquePtr<HttpClientRequest>;
SetURL(self: Pin<&mut HttpClientRequest>, url: &CxxString)113         fn SetURL(self: Pin<&mut HttpClientRequest>, url: &CxxString);
SetMethod(self: Pin<&mut HttpClientRequest>, method: &CxxString)114         fn SetMethod(self: Pin<&mut HttpClientRequest>, method: &CxxString);
SetHeader(self: Pin<&mut HttpClientRequest>, key: &CxxString, val: &CxxString)115         fn SetHeader(self: Pin<&mut HttpClientRequest>, key: &CxxString, val: &CxxString);
SetTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32)116         fn SetTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32);
SetConnectTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32)117         fn SetConnectTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32);
SetBody(request: Pin<&mut HttpClientRequest>, data: *const u8, length: usize)118         unsafe fn SetBody(request: Pin<&mut HttpClientRequest>, data: *const u8, length: usize);
119 
120         #[namespace = "OHOS::NetStack::HttpClient"]
121         type HttpClientTask;
122 
NewHttpClientTask(request: &HttpClientRequest) -> SharedPtr<HttpClientTask>123         fn NewHttpClientTask(request: &HttpClientRequest) -> SharedPtr<HttpClientTask>;
GetResponse(self: Pin<&mut HttpClientTask>) -> Pin<&mut HttpClientResponse>124         fn GetResponse(self: Pin<&mut HttpClientTask>) -> Pin<&mut HttpClientResponse>;
Start(self: Pin<&mut HttpClientTask>) -> bool125         fn Start(self: Pin<&mut HttpClientTask>) -> bool;
Cancel(self: Pin<&mut HttpClientTask>)126         fn Cancel(self: Pin<&mut HttpClientTask>);
GetStatus(self: Pin<&mut HttpClientTask>) -> TaskStatus127         fn GetStatus(self: Pin<&mut HttpClientTask>) -> TaskStatus;
OnCallback(task: SharedPtr<HttpClientTask>, callback: Box<CallbackWrapper>)128         fn OnCallback(task: SharedPtr<HttpClientTask>, callback: Box<CallbackWrapper>);
129 
130         #[namespace = "OHOS::NetStack::HttpClient"]
131         type HttpClientResponse;
132 
GetResponseCode(self: &HttpClientResponse) -> ResponseCode133         fn GetResponseCode(self: &HttpClientResponse) -> ResponseCode;
GetHeaders(response: Pin<&mut HttpClientResponse>) -> Vec<String>134         fn GetHeaders(response: Pin<&mut HttpClientResponse>) -> Vec<String>;
135 
136         #[namespace = "OHOS::NetStack::HttpClient"]
137         type HttpClientError;
138 
GetErrorCode(self: &HttpClientError) -> HttpErrorCode139         fn GetErrorCode(self: &HttpClientError) -> HttpErrorCode;
GetErrorMessage(self: &HttpClientError) -> &CxxString140         fn GetErrorMessage(self: &HttpClientError) -> &CxxString;
141     }
142 
143     #[repr(i32)]
144     #[derive(Debug)]
145     enum TaskStatus {
146         IDLE,
147         RUNNING,
148     }
149 
150     #[repr(i32)]
151     #[derive(Debug)]
152     enum ResponseCode {
153         NONE = 0,
154         OK = 200,
155         CREATED,
156         ACCEPTED,
157         NOT_AUTHORITATIVE,
158         NO_CONTENT,
159         RESET,
160         PARTIAL,
161         MULT_CHOICE = 300,
162         MOVED_PERM,
163         MOVED_TEMP,
164         SEE_OTHER,
165         NOT_MODIFIED,
166         USE_PROXY,
167         BAD_REQUEST = 400,
168         UNAUTHORIZED,
169         PAYMENT_REQUIRED,
170         FORBIDDEN,
171         NOT_FOUND,
172         BAD_METHOD,
173         NOT_ACCEPTABLE,
174         PROXY_AUTH,
175         CLIENT_TIMEOUT,
176         CONFLICT,
177         GONE,
178         LENGTH_REQUIRED,
179         PRECON_FAILED,
180         ENTITY_TOO_LARGE,
181         REQ_TOO_LONG,
182         UNSUPPORTED_TYPE,
183         INTERNAL_ERROR = 500,
184         NOT_IMPLEMENTED,
185         BAD_GATEWAY,
186         UNAVAILABLE,
187         GATEWAY_TIMEOUT,
188         VERSION,
189     }
190 
191     #[repr(i32)]
192     #[derive(Debug)]
193     enum HttpErrorCode {
194         HTTP_NONE_ERR,
195         HTTP_PERMISSION_DENIED_CODE = 201,
196         HTTP_PARSE_ERROR_CODE = 401,
197         HTTP_ERROR_CODE_BASE = 2300000,
198         HTTP_UNSUPPORTED_PROTOCOL,
199         HTTP_FAILED_INIT,
200         HTTP_URL_MALFORMAT,
201         HTTP_COULDNT_RESOLVE_PROXY = 2300005,
202         HTTP_COULDNT_RESOLVE_HOST,
203         HTTP_COULDNT_CONNECT,
204         HTTP_WEIRD_SERVER_REPLY,
205         HTTP_REMOTE_ACCESS_DENIED,
206         HTTP_HTTP2_ERROR = 2300016,
207         HTTP_PARTIAL_FILE = 2300018,
208         HTTP_WRITE_ERROR = 2300023,
209         HTTP_UPLOAD_FAILED = 2300025,
210         HTTP_READ_ERROR = 2300026,
211         HTTP_OUT_OF_MEMORY,
212         HTTP_OPERATION_TIMEDOUT,
213         HTTP_POST_ERROR = 2300034,
214         HTTP_TASK_CANCELED = 2300042,
215         HTTP_TOO_MANY_REDIRECTS = 2300047,
216         HTTP_GOT_NOTHING = 2300052,
217         HTTP_SEND_ERROR = 2300055,
218         HTTP_RECV_ERROR,
219         HTTP_SSL_CERTPROBLEM = 2300058,
220         HTTP_SSL_CIPHER,
221         HTTP_PEER_FAILED_VERIFICATION,
222         HTTP_BAD_CONTENT_ENCODING,
223         HTTP_FILESIZE_EXCEEDED = 2300063,
224         HTTP_REMOTE_DISK_FULL = 2300070,
225         HTTP_REMOTE_FILE_EXISTS = 2300073,
226         HTTP_SSL_CACERT_BADFILE = 2300077,
227         HTTP_REMOTE_FILE_NOT_FOUND,
228         HTTP_AUTH_ERROR = 2300094,
229         HTTP_UNKNOWN_OTHER_ERROR = 2300999,
230     }
231 }
232 
233 impl TryFrom<ffi::TaskStatus> for TaskStatus {
234     type Error = ffi::TaskStatus;
try_from(status: ffi::TaskStatus) -> Result<Self, Self::Error>235     fn try_from(status: ffi::TaskStatus) -> Result<Self, Self::Error> {
236         let ret = match status {
237             ffi::TaskStatus::IDLE => TaskStatus::Idle,
238             ffi::TaskStatus::RUNNING => TaskStatus::Running,
239             _ => {
240                 return Err(status);
241             }
242         };
243         Ok(ret)
244     }
245 }
246 
247 impl TryFrom<ffi::ResponseCode> for ResponseCode {
248     type Error = ffi::ResponseCode;
try_from(value: ffi::ResponseCode) -> Result<Self, Self::Error>249     fn try_from(value: ffi::ResponseCode) -> Result<Self, Self::Error> {
250         let ret = match value {
251             ffi::ResponseCode::NONE => ResponseCode::None,
252             ffi::ResponseCode::OK => ResponseCode::Ok,
253             ffi::ResponseCode::CREATED => ResponseCode::Created,
254             ffi::ResponseCode::ACCEPTED => ResponseCode::Accepted,
255             ffi::ResponseCode::NOT_AUTHORITATIVE => ResponseCode::NotAuthoritative,
256             ffi::ResponseCode::NO_CONTENT => ResponseCode::NoContent,
257             ffi::ResponseCode::RESET => ResponseCode::Reset,
258             ffi::ResponseCode::PARTIAL => ResponseCode::Partial,
259             ffi::ResponseCode::MULT_CHOICE => ResponseCode::MultChoice,
260             ffi::ResponseCode::MOVED_PERM => ResponseCode::MovedPerm,
261             ffi::ResponseCode::MOVED_TEMP => ResponseCode::MovedTemp,
262             ffi::ResponseCode::SEE_OTHER => ResponseCode::SeeOther,
263             ffi::ResponseCode::NOT_MODIFIED => ResponseCode::NotModified,
264             ffi::ResponseCode::USE_PROXY => ResponseCode::UseProxy,
265             ffi::ResponseCode::BAD_REQUEST => ResponseCode::BadRequest,
266             ffi::ResponseCode::UNAUTHORIZED => ResponseCode::Unauthorized,
267             ffi::ResponseCode::PAYMENT_REQUIRED => ResponseCode::PaymentRequired,
268             ffi::ResponseCode::FORBIDDEN => ResponseCode::Forbidden,
269             ffi::ResponseCode::NOT_FOUND => ResponseCode::NotFound,
270             ffi::ResponseCode::BAD_METHOD => ResponseCode::BadMethod,
271             ffi::ResponseCode::NOT_ACCEPTABLE => ResponseCode::NotAcceptable,
272             ffi::ResponseCode::PROXY_AUTH => ResponseCode::ProxyAuth,
273             ffi::ResponseCode::CLIENT_TIMEOUT => ResponseCode::ClientTimeout,
274             ffi::ResponseCode::CONFLICT => ResponseCode::Conflict,
275             ffi::ResponseCode::GONE => ResponseCode::Gone,
276             ffi::ResponseCode::LENGTH_REQUIRED => ResponseCode::LengthRequired,
277             ffi::ResponseCode::PRECON_FAILED => ResponseCode::PreconFailed,
278             ffi::ResponseCode::ENTITY_TOO_LARGE => ResponseCode::EntityTooLarge,
279             ffi::ResponseCode::REQ_TOO_LONG => ResponseCode::ReqTooLong,
280             ffi::ResponseCode::UNSUPPORTED_TYPE => ResponseCode::UnsupportedType,
281             ffi::ResponseCode::INTERNAL_ERROR => ResponseCode::InternalError,
282             ffi::ResponseCode::NOT_IMPLEMENTED => ResponseCode::NotImplemented,
283             ffi::ResponseCode::BAD_GATEWAY => ResponseCode::BadGateway,
284             ffi::ResponseCode::UNAVAILABLE => ResponseCode::Unavailable,
285             ffi::ResponseCode::GATEWAY_TIMEOUT => ResponseCode::GatewayTimeout,
286             ffi::ResponseCode::VERSION => ResponseCode::Version,
287             _ => {
288                 return Err(value);
289             }
290         };
291         Ok(ret)
292     }
293 }
294 
295 impl TryFrom<ffi::HttpErrorCode> for HttpErrorCode {
296     type Error = ffi::HttpErrorCode;
try_from(value: ffi::HttpErrorCode) -> Result<Self, Self::Error>297     fn try_from(value: ffi::HttpErrorCode) -> Result<Self, Self::Error> {
298         let ret = match value {
299             ffi::HttpErrorCode::HTTP_NONE_ERR => HttpErrorCode::HttpNoneErr,
300             ffi::HttpErrorCode::HTTP_PERMISSION_DENIED_CODE => {
301                 HttpErrorCode::HttpPermissionDeniedCode
302             }
303             ffi::HttpErrorCode::HTTP_PARSE_ERROR_CODE => HttpErrorCode::HttpParseErrorCode,
304             ffi::HttpErrorCode::HTTP_ERROR_CODE_BASE => HttpErrorCode::HttpErrorCodeBase,
305             ffi::HttpErrorCode::HTTP_UNSUPPORTED_PROTOCOL => HttpErrorCode::HttpUnsupportedProtocol,
306             ffi::HttpErrorCode::HTTP_FAILED_INIT => HttpErrorCode::HttpFailedInit,
307             ffi::HttpErrorCode::HTTP_URL_MALFORMAT => HttpErrorCode::HttpUrlMalformat,
308             ffi::HttpErrorCode::HTTP_COULDNT_RESOLVE_PROXY => {
309                 HttpErrorCode::HttpCouldntResolveProxy
310             }
311             ffi::HttpErrorCode::HTTP_COULDNT_RESOLVE_HOST => HttpErrorCode::HttpCouldntResolveHost,
312             ffi::HttpErrorCode::HTTP_COULDNT_CONNECT => HttpErrorCode::HttpCouldntConnect,
313             ffi::HttpErrorCode::HTTP_WEIRD_SERVER_REPLY => HttpErrorCode::HttpWeirdServerReply,
314             ffi::HttpErrorCode::HTTP_REMOTE_ACCESS_DENIED => HttpErrorCode::HttpRemoteAccessDenied,
315             ffi::HttpErrorCode::HTTP_HTTP2_ERROR => HttpErrorCode::HttpHttp2Error,
316             ffi::HttpErrorCode::HTTP_PARTIAL_FILE => HttpErrorCode::HttpPartialFile,
317             ffi::HttpErrorCode::HTTP_WRITE_ERROR => HttpErrorCode::HttpWriteError,
318             ffi::HttpErrorCode::HTTP_UPLOAD_FAILED => HttpErrorCode::HttpUploadFailed,
319             ffi::HttpErrorCode::HTTP_READ_ERROR => HttpErrorCode::HttpReadError,
320             ffi::HttpErrorCode::HTTP_OUT_OF_MEMORY => HttpErrorCode::HttpOutOfMemory,
321             ffi::HttpErrorCode::HTTP_OPERATION_TIMEDOUT => HttpErrorCode::HttpOperationTimedout,
322             ffi::HttpErrorCode::HTTP_POST_ERROR => HttpErrorCode::HttpPostError,
323             ffi::HttpErrorCode::HTTP_TASK_CANCELED => HttpErrorCode::HttpTaskCanceled,
324             ffi::HttpErrorCode::HTTP_TOO_MANY_REDIRECTS => HttpErrorCode::HttpTooManyRedirects,
325             ffi::HttpErrorCode::HTTP_GOT_NOTHING => HttpErrorCode::HttpGotNothing,
326             ffi::HttpErrorCode::HTTP_SEND_ERROR => HttpErrorCode::HttpSendError,
327             ffi::HttpErrorCode::HTTP_RECV_ERROR => HttpErrorCode::HttpRecvError,
328             ffi::HttpErrorCode::HTTP_SSL_CERTPROBLEM => HttpErrorCode::HttpSslCertproblem,
329             ffi::HttpErrorCode::HTTP_SSL_CIPHER => HttpErrorCode::HttpSslCipher,
330             ffi::HttpErrorCode::HTTP_PEER_FAILED_VERIFICATION => {
331                 HttpErrorCode::HttpPeerFailedVerification
332             }
333             ffi::HttpErrorCode::HTTP_BAD_CONTENT_ENCODING => HttpErrorCode::HttpBadContentEncoding,
334             ffi::HttpErrorCode::HTTP_FILESIZE_EXCEEDED => HttpErrorCode::HttpFilesizeExceeded,
335             ffi::HttpErrorCode::HTTP_REMOTE_DISK_FULL => HttpErrorCode::HttpRemoteDiskFull,
336             ffi::HttpErrorCode::HTTP_REMOTE_FILE_EXISTS => HttpErrorCode::HttpRemoteFileExists,
337             ffi::HttpErrorCode::HTTP_SSL_CACERT_BADFILE => HttpErrorCode::HttpSslCacertBadfile,
338             ffi::HttpErrorCode::HTTP_REMOTE_FILE_NOT_FOUND => HttpErrorCode::HttpRemoteFileNotFound,
339             ffi::HttpErrorCode::HTTP_AUTH_ERROR => HttpErrorCode::HttpAuthError,
340             ffi::HttpErrorCode::HTTP_UNKNOWN_OTHER_ERROR => HttpErrorCode::HttpUnknownOtherError,
341             _ => {
342                 return Err(value);
343             }
344         };
345         Ok(ret)
346     }
347 }
348