Bug 1946184 - Fix computing the CSD margin right after calling HideWindowChrome(...
[gecko.git] / toolkit / components / bitsdownload / src / bits_interface / request.rs
blob460e3b4950910fb0af0101a6c3dcc12e77686735
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/. */
5 use super::{
6     action::{Action, ServiceAction},
7     error::{
8         ErrorStage::{MainThread, Pretask},
9         ErrorType,
10         ErrorType::{
11             BitsStateCancelled, FailedToDispatchRunnable, FailedToStartThread, InvalidArgument,
12             OperationAlreadyInProgress, TransferAlreadyComplete,
13         },
14     },
15     monitor::MonitorRunnable,
16     task::{
17         CancelTask, ChangeMonitorIntervalTask, CompleteTask, Priority, ResumeTask,
18         SetNoProgressTimeoutTask, SetPriorityTask, SuspendTask,
19     },
20     BitsService, BitsTaskError,
22 use nsIBitsRequest_method; // From xpcom_method.rs
24 use bits_client::{BitsMonitorClient, Guid};
25 use log::{error, info, warn};
26 use moz_task::create_thread;
27 use nserror::{nsresult, NS_ERROR_ABORT, NS_ERROR_NOT_IMPLEMENTED, NS_OK};
28 use nsstring::{nsACString, nsCString};
29 use std::{cell::Cell, fmt};
30 use xpcom::{
31     interfaces::{
32         nsIBits, nsIBitsCallback, nsILoadGroup, nsIProgressEventSink, nsIRequestObserver,
33         nsISupports, nsIThread, nsLoadFlags,
34     },
35     xpcom, xpcom_method, RefPtr, XpCom,
38 /// This structure exists to resolve a race condition. If cancel is called, we
39 /// don't want to immediately set the request state to cancelled, because the
40 /// cancel action could fail. But it's possible that on_stop() could be called
41 /// before the cancel action resolves, and the correct status should be sent to
42 /// OnStopRequest.
43 /// This is how this race condition will be resolved:
44 ///   1.  cancel() is called, which sets the CancelAction to InProgress and
45 ///       stores in it the status that should be set if it succeeds.
46 ///   2.  cancel() dispatches the cancel task off thread.
47 /// At this point, things unfold in one of two ways, depending on the race
48 /// condition. Either:
49 ///   3.  The cancel task returns to the main thread and calls
50 ///       BitsRequest::finish_cancel_action.
51 ///   4.  If the cancel action succeeded, the appropriate status codes are set
52 ///       and the CancelAction is set to RequestEndPending.
53 ///       If the cancel action failed, the CancelAction is set to NotInProgress.
54 ///   5.  The MonitorRunnable detects that the transfer has ended and calls
55 ///       BitsRequest::on_stop, passing different status codes.
56 ///   6.  BitsRequest::on_stop checks the CancelAction and
57 ///       If the cancel action succeeded and RequestEndPending is set, the
58 ///       status codes that were set by BitsRequest::finish_cancel_action are
59 ///       left untouched.
60 ///       If the cancel action failed and NotInProgress is set, the status codes
61 ///       passed to BitsRequest::on_stop are set.
62 ///   7.  onStopRequest is called with the correct status code.
63 /// Or, if MonitorRunnable calls on_stop before the cancel task can finish:
64 ///   3.  The MonitorRunnable detects that the transfer has ended and calls
65 ///       BitsRequest::on_stop, passing status codes to it.
66 ///   4.  BitsRequest::on_stop checks the CancelAction, sees it is set to
67 ///       InProgress, and sets it to RequestEndedWhileInProgress, carrying over
68 ///       the status code from InProgress.
69 ///   5.  BitsRequest::on_stop sets the status to the value passed to it, which
70 ///       will be overwritten if the cancel action succeeds, but kept if it
71 ///       fails.
72 ///   6.  BitsRequest::on_stop returns early, without calling OnStopRequest.
73 ///   7.  The cancel task returns to the main thread and calls
74 ///       BitsRequest::finish_cancel_action.
75 ///   8.  If the cancel action succeeded, the status codes are set from the
76 ///       value stored in RequestEndedWhileInProgress.
77 ///       If the cancel action failed, the status codes are not changed.
78 ///   9.  The CancelAction is set to NotInProgress.
79 ///   10. BitsRequest::finish_cancel_action calls BitsRequest::on_stop without
80 ///       passing it any status codes.
81 ///   11. onStopRequest is called with the correct status code.
82 #[derive(Clone, Copy, PartialEq)]
83 enum CancelAction {
84     NotInProgress,
85     InProgress(Option<nsresult>),
86     RequestEndedWhileInProgress(Option<nsresult>),
87     RequestEndPending,
90 #[xpcom(implement(nsIBitsRequest), nonatomic)]
91 pub struct BitsRequest {
92     bits_id: Guid,
93     bits_service: RefPtr<BitsService>,
94     // Stores the value to be returned by nsIRequest::IsPending.
95     download_pending: Cell<bool>,
96     // Stores the value to be returned by nsIRequest::GetStatus.
97     download_status_nsresult: Cell<nsresult>,
98     // Stores an ErrorType if the request has failed, or None to represent the
99     // success state.
100     download_status_error_type: Cell<Option<ErrorType>>,
101     // This option will be None only after OnStopRequest has been fired.
102     monitor_thread: Cell<Option<RefPtr<nsIThread>>>,
103     monitor_timeout_ms: u32,
104     observer: RefPtr<nsIRequestObserver>,
105     // started indicates whether or not OnStartRequest has been fired.
106     started: Cell<bool>,
107     // finished indicates whether or not we have called
108     // BitsService::dec_request_count() to (assuming that there are no other
109     // requests) shutdown the command thread.
110     finished: Cell<bool>,
111     cancel_action: Cell<CancelAction>,
114 impl fmt::Debug for BitsRequest {
115     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116         write!(f, "BitsRequest {{ id: {} }}", self.bits_id)
117     }
120 /// This implements the nsIBitsRequest interface, documented in nsIBits.idl, to
121 /// enable BITS job management. This interface deals only with BITS jobs that
122 /// already exist. Jobs can be created via BitsService, which will create a
123 /// BitsRequest for that job.
125 /// This is a primarily asynchronous interface, which is accomplished via
126 /// callbacks of type nsIBitsCallback. The callback is passed in as an argument
127 /// and is then passed off-thread via a Task. The Task interacts with BITS and
128 /// is dispatched back to the main thread with the BITS result. Back on the main
129 /// thread, it returns that result via the callback.
130 impl BitsRequest {
131     pub fn new(
132         id: Guid,
133         bits_service: RefPtr<BitsService>,
134         monitor_timeout_ms: u32,
135         observer: RefPtr<nsIRequestObserver>,
136         context: Option<RefPtr<nsISupports>>,
137         monitor_client: BitsMonitorClient,
138         action: ServiceAction,
139     ) -> Result<RefPtr<BitsRequest>, BitsTaskError> {
140         let _ = context;
141         let action: Action = action.into();
142         let monitor_thread = create_thread("BitsMonitor").map_err(|rv| {
143             BitsTaskError::from_nsresult(FailedToStartThread, action, MainThread, rv)
144         })?;
146         // BitsRequest.drop() will call dec_request_count
147         bits_service.inc_request_count();
148         let request: RefPtr<BitsRequest> = BitsRequest::allocate(InitBitsRequest {
149             bits_id: id.clone(),
150             bits_service,
151             download_pending: Cell::new(true),
152             download_status_nsresult: Cell::new(NS_OK),
153             download_status_error_type: Cell::new(None),
154             monitor_thread: Cell::new(Some(monitor_thread.clone())),
155             monitor_timeout_ms,
156             observer,
157             started: Cell::new(false),
158             finished: Cell::new(false),
159             cancel_action: Cell::new(CancelAction::NotInProgress),
160         });
162         let monitor_runnable =
163             MonitorRunnable::new(request.clone(), id, monitor_timeout_ms, monitor_client);
165         if let Err(rv) = monitor_runnable.dispatch(monitor_thread.clone()) {
166             request.shutdown_monitor_thread();
167             return Err(BitsTaskError::from_nsresult(
168                 FailedToDispatchRunnable,
169                 action,
170                 MainThread,
171                 rv,
172             ));
173         }
175         Ok(request)
176     }
178     pub fn get_monitor_thread(&self) -> Option<RefPtr<nsIThread>> {
179         let monitor_thread = self.monitor_thread.take();
180         self.monitor_thread.set(monitor_thread.clone());
181         monitor_thread
182     }
184     fn has_monitor_thread(&self) -> bool {
185         let maybe_monitor_thread = self.monitor_thread.take();
186         let transferred = maybe_monitor_thread.is_some();
187         self.monitor_thread.set(maybe_monitor_thread);
188         transferred
189     }
191     /// If this returns an true, it means that:
192     ///   - The monitor thread and monitor runnable may have been shut down
193     ///   - The BITS job is not in the TRANSFERRING state
194     ///   - The download either completed, failed, or was cancelled
195     ///   - The BITS job may or may not still need complete() or cancel() to be
196     ///     called on it
197     fn request_has_transferred(&self) -> bool {
198         self.request_has_completed() || !self.has_monitor_thread()
199     }
201     /// If this returns an error, it means that:
202     ///   - complete() or cancel() has been called on the BITS job.
203     ///   - BitsService::dec_request_count has already been called.
204     ///   - The BitsClient object that this request was using may have been
205     ///     dropped.
206     fn request_has_completed(&self) -> bool {
207         self.finished.get()
208     }
210     fn shutdown_monitor_thread(&self) {
211         if let Some(monitor_thread) = self.monitor_thread.take() {
212             if let Err(rv) = unsafe { monitor_thread.AsyncShutdown() }.to_result() {
213                 warn!("Failed to shut down monitor thread: {:?}", rv);
214                 warn!("Releasing reference to thread that failed to shut down!");
215             }
216         }
217     }
219     /**
220      * To be called when the transfer starts. Fires observer.OnStartRequest exactly once.
221      */
222     pub fn on_start(&self) {
223         if self.started.get() {
224             return;
225         }
226         self.started.set(true);
227         if let Err(rv) = unsafe { self.observer.OnStartRequest(self.coerce()) }.to_result() {
228             // This behavior is specified by nsIRequestObserver.
229             // See nsIRequestObserver.idl
230             info!(
231                 "Cancelling download because OnStartRequest rejected with: {:?}",
232                 rv
233             );
234             if let Err(rv) = self.cancel(NS_ERROR_ABORT, None) {
235                 warn!("Failed to cancel download: {:?}", rv);
236             }
237         }
238     }
240     pub fn on_progress(&self, transferred_bytes: i64, total_bytes: i64) {
241         if let Some(progress_event_sink) = self.observer.query_interface::<nsIProgressEventSink>() {
242             unsafe {
243                 progress_event_sink.OnProgress(self.coerce(), transferred_bytes, total_bytes);
244             }
245         }
246     }
248     /// To be called when the transfer stops (fails or completes). Fires
249     /// observer.OnStopRequest exactly once, though the call may be delayed to
250     /// resolve a race condition.
251     ///
252     /// The status values, if passed, will be stored in download_status_nsresult
253     /// and download_status_error_type, unless they have been overridden by a
254     /// cancel action.
255     ///
256     /// See the documentation for CancelAction for details.
257     pub fn on_stop(&self, maybe_status: Option<(nsresult, Option<ErrorType>)>) {
258         if !self.has_monitor_thread() {
259             // If the request has already stopped, don't stop it again
260             return;
261         }
263         match self.cancel_action.get() {
264             CancelAction::InProgress(saved_status)
265             | CancelAction::RequestEndedWhileInProgress(saved_status) => {
266                 if let Some((status, result)) = maybe_status {
267                     self.download_status_nsresult.set(status);
268                     self.download_status_error_type.set(result);
269                 }
271                 info!("Deferring OnStopRequest until Cancel Task completes");
272                 self.cancel_action
273                     .set(CancelAction::RequestEndedWhileInProgress(saved_status));
274                 return;
275             }
276             CancelAction::NotInProgress => {
277                 if let Some((status, result)) = maybe_status {
278                     self.download_status_nsresult.set(status);
279                     self.download_status_error_type.set(result);
280                 }
281             }
282             CancelAction::RequestEndPending => {
283                 // Don't set the status variables if the end of this request was
284                 // the result of a cancel action. The cancel action already set
285                 // those values and they should not be changed.
286                 // See the CancelAction documentation for details.
287             }
288         }
290         self.download_pending.set(false);
291         self.shutdown_monitor_thread();
292         unsafe {
293             self.observer
294                 .OnStopRequest(self.coerce(), self.download_status_nsresult.get());
295         }
296     }
298     /// To be called after a cancel or complete task has run successfully. If
299     /// this is the only BitsRequest running, this will shut down
300     /// BitsService's command thread, destroying the BitsClient.
301     pub fn on_finished(&self) {
302         if self.finished.get() {
303             return;
304         }
305         self.finished.set(true);
306         self.bits_service.dec_request_count();
307     }
309     // Return the same thing for GetBitsId() and GetName().
310     xpcom_method!(
311         maybe_get_bits_id => GetBitsId() -> nsACString
312     );
313     xpcom_method!(
314         maybe_get_bits_id => GetName() -> nsACString
315     );
316     fn maybe_get_bits_id(&self) -> Result<nsCString, nsresult> {
317         Ok(self.get_bits_id())
318     }
319     pub fn get_bits_id(&self) -> nsCString {
320         nsCString::from(self.bits_id.to_string())
321     }
323     xpcom_method!(
324         get_bits_transfer_error_nsIBitsRequest => GetTransferError() -> i32
325     );
326     #[allow(non_snake_case)]
327     fn get_bits_transfer_error_nsIBitsRequest(&self) -> Result<i32, nsresult> {
328         let error_type = match self.download_status_error_type.get() {
329             None => nsIBits::ERROR_TYPE_SUCCESS,
330             Some(error_type) => error_type.bits_code(),
331         };
332         Ok(error_type)
333     }
335     xpcom_method!(
336         is_pending => IsPending() -> bool
337     );
338     fn is_pending(&self) -> Result<bool, nsresult> {
339         Ok(self.download_pending.get())
340     }
342     xpcom_method!(
343         get_status_nsIRequest => GetStatus() -> nsresult
344     );
345     #[allow(non_snake_case)]
346     fn get_status_nsIRequest(&self) -> Result<nsresult, nsresult> {
347         Ok(self.get_status())
348     }
349     pub fn get_status(&self) -> nsresult {
350         self.download_status_nsresult.get()
351     }
353     nsIBitsRequest_method!(
354         [Action::SetMonitorInterval]
355         change_monitor_interval => ChangeMonitorInterval(update_interval_ms: u32)
356     );
357     fn change_monitor_interval(
358         &self,
359         update_interval_ms: u32,
360         callback: &nsIBitsCallback,
361     ) -> Result<(), BitsTaskError> {
362         if update_interval_ms == 0 || update_interval_ms >= self.monitor_timeout_ms {
363             return Err(BitsTaskError::new(
364                 InvalidArgument,
365                 Action::SetMonitorInterval,
366                 Pretask,
367             ));
368         }
369         if self.request_has_transferred() {
370             return Err(BitsTaskError::new(
371                 TransferAlreadyComplete,
372                 Action::SetMonitorInterval,
373                 Pretask,
374             ));
375         }
377         let task: Box<ChangeMonitorIntervalTask> = Box::new(ChangeMonitorIntervalTask::new(
378             RefPtr::new(self),
379             self.bits_id.clone(),
380             update_interval_ms,
381             RefPtr::new(callback),
382         ));
384         self.bits_service.dispatch_runnable_to_command_thread(
385             task,
386             "BitsRequest::change_monitor_interval",
387             Action::SetMonitorInterval,
388         )
389     }
391     nsIBitsRequest_method!(
392         [Action::Cancel]
393         cancel_nsIBitsRequest => CancelAsync(status: nsresult)
394     );
395     #[allow(non_snake_case)]
396     fn cancel_nsIBitsRequest(
397         &self,
398         status: nsresult,
399         callback: &nsIBitsCallback,
400     ) -> Result<(), BitsTaskError> {
401         self.cancel(status, Some(RefPtr::new(callback)))
402     }
403     xpcom_method!(
404         cancel_nsIRequest => Cancel(status: nsresult)
405     );
406     #[allow(non_snake_case)]
407     fn cancel_nsIRequest(&self, status: nsresult) -> Result<(), BitsTaskError> {
408         self.cancel(status, None)
409     }
411     fn cancel(
412         &self,
413         status: nsresult,
414         callback: Option<RefPtr<nsIBitsCallback>>,
415     ) -> Result<(), BitsTaskError> {
416         if status.clone().succeeded() {
417             return Err(BitsTaskError::new(InvalidArgument, Action::Cancel, Pretask));
418         }
419         if self.request_has_completed() {
420             return Err(BitsTaskError::new(
421                 TransferAlreadyComplete,
422                 Action::Cancel,
423                 Pretask,
424             ));
425         }
427         // If the transfer is still in a success state, cancelling it should move it to the failure
428         // state that was passed. But if the transfer already failed, the only reason to call cancel
429         // is to remove the job from BITS. So in that case, we should keep the failure status that
430         // we already have.
431         let maybe_status: Option<nsresult> = if self.download_status_nsresult.get().failed() {
432             None
433         } else {
434             Some(status)
435         };
437         if self.cancel_action.get() != CancelAction::NotInProgress {
438             return Err(BitsTaskError::new(
439                 OperationAlreadyInProgress,
440                 Action::Cancel,
441                 Pretask,
442             ));
443         }
444         self.cancel_action
445             .set(CancelAction::InProgress(maybe_status));
447         let task: Box<CancelTask> = Box::new(CancelTask::new(
448             RefPtr::new(self),
449             self.bits_id.clone(),
450             callback,
451         ));
453         self.bits_service.dispatch_runnable_to_command_thread(
454             task,
455             "BitsRequest::cancel",
456             Action::Cancel,
457         )
458     }
460     /// This function must be called when a cancel action completes.
461     ///
462     /// See the documentation for CancelAction for details.
463     pub fn finish_cancel_action(&self, cancelled_successfully: bool) {
464         let (maybe_status, transfer_ended) = match self.cancel_action.get() {
465             CancelAction::InProgress(maybe_status) => (maybe_status, false),
466             CancelAction::RequestEndedWhileInProgress(maybe_status) => (maybe_status, true),
467             _ => {
468                 error!("End of cancel action, but cancel action is not in progress!");
469                 return;
470             }
471         };
472         info!(
473             "Finishing cancel action. cancel success = {}",
474             cancelled_successfully
475         );
476         if cancelled_successfully {
477             // If no status was provided, it is because this cancel action removed the BITS job
478             // after the job had already failed. Keep the original error codes.
479             if let Some(status) = maybe_status {
480                 self.download_status_nsresult.set(status);
481                 self.download_status_error_type
482                     .set(Some(BitsStateCancelled));
483             }
484         }
486         let next_stage = if cancelled_successfully && !transfer_ended {
487             // This signals on_stop not to allow the status codes set above to
488             // be overridden by the ones passed to it.
489             CancelAction::RequestEndPending
490         } else {
491             CancelAction::NotInProgress
492         };
493         self.cancel_action.set(next_stage);
495         if cancelled_successfully {
496             self.on_finished();
497         }
499         if transfer_ended {
500             info!("Running deferred OnStopRequest");
501             self.on_stop(None);
502         }
503     }
505     nsIBitsRequest_method!(
506         [Action::SetPriority]
507         set_priority_high => SetPriorityHigh()
508     );
509     fn set_priority_high(&self, callback: &nsIBitsCallback) -> Result<(), BitsTaskError> {
510         self.set_priority(Priority::High, callback)
511     }
513     nsIBitsRequest_method!(
514         [Action::SetPriority]
515         set_priority_low => SetPriorityLow()
516     );
517     fn set_priority_low(&self, callback: &nsIBitsCallback) -> Result<(), BitsTaskError> {
518         self.set_priority(Priority::Low, callback)
519     }
521     fn set_priority(
522         &self,
523         priority: Priority,
524         callback: &nsIBitsCallback,
525     ) -> Result<(), BitsTaskError> {
526         if self.request_has_transferred() {
527             return Err(BitsTaskError::new(
528                 TransferAlreadyComplete,
529                 Action::SetPriority,
530                 Pretask,
531             ));
532         }
534         let task: Box<SetPriorityTask> = Box::new(SetPriorityTask::new(
535             RefPtr::new(self),
536             self.bits_id.clone(),
537             priority,
538             RefPtr::new(callback),
539         ));
541         self.bits_service.dispatch_runnable_to_command_thread(
542             task,
543             "BitsRequest::set_priority",
544             Action::SetPriority,
545         )
546     }
548     nsIBitsRequest_method!(
549         [Action::SetNoProgressTimeout]
550         set_no_progress_timeout => SetNoProgressTimeout(timeout_secs: u32)
551     );
552     fn set_no_progress_timeout(
553         &self,
554         timeout_secs: u32,
555         callback: &nsIBitsCallback,
556     ) -> Result<(), BitsTaskError> {
557         if self.request_has_transferred() {
558             return Err(BitsTaskError::new(
559                 TransferAlreadyComplete,
560                 Action::SetNoProgressTimeout,
561                 Pretask,
562             ));
563         }
565         let task: Box<SetNoProgressTimeoutTask> = Box::new(SetNoProgressTimeoutTask::new(
566             RefPtr::new(self),
567             self.bits_id.clone(),
568             timeout_secs,
569             RefPtr::new(callback),
570         ));
572         self.bits_service.dispatch_runnable_to_command_thread(
573             task,
574             "BitsRequest::set_no_progress_timeout",
575             Action::SetNoProgressTimeout,
576         )
577     }
579     nsIBitsRequest_method!(
580         [Action::Complete]
581         complete => Complete()
582     );
583     fn complete(&self, callback: &nsIBitsCallback) -> Result<(), BitsTaskError> {
584         if self.request_has_completed() {
585             return Err(BitsTaskError::new(
586                 TransferAlreadyComplete,
587                 Action::Complete,
588                 Pretask,
589             ));
590         }
592         let task: Box<CompleteTask> = Box::new(CompleteTask::new(
593             RefPtr::new(self),
594             self.bits_id.clone(),
595             RefPtr::new(callback),
596         ));
598         self.bits_service.dispatch_runnable_to_command_thread(
599             task,
600             "BitsRequest::complete",
601             Action::Complete,
602         )
603     }
605     nsIBitsRequest_method!(
606         [Action::Suspend]
607         suspend_nsIBitsRequest => SuspendAsync()
608     );
609     #[allow(non_snake_case)]
610     fn suspend_nsIBitsRequest(&self, callback: &nsIBitsCallback) -> Result<(), BitsTaskError> {
611         self.suspend(Some(RefPtr::new(callback)))
612     }
613     xpcom_method!(
614         suspend_nsIRequest => Suspend()
615     );
616     #[allow(non_snake_case)]
617     fn suspend_nsIRequest(&self) -> Result<(), BitsTaskError> {
618         self.suspend(None)
619     }
621     fn suspend(&self, callback: Option<RefPtr<nsIBitsCallback>>) -> Result<(), BitsTaskError> {
622         if self.request_has_transferred() {
623             return Err(BitsTaskError::new(
624                 TransferAlreadyComplete,
625                 Action::Suspend,
626                 Pretask,
627             ));
628         }
630         let task: Box<SuspendTask> = Box::new(SuspendTask::new(
631             RefPtr::new(self),
632             self.bits_id.clone(),
633             callback,
634         ));
636         self.bits_service.dispatch_runnable_to_command_thread(
637             task,
638             "BitsRequest::suspend",
639             Action::Suspend,
640         )
641     }
643     nsIBitsRequest_method!(
644         [Action::Resume]
645         resume_nsIBitsRequest => ResumeAsync()
646     );
647     #[allow(non_snake_case)]
648     fn resume_nsIBitsRequest(&self, callback: &nsIBitsCallback) -> Result<(), BitsTaskError> {
649         self.resume(Some(RefPtr::new(callback)))
650     }
651     xpcom_method!(
652         resume_nsIRequest => Resume()
653     );
654     #[allow(non_snake_case)]
655     fn resume_nsIRequest(&self) -> Result<(), BitsTaskError> {
656         self.resume(None)
657     }
659     fn resume(&self, callback: Option<RefPtr<nsIBitsCallback>>) -> Result<(), BitsTaskError> {
660         if self.request_has_transferred() {
661             return Err(BitsTaskError::new(
662                 TransferAlreadyComplete,
663                 Action::Resume,
664                 Pretask,
665             ));
666         }
668         let task: Box<ResumeTask> = Box::new(ResumeTask::new(
669             RefPtr::new(self),
670             self.bits_id.clone(),
671             callback,
672         ));
674         self.bits_service.dispatch_runnable_to_command_thread(
675             task,
676             "BitsRequest::resume",
677             Action::Resume,
678         )
679     }
681     xpcom_method!(
682         get_load_group => GetLoadGroup() -> *const nsILoadGroup
683     );
685     /**
686      * As stated in nsIBits.idl, nsIBits interfaces are not expected to
687      * implement the loadGroup or loadFlags attributes. This implementation
688      * provides only null implementations only for these methods.
689      */
690     fn get_load_group(&self) -> Result<RefPtr<nsILoadGroup>, nsresult> {
691         Err(NS_ERROR_NOT_IMPLEMENTED)
692     }
694     xpcom_method!(
695         set_load_group => SetLoadGroup(_load_group: *const nsILoadGroup)
696     );
697     fn set_load_group(&self, _load_group: &nsILoadGroup) -> Result<(), nsresult> {
698         Err(NS_ERROR_NOT_IMPLEMENTED)
699     }
701     xpcom_method!(
702         get_load_flags => GetLoadFlags() -> nsLoadFlags
703     );
704     fn get_load_flags(&self) -> Result<nsLoadFlags, nsresult> {
705         Err(NS_ERROR_NOT_IMPLEMENTED)
706     }
708     xpcom_method!(
709         set_load_flags => SetLoadFlags(_load_flags: nsLoadFlags)
710     );
711     fn set_load_flags(&self, _load_flags: nsLoadFlags) -> Result<(), nsresult> {
712         Err(NS_ERROR_NOT_IMPLEMENTED)
713     }
715     xpcom_method!(
716         get_trr_mode => GetTRRMode() -> u32
717     );
718     fn get_trr_mode(&self) -> Result<u32, nsresult> {
719         Err(NS_ERROR_NOT_IMPLEMENTED)
720     }
722     xpcom_method!(
723         set_trr_mode => SetTRRMode(_trr_mode: u32)
724     );
725     fn set_trr_mode(&self, _trr_mode: u32) -> Result<(), nsresult> {
726         Err(NS_ERROR_NOT_IMPLEMENTED)
727     }
729     xpcom_method!(
730         get_canceled_reason => GetCanceledReason() -> nsACString
731     );
732     fn get_canceled_reason(&self) -> Result<nsCString, nsresult> {
733         Err(NS_ERROR_NOT_IMPLEMENTED)
734     }
736     xpcom_method!(
737         set_canceled_reason => SetCanceledReason(_reason: *const nsACString)
738     );
739     fn set_canceled_reason(&self, _reason: *const nsACString) -> Result<(), nsresult> {
740         Err(NS_ERROR_NOT_IMPLEMENTED)
741     }
743     xpcom_method!(
744         cancel_with_reason_nsIRequest => CancelWithReason(status: nsresult, _reason: *const nsACString)
745     );
746     #[allow(non_snake_case)]
747     fn cancel_with_reason_nsIRequest(
748         &self,
749         status: nsresult,
750         _reason: *const nsACString,
751     ) -> Result<(), BitsTaskError> {
752         self.cancel(status, None)
753     }
756 impl Drop for BitsRequest {
757     fn drop(&mut self) {
758         // Make sure that the monitor thread gets cleaned up.
759         self.shutdown_monitor_thread();
760         // Make sure we tell BitsService that we are done with the command thread.
761         self.on_finished();
762     }