I'm reverse-engineering an API with an endpoint /submit, that accepts the type multipart/form-data content. On the webpage of the service, there is a form to upload plaintext files, so the body of the request should look (and according to devtools it actually looks) like this:
-----------------------------16987925643278910326523687321
Content-Disposition: form-data; name="output"; filename="aaa.txt"
Content-Type: text/plain
some text
-----------------------------16987925643278910326523687321--
My OpenAPI specification of the request body is as follows:
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
output:
type: string
This works almost perfectly, but the code generated from the specification doesn't include the filename="something.txt" in its requests, which the API for some reason needs.
OK: Content-Disposition: form-data; name="output"; filename="aaa.txt"
Error: Content-Disposition: form-data; name="output"
How can I specify in the OpenAPI specification, that the part must always be provided with the filename?
As correctly pointed out by #Helen, the solution is to add format: binary after type: string in the specification:
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
output:
type: string
format: binary # <- THIS
Related
I'm relatively new to rust and using reqwest to fetch a PDF document from a REST API endpoint. The content-type of the response is multipart/form-data; boundary=bc1f6465-6738-4b46-9d9d-b9ae36afa8cb with two parts:
--bc1f6465-6738-4b46-9d9d-b9ae36afa8cb
Content-Disposition: form-data; name="metadata"
Content-Type: application/json
{"documentId":"QkNfRENfSUwwMDEsRTA1OEU3ODQtMDAwMC1DNzY5LTg1MjktMTRFRkI5RTBFNjRF"}
--bc1f6465-6738-4b46-9d9d-b9ae36afa8cb
Content-Disposition: form-data; name="document"; filename=document.pdf
Content-Type: application/pdf
%PDF-1.4
<binary content>
%%EOF
--bc1f6465-6738-4b46-9d9d-b9ae36afa8cb--
I want now to save the PDF document in the 2nd part as a valid PDF file on disk. But the multipart functionality within reqwest seems to create new multipart requests whereas I need to parse a multipart response.
My code to download the file:
use reqwest::{self, header::AUTHORIZATION};
fn main() {
let url = "https://example.com/rest/document/123";
let authorization_header = String::from("Bearer ") + access_token.as_str();
let res = client.get(url)
.header(AUTHORIZATION, &authorization_header)
.send()
.expect("Error calling API");
}
Any hint on how to process the multipart/form-data response is appreciated!
When I upload an array of files as below
Given path 'files', 'multiple'
And multipart file files = { read: 'test.pdf', filename: 'upload-name1.pdf', contentType: 'application/pdf' }
And multipart file files = { read: 'test.pdf', filename: 'upload-name2.pdf', contentType: 'application/pdf' }
When method post
Then status 202
The files are added using the multipart/mixed content type eg:
Content-Type: multipart/form-data; boundary=176626466ce00050
--176626466ce00050
content-disposition: form-data; name="files"
content-type: multipart/mixed; boundary=892503f32da73ceb
--892503f32da73ceb
content-disposition: attachment; filename="upload-name1.pdf"
content-type: application/pdf
content-transfer-encoding: binary
...
--892503f32da73ceb
content-disposition: attachment; filename="upload-name2.pdf"
content-length: 553202
content-type: application/pdf
content-transfer-encoding: binary
...
--892503f32da73ceb--
--176626466ce00050
multipart/mixed was defined in RFC2388 but was later deprecated in RFC7578 so some servers such as Jetty will not support it.
Is it possible to override the default behaviour and use multiple form-data Content-Dispositions instead?
I am using Karate 1.3.0 and am pretty sure this wasn`t an issue with earlier versions
I'm unable to simulate this, so maybe you should follow this process: https://github.com/karatelabs/karate/wiki/How-to-Submit-an-Issue
This is what I tried:
* url 'https://httpbin.org/post'
* multipart file foo1 = { read: 'test.pdf', contentType: 'application/pdf' }
* multipart file foo2 = { read: 'test.pdf', contentType: 'application/pdf' }
* method post
You can see from the response that the server detects 2 multi-part files and it all looks ok.
I also see Karate print this in place of the request payload:
Mixed: content-disposition: form-data; name="foo1"; filename="test.pdf"
content-type: application/pdf; charset=UTF-8
content-length: 6514
Completed: true
IsInMemory: true
Mixed: content-disposition: form-data; name="foo2"; filename="test.pdf"
content-type: application/pdf; charset=UTF-8
content-length: 6514
Completed: true
IsInMemory: true
So it looks ok to me or unable to replicate. We simply use Netty to build multi-part payloads. You are welcome to dig into the code and recommend (or contribute a PR) in case we are using Netty wrong or if Netty has a bug.
For completeness, 1.3.1 has an alternate way of supporting an array of files, so you can try this approach:
* url 'https://httpbin.org/post'
# just use the same name, and behind the scenes an array of multi-parts will be sent in the request body
* def first = { name: 'foo', read: 'test.pdf', contentType: 'application/pdf' }
* def second = { name: 'foo', read: 'test.pdf', contentType: 'application/pdf' }
# note how we support an array of files, which can be programmatically built
# here we use enclosed javascript (refer docs) for convenience, note the round-brackets
* multipart files ([ first, second ])
* method post
I have a very specific case I'm trying to test with Karate.
PUT https://test-api.com/endpoint
Content-Type: multipart/mixed; boundary=BOUNDARY
--BOUNDARY
Content-Type: application/vnd.api+json
{"type": "json-api-object"}
--BOUNDARY
Content-Disposition: attachment; name="fieldname"; filename="filename.jpg"
Content-Type: image/jpeg
Content-Encoding: base64
<binary data>
--BOUNDARY--
Examples show multipart/mixed requests, but they don't show how to set the content-type header on each part. I tried using And multipart header... but that didn't parse correctly.
https://github.com/intuit/karate/blob/master/karate-demo/src/test/java/demo/upload/upload.feature
If I can get this figured out with your help, I'll make a PR against the examples to hopefully help someone in the future.
Yeah this is the first time I'm seeing a need for a custom content-type for each part. This will need a change in the code, so yes an example will expedite a fix.
Meanwhile you can customize the content-type for normal requests.
I had success using mulipart files
* configure headers = {"Content-Type": 'multipart/mixed'}
* configure charset = null
* def mFiles = {}
* set mFiles.jsondata = { value: {'type': 'json-api-object'}, contentType: 'application/vnd.api+json' }
* set mFiles.fieldname = { read: 'classpath:path/to/somePhoto.jpg', filename: 'filename.jpg', contentType: 'image/jpeg' }
Given url "https://my-api.com/put"
And multipart files mFiles
When method PUT
According to this comment, multipart file is preferred for anything other than a string in a multipart field.
I'm constructing a multipart/related upload request, as described here, with some custom object metadata in the request body. The upload is successful but the custom metadata fields are not being set.
The request body looks like:
--===============5679188666781658153==
Content-Type: application/json; -charset="utf-8"
MIME-Version: 1.0
{"x-goog-meta-local-path": "./images/02-05-2017/2017-02-05T14:33:30.364112.jpg", "x-goog-meta-capture-ds": "2017-02-05T14:33:30.364112", "name": "0/02-05-2017/2017-02-05T14:33:30.364112.jpg"}
--===============5679188666781658153==
Content-Type: image/jpeg
MIME-Version: 1.0
Content-Transfer-Encoding: base64
<Image Data>
--===============5679188666781658153==--
From my understanding I should be able to arbitrarily set metadata key:value pairs as long as the keys are prefixed with x-goog-meta-*.
Am I missing something? How can I persist the custom metadata to the object using a multipart upload?
I found the answer in this related question: Google Storage API custom header on node.js
As jterrace points out:
Take a look at the JSON request builder here: https://developers.google.com/storage/docs/json_api/v1/objects/insert
You'll notice that metadata is a separate key in the body. So you'll want something like:
var metadata = {
name: "name"
contentLanguage: "en",
metadata: {
"something": "completely different",
},
acl: [...]
};
What follows is a snippet from a raw email:
Content-Type: application/octet-stream;
name="�밶ó���Ĵ������˼�Ӧ��.xls"
I have attempted to parse the name as a Base64 encoded string, but it fails that. What could it be?
I have seen the same text for a Content-Disposition filename:
Content-Disposition: attachment;
filename="�밶ó���Ĵ������˼�Ӧ��.xls"
Neither of these will pass the validation in the System.Net.Mime constructors for ContentType and ContentDisposition objects.
For the record, the attachment is a legitimate xls file.