@@ -201,10 +201,16 @@ impl<'i> Input<'i> {
201
201
Input :: with_log ( input, None )
202
202
}
203
203
204
+ pub fn no_trim ( input : & ' i str ) -> Self {
205
+ Input {
206
+ chars : input. chars ( ) ,
207
+ }
208
+ }
209
+
204
210
pub fn with_log ( original_input : & ' i str , vfn : Option < & dyn Fn ( SyntaxViolation ) > ) -> Self {
205
211
let input = original_input. trim_matches ( c0_control_or_space) ;
206
212
if let Some ( vfn) = vfn {
207
- if input. len ( ) < original_input. len ( ) {
213
+ if input. len ( ) != original_input. len ( ) {
208
214
vfn ( SyntaxViolation :: C0SpaceIgnored )
209
215
}
210
216
if input. chars ( ) . any ( |c| matches ! ( c, '\t' | '\n' | '\r' ) ) {
@@ -912,6 +918,14 @@ impl<'a> Parser<'a> {
912
918
let ( host, remaining) = Parser :: parse_host ( input, scheme_type) ?;
913
919
write ! ( & mut self . serialization, "{}" , host) . unwrap ( ) ;
914
920
let host_end = to_u32 ( self . serialization . len ( ) ) ?;
921
+ if remaining. starts_with ( ":" ) {
922
+ // Port with an empty host
923
+ if let Host :: Domain ( h) = & host {
924
+ if h. is_empty ( ) {
925
+ return Err ( ParseError :: EmptyHost ) ;
926
+ }
927
+ }
928
+ }
915
929
let ( port, remaining) = if let Some ( remaining) = remaining. split_prefix ( ':' ) {
916
930
let scheme = || default_port ( & self . serialization [ ..scheme_end as usize ] ) ;
917
931
Parser :: parse_port ( remaining, scheme, self . context ) ?
@@ -978,10 +992,32 @@ impl<'a> Parser<'a> {
978
992
Ok ( ( host, input) )
979
993
}
980
994
981
- pub ( crate ) fn parse_file_host < ' i > (
995
+ pub fn get_file_host < ' i > ( input : Input < ' i > ) -> ParseResult < ( Host < String > , Input ) > {
996
+ let ( _, host_str, remaining) = Parser :: file_host ( input) ?;
997
+ let host = Host :: parse ( & host_str) ?;
998
+ Ok ( ( host, remaining) )
999
+ }
1000
+
1001
+ fn parse_file_host < ' i > (
982
1002
& mut self ,
983
1003
input : Input < ' i > ,
984
1004
) -> ParseResult < ( bool , HostInternal , Input < ' i > ) > {
1005
+ let ( has_host, host_str, remaining) = Parser :: file_host ( input) ?;
1006
+ let host = if host_str. is_empty ( ) {
1007
+ HostInternal :: None
1008
+ } else {
1009
+ match Host :: parse ( & host_str) ? {
1010
+ Host :: Domain ( ref d) if d == "localhost" => HostInternal :: None ,
1011
+ host => {
1012
+ write ! ( & mut self . serialization, "{}" , host) . unwrap ( ) ;
1013
+ host. into ( )
1014
+ }
1015
+ }
1016
+ } ;
1017
+ Ok ( ( has_host, host, remaining) )
1018
+ }
1019
+
1020
+ pub fn file_host < ' i > ( input : Input < ' i > ) -> ParseResult < ( bool , String , Input < ' i > ) > {
985
1021
// Undo the Input abstraction here to avoid allocating in the common case
986
1022
// where the host part of the input does not contain any tab or newline
987
1023
let input_str = input. chars . as_str ( ) ;
@@ -1010,20 +1046,9 @@ impl<'a> Parser<'a> {
1010
1046
}
1011
1047
}
1012
1048
if is_windows_drive_letter ( host_str) {
1013
- return Ok ( ( false , HostInternal :: None , input) ) ;
1049
+ return Ok ( ( false , "" . to_string ( ) , input) ) ;
1014
1050
}
1015
- let host = if host_str. is_empty ( ) {
1016
- HostInternal :: None
1017
- } else {
1018
- match Host :: parse ( host_str) ? {
1019
- Host :: Domain ( ref d) if d == "localhost" => HostInternal :: None ,
1020
- host => {
1021
- write ! ( & mut self . serialization, "{}" , host) . unwrap ( ) ;
1022
- host. into ( )
1023
- }
1024
- }
1025
- } ;
1026
- Ok ( ( true , host, remaining) )
1051
+ Ok ( ( true , host_str. to_string ( ) , remaining) )
1027
1052
}
1028
1053
1029
1054
pub fn parse_port < P > (
@@ -1448,6 +1473,12 @@ fn c0_control_or_space(ch: char) -> bool {
1448
1473
ch <= ' ' // U+0000 to U+0020
1449
1474
}
1450
1475
1476
+ /// https://infra.spec.whatwg.org/#ascii-tab-or-newline
1477
+ #[ inline]
1478
+ fn ascii_tab_or_new_line ( ch : char ) -> bool {
1479
+ matches ! ( ch, '\t' | '\r' | '\n' )
1480
+ }
1481
+
1451
1482
/// https://url.spec.whatwg.org/#ascii-alpha
1452
1483
#[ inline]
1453
1484
pub fn ascii_alpha ( ch : char ) -> bool {
0 commit comments