summaryrefslogtreecommitdiffstats
path: root/netwerk/base/mozurl/MozURL.h
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/base/mozurl/MozURL.h')
-rw-r--r--netwerk/base/mozurl/MozURL.h231
1 files changed, 231 insertions, 0 deletions
diff --git a/netwerk/base/mozurl/MozURL.h b/netwerk/base/mozurl/MozURL.h
new file mode 100644
index 0000000000..ddd91c1b0c
--- /dev/null
+++ b/netwerk/base/mozurl/MozURL.h
@@ -0,0 +1,231 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozURL_h__
+#define mozURL_h__
+
+#include "mozilla/net/MozURL_ffi.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Result.h"
+
+namespace mozilla {
+namespace net {
+
+// This class provides a thread-safe, immutable URL parser.
+// As long as there is RefPtr to the object, you may use it on any thread.
+// The constructor is private. One can instantiate the object by
+// calling the Init() method as such:
+//
+// RefPtr<MozURL> url;
+// nsAutoCString href("http://example.com/path?query#ref");
+// nsresult rv = MozURL::Init(getter_AddRefs(url), href);
+// if (NS_SUCCEEDED(rv)) { /* use url */ }
+//
+// When changing the URL is needed, you need to call the Mutate() method.
+// This gives you a Mutator object, on which you can perform setter operations.
+// Calling Finalize() on the Mutator will result in a new MozURL and a status
+// code. If any of the setter operations failed, it will be reflected in the
+// status code, and a null MozURL.
+//
+// Note: In the case of a domain name containing non-ascii characters,
+// GetSpec and GetHostname will return the IDNA(punycode) version of the host.
+// Also note that for now, MozURL only supports the UTF-8 charset.
+//
+// Implementor Note: This type is only a holder for methods in C++, and does not
+// reflect the actual layout of the type.
+class MozURL final {
+ public:
+ static nsresult Init(MozURL** aURL, const nsACString& aSpec,
+ const MozURL* aBaseURL = nullptr) {
+ return mozurl_new(aURL, &aSpec, aBaseURL);
+ }
+
+ nsDependentCSubstring Spec() const { return mozurl_spec(this); }
+ nsDependentCSubstring Scheme() const { return mozurl_scheme(this); }
+ nsDependentCSubstring Username() const { return mozurl_username(this); }
+ nsDependentCSubstring Password() const { return mozurl_password(this); }
+ // Will return the hostname of URL. If the hostname is an IPv6 address,
+ // it will be enclosed in square brackets, such as `[::1]`
+ nsDependentCSubstring Host() const { return mozurl_host(this); }
+ // Will return the port number, if specified, or -1
+ int32_t Port() const { return mozurl_port(this); }
+ int32_t RealPort() const { return mozurl_real_port(this); }
+ // If the URL's port number is equal to the default port, will only return the
+ // hostname, otherwise it will return a string of the form `{host}:{port}`
+ // See: https://url.spec.whatwg.org/#default-port
+ nsDependentCSubstring HostPort() const { return mozurl_host_port(this); }
+ nsDependentCSubstring FilePath() const { return mozurl_filepath(this); }
+ nsDependentCSubstring Path() const { return mozurl_path(this); }
+ nsDependentCSubstring Query() const { return mozurl_query(this); }
+ nsDependentCSubstring Ref() const { return mozurl_fragment(this); }
+ bool HasFragment() const { return mozurl_has_fragment(this); }
+ nsDependentCSubstring Directory() const { return mozurl_directory(this); }
+ nsDependentCSubstring PrePath() const { return mozurl_prepath(this); }
+ nsDependentCSubstring SpecNoRef() const { return mozurl_spec_no_ref(this); }
+
+ // This matches the definition of origins and base domains in nsIPrincipal for
+ // almost all URIs (some rare file:// URIs don't match and it would be hard to
+ // fix them). It definitely matches nsIPrincipal for URIs used in quota
+ // manager and there are checks in quota manager and its clients that prevent
+ // different definitions (see QuotaManager::IsPrincipalInfoValid).
+ // See also TestMozURL.cpp which enumerates a huge pile of URIs and checks
+ // that origin and base domain definitions are in sync.
+ void Origin(nsACString& aOrigin) const { mozurl_origin(this, &aOrigin); }
+ nsresult BaseDomain(nsACString& aBaseDomain) const {
+ return mozurl_base_domain(this, &aBaseDomain);
+ }
+
+ nsresult GetCommonBase(const MozURL* aOther, MozURL** aCommon) const {
+ return mozurl_common_base(this, aOther, aCommon);
+ }
+ nsresult GetRelative(const MozURL* aOther, nsACString* aRelative) const {
+ return mozurl_relative(this, aOther, aRelative);
+ }
+
+ size_t SizeOf() { return mozurl_sizeof(this); }
+
+ class Mutator {
+ public:
+ // Calling this method will result in the creation of a new MozURL that
+ // adopts the mutator's mURL.
+ // If any of the setters failed with an error code, that error code will be
+ // returned here. It will also return an error code if Finalize is called
+ // more than once on the Mutator.
+ nsresult Finalize(MozURL** aURL) {
+ nsresult rv = GetStatus();
+ if (NS_SUCCEEDED(rv)) {
+ mURL.forget(aURL);
+ } else {
+ *aURL = nullptr;
+ }
+ return rv;
+ }
+
+ // These setter methods will return a reference to `this` so that you may
+ // chain setter operations as such:
+ //
+ // RefPtr<MozURL> url2;
+ // nsresult rv = url->Mutate().SetHostname("newhost"_ns)
+ // .SetFilePath("new/file/path"_ns)
+ // .Finalize(getter_AddRefs(url2));
+ // if (NS_SUCCEEDED(rv)) { /* use url2 */ }
+ Mutator& SetScheme(const nsACString& aScheme) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_scheme(mURL, &aScheme);
+ }
+ return *this;
+ }
+ Mutator& SetUsername(const nsACString& aUser) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_username(mURL, &aUser);
+ }
+ return *this;
+ }
+ Mutator& SetPassword(const nsACString& aPassword) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_password(mURL, &aPassword);
+ }
+ return *this;
+ }
+ Mutator& SetHostname(const nsACString& aHost) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_hostname(mURL, &aHost);
+ }
+ return *this;
+ }
+ Mutator& SetHostPort(const nsACString& aHostPort) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_host_port(mURL, &aHostPort);
+ }
+ return *this;
+ }
+ Mutator& SetFilePath(const nsACString& aPath) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_pathname(mURL, &aPath);
+ }
+ return *this;
+ }
+ Mutator& SetQuery(const nsACString& aQuery) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_query(mURL, &aQuery);
+ }
+ return *this;
+ }
+ Mutator& SetRef(const nsACString& aRef) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_fragment(mURL, &aRef);
+ }
+ return *this;
+ }
+ Mutator& SetPort(int32_t aPort) {
+ if (NS_SUCCEEDED(GetStatus())) {
+ mStatus = mozurl_set_port_no(mURL, aPort);
+ }
+ return *this;
+ }
+
+ // This method returns the status code of the setter operations.
+ // If any of the setters failed, it will return the code of the first error
+ // that occured. If none of the setters failed, it will return NS_OK.
+ // This method is useful to avoid doing expensive operations when the result
+ // would not be used because an error occurred. For example:
+ //
+ // RefPtr<MozURL> url2;
+ // MozURL::Mutator mut = url->Mutate();
+ // mut.SetScheme("!@#$"); // this would fail
+ // if (NS_SUCCEDED(mut.GetStatus())) {
+ // nsAutoCString host(ExpensiveComputing());
+ // rv = mut.SetHostname(host).Finalize(getter_AddRefs(url2));
+ // }
+ // if (NS_SUCCEEDED(rv)) { /* use url2 */ }
+ nsresult GetStatus() { return mURL ? mStatus : NS_ERROR_NOT_AVAILABLE; }
+
+ static Result<Mutator, nsresult> FromSpec(
+ const nsACString& aSpec, const MozURL* aBaseURL = nullptr) {
+ Mutator m = Mutator(aSpec, aBaseURL);
+ if (m.mURL) {
+ MOZ_ASSERT(NS_SUCCEEDED(m.mStatus));
+ return m;
+ }
+
+ MOZ_ASSERT(NS_FAILED(m.mStatus));
+ return Err(m.mStatus);
+ }
+
+ private:
+ explicit Mutator(MozURL* aUrl) : mStatus(NS_OK) {
+ mozurl_clone(aUrl, getter_AddRefs(mURL));
+ }
+
+ // This is only used to create a mutator from a string without cloning it
+ // so we avoid a pointless copy in FromSpec. It is important that we
+ // check the value of mURL afterwards.
+ explicit Mutator(const nsACString& aSpec,
+ const MozURL* aBaseURL = nullptr) {
+ mStatus = mozurl_new(getter_AddRefs(mURL), &aSpec, aBaseURL);
+ }
+ RefPtr<MozURL> mURL;
+ nsresult mStatus;
+ friend class MozURL;
+ };
+
+ Mutator Mutate() { return Mutator(this); }
+
+ // AddRef and Release are non-virtual on this type, and always call into rust.
+ void AddRef() { mozurl_addref(this); }
+ void Release() { mozurl_release(this); }
+
+ private:
+ // Make it a compile time error for C++ code to ever create, destruct, or copy
+ // MozURL objects. All of these operations will be performed by rust.
+ MozURL(); /* never defined */
+ ~MozURL(); /* never defined */
+ MozURL(const MozURL&) = delete;
+ MozURL& operator=(const MozURL&) = delete;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozURL_h__