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