Skip to content

Commit

Permalink
URLPattern: Add ignoresCase option.
Browse files Browse the repository at this point in the history
Implements spec changes from:

whatwg/urlpattern#168

Bug: 1345036
Change-Id: I659784cff5420603f8805aeed9bcd5852f97b5ae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3866651
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Commit-Queue: Ben Kelly <wanderview@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1041730}
NOKEYCHECK=True
GitOrigin-RevId: de7fdfdc52b4e01e709630eae6ebd29ad5524eed
  • Loading branch information
wanderview authored and copybara-github committed Aug 31, 2022
1 parent fc3227e commit 14f1966
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 75 deletions.
2 changes: 2 additions & 0 deletions blink/renderer/bindings/generated_in_modules.gni
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_component_result.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_result.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_result.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_connection_event_init.cc",
Expand Down
1 change: 1 addition & 0 deletions blink/renderer/bindings/idl_in_modules.gni
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,7 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/url_pattern/url_pattern.idl",
"//third_party/blink/renderer/modules/url_pattern/url_pattern_component_result.idl",
"//third_party/blink/renderer/modules/url_pattern/url_pattern_init.idl",
"//third_party/blink/renderer/modules/url_pattern/url_pattern_options.idl",
"//third_party/blink/renderer/modules/url_pattern/url_pattern_result.idl",
"//third_party/blink/renderer/modules/vibration/navigator_vibration.idl",
"//third_party/blink/renderer/modules/video_rvfc/html_video_element_request_video_frame_callback.idl",
Expand Down
55 changes: 40 additions & 15 deletions blink/renderer/modules/url_pattern/url_pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_union_urlpatterninit_usvstring.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_component_result.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_result.h"
#include "third_party/blink/renderer/modules/url_pattern/url_pattern_canon.h"
#include "third_party/blink/renderer/modules/url_pattern/url_pattern_component.h"
Expand Down Expand Up @@ -215,6 +216,7 @@ URLPatternComponentResult* MakeURLPatternComponentResult(

URLPattern* URLPattern::Create(const V8URLPatternInput* input,
const String& base_url,
const URLPatternOptions* options,
ExceptionState& exception_state) {
if (input->GetContentType() ==
V8URLPatternInput::ContentType::kURLPatternInit) {
Expand All @@ -227,7 +229,7 @@ URLPattern* URLPattern::Create(const V8URLPatternInput* input,

const auto& input_string = input->GetAsUSVString();

url_pattern::Parser parser(input_string);
url_pattern::Parser parser(input_string, *options);
parser.Parse(exception_state);
if (exception_state.HadException())
return nullptr;
Expand All @@ -243,14 +245,33 @@ URLPattern* URLPattern::Create(const V8URLPatternInput* input,
if (base_url)
init->setBaseURL(base_url);

return Create(init, parser.GetProtocolComponent(), exception_state);
return Create(init, parser.GetProtocolComponent(), options, exception_state);
}

URLPattern* URLPattern::Create(const V8URLPatternInput* input,
const String& base_url,
ExceptionState& exception_state) {
return Create(input, base_url, MakeGarbageCollected<URLPatternOptions>(),
exception_state);
}

URLPattern* URLPattern::Create(const V8URLPatternInput* input,
const URLPatternOptions* options,
ExceptionState& exception_state) {
if (input->IsURLPatternInit()) {
return URLPattern::Create(input->GetAsURLPatternInit(),
/*precomputed_protocol_component=*/nullptr,
options, exception_state);
}
return Create(input, /*base_url=*/String(), options, exception_state);
}

URLPattern* URLPattern::Create(const V8URLPatternInput* input,
ExceptionState& exception_state) {
if (input->IsURLPatternInit()) {
return URLPattern::Create(input->GetAsURLPatternInit(),
/*precomputed_protocol_component=*/nullptr,
MakeGarbageCollected<URLPatternOptions>(),
exception_state);
}

Expand All @@ -259,6 +280,7 @@ URLPattern* URLPattern::Create(const V8URLPatternInput* input,

URLPattern* URLPattern::Create(const URLPatternInit* init,
Component* precomputed_protocol_component,
const URLPatternOptions* options,
ExceptionState& exception_state) {
// Each component defaults to a wildcard matching any input. We use
// the null string as a shorthand for the default.
Expand Down Expand Up @@ -290,49 +312,52 @@ URLPattern* URLPattern::Create(const URLPatternInit* init,

auto* protocol_component = precomputed_protocol_component;
if (!protocol_component) {
protocol_component =
Component::Compile(protocol, Component::Type::kProtocol,
/*protocol_component=*/nullptr, exception_state);
protocol_component = Component::Compile(
protocol, Component::Type::kProtocol,
/*protocol_component=*/nullptr, *options, exception_state);
}
if (exception_state.HadException())
return nullptr;

auto* username_component =
Component::Compile(username, Component::Type::kUsername,
protocol_component, exception_state);
protocol_component, *options, exception_state);
if (exception_state.HadException())
return nullptr;

auto* password_component =
Component::Compile(password, Component::Type::kPassword,
protocol_component, exception_state);
protocol_component, *options, exception_state);
if (exception_state.HadException())
return nullptr;

auto* hostname_component =
Component::Compile(hostname, Component::Type::kHostname,
protocol_component, exception_state);
protocol_component, *options, exception_state);
if (exception_state.HadException())
return nullptr;

auto* port_component = Component::Compile(
port, Component::Type::kPort, protocol_component, exception_state);
auto* port_component =
Component::Compile(port, Component::Type::kPort, protocol_component,
*options, exception_state);
if (exception_state.HadException())
return nullptr;

auto* pathname_component =
Component::Compile(pathname, Component::Type::kPathname,
protocol_component, exception_state);
protocol_component, *options, exception_state);
if (exception_state.HadException())
return nullptr;

auto* search_component = Component::Compile(
search, Component::Type::kSearch, protocol_component, exception_state);
auto* search_component =
Component::Compile(search, Component::Type::kSearch, protocol_component,
*options, exception_state);
if (exception_state.HadException())
return nullptr;

auto* hash_component = Component::Compile(
hash, Component::Type::kHash, protocol_component, exception_state);
auto* hash_component =
Component::Compile(hash, Component::Type::kHash, protocol_component,
*options, exception_state);
if (exception_state.HadException())
return nullptr;

Expand Down
11 changes: 11 additions & 0 deletions blink/renderer/modules/url_pattern/url_pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace blink {

class ExceptionState;
class URLPatternInit;
class URLPatternOptions;
class URLPatternResult;

namespace url_pattern {
Expand All @@ -29,13 +30,23 @@ class MODULES_EXPORT URLPattern : public ScriptWrappable {
public:
static URLPattern* Create(const V8URLPatternInput* input,
const String& base_url,
const URLPatternOptions* options,
ExceptionState& exception_state);

static URLPattern* Create(const V8URLPatternInput* input,
const String& base_url,
ExceptionState& exception_state);

static URLPattern* Create(const V8URLPatternInput* input,
const URLPatternOptions* options,
ExceptionState& exception_state);

static URLPattern* Create(const V8URLPatternInput* input,
ExceptionState& exception_state);

static URLPattern* Create(const URLPatternInit* init,
Component* precomputed_protocol_component,
const URLPatternOptions* options,
ExceptionState& exception_state);

URLPattern(Component* protocol,
Expand Down
5 changes: 4 additions & 1 deletion blink/renderer/modules/url_pattern/url_pattern.idl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ enum URLPatternComponent { "protocol", "username", "password", "hostname",
Exposed=(Window,Worker)
] interface URLPattern {
[RaisesException, Measure]
constructor(optional URLPatternInput input = {}, optional USVString baseURL);
constructor(optional URLPatternInput input = {}, optional USVString baseURL, optional URLPatternOptions options = {});

[RaisesException, Measure]
constructor(URLPatternInput input, URLPatternOptions options);

[RaisesException, CallWith=ScriptState, Measure]
boolean test(optional URLPatternInput input = {}, optional USVString baseURL);
Expand Down
90 changes: 36 additions & 54 deletions blink/renderer/modules/url_pattern/url_pattern_component.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_options.h"
#include "third_party/blink/renderer/modules/url_pattern/url_pattern_canon.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
Expand Down Expand Up @@ -118,63 +119,42 @@ liburlpattern::EncodeCallback GetEncodeCallback(base::StringPiece pattern_utf8,

// Utility method to get the correct liburlpattern parse options for a given
// type.
const liburlpattern::Options& GetOptions(Component::Type type,
Component* protocol_component) {
const liburlpattern::Options GetOptions(
Component::Type type,
Component* protocol_component,
const URLPatternOptions& external_options) {
using liburlpattern::Options;

// The liburlpattern::Options to use for most component patterns. We
// default to strict mode and case sensitivity. In addition, most
// components have no concept of a delimiter or prefix character.
DEFINE_THREAD_SAFE_STATIC_LOCAL(Options, default_options,
({.delimiter_list = "",
.prefix_list = "",
.sensitive = true,
.strict = true}));

// The liburlpattern::Options to use for hostname patterns. This uses a
// "." delimiter controlling how far a named group like ":bar" will match
// by default. Note, hostnames are case insensitive but we require case
// sensitivity here. This assumes that the hostname values have already
// been normalized to lower case as in URL().
DEFINE_THREAD_SAFE_STATIC_LOCAL(Options, hostname_options,
({.delimiter_list = ".",
.prefix_list = "",
.sensitive = true,
.strict = true}));

// The liburlpattern::Options to use for pathname patterns. This uses a
// "/" delimiter controlling how far a named group like ":bar" will match
// by default. It also configures "/" to be treated as an automatic
// prefix before groups.
DEFINE_THREAD_SAFE_STATIC_LOCAL(Options, pathname_options,
({.delimiter_list = "/",
.prefix_list = "/",
.sensitive = true,
.strict = true}));

switch (type) {
case Component::Type::kHostname:
return hostname_options;
case Component::Type::kPathname:
// Just like how we select a different encoding callback based on
// whether we are treating the pattern string as a standard or
// cannot-be-a-base URL, we must also choose the right liburlppatern
// options as well. We should only use use the options that treat
// `/` specially if we are treating this a standard URL.
DCHECK(protocol_component);
if (protocol_component->ShouldTreatAsStandardURL())
return pathname_options;
else
return default_options;
case Component::Type::kProtocol:
case Component::Type::kUsername:
case Component::Type::kPassword:
case Component::Type::kPort:
case Component::Type::kSearch:
case Component::Type::kHash:
return default_options;
// default to strict mode and most components have no concept of a delimiter
// or prefix character. Case sensitivity is set via the external options.
Options value = {.delimiter_list = "",
.prefix_list = "",
.sensitive = !external_options.ignoreCase(),
.strict = true};

if (type == Component::Type::kHostname) {
// Hostname patterns use a "." delimiter controlling how far a named group
// like ":bar" will match.
value.delimiter_list = ".";

} else if (type == Component::Type::kPathname) {
// Just like how we select a different encoding callback based on
// whether we are treating the pattern string as a standard or
// cannot-be-a-base URL, we must also choose the right liburlppatern
// options as well. We should only use use the options that treat
// `/` specially if we are treating this a standard URL.
DCHECK(protocol_component);
if (protocol_component->ShouldTreatAsStandardURL()) {
// Pathname patterns for "standard" URLs use a "/" delimiter controlling
// how far a named group like ":bar" will match. They also use "/" as an
// automatic prefix before groups.
value.delimiter_list = "/";
value.prefix_list = "/";
}
}
NOTREACHED();

return value;
}

int ComparePart(const liburlpattern::Part& lh, const liburlpattern::Part& rh) {
Expand Down Expand Up @@ -221,9 +201,11 @@ int ComparePart(const liburlpattern::Part& lh, const liburlpattern::Part& rh) {
Component* Component::Compile(StringView pattern,
Type type,
Component* protocol_component,
const URLPatternOptions& external_options,
ExceptionState& exception_state) {
StringView final_pattern = pattern.IsNull() ? "*" : pattern;
const liburlpattern::Options& options = GetOptions(type, protocol_component);
const liburlpattern::Options& options =
GetOptions(type, protocol_component, external_options);

// Parse the pattern.
// Lossy UTF8 conversion is fine given the input has come through a
Expand Down
2 changes: 2 additions & 0 deletions blink/renderer/modules/url_pattern/url_pattern_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace blink {

class ExceptionState;
class URLPatternOptions;

namespace url_pattern {

Expand Down Expand Up @@ -49,6 +50,7 @@ class Component final : public GarbageCollected<Component> {
static Component* Compile(StringView pattern,
Type type,
Component* protocol_component,
const URLPatternOptions& external_options,
ExceptionState& exception_state);

// Compare the pattern strings in the two given components. This provides a
Expand Down
8 changes: 8 additions & 0 deletions blink/renderer/modules/url_pattern/url_pattern_options.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// https://wicg.github.io/urlpattern/
dictionary URLPatternOptions {
boolean ignoreCase = false;
};
9 changes: 5 additions & 4 deletions blink/renderer/modules/url_pattern/url_pattern_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
namespace blink {
namespace url_pattern {

Parser::Parser(const String& input) : input_(input), utf8_(input) {}
Parser::Parser(const String& input, const URLPatternOptions& external_options)
: input_(input), utf8_(input), external_options_(external_options) {}

void Parser::Parse(ExceptionState& exception_state) {
DCHECK_EQ(state_, StringParseState::kInit);
Expand Down Expand Up @@ -457,9 +458,9 @@ String Parser::MakeComponentString() const {

void Parser::ComputeShouldTreatAsStandardURL(ExceptionState& exception_state) {
DCHECK_EQ(state_, StringParseState::kProtocol);
protocol_component_ =
Component::Compile(MakeComponentString(), Component::Type::kProtocol,
/*protocol_component=*/nullptr, exception_state);
protocol_component_ = Component::Compile(
MakeComponentString(), Component::Type::kProtocol,
/*protocol_component=*/nullptr, external_options_, exception_state);
if (protocol_component_ && protocol_component_->ShouldTreatAsStandardURL())
should_treat_as_standard_url_ = true;
}
Expand Down
8 changes: 7 additions & 1 deletion blink/renderer/modules/url_pattern/url_pattern_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace blink {

class ExceptionState;
class URLPatternInit;
class URLPatternOptions;

namespace url_pattern {

Expand All @@ -37,7 +38,7 @@ class Parser final {
STACK_ALLOCATED();

public:
explicit Parser(const String& input);
Parser(const String& input, const URLPatternOptions& external_options);

// Attempt to parse the input string used to construct the Parser object.
// This method may only be called once. Any errors will be thrown on the
Expand Down Expand Up @@ -154,6 +155,11 @@ class Parser final {
// UTF8 representation of `input_`.
const StringUTF8Adaptor utf8_;

// Options passed in to the URLPattern constructor. The external options is
// a garbage collected object. Since this is a stack allocated object this
// reference will keep the options alive.
const URLPatternOptions& external_options_;

// As we parse the input string we populate a `URLPatternInit` dictionary
// with each component pattern. This is then the final result of the parse.
URLPatternInit* result_ = nullptr;
Expand Down
Loading

0 comments on commit 14f1966

Please sign in to comment.