@@ -52,6 +52,7 @@ const objectGetRetention = require('./objectGetRetention');
5252const objectGetTagging = require ( './objectGetTagging' ) ;
5353const objectHead = require ( './objectHead' ) ;
5454const objectPut = require ( './objectPut' ) ;
55+ const objectPost = require ( './objectPost' ) ;
5556const objectPutACL = require ( './objectPutACL' ) ;
5657const objectPutLegalHold = require ( './objectPutLegalHold' ) ;
5758const objectPutTagging = require ( './objectPutTagging' ) ;
@@ -68,6 +69,10 @@ const validateQueryAndHeaders = require('../utilities/validateQueryAndHeaders');
6869const parseCopySource = require ( './apiUtils/object/parseCopySource' ) ;
6970const { tagConditionKeyAuth } = require ( './apiUtils/authorization/tagConditionKeys' ) ;
7071const checkHttpHeadersSize = require ( './apiUtils/object/checkHttpHeadersSize' ) ;
72+ const { decryptToken } = require ( './apiUtils/object/continueToken' ) ;
73+ const busboy = require ( 'busboy' ) ;
74+
75+
7176
7277const monitoringMap = policies . actionMaps . actionMonitoringMapS3 ;
7378
@@ -184,8 +189,98 @@ const api = {
184189 }
185190 return { returnTagCount, isImplicitDeny } ;
186191 }
192+ let bb ;
193+ let fileEventData = null ;
194+
195+ if ( apiMethod === 'objectPost' && request . headers [ 'content-type' ] . includes ( 'multipart/form-data' ) ) {
196+ bb = busboy ( { headers : request . headers } ) ;
197+ }
187198
188199 return async . waterfall ( [
200+ next => {
201+ if ( apiMethod === 'objectPut' || apiMethod === 'objectPutPart' ) {
202+ return next ( null ) ;
203+ }
204+ if ( apiMethod === 'objectPost' && request . headers [ 'content-type' ] . includes ( 'multipart/form-data' ) ) {
205+ writeContinue ( request , response ) ;
206+
207+ let algoOK = false ;
208+ let credOK = false ;
209+ let dateOK = false ;
210+ let sigOK = false ;
211+ let policyOK = false ;
212+ request . formData = { } ;
213+ bb . on ( 'field' , ( fieldname , val ) => {
214+ request . formData [ fieldname ] = val ;
215+ if ( request . formData . Policy ) {
216+ request . formData . decryptedPolicy = JSON . parse ( decryptToken ( request . formData . Policy ) ) ;
217+ }
218+
219+ // TODO - put content type field for file in request
220+ if ( fieldname === 'X-Amz-Algorithm' ) {
221+ algoOK = true ;
222+ }
223+ if ( fieldname === 'X-Amz-Credential' ) {
224+ credOK = true ;
225+ }
226+ if ( fieldname === 'X-Amz-Date' ) {
227+ dateOK = true ;
228+ }
229+ if ( fieldname === 'X-Amz-Signature' ) {
230+ sigOK = true ;
231+ }
232+ if ( fieldname === 'Policy' ) {
233+ policyOK = true ;
234+ }
235+ } ) ;
236+
237+ bb . on ( 'file' , ( fieldname , file , filename , encoding , mimetype ) => {
238+ fileEventData = { fieldname, file, filename, encoding, mimetype } ;
239+ if ( algoOK && credOK && dateOK && sigOK && policyOK ) {
240+ return next ( null ) ;
241+ }
242+ } ) ;
243+
244+ bb . on ( 'finish' , ( ) => {
245+ // if authorization field is not found, return error
246+ if ( ! algoOK || ! credOK || ! dateOK || ! sigOK || ! policyOK ) {
247+ return next ( errors . InvalidRequest ) ;
248+ }
249+ } ) ;
250+ request . pipe ( bb ) ;
251+ } else {
252+ // issue 100 Continue to the client
253+ writeContinue ( request , response ) ;
254+ const MAX_POST_LENGTH = request . method === 'POST' ?
255+ 1024 * 1024 : 1024 * 1024 / 2 ; // 1 MB or 512 KB
256+ const post = [ ] ;
257+ let postLength = 0 ;
258+ request . on ( 'data' , chunk => {
259+ postLength += chunk . length ;
260+ // Sanity check on post length
261+ if ( postLength <= MAX_POST_LENGTH ) {
262+ post . push ( chunk ) ;
263+ }
264+ } ) ;
265+
266+ request . on ( 'error' , err => {
267+ log . trace ( 'error receiving request' , {
268+ error : err ,
269+ } ) ;
270+ return next ( errors . InternalError ) ;
271+ } ) ;
272+
273+ request . on ( 'end' , ( ) => {
274+ if ( postLength > MAX_POST_LENGTH ) {
275+ log . error ( 'body length is too long for request type' ,
276+ { postLength } ) ;
277+ return next ( errors . InvalidRequest ) ;
278+ }
279+ return next ( null ) ;
280+ } ) ;
281+ }
282+ return undefined ;
283+ } ,
189284 next => auth . server . doAuth (
190285 request , log , ( err , userInfo , authorizationResults , streamingV4Params ) => {
191286 if ( err ) {
@@ -200,41 +295,7 @@ const api = {
200295 authNames . userName = userInfo . getIAMdisplayName ( ) ;
201296 }
202297 log . addDefaultFields ( authNames ) ;
203- if ( apiMethod === 'objectPut' || apiMethod === 'objectPutPart' ) {
204- return next ( null , userInfo , authorizationResults , streamingV4Params ) ;
205- }
206- // issue 100 Continue to the client
207- writeContinue ( request , response ) ;
208- const MAX_POST_LENGTH = request . method === 'POST' ?
209- 1024 * 1024 : 1024 * 1024 / 2 ; // 1 MB or 512 KB
210- const post = [ ] ;
211- let postLength = 0 ;
212- request . on ( 'data' , chunk => {
213- postLength += chunk . length ;
214- // Sanity check on post length
215- if ( postLength <= MAX_POST_LENGTH ) {
216- post . push ( chunk ) ;
217- }
218- } ) ;
219-
220- request . on ( 'error' , err => {
221- log . trace ( 'error receiving request' , {
222- error : err ,
223- } ) ;
224- return next ( errors . InternalError ) ;
225- } ) ;
226-
227- request . on ( 'end' , ( ) => {
228- if ( postLength > MAX_POST_LENGTH ) {
229- log . error ( 'body length is too long for request type' ,
230- { postLength } ) ;
231- return next ( errors . InvalidRequest ) ;
232- }
233- // Convert array of post buffers into one string
234- request . post = Buffer . concat ( post , postLength ) . toString ( ) ;
235- return next ( null , userInfo , authorizationResults , streamingV4Params ) ;
236- } ) ;
237- return undefined ;
298+ return next ( null , userInfo , authorizationResults , streamingV4Params ) ;
238299 } ,
239300 // Tag condition keys require information from CloudServer for evaluation
240301 ( userInfo , authorizationResults , streamingV4Params , next ) => tagConditionKeyAuth (
@@ -244,6 +305,10 @@ const api = {
244305 apiMethod ,
245306 log ,
246307 ( err , authResultsWithTags ) => {
308+ // TODO CLDSRV-527 remove ignore for POST object here
309+ if ( apiMethod === 'objectPost' ) {
310+ return next ( null , userInfo , authorizationResults , streamingV4Params ) ;
311+ }
247312 if ( err ) {
248313 log . trace ( 'tag authentication error' , { error : err } ) ;
249314 return next ( err ) ;
@@ -271,6 +336,12 @@ const api = {
271336 return acc ;
272337 } , { } ) ;
273338 }
339+ if ( apiMethod === 'objectPost' && fileEventData ) {
340+ request . _response = response ;
341+ request . file = fileEventData . file ;
342+ return this [ apiMethod ] ( userInfo , request , streamingV4Params ,
343+ log , callback , authorizationResults ) ;
344+ }
274345 if ( apiMethod === 'objectPut' || apiMethod === 'objectPutPart' ) {
275346 request . _response = response ;
276347 return this [ apiMethod ] ( userInfo , request , streamingV4Params ,
@@ -337,6 +408,7 @@ const api = {
337408 objectCopy,
338409 objectHead,
339410 objectPut,
411+ objectPost,
340412 objectPutACL,
341413 objectPutLegalHold,
342414 objectPutTagging,
0 commit comments