@@ -5,13 +5,21 @@ use bstr::{BStr, BString, ByteSlice};
5
5
#[ derive( Debug , thiserror:: Error ) ]
6
6
#[ allow( missing_docs) ]
7
7
pub enum Error {
8
- #[ error( "Could not decode URL as UTF8" ) ]
9
- Utf8 ( #[ from] std:: str:: Utf8Error ) ,
10
- #[ error( transparent) ]
11
- Url ( #[ from] url:: ParseError ) ,
12
- #[ error( "file URLs require an absolute or relative path to the repository" ) ]
13
- MissingRepositoryPath ,
14
- #[ error( "Relative URLs are not permitted: {url:?}" ) ]
8
+ #[ error( "{} \" {url}\" is not valid UTF-8" , . kind. get_error_str( ) ) ]
9
+ Utf8 {
10
+ url : BString ,
11
+ kind : UrlKind ,
12
+ source : std:: str:: Utf8Error ,
13
+ } ,
14
+ #[ error( "{} {url:?} can not be parsed as valid URL" , . kind. get_error_str( ) ) ]
15
+ Url {
16
+ url : String ,
17
+ kind : UrlKind ,
18
+ source : url:: ParseError ,
19
+ } ,
20
+ #[ error( "{} \" {url}\" does not specify a path to a repository" , . kind. get_error_str( ) ) ]
21
+ MissingRepositoryPath { url : BString , kind : UrlKind } ,
22
+ #[ error( "URL {url:?} is relative which is not allowed in this context" ) ]
15
23
RelativeUrl { url : String } ,
16
24
}
17
25
@@ -21,6 +29,27 @@ impl From<Infallible> for Error {
21
29
}
22
30
}
23
31
32
+ ///
33
+ #[ derive( Debug ) ]
34
+ pub enum UrlKind {
35
+ ///
36
+ Url ,
37
+ ///
38
+ Scp ,
39
+ ///
40
+ Local ,
41
+ }
42
+
43
+ impl UrlKind {
44
+ fn get_error_str ( & self ) -> & ' static str {
45
+ match self {
46
+ UrlKind :: Url => "URL" ,
47
+ UrlKind :: Scp => "SCP-like target" ,
48
+ UrlKind :: Local => "local path" ,
49
+ }
50
+ }
51
+ }
52
+
24
53
enum InputScheme {
25
54
Url { protocol_end : usize } ,
26
55
Scp { colon : usize } ,
@@ -61,7 +90,16 @@ pub fn parse(input: &BStr) -> Result<crate::Url, Error> {
61
90
}
62
91
63
92
fn parse_url ( input : & BStr ) -> Result < crate :: Url , Error > {
64
- let url = url:: Url :: parse ( std:: str:: from_utf8 ( input) ?) ?;
93
+ let input = std:: str:: from_utf8 ( input) . map_err ( |source| Error :: Utf8 {
94
+ url : input. to_owned ( ) ,
95
+ kind : UrlKind :: Url ,
96
+ source,
97
+ } ) ?;
98
+ let url = url:: Url :: parse ( input) . map_err ( |source| Error :: Url {
99
+ url : input. to_owned ( ) ,
100
+ kind : UrlKind :: Url ,
101
+ source,
102
+ } ) ?;
65
103
66
104
Ok ( crate :: Url {
67
105
serialize_alternative_form : false ,
@@ -79,7 +117,11 @@ fn parse_url(input: &BStr) -> Result<crate::Url, Error> {
79
117
}
80
118
81
119
fn parse_scp ( input : & BStr , colon : usize ) -> Result < crate :: Url , Error > {
82
- let input = std:: str:: from_utf8 ( input) ?;
120
+ let input = std:: str:: from_utf8 ( input) . map_err ( |source| Error :: Utf8 {
121
+ url : input. to_owned ( ) ,
122
+ kind : UrlKind :: Scp ,
123
+ source,
124
+ } ) ?;
83
125
84
126
// TODO: this incorrectly splits at IPv6 addresses, check for `[]` before splitting
85
127
let ( host, path) = input. split_at ( colon) ;
@@ -89,7 +131,11 @@ fn parse_scp(input: &BStr, colon: usize) -> Result<crate::Url, Error> {
89
131
// should never differ in any other way (ssh URLs should not contain a query or fragment part).
90
132
// To avoid the various off-by-one errors caused by the `/` characters, we keep using the path
91
133
// determined above and can therefore skip parsing it here as well.
92
- let url = url:: Url :: parse ( & format ! ( "ssh://{host}" ) ) ?;
134
+ let url = url:: Url :: parse ( & format ! ( "ssh://{host}" ) ) . map_err ( |source| Error :: Url {
135
+ url : input. to_owned ( ) ,
136
+ kind : UrlKind :: Scp ,
137
+ source,
138
+ } ) ?;
93
139
94
140
Ok ( crate :: Url {
95
141
serialize_alternative_form : true ,
0 commit comments