I am in need to post the following request:
POST http://target-host.com/some/endpoint HTTP/1.1
Content-Type: multipart/form-data; boundary="2e3956ac-de47-4cad-90df-05199a7c1f53"
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 6971
Host: target-host.com
--2e3956ac-de47-4cad-90df-05199a7c1f53
Content-Disposition: form-data; name="some-label"
value
--2e3956ac-de47-4cad-90df-05199a7c1f53
Content-Disposition: form-data; name="file"; filename="my-filename.txt"
<file contents>
--2e3956ac-de47-4cad-90df-05199a7c1f53--
I can do this really easily with Python requests
library as follows:
import requests
with open("some_file", "rb") as f:
byte_string = f.read()
requests.post(
"http://target-host.com/some/endpoint",
data={"some-label": "value"},
files={"file": ("my-filename.txt", byte_string)})
Is there any way to do the same with the Flurl.Http
library?
My problem with the documented way of doing it is that it will insert the Content-Type
header for each key-value pair and it will insert the filename*=utf-8''
header for the file data. The server I am trying to post the request to, however, does not support this. Also note the double quotes around the name
and filename
values in the headers.
EDIT: Below is the code I used to make the post request with Flurl.Http
:
using System.IO;
using Flurl;
using Flurl.Http;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
var fs = File.OpenRead("some_file");
var response = "http://target-host.com"
.AppendPathSegment("some/endpoint")
.PostMultipartAsync(mp => mp
.AddString("some-label", "value")
.AddFile("file", fs, "my-filename.txt")
).Result;
}
}
}
According the spec (dated June 2011), sending both filename
and filename*
is recommended for maximum compatibility:
Many user agent implementations predating this specification do not understand the "filename*" parameter. Therefore, when both "filename" and "filename*" are present in a single header field value, recipients SHOULD pick "filename*" and ignore "filename". This way, senders can avoid special-casing specific user agents by sending both the more expressive "filename*" parameter, and the "filename" parameter as fallback for legacy recipients.
If filename*
is actually causing the call to fail, there's a real problem with the server adhering to the HTTP spec. Also, enclosing name
and filename
in quotes is very non-standard.
That said, Flurl's shortcuts cover the 90% cases, but you can always use the underlying HttpClient APIs to cover unusual cases like this one. In this case I think you need to build up the content manually so you can deal with those Content-Disposition
headers:
var mpc = new MultipartContent();
var sc = new StringContent("value");
sc.Headers.Add("Content-Disposition", "form-data; name=\"some-label\"");
mpc.Add(sc);
var fc = new StreamContent(fs);
fc.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"my-filename.txt\"");
mpc.Add(fc);
Then you can use it with Flurl like this:
var response = await "http://target-host.com"....PostAsync(mpc);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With