Upload multiple files to Symfony Backend manually (without form) - reactjs

I'm facing an issue trying to send multiples files from a ReactJS App to a Symfony Backend.
I upload two files but only one is visible in my Symfony backend.
Data are sent from a ReactJS dropzone, I well checked that the two files are sent via formData, I well used the 'content-type': 'multipart/form-data' to post the data.
In Chrome Newtwork Tab, the Form Data details shows that two files are well attached to the request :
------WebKitFormBoundaryTif9sihCtI30UXXS Content-Disposition: form-data; name="file"; filename="glacier-583419_960_720.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryTif9sihCtI30UXXS Content-Disposition: form-data; name="file"; filename="image-ile.jpg" Content-Type:
image/jpeg
Nevertheless, in my Symfony backend the File Parameter Bag only shows one file :
return $request->files;
Serialized response :
{
"parameters": {
"file": {
"test": false,
"original_name": "glacier-583419_960_720.jpg",
"mime_type": "image/jpeg",
"error": 0
}
},
"file_keys": [
"error",
"name",
"size",
"tmp_name",
"type"
]
}
As you can see, in "parameters", only one file is present instead of two.
Is anybody already encountered this problem ? I don't have any idea of what could be the issue ?

I solved my issue, it was trivial but it could help someone else for future readings.
As per indicated in the Form Data sent :
------WebKitFormBoundaryTif9sihCtI30UXXS Content-Disposition: form-data; name="file"; filename="glacier-583419_960_720.jpg" Content-Type: image/jpeg
------WebKitFormBoundaryTif9sihCtI30UXXS Content-Disposition: form-data; name="file"; filename="image-ile.jpg" Content-Type: image/jpeg
Each element added in the Form Data had the same name value.
Here is the problem :
var tempFormData = new FormData();
setFormData(acceptedFiles.map((file)=>{
tempFormData.append('file', file);
}));
Corrected code :
var tempFormData = new FormData();
setFormData(acceptedFiles.map((file)=>{
tempFormData.append(file.name, file);
}));
So the error was not coming from Symfony but from front-end App not well formatting the data sent.

Related

Workato - Hash containing an array when sent in a multipart form request is considered as a file

I am trying to send an array as value for a hash key in a POST multipart request.
input = {"attribute"=> ["Countries:India", "Category:Can"]}
post("url")
.request_format_multipart_form.payload(input)
This works when using Ruby's HTTP and also POSTMAN. I can also see the differences between how Postman and Workato handles the form data.
Postman:
----------------------------428750340837882951989223
Content-Disposition: form-data; name="attribute"
Category:Test
----------------------------428750340837882951989223
Content-Disposition: form-data; name="attribute"
Countries:India
----------------------------428750340837882951989223--
Workato:
------RubyFormBoundaryhokO7A27Xb6cdSEz
Content-Disposition: form-data; name="attribute"; filename="attribute"
Content-Type: Category:Can
Countries:India
------RubyFormBoundaryhokO7A27Xb6cdSEz--
Why does Workato consider an array as a file? or am I wrong with the call?
I solved this by changing the request type to application/x-www-form-urlencoded and encode the input parameters as form data in the body (Using encode_www_form).
input = {"attribute"=> ["Countries:India", "Category:Can"]}
input = input.encode_www_form
post("url",input)
.request_format_www_form_urlencoded

How do I create a request in Swagger Inspector that accepts multiple data types?

I am currently trying to submit a request using the Swagger Inspector using multipart/form-data header to allow the submission of a file in conjunction with json data.
The JSON body of my request looks like:
And the headers with file upload look like:
For requests where I am just sending json to the server the Content-Type header is set to application/json and it is able to read from the body box. However I do not understand how this interface allows me to specify that the information coming from the body field is json and despite there being files on on the request.
I have seen requests that define multiple data types using the Conetent-Disspostion header, that look this this (reffenced from this Stack Overflow Post):
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
My question would be how do I create a request in swagger inspector that accepts multiple data types? It seems like I would need to set mulple sections in the body separated by boundaries with multiple Content-Disposition and Content-Type's for each. Would there be a cleaner way to do that through the Swagger Inspector interface? Or am I going about this in the wrong way?
Thanks!
Swagger Inspector currently supports multipart/form-data requests containing one or more files. It does not support arbitrary body parts in multipart requests (e.g. a file + JSON or text data). You'll need to use another HTTP client to test such requests.
You can submit feature request for Swagger Inspector here:
https://community.smartbear.com/t5/Swagger-Inspector-Feature/idb-p/SwaggerInspectorFeatureRequests

Inserting a ContentVersion using Angularjs $http

I have been trying to insert files using Salesforce Chatter REST API but its been documented for curl. I am unable to find how to do the same in Angularjs using $http with visualforce. I am not able to set the request header and body properly. Please provide the header and body contents for the request, if this has to be done using javascript rather than curl.
Example for creating a new Document
curl https://yourInstance.salesforce.com/services/data/v23.0/sobjects/Document/
-H "Authorization: Bearer token"
-H "Content-Type: multipart/form-data;boundary=\"boundary_string\""
--data-binary #newdocument.json
Example request body for creating a new Document
This code is the contents of newdocument.json. The binary data for the PDF content has been omitted for brevity and replaced
with “Binary data goes here.” An actual request contains the full binary content.
--boundary_string
Content-Disposition: form-data; name="entity_document";
Content-Type: application/json
{
"Description" : "Marketing brochure for Q1 2011",
"Keywords" : "marketing,sales,update",
"FolderId" : "005D0000001GiU7",
"Name" : "Marketing Brochure Q1",
"Type" : "pdf"
}
--boundary_string
Content-Type: application/pdf
Content-Disposition: form-data; name="Body"; filename="2011Q1MktgBrochure.pdf"
Binary data goes here.
--boundary_string--

How to send multipart/form-data with antd upload react

I am using react and antd.
The component I am using from antd is Drag and Drop.
I am trying to send multipart/form-data using FormData object.
It sends the file (.zip file that should be sent as blob) but it does not send it as blob nor anything related to the other keys and values.
Here's a Sandbox.
Expected Request Payload:
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
Content-Disposition: form-data; name="file"; filename="aFileName.zip"
Content-Type: application/octet-stream
[0,1,2]
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
Content-Disposition: form-data; name="x2"
y2
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
Content-Disposition: form-data; name="x3"
true
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
Content-Disposition: form-data; name="x4"
2
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
Actual Request Paylod:
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
Content-Disposition: form-data; name="file"; filename="aFileName.zip"
Content-Type: application/zip
------WebKitFormBoundaryysdTGvf0cRZVGpQ4
I have used customRequest to solve this problem.
You can find an example here: Send multipart/form-data with antd upload #11616
If you just want to use <Upload> as a file input and only have <Form> submit the file for you, here is my solution

javamail transport send requests attachment multiple times

