• 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 std::pin::Pin;
15 use std::sync::atomic::{AtomicBool, Ordering};
16 use std::sync::{Arc, Mutex, Weak};
17 
18 use cxx::SharedPtr;
19 use ffi::{
20     GetPerformanceInfo, GetResolvConf, HttpClientRequest, HttpClientTask, NewHttpClientTask,
21     OnCallback,
22 };
23 use ffrt_rs::{ffrt_sleep, ffrt_spawn};
24 use request_utils::error;
25 use request_utils::task_id::TaskId;
26 
27 use crate::error::{HttpClientError, HttpErrorCode};
28 use crate::info::{DownloadInfo, DownloadInfoMgr, RustPerformanceInfo};
29 use crate::request::RequestCallback;
30 use crate::response::{Response, ResponseCode};
31 use crate::task::{RequestTask, TaskStatus};
32 
33 enum NewTaskResult {
34     Success(SharedPtr<HttpClientTask>, Box<CallbackWrapper>),
35     Failed(Box<dyn RequestCallback>),
36 }
37 
38 pub struct CallbackWrapper {
39     inner: Option<Box<dyn RequestCallback>>,
40     // TODO This reset flag has never been assigned to true. Does it look useless?
41     reset: Arc<AtomicBool>,
42     task: Weak<Mutex<SharedPtr<HttpClientTask>>>,
43     task_id: TaskId,
44     info: DownloadInfo,
45     info_mgr: Arc<DownloadInfoMgr>,
46     tries: usize,
47     current: u64,
48 }
49 
50 impl CallbackWrapper {
from_callback( inner: Box<dyn RequestCallback + 'static>, reset: Arc<AtomicBool>, task: Weak<Mutex<SharedPtr<HttpClientTask>>>, task_id: TaskId, info_mgr: Arc<DownloadInfoMgr>, current: u64, ) -> Self51     pub(crate) fn from_callback(
52         inner: Box<dyn RequestCallback + 'static>,
53         reset: Arc<AtomicBool>,
54         task: Weak<Mutex<SharedPtr<HttpClientTask>>>,
55         task_id: TaskId,
56         info_mgr: Arc<DownloadInfoMgr>,
57         current: u64,
58     ) -> Self {
59         let mut info = DownloadInfo::new();
60         let dns = GetResolvConf();
61         info.set_network_dns(dns);
62         Self {
63             inner: Some(inner),
64             reset,
65             task,
66             task_id,
67             info,
68             info_mgr,
69             tries: 0,
70             current,
71         }
72     }
73 }
74 
75 impl CallbackWrapper {
on_success(&mut self, _request: &HttpClientRequest, response: &ffi::HttpClientResponse)76     fn on_success(&mut self, _request: &HttpClientRequest, response: &ffi::HttpClientResponse) {
77         let mut performance = RustPerformanceInfo::default();
78         GetPerformanceInfo(response, Pin::new(&mut performance));
79         self.info.set_performance(performance);
80         self.info.set_size(self.current as i64);
81         self.info_mgr
82             .insert_download_info(self.task_id.clone(), self.info.clone());
83 
84         let Some(mut callback) = self.inner.take() else {
85             return;
86         };
87         let response = Response::from_ffi(response);
88         if (response.status().clone() as u32 >= 300) || (response.status().clone() as u32) < 200 {
89             let error = HttpClientError::new(
90                 HttpErrorCode::HttpNoneErr,
91                 (response.status() as u32).to_string(),
92             );
93             callback.on_fail(error);
94         } else {
95             callback.on_success(response);
96         }
97     }
98 
on_fail( &mut self, request: &HttpClientRequest, response: &ffi::HttpClientResponse, error: &ffi::HttpClientError, )99     fn on_fail(
100         &mut self,
101         request: &HttpClientRequest,
102         response: &ffi::HttpClientResponse,
103         error: &ffi::HttpClientError,
104     ) {
105         let mut performance = RustPerformanceInfo::default();
106         GetPerformanceInfo(response, Pin::new(&mut performance));
107         self.info.set_performance(performance);
108         self.info.set_size(self.current as i64);
109         self.info_mgr
110             .insert_download_info(self.task_id.clone(), self.info.clone());
111         let error = HttpClientError::from_ffi(error);
112         if *error.code() == HttpErrorCode::HttpWriteError {
113             self.on_cancel(request, response);
114             return;
115         }
116         let Some(callback) = self.inner.take() else {
117             return;
118         };
119 
120         let (new_task, mut new_callback) = match self.create_new_task(callback, request) {
121             NewTaskResult::Success(new_task, new_callback) => (new_task, new_callback),
122             NewTaskResult::Failed(mut callback) => {
123                 callback.on_fail(error);
124                 return;
125             }
126         };
127 
128         if self.tries < 3 {
129             self.tries += 1;
130             new_callback.tries = self.tries;
131             Self::start_new_task(new_task, new_callback);
132             return;
133         }
134 
135         let reset = self.reset.clone();
136         ffrt_spawn(move || {
137             for _ in 0..20 {
138                 ffrt_sleep(1000);
139                 if reset.load(Ordering::SeqCst) {
140                     Self::start_new_task(new_task, new_callback);
141                     reset.store(false, Ordering::SeqCst);
142                     return;
143                 }
144             }
145             if let Some(mut callback) = new_callback.inner {
146                 callback.on_fail(error);
147             }
148         });
149     }
150 
on_cancel(&mut self, request: &HttpClientRequest, _response: &ffi::HttpClientResponse)151     fn on_cancel(&mut self, request: &HttpClientRequest, _response: &ffi::HttpClientResponse) {
152         let Some(mut callback) = self.inner.take() else {
153             return;
154         };
155 
156         if self.reset.load(Ordering::SeqCst) {
157             let (new_task, new_callback) = match self.create_new_task(callback, request) {
158                 NewTaskResult::Success(new_task, new_callback) => (new_task, new_callback),
159                 NewTaskResult::Failed(mut callback) => {
160                     callback.on_cancel();
161                     return;
162                 }
163             };
164             Self::start_new_task(new_task, new_callback);
165             self.reset.store(false, Ordering::SeqCst);
166         } else {
167             callback.on_cancel();
168         }
169     }
170 
on_data_receive( &mut self, task: SharedPtr<ffi::HttpClientTask>, data: *const u8, size: usize, )171     fn on_data_receive(
172         &mut self,
173         task: SharedPtr<ffi::HttpClientTask>,
174         data: *const u8,
175         size: usize,
176     ) {
177         let Some(callback) = self.inner.as_mut() else {
178             return;
179         };
180         self.current += size as u64;
181         let data = unsafe { std::slice::from_raw_parts(data, size) };
182         let task = RequestTask::from_ffi(task);
183         callback.on_data_receive(data, task);
184     }
185 
on_progress(&mut self, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64)186     fn on_progress(&mut self, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64) {
187         let Some(callback) = self.inner.as_mut() else {
188             return;
189         };
190         callback.on_progress(dl_total, dl_now, ul_total, ul_now);
191     }
192 
create_new_task( &mut self, mut callback: Box<dyn RequestCallback>, request: &HttpClientRequest, ) -> NewTaskResult193     fn create_new_task(
194         &mut self,
195         mut callback: Box<dyn RequestCallback>,
196         request: &HttpClientRequest,
197     ) -> NewTaskResult {
198         if self.current > 0 {
199             callback.on_restart();
200         }
201 
202         let new_task = NewHttpClientTask(request);
203         if new_task.is_null() {
204             error!("create_new_task NewHttpClientTask return null.");
205             return NewTaskResult::Failed(callback);
206         }
207         let new_callback = Box::new(CallbackWrapper::from_callback(
208             callback,
209             self.reset.clone(),
210             self.task.clone(),
211             self.task_id.clone(),
212             self.info_mgr.clone(),
213             0,
214         ));
215         NewTaskResult::Success(new_task, new_callback)
216     }
217 
start_new_task(task: SharedPtr<HttpClientTask>, callback: Box<CallbackWrapper>)218     fn start_new_task(task: SharedPtr<HttpClientTask>, callback: Box<CallbackWrapper>) {
219         if let Some(r) = callback.task.upgrade() {
220             *r.lock().unwrap() = task.clone();
221         }
222         OnCallback(&task, callback);
223         // TODO start may return false. Not handling it may result in no callback, which
224         // the caller cannot perceive
225         RequestTask::pin_mut(&task).Start();
226     }
227 }
228 
229 unsafe impl Send for HttpClientTask {}
230 unsafe impl Sync for HttpClientTask {}
231 
232 #[allow(unused_unsafe)]
233 #[cxx::bridge(namespace = "OHOS::Request")]
234 pub(crate) mod ffi {
235     extern "Rust" {
236         type CallbackWrapper;
on_success( self: &mut CallbackWrapper, request: &HttpClientRequest, response: &HttpClientResponse, )237         fn on_success(
238             self: &mut CallbackWrapper,
239             request: &HttpClientRequest,
240             response: &HttpClientResponse,
241         );
on_fail( self: &mut CallbackWrapper, request: &HttpClientRequest, response: &HttpClientResponse, error: &HttpClientError, )242         fn on_fail(
243             self: &mut CallbackWrapper,
244             request: &HttpClientRequest,
245             response: &HttpClientResponse,
246             error: &HttpClientError,
247         );
on_cancel( self: &mut CallbackWrapper, request: &HttpClientRequest, response: &HttpClientResponse, )248         fn on_cancel(
249             self: &mut CallbackWrapper,
250             request: &HttpClientRequest,
251             response: &HttpClientResponse,
252         );
on_data_receive( self: &mut CallbackWrapper, task: SharedPtr<HttpClientTask>, data: *const u8, size: usize, )253         unsafe fn on_data_receive(
254             self: &mut CallbackWrapper,
255             task: SharedPtr<HttpClientTask>,
256             data: *const u8,
257             size: usize,
258         );
on_progress( self: &mut CallbackWrapper, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64, )259         fn on_progress(
260             self: &mut CallbackWrapper,
261             dl_total: u64,
262             dl_now: u64,
263             ul_total: u64,
264             ul_now: u64,
265         );
266 
267         type RustPerformanceInfo;
set_dns_timing(self: &mut RustPerformanceInfo, time: f64)268         fn set_dns_timing(self: &mut RustPerformanceInfo, time: f64);
set_connect_timing(self: &mut RustPerformanceInfo, time: f64)269         fn set_connect_timing(self: &mut RustPerformanceInfo, time: f64);
set_tls_timing(self: &mut RustPerformanceInfo, time: f64)270         fn set_tls_timing(self: &mut RustPerformanceInfo, time: f64);
set_first_send_timing(self: &mut RustPerformanceInfo, time: f64)271         fn set_first_send_timing(self: &mut RustPerformanceInfo, time: f64);
set_first_receive_timing(self: &mut RustPerformanceInfo, time: f64)272         fn set_first_receive_timing(self: &mut RustPerformanceInfo, time: f64);
set_total_timing(self: &mut RustPerformanceInfo, time: f64)273         fn set_total_timing(self: &mut RustPerformanceInfo, time: f64);
set_redirect_timing(self: &mut RustPerformanceInfo, time: f64)274         fn set_redirect_timing(self: &mut RustPerformanceInfo, time: f64);
275     }
276 
277     unsafe extern "C++" {
278         include!("http_client_request.h");
279         include!("wrapper.h");
280         include!("http_client_task.h");
281 
282         #[namespace = "OHOS::NetStack::HttpClient"]
283         type TaskStatus;
284 
285         #[namespace = "OHOS::NetStack::HttpClient"]
286         type ResponseCode;
287 
288         #[namespace = "OHOS::NetStack::HttpClient"]
289         type HttpClientRequest;
290 
291         #[namespace = "OHOS::NetStack::HttpClient"]
292         type HttpErrorCode;
293 
NewHttpClientRequest() -> UniquePtr<HttpClientRequest>294         fn NewHttpClientRequest() -> UniquePtr<HttpClientRequest>;
SetURL(self: Pin<&mut HttpClientRequest>, url: &CxxString)295         fn SetURL(self: Pin<&mut HttpClientRequest>, url: &CxxString);
SetMethod(self: Pin<&mut HttpClientRequest>, method: &CxxString)296         fn SetMethod(self: Pin<&mut HttpClientRequest>, method: &CxxString);
SetHeader(self: Pin<&mut HttpClientRequest>, key: &CxxString, val: &CxxString)297         fn SetHeader(self: Pin<&mut HttpClientRequest>, key: &CxxString, val: &CxxString);
SetTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32)298         fn SetTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32);
SetConnectTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32)299         fn SetConnectTimeout(self: Pin<&mut HttpClientRequest>, timeout: u32);
SetBody(request: Pin<&mut HttpClientRequest>, data: *const u8, length: usize)300         unsafe fn SetBody(request: Pin<&mut HttpClientRequest>, data: *const u8, length: usize);
301 
302         #[namespace = "OHOS::NetStack::HttpClient"]
303         type HttpClientTask;
304 
NewHttpClientTask(request: &HttpClientRequest) -> SharedPtr<HttpClientTask>305         fn NewHttpClientTask(request: &HttpClientRequest) -> SharedPtr<HttpClientTask>;
GetResponse(self: Pin<&mut HttpClientTask>) -> Pin<&mut HttpClientResponse>306         fn GetResponse(self: Pin<&mut HttpClientTask>) -> Pin<&mut HttpClientResponse>;
Start(self: Pin<&mut HttpClientTask>) -> bool307         fn Start(self: Pin<&mut HttpClientTask>) -> bool;
Cancel(self: Pin<&mut HttpClientTask>)308         fn Cancel(self: Pin<&mut HttpClientTask>);
GetStatus(self: Pin<&mut HttpClientTask>) -> TaskStatus309         fn GetStatus(self: Pin<&mut HttpClientTask>) -> TaskStatus;
OnCallback(task: &SharedPtr<HttpClientTask>, callback: Box<CallbackWrapper>)310         fn OnCallback(task: &SharedPtr<HttpClientTask>, callback: Box<CallbackWrapper>);
311 
312         #[namespace = "OHOS::NetStack::HttpClient"]
313         type HttpClientResponse;
314 
GetResponseCode(self: &HttpClientResponse) -> ResponseCode315         fn GetResponseCode(self: &HttpClientResponse) -> ResponseCode;
GetHeaders(response: Pin<&mut HttpClientResponse>) -> Vec<String>316         fn GetHeaders(response: Pin<&mut HttpClientResponse>) -> Vec<String>;
GetResolvConf() -> Vec<String>317         fn GetResolvConf() -> Vec<String>;
318 
319         #[namespace = "OHOS::NetStack::HttpClient"]
320         type HttpClientError;
321 
GetErrorCode(self: &HttpClientError) -> HttpErrorCode322         fn GetErrorCode(self: &HttpClientError) -> HttpErrorCode;
GetErrorMessage(self: &HttpClientError) -> &CxxString323         fn GetErrorMessage(self: &HttpClientError) -> &CxxString;
324 
GetPerformanceInfo( response: &HttpClientResponse, performance: Pin<&mut RustPerformanceInfo>, )325         fn GetPerformanceInfo(
326             response: &HttpClientResponse,
327             performance: Pin<&mut RustPerformanceInfo>,
328         );
329     }
330 
331     #[repr(i32)]
332     enum TaskStatus {
333         IDLE,
334         RUNNING,
335     }
336 
337     #[repr(i32)]
338     enum ResponseCode {
339         NONE = 0,
340         OK = 200,
341         CREATED,
342         ACCEPTED,
343         NOT_AUTHORITATIVE,
344         NO_CONTENT,
345         RESET,
346         PARTIAL,
347         MULT_CHOICE = 300,
348         MOVED_PERM,
349         MOVED_TEMP,
350         SEE_OTHER,
351         NOT_MODIFIED,
352         USE_PROXY,
353         BAD_REQUEST = 400,
354         UNAUTHORIZED,
355         PAYMENT_REQUIRED,
356         FORBIDDEN,
357         NOT_FOUND,
358         BAD_METHOD,
359         NOT_ACCEPTABLE,
360         PROXY_AUTH,
361         CLIENT_TIMEOUT,
362         CONFLICT,
363         GONE,
364         LENGTH_REQUIRED,
365         PRECON_FAILED,
366         ENTITY_TOO_LARGE,
367         REQ_TOO_LONG,
368         UNSUPPORTED_TYPE,
369         INTERNAL_ERROR = 500,
370         NOT_IMPLEMENTED,
371         BAD_GATEWAY,
372         UNAVAILABLE,
373         GATEWAY_TIMEOUT,
374         VERSION,
375     }
376 
377     #[repr(i32)]
378     enum HttpErrorCode {
379         HTTP_NONE_ERR,
380         HTTP_PERMISSION_DENIED_CODE = 201,
381         HTTP_PARSE_ERROR_CODE = 401,
382         HTTP_ERROR_CODE_BASE = 2300000,
383         HTTP_UNSUPPORTED_PROTOCOL,
384         HTTP_FAILED_INIT,
385         HTTP_URL_MALFORMAT,
386         HTTP_COULDNT_RESOLVE_PROXY = 2300005,
387         HTTP_COULDNT_RESOLVE_HOST,
388         HTTP_COULDNT_CONNECT,
389         HTTP_WEIRD_SERVER_REPLY,
390         HTTP_REMOTE_ACCESS_DENIED,
391         HTTP_HTTP2_ERROR = 2300016,
392         HTTP_PARTIAL_FILE = 2300018,
393         HTTP_WRITE_ERROR = 2300023,
394         HTTP_UPLOAD_FAILED = 2300025,
395         HTTP_READ_ERROR = 2300026,
396         HTTP_OUT_OF_MEMORY,
397         HTTP_OPERATION_TIMEDOUT,
398         HTTP_POST_ERROR = 2300034,
399         HTTP_TASK_CANCELED = 2300042,
400         HTTP_TOO_MANY_REDIRECTS = 2300047,
401         HTTP_GOT_NOTHING = 2300052,
402         HTTP_SEND_ERROR = 2300055,
403         HTTP_RECV_ERROR,
404         HTTP_SSL_CERTPROBLEM = 2300058,
405         HTTP_SSL_CIPHER,
406         HTTP_PEER_FAILED_VERIFICATION,
407         HTTP_BAD_CONTENT_ENCODING,
408         HTTP_FILESIZE_EXCEEDED = 2300063,
409         HTTP_REMOTE_DISK_FULL = 2300070,
410         HTTP_REMOTE_FILE_EXISTS = 2300073,
411         HTTP_SSL_CACERT_BADFILE = 2300077,
412         HTTP_REMOTE_FILE_NOT_FOUND,
413         HTTP_AUTH_ERROR = 2300094,
414         HTTP_UNKNOWN_OTHER_ERROR = 2300999,
415     }
416 }
417 
418 impl TryFrom<ffi::TaskStatus> for TaskStatus {
419     type Error = ffi::TaskStatus;
try_from(status: ffi::TaskStatus) -> Result<Self, Self::Error>420     fn try_from(status: ffi::TaskStatus) -> Result<Self, Self::Error> {
421         let ret = match status {
422             ffi::TaskStatus::IDLE => TaskStatus::Idle,
423             ffi::TaskStatus::RUNNING => TaskStatus::Running,
424             _ => {
425                 return Err(status);
426             }
427         };
428         Ok(ret)
429     }
430 }
431 
432 impl TryFrom<ffi::ResponseCode> for ResponseCode {
433     type Error = ffi::ResponseCode;
try_from(value: ffi::ResponseCode) -> Result<Self, Self::Error>434     fn try_from(value: ffi::ResponseCode) -> Result<Self, Self::Error> {
435         let ret = match value {
436             ffi::ResponseCode::NONE => ResponseCode::None,
437             ffi::ResponseCode::OK => ResponseCode::Ok,
438             ffi::ResponseCode::CREATED => ResponseCode::Created,
439             ffi::ResponseCode::ACCEPTED => ResponseCode::Accepted,
440             ffi::ResponseCode::NOT_AUTHORITATIVE => ResponseCode::NotAuthoritative,
441             ffi::ResponseCode::NO_CONTENT => ResponseCode::NoContent,
442             ffi::ResponseCode::RESET => ResponseCode::Reset,
443             ffi::ResponseCode::PARTIAL => ResponseCode::Partial,
444             ffi::ResponseCode::MULT_CHOICE => ResponseCode::MultChoice,
445             ffi::ResponseCode::MOVED_PERM => ResponseCode::MovedPerm,
446             ffi::ResponseCode::MOVED_TEMP => ResponseCode::MovedTemp,
447             ffi::ResponseCode::SEE_OTHER => ResponseCode::SeeOther,
448             ffi::ResponseCode::NOT_MODIFIED => ResponseCode::NotModified,
449             ffi::ResponseCode::USE_PROXY => ResponseCode::UseProxy,
450             ffi::ResponseCode::BAD_REQUEST => ResponseCode::BadRequest,
451             ffi::ResponseCode::UNAUTHORIZED => ResponseCode::Unauthorized,
452             ffi::ResponseCode::PAYMENT_REQUIRED => ResponseCode::PaymentRequired,
453             ffi::ResponseCode::FORBIDDEN => ResponseCode::Forbidden,
454             ffi::ResponseCode::NOT_FOUND => ResponseCode::NotFound,
455             ffi::ResponseCode::BAD_METHOD => ResponseCode::BadMethod,
456             ffi::ResponseCode::NOT_ACCEPTABLE => ResponseCode::NotAcceptable,
457             ffi::ResponseCode::PROXY_AUTH => ResponseCode::ProxyAuth,
458             ffi::ResponseCode::CLIENT_TIMEOUT => ResponseCode::ClientTimeout,
459             ffi::ResponseCode::CONFLICT => ResponseCode::Conflict,
460             ffi::ResponseCode::GONE => ResponseCode::Gone,
461             ffi::ResponseCode::LENGTH_REQUIRED => ResponseCode::LengthRequired,
462             ffi::ResponseCode::PRECON_FAILED => ResponseCode::PreconFailed,
463             ffi::ResponseCode::ENTITY_TOO_LARGE => ResponseCode::EntityTooLarge,
464             ffi::ResponseCode::REQ_TOO_LONG => ResponseCode::ReqTooLong,
465             ffi::ResponseCode::UNSUPPORTED_TYPE => ResponseCode::UnsupportedType,
466             ffi::ResponseCode::INTERNAL_ERROR => ResponseCode::InternalError,
467             ffi::ResponseCode::NOT_IMPLEMENTED => ResponseCode::NotImplemented,
468             ffi::ResponseCode::BAD_GATEWAY => ResponseCode::BadGateway,
469             ffi::ResponseCode::UNAVAILABLE => ResponseCode::Unavailable,
470             ffi::ResponseCode::GATEWAY_TIMEOUT => ResponseCode::GatewayTimeout,
471             ffi::ResponseCode::VERSION => ResponseCode::Version,
472             _ => {
473                 return Err(value);
474             }
475         };
476         Ok(ret)
477     }
478 }
479 
480 impl TryFrom<ffi::HttpErrorCode> for HttpErrorCode {
481     type Error = ffi::HttpErrorCode;
try_from(value: ffi::HttpErrorCode) -> Result<Self, Self::Error>482     fn try_from(value: ffi::HttpErrorCode) -> Result<Self, Self::Error> {
483         let ret = match value {
484             ffi::HttpErrorCode::HTTP_NONE_ERR => HttpErrorCode::HttpNoneErr,
485             ffi::HttpErrorCode::HTTP_PERMISSION_DENIED_CODE => {
486                 HttpErrorCode::HttpPermissionDeniedCode
487             }
488             ffi::HttpErrorCode::HTTP_PARSE_ERROR_CODE => HttpErrorCode::HttpParseErrorCode,
489             ffi::HttpErrorCode::HTTP_ERROR_CODE_BASE => HttpErrorCode::HttpErrorCodeBase,
490             ffi::HttpErrorCode::HTTP_UNSUPPORTED_PROTOCOL => HttpErrorCode::HttpUnsupportedProtocol,
491             ffi::HttpErrorCode::HTTP_FAILED_INIT => HttpErrorCode::HttpFailedInit,
492             ffi::HttpErrorCode::HTTP_URL_MALFORMAT => HttpErrorCode::HttpUrlMalformat,
493             ffi::HttpErrorCode::HTTP_COULDNT_RESOLVE_PROXY => {
494                 HttpErrorCode::HttpCouldntResolveProxy
495             }
496             ffi::HttpErrorCode::HTTP_COULDNT_RESOLVE_HOST => HttpErrorCode::HttpCouldntResolveHost,
497             ffi::HttpErrorCode::HTTP_COULDNT_CONNECT => HttpErrorCode::HttpCouldntConnect,
498             ffi::HttpErrorCode::HTTP_WEIRD_SERVER_REPLY => HttpErrorCode::HttpWeirdServerReply,
499             ffi::HttpErrorCode::HTTP_REMOTE_ACCESS_DENIED => HttpErrorCode::HttpRemoteAccessDenied,
500             ffi::HttpErrorCode::HTTP_HTTP2_ERROR => HttpErrorCode::HttpHttp2Error,
501             ffi::HttpErrorCode::HTTP_PARTIAL_FILE => HttpErrorCode::HttpPartialFile,
502             ffi::HttpErrorCode::HTTP_WRITE_ERROR => HttpErrorCode::HttpWriteError,
503             ffi::HttpErrorCode::HTTP_UPLOAD_FAILED => HttpErrorCode::HttpUploadFailed,
504             ffi::HttpErrorCode::HTTP_READ_ERROR => HttpErrorCode::HttpReadError,
505             ffi::HttpErrorCode::HTTP_OUT_OF_MEMORY => HttpErrorCode::HttpOutOfMemory,
506             ffi::HttpErrorCode::HTTP_OPERATION_TIMEDOUT => HttpErrorCode::HttpOperationTimedout,
507             ffi::HttpErrorCode::HTTP_POST_ERROR => HttpErrorCode::HttpPostError,
508             ffi::HttpErrorCode::HTTP_TASK_CANCELED => HttpErrorCode::HttpTaskCanceled,
509             ffi::HttpErrorCode::HTTP_TOO_MANY_REDIRECTS => HttpErrorCode::HttpTooManyRedirects,
510             ffi::HttpErrorCode::HTTP_GOT_NOTHING => HttpErrorCode::HttpGotNothing,
511             ffi::HttpErrorCode::HTTP_SEND_ERROR => HttpErrorCode::HttpSendError,
512             ffi::HttpErrorCode::HTTP_RECV_ERROR => HttpErrorCode::HttpRecvError,
513             ffi::HttpErrorCode::HTTP_SSL_CERTPROBLEM => HttpErrorCode::HttpSslCertproblem,
514             ffi::HttpErrorCode::HTTP_SSL_CIPHER => HttpErrorCode::HttpSslCipher,
515             ffi::HttpErrorCode::HTTP_PEER_FAILED_VERIFICATION => {
516                 HttpErrorCode::HttpPeerFailedVerification
517             }
518             ffi::HttpErrorCode::HTTP_BAD_CONTENT_ENCODING => HttpErrorCode::HttpBadContentEncoding,
519             ffi::HttpErrorCode::HTTP_FILESIZE_EXCEEDED => HttpErrorCode::HttpFilesizeExceeded,
520             ffi::HttpErrorCode::HTTP_REMOTE_DISK_FULL => HttpErrorCode::HttpRemoteDiskFull,
521             ffi::HttpErrorCode::HTTP_REMOTE_FILE_EXISTS => HttpErrorCode::HttpRemoteFileExists,
522             ffi::HttpErrorCode::HTTP_SSL_CACERT_BADFILE => HttpErrorCode::HttpSslCacertBadfile,
523             ffi::HttpErrorCode::HTTP_REMOTE_FILE_NOT_FOUND => HttpErrorCode::HttpRemoteFileNotFound,
524             ffi::HttpErrorCode::HTTP_AUTH_ERROR => HttpErrorCode::HttpAuthError,
525             ffi::HttpErrorCode::HTTP_UNKNOWN_OTHER_ERROR => HttpErrorCode::HttpUnknownOtherError,
526             _ => {
527                 return Err(value);
528             }
529         };
530         Ok(ret)
531     }
532 }
533