Parse multipart/form-data Body on AWS Lambda in Java - java

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.

Ok so this is definitely NOT the ideal solution but I was able to make this work.
Problem
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.
Solution
Download the 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;
}

Related

I am sending form data which contains zip file as well as few other parameter from angular 2, but In Java back end I finding difficulties to consume

the error which I am getting is 415 Unsupported media type.
I am sending form data with zip file as well as few other parameters.
In angular2 I am setting content type as multipart/form-data.
In Java backend also consume as multipart/form data.
I am using javax.ws.rs api.
The methods which I have tried.
Using #FormParam didn't work
Using FileInputStream didn't work
I can't use FormDataParam because I am not using jersey. I need alternate of FormDataParam in jax-ws-rs.
Try with #Consumes(MediaType.APPLICATION_OCTET_STREAM)
In Backend, you receive a MultipartFile. In Java Sprint it looks as follows:
#PostMapping
public ResponseEntity<?> postMetsData(#RequestParam("file") MultipartFile file) {
// your Business-Code here
}
On Frontend-Side, you have to push same Formdata as following. The example uses a String-Value and a zip-file named 'file' in FormData:
// Popup for fileupload
let inputElement = document.createElement("input");
inputElement.type = 'file';
inputElement.accept = XdomeaService.fileType.zip + ", " + XdomeaService.fileType.xml;
// get file, chosen by user in popup
let files = fileChosenEvent.target as HTMLInputElement;
// create FormData
const formData = new FormData();
formData.append('agencyId', agencyId.toString())
formData.append('file', new Blob([files.files[0]], { type: application/octet-stream" }), file.name);
this.uploadZipfile(formData)

How do display the pdf file in scala template page in play 2 framework?

I have successfully generated the pdf using some 3rd party library,but now i am stuck at the point as to how to display the generated pdf file in the browser using scala template.
Any help will be highly appreciated.
Thanks in advance.
The most simple way is to use a built-in controller method for serving files.
Java solution:
File file = getYourPdfFile();
return ok(file);
The ok method is overloaded and accepts a file, a stream or a byte array. The Java documentation can be found here.
Scala solution:
def serveFile(file: File, fileName: String) {
Ok.sendFile(
content = file,
fileName = _ => fileName
)
}
If you want to have more control over a response you can build it manually. Hereunder you have an example which uses a byte array as a response body:
def byteArrayToResult(pdfAsByteArray: Array[Byte], fileName: String): Result = {
val ticketInputStream = new ByteArrayInputStream(pdfAsByteArray)
val fileContent = Enumerator.fromStream(ticketInputStream)
val headers = Map(
CONTENT_LENGTH -> pdfAsByteArray.length.toString,
CONTENT_DISPOSITION -> s"attachment; filename=$fileName"
)
Result(ResponseHeader(200, headers), fileContent
).as("application/pdf")
}
Depending on the way that you hold a generated file you can also use Enumerator.fromFile() instead of the fromStream() method. You can read more about a whole concept in the Scala documentation.

Alfresco REST, file upload: cannot set description and filename

I'm using the following code to upload a file onto Alfresco
CloseableHttpClient client=HttpClients.createDefault();
HttpPost postMethod=new HttpPost(AlfrescoRequests.getUploadRequest()+"?alf_ticket="+DocumentUno.alFrescoSessionTicket.replace("\"", ""));
System.out.println(AlfrescoRequests.getUploadRequest()+"?ticket="+DocumentUno.alFrescoSessionTicket.replace("\"", ""));
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.RFC6532);
reqEntity.addPart("filedata", new FileBody(file));
reqEntity.addPart("alt_destination",new StringBody("workspace://SpacesStore/9a37fce5-2715-4730-a245-64f161304879"));
reqEntity.addPart("filename",new StringBody("ip_VM1985.txt"));
reqEntity.addPart("description", new StringBody("Descrizione del file"));
postMethod.setEntity(reqEntity);
System.out.println("executing request " + postMethod.getRequestLine());
CloseableHttpResponse resp = client.execute(postMethod);
Where AlfrescoRequests.getUploadRequest() gives the REST request URL (query-part excluded)
public static String getUploadRequest()
{
return DocumentUno.ECM_ADDRESS+"/alfresco/service/api/upload";
}
The upload is done correctly, i get a code 200, but the description is not set and i cannot specify a filename, that remains the same of the original file. Please tell me if you need other details.
The /alfresco/service/api/upload webscript unfortunately does not handle metadata. This is a known feature of Alfresco. The filename is handled but the description, which really is the cm:description property, like any other additional standard or custom properties that you might have, are not saved.
I believe the description parameter of the webscript is used as the first parameter for this API:
ScriptNode checkin(String history, boolean majorVersion)
... and has nothing to do with the document title/description.
There is an open-source plugin (which I authored) that overcomes this limitation by allowing to specify any additional metadata during the upload:
http://softwareloop.com/uploader-plus-an-alfresco-uploader-that-prompts-for-metadata/
It comprises a repo amp and a share amp. Since you're using web services, you just need the repo amp.

Multipart/form-data does not support for request.getparamerter [duplicate]

This question already has answers here:
How can I upload files to a server using JSP/Servlet?
(14 answers)
Closed 9 years ago.
I have a form. it has file uploading part as well as several input Fields. i am using request.getParameter() to get values from the jsp into the servlet.
But when i add encrypt=multipart, request.get parameter doesn't work. it returns null. i know multipart does not support for the request.getParameter(). Is there any solution for upload files. I want to use request.get parameter also.
apache commons library will be useful for such requirement.
refer: http://javakart.blogspot.in/2012/11/file-upload-example-using-servlet.html
http://www.tutorialspoint.com/servlets/servlets-file-uploading.htm
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
//this will help you identify request is of type multipart or not.
once you check, parse the request and get the form fields and File Item using library.
Example:
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// Process regular form field (input type="text|radio|checkbox|etc", select, etc).
String fieldname = item.getFieldName();
String fieldvalue = item.getString();
// ... (do your job here)
} else {
// Process form file field (input type="file").
String fieldname = item.getFieldName();
String filename = FilenameUtils.getName(item.getName());
InputStream filecontent = item.getInputStream();
// ... (do your job here)
}
}
request.getParameter() and its related methods do not work with multi-part requests, and will always return null when dealing with multipart form data.
If you want to use request.getParameter() then you can use commons FileUpload.
Annotate your servlet with #MultipartConfig, then use the getParts() method to access the parts. You are using Servlet 3.0, right?
When you use multipart then your form fields are included in request Stream. So you have to check whether they are form fields or not.
Please see this answer.

