Skip to content

Commit

Permalink
URLPattern: Create helper for accepting values from script.
Browse files Browse the repository at this point in the history
This allows a string, dictionary or URLPattern wrapper to be coerced to
URLPattern, so that code further in the function need only deal with
complete patterns.

Bug: 1504683
Change-Id: Ie7a6f9e4e92fd81f6eeba84403bebf2615af619c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5053645
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Reviewed-by: Shunya Shishido <sisidovski@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1228890}
  • Loading branch information
jeremyroman authored and Chromium LUCI CQ committed Nov 24, 2023
1 parent 682a574 commit a72861d
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 1 deletion.
2 changes: 2 additions & 0 deletions third_party/blink/renderer/bindings/generated_in_core.gni
Original file line number Diff line number Diff line change
Expand Up @@ -1859,6 +1859,8 @@ generated_union_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_uint32arrayallowshared_unsignedlongsequence.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_unsignedlong_unsignedlongsequence.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_unsignedlong_unsignedlongsequence.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_urlpattern_urlpatterninit_usvstring.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_urlpattern_urlpatterninit_usvstring.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_urlpatterninit_usvstring.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_urlpatterninit_usvstring.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_union_usvstring_uint32array.cc",
Expand Down
5 changes: 4 additions & 1 deletion third_party/blink/renderer/core/url_pattern/build.gni
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

blink_core_tests_url_pattern = [ "url_pattern_histogram_test.cc" ]
blink_core_tests_url_pattern = [
"url_pattern_histogram_test.cc",
"url_pattern_test.cc",
]
51 changes: 51 additions & 0 deletions third_party/blink/renderer/core/url_pattern/url_pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/strings/string_util.h"
#include "third_party/blink/renderer/bindings/core/v8/script_regexp.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_urlpattern_urlpatterninit_usvstring.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_urlpatterninit_usvstring.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_url_pattern_component_result.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_url_pattern_init.h"
Expand Down Expand Up @@ -294,6 +295,56 @@ URLPatternComponentResult* MakeURLPatternComponentResult(

} // namespace

URLPattern* URLPattern::From(const V8URLPatternCompatible* compatible,
const KURL& base_url,
ExceptionState& exception_state) {
switch (compatible->GetContentType()) {
case V8URLPatternCompatible::ContentType::kURLPattern:
return compatible->GetAsURLPattern();
case V8URLPatternCompatible::ContentType::kURLPatternInit: {
URLPatternInit* original_init = compatible->GetAsURLPatternInit();
URLPatternInit* init;
if (original_init->hasBaseURL()) {
init = original_init;
} else {
init = URLPatternInit::Create();
if (original_init->hasProtocol()) {
init->setProtocol(original_init->protocol());
}
if (original_init->hasUsername()) {
init->setUsername(original_init->username());
}
if (original_init->hasPassword()) {
init->setPassword(original_init->password());
}
if (original_init->hasHostname()) {
init->setHostname(original_init->hostname());
}
if (original_init->hasPort()) {
init->setPort(original_init->port());
}
if (original_init->hasPathname()) {
init->setPathname(original_init->pathname());
}
if (original_init->hasSearch()) {
init->setSearch(original_init->search());
}
if (original_init->hasHash()) {
init->setHash(original_init->hash());
}
init->setBaseURL(base_url.GetString());
}
return Create(init, /*precomputed_protocol_component=*/nullptr,
MakeGarbageCollected<URLPatternOptions>(), exception_state);
}
case V8URLPatternCompatible::ContentType::kUSVString:
return Create(
MakeGarbageCollected<V8URLPatternInput>(compatible->GetAsUSVString()),
base_url.GetString(), MakeGarbageCollected<URLPatternOptions>(),
exception_state);
}
}

