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,99 @@ 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 () == "http" || parsedUrl .getScheme () == "https" ) && parsedUrl .getPath ().isEmpty ()) {
85+ try {
86+ return new URI (parsedUrl .getScheme (), parsedUrl .getAuthority (), "/" , parsedUrl .getQuery (), parsedUrl .getFragment ()).toString ();
87+ } catch (URISyntaxException e ) {
88+ return url ;
89+ }
90+ }
91+ return url ;
92+ }
93+
94+ UrlMatcher (URL baseURL , String glob ) {
95+ this (baseURL , null , null , glob );
7396 }
7497
7598 UrlMatcher (Pattern pattern ) {
76- this (pattern , toPredicate ( pattern ) );
99+ this (null , pattern , null , null );
77100 }
101+
78102 UrlMatcher (Predicate <String > predicate ) {
79- this (predicate , predicate );
103+ this (null , null , predicate , null );
80104 }
81105
82- private UrlMatcher (Object rawSource , Predicate <String > predicate ) {
83- this .rawSource = rawSource ;
106+ private UrlMatcher (URL baseURL , Pattern pattern , Predicate <String > predicate , String glob ) {
107+ this .baseURL = baseURL ;
108+ this .pattern = pattern ;
84109 this .predicate = predicate ;
110+ this .glob = glob ;
85111 }
86112
87113 boolean test (String value ) {
88- return predicate == null || predicate .test (value );
114+ return testImpl (baseURL , pattern , predicate , glob , value );
115+ }
116+
117+ private static boolean testImpl (URL baseURL , Pattern pattern , Predicate <String > predicate , String glob , String value ) {
118+ if (pattern != null ) {
119+ return pattern .matcher (value ).find ();
120+ }
121+ if (predicate != null ) {
122+ return predicate .test (value );
123+ }
124+ if (glob != null ) {
125+ if (!glob .startsWith ("*" )) {
126+ glob = normaliseUrl (glob );
127+ // Allow http(s) baseURL to match ws(s) urls.
128+ if (baseURL != null && Pattern .compile ("^https?://" ).matcher (baseURL .getProtocol ()).find () && Pattern .compile ("^wss?://" ).matcher (value ).find ()) {
129+ try {
130+ baseURL = new URL (baseURL .toString ().replaceFirst ("^http" , "ws" ));
131+ } catch (MalformedURLException e ) {
132+ // Handle exception
133+ }
134+ }
135+ glob = resolveUrl (baseURL , glob );
136+ }
137+ return Pattern .compile (globToRegex (glob )).matcher (value ).find ();
138+ }
139+ return true ;
89140 }
90141
91142 @ Override
92143 public boolean equals (Object o ) {
93144 if (this == o ) return true ;
94145 if (o == null || getClass () != o .getClass ()) return false ;
95146 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 ();
147+ List <Boolean > matches = new ArrayList <>();
148+ if (baseURL != null && that .baseURL != null ) {
149+ matches .add (baseURL .equals (that .baseURL ));
100150 }
101- return Objects .equals (rawSource , that .rawSource );
102- }
103-
104- @ Override
105- public int hashCode () {
106- return Objects .hash (rawSource );
151+ if (pattern != null && that .pattern != null ) {
152+ matches .add (pattern .pattern ().equals (that .pattern .pattern ()) && pattern .flags () == that .pattern .flags ());
153+ }
154+ if (predicate != null && that .predicate != null ) {
155+ matches .add (predicate .equals (that .predicate ));
156+ }
157+ if (glob != null && that .glob != null ) {
158+ matches .add (glob .equals (that .glob ));
159+ }
160+ return matches .stream ().allMatch (m -> m );
107161 }
108162
109163 @ Override
110164 public String toString () {
111- if (rawSource = = null )
112- return "<any>" ;
113- if (rawSource instanceof Predicate )
114- return "matching predicate" ;
115- return rawSource . toString ( );
165+ if (pattern ! = null )
166+ return String . format ( "<regex pattern= \" %s \" flags= \" %s \" >" , pattern . pattern (), toJsRegexFlags ( pattern )) ;
167+ if (predicate != null )
168+ return "< predicate> " ;
169+ return String . format ( "<glob pattern= \" %s \" >" , glob );
116170 }
117171}
0 commit comments