Content-Type header property value quoting doesn't work with third-party server - http-headers

Is it correct to quote the boundary property value of Content-Type header?
I have sent an http-request with two files to a third-party server and get the following response:
Boundary '--"38b14895-fd44-4acc-8287-9f0378691da2"' not found in message body
because RestSharp quotes the boundary value, but the server doesn't unquote it. I can neither change the third-party server nor customize RestSharp header quoting.
What is the problem? Does the http spec allow escaped strings in header property values? I've read the spec, but haven't found a place where this would be explicitly defined.
I create the RestRequest something like this:
private RestRequest CreateRequest( ... )
{
var request_url = $"url?param=value";
var request = new RestRequest( request_url, Method.Post );
request.AddFile( "file1", ..., "file1", "application/xml" );
request.AddFile( "file2", ..., "file2", "audio/x-wav" );
request.AddHeader( "Content-Type", "multipart/form-data" );
return request;
}
and get the following HTTP-request:
POST /url?param=value
Host: 192.168.1.1:80
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/108.0.1.0
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary="38b14895-fd44-4acc-8287-9f0378691da2"
Content-Length: 227841
--38b14895-fd44-4acc-8287-9f0378691da2
Content-Type: application/xml
Content-Disposition: form-data; name="file1"; filename="file1"
[data]
--38b14895-fd44-4acc-8287-9f0378691da2
Content-Type: audio/x-wav
Content-Disposition: form-data; name="file2"; filename="file2"
[data]
--38b14895-fd44-4acc-8287-9f0378691da2--

Okay so I have just been dealing with a very similar issue. I found this GitHub Issue which gives some good context into the actual issue that is occurring here but I have also found a fix.
Firstly, you shouldn't manually add the "Content-Type" header. RestSharp will do this for you since you are using the AddFile() method.
I am assuming you are using the latest version of RestSharp, if so you can set the request.OnBeforeRequest property of the RestRequest to handle this and strip out the double quotes around the boundary before the request is sent:
request.OnBeforeRequest = (http) =>
{
var boundary = http.Content.Headers.ContentType.Parameters.First(o => o.Name == "boundary");
boundary.Value = boundary.Value.Replace("\"", String.Empty);
return default;
};
Hope this helps!

Related

Getting error in file upload using karate api

Could anyone please assist me to file upload functionality using Karate API? I have tried many ways, but getting error message as
"[{"title":"QUERY.BIZ.004","status":500,"detail":"Error in uploading document","timestamp":"2021-12-01T09:04:01.033+01:00"}]"
PAYLOAD DETAILS
metadata: {"key":"FILE_NAME","value":"karate-logo"}
metadata: {"key":"FILE_EXTENSION","value":"jpg"}
metadata: {"key":"TAG","value":"REQUEST"}
metadata: {"key":"DOC_TYP","value":"00008"}
file: (binary)
REQUEST HEADERS
Accept: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 2368
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9A1eYQihw4rdVq9f
Below mentioned karate API code which I used in the framework
Given url posturl
And path 'document'
And header id = '1608672'
And header Content-Type = 'multipart/form-data'
And multipart file file = { read: 'classpath:dataDrivenPayload/karate-logo.jpg', filename: 'karate-logo.jpg', contentType: 'image/jpg' }
And multipart field metadata = {"key":"FILE_NAME","value":"karate-logo"}, {"key":"FILE_EXTENSION","value":"jpg"}, {"key":"TAG","value":"REQUEST"}, {"key":"DOC_TYP","value":"00008"}
When method POST
Then status 200
I think the metadata needs to be sent as multiple "parts".
Try something like this:
* url 'https://httpbin.org/anything'
* multipart file metadata = { value: '{"key":"FILE_NAME","value":"karate-logo"}' }
* multipart file metadata = { value: '{"key":"FILE_EXTENSION","value":"jpg"}' }
* method post
* status 200
Otherwise, please use these instructions to troubleshoot, and work with your server-side team if possible: github.com/karatelabs/karate/issues/1645#issuecomment-862502881

Why does this REST request work from every client except Talend API tester

