@@ -9,18 +9,51 @@ const os = require('os');
99const MAX_FIELD_SIZE = 20 * 1024 ; // 20KB
1010/** @see doc: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html */
1111const MAX_KEY_SIZE = 1024 ;
12+ const POST_OBJECT_OPTIONAL_FIELDS = [
13+ 'acl' ,
14+ 'awsaccesskeyid' ,
15+ 'bucket' ,
16+ 'cache-control' ,
17+ 'content-disposition' ,
18+ 'content-encoding' ,
19+ 'content-type' ,
20+ 'expires' ,
21+ 'policy' ,
22+ 'redirect' ,
23+ 'tagging' ,
24+ 'success_action_redirect' ,
25+ 'success_action_status' ,
26+ 'x-amz-meta-' ,
27+ 'x-amz-storage-class' ,
28+ 'x-amz-security-token' ,
29+ 'x-amz-signgnature' ,
30+ 'x-amz-website-redirect-location' ,
31+ ] ;
1232
1333async function authenticateRequest ( request , requestContexts , log ) {
1434 return new Promise ( resolve => {
1535 // TODO RING-45960 remove ignore for POST object here
36+ // if (err) {
37+ // log.trace('authentication error', { error: err });
38+ // return reject(err);
39+ // }
1640 auth . server . doAuth ( request , log , ( err , userInfo , authorizationResults , streamingV4Params ) =>
1741 resolve ( { userInfo, authorizationResults, streamingV4Params } ) , 's3' , requestContexts ) ;
1842 } ) ;
1943}
2044
2145async function parseFormData ( request , response , requestContexts , log ) {
2246 /* eslint-disable no-param-reassign */
23- const formDataParser = busboy ( { headers : request . headers } ) ;
47+ let formDataParser ;
48+ try {
49+ formDataParser = busboy ( { headers : request . headers } ) ;
50+ } catch ( err ) {
51+ log . trace ( 'Error creating form data parser' , { error : err . toString ( ) } ) ;
52+ return Promise . reject ( errors . PreconditionFailed
53+ . customizeDescription ( 'Bucket POST must be of the enclosure-type multipart/form-data' ) ) ;
54+ }
55+
56+ // formDataParser = busboy({ headers: request.headers });
2457 writeContinue ( request , response ) ;
2558
2659 return new Promise ( ( resolve , reject ) => {
@@ -37,20 +70,28 @@ async function parseFormData(request, response, requestContexts, log) {
3770 const formParserFinishedPromise = new Promise ( ( res ) => { formParserFinishedPromiseResolve = res ; } ) ;
3871
3972 formDataParser . on ( 'field' , ( fieldname , val ) => {
73+ // Check if we have exceeded the max size allowed for all fields
4074 totalFieldSize += Buffer . byteLength ( val , 'utf8' ) ;
4175 if ( totalFieldSize > MAX_FIELD_SIZE ) {
4276 return reject ( errors . MaxPostPreDataLengthExceeded ) ;
4377 }
78+
79+ // validate the fieldname
4480 const lowerFieldname = fieldname . toLowerCase ( ) ;
81+ // special handling for key field
4582 if ( lowerFieldname === 'key' ) {
4683 if ( val . length > MAX_KEY_SIZE ) {
4784 return reject ( errors . KeyTooLong ) ;
4885 } else if ( val . length === 0 ) {
4986 return reject ( errors . InvalidArgument
5087 . customizeDescription ( 'User key must have a length greater than 0.' ) ) ;
5188 }
89+ request . formData [ lowerFieldname ] = val ;
90+ }
91+ // add only the recognized fields to the formData object
92+ if ( POST_OBJECT_OPTIONAL_FIELDS . some ( field => lowerFieldname . startsWith ( field ) ) ) {
93+ request . formData [ lowerFieldname ] = val ;
5294 }
53- request . formData [ lowerFieldname ] = val ;
5495 return undefined ;
5596 } ) ;
5697
@@ -140,11 +181,6 @@ function getFileStat(filePath, log) {
140181}
141182
142183async function processPostForm ( request , response , requestContexts , log , callback ) {
143- if ( ! request . headers || ! request . headers [ 'content-type' ] . includes ( 'multipart/form-data' ) ) {
144- const contentTypeError = errors . PreconditionFailed
145- . customizeDescription ( 'Bucket POST must be of the enclosure-type multipart/form-data' ) ;
146- return process . nextTick ( callback , contentTypeError ) ;
147- }
148184 try {
149185 const { userInfo, authorizationResults, streamingV4Params } =
150186 await parseFormData ( request , response , requestContexts , log ) ;
0 commit comments