@@ -21,7 +21,7 @@ use http::request::Parts;
21
21
use http:: StatusCode ;
22
22
use sha2:: { Digest , Sha256 } ;
23
23
use std:: collections:: HashMap ;
24
- use tokio:: io:: AsyncReadExt ;
24
+ use tokio:: io:: { AsyncRead , AsyncReadExt } ;
25
25
use tokio_util:: io:: StreamReader ;
26
26
use url:: Url ;
27
27
@@ -69,36 +69,7 @@ pub async fn publish(app: AppState, req: Parts, body: Body) -> AppResult<Json<Go
69
69
// .crate tarball file
70
70
71
71
const MAX_JSON_LENGTH : u32 = 1024 * 1024 ; // 1 MB
72
-
73
- let json_len = reader. read_u32_le ( ) . await . map_err ( |e| {
74
- if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof {
75
- bad_request ( "invalid metadata length" )
76
- } else {
77
- e. into ( )
78
- }
79
- } ) ?;
80
-
81
- if json_len > MAX_JSON_LENGTH {
82
- return Err ( custom (
83
- StatusCode :: PAYLOAD_TOO_LARGE ,
84
- "JSON metadata blob too large" ,
85
- ) ) ;
86
- }
87
-
88
- let mut json_bytes = vec ! [ 0 ; json_len as usize ] ;
89
- reader. read_exact ( & mut json_bytes) . await . map_err ( |e| {
90
- if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof {
91
- let message = format ! ( "invalid metadata length for remaining payload: {json_len}" ) ;
92
- bad_request ( message)
93
- } else {
94
- e. into ( )
95
- }
96
- } ) ?;
97
-
98
- let metadata: PublishMetadata = serde_json:: from_slice ( & json_bytes)
99
- . map_err ( |e| bad_request ( format_args ! ( "invalid upload request: {e}" ) ) ) ?;
100
-
101
- drop ( json_bytes) ;
72
+ let metadata = read_json_metadata ( & mut reader, MAX_JSON_LENGTH ) . await ?;
102
73
103
74
Crate :: validate_crate_name ( "crate" , & metadata. name ) . map_err ( bad_request) ?;
104
75
@@ -631,6 +602,37 @@ async fn count_versions_published_today(
631
602
. await
632
603
}
633
604
605
+ async fn read_json_metadata < R : AsyncRead + Unpin > (
606
+ reader : & mut R ,
607
+ max_length : u32 ,
608
+ ) -> Result < PublishMetadata , BoxedAppError > {
609
+ let json_len = reader. read_u32_le ( ) . await . map_err ( |e| {
610
+ if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof {
611
+ bad_request ( "invalid metadata length" )
612
+ } else {
613
+ e. into ( )
614
+ }
615
+ } ) ?;
616
+
617
+ if json_len > max_length {
618
+ let message = "JSON metadata blob too large" ;
619
+ return Err ( custom ( StatusCode :: PAYLOAD_TOO_LARGE , message) ) ;
620
+ }
621
+
622
+ let mut json_bytes = vec ! [ 0 ; json_len as usize ] ;
623
+ reader. read_exact ( & mut json_bytes) . await . map_err ( |e| {
624
+ if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof {
625
+ let message = format ! ( "invalid metadata length for remaining payload: {json_len}" ) ;
626
+ bad_request ( message)
627
+ } else {
628
+ e. into ( )
629
+ }
630
+ } ) ?;
631
+
632
+ serde_json:: from_slice ( & json_bytes)
633
+ . map_err ( |e| bad_request ( format_args ! ( "invalid upload request: {e}" ) ) )
634
+ }
635
+
634
636
async fn is_reserved_name ( name : & str , conn : & mut AsyncPgConnection ) -> QueryResult < bool > {
635
637
select ( exists ( reserved_crate_names:: table. filter (
636
638
canon_crate_name ( reserved_crate_names:: name) . eq ( canon_crate_name ( name) ) ,
0 commit comments