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 %}