tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }