lib.rs (9756B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 extern crate bhttp; 6 extern crate nserror; 7 extern crate nsstring; 8 extern crate thin_vec; 9 #[macro_use] 10 extern crate xpcom; 11 12 use bhttp::{Message, Mode, StatusCode}; 13 use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_ERROR_UNEXPECTED, NS_OK}; 14 use nsstring::{nsACString, nsCString}; 15 use std::io::Cursor; 16 use thin_vec::ThinVec; 17 use xpcom::interfaces::{nsIBinaryHttpRequest, nsIBinaryHttpResponse}; 18 use xpcom::RefPtr; 19 20 enum HeaderComponent { 21 Name, 22 Value, 23 } 24 25 // Extracts either the names or the values of a slice of header (name, value) pairs. 26 fn extract_header_components( 27 headers: &[(Vec<u8>, Vec<u8>)], 28 component: HeaderComponent, 29 ) -> ThinVec<nsCString> { 30 let mut header_components = ThinVec::with_capacity(headers.len()); 31 for (name, value) in headers { 32 match component { 33 HeaderComponent::Name => header_components.push(nsCString::from(name.clone())), 34 HeaderComponent::Value => header_components.push(nsCString::from(value.clone())), 35 } 36 } 37 header_components 38 } 39 40 #[xpcom(implement(nsIBinaryHttpRequest), atomic)] 41 struct BinaryHttpRequest { 42 method: Vec<u8>, 43 scheme: Vec<u8>, 44 authority: Vec<u8>, 45 path: Vec<u8>, 46 headers: Vec<(Vec<u8>, Vec<u8>)>, 47 content: Vec<u8>, 48 } 49 50 impl BinaryHttpRequest { 51 xpcom_method!(get_method => GetMethod() -> nsACString); 52 fn get_method(&self) -> Result<nsCString, nsresult> { 53 Ok(nsCString::from(self.method.clone())) 54 } 55 56 xpcom_method!(get_scheme => GetScheme() -> nsACString); 57 fn get_scheme(&self) -> Result<nsCString, nsresult> { 58 Ok(nsCString::from(self.scheme.clone())) 59 } 60 61 xpcom_method!(get_authority => GetAuthority() -> nsACString); 62 fn get_authority(&self) -> Result<nsCString, nsresult> { 63 Ok(nsCString::from(self.authority.clone())) 64 } 65 66 xpcom_method!(get_path => GetPath() -> nsACString); 67 fn get_path(&self) -> Result<nsCString, nsresult> { 68 Ok(nsCString::from(self.path.clone())) 69 } 70 71 xpcom_method!(get_content => GetContent() -> ThinVec<u8>); 72 fn get_content(&self) -> Result<ThinVec<u8>, nsresult> { 73 Ok(self.content.clone().into_iter().collect()) 74 } 75 76 xpcom_method!(get_header_names => GetHeaderNames() -> ThinVec<nsCString>); 77 fn get_header_names(&self) -> Result<ThinVec<nsCString>, nsresult> { 78 Ok(extract_header_components( 79 &self.headers, 80 HeaderComponent::Name, 81 )) 82 } 83 84 xpcom_method!(get_header_values => GetHeaderValues() -> ThinVec<nsCString>); 85 fn get_header_values(&self) -> Result<ThinVec<nsCString>, nsresult> { 86 Ok(extract_header_components( 87 &self.headers, 88 HeaderComponent::Value, 89 )) 90 } 91 } 92 93 #[xpcom(implement(nsIBinaryHttpResponse), atomic)] 94 struct BinaryHttpResponse { 95 status: u16, 96 headers: Vec<(Vec<u8>, Vec<u8>)>, 97 content: Vec<u8>, 98 } 99 100 impl BinaryHttpResponse { 101 xpcom_method!(get_status => GetStatus() -> u16); 102 fn get_status(&self) -> Result<u16, nsresult> { 103 Ok(self.status) 104 } 105 106 xpcom_method!(get_content => GetContent() -> ThinVec<u8>); 107 fn get_content(&self) -> Result<ThinVec<u8>, nsresult> { 108 Ok(self.content.clone().into_iter().collect()) 109 } 110 111 xpcom_method!(get_header_names => GetHeaderNames() -> ThinVec<nsCString>); 112 fn get_header_names(&self) -> Result<ThinVec<nsCString>, nsresult> { 113 Ok(extract_header_components( 114 &self.headers, 115 HeaderComponent::Name, 116 )) 117 } 118 119 xpcom_method!(get_header_values => GetHeaderValues() -> ThinVec<nsCString>); 120 fn get_header_values(&self) -> Result<ThinVec<nsCString>, nsresult> { 121 Ok(extract_header_components( 122 &self.headers, 123 HeaderComponent::Value, 124 )) 125 } 126 } 127 128 #[xpcom(implement(nsIBinaryHttp), atomic)] 129 struct BinaryHttp {} 130 131 impl BinaryHttp { 132 xpcom_method!(encode_request => EncodeRequest(request: *const nsIBinaryHttpRequest) -> ThinVec<u8>); 133 fn encode_request(&self, request: &nsIBinaryHttpRequest) -> Result<ThinVec<u8>, nsresult> { 134 let mut method = nsCString::new(); 135 unsafe { request.GetMethod(&mut *method) }.to_result()?; 136 let mut scheme = nsCString::new(); 137 unsafe { request.GetScheme(&mut *scheme) }.to_result()?; 138 let mut authority = nsCString::new(); 139 unsafe { request.GetAuthority(&mut *authority) }.to_result()?; 140 let mut path = nsCString::new(); 141 unsafe { request.GetPath(&mut *path) }.to_result()?; 142 let mut message = Message::request( 143 method.to_vec(), 144 scheme.to_vec(), 145 authority.to_vec(), 146 path.to_vec(), 147 ); 148 let mut header_names = ThinVec::new(); 149 unsafe { request.GetHeaderNames(&mut header_names) }.to_result()?; 150 let mut header_values = ThinVec::with_capacity(header_names.len()); 151 unsafe { request.GetHeaderValues(&mut header_values) }.to_result()?; 152 if header_names.len() != header_values.len() { 153 return Err(NS_ERROR_INVALID_ARG); 154 } 155 for (name, value) in header_names.iter().zip(header_values.iter()) { 156 message.put_header(name.to_vec(), value.to_vec()); 157 } 158 let mut content = ThinVec::new(); 159 unsafe { request.GetContent(&mut content) }.to_result()?; 160 message.write_content(content); 161 let mut encoded = ThinVec::new(); 162 message 163 .write_bhttp(Mode::KnownLength, &mut encoded) 164 .map_err(|_| NS_ERROR_FAILURE)?; 165 Ok(encoded) 166 } 167 168 xpcom_method!(decode_response => DecodeResponse(response: *const ThinVec<u8>) -> *const nsIBinaryHttpResponse); 169 fn decode_response( 170 &self, 171 response: &ThinVec<u8>, 172 ) -> Result<RefPtr<nsIBinaryHttpResponse>, nsresult> { 173 let mut cursor = Cursor::new(response); 174 let decoded = Message::read_bhttp(&mut cursor).map_err(|_| NS_ERROR_UNEXPECTED)?; 175 let status = decoded.control().status().ok_or(NS_ERROR_UNEXPECTED)?; 176 let headers = decoded 177 .header() 178 .iter() 179 .map(|field| (field.name().to_vec(), field.value().to_vec())) 180 .collect(); 181 let content = decoded.content().to_vec(); 182 let binary_http_response = BinaryHttpResponse::allocate(InitBinaryHttpResponse { 183 status: status.into(), 184 headers, 185 content, 186 }); 187 binary_http_response 188 .query_interface::<nsIBinaryHttpResponse>() 189 .ok_or(NS_ERROR_FAILURE) 190 } 191 192 xpcom_method!(decode_request => DecodeRequest(request: *const ThinVec<u8>) -> *const nsIBinaryHttpRequest); 193 fn decode_request( 194 &self, 195 request: &ThinVec<u8>, 196 ) -> Result<RefPtr<nsIBinaryHttpRequest>, nsresult> { 197 let mut cursor = Cursor::new(request); 198 let decoded = Message::read_bhttp(&mut cursor).map_err(|_| NS_ERROR_UNEXPECTED)?; 199 let method = decoded 200 .control() 201 .method() 202 .ok_or(NS_ERROR_UNEXPECTED)? 203 .to_vec(); 204 let scheme = decoded 205 .control() 206 .scheme() 207 .ok_or(NS_ERROR_UNEXPECTED)? 208 .to_vec(); 209 // authority and path can be empty, in which case we return empty arrays 210 let authority = decoded.control().authority().unwrap_or(&[]).to_vec(); 211 let path = decoded.control().path().unwrap_or(&[]).to_vec(); 212 let headers = decoded 213 .header() 214 .iter() 215 .map(|field| (field.name().to_vec(), field.value().to_vec())) 216 .collect(); 217 let content = decoded.content().to_vec(); 218 let binary_http_request = BinaryHttpRequest::allocate(InitBinaryHttpRequest { 219 method, 220 scheme, 221 authority, 222 path, 223 headers, 224 content, 225 }); 226 binary_http_request 227 .query_interface::<nsIBinaryHttpRequest>() 228 .ok_or(NS_ERROR_FAILURE) 229 } 230 231 xpcom_method!(encode_response => EncodeResponse(response: *const nsIBinaryHttpResponse) -> ThinVec<u8>); 232 fn encode_response(&self, response: &nsIBinaryHttpResponse) -> Result<ThinVec<u8>, nsresult> { 233 let mut status = 0; 234 unsafe { response.GetStatus(&mut status) }.to_result()?; 235 let mut message = 236 Message::response(StatusCode::try_from(status).map_err(|_| NS_ERROR_FAILURE)?); 237 let mut header_names = ThinVec::new(); 238 unsafe { response.GetHeaderNames(&mut header_names) }.to_result()?; 239 let mut header_values = ThinVec::with_capacity(header_names.len()); 240 unsafe { response.GetHeaderValues(&mut header_values) }.to_result()?; 241 if header_names.len() != header_values.len() { 242 return Err(NS_ERROR_INVALID_ARG); 243 } 244 for (name, value) in header_names.iter().zip(header_values.iter()) { 245 message.put_header(name.to_vec(), value.to_vec()); 246 } 247 let mut content = ThinVec::new(); 248 unsafe { response.GetContent(&mut content) }.to_result()?; 249 message.write_content(content); 250 let mut encoded = ThinVec::new(); 251 message 252 .write_bhttp(Mode::KnownLength, &mut encoded) 253 .map_err(|_| NS_ERROR_FAILURE)?; 254 Ok(encoded) 255 } 256 } 257 258 #[no_mangle] 259 pub extern "C" fn binary_http_constructor( 260 iid: *const xpcom::nsIID, 261 result: *mut *mut xpcom::reexports::libc::c_void, 262 ) -> nsresult { 263 let binary_http = BinaryHttp::allocate(InitBinaryHttp {}); 264 unsafe { binary_http.QueryInterface(iid, result) } 265 }