@@ -81,7 +81,71 @@ pub(super) fn is_url_code_point(code_point: char) -> bool {
8181 // U+003B (;), U+003D (=), U+003F (?), U+0040 (@), U+005F (_), U+007E (~), and code
8282 // points in the range U+00A0 to U+10FFFD, inclusive, excluding surrogates and
8383 // noncharacters.
84- code_point. is_ascii_alphanumeric ( ) || "!$&'()*+,-./:;=?@_~" . contains ( code_point)
84+ code_point. is_ascii ( ) && is_ascii_url_code_point_byte ( code_point as u8 )
85+ }
86+
87+ #[ inline]
88+ fn is_ascii_url_code_point_byte ( byte : u8 ) -> bool {
89+ byte. is_ascii_alphanumeric ( )
90+ || matches ! (
91+ byte,
92+ b'!' | b'$'
93+ | b'&'
94+ | b'\''
95+ | b'('
96+ | b')'
97+ | b'*'
98+ | b'+'
99+ | b','
100+ | b'-'
101+ | b'.'
102+ | b'/'
103+ | b':'
104+ | b';'
105+ | b'='
106+ | b'?'
107+ | b'@'
108+ | b'_'
109+ | b'~'
110+ )
111+ }
112+
113+ #[ inline]
114+ fn is_ascii_path_state_copyable_byte ( byte : u8 ) -> bool {
115+ byte. is_ascii_alphanumeric ( )
116+ || matches ! (
117+ byte,
118+ b'!' | b'$'
119+ | b'&'
120+ | b'\''
121+ | b'('
122+ | b')'
123+ | b'*'
124+ | b'+'
125+ | b','
126+ | b'-'
127+ | b'.'
128+ | b':'
129+ | b';'
130+ | b'='
131+ | b'@'
132+ | b'_'
133+ | b'~'
134+ )
135+ }
136+
137+ #[ inline]
138+ fn is_ascii_query_state_copyable_byte ( byte : u8 ) -> bool {
139+ is_ascii_url_code_point_byte ( byte)
140+ }
141+
142+ #[ inline]
143+ fn ascii_copyable_state_prefix_length ( input : & str , is_copyable_byte : impl Fn ( u8 ) -> bool ) -> usize {
144+ input
145+ . as_bytes ( )
146+ . iter ( )
147+ . position ( |& byte| !is_copyable_byte ( byte) )
148+ . unwrap_or ( input. len ( ) )
85149}
86150
87151// https://url.spec.whatwg.org/#single-dot-path-segment
@@ -1061,6 +1125,16 @@ pub(crate) fn basic_parse_into(
10611125 }
10621126 // 2. Otherwise, run these steps:
10631127 else {
1128+ // OPTIMIZATION: The spec processes one code point at a time here. Copy the prefix of ASCII
1129+ // bytes that can be appended without changing parser state or requiring percent-encoding.
1130+ let prefix_length =
1131+ ascii_copyable_state_prefix_length ( remaining, is_ascii_path_state_copyable_byte) ;
1132+ if prefix_length > 0 {
1133+ buffer. push_str ( & remaining[ ..prefix_length] ) ;
1134+ pointer += prefix_length;
1135+ continue ;
1136+ }
1137+
10641138 // 1. If c is not a URL code point and not U+0025 (%), invalid-URL-unit validation error.
10651139 if let Some ( byte) = code_point {
10661140 if !is_url_code_point ( byte) && byte != '%' {
@@ -1167,6 +1241,16 @@ pub(crate) fn basic_parse_into(
11671241 }
11681242 // 3. Otherwise, if c is not the EOF code point:
11691243 else if let Some ( byte) = code_point {
1244+ // OPTIMIZATION: The spec appends query code points one at a time before the final encoding pass.
1245+ // Copy the matching ASCII URL-code-point prefix directly and resume normal handling at the first special byte.
1246+ let prefix_length =
1247+ ascii_copyable_state_prefix_length ( remaining, is_ascii_query_state_copyable_byte) ;
1248+ if prefix_length > 0 {
1249+ buffer. push_str ( & remaining[ ..prefix_length] ) ;
1250+ pointer += prefix_length;
1251+ continue ;
1252+ }
1253+
11701254 // 1. If c is not a URL code point and not U+0025 (%), invalid-URL-unit validation error.
11711255 if !is_url_code_point ( byte) && byte != '%' {
11721256 report_validation_error ( State :: Query , pointer, code_point, "invalid-URL-unit" ) ;
0 commit comments