summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/binary_http/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http/binary_http/src/lib.rs')
-rw-r--r--netwerk/protocol/http/binary_http/src/lib.rs264
1 files changed, 264 insertions, 0 deletions
diff --git a/netwerk/protocol/http/binary_http/src/lib.rs b/netwerk/protocol/http/binary_http/src/lib.rs
new file mode 100644
index 0000000000..fab357dcca
--- /dev/null
+++ b/netwerk/protocol/http/binary_http/src/lib.rs
@@ -0,0 +1,264 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+extern crate bhttp;
+extern crate nserror;
+extern crate nsstring;
+extern crate thin_vec;
+#[macro_use]
+extern crate xpcom;
+
+use bhttp::{Message, Mode};
+use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_ERROR_UNEXPECTED, NS_OK};
+use nsstring::{nsACString, nsCString};
+use std::io::Cursor;
+use thin_vec::ThinVec;
+use xpcom::interfaces::{nsIBinaryHttpRequest, nsIBinaryHttpResponse};
+use xpcom::RefPtr;
+
+enum HeaderComponent {
+ Name,
+ Value,
+}
+
+// Extracts either the names or the values of a slice of header (name, value) pairs.
+fn extract_header_components(
+ headers: &[(Vec<u8>, Vec<u8>)],
+ component: HeaderComponent,
+) -> ThinVec<nsCString> {
+ let mut header_components = ThinVec::with_capacity(headers.len());
+ for (name, value) in headers {
+ match component {
+ HeaderComponent::Name => header_components.push(nsCString::from(name.clone())),
+ HeaderComponent::Value => header_components.push(nsCString::from(value.clone())),
+ }
+ }
+ header_components
+}
+
+#[xpcom(implement(nsIBinaryHttpRequest), atomic)]
+struct BinaryHttpRequest {
+ method: Vec<u8>,
+ scheme: Vec<u8>,
+ authority: Vec<u8>,
+ path: Vec<u8>,
+ headers: Vec<(Vec<u8>, Vec<u8>)>,
+ content: Vec<u8>,
+}
+
+impl BinaryHttpRequest {
+ xpcom_method!(get_method => GetMethod() -> nsACString);
+ fn get_method(&self) -> Result<nsCString, nsresult> {
+ Ok(nsCString::from(self.method.clone()))
+ }
+
+ xpcom_method!(get_scheme => GetScheme() -> nsACString);
+ fn get_scheme(&self) -> Result<nsCString, nsresult> {
+ Ok(nsCString::from(self.scheme.clone()))
+ }
+
+ xpcom_method!(get_authority => GetAuthority() -> nsACString);
+ fn get_authority(&self) -> Result<nsCString, nsresult> {
+ Ok(nsCString::from(self.authority.clone()))
+ }
+
+ xpcom_method!(get_path => GetPath() -> nsACString);
+ fn get_path(&self) -> Result<nsCString, nsresult> {
+ Ok(nsCString::from(self.path.clone()))
+ }
+
+ xpcom_method!(get_content => GetContent() -> ThinVec<u8>);
+ fn get_content(&self) -> Result<ThinVec<u8>, nsresult> {
+ Ok(self.content.clone().into_iter().collect())
+ }
+
+ xpcom_method!(get_header_names => GetHeaderNames() -> ThinVec<nsCString>);
+ fn get_header_names(&self) -> Result<ThinVec<nsCString>, nsresult> {
+ Ok(extract_header_components(
+ &self.headers,
+ HeaderComponent::Name,
+ ))
+ }
+
+ xpcom_method!(get_header_values => GetHeaderValues() -> ThinVec<nsCString>);
+ fn get_header_values(&self) -> Result<ThinVec<nsCString>, nsresult> {
+ Ok(extract_header_components(
+ &self.headers,
+ HeaderComponent::Value,
+ ))
+ }
+}
+
+#[xpcom(implement(nsIBinaryHttpResponse), atomic)]
+struct BinaryHttpResponse {
+ status: u16,
+ headers: Vec<(Vec<u8>, Vec<u8>)>,
+ content: Vec<u8>,
+}
+
+impl BinaryHttpResponse {
+ xpcom_method!(get_status => GetStatus() -> u16);
+ fn get_status(&self) -> Result<u16, nsresult> {
+ Ok(self.status)
+ }
+
+ xpcom_method!(get_content => GetContent() -> ThinVec<u8>);
+ fn get_content(&self) -> Result<ThinVec<u8>, nsresult> {
+ Ok(self.content.clone().into_iter().collect())
+ }
+
+ xpcom_method!(get_header_names => GetHeaderNames() -> ThinVec<nsCString>);
+ fn get_header_names(&self) -> Result<ThinVec<nsCString>, nsresult> {
+ Ok(extract_header_components(
+ &self.headers,
+ HeaderComponent::Name,
+ ))
+ }
+
+ xpcom_method!(get_header_values => GetHeaderValues() -> ThinVec<nsCString>);
+ fn get_header_values(&self) -> Result<ThinVec<nsCString>, nsresult> {
+ Ok(extract_header_components(
+ &self.headers,
+ HeaderComponent::Value,
+ ))
+ }
+}
+
+#[xpcom(implement(nsIBinaryHttp), atomic)]
+struct BinaryHttp {}
+
+impl BinaryHttp {
+ xpcom_method!(encode_request => EncodeRequest(request: *const nsIBinaryHttpRequest) -> ThinVec<u8>);
+ fn encode_request(&self, request: &nsIBinaryHttpRequest) -> Result<ThinVec<u8>, nsresult> {
+ let mut method = nsCString::new();
+ unsafe { request.GetMethod(&mut *method) }.to_result()?;
+ let mut scheme = nsCString::new();
+ unsafe { request.GetScheme(&mut *scheme) }.to_result()?;
+ let mut authority = nsCString::new();
+ unsafe { request.GetAuthority(&mut *authority) }.to_result()?;
+ let mut path = nsCString::new();
+ unsafe { request.GetPath(&mut *path) }.to_result()?;
+ let mut message = Message::request(
+ method.to_vec(),
+ scheme.to_vec(),
+ authority.to_vec(),
+ path.to_vec(),
+ );
+ let mut header_names = ThinVec::new();
+ unsafe { request.GetHeaderNames(&mut header_names) }.to_result()?;
+ let mut header_values = ThinVec::with_capacity(header_names.len());
+ unsafe { request.GetHeaderValues(&mut header_values) }.to_result()?;
+ if header_names.len() != header_values.len() {
+ return Err(NS_ERROR_INVALID_ARG);
+ }
+ for (name, value) in header_names.iter().zip(header_values.iter()) {
+ message.put_header(name.to_vec(), value.to_vec());
+ }
+ let mut content = ThinVec::new();
+ unsafe { request.GetContent(&mut content) }.to_result()?;
+ message.write_content(content);
+ let mut encoded = ThinVec::new();
+ message
+ .write_bhttp(Mode::KnownLength, &mut encoded)
+ .map_err(|_| NS_ERROR_FAILURE)?;
+ Ok(encoded)
+ }
+
+ xpcom_method!(decode_response => DecodeResponse(response: *const ThinVec<u8>) -> *const nsIBinaryHttpResponse);
+ fn decode_response(
+ &self,
+ response: &ThinVec<u8>,
+ ) -> Result<RefPtr<nsIBinaryHttpResponse>, nsresult> {
+ let mut cursor = Cursor::new(response);
+ let decoded = Message::read_bhttp(&mut cursor).map_err(|_| NS_ERROR_UNEXPECTED)?;
+ let status = decoded.control().status().ok_or(NS_ERROR_UNEXPECTED)?;
+ let headers = decoded
+ .header()
+ .iter()
+ .map(|field| (field.name().to_vec(), field.value().to_vec()))
+ .collect();
+ let content = decoded.content().to_vec();
+ let binary_http_response = BinaryHttpResponse::allocate(InitBinaryHttpResponse {
+ status,
+ headers,
+ content,
+ });
+ binary_http_response
+ .query_interface::<nsIBinaryHttpResponse>()
+ .ok_or(NS_ERROR_FAILURE)
+ }
+
+ xpcom_method!(decode_request => DecodeRequest(request: *const ThinVec<u8>) -> *const nsIBinaryHttpRequest);
+ fn decode_request(
+ &self,
+ request: &ThinVec<u8>,
+ ) -> Result<RefPtr<nsIBinaryHttpRequest>, nsresult> {
+ let mut cursor = Cursor::new(request);
+ let decoded = Message::read_bhttp(&mut cursor).map_err(|_| NS_ERROR_UNEXPECTED)?;
+ let method = decoded
+ .control()
+ .method()
+ .ok_or(NS_ERROR_UNEXPECTED)?
+ .to_vec();
+ let scheme = decoded
+ .control()
+ .scheme()
+ .ok_or(NS_ERROR_UNEXPECTED)?
+ .to_vec();
+ // authority and path can be empty, in which case we return empty arrays
+ let authority = decoded.control().authority().unwrap_or(&[]).to_vec();
+ let path = decoded.control().path().unwrap_or(&[]).to_vec();
+ let headers = decoded
+ .header()
+ .iter()
+ .map(|field| (field.name().to_vec(), field.value().to_vec()))
+ .collect();
+ let content = decoded.content().to_vec();
+ let binary_http_request = BinaryHttpRequest::allocate(InitBinaryHttpRequest {
+ method,
+ scheme,
+ authority,
+ path,
+ headers,
+ content,
+ });
+ binary_http_request
+ .query_interface::<nsIBinaryHttpRequest>()
+ .ok_or(NS_ERROR_FAILURE)
+ }
+
+ xpcom_method!(encode_response => EncodeResponse(response: *const nsIBinaryHttpResponse) -> ThinVec<u8>);
+ fn encode_response(&self, response: &nsIBinaryHttpResponse) -> Result<ThinVec<u8>, nsresult> {
+ let mut status = 0;
+ unsafe { response.GetStatus(&mut status) }.to_result()?;
+ let mut message = Message::response(status);
+ let mut header_names = ThinVec::new();
+ unsafe { response.GetHeaderNames(&mut header_names) }.to_result()?;
+ let mut header_values = ThinVec::with_capacity(header_names.len());
+ unsafe { response.GetHeaderValues(&mut header_values) }.to_result()?;
+ if header_names.len() != header_values.len() {
+ return Err(NS_ERROR_INVALID_ARG);
+ }
+ for (name, value) in header_names.iter().zip(header_values.iter()) {
+ message.put_header(name.to_vec(), value.to_vec());
+ }
+ let mut content = ThinVec::new();
+ unsafe { response.GetContent(&mut content) }.to_result()?;
+ message.write_content(content);
+ let mut encoded = ThinVec::new();
+ message
+ .write_bhttp(Mode::KnownLength, &mut encoded)
+ .map_err(|_| NS_ERROR_FAILURE)?;
+ Ok(encoded)
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn binary_http_constructor(
+ iid: *const xpcom::nsIID,
+ result: *mut *mut xpcom::reexports::libc::c_void,
+) -> nsresult {
+ let binary_http = BinaryHttp::allocate(InitBinaryHttp {});
+ unsafe { binary_http.QueryInterface(iid, result) }
+}