tor-browser

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

UnderlyingSinkCallbackHelpers.h (7837B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_UnderlyingSinkCallbackHelpers_h
      8 #define mozilla_dom_UnderlyingSinkCallbackHelpers_h
      9 
     10 #include "mozilla/Buffer.h"
     11 #include "mozilla/HoldDropJSObjects.h"
     12 #include "mozilla/Maybe.h"
     13 #include "mozilla/dom/Promise.h"
     14 #include "mozilla/dom/UnderlyingSinkBinding.h"
     15 #include "nsCycleCollectionParticipant.h"
     16 #include "nsIAsyncOutputStream.h"
     17 #include "nsISupports.h"
     18 #include "nsISupportsImpl.h"
     19 
     20 /*
     21 * See the comment in UnderlyingSourceCallbackHelpers.h!
     22 *
     23 * A native implementation of these callbacks is however currently not required.
     24 */
     25 namespace mozilla::dom {
     26 
     27 class WritableStreamDefaultController;
     28 
     29 class UnderlyingSinkAlgorithmsBase : public nsISupports {
     30 public:
     31  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     32  NS_DECL_CYCLE_COLLECTION_CLASS(UnderlyingSinkAlgorithmsBase)
     33 
     34  MOZ_CAN_RUN_SCRIPT virtual void StartCallback(
     35      JSContext* aCx, WritableStreamDefaultController& aController,
     36      JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv) = 0;
     37 
     38  MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> WriteCallback(
     39      JSContext* aCx, JS::Handle<JS::Value> aChunk,
     40      WritableStreamDefaultController& aController, ErrorResult& aRv) = 0;
     41 
     42  MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> CloseCallback(
     43      JSContext* aCx, ErrorResult& aRv) = 0;
     44 
     45  MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> AbortCallback(
     46      JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
     47      ErrorResult& aRv) = 0;
     48 
     49  // Implement this when you need to release underlying resources immediately
     50  // from closed/errored(aborted) streams, without waiting for GC.
     51  virtual void ReleaseObjects() {}
     52 
     53 protected:
     54  virtual ~UnderlyingSinkAlgorithmsBase() = default;
     55 };
     56 
     57 // https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink
     58 class UnderlyingSinkAlgorithms final : public UnderlyingSinkAlgorithmsBase {
     59 public:
     60  NS_DECL_ISUPPORTS_INHERITED
     61  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
     62      UnderlyingSinkAlgorithms, UnderlyingSinkAlgorithmsBase)
     63 
     64  UnderlyingSinkAlgorithms(nsIGlobalObject* aGlobal,
     65                           JS::Handle<JSObject*> aUnderlyingSink,
     66                           UnderlyingSink& aUnderlyingSinkDict)
     67      : mGlobal(aGlobal), mUnderlyingSink(aUnderlyingSink) {
     68    // Step 6. (implicit Step 2.)
     69    if (aUnderlyingSinkDict.mStart.WasPassed()) {
     70      mStartCallback = aUnderlyingSinkDict.mStart.Value();
     71    }
     72 
     73    // Step 7. (implicit Step 3.)
     74    if (aUnderlyingSinkDict.mWrite.WasPassed()) {
     75      mWriteCallback = aUnderlyingSinkDict.mWrite.Value();
     76    }
     77 
     78    // Step 8. (implicit Step 4.)
     79    if (aUnderlyingSinkDict.mClose.WasPassed()) {
     80      mCloseCallback = aUnderlyingSinkDict.mClose.Value();
     81    }
     82 
     83    // Step 9. (implicit Step 5.)
     84    if (aUnderlyingSinkDict.mAbort.WasPassed()) {
     85      mAbortCallback = aUnderlyingSinkDict.mAbort.Value();
     86    }
     87 
     88    mozilla::HoldJSObjects(this);
     89  };
     90 
     91  MOZ_CAN_RUN_SCRIPT void StartCallback(
     92      JSContext* aCx, WritableStreamDefaultController& aController,
     93      JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv) override;
     94 
     95  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WriteCallback(
     96      JSContext* aCx, JS::Handle<JS::Value> aChunk,
     97      WritableStreamDefaultController& aController, ErrorResult& aRv) override;
     98 
     99  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CloseCallback(
    100      JSContext* aCx, ErrorResult& aRv) override;
    101 
    102  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> AbortCallback(
    103      JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
    104      ErrorResult& aRv) override;
    105 
    106 protected:
    107  ~UnderlyingSinkAlgorithms() override { mozilla::DropJSObjects(this); }
    108 
    109 private:
    110  // Virtually const, but are cycle collected
    111  nsCOMPtr<nsIGlobalObject> mGlobal;
    112  JS::Heap<JSObject*> mUnderlyingSink;
    113  MOZ_KNOWN_LIVE RefPtr<UnderlyingSinkStartCallback> mStartCallback;
    114  MOZ_KNOWN_LIVE RefPtr<UnderlyingSinkWriteCallback> mWriteCallback;
    115  MOZ_KNOWN_LIVE RefPtr<UnderlyingSinkCloseCallback> mCloseCallback;
    116  MOZ_KNOWN_LIVE RefPtr<UnderlyingSinkAbortCallback> mAbortCallback;
    117 };
    118 
    119 // https://streams.spec.whatwg.org/#writablestream-set-up
    120 // Wrappers defined by the "Set up" methods in the spec.
    121 // (closeAlgorithmWrapper, abortAlgorithmWrapper)
    122 // This helps you just return nullptr when 1) the algorithm is synchronous, or
    123 // 2) an error occurred, as this wrapper will return a resolved or rejected
    124 // promise respectively.
    125 // Note that StartCallback is only for JS consumers to access the
    126 // controller, and thus is no-op here since native consumers can call
    127 // `ErrorNative()` etc. without direct controller access.
    128 class UnderlyingSinkAlgorithmsWrapper : public UnderlyingSinkAlgorithmsBase {
    129 public:
    130  void StartCallback(JSContext* aCx,
    131                     WritableStreamDefaultController& aController,
    132                     JS::MutableHandle<JS::Value> aRetVal,
    133                     ErrorResult& aRv) final {
    134    // Step 1: Let startAlgorithm be an algorithm that returns undefined.
    135    aRetVal.setUndefined();
    136  }
    137 
    138  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WriteCallback(
    139      JSContext* aCx, JS::Handle<JS::Value> aChunk,
    140      WritableStreamDefaultController& aController, ErrorResult& aRv) final;
    141 
    142  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CloseCallback(
    143      JSContext* aCx, ErrorResult& aRv) final;
    144 
    145  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> AbortCallback(
    146      JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
    147      ErrorResult& aRv) final;
    148 
    149  virtual already_AddRefed<Promise> WriteCallbackImpl(
    150      JSContext* aCx, JS::Handle<JS::Value> aChunk,
    151      WritableStreamDefaultController& aController, ErrorResult& aRv) = 0;
    152 
    153  virtual already_AddRefed<Promise> CloseCallbackImpl(JSContext* aCx,
    154                                                      ErrorResult& aRv) {
    155    // (closeAlgorithm is optional, give null by default)
    156    return nullptr;
    157  }
    158 
    159  virtual already_AddRefed<Promise> AbortCallbackImpl(
    160      JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
    161      ErrorResult& aRv) {
    162    // (abortAlgorithm is optional, give null by default)
    163    return nullptr;
    164  }
    165 };
    166 
    167 class WritableStreamToOutput final : public UnderlyingSinkAlgorithmsWrapper,
    168                                     public nsIOutputStreamCallback {
    169  NS_DECL_ISUPPORTS_INHERITED
    170  NS_DECL_NSIOUTPUTSTREAMCALLBACK
    171  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WritableStreamToOutput,
    172                                           UnderlyingSinkAlgorithmsBase)
    173 
    174  WritableStreamToOutput(nsIGlobalObject* aParent,
    175                         nsIAsyncOutputStream* aOutput)
    176      : mWritten(0), mParent(aParent), mOutput(aOutput) {}
    177 
    178  // Streams algorithms
    179 
    180  already_AddRefed<Promise> WriteCallbackImpl(
    181      JSContext* aCx, JS::Handle<JS::Value> aChunk,
    182      WritableStreamDefaultController& aController, ErrorResult& aRv) override;
    183 
    184  // No CloseCallbackImpl() since ReleaseObjects() will call Close()
    185 
    186  already_AddRefed<Promise> AbortCallbackImpl(
    187      JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
    188      ErrorResult& aRv) override;
    189 
    190  void ReleaseObjects() override;
    191 
    192 private:
    193  ~WritableStreamToOutput() override = default;
    194 
    195  void ClearData() {
    196    mData = Nothing();
    197    mPromise = nullptr;
    198    mWritten = 0;
    199  }
    200 
    201  uint32_t mWritten;
    202  nsCOMPtr<nsIGlobalObject> mParent;
    203  nsCOMPtr<nsIAsyncOutputStream> mOutput;
    204  RefPtr<Promise> mPromise;  // Resolved when entirely written
    205  Maybe<Buffer<uint8_t>> mData;
    206 };
    207 
    208 }  // namespace mozilla::dom
    209 
    210 #endif