@@ -46,7 +46,11 @@ impl FromStr for S3Prefix {
4646
4747 Ok ( S3Prefix {
4848 bucket,
49- prefix : parsed. path ( ) [ 1 ..] . into ( ) ,
49+ prefix : parsed
50+ . path ( )
51+ . get ( 1 ..)
52+ . map ( PathBuf :: from)
53+ . unwrap_or_default ( ) ,
5054 } )
5155 }
5256}
@@ -77,28 +81,105 @@ impl ReportWriter for S3Writer {
7781 mime : & Mime ,
7882 encoding_type : EncodingType ,
7983 ) -> Fallible < ( ) > {
80- let mut request = self
81- . client
82- . put_object ( )
83- . body ( aws_smithy_http:: byte_stream:: ByteStream :: from ( s) )
84- . acl ( aws_sdk_s3:: model:: ObjectCannedAcl :: PublicRead )
85- . key ( format ! (
86- "{}/{}" ,
87- self . prefix,
88- path. as_ref( ) . to_str( ) . unwrap( )
89- ) )
90- . content_type ( mime. to_string ( ) )
91- . bucket ( self . bucket . clone ( ) ) ;
92- match encoding_type {
93- EncodingType :: Plain => { }
94- EncodingType :: Gzip => {
95- request = request. content_encoding ( "gzip" ) ;
84+ // At least 50 MB, then use a multipart upload...
85+ if s. len ( ) >= 50 * 1024 * 1024 {
86+ let mut request = self
87+ . client
88+ . create_multipart_upload ( )
89+ . acl ( aws_sdk_s3:: model:: ObjectCannedAcl :: PublicRead )
90+ . key ( format ! (
91+ "{}/{}" ,
92+ self . prefix,
93+ path. as_ref( ) . to_str( ) . unwrap( )
94+ ) )
95+ . content_type ( mime. to_string ( ) )
96+ . bucket ( self . bucket . clone ( ) ) ;
97+ match encoding_type {
98+ EncodingType :: Plain => { }
99+ EncodingType :: Gzip => {
100+ request = request. content_encoding ( "gzip" ) ;
101+ }
96102 }
97- }
98- match self . runtime . block_on ( request. send ( ) ) {
99- Ok ( _) => Ok ( ( ) ) ,
100- Err ( e) => {
101- failure:: bail!( "Failed to upload to {:?}: {:?}" , path. as_ref( ) , e) ;
103+ let upload = match self . runtime . block_on ( request. send ( ) ) {
104+ Ok ( u) => u,
105+ Err ( e) => {
106+ failure:: bail!( "Failed to upload to {:?}: {:?}" , path. as_ref( ) , e) ;
107+ }
108+ } ;
109+
110+ let chunk_size = 20 * 1024 * 1024 ;
111+ let bytes = bytes_1:: Bytes :: from ( s) ;
112+ let mut part = 1 ;
113+ let mut start = 0 ;
114+ let mut parts = aws_sdk_s3:: model:: CompletedMultipartUpload :: builder ( ) ;
115+ while start < bytes. len ( ) {
116+ let chunk = bytes. slice ( start..std:: cmp:: min ( start + chunk_size, bytes. len ( ) ) ) ;
117+
118+ let request = self
119+ . client
120+ . upload_part ( )
121+ . part_number ( part)
122+ . body ( chunk. into ( ) )
123+ . upload_id ( upload. upload_id ( ) . unwrap ( ) )
124+ . key ( upload. key ( ) . unwrap ( ) )
125+ . bucket ( self . bucket . clone ( ) ) ;
126+ match self . runtime . block_on ( request. send ( ) ) {
127+ Ok ( p) => {
128+ parts = parts. parts (
129+ aws_sdk_s3:: model:: CompletedPart :: builder ( )
130+ . e_tag ( p. e_tag . clone ( ) . unwrap ( ) )
131+ . part_number ( part)
132+ . build ( ) ,
133+ )
134+ }
135+ Err ( e) => {
136+ failure:: bail!( "Failed to upload to {:?}: {:?}" , path. as_ref( ) , e) ;
137+ }
138+ } ;
139+
140+ start += chunk_size;
141+ part += 1 ;
142+ }
143+
144+ let request = self
145+ . client
146+ . complete_multipart_upload ( )
147+ . multipart_upload ( parts. build ( ) )
148+ . upload_id ( upload. upload_id ( ) . unwrap ( ) )
149+ . key ( upload. key ( ) . unwrap ( ) )
150+ . bucket ( self . bucket . clone ( ) ) ;
151+ match self . runtime . block_on ( request. send ( ) ) {
152+ Ok ( _) => ( ) ,
153+ Err ( e) => {
154+ failure:: bail!( "Failed to upload to {:?}: {:?}" , path. as_ref( ) , e) ;
155+ }
156+ } ;
157+
158+ Ok ( ( ) )
159+ } else {
160+ let mut request = self
161+ . client
162+ . put_object ( )
163+ . body ( aws_smithy_http:: byte_stream:: ByteStream :: from ( s) )
164+ . acl ( aws_sdk_s3:: model:: ObjectCannedAcl :: PublicRead )
165+ . key ( format ! (
166+ "{}/{}" ,
167+ self . prefix,
168+ path. as_ref( ) . to_str( ) . unwrap( )
169+ ) )
170+ . content_type ( mime. to_string ( ) )
171+ . bucket ( self . bucket . clone ( ) ) ;
172+ match encoding_type {
173+ EncodingType :: Plain => { }
174+ EncodingType :: Gzip => {
175+ request = request. content_encoding ( "gzip" ) ;
176+ }
177+ }
178+ match self . runtime . block_on ( request. send ( ) ) {
179+ Ok ( _) => Ok ( ( ) ) ,
180+ Err ( e) => {
181+ failure:: bail!( "Failed to upload to {:?}: {:?}" , path. as_ref( ) , e) ;
182+ }
102183 }
103184 }
104185 }
0 commit comments