1313
1414package org .eclipse .jetty .rewrite .handler ;
1515
16+ import java .io .ByteArrayInputStream ;
17+ import java .io .ByteArrayOutputStream ;
18+ import java .io .IOException ;
19+ import java .nio .ByteBuffer ;
20+ import java .util .Objects ;
21+ import java .util .Properties ;
1622import java .util .stream .Stream ;
1723
1824import org .eclipse .jetty .http .HttpStatus ;
1925import org .eclipse .jetty .http .HttpTester ;
2026import org .eclipse .jetty .http .HttpURI ;
2127import org .eclipse .jetty .http .UriCompliance ;
22- import org .eclipse .jetty .io .Content ;
2328import org .eclipse .jetty .server .Handler ;
2429import org .eclipse .jetty .server .Request ;
2530import org .eclipse .jetty .server .Response ;
@@ -36,14 +41,20 @@ public static Stream<Arguments> scenarios()
3641 {
3742 return Stream .of (
3843 // shouldn't change anything
39- Arguments .of ("/foo" , null , "/foo" , null , "/foo" ),
40- Arguments .of ("/" , null , "/" , null , "/" ),
44+ Arguments .of ("/foo" , null , "/foo" , "" , "/foo" ),
45+ Arguments .of ("/" , null , "/" , "" , "/" ),
4146 // simple compact path
42- Arguments .of ("////foo" , null , "/foo" , null , "/foo" ),
47+ Arguments .of ("////foo" , null , "/foo" , "" , "/foo" ),
4348 // with simple query
4449 Arguments .of ("//foo//bar" , "a=b" , "/foo/bar" , "a=b" , "/foo/bar?a=b" ),
4550 // with query that has double slashes (should preserve slashes in query)
46- Arguments .of ("//foo//bar" , "a=b//c" , "/foo/bar" , "a=b//c" , "/foo/bar?a=b//c" )
51+ Arguments .of ("//foo//bar" , "a=b//c" , "/foo/bar" , "a=b//c" , "/foo/bar?a=b//c" ),
52+ // with ambiguous path parameter
53+ Arguments .of ("//foo/..;/bar" , "a=b//c" , "/bar" , "a=b//c" , "/bar?a=b//c" ),
54+ // with ambiguous path separator (not changed)
55+ Arguments .of ("//foo/b%2far" , "a=b//c" , "/foo/b%2Far" , "a=b//c" , "/foo/b%2Far?a=b//c" ),
56+ // with ambiguous path encoding (not changed)
57+ Arguments .of ("//foo/%2562ar" , "a=b//c" , "/foo/%2562ar" , "a=b//c" , "/foo/%2562ar?a=b//c" )
4758 );
4859 }
4960
@@ -59,24 +70,67 @@ public void testCompactPathRule(String inputPath, String inputQuery, String expe
5970 @ Override
6071 public boolean handle (Request request , Response response , Callback callback )
6172 {
62- Content .Sink .write (response , true , request .getHttpURI ().getPathQuery (), callback );
73+ Properties props = new Properties ();
74+ HttpURI httpURI = request .getHttpURI ();
75+ props .setProperty ("uri.path" , of (httpURI .getPath ()));
76+ props .setProperty ("uri.query" , of (httpURI .getQuery ()));
77+ props .setProperty ("uri.pathQuery" , of (httpURI .getPathQuery ()));
78+ props .setProperty ("uri.hasViolations" , of (httpURI .hasViolations ()));
79+ props .setProperty ("uri.isAmbiguous" , of (httpURI .isAmbiguous ()));
80+ props .setProperty ("uri.hasAmbiguousEmptySegment" , of (httpURI .hasAmbiguousEmptySegment ()));
81+ props .setProperty ("uri.hasAmbiguousEncoding" , of (httpURI .hasAmbiguousEncoding ()));
82+ props .setProperty ("uri.hasAmbiguousParameter" , of (httpURI .hasAmbiguousParameter ()));
83+ props .setProperty ("uri.hasAmbiguousSeparator" , of (httpURI .hasAmbiguousSeparator ()));
84+ props .setProperty ("uri.hasAmbiguousSegment" , of (httpURI .hasAmbiguousSegment ()));
85+ try (ByteArrayOutputStream out = new ByteArrayOutputStream ())
86+ {
87+ props .store (out , "HttpURI State" );
88+ response .write (true , ByteBuffer .wrap (out .toByteArray ()), callback );
89+ }
90+ catch (IOException e )
91+ {
92+ callback .failed (e );
93+ }
6394 return true ;
6495 }
96+
97+ private String of (Object obj )
98+ {
99+ if (obj == null )
100+ return "" ;
101+ if (obj instanceof Boolean )
102+ return Boolean .toString ((Boolean )obj );
103+ return Objects .toString (obj );
104+ }
65105 });
66106
67107
68108 String request = """
69109 GET %s HTTP/1.1
70110 Host: localhost
71-
111+
72112 """ .formatted (HttpURI .build ().path (inputPath ).query (inputQuery ));
73113
74114 HttpTester .Response response = HttpTester .parseResponse (_connector .getResponse (request ));
75- System .err .println (response .getReason ());
76115 assertEquals (HttpStatus .OK_200 , response .getStatus ());
77- HttpURI .Mutable result = HttpURI .build (response .getContent ());
78- assertEquals (expectedPath , result .getPath ());
79- assertEquals (expectedQuery , result .getQuery ());
80- assertEquals (expectedPathQuery , result .getPathQuery ());
116+ Properties props = new Properties ();
117+ try (ByteArrayInputStream in = new ByteArrayInputStream (response .getContentBytes ()))
118+ {
119+ props .load (in );
120+ assertEquals (expectedPath , props .getProperty ("uri.path" ));
121+ assertEquals (expectedQuery , props .getProperty ("uri.query" ));
122+ assertEquals (expectedPathQuery , props .getProperty ("uri.pathQuery" ));
123+
124+ boolean ambiguousPathSep = inputPath .contains ("%2f" );
125+ boolean ambiguousPathEncoding = inputPath .contains ("%25" );
126+
127+ assertEquals (Boolean .toString (ambiguousPathSep || ambiguousPathEncoding ), props .getProperty ("uri.isAmbiguous" ));
128+ assertEquals (Boolean .toString (ambiguousPathSep || ambiguousPathEncoding ), props .getProperty ("uri.hasViolations" ));
129+ assertEquals ("false" , props .getProperty ("uri.hasAmbiguousEmptySegment" ));
130+ assertEquals (Boolean .toString (ambiguousPathEncoding ), props .getProperty ("uri.hasAmbiguousEncoding" ));
131+ assertEquals ("false" , props .getProperty ("uri.hasAmbiguousParameter" ));
132+ assertEquals (Boolean .toString (ambiguousPathSep ), props .getProperty ("uri.hasAmbiguousSeparator" ));
133+ assertEquals ("false" , props .getProperty ("uri.hasAmbiguousSegment" ));
134+ }
81135 }
82136}
0 commit comments