URLPattern* URLPattern::Create(const V8URLPatternInput* input,
const String& base_url,
const URLPatternOptions* options,
Expand Down
8 changes: 8 additions & 0 deletions third_party/blink/renderer/core/url_pattern/url_pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace blink {

class ExceptionState;
class KURL;
class URLPatternInit;
class URLPatternOptions;
class URLPatternResult;
Expand All @@ -29,6 +30,13 @@ class CORE_EXPORT URLPattern : public ScriptWrappable {
Component::Type::kHash>;

public:
// Used to convert the convenience types that may be passed to WebIDL APIs in
// place of a URLPattern into a URLPattern object. `base_url` will usually be
// the result of calling `ExecutionContext::BaseURL`.
static URLPattern* From(const V8URLPatternCompatible* compatible,
const KURL& base_url,
ExceptionState& exception_state);

static URLPattern* Create(const V8URLPatternInput* input,
const String& base_url,
const URLPatternOptions* options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

typedef (USVString or URLPatternInit) URLPatternInput;
typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible;

enum URLPatternComponent { "protocol", "username", "password", "hostname",
"port", "pathname", "search", "hash" };
Expand Down
107 changes: 107 additions & 0 deletions third_party/blink/renderer/core/url_pattern/url_pattern_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "third_party/blink/renderer/core/url_pattern/url_pattern.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_urlpattern_urlpatterninit_usvstring.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_url_pattern.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"

namespace blink {

namespace {

v8::Local<v8::Value> Eval(V8TestingScope& scope, const char* source) {
v8::Local<v8::Script> script =
v8::Script::Compile(scope.GetContext(),
V8String(scope.GetIsolate(), source))
.ToLocalChecked();
return script->Run(scope.GetContext()).ToLocalChecked();
}

} // namespace

TEST(URLPatternTest, CompatibleFromString) {
KURL base_url("https://urlpattern.example/foo/bar");
V8TestingScope scope(base_url);
v8::Local<v8::String> pattern_string =
V8String(scope.GetIsolate(), "baz/:quux");
auto* compatible = V8URLPatternCompatible::Create(
scope.GetIsolate(), pattern_string, ASSERT_NO_EXCEPTION);
auto* url_pattern =
URLPattern::From(compatible, base_url, ASSERT_NO_EXCEPTION);
EXPECT_EQ(url_pattern->protocol(), "https");
EXPECT_EQ(url_pattern->hostname(), "urlpattern.example");
EXPECT_EQ(url_pattern->pathname(), "/foo/baz/:quux");
}

TEST(URLPatternTest, CompatibleFromStringInvalid) {
KURL base_url("https://urlpattern.example/foo/bar");
V8TestingScope scope(base_url);
v8::Local<v8::String> pattern_string = V8String(scope.GetIsolate(), "{");
auto* compatible = V8URLPatternCompatible::Create(
scope.GetIsolate(), pattern_string, ASSERT_NO_EXCEPTION);
DummyExceptionStateForTesting exception_state;
EXPECT_FALSE(URLPattern::From(compatible, base_url, exception_state));
EXPECT_TRUE(exception_state.HadException());
}

TEST(URLPatternTest, CompatibleFromInit) {
KURL base_url("https://urlpattern.example/foo/bar");
V8TestingScope scope(base_url);
v8::Local<v8::Value> init = Eval(scope, "({search: 'a=42'})");
ASSERT_TRUE(init->IsObject());
auto* compatible = V8URLPatternCompatible::Create(scope.GetIsolate(), init,
ASSERT_NO_EXCEPTION);
auto* url_pattern =
URLPattern::From(compatible, base_url, ASSERT_NO_EXCEPTION);
EXPECT_EQ(url_pattern->protocol(), "https");
EXPECT_EQ(url_pattern->hostname(), "urlpattern.example");
EXPECT_EQ(url_pattern->pathname(), "/foo/bar");
EXPECT_EQ(url_pattern->search(), "a=42");
}

TEST(URLPatternTest, CompatibleFromInitWithBaseURL) {
KURL base_url("https://urlpattern.example/foo/bar");
V8TestingScope scope(base_url);
v8::Local<v8::Value> init =
Eval(scope, "({search: 'a=42', baseURL: 'https://alt.example/'})");
ASSERT_TRUE(init->IsObject());
auto* compatible = V8URLPatternCompatible::Create(scope.GetIsolate(), init,
ASSERT_NO_EXCEPTION);
auto* url_pattern =
URLPattern::From(compatible, base_url, ASSERT_NO_EXCEPTION);
EXPECT_EQ(url_pattern->protocol(), "https");
EXPECT_EQ(url_pattern->hostname(), "alt.example");
EXPECT_EQ(url_pattern->pathname(), "/");
EXPECT_EQ(url_pattern->search(), "a=42");
}

TEST(URLPatternTest, CompatibleFromInitInvalid) {
KURL base_url("https://urlpattern.example/foo/bar");
V8TestingScope scope(base_url);
v8::Local<v8::Value> init = Eval(scope, "({hash: '{'})");
ASSERT_TRUE(init->IsObject());
auto* compatible = V8URLPatternCompatible::Create(scope.GetIsolate(), init,
ASSERT_NO_EXCEPTION);
DummyExceptionStateForTesting exception_state;
EXPECT_FALSE(URLPattern::From(compatible, base_url, exception_state));
EXPECT_TRUE(exception_state.HadException());
}

TEST(URLPatternTest, CompatibleFromURLPattern) {
KURL base_url("https://urlpattern.example/foo/bar");
V8TestingScope scope(base_url);
v8::Local<v8::Value> wrapper =
Eval(scope, "new URLPattern({protocol: 'https'})");
ASSERT_TRUE(V8URLPattern::HasInstance(scope.GetIsolate(), wrapper));
auto* compatible = V8URLPatternCompatible::Create(scope.GetIsolate(), wrapper,
ASSERT_NO_EXCEPTION);
auto* url_pattern =
URLPattern::From(compatible, base_url, ASSERT_NO_EXCEPTION);
EXPECT_EQ(url_pattern, ToScriptWrappable(wrapper.As<v8::Object>()));
}

} // namespace blink

0 comments on commit a72861d

Please sign in to comment.