Oracle Workflow API: adding and accessing file Attachments to a Human Task

I am using the Workflow Services Java API (11.1.1) for SOA Suite to access and manipulate human tasks. I would like to be able to access and add file attachments to existing human tasks. I am using the methods provided in the AttachmentType interface.
When adding an attachment, the problem I am running into is that an attachment does get created and associated with the task, however it is empty and has no content. I have attempted both setting the input stream of the attachment, as well as the content string and in each case have had no success (and setting the content string results in an exception when trying to update the corresponding task).
I have successfully added and accessed an attachment using the worklist application, however when trying to access the content of this attachment through code I receive an object with mostly null/0 values throughout, apart from the attachment name.
The code I am using to access attachments resembles:
List attachments = taskWithAttachments.getAttachment();
for(Object o : attachments){
AttachmentType a = (AttachmentType) o;
String content = a.getContent(); // NULL
InputStream str = a.getInputStream(); // NULL
String name = a.getName(); // Has the attachment name
String mime = a.getMimeType(); // Has the mime type
long size = a.getSize(); // 0
...
}
As the API's are not overly rich in documentation I may well be using them incorrectly. I would really appreciate any help/suggestions/alternatives in dealing with BPEL task attachments.
Thanks
After contacting Oracle for support, it turns out that the attachments portion of the Workflow API is broken in the current release. The fix will be included in a future release.

Categories