@@ -79,6 +79,7 @@ macro_rules! simple_enum_error {
79
79
80
80
simple_enum_error ! {
81
81
EmptyHost => "empty host" ,
82
+ InvalidAuthority => "invalid authority" ,
82
83
IdnaError => "invalid international domain name" ,
83
84
InvalidPort => "invalid port number" ,
84
85
InvalidIpv4Address => "invalid IPv4 address" ,
@@ -840,11 +841,13 @@ impl<'a> Parser<'a> {
840
841
self . serialization . push ( '/' ) ;
841
842
self . serialization . push ( '/' ) ;
842
843
// authority state
844
+ let before_authority = self . serialization . len ( ) ;
843
845
let ( username_end, remaining) = self . parse_userinfo ( input, scheme_type) ?;
846
+ let has_authority = before_authority != self . serialization . len ( ) ;
844
847
// host state
845
848
let host_start = to_u32 ( self . serialization . len ( ) ) ?;
846
849
let ( host_end, host, port, remaining) =
847
- self . parse_host_and_port ( remaining, scheme_end, scheme_type) ?;
850
+ self . parse_host_and_port ( remaining, scheme_end, scheme_type, has_authority ) ?;
848
851
// path state
849
852
let path_start = to_u32 ( self . serialization . len ( ) ) ?;
850
853
let remaining = self . parse_path_start ( scheme_type, & mut true , remaining) ;
@@ -888,7 +891,18 @@ impl<'a> Parser<'a> {
888
891
}
889
892
let ( mut userinfo_char_count, remaining) = match last_at {
890
893
None => return Ok ( ( to_u32 ( self . serialization . len ( ) ) ?, input) ) ,
891
- Some ( ( 0 , remaining) ) => return Ok ( ( to_u32 ( self . serialization . len ( ) ) ?, remaining) ) ,
894
+ Some ( ( 0 , remaining) ) => {
895
+ // Otherwise, if one of the following is true
896
+ // c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
897
+ // url is special and c is U+005C (\)
898
+ // If @ flag is set and buffer is the empty string, validation error, return failure.
899
+ if let ( Some ( c) , _) = remaining. split_first ( ) {
900
+ if c == '/' || c == '?' || c == '#' || scheme_type. is_special ( ) && c == '\\' {
901
+ return Err ( ParseError :: InvalidAuthority ) ;
902
+ }
903
+ }
904
+ return Ok ( ( to_u32 ( self . serialization . len ( ) ) ?, remaining) ) ;
905
+ }
892
906
Some ( x) => x,
893
907
} ;
894
908
@@ -930,18 +944,26 @@ impl<'a> Parser<'a> {
930
944
input : Input < ' i > ,
931
945
scheme_end : u32 ,
932
946
scheme_type : SchemeType ,
947
+ has_authority : bool ,
933
948
) -> ParseResult < ( u32 , HostInternal , Option < u16 > , Input < ' i > ) > {
934
949
let ( host, remaining) = Parser :: parse_host ( input, scheme_type) ?;
935
950
write ! ( & mut self . serialization, "{}" , host) . unwrap ( ) ;
936
951
let host_end = to_u32 ( self . serialization . len ( ) ) ?;
937
- if remaining. starts_with ( ":" ) {
938
- // Port with an empty host
939
- if let Host :: Domain ( h) = & host {
940
- if h. is_empty ( ) {
952
+ if let Host :: Domain ( h) = & host {
953
+ if h. is_empty ( ) {
954
+ // Port with an empty host
955
+ if remaining. starts_with ( ":" ) {
956
+ return Err ( ParseError :: EmptyHost ) ;
957
+ }
958
+ if scheme_type. is_special ( ) {
959
+ return Err ( ParseError :: EmptyHost ) ;
960
+ }
961
+ if !scheme_type. is_special ( ) && has_authority {
941
962
return Err ( ParseError :: EmptyHost ) ;
942
963
}
943
964
}
944
- }
965
+ } ;
966
+
945
967
let ( port, remaining) = if let Some ( remaining) = remaining. split_prefix ( ':' ) {
946
968
let scheme = || default_port ( & self . serialization [ ..scheme_end as usize ] ) ;
947
969
Parser :: parse_port ( remaining, scheme, self . context ) ?
@@ -1010,7 +1032,10 @@ impl<'a> Parser<'a> {
1010
1032
1011
1033
pub fn get_file_host < ' i > ( input : Input < ' i > ) -> ParseResult < ( Host < String > , Input ) > {
1012
1034
let ( _, host_str, remaining) = Parser :: file_host ( input) ?;
1013
- let host = Host :: parse ( & host_str) ?;
1035
+ let host = match Host :: parse ( & host_str) ? {
1036
+ Host :: Domain ( ref d) if d == "localhost" => Host :: Domain ( "" . to_string ( ) ) ,
1037
+ host => host,
1038
+ } ;
1014
1039
Ok ( ( host, remaining) )
1015
1040
}
1016
1041
0 commit comments