tor-browser

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

nsIURIMutator.idl (21277B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "nsISupports.idl"
      7 interface nsIURI;
      8 interface nsIObjectInputStream;
      9 interface nsIURIMutator;
     10 
     11 %{C++
     12 #include "nsString.h"
     13 #include "nsCOMPtr.h"
     14 #include <utility>
     15 
     16 #undef SetPort  // XXX Windows!
     17 
     18 namespace mozilla {
     19 class Encoding;
     20 }
     21 
     22 namespace mozilla {
     23 namespace ipc {
     24 class URIParams;
     25 } // namespace ipc
     26 } // namespace mozilla
     27 
     28 template <class T>
     29 class BaseURIMutator
     30 {
     31 // This is the base class that can be extended by implementors of nsIURIMutator
     32 // in order to avoid code duplication
     33 // Class type T should be the type of the class that implements nsIURI
     34 protected:
     35  virtual T* Create()
     36  {
     37    return new T();
     38  }
     39 
     40  [[nodiscard]] nsresult InitFromURI(T* aURI)
     41  {
     42    nsCOMPtr<nsIURI> clone;
     43    nsresult rv = aURI->Clone(getter_AddRefs(clone));
     44    if (NS_FAILED(rv)) {
     45      return rv;
     46    }
     47    mURI = static_cast<T*>(clone.get());
     48    return NS_OK;
     49  }
     50 
     51  [[nodiscard]] nsresult InitFromInputStream(nsIObjectInputStream* aStream)
     52  {
     53    RefPtr<T> uri = Create();
     54    nsresult rv = uri->ReadPrivate(aStream);
     55    if (NS_FAILED(rv)) {
     56      return rv;
     57    }
     58    mURI = std::move(uri);
     59    return NS_OK;
     60  }
     61 
     62  [[nodiscard]] nsresult InitFromIPCParams(const mozilla::ipc::URIParams& aParams)
     63  {
     64    RefPtr<T> uri = Create();
     65    bool ret = uri->Deserialize(aParams);
     66    if (!ret) {
     67      return NS_ERROR_FAILURE;
     68    }
     69    mURI = std::move(uri);
     70    return NS_OK;
     71  }
     72 
     73  [[nodiscard]] nsresult InitFromSpec(const nsACString& aSpec)
     74  {
     75    nsresult rv = NS_OK;
     76    RefPtr<T> uri;
     77    if (mURI) {
     78      // This only works because all other Init methods create a new object
     79      mURI.swap(uri);
     80    } else {
     81      uri = Create();
     82    }
     83 
     84    rv = uri->SetSpecInternal(aSpec);
     85    if (NS_FAILED(rv)) {
     86      return rv;
     87    }
     88    mURI = std::move(uri);
     89    return NS_OK;
     90  }
     91 
     92  RefPtr<T> mURI;
     93 };
     94 
     95 // Since most implementations of nsIURIMutator would extend BaseURIMutator,
     96 // some methods would have the same implementation. We provide a useful macro
     97 // to avoid code duplication.
     98 #define NS_DEFINE_NSIMUTATOR_COMMON                                           \
     99  [[nodiscard]] NS_IMETHOD                                                    \
    100  Deserialize(const mozilla::ipc::URIParams& aParams) override                \
    101  {                                                                           \
    102    return InitFromIPCParams(aParams);                                        \
    103  }                                                                           \
    104                                                                              \
    105  [[nodiscard]] NS_IMETHOD                                                    \
    106  Finalize(nsIURI** aURI) override                                            \
    107  {                                                                           \
    108    mURI.forget(aURI); return NS_OK;                                          \
    109  }                                                                           \
    110                                                                              \
    111  [[nodiscard]] NS_IMETHOD                                                    \
    112  SetSpec(const nsACString& aSpec, nsIURIMutator** aMutator) override         \
    113  {                                                                           \
    114    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    115    return InitFromSpec(aSpec);                                               \
    116  }                                                                           \
    117 
    118 // Implements AddRef, Release and QueryInterface for the mutator
    119 #define NS_IMPL_NSIURIMUTATOR_ISUPPORTS(aClass, ...)                          \
    120  NS_IMPL_ADDREF(aClass)                                                      \
    121  NS_IMPL_RELEASE(aClass)                                                     \
    122  NS_IMPL_NSIURIMUTATOR_QUERY_INTERFACE(aClass, __VA_ARGS__)                  \
    123 
    124 // The list of interfaces is queried and an AddRef-ed pointer is returned if
    125 // there is a match. Otherwise, we call QueryInterface on mURI and return.
    126 // The reason for this specialized QueryInterface implementation is that we
    127 // we want to be able to instantiate the mutator for a given CID of a
    128 // nsIURI implementation, call nsISerializable.Read() on the mutator to
    129 // deserialize the URI then QueryInterface the mutator to an nsIURI interface.
    130 // See bug 1442239.
    131 // If you QueryInterface a mutator to an interface of the URI
    132 // implementation this is similar to calling Finalize.
    133 #define NS_IMPL_NSIURIMUTATOR_QUERY_INTERFACE(aClass, ...)                    \
    134  static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0,                               \
    135                "Need more arguments");                                       \
    136  NS_INTERFACE_MAP_BEGIN(aClass)                                              \
    137    nsCOMPtr<nsIURI> uri;                                                     \
    138    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURIMutator)              \
    139    MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__))                   \
    140    if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {                              \
    141      foundInterface = nullptr;                                               \
    142    } else                                                                    \
    143    if (mURI &&                                                               \
    144        NS_SUCCEEDED(mURI->QueryInterface(aIID, getter_AddRefs(uri)))) {      \
    145        mURI = nullptr;                                                       \
    146        foundInterface = uri.get();                                           \
    147    } else                                                                    \
    148  NS_INTERFACE_MAP_END                                                        \
    149 
    150 %}
    151 
    152 [ptr] native Encoding(const mozilla::Encoding);
    153 [ref] native const_URIParams_ref(const mozilla::ipc::URIParams);
    154 
    155 [scriptable, builtinclass, uuid(1fc53257-898b-4c5e-b69c-05bc84b4cd8f)]
    156 interface nsIURISetSpec : nsISupports
    157 {
    158  /**
    159   * This setter is different from all other setters because it may be used to
    160   * initialize the object. We define it separately allowing mutator implementors
    161   * to define it separately, while the rest of the setters may be simply
    162   * forwarded to the mutable URI.
    163   */
    164  [must_use] nsIURIMutator setSpec(in AUTF8String aSpec);
    165 };
    166 
    167 /**
    168 * These methods allow the mutator to change various parts of the URI.
    169 * They return the same nsIURIMutator so that we may chain setter operations:
    170 * Example:
    171 * let newURI = uri.mutate()
    172 *                 .setSpec("http://example.com")
    173 *                 .setQuery("hello")
    174 *                 .finalize();
    175 */
    176 [scriptable, builtinclass, uuid(5403a6ec-99d7-405e-8b45-9f805bbdfcef)]
    177 interface nsIURISetters : nsIURISetSpec
    178 {
    179  /**
    180   * Setting the scheme outside of a protocol handler implementation is highly
    181   * discouraged since that will generally lead to incorrect results.
    182   */
    183  [must_use] nsIURIMutator setScheme(in AUTF8String aScheme);
    184  [must_use] nsIURIMutator setUserPass(in AUTF8String aUserPass);
    185  [must_use] nsIURIMutator setUsername(in AUTF8String aUsername);
    186  [must_use] nsIURIMutator setPassword(in AUTF8String aPassword);
    187 
    188  /**
    189   * If you setHostPort to a value that only has a host part, the port
    190   * will not be reset. To reset the port set it to -1 beforehand.
    191   * If setting the host succeeds, this method will return NS_OK, even if
    192   * setting the port fails (error in parsing the port, or value out of range)
    193   */
    194  [must_use] nsIURIMutator setHostPort(in AUTF8String aHostPort);
    195  [must_use] nsIURIMutator setHost(in AUTF8String aHost);
    196  [must_use] nsIURIMutator setPort(in long aPort);
    197  [must_use] nsIURIMutator setPathQueryRef(in AUTF8String aPathQueryRef);
    198  [must_use] nsIURIMutator setRef(in AUTF8String aRef);
    199  [must_use] nsIURIMutator setFilePath(in AUTF8String aFilePath);
    200  [must_use] nsIURIMutator setQuery(in AUTF8String aQuery);
    201  [must_use, noscript] nsIURIMutator setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
    202 };
    203 
    204 %{C++
    205 
    206 // Using this macro instead of NS_FORWARD_SAFE_NSIURISETTERS makes chaining
    207 // setter operations possible.
    208 #define NS_FORWARD_SAFE_NSIURISETTERS_RET(_to)                                \
    209  [[nodiscard]] NS_IMETHOD                                                    \
    210  SetScheme(const nsACString& aScheme, nsIURIMutator** aMutator) override     \
    211  {                                                                           \
    212    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    213    return !_to ? NS_ERROR_NULL_POINTER : _to->SetScheme(aScheme);            \
    214  }                                                                           \
    215  [[nodiscard]] NS_IMETHOD                                                    \
    216  SetUserPass(const nsACString& aUserPass, nsIURIMutator** aMutator) override \
    217  {                                                                           \
    218    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    219    return !_to ? NS_ERROR_NULL_POINTER : _to->SetUserPass(aUserPass);        \
    220  }                                                                           \
    221  [[nodiscard]] NS_IMETHOD                                                    \
    222  SetUsername(const nsACString& aUsername, nsIURIMutator** aMutator) override \
    223  {                                                                           \
    224    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    225    return !_to ? NS_ERROR_NULL_POINTER : _to->SetUsername(aUsername);        \
    226  }                                                                           \
    227  [[nodiscard]] NS_IMETHOD                                                    \
    228  SetPassword(const nsACString& aPassword, nsIURIMutator** aMutator) override \
    229  {                                                                           \
    230    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    231    return !_to ? NS_ERROR_NULL_POINTER : _to->SetPassword(aPassword);        \
    232  }                                                                           \
    233  [[nodiscard]] NS_IMETHOD                                                    \
    234  SetHostPort(const nsACString& aHostPort, nsIURIMutator** aMutator) override \
    235  {                                                                           \
    236    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    237    return !_to ? NS_ERROR_NULL_POINTER : _to->SetHostPort(aHostPort);        \
    238  }                                                                           \
    239  [[nodiscard]] NS_IMETHOD                                                    \
    240  SetHost(const nsACString& aHost, nsIURIMutator** aMutator) override         \
    241  {                                                                           \
    242    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    243    return !_to ? NS_ERROR_NULL_POINTER : _to->SetHost(aHost);                \
    244  }                                                                           \
    245  [[nodiscard]] NS_IMETHOD                                                    \
    246  SetPort(int32_t aPort, nsIURIMutator** aMutator) override                   \
    247  {                                                                           \
    248    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    249    return !_to ? NS_ERROR_NULL_POINTER : _to->SetPort(aPort);                \
    250  }                                                                           \
    251  [[nodiscard]] NS_IMETHOD                                                    \
    252  SetPathQueryRef(const nsACString& aPathQueryRef, nsIURIMutator** aMutator) override \
    253  {                                                                           \
    254    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    255    return !_to ? NS_ERROR_NULL_POINTER : _to->SetPathQueryRef(aPathQueryRef); \
    256  }                                                                           \
    257  [[nodiscard]] NS_IMETHOD                                                    \
    258  SetRef(const nsACString& aRef, nsIURIMutator** aMutator) override           \
    259  {                                                                           \
    260    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    261    return !_to ? NS_ERROR_NULL_POINTER : _to->SetRef(aRef);                  \
    262  }                                                                           \
    263  [[nodiscard]] NS_IMETHOD                                                    \
    264  SetFilePath(const nsACString& aFilePath, nsIURIMutator** aMutator) override \
    265  {                                                                           \
    266    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    267    return !_to ? NS_ERROR_NULL_POINTER : _to->SetFilePath(aFilePath);        \
    268  }                                                                           \
    269  [[nodiscard]] NS_IMETHOD                                                    \
    270  SetQuery(const nsACString& aQuery, nsIURIMutator** aMutator) override       \
    271  {                                                                           \
    272    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    273    return !_to ? NS_ERROR_NULL_POINTER : _to->SetQuery(aQuery);              \
    274  }                                                                           \
    275  [[nodiscard]] NS_IMETHOD                                                    \
    276  SetQueryWithEncoding(const nsACString& query, const mozilla::Encoding *encoding, nsIURIMutator** aMutator) override \
    277  {                                                                           \
    278    if (aMutator) NS_ADDREF(*aMutator = this);                                \
    279    return !_to ? NS_ERROR_NULL_POINTER : _to->SetQueryWithEncoding(query, encoding); \
    280  }                                                                           \
    281 
    282 %}
    283 
    284 [scriptable, builtinclass, uuid(4d1f3103-1c44-4dcd-b717-5d22a697a7d9)]
    285 interface nsIURIMutator : nsIURISetters
    286 {
    287  /**
    288   * Initalizes the URI by reading IPC URIParams.
    289   * See nsIURI.
    290   */
    291  [noscript, notxpcom, must_use]
    292  nsresult deserialize(in const_URIParams_ref aParams);
    293 
    294  /**
    295   * Finishes changing or constructing the URI and returns an immutable URI.
    296   */
    297  [must_use]
    298  nsIURI finalize();
    299 };
    300 
    301 %{C++
    302 
    303 // This templated struct is used to extract the class type of the method
    304 template <typename Method>
    305 struct nsMethodTypeTraits;
    306 
    307 template <class C, typename R, typename... As>
    308 struct nsMethodTypeTraits<R(C::*)(As...)>
    309 {
    310  typedef C class_type;
    311 };
    312 
    313 #ifdef NS_HAVE_STDCALL
    314 template <class C, typename R, typename... As>
    315 struct nsMethodTypeTraits<R(__stdcall C::*)(As...)>
    316 {
    317  typedef C class_type;
    318 };
    319 #endif
    320 
    321 
    322 // This class provides a useful helper that allows chaining of setter operations
    323 class MOZ_STACK_CLASS NS_MutateURI
    324 {
    325 public:
    326  explicit NS_MutateURI(nsIURI* aURI);
    327  explicit NS_MutateURI(const char * aContractID);
    328 
    329  explicit NS_MutateURI(nsIURIMutator* m)
    330  {
    331    mStatus = m ? NS_OK : NS_ERROR_NULL_POINTER;
    332    mMutator = m;
    333    NS_ENSURE_SUCCESS_VOID(mStatus);
    334  }
    335 
    336  NS_MutateURI& SetSpec(const nsACString& aSpec)
    337  {
    338    if (NS_FAILED(mStatus)) {
    339      return *this;
    340    }
    341    mStatus = mMutator->SetSpec(aSpec, nullptr);
    342    return *this;
    343  }
    344  NS_MutateURI& SetScheme(const nsACString& aScheme)
    345  {
    346    if (NS_FAILED(mStatus)) {
    347      return *this;
    348    }
    349    mStatus = mMutator->SetScheme(aScheme, nullptr);
    350    NS_ENSURE_SUCCESS(mStatus, *this);
    351    return *this;
    352  }
    353  NS_MutateURI& SetUserPass(const nsACString& aUserPass)
    354  {
    355    if (NS_FAILED(mStatus)) {
    356      return *this;
    357    }
    358    mStatus = mMutator->SetUserPass(aUserPass, nullptr);
    359    return *this;
    360  }
    361  NS_MutateURI& SetUsername(const nsACString& aUsername)
    362  {
    363    if (NS_FAILED(mStatus)) {
    364      return *this;
    365    }
    366    mStatus = mMutator->SetUsername(aUsername, nullptr);
    367    NS_ENSURE_SUCCESS(mStatus, *this);
    368    return *this;
    369  }
    370  NS_MutateURI& SetPassword(const nsACString& aPassword)
    371  {
    372    if (NS_FAILED(mStatus)) {
    373      return *this;
    374    }
    375    mStatus = mMutator->SetPassword(aPassword, nullptr);
    376    NS_ENSURE_SUCCESS(mStatus, *this);
    377    return *this;
    378  }
    379  NS_MutateURI& SetHostPort(const nsACString& aHostPort)
    380  {
    381    if (NS_FAILED(mStatus)) {
    382      return *this;
    383    }
    384    mStatus = mMutator->SetHostPort(aHostPort, nullptr);
    385    NS_ENSURE_SUCCESS(mStatus, *this);
    386    return *this;
    387  }
    388  NS_MutateURI& SetHost(const nsACString& aHost)
    389  {
    390    if (NS_FAILED(mStatus)) {
    391      return *this;
    392    }
    393    mStatus = mMutator->SetHost(aHost, nullptr);
    394    NS_ENSURE_SUCCESS(mStatus, *this);
    395    return *this;
    396  }
    397  NS_MutateURI& SetPort(int32_t aPort)
    398  {
    399    if (NS_FAILED(mStatus)) {
    400      return *this;
    401    }
    402    mStatus = mMutator->SetPort(aPort, nullptr);
    403    NS_ENSURE_SUCCESS(mStatus, *this);
    404    return *this;
    405  }
    406  NS_MutateURI& SetPathQueryRef(const nsACString& aPathQueryRef)
    407  {
    408    if (NS_FAILED(mStatus)) {
    409      return *this;
    410    }
    411    mStatus = mMutator->SetPathQueryRef(aPathQueryRef, nullptr);
    412    NS_ENSURE_SUCCESS(mStatus, *this);
    413    return *this;
    414  }
    415  NS_MutateURI& SetRef(const nsACString& aRef)
    416  {
    417    if (NS_FAILED(mStatus)) {
    418      return *this;
    419    }
    420    mStatus = mMutator->SetRef(aRef, nullptr);
    421    NS_ENSURE_SUCCESS(mStatus, *this);
    422    return *this;
    423  }
    424  NS_MutateURI& SetFilePath(const nsACString& aFilePath)
    425  {
    426    if (NS_FAILED(mStatus)) {
    427      return *this;
    428    }
    429    mStatus = mMutator->SetFilePath(aFilePath, nullptr);
    430    NS_ENSURE_SUCCESS(mStatus, *this);
    431    return *this;
    432  }
    433  NS_MutateURI& SetQuery(const nsACString& aQuery)
    434  {
    435    if (NS_FAILED(mStatus)) {
    436      return *this;
    437    }
    438    mStatus = mMutator->SetQuery(aQuery, nullptr);
    439    NS_ENSURE_SUCCESS(mStatus, *this);
    440    return *this;
    441  }
    442  NS_MutateURI& SetQueryWithEncoding(const nsACString& query, const mozilla::Encoding *encoding)
    443  {
    444    if (NS_FAILED(mStatus)) {
    445      return *this;
    446    }
    447    mStatus = mMutator->SetQueryWithEncoding(query, encoding, nullptr);
    448    NS_ENSURE_SUCCESS(mStatus, *this);
    449    return *this;
    450  }
    451 
    452  /**
    453   * This method allows consumers to call the methods declared in other
    454   * interfaces implemented by the mutator object.
    455   *
    456   * Example:
    457   * nsCOMPtr<nsIURI> uri;
    458   * nsresult rv = NS_MutateURI(new URIClass::Mutator())
    459   *                 .SetSpec(aSpec)
    460   *                 .Apply(&SomeInterface::Method, arg1, arg2)
    461   *                 .Finalize(uri);
    462   *
    463   * If mMutator does not implement SomeInterface, do_QueryInterface will fail
    464   * and the method will not be called.
    465   * If aMethod does not exist, or if there is a mismatch between argument
    466   * types, or the number of arguments, then there will be a compile error.
    467   */
    468  template <typename Method, typename... Args>
    469  NS_MutateURI& Apply(Method aMethod, Args&&... aArgs)
    470  {
    471    typedef typename nsMethodTypeTraits<Method>::class_type Interface;
    472    NS_ENSURE_SUCCESS(mStatus, *this);
    473    nsCOMPtr<Interface> target = do_QueryInterface(mMutator, &mStatus);
    474    MOZ_ASSERT(NS_SUCCEEDED(mStatus), "URL object must implement interface");
    475    NS_ENSURE_SUCCESS(mStatus, *this);
    476    mStatus = (target->*aMethod)(std::forward<Args>(aArgs)...);
    477    return *this;
    478  }
    479 
    480  template <class C>
    481  [[nodiscard]] nsresult Finalize(nsCOMPtr<C>& aURI)
    482  {
    483    NS_ENSURE_SUCCESS(mStatus, mStatus);
    484 
    485    nsCOMPtr<nsIURI> uri;
    486    mStatus = mMutator->Finalize(getter_AddRefs(uri));
    487    NS_ENSURE_SUCCESS(mStatus, mStatus);
    488 
    489    aURI = do_QueryInterface(uri, &mStatus);
    490    NS_ENSURE_SUCCESS(mStatus, mStatus);
    491 
    492    mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
    493    return NS_OK;
    494  }
    495 
    496  // Overload for nsIURI to avoid query interface.
    497  [[nodiscard]] nsresult Finalize(nsCOMPtr<nsIURI>& aURI)
    498  {
    499    if (NS_FAILED(mStatus)) return mStatus;
    500    mStatus = mMutator->Finalize(getter_AddRefs(aURI));
    501    NS_ENSURE_SUCCESS(mStatus, mStatus);
    502 
    503    mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
    504    return NS_OK;
    505  }
    506 
    507  template <class C>
    508  [[nodiscard]] nsresult Finalize(C** aURI)
    509  {
    510    NS_ENSURE_SUCCESS(mStatus, mStatus);
    511 
    512    nsCOMPtr<nsIURI> uri;
    513    mStatus = mMutator->Finalize(getter_AddRefs(uri));
    514    NS_ENSURE_SUCCESS(mStatus, mStatus);
    515 
    516    nsCOMPtr<C> result = do_QueryInterface(uri, &mStatus);
    517    NS_ENSURE_SUCCESS(mStatus, mStatus);
    518 
    519    result.forget(aURI);
    520    mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
    521    return NS_OK;
    522  }
    523 
    524  [[nodiscard]] nsresult Finalize(nsIURI** aURI)
    525  {
    526    if (NS_FAILED(mStatus)) return mStatus;
    527    mStatus = mMutator->Finalize(aURI);
    528    NS_ENSURE_SUCCESS(mStatus, mStatus);
    529 
    530    mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
    531    return NS_OK;
    532  }
    533 
    534  nsresult GetStatus() { return mStatus; }
    535 private:
    536  nsresult mStatus;
    537  nsCOMPtr<nsIURIMutator> mMutator;
    538 };
    539 
    540 %}