I am new to AWS Lambda and I am trying to implement a Lambda function that receives a POST request containing data encoded as multipart/form-data. The message is received through the API Gateway using Lambda Proxy integration and the body is encoded in Base64 when it arrives to the Lambda function. After decoding it manually, I see it contains a multipart body like the following:
-----WebKitFormBoundary3EZ0C3tbP2JpAmz4
Content-Disposition: form-data; name="param1"
value1
-----WebKitFormBoundary3EZ0C3tbP2JpAmz4
Content-Disposition: form-data; name="param2"
value2
------WebKitFormBoundary3EZ0C3tbP2JpAmz4
Content-Disposition: form-data; name="myfile"; filename="ivr.png"
Content-Type: image/png
PNG
... [binary stuff]
------WebKitFormBoundary3EZ0C3tbP2JpAmz4--
What I need is to parse this message in java 8 so I can access the individual parts. I managed to do it using the +javax.mail.Multipart+ object but it seems I cannot access the "name" property for the parts and as such I cannot distinguish between same type elements, e.g. "param1" and "param2". I believe this can be related to the fact that this Class is for parsing email messages... Is there another way to parse this multipart body inside the lambda function? This is the code I have to parse it (base64 is the string containing the body):
DataSource source = new ByteArrayDataSource(new ByteArrayInputStream(Base64.decodeBase64(base64)), "multipart/mixed");
MimeMultipart mp = new MimeMultipart(source);
I'd appreciate any help you can provide.
We've got a completely serverless click counter in React. js. A local development environment, to test and make changes. And it's deployed to production as well, so you can share it with your users.
Multipart form data: The ENCTYPE attribute of <form> tag specifies the method of encoding for the form data. It is one of the two ways of encoding the HTML form. It is specifically used when file uploading is required in HTML form. It sends the form data to server in multiple parts because of large size of file.
You will want to select “New API'” here, enter in an “API name” and click “Create API”. Under the “Actions” menu please select “Create Method”. Please select “ANY” here and click on the tick to confirm. Make sure you select “Lambda Function” here and type in your “Lambda Function” name, in this case “mediumtutorial”.
Ok so this is definitely NOT the ideal solution but I was able to make this work.
There are actually many libraries out there to parse multipart form data. The actual problem is all libraries rely on javax.servlet
package - most importantly HttpServletRequest
class (and few more).
Since we can't access javax.servlet
package classes in AWS Lambda environment, my solution is to fix that.
javax.servlet
package from GitHub and add that to you your lambda function. See the image below - you can see that my class MultipartFormDataTest
is within my package com...
and I also have javax.servlet
package within the same Java module.Once we do this, we can use one or more libraries that will do all the work for us. The best library I've found that will parse the file content is Delight FileUpload - https://mvnrepository.com/artifact/org.javadelight/delight-fileupload.
Once that library is added, the method below getFilesFromMultipartFormData()
will return ArrayList<File>
where each item in the list represents a File
that was sent in the request.
/**
* @param context context
* @param body this value taken from the `request.getBody()`
* @param contentType this value is taken from `request.headers().get("Content-Type")`
* @return List of File objects
*/
private List<File> getFilesFromMultipartFormData(Context context, String body, String contentType) {
ArrayList<File> files = new ArrayList<>();
List<FileItem> fileItems = FileUpload.parse(body.getBytes(StandardCharsets.UTF_8), contentType);
for(FileItem fileItem : fileItems) {
if(fileItem == null) {
continue;
}
logger.log("fileItem name: " + fileItem.getName());
logger.log("fileItem content-type: " + fileItem.getContentType());
logger.log("fileItem size: " + fileItem.getSize());
// Note: instead of storing it locally, you can also directly store it to S3 for example
try {
// I'm setting the extension to .png but you can look at the fileItem.getContentType()
// to make sure it is an image vs. pdf vs. some other format
File temp = File.createTempFile(fileItem.getName(), ".png");
Files.copy(fileItem.getInputStream(), temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
files.add(temp);
} catch (Exception e) {
continue;
}
}
return files;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With