Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boundary not being returned #9

Open
jbrosan opened this issue Sep 27, 2017 · 3 comments
Open

Boundary not being returned #9

jbrosan opened this issue Sep 27, 2017 · 3 comments

Comments

@jbrosan
Copy link

jbrosan commented Sep 27, 2017

Hi,

I am currently experiencing an issue with uploading a file using multipart/form-data to AWS. I've setup the API Gateway as you have it in your video and added my lambda.

It seems that the getBoundary method is not returning a boundary and when I attempt to parse into parts that its just not working. The parts array is empty.

Any ideas or suggestions on what could be happening and how to resolve it would be most appreciated.

Thanks ,
John

LAMBDA


'use strict';

const AWS = require('aws-sdk');
const multipart = require('parse-multipart');


module.exports.fileUpload = (event, context, callback) => {

  AWS.config.update({
    accessKeyId: process.env.PUBLIC_AWS_KEY,
    secretAccessKey: process.env.SECRET_AWS_KEY
  });

  try {

    let bodyBuffer = new Buffer(event['body-json'].toString(), 'base64');
    console.log('BUFFER: ', bodyBuffer.toString());

    let boundary = multipart.getBoundary(event.params.header['content-type']);
    console.log('BOUNDARY: ', boundary);

    let parts = multipart.Parse(bodyBuffer, boundary);
    console.log('PARTS: ', parts);
    console.log('PARTS LEN: ', parts.length);

    const response = {
      statusCode: 200,
      headers: {
        "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
        "Access-Control-Allow-Credentials" : false // Required for cookies, authorization headers with HTTPS
      },
      body: JSON.stringify({
        message: 'File upload com1plete'
      }),
    };
    callback(null, response);

  } catch (err) {
    console.log("ERROR: ", err);
    const response = {
      statusCode: 500,
      headers: {
        "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
        "Access-Control-Allow-Credentials" : false // Required for cookies, authorization headers with HTTPS
      },
      body: JSON.stringify({
        message: 'File upload ERR: ' + err.toString()
      }),
    };
    callback(response, null);
  }
  
};

The event

