1616
1717package com .microsoft .playwright .impl ;
1818
19- import com .google .gson .JsonArray ;
20- import com .google .gson .JsonObject ;
2119import com .microsoft .playwright .PlaywrightException ;
2220
2321import java .net .MalformedURLException ;
22+ import java .net .URI ;
23+ import java .net .URISyntaxException ;
2424import java .net .URL ;
25- import java .util .Objects ;
2625import java .util .function .Predicate ;
2726import java .util .regex .Pattern ;
27+ import java .util .ArrayList ;
28+ import java .util .List ;
2829
2930import static com .microsoft .playwright .impl .Utils .globToRegex ;
3031import static com .microsoft .playwright .impl .Utils .toJsRegexFlags ;
3132
3233class UrlMatcher {
33- final Object rawSource ;
34- private final Predicate <String > predicate ;
35-
36- private static Predicate <String > toPredicate (Pattern pattern ) {
37- return s -> pattern .matcher (s ).find ();
38- }
39-
40- static UrlMatcher any () {
41- return new UrlMatcher ((Object ) null , null );
42- }
34+ private final URL baseURL ;
35+ public final String glob ;
36+ public final Pattern pattern ;
37+ public final Predicate <String > predicate ;
4338
4439 static UrlMatcher forOneOf (URL baseUrl , Object object ) {
4540 if (object == null ) {
46- return UrlMatcher . any ( );
41+ return new UrlMatcher ( baseUrl , ( String ) null );
4742 }
4843 if (object instanceof String ) {
4944 return new UrlMatcher (baseUrl , (String ) object );
@@ -58,6 +53,16 @@ static UrlMatcher forOneOf(URL baseUrl, Object object) {
5853 }
5954
6055 static String resolveUrl (URL baseUrl , String spec ) {
56+ try {
57+ URL specURL = new URL (spec );
58+ // We want to follow HTTP spec, so we enforce a slash if there is no path.
59+ if (specURL .getPath ().isEmpty ()) {
60+ spec = specURL .toString () + "/" ;
61+ }
62+ } catch (MalformedURLException e ) {
63+ // Ignore - we end up here if spec is e.g. a relative path.
64+ }
65+
6166 if (baseUrl == null ) {
6267 return spec ;
6368 }
@@ -68,50 +73,102 @@ static String resolveUrl(URL baseUrl, String spec) {
6873 }
6974 }
7075
71- UrlMatcher (URL base , String url ) {
72- this (url , toPredicate (Pattern .compile (globToRegex (resolveUrl (base , url )))).or (s -> url == null || url .equals (s )));
76+ static private String normaliseUrl (String url ) {
77+ URI parsedUrl ;
78+ try {
79+ parsedUrl = new URI (url );
80+ } catch (URISyntaxException e ) {
81+ return url ;
82+ }
83+ // Align with the Node.js URL parser which automatically adds a slash to the path if it is empty.
84+ if (parsedUrl .getScheme () != null && (
85+ parsedUrl .getScheme ().equals ("http" ) || parsedUrl .getScheme ().equals ("https" ) ||
86+ parsedUrl .getScheme ().equals ("ws" ) || parsedUrl .getScheme ().equals ("wss" )
87+ ) && parsedUrl .getPath ().isEmpty ()) {
88+ try {
89+ return new URI (parsedUrl .getScheme (), parsedUrl .getAuthority (), "/" , parsedUrl .getQuery (), parsedUrl .getFragment ()).toString ();
90+ } catch (URISyntaxException e ) {
91+ return url ;
92+ }
93+ }
94+ return url ;
95+ }
96+
97+ UrlMatcher (URL baseURL , String glob ) {
98+ this (baseURL , null , null , glob );
7399 }
74100
75101 UrlMatcher (Pattern pattern ) {
76- this (pattern , toPredicate ( pattern ) );
102+ this (null , pattern , null , null );
77103 }
104+
78105 UrlMatcher (Predicate <String > predicate ) {
79- this (predicate , predicate );
106+ this (null , null , predicate , null );
80107 }
81108
82- private UrlMatcher (Object rawSource , Predicate <String > predicate ) {
83- this .rawSource = rawSource ;
109+ private UrlMatcher (URL baseURL , Pattern pattern , Predicate <String > predicate , String glob ) {
110+ this .baseURL = baseURL ;
111+ this .pattern = pattern ;
84112 this .predicate = predicate ;
113+ this .glob = glob ;
85114 }
86115
87116 boolean test (String value ) {
88- return predicate == null || predicate .test (value );
117+ return testImpl (baseURL , pattern , predicate , glob , value );
118+ }
119+
120+ private static boolean testImpl (URL baseURL , Pattern pattern , Predicate <String > predicate , String glob , String value ) {
121+ if (pattern != null ) {
122+ return pattern .matcher (value ).find ();
123+ }
124+ if (predicate != null ) {
125+ return predicate .test (value );
126+ }
127+ if (glob != null ) {
128+ if (!glob .startsWith ("*" )) {
129+ glob = normaliseUrl (glob );
130+ // Allow http(s) baseURL to match ws(s) urls.
131+ if (baseURL != null && Pattern .compile ("^https?://" ).matcher (baseURL .getProtocol ()).find () && Pattern .compile ("^wss?://" ).matcher (value ).find ()) {
132+ try {
133+ baseURL = new URL (baseURL .toString ().replaceFirst ("^http" , "ws" ));
134+ } catch (MalformedURLException e ) {
135+ // Handle exception
136+ }
137+ }
138+ glob = resolveUrl (baseURL , glob );
139+ }
140+ return Pattern .compile (globToRegex (glob )).matcher (value ).find ();
141+ }
142+ return true ;
89143 }
90144
91145 @ Override
92146 public boolean equals (Object o ) {
93147 if (this == o ) return true ;
94148 if (o == null || getClass () != o .getClass ()) return false ;
95149 UrlMatcher that = (UrlMatcher ) o ;
96- if (rawSource instanceof Pattern && that .rawSource instanceof Pattern ) {
97- Pattern a = (Pattern ) rawSource ;
98- Pattern b = (Pattern ) that .rawSource ;
99- return a .pattern ().equals (b .pattern ()) && a .flags () == b .flags ();
150+ List <Boolean > matches = new ArrayList <>();
151+ if (baseURL != null && that .baseURL != null ) {
152+ matches .add (baseURL .equals (that .baseURL ));
100153 }
101- return Objects .equals (rawSource , that .rawSource );
102- }
103-
104- @ Override
105- public int hashCode () {
106- return Objects .hash (rawSource );
154+ if (pattern != null && that .pattern != null ) {
155+ matches .add (pattern .pattern ().equals (that .pattern .pattern ()) && pattern .flags () == that .pattern .flags ());
156+ }
157+ if (predicate != null && that .predicate != null ) {
158+ matches .add (predicate .equals (that .predicate ));
159+ }
160+ if (glob != null && that .glob != null ) {
161+ matches .add (glob .equals (that .glob ));
162+ }
163+ return matches .stream ().allMatch (m -> m );
107164 }
108165
109166 @ Override
110167 public String toString () {
111- if (rawSource = = null )
112- return "<any>" ;
113- if (rawSource instanceof Predicate )
114- return "matching predicate" ;
115- return rawSource . toString ( );
168+ if (pattern ! = null )
169+ return String . format ( "<regex pattern= \" %s \" flags= \" %s \" >" , pattern . pattern (), toJsRegexFlags ( pattern )) ;
170+ if (predicate != null )
171+ return "< predicate> " ;
172+ return String . format ( "<glob pattern= \" %s \" >" , glob );
116173 }
117174}
0 commit comments