DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
/* 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"

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); }

  // 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);
  }

  class MOZ_STACK_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(NS_LITERAL_CSTRING("newhost"))
    //                            .SetFilePath(NS_LITERAL_CSTRING("new/file/path"))
    //                            .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; }

   private:
    explicit Mutator(MozURL* aUrl) : mStatus(NS_OK) {
      mozurl_clone(aUrl, getter_AddRefs(mURL));
    }
    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.
  nsrefcnt AddRef() { return mozurl_addref(this); }
  nsrefcnt Release() { return 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__