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