I currently have a fully functional email notification system. It is all working correctly, but have noticed that one of the inline images, which is attached to the email via a rest service, is being requested three times.
It appears to be happening once transport.send is invoked. I'm assuming that when javamail goes to send email, it then calls for all inline images referenced and generates the base64 image and places it in the outgoing email.
My question is...
Is the above assumptions correct and why would it be calling the service multiple times when it has been verified in the raw email that it contains the image only once.
Below is a copy of the raw email with addresses changed, base64 images, text/plain and text/html versions removed.
Raw email
Date: Thu, 25 Feb 2016 20:40:04 -0800 (PST)
From: something.news.noreply#something.org
To: user.email#something.org
Message-ID: <56557433.31456461613977.JavaMail.something.news.noreply#something.orgh>
Subject: Business News for 02/26/2016
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_6_670038123.1456461604268"
X-Priority: 3
------=_Part_6_670038123.1456461604268
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
TEXT VERSION OF EMAIL
------=_Part_6_670038123.1456461604268
Content-Type: multipart/related;
boundary="----=_Part_7_2073972040.1456461604268"
------=_Part_7_2073972040.1456461604268
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
HTML VERSION OF EMAIL
------=_Part_7_2073972040.1456461604268
Content-Type: image/png;
name="840da574-a395-4fb8-8f33-bcbb1837220e?t=1452039853427"
Content-Transfer-Encoding: base64
Content-ID: <#9dc060f2-84ec-4344-8871-68d4e4885b70_840da574-a395-4fb8-8f33-bcbb1837220e?t=1452039853427>
Content-Disposition: inline;
filename="840da574-a395-4fb8-8f33-bcbb1837220e?t=1452039853427"
BASE 64 IMAGE
------=_Part_7_2073972040.1456461604268
Content-Type: image/png;
name="21ae1010-9675-4daa-8ac8-659052b943e8?t=1450724912940"
Content-Transfer-Encoding: base64
Content-ID: <#17ab1018-2bc5-44f5-9934-fb7b0f1a860b_21ae1010-9675-4daa-8ac8-659052b943e8?t=1450724912940>
Content-Disposition: inline;
filename="21ae1010-9675-4daa-8ac8-659052b943e8?t=1450724912940"
BASE 64 IMAGE
------=_Part_7_2073972040.1456461604268
Content-Type: image/png;
name="a96af9b6-9093-4086-bf91-e5677bef533f?t=1450966405365"
Content-Transfer-Encoding: base64
Content-ID: <#15a682c9-95e8-42ee-880b-f52a47396341_a96af9b6-9093-4086-bf91-e5677bef533f?t=1450966405365>
Content-Disposition: inline;
filename="a96af9b6-9093-4086-bf91-e5677bef533f?t=1450966405365"
BASE 64 IMAGE
------=_Part_7_2073972040.1456461604268
Content-Type: image/png;
name="25caf361-80a9-44c2-9ae6-97c19709becf?t=1450966427231"
Content-Transfer-Encoding: base64
Content-ID: <#2e9839ae-9c10-4c8f-9c4a-bc9e1a934fc3_25caf361-80a9-44c2-9ae6-97c19709becf?t=1450966427231>
Content-Disposition: inline;
filename="25caf361-80a9-44c2-9ae6-97c19709becf?t=1450966427231"
BASE 64 IMAGE
------=_Part_7_2073972040.1456461604268
Content-Type: image/png; name=upChart
Content-Transfer-Encoding: base64
Content-ID: <#6ca90a68-1d24-4414-ac8a-8c84b50bb663_upChart>
Content-Disposition: inline; filename=upChart
BASE 64 IMAGE
THIS IS THE IMAGE THAT IS RETRIEVED VIA A WEB SERVICE CALL. IT CREATES A CHART
IMAGE THAT GET ATTACHED TO EMAIL.
------=_Part_7_2073972040.1456461604268
Content-Type: image/png;
name="10739ce0-c979-4e47-8cee-666304b9a92e?t=1451426510519"
Content-Transfer-Encoding: base64
Content-ID: <#14227419-3db7-444b-a704-7abaccd1e380_10739ce0-c979-4e47-8cee-666304b9a92e?t=1451426510519>
Content-Disposition: inline;
filename="10739ce0-c979-4e47-8cee-666304b9a92e?t=1451426510519"
BASE 64 IMAGE
------=_Part_7_2073972040.1456461604268
Content-Type: image/png;
name="995344fa-765f-4a27-848c-d36d26c593f3?t=1451426553685"
Content-Transfer-Encoding: base64
Content-ID: <#f17f0535-a2a3-47a8-aca4-9ed883542de8_995344fa-765f-4a27-848c-d36d26c593f3?t=1451426553685>
Content-Disposition: inline;
filename="995344fa-765f-4a27-848c-d36d26c593f3?t=1451426553685"
BASE 64 IMAGE
------=_Part_7_2073972040.1456461604268--
------=_Part_6_670038123.1456461604268--
I have added I believe the relevant code. The code starts with what it started out like and then two changes I made based on the suggestion.
Started as:
try {
// Get a REST client so we can call the Highcharts service.
hcClient = new RestClient(hcServer, hcResource);
// Create a client response object.
ClientResponse cr = null;
// Initialize tries counter and loop a maximum of 3 tries
// if highcharts export server doesn't respond with a 200.
int tries = 0;
do {
// Increase tries count.
tries++;
// Call the service and place response data into our data object.
cr = hcClient.getWebResource().post(ClientResponse.class, params);
// Pull the response status from client.
upChartRespStatus = cr.getStatus();
// Determine if we received a 200 code or not.
if(upChartRespStatus == 200) {
// Obtain entity and build response.
response = Response
.ok(new ByteArrayInputStream(cr.getEntity(cbChart.getClass())))
.build();
} else {
// Log warning that chart was not received, what the response
// status was and what try we are on.
logger.warn("Unable to get requested chart, response code was "+upChartRespStatus+".");
logger.warn("Reattempting to get chart. The current count of retries is: "+tries);
}
} while (tries <= 3 && upChartRespStatus != 200);
} catch(Exception e) {
logger.error(e.getMessage());
} finally {
hcClient.destroy();
}
I thought maybe I would try sending a base64 encoded image. I didn't even get the image in the email doing this.
// Determine if we received a 200 code or not.
if(upChartRespStatus == 200) {
// Get entity from client request.
ByteArrayInputStream bais = new ByteArrayInputStream(cr.getEntity(cbChart.getClass()));
String b64Image = new String(Base64.encode(read(bais)));
// Obtain entity and build response.
response = Response
.ok(b64Image)
.header("Content-Type", "image/png")
.header("Content-Length", b64Image.length())
.header("Content-Transfer-Encoding", "BASE64")
.build();
} else {
// Log warning that chart was not received, what the response
// status was and what try we are on.
logger.warn("Unable to get requested chart, response code was "+upChartRespStatus+".");
logger.warn("Reattempting to get chart. The current count of retries is: "+tries);
}
My last attempt was going back to binary, but making sure that the headers were all in place. This last attempt did yield the chart image in the email, but still in all cases the transport.send is still calling the service three times before it actually sends.
// Determine if we received a 200 code or not.
if(upChartRespStatus == 200) {
// Get entity from client request.
ByteArrayInputStream bais = new ByteArrayInputStream(cr.getEntity(cbChart.getClass()));
// Obtain entity and build response.
response = Response
.ok(bais)
.header("Content-Type", "image/png")
.header("Content-Length", bais.available())
.header("Content-Transfer-Encoding", "BINARY")
.build();
} else {
// Log warning that chart was not received, what the response
// status was and what try we are on.
logger.warn("Unable to get requested chart, response code was "+upChartRespStatus+".");
logger.warn("Reattempting to get chart. The current count of retries is: "+tries);
}
Okay. So I got some success. Instead of setting headers at the service, I think that was to late. I took a look at the code that creates the email and specifically when the image gets added to its part. I've added what the code was and what I changed. By doing this, it is now only calling the service twice instead of three times.
private void addImagesInline(Multipart parent, List<URL> embeded, HashMap<String,String> cids) throws MessagingException {
if (embeded != null) {
for (URL img : embeded) {
final MimeBodyPart htmlPartImg = new MimeBodyPart();
DataSource htmlPartImgDs = new URLDataSource(img);
htmlPartImg.setDataHandler(new DataHandler(htmlPartImgDs));
String fileName = img.getFile();
fileName = getFileName(fileName);
String newFileName = cids.get(fileName);
boolean imageNotReferencedInHtml = newFileName == null;
if (imageNotReferencedInHtml) continue;
htmlPartImg.setHeader("Content-ID", "<"+newFileName+">");
htmlPartImg.setDisposition(BodyPart.INLINE);
htmlPartImg.setFileName(fileName);
parent.addBodyPart(htmlPartImg);
}
}
}
I added these to lines of code.
htmlPartImg.setHeader("Content-Type", "image/png");
htmlPartImg.setHeader("Content-Transfer-Encoding", "BASE64");
Thanks in advance for any replies!
I would expect the image to be requested twice. JavaMail will read the image once to determine what encoding is appropriate, based on the content of the image data. It will then read it again to encode it and include it in the message.
You can read the image yourself and save it locally to avoid multiple requests, or you can tell JavaMail what encoding to use by setting the Content-Transfer-Encoding header for the part; that way it won't have to guess what to use.

Resources