This is an example of a REST POST request that works everywhere except Talend API tester. It give a 500 error.
Here is how I set the request up in my applications.
URLConnection connection = new URL("https://" + authHost + "/connect/token").openConnection();
logger.info("Connection oppened");
// message contains the form data: key=value&key=value&key=value
String message = "password=" + password + "&grant_type=password&username=" + username +
"&client_id=foolid&scope=mouthwash";
logger.info(message);
// Setting header fields.
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Accept", "application/json");
connection.getOutputStream().write(message.getBytes("UTF-8"));
Here is a working example in Postman
POST /connect/token HTTP/1.1
Host: identityserver.uat.example.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Cookie: ARRAffinity=6a37d2ecf3441e27913cb832c4b767c68cad0e45c8806b3c5344d1b52d57f67a; ARRAffinitySameSite=6a37d2ecf3441e27913cb832c4b767c68cad0e45c8806b3c5344d1b52d57f67a
Content-Length: 137
password=secret&grant_type=password&username=fool&client_id=foolid&scope=mouthwash
And here is what Talend say it sends, which gets the 500 error -- which I understand comes from the server.
POST /connect/token HTTP/1.1
Accept: application/json
Content-Length: 137
Content-Type: application/x-www-form-urlencoded
Host: identityserver.uat.example.com
password=secret&grant_type=password&username=fool&client_id=foolid&scope=mouthwash
What's happening here?

Creating multipart/mixed request

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.

How to send request POST message to API server in flutter?

I'm using NAVER API to detect faces, so I have to send POST message to API server. The format of message is like below.
[HTTP Request Header]
POST /v1/vision/face HTTP/1.1
Host: openapi.naver.com
Content-Type: multipart/form-data; boundary={boundary-text}
X-Naver-Client-Id: {Client ID}
X-Naver-Client-Secret: {Client Secret}
Content-Length: 96703
--{boundary-text}
Content-Disposition: form-data; name="image"; filename="test.jpg"
Content-Type: image/jpeg
{image binary data}
--{boundary-text}--
After I checked format, I wrote using MultipartRequest and MultipartFile.
Future<void> getFaceData() async {
final Uri url = Uri.parse('https://openapi.naver.com/v1/vision/face');
final request = http.MultipartRequest('POST',url);
request.fields['X-Naver-Client-Id'] = 'client key(I added real value)';
request.fields['X-Naver-Client-Secret'] = 'client secret(I added real value)';
request.files.add(await http.MultipartFile.fromPath(
'image',
_image.path,
contentType: MediaType('multipart','form-data')
));
http.StreamedResponse response = await request.send();
print(response.statusCode);
}
But this code gets 401 error which is UNAUTHORIZED. What is the problem? How can I fix it?
The X-Naver... values are HTTP headers, rather than form fields. Add them like this instead:
request.headers['X-Naver-Client-Id'] = 'client key(I added real value)';
request.headers['X-Naver-Client-Secret'] = 'client secret(I added real value)';

How can I replace the 'Accept' http header in AS3

all
I send a http request from flash client(AS3) to a RESTFull service. The server side response json or xml data depend on the 'Accept' parameter in http header. But, I always accept xml format data even if I set the 'Accept' to 'application/json' in the client side. With wireshark I found that there are double 'Accept' parameter in the http header. Can somebody tell me why ? And/or how to get out of this.
POST /psplatform/rest/szdata/all HTTP/1.1
Host: 203.175.156.88:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-type: application/json
Accept: application/json
Content-length: 8
public function reload():void{
data = new Object();
new URLLoader(createJSONURLRequest("http://203.175.156.88:8080/psplatform/rest/szdata/all")).addEventListener(Event.COMPLETE, loaderCompleteHandler);
}
private function createJSONURLRequest(url:String):URLRequest{
var urlRequest:URLRequest = new URLRequest(url);
urlRequest.method = URLRequestMethod.POST;
urlRequest.contentType = "application/json";
//var urlVariables:URLVariables = new URLVariables("{}");
urlRequest.data = "{name:0}";
urlRequest.requestHeaders.push(new URLRequestHeader("Accept", "application/json"));
return urlRequest;
}