@@ -99,7 +99,7 @@ pub struct NewCrate<'a> {
99
99
100
100
impl < ' a > NewCrate < ' a > {
101
101
pub fn create_or_update (
102
- mut self ,
102
+ self ,
103
103
conn : & PgConnection ,
104
104
uploader : i32 ,
105
105
rate_limit : Option < & PublishRateLimit > ,
@@ -128,31 +128,25 @@ impl<'a> NewCrate<'a> {
128
128
} )
129
129
}
130
130
131
- fn validate ( & mut self ) -> CargoResult < ( ) > {
131
+ fn validate ( & self ) -> CargoResult < ( ) > {
132
132
fn validate_url ( url : Option < & str > , field : & str ) -> CargoResult < ( ) > {
133
133
let url = match url {
134
134
Some ( s) => s,
135
135
None => return Ok ( ( ) ) ,
136
136
} ;
137
- let url = Url :: parse ( url)
138
- . map_err ( |_| human ( & format_args ! ( "`{}` is not a valid url: `{}`" , field, url) ) ) ?;
139
- match & url. scheme ( ) [ ..] {
140
- "http" | "https" => { }
141
- s => {
142
- return Err ( human ( & format_args ! (
143
- "`{}` has an invalid url \
144
- scheme: `{}`",
145
- field, s
146
- ) ) ) ;
147
- }
148
- }
149
- if url. cannot_be_a_base ( ) {
137
+
138
+ // Manually check the string, as `Url::parse` may normalize relative URLs
139
+ // making it difficult to ensure that both slashes are present.
140
+ if !url. starts_with ( "http://" ) && !url. starts_with ( "https://" ) {
150
141
return Err ( human ( & format_args ! (
151
- "`{}` must have relative scheme \
152
- data: {}",
142
+ "URL for field `{}` must begin with http:// or https:// (url: {})" ,
153
143
field, url
154
144
) ) ) ;
155
145
}
146
+
147
+ // Ensure the entire URL parses as well
148
+ Url :: parse ( url)
149
+ . map_err ( |_| human ( & format_args ! ( "`{}` is not a valid url: `{}`" , field, url) ) ) ?;
156
150
Ok ( ( ) )
157
151
}
158
152
@@ -524,7 +518,21 @@ sql_function!(fn to_char(a: Date, b: Text) -> Text);
524
518
525
519
#[ cfg( test) ]
526
520
mod tests {
527
- use crate :: models:: Crate ;
521
+ use crate :: models:: { Crate , NewCrate } ;
522
+
523
+ #[ test]
524
+ fn deny_relative_urls ( ) {
525
+ let krate = NewCrate {
526
+ name : "name" ,
527
+ description : None ,
528
+ homepage : Some ( "https:/example.com/home" ) ,
529
+ documentation : None ,
530
+ readme : None ,
531
+ repository : None ,
532
+ max_upload_size : None ,
533
+ } ;
534
+ assert ! ( krate. validate( ) . is_err( ) ) ;
535
+ }
528
536
529
537
#[ test]
530
538
fn documentation_blocked_no_url_provided ( ) {
0 commit comments