Event: { 'body-json': 'LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5cWlxRUxCQ0lpUlJhU1hpTQ0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmaWxlIjsgZmlsZW5hbWU9ImpvaG5sZWRlczk4YnNhbXBsZS5jc3YiDQpDb250ZW50LVR5cGU6IHRleHQvY3N2DQoNCkxFREVTMTk5OEJbXQpJTlZPSUNFX0RBVEV8SU5WT0lDRV9OVU1CRVJ8Q0xJRU5UX0lEfExBV19GSVJNX01BVFRFUl9JRHxJTlZPSUNFX1RPVEFMfEJJTExJTkdfU1RBUlRfREFURXxCSUxMSU5HX0VORF9EQVRFfElOVk9JQ0VfREVTQ1JJUFRJT058TElORV9JVEVNX05VTUJFUnxFWFAvRkVFL0lOVl9BREpfVFlQRXxMSU5FX0lURU1fTlVNQkVSX09GX1VOSVRTfExJTkVfSVRFTV9BREpVU1RNRU5UX0FNT1VOVHxMSU5FX0lURU1fVE9UQUx8TElORV9JVEVNX0RBVEV8TElORV9JVEVNX1RBU0tfQ09ERXxMSU5FX0lURU1fRVhQRU5TRV9DT0RFfExJTkVfSVRFTV9BQ1RJVklUWV9DT0RFfFRJTUVLRUVQRVJfSUR8TElORV9JVEVNX0RFU0NSSVBUSU9OfExBV19GSVJNX0lEfExJTkVfSVRFTV9VTklUX0NPU1R8VElNRUtFRVBFUl9OQU1FfFRJTUVLRUVQRVJfQ0xBU1NJRklDQVRJT058Q0xJRU5UX01BVFRFUl9JRAoxOTk5MDIyNXw5NjU0MnwwMDcxMXwwNTI4fDE2ODQuNDV8MTk5OTAxMDF8MTk5OTAxMzF8Rm9yIHNlcnZpY2VzIHJlbmRlcmVkfDF8RnwyLjAwfC03MHw2MzB8MTk5OTAxMTV8TDUxMHx8QTEwMnwyMjU0N3xSZXNlYXJjaCBBdHRvcm5leeKAmXMgZmVlcywgU2V0IG9mZiBjbGFpbXwyNC02NDM3MzgxfDM1MHxBcm5zbGV5LCBSb2JlcnR8UEFSVE5SfDQyMy05ODdbXQoxOTk5MDIyNXw5NjU0MnwwMDcxMXwwNTI4fDE2ODQuNDV8MTk5OTAxMDF8MTk5OTAxMzF8Rm9yIHNlcnZpY2VzIHJlbmRlcmVkfDJ8RnwyLjAwfDB8NzAwfDE5OTkwMTE1fEw1MTB8fEExMDJ8MjI1NDd8UmVzZWFyY2ggYXR0b3JuZXkncyBmZWVzLCBUcmlhbCBwbGVhZGluZ3wyNC02NDM3MzgxfDM1MHxBcm5zbGV5LCBSb2JlcnR8UEFSVE5SfDQyMy05ODdbXQoxOTk5MDIyNXw5NjU0MnwwMDcxMXwwNTI4fDE2ODQuNDV8MTk5OTAxMDF8MTk5OTAxMzF8Rm9yIHNlcnZpY2VzIHJlbmRlcmVkfDN8RnwwLjIwMHwwfDQwfDE5OTkwMTE2fEw1MTB8fEExMDd8NDU4NzV8VGVsZXBob25lIGNvbmZlcmVuY2Ugd2l0aCBKb2huIERvZXwyNC02NDM3MzgxfDIwMHxCZWFzdGVyLCBKb2hufEFTU09DfDQyMy05ODdbXQoxOTk5MDIyNXw5NjU0MnwwMDcxMXwwNTI4fDE2ODQuNDV8MTk5OTAxMDF8MTk5OTAxMzF8Rm9yIHNlcnZpY2VzIHJlbmRlcmVkfDR8RXwxfDB8MjQuOTV8MTk5OTAxMTd8fEUxMTF8fHxNZWFsc3wyNC02NDM3MzgxfDI0Ljk1fHx8NDIzLTk4N1tdCjE5OTkwMjI1fDk2NTQyfDAwNzExfDA1Mjh8MTY4NC40NXwxOTk5MDEwMXwxOTk5MDEzMXxGb3Igc2VydmljZXMgcmVuZGVyZWR8NXxFfDF8MHwyODkuNXwxOTk5MDExN3x8RTExMHx8fE91dC1vZl90b3duIHRyYXZlbHwyNC02NDM3MzgxfDI4OS41fHx8NDIzLTk4N1tdCjE5OTkwMjI1fDk2NTQyfDAwNzExfDEzMjZ8MTI1MHwxOTk5MDEwMXwxOTk5MDEzMXxNb250aGx5IFJldGFpbmVyfDZ8SUZ8MXwxMjUwLnwxMjUwfDE5OTkwMTMxfHx8fHxNb250aGx5IFJldGFpbmVyIEZlZXwyNC02NDM3MzgxfHx8fDQyNS05MzZbXQoyMDE2MDkzMHw5NjU1NHwwMDgxNHwwNjI4fDY4NC41MHwyMDE2MDkwMXwyMDE2MDkzMHxGb3Igc2VydmljZXMgcmVuZGVyZWR8MXxGfDMuNTB8LTMwfDY1NnwyMDE2MDExNXxMNTEwfHxBMTAyfDIyNTQ3fFJlc2VhcmNoIEF0dG9ybmV54oCZcyBmZWVzLCBTZXQgb2ZmIGNsYWltfDI0LTY0MzczODF8MzUwfEFybnNsZXksIFJvYmVydHxQQVJUTlJ8NDIzLTk4N1tdCjIwMTYwOTMwfDk2NTU0fDAwODE0fDA2Mjh8Njg0LjUwfDIwMTYwOTAxfDIwMTYwOTMwfEZvciBzZXJ2aWNlcyByZW5kZXJlZHwyfEZ8NC4wMHwwfDcwMXwyMDE2MTExNXxMNTEwfHxBMTAyfDIyNTQ3fFJlc2VhcmNoIGF0dG9ybmV5J3MgZmVlcywgVHJpYWwgcGxlYWRpbmd8MjQtNjQzNzM4MXwzNTB8QXJuc2xleSwgUm9iZXJ0fFBBUlROUnw0MjMtOTg3W10KMjAxNjA5MzB8OTY1NTR8MDA4MTR8MDYyOHw2ODQuNTB8MjAxNjA5MDF8MjAxNjA5MzB8Rm9yIHNlcnZpY2VzIHJlbmRlcmVkfDN8RnwwLjMwMHwwfDQxfDIwMTYwMzE3fEw1MTB8fEExMDd8NDU4NzV8VGVsZXBob25lIGNvbmZlcmVuY2Ugd2l0aCBKb2huIERvZXwyNC02NDM3MzgxfDIwMHxCZWFzdGVyLCBKb2hufEFTU09DfDQyMy05ODdbXQoyMDE3MTEzMHw4NjU0MnwwMDMyMnwwNjI4fDY4NC41MHwyMDE3MTEwMXwyMDE3MTEzMHxGb3Igc2VydmljZXMgcmVuZGVyZWR8NHxFfDF8MHwzNC45NXwyMDE3MDExN3x8RTExMXx8fE1lYWxzfDI0LTY0MzczODF8MjQuOTV8fHw0MjMtOTg3W10KMjAxNzExMzB8ODY1NDJ8MDAzMjJ8MDYyOHw2ODQuNTB8MjAxNzExMDF8MjAxNzExMzB8Rm9yIHNlcnZpY2VzIHJlbmRlcmVkfDV8RXwxfDB8MzAxLjV8MjAxNzAzMjF8fEUxMTB8fHxPdXQtb2ZfdG93biB0cmF2ZWx8MjQtNjQzNzM4MXwyODkuNXx8fDQyMy05ODdbXQoyMDE3MTEzMHw4NjU0MnwwMDMyMnwxNDI2fDEyNTB8MjAxNzExMDF8MjAxNzExMzB8TW9udGhseSBSZXRhaW5lcnw2fElGfDF8MTI1MC58MTI1MHwyMDE3MTAzMXx8fHx8TW9udGhseSBSZXRhaW5lciBGZWV8MjQtNjQzNzM4MXx8fHw0MjUtOTM2W10KDQotLS0tLS1XZWJLaXRGb3JtQm91bmRhcnlxaXFFTEJDSWlSUmFTWGlNLS0NCg==',
params: 
{ path: {},
querystring: {},
header: 
{ Accept: '*/*',
'accept-encoding': 'gzip, deflate, br',
'Accept-Language': 'en-US,en;q=0.8',
'CloudFront-Forwarded-Proto': 'https',
'CloudFront-Is-Desktop-Viewer': 'true',
'CloudFront-Is-Mobile-Viewer': 'false',
'CloudFront-Is-SmartTV-Viewer': 'false',
'CloudFront-Is-Tablet-Viewer': 'false',
'CloudFront-Viewer-Country': 'US',
'content-type': 'multipart/form-data',
Host: 'row9htct2d.execute-api.us-east-1.amazonaws.com',
origin: 'http://localhost:8088',
Referer: 'http://localhost:8088/fileupload',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
Via: '2.0 3ca41706981cad42d8ecaabd29f88efa.cloudfront.net (CloudFront)',
'X-Amz-Cf-Id': 'n9aypJ5g7m02dROkhxA57KOXOYQAA3sQm4VkjqmxA9XTEJvO42yj2g==',
'X-Amzn-Trace-Id': 'Root=1-59cc056f-3b0fff4e2a4dcafc6dd77544',
'X-Forwarded-For': '174.55.194.210, 205.251.250.63',
'X-Forwarded-Port': '443',
'X-Forwarded-Proto': 'https' } },
'stage-variables': {},
context: 
{ 'account-id': '',
'api-id': 'row9htct2d',
'api-key': '',
'authorizer-principal-id': '',
caller: '',
'cognito-authentication-provider': '',
'cognito-authentication-type': '',
'cognito-identity-id': '',
'cognito-identity-pool-id': '',
'http-method': 'POST',
stage: 'dev',
'source-ip': '174.55.194.210',
user: '',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
'user-arn': '',
'request-id': 'bed12d29-a3bf-11e7-bc09-dd4b4cd0dee2',
'resource-id': 'b70xn9',
'resource-path': '/api/fileupload' } }
@christiansalazar
Copy link
Contributor

