@@ -4,7 +4,7 @@ use crate::{
4
4
schema:: { crates, readme_renderings, versions} ,
5
5
uploaders:: Uploader ,
6
6
} ;
7
- use std:: { io :: Read , path :: Path , sync:: Arc , thread} ;
7
+ use std:: { collections :: HashMap , ffi :: OsString , io :: Read , sync:: Arc , thread} ;
8
8
9
9
use cargo_registry_markdown:: text_to_html;
10
10
use chrono:: { TimeZone , Utc } ;
@@ -196,16 +196,28 @@ fn get_readme(
196
196
render_pkg_readme ( archive, & pkg_name)
197
197
}
198
198
199
- fn render_pkg_readme < R : Read > ( mut archive : Archive < R > , pkg_name : & str ) -> Option < String > {
200
- let mut entries = archive
199
+ fn render_pkg_readme < R : Read > ( mut pkg : Archive < R > , pkg_name : & str ) -> Option < String > {
200
+ // Pulls the entire archive into memory - since we need to access files
201
+ // within the archive potentially out of order (first Cargo.toml, then README)
202
+ let entries: HashMap < _ , _ > = pkg
201
203
. entries ( )
202
- . unwrap_or_else ( |_| panic ! ( "[{}] Invalid tar archive entries" , pkg_name) ) ;
204
+ . unwrap_or_else ( |_| panic ! ( "[{}] Invalid tar archive entries" , pkg_name) )
205
+ . filter_map ( |e| {
206
+ let mut file = e. ok ( ) ?;
207
+ let path = file. path ( ) . ok ( ) ?. as_os_str ( ) . to_owned ( ) ;
208
+ let mut contents = String :: new ( ) ;
209
+ file. read_to_string ( & mut contents)
210
+ . unwrap_or_else ( |_| panic ! ( "[{}] Couldn't read file contents" , pkg_name) ) ;
211
+ Some ( ( path, contents) )
212
+ } )
213
+ . collect ( ) ;
203
214
204
215
let manifest: Manifest = {
205
216
let path = format ! ( "{}/Cargo.toml" , pkg_name) ;
206
- let contents = find_file_by_path ( & mut entries, Path :: new ( & path) , pkg_name)
217
+ let contents = entries
218
+ . get ( & OsString :: from ( path) )
207
219
. unwrap_or_else ( || panic ! ( "[{}] couldn't open file: Cargo.toml" , pkg_name) ) ;
208
- toml:: from_str ( & contents)
220
+ toml:: from_str ( contents)
209
221
. unwrap_or_else ( |_| panic ! ( "[{}] Syntax error in manifest file" , pkg_name) )
210
222
} ;
211
223
@@ -216,9 +228,9 @@ fn render_pkg_readme<R: Read>(mut archive: Archive<R>, pkg_name: &str) -> Option
216
228
. clone ( )
217
229
. unwrap_or_else ( || "README.md" . into ( ) ) ;
218
230
let path = format ! ( "{}/{}" , pkg_name, readme_path) ;
219
- let contents = find_file_by_path ( & mut entries , Path :: new ( & path) , pkg_name ) ?;
231
+ let contents = entries . get ( & OsString :: from ( path) ) ?;
220
232
text_to_html (
221
- & contents,
233
+ contents,
222
234
& readme_path,
223
235
manifest. package . repository . as_deref ( ) ,
224
236
)
@@ -237,31 +249,6 @@ fn render_pkg_readme<R: Read>(mut archive: Archive<R>, pkg_name: &str) -> Option
237
249
}
238
250
}
239
251
240
- /// Search an entry by its path in a Tar archive.
241
- fn find_file_by_path < R : Read > (
242
- entries : & mut tar:: Entries < ' _ , R > ,
243
- path : & Path ,
244
- pkg_name : & str ,
245
- ) -> Option < String > {
246
- let mut file = entries
247
- . find ( |entry| match * entry {
248
- Err ( _) => false ,
249
- Ok ( ref file) => {
250
- let filepath = match file. path ( ) {
251
- Ok ( p) => p,
252
- Err ( _) => return false ,
253
- } ;
254
- filepath == path
255
- }
256
- } ) ?
257
- . unwrap_or_else ( |_| panic ! ( "[{}] file is not present: {}" , pkg_name, path. display( ) ) ) ;
258
-
259
- let mut contents = String :: new ( ) ;
260
- file. read_to_string ( & mut contents)
261
- . unwrap_or_else ( |_| panic ! ( "[{}] Couldn't read file contents" , pkg_name) ) ;
262
- Some ( contents)
263
- }
264
-
265
252
#[ cfg( test) ]
266
253
mod tests {
267
254
use std:: io:: Write ;
@@ -325,6 +312,24 @@ readme = "README.md"
325
312
assert ! ( result. contains( "readme" ) )
326
313
}
327
314
315
+ #[ test]
316
+ fn test_render_pkg_readme_tar_order_backward ( ) {
317
+ let mut pkg = tar:: Builder :: new ( vec ! [ ] ) ;
318
+ add_file ( & mut pkg, "foo-0.0.1/README.md" , b"readme" ) ;
319
+ add_file (
320
+ & mut pkg,
321
+ "foo-0.0.1/Cargo.toml" ,
322
+ br#"
323
+ [package]
324
+ readme = "README.md"
325
+ "# ,
326
+ ) ;
327
+ let serialized_archive = pkg. into_inner ( ) . unwrap ( ) ;
328
+ let result =
329
+ render_pkg_readme ( tar:: Archive :: new ( & * serialized_archive) , "foo-0.0.1" ) . unwrap ( ) ;
330
+ assert ! ( result. contains( "readme" ) )
331
+ }
332
+
328
333
#[ test]
329
334
fn test_render_pkg_readme_w_link ( ) {
330
335
let mut pkg = tar:: Builder :: new ( vec ! [ ] ) ;
0 commit comments