Mulesoft is rejected a file upload saying:
"Unable to get name from form-data"
According to this link: MuleSoft Support they suggest naming convention of
following: Content-Disposition, instead of what is being sent as content-disposition.
Feature:
Given url 'https:someurlpath'
And header Authorization = 'Basic ' + 'feefff'
And header Content-Type = 'multipart/form-data'
And header Accept-Encoding = 'gzip, deflate, br'
And multipart field callingApplicationName = 'Karate'
And multipart file binaryContent = { read: 'response.tif', filename: 'response.tif', contentType: 'image/tiff' }
And multipart field properties = '[{"displayName":"SR Number","value":["1234","12345"]},{"displayName":"Document Type","value":"CLAI"},{"displayName":"Ingestion Source","value":"FILENETTOOLS"},{"displayName":"Received Date","value":"2022-01-14T00:52:50.837650Z"},{"displayName":"Pages","value":"0"}]'
When method Post
Then status 200
And print response
And match response.status == 'ACTIVE'
Here is the request:
1 > POST https://api.maha.com/documents-process-api/v1/documentC/specialR/documents/
1 > Authorization: Basic foooooooobooooooo
1 > Content-Type: multipart/form-data; boundary=231ef49a739286f9
1 > Accept-Encoding: gzip, deflate, br
1 > Content-Length: 214420
1 > Host: api.maha.com
1 > Connection: Keep-Alive
1 > User-Agent: Apache-HttpClient/4.5.13 (Java/14.0.2)
content-disposition: form-data; name="callingApplicationName"; filename=""
content-type: text/plain; charset=UTF-8
content-length: 6
Completed: true
IsInMemory: true
Mixed: content-disposition: form-data; name="binaryContent"; filename="response.tif"
content-type: image/tiff; charset=UTF-8
content-length: 213642
Completed: true
IsInMemory: false
RealFile: /Users/req/workspace/hlx/sasquatch-automated-tests/src/test/groovy/com/maha/gpa/document/storage/service/response.tif DefaultDeleteAfter: true
content-disposition: form-data; name="properties"; filename=""
content-type: text/plain; charset=UTF-8
content-length: 278
Completed: true
IsInMemory: true
Yes this is a known issue with a workaround, refer this thread please: https://github.com/karatelabs/karate/issues/1647
Meanwhile you are most welcome to contribute code to Karate to fix this :)
Related
When i send the Content-Type = 'application/x-www-form-urlencoded' as header it is changed to Content-Type: application/json; in Karate version 0.9.2 .
In Karate version 0.7.0 it is sent as Content-Type = 'application/x-www-form-urlencoded' only .
Given url "https://foo.bar.buzz"
And header Content-Type = 'application/x-www-form-urlencoded'
And form field username = "check"
And form field password = "Password"
And request {}
And header Content-Type = 'application/json'
When method POST
Then status 200
In the 3rd last line you have the header set ?
And you should never use a request body for a form submit.
Try the below, it works fine:
Given url 'https://postman-echo.com/post'
And form field foo = 'bar'
When method post
Result:
1 > POST https://postman-echo.com/post
1 > Accept-Encoding: gzip,deflate
1 > Connection: Keep-Alive
1 > Content-Length: 7
1 > Content-Type: application/x-www-form-urlencoded; charset=UTF-8
1 > Host: postman-echo.com
1 > User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_112)
foo=bar
I am working on an ASP.NET Core 2.2 API using the Microsoft.AspNetCore.OData NuGet v7.1.0 and I am trying to test OData batch using Postman v7.0.5.
The problem I am having is that it always fails to see the data in the last POST request in my batch. In the response, I get "201 Created" for every post except the last on, which returns "400 Bad Request" because it is not picking up the data in the last request body.
Here is the relevant section of my Startup.cs where I enable OData Batch handling;
app.UseODataBatching();
app.UseMvc(routeBuilder =>
{
routeBuilder
.MapODataServiceRoute("ODataRoutes", "api/v1",
modelBuilder.GetEdmModel(app.ApplicationServices),
new DefaultODataBatchHandler());
});
In Postman, I have a POST request to
{{url}}/api/v1/$batch
and in the Request -->Headers section, I have a Content-Type header set to
multipart/mixed; boundary=batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0
The Body of the request is set to "Raw" and "Text"
Below is the request body;
--batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /api/v1/AddressComplianceCode HTTP/1.1
OData-Version: 4.0
Content-Type: application/json
Accept: application/json;odata.metadata=minimal
{
"Code": "Z1",
"Description": "Test Batch Z1",
"Active": true
}
--batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /api/v1/AddressComplianceCode HTTP/1.1
OData-Version: 4.0
Content-Type: application/json
Accept: application/json;odata.metadata=minimal
{
"Code": "Z2",
"Description": "Test Batch Z2",
"Active": true
}
--batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /api/v1/AddressComplianceCode HTTP/1.1
OData-Version: 4.0
Content-Type: application/json
Accept: application/json;odata.metadata=minimal
{
"Code": "Z3",
"Description": "Test Batch Z3",
"Active": true
}
--batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /api/v1/AddressComplianceCode HTTP/1.1
OData-Version: 4.0
Content-Type: application/json
Accept: application/json;odata.metadata=minimal
{
"Code": "Z4",
"Description": "Test Batch Z4",
"Active": true
}
--batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0--
And here is the response;
--batchresponse_f2c84aaf-dc39-4f20-8da0-881f402436fa
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Location: https://localhost:44331/api/v1/AddressComplianceCode('Z1')
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
OData-Version: 4.0
{"#odata.context":"https://localhost:44331/api/v1/$metadata#AddressComplianceCode/$entity","Code":"Z1","Description":"Test Batch Z1","MarkedForRetirement":false,"RetirementDate":null,"LastModifiedDate":"2019-03-12T10:19:20.9434728-04:00","LastModifiedBy":null,"CreatedDate":"2019-03-12T10:19:20.9434728-04:00","CreatedBy":null,"Delete":false,"Active":true}
--batchresponse_f2c84aaf-dc39-4f20-8da0-881f402436fa
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Location: https://localhost:44331/api/v1/AddressComplianceCode('Z2')
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
OData-Version: 4.0
{"#odata.context":"https://localhost:44331/api/v1/$metadata#AddressComplianceCode/$entity","Code":"Z2","Description":"Test Batch Z2","MarkedForRetirement":false,"RetirementDate":null,"LastModifiedDate":"2019-03-12T10:19:21.2241031-04:00","LastModifiedBy":null,"CreatedDate":"2019-03-12T10:19:21.2241031-04:00","CreatedBy":null,"Delete":false,"Active":true}
--batchresponse_f2c84aaf-dc39-4f20-8da0-881f402436fa
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Location: https://localhost:44331/api/v1/AddressComplianceCode('Z3')
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
OData-Version: 4.0
{"#odata.context":"https://localhost:44331/api/v1/$metadata#AddressComplianceCode/$entity","Code":"Z3","Description":"Test Batch Z3","MarkedForRetirement":false,"RetirementDate":null,"LastModifiedDate":"2019-03-12T10:19:21.5068813-04:00","LastModifiedBy":null,"CreatedDate":"2019-03-12T10:19:21.5068813-04:00","CreatedBy":null,"Delete":false,"Active":true}
--batchresponse_f2c84aaf-dc39-4f20-8da0-881f402436fa
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 400 Bad Request
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
OData-Version: 4.0
{"error":{"code":"","message":"The input was not valid.","details":[{"code":"","message":"The input was not valid."}]}}
--batchresponse_f2c84aaf-dc39-4f20-8da0-881f402436fa--
No matter how many POST sections I add to the request ( I have tested 2, 3 and 4), the last request always fails to pass the request body values.
I have reviewed the Batch advanced tutorial at www.odata.org site, as well as all of the relevant SO posts I could find. I also tried the Github issues pages using the filter;
is:issue is:open batch
All with no luck so far.
What am I missing here?
Based upon my own experiences, I'd guess it's because you're sending LFs with Postman, rather than CRLFs.
Postman will send whatever newline you've entered (perhaps pasted in from something that prefers LF) , but multipart/mixed data requires CRLF. Sending just the LF confuses the ODataMultipartMixedBatchReader about whether a boundary line is an end-boundary or not, and causes the end-boundary marker to be added to the request. This in turn confuses the model binder on the ASP.NET Core side of things, which can't deserialize the request body.
I have a Website and a python flask RESTFUL API. When testing the API with Postman it works just fine, but the same request using XMLHttprequest in js gives me a 400 BAD Request code. I looked at the headers send and replicated the XMLHttprequest headers in Postman, to get a 400 BAD REQUEST Code. If i remove the Content-Length header from the request, it works fine. My Postman code (HTML, without content-length):
POST /user/181453766040485888 HTTP/1.1
Host: 127.0.0.1:5000
Content-Type: multipart/form-data; boundary=---
-WebKitFormBoundary7MA4YWxkTrZu0gW
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keeep-alive
Host: 127.0.0.1:5000
Origin: http://localhost:52014
Referer: http://localhost:52014/settings.php
User-Agent: Mozilla/5.0 (Windows NT 10.0;
Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106 (Edition Campaign 76)
cache-control: no-cache
Postman-Token: 5dd34b0b-965c-4d31-83b9-2364b03c0aa2
Content-Disposition: form-data; name="status"
0
Content-Disposition: form-data; name="username"
0
Content-Disposition: form-data; name="token"
0
Content-Disposition: form-data; name="display_names"
1
Content-Disposition: form-data; name="messages"
1
Content-Disposition: form-data; name="roles"
1
Content-Disposition: form-data; name="votes"
1
------WebKitFormBoundary7MA4YWxkTrZu0gW--
My js function (for testing):
function save() {
var formData = new FormData();
formData.append("status", 0);
formData.append("username", 0);
formData.append("token", 0);
formData.append("display_names", 0);
formData.append("messages", 0);
formData.append("roles", 0);
formData.append("votes", 0);
const Http = new XMLHttpRequest();
const url='http://127.0.0.1:5000/user/181453766040485888';
Http.open("POST", url);
Http.onreadystatechange=(e)=>{
console.log(Http.responseText)
}
Http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
Http.send(formData);
}
my API function that handles the request (abstract):
def post(self, id):
if database.execute(database.SAVE_USER_SETTINGS.format(id, request.form["status"], request.form["username"],
request.form["token"], request.form["display_names"],
request.form["messages"], request.form["roles"],
request.form["votes"])):
return (id, request.form["status"], request.form["username"],
request.form["token"], request.form["display_names"],
request.form["messages"], request.form["roles"],
request.form["votes"]), 201
return {}, 500
I tried to copy a file on OneDrive:
Request:
POST https://api.onedrive.com/v1.0/drive/root:/onedrive_test/foo/bar/a.txt:/action.copy
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json
Content-Length: 84
Accept: */*
Authorization: Bearer Ew...
Prefer: respond-async
User-Agent: python-requests/2.7.0 CPython/3.4.4 Windows/7
b'{"parentReference": {"path": "/drive/root:/onedrive_test/foo/bar"}, "name": "b.txt"}'
Response: 202 Accepted
Request:
GET https://api.onedrive.com/v1.0/monitor/4sT2gLAWdXVK7EdkDM7k24ObcUFTzScBof3T80HbmKfVHPnUCDK4fWe01ttH9...
Accept-Encoding: gzip, deflate
Connection: keep-alive
Accept: */*
Authorization: Bearer Ew...
User-Agent: python-requests/2.7.0 CPython/3.4.4 Windows/7
None
Response: 500 Internal server error if copying to the same folder where source file is.
If I use
b'{"parentReference": {"path": "/drive/root:/onedrive_test/foo/bar2"}, "name": "b.txt"}'
or
b'{"parentReference": {"path": "/drive/root:/onedrive_test/foo"}, "name": "b.txt"}'
everything works fine.
This is an ongoing issue with OneDrive Consumer - I'll respond to this answer with a comment once it is resolved.
I have tried multiple HTTP APIs to post a file to OneDrive using the POST method, and I am getting always the same error.
I went to the extreme case of creating my own SSL TCP socket and send the following bytes:
POST /v5.0/folder.a4fb14adbccd1917.A4FB14ADBCCD1917!32089/files HTTP/1.1
Accept-Encoding:
Authorization: Bearer eWciaQ1DBAAUGCCXc8wU/zFu9QnLdZXy%2bYnElFkAAXA4AJqTmiPoOUADOkV98mAdpBZp8SeF0zjYzU4%2bVa0fVR/aWr4X0cHWAzEF7s7HBEABBptxlWcKHEyrgKfbH2YbADpxEjU0gRrOz37WInvPSgFVD8BZ9GtCQwdHh3GUXunbM/Nlqh1TIzELMJYuPEgaEBBWT25f8SoKziZi2kPVlZDPokjJBq2bxrYcAWydDK74ivuiuDGkX4hMpmWZmWtergEybpN2EgObHQa8O3GT2a9ta2hps0ElCv0GkhWG/u1t19/xjokW2dNbbsJ01A9iJkMYXhaMTYg71sGjqzHdXjAJf0hXNg8NiIOTy82MlHqEwCwEyzfXOSGddt0cLkIDZgAACEDf3skftS5%2bWAHGkGlcwFj4DRlrn3/F2DvOZWgyeITjkWfzdx%2b4B8m5olyO5oYKWf77zjVxnUkJ50cIOVCJq/OgnV1kMGB45EExY3%2b3T9JjN0rm91doGnuFGj1m/vuzVN3eP5f3Jr0hMvXbMpzFBImV/c/5SU5esBzA1zas9xt%2bKEi0rriVSqHS4QI4Bps3RN5KpQd4yrNxcTDi%2b9b9AkUVQB%2bxeW5lWGuR5YvaAOHhcePRqNqT2MY7c1zQMoa/C7E63FuOoSdr0KPJbsDKl8aXEt9vT/6A8BK0MnY%2b7MJ1cZaFL%2bhvK0lfI4Z6LJa/3Ayy%2bPt8%2bOc8gNP1Mu/1RCdOT8K1PxwhnvUIE8cnRyI28LUm%2bWUCnurRCNMNBorhZu64JxqOC1EGOja6wNcyI%2bw3TQ1dorDJWN91qENQAxxBMpl1LWdp548kDJcEPwxI4SkXQKnvWcxW1vCZY90SHzruvNmb
Content-Length: 197
Content-Type: multipart/form-data; boundary=8381f8b9-b470-43ce-b23b-f13cf5840014
Host: apis.live.net
Connection: Keep-Alive
Cache-Control: no-cache
--8381f8b9-b470-43ce-b23b-f13cf5840014
Content-Length: 9
Content-Type: application/octet-stream; charset=UTF-8
Content-Disposition: form-data; name="file"; filename="hello.txt"
xxxxxxxxx
--8381f8b9-b470-43ce-b23b-f13cf5840014--
And I always get the following bytes back:
HTTP/1.1 400 Bad Request
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Length: 276
Content-Type: application/json; charset=UTF-8
Server: Live-API/18.105.8117.3007 Microsoft-HTTPAPI/2.0
P3P: CP="BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo"
X-MSNSERVER: BY3301____PAP073
X-Content-Type-Options: nosniff
X-HTTP-Live-Request-Id: API.f06af310-9b49-4cbf-bf71-8c9d79570ec9
X-AsmVersion: UNKNOWN; 18.105.0.0
Date: Mon, 06 Oct 2014 21:37:15 GMT
{
"error": {
"code": "request_body_invalid",
"message": "The request entity body has an incorrect value in the 'Content-Disposition' header. The expected format for this value is 'Content-Disposition: form-data; name=\"file\"; filename=\"[FileName]\"'."
}
}
All of this happened after I tried to answer this SO question.
Any idea?
UPDATE: I used the onedrive-api tag as recommended in the MSDN forums.
Try putting the Content-Disposition header as the first header after the boundary, followed by the Content-Type:
--8381f8b9-b470-43ce-b23b-f13cf5840014
Content-Disposition: form-data; name="file"; filename="hello.txt"
Content-Type: application/octet-stream; charset=UTF-8
You may need to omit the Content-Length as well to make it work. Pretty fragile really.