Repository: restsharp/RestSharp

Issue:
Double quotes option for multipart/form-data boundary
I tried migration 104 to 108.

But since version 107, System.net.http is used for Http Request. It makes difference.

When upload file using multipart/form-data, `AddFiles`  called. 
And it makes MultipartFormDataContent and pass boundary to parameter.

https://github.com/restsharp/RestSharp/blob/f7d3984244c4808ae7c068e028753c2857f325b9/src/RestSharp/Request/RequestContent.cs#L48-L51

Also this is :

https://github.com/restsharp/RestSharp/blob/f7d3984244c4808ae7c068e028753c2857f325b9/src/RestSharp/Request/RequestContent.cs#L211

When MultipartFormDataContent created the boundary parameter will always wrapped "(double quotes).

boundary will like this in version 107 : 
> boundary="gc0pJq0M8jU534c0p" 

But in version 104 :
> boundary=gc0pJq0M8jU534c0p 

There is no double quotes. 
According to [RFC 2046](https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1) double quotes is selective option.

How about add new option in RestSharp for double quotes?


Hints:

Patch:
diff --git a/src/RestSharp/Request/RequestContent.cs b/src/RestSharp/Request/RequestContent.cs
index bf900be82..1b3db3c9c 100644
--- a/src/RestSharp/Request/RequestContent.cs
+++ b/src/RestSharp/Request/RequestContent.cs
@@ -47,7 +47,7 @@ public HttpContent BuildContent() {
     void AddFiles() {
         if (!_request.HasFiles() && !_request.AlwaysMultipartFormData) return;
 
-        var mpContent = new MultipartFormDataContent(GetOrSetFormBoundary());
+        var mpContent = CreateMultipartFormDataContent();
 
         foreach (var file in _request.Files) {
             var stream = file.GetFile();
@@ -58,10 +58,7 @@ void AddFiles() {
 
             var dispositionHeader = file.Options.DisableFilenameEncoding
                 ? ContentDispositionHeaderValue.Parse($"form-data; name=\"{file.Name}\"; filename=\"{file.FileName}\"")
-                : new ContentDispositionHeaderValue("form-data") {
-                    Name     = $"\"{file.Name}\"",
-                    FileName = $"\"{file.FileName}\""
-                };
+                : new ContentDispositionHeaderValue("form-data") { Name = $"\"{file.Name}\"", FileName = $"\"{file.FileName}\"" };
             if (!file.Options.DisableFileNameStar) dispositionHeader.FileNameStar = file.FileName;
             fileContent.Headers.ContentDisposition = dispositionHeader;
 
@@ -102,11 +99,7 @@ HttpContent GetSerialized() {
 
             var contentType = body.ContentType.Or(serializer.Serializer.ContentType);
 
-            return new StringContent(
-                content,
-                _client.Options.Encoding,
-                contentType.Value
-            );
+            return new StringContent(content, _client.Options.Encoding, contentType.Value);
         }
     }
 
@@ -117,6 +110,15 @@ static bool BodyShouldBeMultipartForm(BodyParameter bodyParameter) {
 
     string GetOrSetFormBoundary() => _request.FormBoundary ?? (_request.FormBoundary = Guid.NewGuid().ToString());
 
+    MultipartFormDataContent CreateMultipartFormDataContent() {
+        var boundary    = GetOrSetFormBoundary();
+        var mpContent   = new MultipartFormDataContent(boundary);
+        var contentType = new MediaTypeHeaderValue("multipart/form-data");
+        contentType.Parameters.Add(new NameValueHeaderValue(nameof(boundary), GetBoundary(boundary, _request.MultipartFormQuoteParameters)));
+        mpContent.Headers.ContentType = contentType;
+        return mpContent;
+    }
+
     void AddBody(bool hasPostParameters) {
         if (!_request.TryGetBodyParameter(out var bodyParameter)) return;
 
@@ -125,7 +127,7 @@ void AddBody(bool hasPostParameters) {
         // we need to send the body
         if (hasPostParameters || _request.HasFiles() || BodyShouldBeMultipartForm(bodyParameter!) || _request.AlwaysMultipartFormData) {
             // here we must use multipart form data
-            var mpContent = Content as MultipartFormDataContent ?? new MultipartFormDataContent(GetOrSetFormBoundary());
+            var mpContent = Content as MultipartFormDataContent ?? CreateMultipartFormDataContent();
             var ct        = bodyContent.Headers.ContentType?.MediaType;
             var name      = bodyParameter!.Name.IsEmpty() ? ct : bodyParameter.Name;
 
@@ -155,7 +157,7 @@ void AddPostParameters(GetOrPostParameter[] postParameters) {
 
                 mpContent.Add(
                     new StringContent(postParameter.Value?.ToString() ?? "", _client.Options.Encoding, postParameter.ContentType.Value),
-                    _request.MultipartFormQuoteParameters ? $"\"{parameterName}\"" : parameterName
+                    parameterName
                 );
             }
         }
@@ -177,6 +179,8 @@ void AddPostParameters(GetOrPostParameter[] postParameters) {
         }
     }
 
+    static string GetBoundary(string boundary, bool quote) => quote ? $"\"{boundary}\"" : boundary;
+
     void AddHeaders() {
         var contentHeaders = _request.Parameters
             .GetParameters<HeaderParameter>()
@@ -203,7 +207,7 @@ void AddHeader(HeaderParameter parameter) {
 
         string GetContentTypeHeader(string contentType)
             => Content is MultipartFormDataContent
-                ? $"{contentType}; boundary=\"{GetOrSetFormBoundary()}\""
+                ? $"{contentType}; boundary={GetBoundary(GetOrSetFormBoundary(), _request.MultipartFormQuoteParameters)}"
                 : contentType;
     }
 
diff --git a/src/RestSharp/Request/RestRequest.cs b/src/RestSharp/Request/RestRequest.cs
index 0cc33ba16..023877522 100644
--- a/src/RestSharp/Request/RestRequest.cs
+++ b/src/RestSharp/Request/RestRequest.cs
@@ -86,7 +86,7 @@ public RestRequest(Uri resource, Method method = Method.Get)
     /// quotation marks. Default is false. Enable it if the remote endpoint requires parameters
     /// to be in quotes (for example, FreshDesk API). 
     /// </summary>
-    public bool MultipartFormQuoteParameters { get; set; }
+    public bool MultipartFormQuoteParameters { get; set; } = true;
 
     public string? FormBoundary { get; set; }
 


Test patch:
diff --git a/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs b/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs
index 4ea0e3c8b..6e4a995e9 100644
--- a/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs
+++ b/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs
@@ -32,13 +32,13 @@ public MultipartFormDataTests(ITestOutputHelper output) {
         $"--{{0}}--{LineBreak}";
 
     const string ExpectedFileAndBodyRequestContent =
-        "--{0}" +
-        $"{LineBreak}{KnownHeaders.ContentType}: application/octet-stream" +
+        "--{0}"                                                                                                  +
+        $"{LineBreak}{KnownHeaders.ContentType}: application/octet-stream"                                       +
         $"{LineBreak}{KnownHeaders.ContentDisposition}: form-data; name=\"fileName\"; filename=\"TestFile.txt\"" +
-        $"{LineBreak}{LineBreak}This is a test file for RestSharp.{LineBreak}" +
-        $"--{{0}}{LineBreak}{KnownHeaders.ContentType}: application/json; {CharsetString}" +
-        $"{LineBreak}{KnownHeaders.ContentDisposition}: form-data; name=controlName" +
-        $"{LineBreak}{LineBreak}test{LineBreak}" +
+        $"{LineBreak}{LineBreak}This is a test file for RestSharp.{LineBreak}"                                   +
+        $"--{{0}}{LineBreak}{KnownHeaders.ContentType}: application/json; {CharsetString}"                       +
+        $"{LineBreak}{KnownHeaders.ContentDisposition}: form-data; name=controlName"                             +
+        $"{LineBreak}{LineBreak}test{LineBreak}"                                                                 +
         $"--{{0}}--{LineBreak}";
 
     const string ExpectedDefaultMultipartContentType = "multipart/form-data; boundary=\"{0}\"";
@@ -76,11 +76,24 @@ public async Task AlwaysMultipartFormData_WithParameter_Execute() {
         Assert.Null(response.ErrorException);
     }
 
+    [Fact]
+    public async Task MultipartFormData_NoBoundaryQuotes() {
+        var request = new RestRequest("/", Method.Post) { AlwaysMultipartFormData = true };
+
+        AddParameters(request);
+        request.MultipartFormQuoteParameters = false;
+
+        var response = await _client.ExecuteAsync(request);
+
+        var expected = string.Format(Expected, request.FormBoundary);
+
+        response.Content.Should().Be(expected);
+        RequestHandler.CapturedContentType.Should().Be($"multipart/form-data; boundary={request.FormBoundary}");
+    }
+
     [Fact]
     public async Task MultipartFormData() {
-        var request = new RestRequest("/", Method.Post) {
-            AlwaysMultipartFormData = true
-        };
+        var request = new RestRequest("/", Method.Post) { AlwaysMultipartFormData = true };
 
         AddParameters(request);
 
@@ -91,7 +104,8 @@ public async Task MultipartFormData() {
         _output.WriteLine($"Expected: {expected}");
         _output.WriteLine($"Actual: {response.Content}");
 
-        Assert.Equal(expected, response.Content);
+        response.Content.Should().Be(expected);
+        RequestHandler.CapturedContentType.Should().Be($"multipart/form-data; boundary=\"{request.FormBoundary}\"");
     }
 
     [Fact]
@@ -187,4 +201,4 @@ public async Task ShouldHaveJsonContentType() {
 
         var response = await _client.ExecuteAsync(request);
     }
-}
\ No newline at end of file
+}