tor-browser

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

URLPattern.cpp (11979B)


      1 /* -*- Mode: IDL; 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 file,
      4 * You can obtain one at http://mozilla.org/MPL/2.0/.
      5 */
      6 #include "URLPattern.h"
      7 
      8 #include "mozilla/ErrorResult.h"
      9 #include "mozilla/net/MozURL.h"
     10 
     11 namespace mozilla::dom {
     12 
     13 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLPattern, mParent)
     14 
     15 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLPattern)
     16 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLPattern)
     17 
     18 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLPattern)
     19  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     20  NS_INTERFACE_MAP_ENTRY(nsISupports)
     21 NS_INTERFACE_MAP_END
     22 
     23 JSObject* URLPattern::WrapObject(JSContext* aCx,
     24                                 JS::Handle<JSObject*> aGivenProto) {
     25  return URLPattern_Binding::Wrap(aCx, this, aGivenProto);
     26 }
     27 
     28 void GlueToBindingInit(const UrlpInit& aGInit, URLPatternInit& aBInit) {
     29  if (aGInit.protocol.valid) {
     30    aBInit.mProtocol.Construct(aGInit.protocol.string);
     31  }
     32  if (aGInit.username.valid) {
     33    aBInit.mUsername.Construct(aGInit.username.string);
     34  }
     35  if (aGInit.password.valid) {
     36    aBInit.mPassword.Construct(aGInit.password.string);
     37  }
     38  if (aGInit.hostname.valid) {
     39    aBInit.mHostname.Construct(aGInit.hostname.string);
     40  }
     41  if (aGInit.port.valid) {
     42    aBInit.mPort.Construct(aGInit.port.string);
     43  }
     44  if (aGInit.pathname.valid) {
     45    aBInit.mPathname.Construct(aGInit.pathname.string);
     46  }
     47  if (aGInit.search.valid) {
     48    aBInit.mSearch.Construct(aGInit.search.string);
     49  }
     50  if (aGInit.hash.valid) {
     51    aBInit.mHash.Construct(aGInit.hash.string);
     52  }
     53  if (aGInit.base_url.valid) {
     54    aBInit.mBaseURL.Construct(aGInit.base_url.string);
     55  }
     56 }
     57 
     58 void BindingToGlueInit(const URLPatternInit& aBInit, UrlpInit& aGInit) {
     59  if (aBInit.mProtocol.WasPassed()) {
     60    aGInit.protocol = net::CreateMaybeString(aBInit.mProtocol.Value(), true);
     61  }
     62  if (aBInit.mUsername.WasPassed()) {
     63    aGInit.username = net::CreateMaybeString(aBInit.mUsername.Value(), true);
     64  }
     65  if (aBInit.mPassword.WasPassed()) {
     66    aGInit.password = net::CreateMaybeString(aBInit.mPassword.Value(), true);
     67  }
     68  if (aBInit.mHostname.WasPassed()) {
     69    aGInit.hostname = net::CreateMaybeString(aBInit.mHostname.Value(), true);
     70  }
     71  if (aBInit.mPort.WasPassed()) {
     72    aGInit.port = net::CreateMaybeString(aBInit.mPort.Value(), true);
     73  }
     74  if (aBInit.mPathname.WasPassed()) {
     75    aGInit.pathname = net::CreateMaybeString(aBInit.mPathname.Value(), true);
     76  }
     77  if (aBInit.mSearch.WasPassed()) {
     78    aGInit.search = net::CreateMaybeString(aBInit.mSearch.Value(), true);
     79  }
     80  if (aBInit.mHash.WasPassed()) {
     81    aGInit.hash = net::CreateMaybeString(aBInit.mHash.Value(), true);
     82  }
     83  if (aBInit.mBaseURL.WasPassed()) {
     84    aGInit.base_url = net::CreateMaybeString(aBInit.mBaseURL.Value(), true);
     85  }
     86 }
     87 
     88 // static
     89 already_AddRefed<URLPattern> URLPattern::Constructor(
     90    const GlobalObject& aGlobal, const UTF8StringOrURLPatternInit& aInput,
     91    const URLPatternOptions& aOptions, ErrorResult& rv) {
     92  MOZ_LOG(gUrlPatternLog, LogLevel::Debug,
     93          ("UrlPattern::Constructor() (without base)"));
     94  UrlpPattern pattern{};
     95  UrlpOptions options{};
     96  options.ignore_case = aOptions.mIgnoreCase;
     97  if (!aInput.IsURLPatternInit()) {
     98    bool res = urlp_parse_pattern_from_string(&aInput.GetAsUTF8String(),
     99                                              nullptr, options, &pattern);
    100    if (!res) {
    101      rv.ThrowTypeError("Failed to create URLPattern (from string)");
    102      return nullptr;
    103    }
    104  } else {
    105    UrlpInit init{};
    106    URLPatternInit b_init;
    107    b_init = aInput.GetAsURLPatternInit();
    108    BindingToGlueInit(b_init, init);
    109    if (init.base_url.valid && init.base_url.string.Equals("")) {
    110      rv.ThrowTypeError("Should not provide empty base url with init");
    111      return nullptr;
    112    }
    113    bool res = urlp_parse_pattern_from_init(&init, options, &pattern);
    114    if (!res) {
    115      rv.ThrowTypeError("Failed to create URLPattern (from init)");
    116      return nullptr;
    117    }
    118  }
    119 
    120  return MakeAndAddRef<URLPattern>(aGlobal.GetAsSupports(), pattern,
    121                                   aOptions.mIgnoreCase);
    122 }
    123 
    124 // static
    125 already_AddRefed<URLPattern> URLPattern::Constructor(
    126    const GlobalObject& aGlobal, const UTF8StringOrURLPatternInit& aInput,
    127    const nsACString& aBase, const URLPatternOptions& aOptions,
    128    ErrorResult& rv) {
    129  MOZ_LOG(gUrlPatternLog, LogLevel::Debug,
    130          ("UrlPattern::Constructor() (w base)"));
    131  UrlpPattern pattern{};
    132  UrlpOptions options{};
    133  options.ignore_case = aOptions.mIgnoreCase;
    134  if (!aInput.IsURLPatternInit()) {
    135    bool res = urlp_parse_pattern_from_string(&aInput.GetAsUTF8String(), &aBase,
    136                                              options, &pattern);
    137    if (!res) {
    138      rv.ThrowTypeError(
    139          "Failed to create URLPattern with base url (from string)");
    140      return nullptr;
    141    }
    142  } else {
    143    if (!aBase.IsEmpty()) {
    144      rv.ThrowTypeError("Should not provide base url with init");
    145      return nullptr;
    146    }
    147    UrlpInit init{};
    148    URLPatternInit b_init;
    149    b_init = aInput.GetAsURLPatternInit();
    150    BindingToGlueInit(b_init, init);
    151    bool res = urlp_parse_pattern_from_init(&init, options, &pattern);
    152    if (!res) {
    153      rv.ThrowTypeError(
    154          "Failed to create URLPattern with base url (from init)");
    155      return nullptr;
    156    }
    157  }
    158  return MakeAndAddRef<URLPattern>(aGlobal.GetAsSupports(), pattern,
    159                                   aOptions.mIgnoreCase);
    160 }
    161 
    162 URLPattern::~URLPattern() { urlp_pattern_free(mPattern); }
    163 
    164 void ConvertGroupsToRecord(
    165    const nsTHashMap<nsCStringHashKey, MaybeString>& aGroups,
    166    Optional<Record<nsCString, OwningUTF8StringOrUndefined>>& aRes) {
    167  Record<nsCString, OwningUTF8StringOrUndefined> record;
    168  for (auto iter = aGroups.ConstIter(); !iter.Done(); iter.Next()) {
    169    OwningUTF8StringOrUndefined value;
    170    value.SetUndefined();
    171    MaybeString s = iter.Data();
    172    if (s.valid) {
    173      value.SetAsUTF8String().Assign(s.string);
    174    }
    175    auto* entry = record.Entries().AppendElement().get();
    176    entry->mKey.Assign(iter.Key());
    177    entry->mValue = std::move(value);
    178  }
    179  aRes.Construct(std::move(record));
    180 }
    181 
    182 void GlueToBindingComponent(const net::UrlpComponentResult& aGlueCompRes,
    183                            URLPatternComponentResult& aBindingCompRes) {
    184  aBindingCompRes.mInput.Construct(aGlueCompRes.mInput);
    185  ConvertGroupsToRecord(aGlueCompRes.mGroups, aBindingCompRes.mGroups);
    186 }
    187 
    188 void ConvertInputsToSequence(
    189    const CopyableTArray<UrlpInput>& aInputs,
    190    Optional<Sequence<OwningUTF8StringOrURLPatternInit>>& aRes,
    191    ErrorResult& rv) {
    192  Sequence<OwningUTF8StringOrURLPatternInit> sequence;
    193  for (const auto& input : aInputs) {
    194    OwningUTF8StringOrURLPatternInit variant;
    195    if (input.string_or_init_type == UrlpStringOrInitType::String) {
    196      variant.SetAsUTF8String().Assign(input.str);
    197    } else {
    198      GlueToBindingInit(input.init, variant.SetAsURLPatternInit());
    199    }
    200 
    201    if (!sequence.AppendElement(std::move(variant), fallible)) {
    202      aRes.Reset();
    203      rv.ThrowOperationError("Failed to append inputs list to sequence");
    204      return;
    205    }
    206  }
    207  aRes.Construct(std::move(sequence));
    208 }
    209 
    210 void GlueToBindingResult(const net::UrlpResult& aGlueRes,
    211                         URLPatternResult& aBindingRes, ErrorResult& rv) {
    212  if (aGlueRes.mProtocol.isSome()) {
    213    URLPatternComponentResult tmp;
    214    GlueToBindingComponent(aGlueRes.mProtocol.value(), tmp);
    215    aBindingRes.mProtocol.Construct(std::move(tmp));
    216  }
    217  if (aGlueRes.mUsername.isSome()) {
    218    URLPatternComponentResult tmp;
    219    GlueToBindingComponent(aGlueRes.mUsername.value(), tmp);
    220    aBindingRes.mUsername.Construct(std::move(tmp));
    221  }
    222  if (aGlueRes.mPassword.isSome()) {
    223    URLPatternComponentResult tmp;
    224    GlueToBindingComponent(aGlueRes.mPassword.value(), tmp);
    225    aBindingRes.mPassword.Construct(std::move(tmp));
    226  }
    227  if (aGlueRes.mHostname.isSome()) {
    228    URLPatternComponentResult tmp;
    229    GlueToBindingComponent(aGlueRes.mHostname.value(), tmp);
    230    aBindingRes.mHostname.Construct(std::move(tmp));
    231  }
    232  if (aGlueRes.mPort.isSome()) {
    233    URLPatternComponentResult tmp;
    234    GlueToBindingComponent(aGlueRes.mPort.value(), tmp);
    235    aBindingRes.mPort.Construct(std::move(tmp));
    236  }
    237  if (aGlueRes.mPathname.isSome()) {
    238    URLPatternComponentResult tmp;
    239    GlueToBindingComponent(aGlueRes.mPathname.value(), tmp);
    240    aBindingRes.mPathname.Construct(std::move(tmp));
    241  }
    242  if (aGlueRes.mSearch.isSome()) {
    243    URLPatternComponentResult tmp;
    244    GlueToBindingComponent(aGlueRes.mSearch.value(), tmp);
    245    aBindingRes.mSearch.Construct(std::move(tmp));
    246  }
    247  if (aGlueRes.mHash.isSome()) {
    248    URLPatternComponentResult tmp;
    249    GlueToBindingComponent(aGlueRes.mHash.value(), tmp);
    250    aBindingRes.mHash.Construct(std::move(tmp));
    251  }
    252  ConvertInputsToSequence(aGlueRes.mInputs, aBindingRes.mInputs, rv);
    253 }
    254 
    255 bool URLPattern::Test(const UTF8StringOrURLPatternInit& aInput,
    256                      const Optional<nsACString>& aBaseUrl, ErrorResult& rv) {
    257  MOZ_LOG(gUrlPatternLog, LogLevel::Debug, ("UrlPattern::Test()"));
    258  UrlpInput input;
    259  Maybe<nsAutoCString> execBaseUrl;
    260  if (aInput.IsURLPatternInit()) {
    261    UrlpInit initGlue{};
    262    BindingToGlueInit(aInput.GetAsURLPatternInit(), initGlue);
    263    input = net::CreateUrlpInput(initGlue);
    264    if (aBaseUrl.WasPassed()) {
    265      rv.ThrowTypeError(
    266          "Do not pass baseUrl separately with init, use init's baseURL "
    267          "property");
    268      return false;
    269    }
    270  } else {
    271    input = net::CreateUrlpInput(aInput.GetAsUTF8String());
    272    if (aBaseUrl.WasPassed()) {
    273      execBaseUrl.emplace(aBaseUrl.Value());
    274    }
    275  }
    276  return net::UrlpPatternTest(mPattern, input, execBaseUrl, mIgnoreCase);
    277 }
    278 
    279 void URLPattern::Exec(const UTF8StringOrURLPatternInit& aInput,
    280                      const Optional<nsACString>& aBaseUrl,
    281                      Nullable<URLPatternResult>& aResult, ErrorResult& rv) {
    282  MOZ_LOG(gUrlPatternLog, LogLevel::Debug, ("UrlPattern::Exec()"));
    283  UrlpInput input;
    284  Maybe<nsAutoCString> execBaseUrl;
    285  if (aInput.IsURLPatternInit()) {
    286    UrlpInit initGlue{};
    287    BindingToGlueInit(aInput.GetAsURLPatternInit(), initGlue);
    288    input = net::CreateUrlpInput(initGlue);
    289    if (aBaseUrl.WasPassed()) {
    290      rv.ThrowTypeError(
    291          "Do not pass baseUrl separately with init, use init's baseURL "
    292          "property");
    293      return;
    294    }
    295  } else {
    296    input = net::CreateUrlpInput(aInput.GetAsUTF8String());
    297    if (aBaseUrl.WasPassed()) {
    298      execBaseUrl.emplace(aBaseUrl.Value());
    299    }
    300  }
    301 
    302  Maybe<net::UrlpResult> patternResult =
    303      net::UrlpPatternExec(mPattern, input, execBaseUrl, mIgnoreCase);
    304  if (patternResult.isSome()) {
    305    URLPatternResult res;
    306    GlueToBindingResult(patternResult.value(), res, rv);
    307    if (rv.Failed()) {
    308      aResult.SetNull();
    309      return;
    310    }
    311    aResult.SetValue(std::move(res));
    312    return;
    313  }
    314  aResult.SetNull();
    315 }
    316 
    317 void URLPattern::GetProtocol(nsACString& aProtocol) const {
    318  aProtocol.Assign(net::UrlpGetProtocol(mPattern));
    319 }
    320 
    321 void URLPattern::GetUsername(nsACString& aUsername) const {
    322  aUsername.Assign(net::UrlpGetUsername(mPattern));
    323 }
    324 
    325 void URLPattern::GetPassword(nsACString& aPassword) const {
    326  aPassword.Assign(net::UrlpGetPassword(mPattern));
    327 }
    328 
    329 void URLPattern::GetHostname(nsACString& aHostname) const {
    330  aHostname.Assign(net::UrlpGetHostname(mPattern));
    331 }
    332 
    333 void URLPattern::GetPort(nsACString& aPort) const {
    334  aPort.Assign(net::UrlpGetPort(mPattern));
    335 }
    336 
    337 void URLPattern::GetPathname(nsACString& aPathname) const {
    338  aPathname.Assign(net::UrlpGetPathname(mPattern));
    339 }
    340 
    341 void URLPattern::GetSearch(nsACString& aSearch) const {
    342  aSearch.Assign(net::UrlpGetSearch(mPattern));
    343 }
    344 
    345 void URLPattern::GetHash(nsACString& aHash) const {
    346  aHash.Assign(net::UrlpGetHash(mPattern));
    347 }
    348 
    349 bool URLPattern::HasRegExpGroups() const {
    350  return urlp_get_has_regexp_groups(mPattern);
    351 }
    352 
    353 }  // namespace mozilla::dom