@@ -81,28 +81,105 @@ impl ReportWriter for S3Writer {
8181 mime : & Mime ,
8282 encoding_type : EncodingType ,
8383 ) -> Fallible < ( ) > {
84- let mut request = self
85- . client
86- . put_object ( )
87- . body ( aws_smithy_http:: byte_stream:: ByteStream :: from ( s) )
88- . acl ( aws_sdk_s3:: model:: ObjectCannedAcl :: PublicRead )
89- . key ( format ! (
90- "{}/{}" ,
91- self . prefix,
92- path. as_ref( ) . to_str( ) . unwrap( )
93- ) )
94- . content_type ( mime. to_string ( ) )
95- . bucket ( self . bucket . clone ( ) ) ;
96- match encoding_type {
97- EncodingType :: Plain => { }
98- EncodingType :: Gzip => {
99- 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+ }
100102 }
101- }
102- match self . runtime . block_on ( request. send ( ) ) {
103- Ok ( _) => Ok ( ( ) ) ,
104- Err ( e) => {
105- 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+ }
106183 }
107184 }
108185 }
0 commit comments