christiansalazar commented Oct 4, 2017

hi, sorry for my late response. I see no boundary in your payload.

take a deep look at your "body-json" string, it is a base64 encoded payload (your "post"), this is:

"LS0tLS0tV2V...WGlNLS0NCg=="

when u decode it, you can see:

------WebKitFormBoundaryqiqELBCIiRRaSXiM
Content-Disposition: form-data; name="file"; filename="johnledes98bsample.csv"
Content-Type: text/csv

LEDES1998B[]
INVOICE_DATE|INVOICE_NUMBER|CLIENT_ID|LAW_FIRM_MATTER_ID|INVOICE_TOTAL|BILLING_START_DATE|BILLING_END_DATE|INVOICE_DESCRIPTION|LINE_ITEM_NUMBER|EXP/FEE/INV_ADJ_TYPE|LINE_ITEM_NUMBER_OF_UNITS|LINE_ITEM_ADJUSTMENT_AMOUNT|LINE_ITEM_TOTAL|LINE_ITEM_DATE|LINE_ITEM_TASK_CODE|LINE_ITEM_EXPENSE_CODE|LINE_ITEM_ACTIVITY_CODE|TIMEKEEPER_ID|LINE_ITEM_DESCRIPTION|LAW_FIRM_ID|LINE_ITEM_UNIT_COST|TIMEKEEPER_NAME|TIMEKEEPER_CLASSIFICATION|CLIENT_MATTER_ID
19990225|96542|00711|0528|1684.45|19990101|19990131|For services rendered|1|F|2.00|-70|630|19990115|L510||A102|22547|Research Attorney’s fees, Set off claim|24-6437381|350|Arnsley, Robert|PARTNR|423-987[]
19990225|96542|00711|0528|1684.45|19990101|19990131|For services rendered|2|F|2.00|0|700|19990115|L510||A102|22547|Research attorney's fees, Trial pleading|24-6437381|350|Arnsley, Robert|PARTNR|423-987[]
19990225|96542|00711|0528|1684.45|19990101|19990131|For services rendered|3|F|0.200|0|40|19990116|L510||A107|45875|Telephone conference with John Doe|24-6437381|200|Beaster, John|ASSOC|423-987[]
19990225|96542|00711|0528|1684.45|19990101|19990131|For services rendered|4|E|1|0|24.95|19990117||E111|||Meals|24-6437381|24.95|||423-987[]
19990225|96542|00711|0528|1684.45|19990101|19990131|For services rendered|5|E|1|0|289.5|19990117||E110|||Out-of_town travel|24-6437381|289.5|||423-987[]
19990225|96542|00711|1326|1250|19990101|19990131|Monthly Retainer|6|IF|1|1250.|1250|19990131|||||Monthly Retainer Fee|24-6437381||||425-936[]
20160930|96554|00814|0628|684.50|20160901|20160930|For services rendered|1|F|3.50|-30|656|20160115|L510||A102|22547|Research Attorney’s fees, Set off claim|24-6437381|350|Arnsley, Robert|PARTNR|423-987[]
20160930|96554|00814|0628|684.50|20160901|20160930|For services rendered|2|F|4.00|0|701|20161115|L510||A102|22547|Research attorney's fees, Trial pleading|24-6437381|350|Arnsley, Robert|PARTNR|423-987[]
20160930|96554|00814|0628|684.50|20160901|20160930|For services rendered|3|F|0.300|0|41|20160317|L510||A107|45875|Telephone conference with John Doe|24-6437381|200|Beaster, John|ASSOC|423-987[]
20171130|86542|00322|0628|684.50|20171101|20171130|For services rendered|4|E|1|0|34.95|20170117||E111|||Meals|24-6437381|24.95|||423-987[]
20171130|86542|00322|0628|684.50|20171101|20171130|For services rendered|5|E|1|0|301.5|20170321||E110|||Out-of_town travel|24-6437381|289.5|||423-987[]
20171130|86542|00322|1426|1250|20171101|20171130|Monthly Retainer|6|IF|1|1250.|1250|20171031|||||Monthly Retainer Fee|24-6437381||||425-936[]

