Pier Angelo Vendrame pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser
Commits:
-
3fcf8e84
by Elena at 2026-08-19T10:58:03+02:00
-
15498d90
by Elena at 2026-08-19T11:09:16+02:00
-
0e880d8f
by Elena at 2026-08-19T11:09:19+02:00
-
491ab443
by Elena at 2026-08-19T11:09:19+02:00
-
8a46afe3
by Elena at 2026-08-19T11:11:03+02:00
-
81b76447
by Elena at 2026-08-19T11:11:05+02:00
12 changed files:
- toolkit/components/tor-integration/TorService.h
- toolkit/components/tor-integration/components.conf
- toolkit/components/tor-integration/moz.build
- toolkit/components/tor-integration/ITorService.idl โ toolkit/components/tor-integration/torITorService.idl
- toolkit/components/tor-integration/tor_provider/src/ctor/control_port/control_port.rs
- toolkit/components/tor-integration/tor_provider/src/ctor/control_port/error.rs
- toolkit/components/tor-integration/tor_provider/src/ctor/reply_parser/dispatcher.rs
- toolkit/components/tor-integration/tor_provider/src/ctor/reply_parser/mod.rs
- toolkit/components/tor-integration/tor_provider/src/ctor/reply_parser/test_utils.rs
- toolkit/components/tor-integration/tor_service/src/control_port.rs
- toolkit/components/tor-integration/tor_service/src/service.rs
- tools/lint/eslint/eslint-plugin-mozilla/lib/services.json
Changes:
| ... | ... | @@ -7,17 +7,17 @@ |
| 7 | 7 | |
| 8 | 8 | #include "nsCOMPtr.h"
|
| 9 | 9 | |
| 10 | -#include "ITorService.h"
|
|
| 10 | +#include "torITorService.h"
|
|
| 11 | 11 | |
| 12 | 12 | // Inspired by
|
| 13 | 13 | // toolkit/components/extensions/storage/ExtensionStorageComponents.h.
|
| 14 | 14 | |
| 15 | 15 | // Implemented in Rust
|
| 16 | -extern "C" nsresult NewTorServiceImpl(ITorService** aResult);
|
|
| 16 | +extern "C" nsresult NewTorServiceImpl(torITorService** aResult);
|
|
| 17 | 17 | |
| 18 | 18 | namespace torproject {
|
| 19 | -already_AddRefed<ITorService> NewTorService() {
|
|
| 20 | - nsCOMPtr<ITorService> service;
|
|
| 19 | +already_AddRefed<torITorService> NewTorService() {
|
|
| 20 | + nsCOMPtr<torITorService> service;
|
|
| 21 | 21 | nsresult rv = NewTorServiceImpl(getter_AddRefs(service));
|
| 22 | 22 | if (NS_WARN_IF(NS_FAILED(rv))) {
|
| 23 | 23 | return nullptr;
|
| ... | ... | @@ -6,7 +6,7 @@ Classes = [ |
| 6 | 6 | {
|
| 7 | 7 | 'cid': '{2537313c-e120-408c-a2f6-86e6e1bdf899}',
|
| 8 | 8 | 'contract_ids': ['@torproject.org/tor-service;1'],
|
| 9 | - 'interfaces': ['ITorService'],
|
|
| 9 | + 'interfaces': ['torITorService'],
|
|
| 10 | 10 | 'constructor': 'torproject::NewTorService',
|
| 11 | 11 | 'headers': ['torproject/TorService.h'],
|
| 12 | 12 | 'js_name': 'tor',
|
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
| 4 | 4 | |
| 5 | 5 | XPIDL_MODULE = "tor"
|
| 6 | -XPIDL_SOURCES += ["ITorService.idl"]
|
|
| 6 | +XPIDL_SOURCES += ["torITorService.idl"]
|
|
| 7 | 7 | XPCOM_MANIFESTS += [
|
| 8 | 8 | "components.conf",
|
| 9 | 9 | ]
|
| ... | ... | @@ -6,27 +6,27 @@ |
| 6 | 6 | #include "nsIFile.idl"
|
| 7 | 7 | |
| 8 | 8 | [scriptable, uuid(4b250614-968a-412f-9191-9ffd9d4bd001)]
|
| 9 | -interface ITorControlPortReceiver : nsISupports {
|
|
| 9 | +interface torITorControlPortReceiver : nsISupports {
|
|
| 10 | 10 | void onAsyncMessage(in ACString message);
|
| 11 | 11 | };
|
| 12 | 12 | |
| 13 | 13 | [scriptable, uuid(1389d157-4695-43a2-a7d8-538aaa350766)]
|
| 14 | -interface ITorMessageHandler : nsISupports {
|
|
| 14 | +interface torITorMessageHandler : nsISupports {
|
|
| 15 | 15 | void onMessage(in ACString message);
|
| 16 | 16 | void onError(in ACString error);
|
| 17 | 17 | };
|
| 18 | 18 | |
| 19 | 19 | // TODO: Remove once we have a provider.
|
| 20 | 20 | [scriptable, uuid(f56d710e-5650-4b8c-8d31-279f360003ee)]
|
| 21 | -interface ITorControlPort : nsISupports {
|
|
| 22 | - void start(in ITorControlPortReceiver receiver);
|
|
| 23 | - void sendCommand(in ACString command, in ITorMessageHandler handler);
|
|
| 21 | +interface torITorControlPort : nsISupports {
|
|
| 22 | + void start(in torITorControlPortReceiver receiver);
|
|
| 23 | + void sendCommand(in ACString command, in torITorMessageHandler handler);
|
|
| 24 | 24 | void close();
|
| 25 | 25 | };
|
| 26 | 26 | |
| 27 | 27 | [scriptable, uuid(2537313c-e120-408c-a2f6-86e6e1bdf899)]
|
| 28 | -interface ITorService : nsISupports {
|
|
| 28 | +interface torITorService : nsISupports {
|
|
| 29 | 29 | // For development purposes...
|
| 30 | - ITorControlPort createControlPort(in ACString host, in long port);
|
|
| 31 | - ITorControlPort createControlPortIPC(in nsIFile socket);
|
|
| 30 | + torITorControlPort createControlPort(in ACString host, in long port);
|
|
| 31 | + torITorControlPort createControlPortIPC(in nsIFile socket);
|
|
| 32 | 32 | }; |
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // <http://opensource.org/licenses/MIT>, at your option. This file may not be
|
| 4 | 4 | // copied, modified, or distributed except according to those terms.
|
| 5 | 5 | |
| 6 | -use bytes::{BufMut, Bytes, BytesMut};
|
|
| 6 | +use bytes::Bytes;
|
|
| 7 | 7 | use std::{
|
| 8 | 8 | cell::Cell,
|
| 9 | 9 | rc::{Rc, Weak},
|
| ... | ... | @@ -79,35 +79,22 @@ impl ControlPortInner { |
| 79 | 79 | }
|
| 80 | 80 | }
|
| 81 | 81 | |
| 82 | - fn close(&self) -> Result<(), ControlSocketError> {
|
|
| 83 | - if self.closed.replace(true) {
|
|
| 84 | - return Ok(());
|
|
| 85 | - }
|
|
| 86 | - self.reply_dispatcher.fail_all(ReplyError::ConnectionClosed);
|
|
| 87 | - self.socket.close()
|
|
| 88 | - }
|
|
| 89 | - |
|
| 90 | - fn set_async_handler(&self, cb: Box<dyn Fn(Reply)>) {
|
|
| 91 | - self.reply_dispatcher.set_async_handler(cb);
|
|
| 92 | - }
|
|
| 93 | - |
|
| 94 | 82 | fn send_command(
|
| 95 | 83 | self: &Rc<Self>,
|
| 96 | - mut command: Bytes,
|
|
| 84 | + command: Bytes,
|
|
| 97 | 85 | handler: Box<dyn FnOnce(Result<Reply, ControlPortError>)>,
|
| 98 | 86 | ) {
|
| 99 | 87 | if self.closed.get() {
|
| 100 | - handler(Err(ControlPortError::ConnectionError(
|
|
| 101 | - ControlSocketError::ConnectionClosed,
|
|
| 88 | + handler(Err(ControlPortError::ProtocolError(
|
|
| 89 | + ReplyError::ConnectionClosed,
|
|
| 102 | 90 | )));
|
| 103 | 91 | return;
|
| 104 | 92 | }
|
| 105 | 93 | |
| 106 | - if !command.ends_with(b"\r\n") {
|
|
| 107 | - let mut buf = BytesMut::from(command);
|
|
| 108 | - buf.put(&b"\r\n"[..]);
|
|
| 109 | - command = buf.freeze();
|
|
| 110 | - }
|
|
| 94 | + debug_assert!(
|
|
| 95 | + command.ends_with(b"\r\n"),
|
|
| 96 | + "Commands are expected to end with CRLF."
|
|
| 97 | + );
|
|
| 111 | 98 | |
| 112 | 99 | // The callback is going to be called before other commands are sent,
|
| 113 | 100 | // therefore it is safe to queue the callback at this point, as next
|
| ... | ... | @@ -128,14 +115,33 @@ impl ControlPortInner { |
| 128 | 115 | handler(r.map_err(|e| ControlPortError::ProtocolError(e)));
|
| 129 | 116 | }));
|
| 130 | 117 | }
|
| 131 | - Err(e) => {
|
|
| 132 | - handler(Err(ControlPortError::from(e)));
|
|
| 118 | + Err(ControlSocketError::ConnectionClosed) => {
|
|
| 119 | + handler(Err(ControlPortError::ProtocolError(
|
|
| 120 | + ReplyError::ConnectionClosed,
|
|
| 121 | + )));
|
|
| 122 | + this.async_failure();
|
|
| 123 | + }
|
|
| 124 | + Err(ControlSocketError::ImplementationError(rv)) => {
|
|
| 125 | + handler(Err(ControlPortError::ConnectionError(rv)));
|
|
| 133 | 126 | this.async_failure();
|
| 134 | 127 | }
|
| 135 | 128 | }
|
| 136 | 129 | }),
|
| 137 | 130 | );
|
| 138 | 131 | }
|
| 132 | + |
|
| 133 | + fn set_async_handler(&self, cb: Option<Box<dyn Fn(Reply)>>) {
|
|
| 134 | + self.reply_dispatcher.set_async_handler(cb);
|
|
| 135 | + }
|
|
| 136 | + |
|
| 137 | + fn close(&self) -> Result<(), ControlSocketError> {
|
|
| 138 | + if self.closed.replace(true) {
|
|
| 139 | + return Ok(());
|
|
| 140 | + }
|
|
| 141 | + self.reply_dispatcher.fail_all(ReplyError::ConnectionClosed);
|
|
| 142 | + self.reply_dispatcher.set_async_handler(None);
|
|
| 143 | + self.socket.close()
|
|
| 144 | + }
|
|
| 139 | 145 | }
|
| 140 | 146 | |
| 141 | 147 | impl Drop for ControlPortInner {
|
| ... | ... | @@ -157,11 +163,6 @@ impl ControlPort { |
| 157 | 163 | Ok(Self(ControlPortInner::new(Rc::from(socket))?))
|
| 158 | 164 | }
|
| 159 | 165 | |
| 160 | - #[inline]
|
|
| 161 | - pub fn close(&self) -> Result<(), ControlSocketError> {
|
|
| 162 | - self.0.close()
|
|
| 163 | - }
|
|
| 164 | - |
|
| 165 | 166 | // TODO: Keep only the methods speicifc to commands and remove this one
|
| 166 | 167 | // (tor-browser#44930).
|
| 167 | 168 | #[inline]
|
| ... | ... | @@ -174,7 +175,12 @@ impl ControlPort { |
| 174 | 175 | }
|
| 175 | 176 | |
| 176 | 177 | #[inline]
|
| 177 | - pub fn set_async_handler(&self, cb: Box<dyn Fn(Reply)>) {
|
|
| 178 | + pub fn set_async_handler(&self, cb: Option<Box<dyn Fn(Reply)>>) {
|
|
| 178 | 179 | self.0.set_async_handler(cb);
|
| 179 | 180 | }
|
| 181 | + |
|
| 182 | + #[inline]
|
|
| 183 | + pub fn close(&self) -> Result<(), ControlSocketError> {
|
|
| 184 | + self.0.close()
|
|
| 185 | + }
|
|
| 180 | 186 | } |
| ... | ... | @@ -5,14 +5,12 @@ |
| 5 | 5 | |
| 6 | 6 | use thiserror::Error;
|
| 7 | 7 | |
| 8 | -use super::super::{ControlSocketError, ReplyError};
|
|
| 8 | +use crate::ctor::ReplyError;
|
|
| 9 | 9 | |
| 10 | 10 | #[derive(Error, Debug, Clone, PartialEq, Eq)]
|
| 11 | 11 | pub enum ControlPortError {
|
| 12 | - #[error("connection error")]
|
|
| 13 | - ConnectionError(#[from] ControlSocketError),
|
|
| 14 | - #[error("protocol violation")]
|
|
| 12 | + #[error("connection error: {0:#x}")]
|
|
| 13 | + ConnectionError(u32),
|
|
| 14 | + #[error("protocol violation: {0}")]
|
|
| 15 | 15 | ProtocolError(#[from] ReplyError),
|
| 16 | - #[error("unsuccessful command ({code}): {message}")]
|
|
| 17 | - TorError { code: u16, message: String },
|
|
| 18 | 16 | } |
| ... | ... | @@ -56,9 +56,9 @@ impl ReplyDispatcher { |
| 56 | 56 | }
|
| 57 | 57 | |
| 58 | 58 | /// Register the handler for async notifications.
|
| 59 | - pub fn set_async_handler(&self, cb: Box<dyn Fn(Reply)>) {
|
|
| 59 | + pub fn set_async_handler(&self, cb: Option<Box<dyn Fn(Reply)>>) {
|
|
| 60 | 60 | // Reentrancy safety: we do not use the handler yet.
|
| 61 | - *self.async_handler.borrow_mut() = Some(Rc::from(cb))
|
|
| 61 | + *self.async_handler.borrow_mut() = cb.map(|cb| Rc::from(cb));
|
|
| 62 | 62 | }
|
| 63 | 63 | |
| 64 | 64 | /// Feed data to parse.
|
| ... | ... | @@ -290,7 +290,7 @@ mod tests { |
| 290 | 290 | let dispatcher = ReplyDispatcher::new();
|
| 291 | 291 | let notification_called = Rc::new(Cell::new(false));
|
| 292 | 292 | let notification_called2 = notification_called.clone();
|
| 293 | - dispatcher.set_async_handler(Box::new(move |r| {
|
|
| 293 | + dispatcher.set_async_handler(Some(Box::new(move |r| {
|
|
| 294 | 294 | assert_eq!(
|
| 295 | 295 | *r.end_line(),
|
| 296 | 296 | EndReplyLine {
|
| ... | ... | @@ -299,7 +299,7 @@ mod tests { |
| 299 | 299 | }
|
| 300 | 300 | );
|
| 301 | 301 | notification_called2.set(true);
|
| 302 | - }));
|
|
| 302 | + })));
|
|
| 303 | 303 | let reply_called = Rc::new(Cell::new(false));
|
| 304 | 304 | let reply_called2 = reply_called.clone();
|
| 305 | 305 | dispatcher.push_callback(Box::new(move |_| {
|
| ... | ... | @@ -323,12 +323,12 @@ mod tests { |
| 323 | 323 | #[test]
|
| 324 | 324 | fn async_replace_handler() {
|
| 325 | 325 | let dispatcher = ReplyDispatcher::new();
|
| 326 | - dispatcher.set_async_handler(Box::new(move |_| {
|
|
| 326 | + dispatcher.set_async_handler(Some(Box::new(move |_| {
|
|
| 327 | 327 | unreachable!("This handler should never be called, as it has been replaced.");
|
| 328 | - }));
|
|
| 328 | + })));
|
|
| 329 | 329 | let called = Rc::new(Cell::new(false));
|
| 330 | 330 | let c = called.clone();
|
| 331 | - dispatcher.set_async_handler(Box::new(move |r| {
|
|
| 331 | + dispatcher.set_async_handler(Some(Box::new(move |r| {
|
|
| 332 | 332 | assert_eq!(
|
| 333 | 333 | *r.end_line(),
|
| 334 | 334 | EndReplyLine {
|
| ... | ... | @@ -337,7 +337,7 @@ mod tests { |
| 337 | 337 | }
|
| 338 | 338 | );
|
| 339 | 339 | c.set(true);
|
| 340 | - }));
|
|
| 340 | + })));
|
|
| 341 | 341 | assert!(!called.get());
|
| 342 | 342 | dispatcher
|
| 343 | 343 | .feed(&Bytes::from_static(b"650 Notification\r\n"))
|
| ... | ... | @@ -345,6 +345,18 @@ mod tests { |
| 345 | 345 | assert!(called.get());
|
| 346 | 346 | }
|
| 347 | 347 | |
| 348 | + #[test]
|
|
| 349 | + fn async_remove_handler() {
|
|
| 350 | + let dispatcher = ReplyDispatcher::new();
|
|
| 351 | + dispatcher.set_async_handler(Some(Box::new(move |_| {
|
|
| 352 | + unreachable!("This handler should never be called, as it has been replaced.");
|
|
| 353 | + })));
|
|
| 354 | + dispatcher.set_async_handler(None);
|
|
| 355 | + dispatcher
|
|
| 356 | + .feed(&Bytes::from_static(b"650 Notification\r\n"))
|
|
| 357 | + .unwrap();
|
|
| 358 | + }
|
|
| 359 | + |
|
| 348 | 360 | #[test]
|
| 349 | 361 | fn sync_async_single_feed() {
|
| 350 | 362 | let dispatcher = ReplyDispatcher::new();
|
| ... | ... | @@ -356,7 +368,7 @@ mod tests { |
| 356 | 368 | }));
|
| 357 | 369 | let async_called = Rc::new(Cell::new(false));
|
| 358 | 370 | let ac = async_called.clone();
|
| 359 | - dispatcher.set_async_handler(Box::new(move |r| {
|
|
| 371 | + dispatcher.set_async_handler(Some(Box::new(move |r| {
|
|
| 360 | 372 | assert_eq!(
|
| 361 | 373 | *r.end_line(),
|
| 362 | 374 | EndReplyLine {
|
| ... | ... | @@ -365,7 +377,7 @@ mod tests { |
| 365 | 377 | }
|
| 366 | 378 | );
|
| 367 | 379 | ac.set(true);
|
| 368 | - }));
|
|
| 380 | + })));
|
|
| 369 | 381 | dispatcher
|
| 370 | 382 | .feed(&Bytes::from_static(b"250 OK\r\n650 Notification\r\n"))
|
| 371 | 383 | .unwrap();
|
| ... | ... | @@ -450,13 +462,13 @@ mod tests { |
| 450 | 462 | let notifications = Rc::new(Cell::new(0));
|
| 451 | 463 | let n = notifications.clone();
|
| 452 | 464 | let d = dispatcher.clone();
|
| 453 | - dispatcher.set_async_handler(Box::new(move |_| {
|
|
| 465 | + dispatcher.set_async_handler(Some(Box::new(move |_| {
|
|
| 454 | 466 | n.set(n.get() + 1);
|
| 455 | 467 | if n.get() < 2 {
|
| 456 | 468 | d.feed(&Bytes::from_static(b"650 Notification 2\r\n"))
|
| 457 | 469 | .unwrap();
|
| 458 | 470 | }
|
| 459 | - }));
|
|
| 471 | + })));
|
|
| 460 | 472 | dispatcher
|
| 461 | 473 | .feed(&Bytes::from_static(b"650 Notification 1\r\n"))
|
| 462 | 474 | .unwrap();
|
| ... | ... | @@ -514,9 +526,9 @@ mod tests { |
| 514 | 526 | #[test]
|
| 515 | 527 | fn error_propagation() {
|
| 516 | 528 | let dispatcher = ReplyDispatcher::new();
|
| 517 | - dispatcher.set_async_handler(Box::new(|_| {
|
|
| 529 | + dispatcher.set_async_handler(Some(Box::new(|_| {
|
|
| 518 | 530 | unreachable!("Errors should not be propagated to the async handler.");
|
| 519 | - }));
|
|
| 531 | + })));
|
|
| 520 | 532 | let first = Rc::new(Cell::new(false));
|
| 521 | 533 | let f = first.clone();
|
| 522 | 534 | let second = Rc::new(Cell::new(false));
|
| ... | ... | @@ -15,6 +15,8 @@ mod test_utils; |
| 15 | 15 | |
| 16 | 16 | pub use dispatcher::ReplyDispatcher;
|
| 17 | 17 | pub use error::ReplyError;
|
| 18 | -pub(crate) use factory::ReplyFactory;
|
|
| 19 | 18 | pub use line::{DetailReplyLine, EndReplyLine};
|
| 20 | 19 | pub use reply::Reply;
|
| 20 | + |
|
| 21 | +#[cfg(test)]
|
|
| 22 | +pub(crate) use test_utils::make_reply; |
| ... | ... | @@ -6,10 +6,19 @@ |
| 6 | 6 | use bytes::Bytes;
|
| 7 | 7 | |
| 8 | 8 | use super::{
|
| 9 | + factory::ReplyFactory,
|
|
| 9 | 10 | line::{DetailReplyLine, EndReplyLine},
|
| 10 | 11 | reply::Reply,
|
| 11 | 12 | };
|
| 12 | 13 | |
| 14 | +pub(crate) fn make_reply(data: &'static [u8]) -> Reply {
|
|
| 15 | + let mut factory = ReplyFactory::default();
|
|
| 16 | + let mut replies = factory.build(&Bytes::from_static(data)).unwrap();
|
|
| 17 | + assert_eq!(replies.len(), 1);
|
|
| 18 | + assert!(!factory.has_pending_data());
|
|
| 19 | + replies.pop_front().unwrap()
|
|
| 20 | +}
|
|
| 21 | + |
|
| 13 | 22 | pub(super) fn check_250_ok(reply: &Reply, has_details: bool) {
|
| 14 | 23 | assert_eq!(reply.has_details(), has_details);
|
| 15 | 24 | assert_eq!(
|
| ... | ... | @@ -2,18 +2,20 @@ |
| 2 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| 3 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| 4 | 4 | |
| 5 | -use bytes::Bytes;
|
|
| 6 | 5 | use nserror::nsresult;
|
| 7 | 6 | use nserror::{NS_ERROR_NOT_CONNECTED, NS_OK};
|
| 8 | 7 | use nsstring::{nsACString, nsCString};
|
| 9 | -use tor_provider::ctor::ControlPort;
|
|
| 10 | -use tor_provider::ctor::ControlSocketError;
|
|
| 11 | -use xpcom::interfaces::{nsIFile, ITorControlPort, ITorControlPortReceiver, ITorMessageHandler};
|
|
| 8 | +use tor_provider::ctor::{ControlPort, ControlSocketError};
|
|
| 9 | +use xpcom::interfaces::{nsIFile, torITorControlPortReceiver, torITorMessageHandler};
|
|
| 12 | 10 | use xpcom::RefPtr;
|
| 13 | 11 | |
| 12 | +// Actually used, but the compiler does not detect it.
|
|
| 13 | +#[allow(unused)]
|
|
| 14 | +use xpcom::interfaces::torITorControlPort;
|
|
| 15 | + |
|
| 14 | 16 | use super::control_socket::ControlSocketXpcom;
|
| 15 | 17 | |
| 16 | -#[xpcom(implement(ITorControlPort), atomic)]
|
|
| 18 | +#[xpcom(implement(torITorControlPort), atomic)]
|
|
| 17 | 19 | pub struct ControlPortXpcom {
|
| 18 | 20 | control_port: ControlPort,
|
| 19 | 21 | }
|
| ... | ... | @@ -32,42 +34,46 @@ impl ControlPortXpcom { |
| 32 | 34 | Ok(Self::allocate(InitControlPortXpcom { control_port }))
|
| 33 | 35 | }
|
| 34 | 36 | |
| 35 | - xpcom_method!(start => Start(receiver: *const ITorControlPortReceiver));
|
|
| 36 | - pub fn start(&self, receiver: &ITorControlPortReceiver) -> Result<(), nsresult> {
|
|
| 37 | + xpcom_method!(start => Start(receiver: *const torITorControlPortReceiver));
|
|
| 38 | + pub fn start(&self, receiver: &torITorControlPortReceiver) -> Result<(), nsresult> {
|
|
| 37 | 39 | let receiver = RefPtr::new(receiver);
|
| 38 | - self.control_port.set_async_handler(Box::new(move |reply| {
|
|
| 39 | - let mut buf = Vec::new();
|
|
| 40 | - if let Err(e) = reply.write_to(&mut buf) {
|
|
| 41 | - log::error!(
|
|
| 42 | - "Cannot convert the reply to the raw message: {}.",
|
|
| 43 | - e.to_string()
|
|
| 44 | - );
|
|
| 45 | - return;
|
|
| 46 | - }
|
|
| 47 | - if buf.ends_with(b"\r\n") {
|
|
| 48 | - buf.truncate(buf.len() - 2);
|
|
| 49 | - }
|
|
| 50 | - // These conversions re-use the buffer, Gecko uses the same
|
|
| 51 | - // allocator for Rust and C++ (see the nsstring crate).
|
|
| 52 | - let as_str = nsCString::from(buf);
|
|
| 53 | - // Safety: call to an XPCOM method that we expect to be exposed on
|
|
| 54 | - // Rust. As per the documentation in nsstring, it is safe to pass
|
|
| 55 | - // nsCStrings created in Rust to C++.
|
|
| 56 | - unsafe { receiver.OnAsyncMessage(&*as_str) };
|
|
| 57 | - }));
|
|
| 40 | + self.control_port
|
|
| 41 | + .set_async_handler(Some(Box::new(move |reply| {
|
|
| 42 | + let mut buf = Vec::new();
|
|
| 43 | + if let Err(e) = reply.write_to(&mut buf) {
|
|
| 44 | + log::error!(
|
|
| 45 | + "Cannot convert the reply to the raw message: {}.",
|
|
| 46 | + e.to_string()
|
|
| 47 | + );
|
|
| 48 | + return;
|
|
| 49 | + }
|
|
| 50 | + if buf.ends_with(b"\r\n") {
|
|
| 51 | + buf.truncate(buf.len() - 2);
|
|
| 52 | + }
|
|
| 53 | + // These conversions re-use the buffer, Gecko uses the same
|
|
| 54 | + // allocator for Rust and C++ (see the nsstring crate).
|
|
| 55 | + let as_str = nsCString::from(buf);
|
|
| 56 | + // Safety: call to an XPCOM method that we expect to be exposed
|
|
| 57 | + // on Rust. As per the documentation in nsstring, it is safe to
|
|
| 58 | + // pass nsCStrings created in Rust to C++.
|
|
| 59 | + unsafe { receiver.OnAsyncMessage(&*as_str) };
|
|
| 60 | + })));
|
|
| 58 | 61 | Ok(())
|
| 59 | 62 | }
|
| 60 | 63 | |
| 61 | - xpcom_method!(send_command => SendCommand(command: *const nsACString, handler: *const ITorMessageHandler));
|
|
| 64 | + xpcom_method!(send_command => SendCommand(command: *const nsACString, handler: *const torITorMessageHandler));
|
|
| 62 | 65 | pub fn send_command(
|
| 63 | 66 | &self,
|
| 64 | 67 | command: &nsACString,
|
| 65 | - handler: &ITorMessageHandler,
|
|
| 68 | + handler: &torITorMessageHandler,
|
|
| 66 | 69 | ) -> Result<(), nsresult> {
|
| 67 | - let command = Bytes::copy_from_slice(&command[..]);
|
|
| 70 | + let mut command = command.to_vec();
|
|
| 71 | + if !command.ends_with(b"\r\n") {
|
|
| 72 | + command.extend_from_slice(b"\r\n");
|
|
| 73 | + }
|
|
| 68 | 74 | let handler = RefPtr::new(handler);
|
| 69 | 75 | self.control_port.send_command(
|
| 70 | - command,
|
|
| 76 | + command.into(),
|
|
| 71 | 77 | Box::new(move |reply| {
|
| 72 | 78 | let mut buf = Vec::new();
|
| 73 | 79 | let reply = match reply {
|
| ... | ... | @@ -4,12 +4,16 @@ |
| 4 | 4 | |
| 5 | 5 | use nserror::{nsresult, NS_ERROR_NULL_POINTER, NS_OK};
|
| 6 | 6 | use nsstring::nsACString;
|
| 7 | -use xpcom::interfaces::{nsIFile, ITorControlPort, ITorService};
|
|
| 7 | +use xpcom::interfaces::{nsIFile, torITorControlPort};
|
|
| 8 | 8 | use xpcom::RefPtr;
|
| 9 | 9 | |
| 10 | 10 | use super::control_port::ControlPortXpcom;
|
| 11 | 11 | |
| 12 | -#[xpcom(implement(ITorService), atomic)]
|
|
| 12 | +// Actually used, but the compiler does not detect it.
|
|
| 13 | +#[allow(unused)]
|
|
| 14 | +use xpcom::interfaces::torITorService;
|
|
| 15 | + |
|
| 16 | +#[xpcom(implement(torITorService), atomic)]
|
|
| 13 | 17 | struct TorService {}
|
| 14 | 18 | |
| 15 | 19 | impl TorService {
|
| ... | ... | @@ -17,31 +21,31 @@ impl TorService { |
| 17 | 21 | TorService::allocate(InitTorService {})
|
| 18 | 22 | }
|
| 19 | 23 | |
| 20 | - xpcom_method!(create_control_port => CreateControlPort(host: *const nsACString, port: i32, out: *mut *const ITorControlPort));
|
|
| 24 | + xpcom_method!(create_control_port => CreateControlPort(host: *const nsACString, port: i32, out: *mut *const torITorControlPort));
|
|
| 21 | 25 | fn create_control_port(
|
| 22 | 26 | &self,
|
| 23 | 27 | host: &nsACString,
|
| 24 | 28 | port: i32,
|
| 25 | - out: *mut *const ITorControlPort,
|
|
| 29 | + out: *mut *const torITorControlPort,
|
|
| 26 | 30 | ) -> Result<(), nsresult> {
|
| 27 | 31 | if out.is_null() {
|
| 28 | 32 | return Err(NS_ERROR_NULL_POINTER);
|
| 29 | 33 | }
|
| 30 | - let cp = RefPtr::new(ControlPortXpcom::new_tcp(host, port)?.coerce::<ITorControlPort>());
|
|
| 34 | + let cp = RefPtr::new(ControlPortXpcom::new_tcp(host, port)?.coerce::<torITorControlPort>());
|
|
| 31 | 35 | cp.forget(unsafe { &mut *out });
|
| 32 | 36 | Ok(())
|
| 33 | 37 | }
|
| 34 | 38 | |
| 35 | - xpcom_method!(create_control_port_ipc => CreateControlPortIPC(socket: *const nsIFile, out: *mut *const ITorControlPort));
|
|
| 39 | + xpcom_method!(create_control_port_ipc => CreateControlPortIPC(socket: *const nsIFile, out: *mut *const torITorControlPort));
|
|
| 36 | 40 | fn create_control_port_ipc(
|
| 37 | 41 | &self,
|
| 38 | 42 | socket: &nsIFile,
|
| 39 | - out: *mut *const ITorControlPort,
|
|
| 43 | + out: *mut *const torITorControlPort,
|
|
| 40 | 44 | ) -> Result<(), nsresult> {
|
| 41 | 45 | if out.is_null() {
|
| 42 | 46 | return Err(NS_ERROR_NULL_POINTER);
|
| 43 | 47 | }
|
| 44 | - let cp = RefPtr::new(ControlPortXpcom::new_ipc(socket)?.coerce::<ITorControlPort>());
|
|
| 48 | + let cp = RefPtr::new(ControlPortXpcom::new_ipc(socket)?.coerce::<torITorControlPort>());
|
|
| 45 | 49 | cp.forget(unsafe { &mut *out });
|
| 46 | 50 | Ok(())
|
| 47 | 51 | }
|
| ... | ... | @@ -49,11 +53,11 @@ impl TorService { |
| 49 | 53 | |
| 50 | 54 | // See toolkit/components/extensions/storage/webext_storage_bridge/src/lib.rs.
|
| 51 | 55 | #[no_mangle]
|
| 52 | -pub unsafe extern "C" fn NewTorServiceImpl(result: *mut *const ITorService) -> nsresult {
|
|
| 56 | +pub unsafe extern "C" fn NewTorServiceImpl(result: *mut *const torITorService) -> nsresult {
|
|
| 53 | 57 | if result.is_null() {
|
| 54 | 58 | return NS_ERROR_NULL_POINTER;
|
| 55 | 59 | }
|
| 56 | 60 | let service = TorService::new();
|
| 57 | - RefPtr::new(service.coerce::<ITorService>()).forget(&mut *result);
|
|
| 61 | + RefPtr::new(service.coerce::<torITorService>()).forget(&mut *result);
|
|
| 58 | 62 | NS_OK
|
| 59 | 63 | } |
| ... | ... | @@ -59,5 +59,5 @@ |
| 59 | 59 | "nsIXULAppInfo": "appinfo",
|
| 60 | 60 | "nsIXULRuntime": "appinfo",
|
| 61 | 61 | "nsIXULStore": "xulStore",
|
| 62 | - "ITorService": "tor"
|
|
| 62 | + "torITorService": "tor"
|
|
| 63 | 63 | } |