------WebKitFormBoundaryqiqELBCIiRRaSXiM--

As you can see in your payload, the boundary is there:

----WebKitFormBoundaryqiqELBCIiRRaSXiM

The problem i see is: The boundary doesnt come in the original parameters, it should.

Todo:

  1. (worst) If you cant find a way to have this boundary in the events data, then hack it..read the base64 encoded payload and extract the string "----WebKitFormBoundaryqiqELBCIiRRaSXiM" (it will change on every post, so find a way to retrieve it). Then, use this boundary instead of a call to getBoundary().

  2. (possible cause) Maybe your html code (the form) does not explicitly set the "multipart/form-data" attribute. So, your apigateway expects a multipart/form-data payload, and because the form doesnt provide it then the boundary is not set (the browser submitting your form is the responsible to provide it, not apigateway.

  3. (best solution) the getBoundary method is designed to read the boundary from your incoming data from "event.params.header", this header is created by the Apigateway.

var boundary = multipart.getBoundary(event.params.header['content-type']);

In your apigateway, in the specific method (POST or GET), look at the "Integration Request", then "Body Mapping Templates", and ensure you are providing the right values, this values are created on-the-fly by apigateway using a code-template.

Next code fragement is a copy of my own template (created automatically by apigeteway), this templated is executed by apigateway and it copies values from the apigateway to your service (in json format), so maybe you miss something in this part (look at the "params" part, apigateway will build it, and, it should provide it: events.params.header...).

(you can copy and paste this code into your "Body Mapping Template")

#set($allParams = $input.params())
{
"body-json" : $input.json('$'),
"params" : {
#foreach($type in $allParams.keySet())
    #set($params = $allParams.get($type))
"$type" : {
    #foreach($paramName in $params.keySet())
    "$paramName" : "$util.escapeJavaScript($params.get($paramName))"
        #if($foreach.hasNext),#end
    #end
}
    #if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
    #if($foreach.hasNext),#end
#end
},
"context" : {
    "account-id" : "$context.identity.accountId",
    "api-id" : "$context.apiId",
    "api-key" : "$context.identity.apiKey",
    "authorizer-principal-id" : "$context.authorizer.principalId",
    "caller" : "$context.identity.caller",
    "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider",
    "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType",
    "cognito-identity-id" : "$context.identity.cognitoIdentityId",
    "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId",
    "http-method" : "$context.httpMethod",
    "stage" : "$context.stage",
    "source-ip" : "$context.identity.sourceIp",
    "user" : "$context.identity.user",
    "user-agent" : "$context.identity.userAgent",
    "user-arn" : "$context.identity.userArn",
    "request-id" : "$context.requestId",
    "resource-id" : "$context.resourceId",
    "resource-path" : "$context.resourcePath"
    }
}

@jbrosan
Copy link
Author

jbrosan commented Oct 6, 2017

Hi christiansalazar,

Thank you for your response. You were absolutely correct. The boundary was not being set correctly. A header was being set and was overwriting the boundary information. Once I pulled that out, it all worked great!

Thanks again for your help and your response. I really appreciate it!

Cheers!
John

@christiansalazar
Copy link
Contributor

:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants