Skip to content

Commit c969747

Browse files
Fixes #1828 (#1887)
1 parent ebb1df1 commit c969747

File tree

7 files changed

+86
-50
lines changed

7 files changed

+86
-50
lines changed

src/RestSharp/Parameters/FileParameter.cs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ namespace RestSharp;
2020
[PublicAPI]
2121
public record FileParameter {
2222
/// <summary>
23-
/// Provides raw data for file
23+
/// Name of the parameter
2424
/// </summary>
25-
public Func<Stream> GetFile { get; }
25+
public string Name { get; }
2626

2727
/// <summary>
2828
/// Name of the file to use when uploading
@@ -35,15 +35,18 @@ public record FileParameter {
3535
public string? ContentType { get; }
3636

3737
/// <summary>
38-
/// Name of the parameter
38+
/// Provides raw data for file
3939
/// </summary>
40-
public string Name { get; }
40+
public Func<Stream> GetFile { get; }
41+
42+
public FileParameterOptions Options { get; }
4143

42-
FileParameter(string name, string fileName, Func<Stream> getFile, string? contentType = null) {
43-
Name = name;
44-
FileName = fileName;
45-
GetFile = getFile;
46-
ContentType = contentType ?? Serializers.ContentType.Binary;
44+
FileParameter(string name, string fileName, Func<Stream> getFile, string? contentType, FileParameterOptions options) {
45+
Name = name;
46+
FileName = fileName;
47+
GetFile = getFile;
48+
Options = options;
49+
ContentType = contentType ?? Serializers.ContentType.Binary;
4750
}
4851

4952
/// <summary>
@@ -53,9 +56,10 @@ public record FileParameter {
5356
/// <param name="data">The data to use as the file's contents.</param>
5457
/// <param name="filename">The filename to use in the request.</param>
5558
/// <param name="contentType">The content type to use in the request.</param>
59+
/// <param name="options">File parameter options</param>
5660
/// <returns>The <see cref="FileParameter" /></returns>
57-
public static FileParameter Create(string name, byte[] data, string filename, string? contentType = null) {
58-
return new FileParameter(name, filename, GetFile, contentType);
61+
public static FileParameter Create(string name, byte[] data, string filename, string? contentType = null, FileParameterOptions? options = null) {
62+
return new FileParameter(name, filename, GetFile, contentType, options ?? new FileParameterOptions());
5963

6064
Stream GetFile() {
6165
var stream = new MemoryStream();
@@ -73,24 +77,31 @@ Stream GetFile() {
7377
/// <param name="getFile">Delegate that will be called with the request stream so you can write to it..</param>
7478
/// <param name="fileName">The filename to use in the request.</param>
7579
/// <param name="contentType">Optional: parameter content type, default is "application/g-zip"</param>
80+
/// <param name="options">File parameter options</param>
7681
/// <returns>The <see cref="FileParameter" /> using the default content type.</returns>
7782
public static FileParameter Create(
78-
string name,
79-
Func<Stream> getFile,
80-
string fileName,
81-
string? contentType = null
83+
string name,
84+
Func<Stream> getFile,
85+
string fileName,
86+
string? contentType = null,
87+
FileParameterOptions? options = null
8288
)
83-
=> new(name, fileName, getFile, contentType ?? Serializers.ContentType.Binary);
89+
=> new(name, fileName, getFile, contentType ?? Serializers.ContentType.Binary, options ?? new FileParameterOptions());
8490

85-
public static FileParameter FromFile(string fullPath, string? name = null, string? contentType = null) {
86-
if (!File.Exists(Ensure.NotEmptyString(fullPath, nameof(fullPath))))
87-
throw new FileNotFoundException("File not found", fullPath);
91+
public static FileParameter FromFile(string fullPath, string? name = null, string? contentType = null, FileParameterOptions? options = null) {
92+
if (!File.Exists(Ensure.NotEmptyString(fullPath, nameof(fullPath)))) throw new FileNotFoundException("File not found", fullPath);
8893

89-
var fileName = Path.GetFileName(fullPath);
94+
var fileName = Path.GetFileName(fullPath);
9095
var parameterName = name ?? fileName;
91-
92-
return new FileParameter(parameterName, fileName, GetFile, contentType);
96+
97+
return new FileParameter(parameterName, fileName, GetFile, contentType, options ?? new FileParameterOptions());
9398

9499
Stream GetFile() => File.OpenRead(fullPath);
95100
}
96-
}
101+
}
102+
103+
[PublicAPI]
104+
public class FileParameterOptions {
105+
public bool DisableFileNameStar { get; set; } = true;
106+
public bool DisableFilenameEncoding { get; set; }
107+
}

src/RestSharp/Request/RequestContent.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,16 @@ void AddFiles() {
5757

5858
if (file.ContentType != null) fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType);
5959

60-
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
61-
Name = $"\"{file.Name}\"",
62-
FileName = $"\"{file.FileName}\""
63-
};
64-
mpContent.Add(fileContent, file.Name, file.FileName);
60+
var dispositionHeader = file.Options.DisableFilenameEncoding
61+
? ContentDispositionHeaderValue.Parse($"form-data; name=\"{file.Name}\"; filename=\"{file.FileName}\"")
62+
: new ContentDispositionHeaderValue("form-data") {
63+
Name = $"\"{file.Name}\"",
64+
FileName = $"\"{file.FileName}\""
65+
};
66+
if (!file.Options.DisableFileNameStar) dispositionHeader.FileNameStar = file.FileName;
67+
fileContent.Headers.ContentDisposition = dispositionHeader;
68+
69+
mpContent.Add(fileContent);
6570
}
6671

6772
Content = mpContent;
@@ -172,7 +177,7 @@ void AddPostParameters(ParametersCollection? postParameters) {
172177
.Select(x => new KeyValuePair<string, string>(x.Name!, x.Value!.ToString()!))!;
173178
var encodedItems = formData.Select(i => $"{WebUtility.UrlEncode(i.Key)}={WebUtility.UrlEncode(i.Value)}" /*.Replace("%20", "+")*/);
174179
var encodedContent = new StringContent(string.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
175-
180+
176181
Content = encodedContent;
177182
#endif
178183
}

src/RestSharp/Request/RestRequestExtensions.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,16 @@ public static RestRequest AddOrUpdateParameters(this RestRequest request, IEnume
268268
/// <param name="name">Parameter name</param>
269269
/// <param name="path">Full path to the file</param>
270270
/// <param name="contentType">Optional: content type</param>
271+
/// <param name="options">File parameter header options</param>
271272
/// <returns></returns>
272-
public static RestRequest AddFile(this RestRequest request, string name, string path, string? contentType = null)
273-
=> request.AddFile(FileParameter.FromFile(path, name, contentType));
273+
public static RestRequest AddFile(
274+
this RestRequest request,
275+
string name,
276+
string path,
277+
string? contentType = null,
278+
FileParameterOptions? options = null
279+
)
280+
=> request.AddFile(FileParameter.FromFile(path, name, contentType, options));
274281

275282
/// <summary>
276283
/// Adds bytes to the request as file attachment
@@ -280,9 +287,17 @@ public static RestRequest AddFile(this RestRequest request, string name, string
280287
/// <param name="bytes">File content as bytes</param>
281288
/// <param name="filename">File name</param>
282289
/// <param name="contentType">Optional: content type. Default is "application/octet-stream"</param>
290+
/// <param name="options">File parameter header options</param>
283291
/// <returns></returns>
284-
public static RestRequest AddFile(this RestRequest request, string name, byte[] bytes, string filename, string? contentType = null)
285-
=> request.AddFile(FileParameter.Create(name, bytes, filename, contentType));
292+
public static RestRequest AddFile(
293+
this RestRequest request,
294+
string name,
295+
byte[] bytes,
296+
string filename,
297+
string? contentType = null,
298+
FileParameterOptions? options = null
299+
)
300+
=> request.AddFile(FileParameter.Create(name, bytes, filename, contentType, options));
286301

287302
/// <summary>
288303
/// Adds a file attachment to the request, where the file content will be retrieved from a given stream
@@ -292,15 +307,17 @@ public static RestRequest AddFile(this RestRequest request, string name, byte[]
292307
/// <param name="getFile">Function that returns a stream with the file content</param>
293308
/// <param name="fileName">File name</param>
294309
/// <param name="contentType">Optional: content type. Default is "application/octet-stream"</param>
310+
/// <param name="options">File parameter header options</param>
295311
/// <returns></returns>
296312
public static RestRequest AddFile(
297-
this RestRequest request,
298-
string name,
299-
Func<Stream> getFile,
300-
string fileName,
301-
string? contentType = null
313+
this RestRequest request,
314+
string name,
315+
Func<Stream> getFile,
316+
string fileName,
317+
string? contentType = null,
318+
FileParameterOptions? options = null
302319
)
303-
=> request.AddFile(FileParameter.Create(name, getFile, fileName, contentType));
320+
=> request.AddFile(FileParameter.Create(name, getFile, fileName, contentType, options));
304321

305322
/// <summary>
306323
/// Adds a body parameter to the request
763 KB
Loading
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is a test file for RestSharp.

test/RestSharp.Tests.Integrated/RestSharp.Tests.Integrated.csproj

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,23 @@
44
<TargetFrameworks>net6</TargetFrameworks>
55
</PropertyGroup>
66
<ItemGroup>
7-
<ProjectReference Include="..\..\src\RestSharp.Serializers.Xml\RestSharp.Serializers.Xml.csproj" />
8-
<ProjectReference Include="..\..\src\RestSharp\RestSharp.csproj" />
9-
<ProjectReference Include="..\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj" />
7+
<ProjectReference Include="..\..\src\RestSharp.Serializers.Xml\RestSharp.Serializers.Xml.csproj"/>
8+
<ProjectReference Include="..\..\src\RestSharp\RestSharp.csproj"/>
9+
<ProjectReference Include="..\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj"/>
1010
</ItemGroup>
1111
<ItemGroup>
12-
<None Update="Assets\Koala.jpg" CopyToOutputDirectory="PreserveNewest" />
13-
<None Update="Assets\TestFile.txt" CopyToOutputDirectory="PreserveNewest" />
12+
<None Update="Assets\Koala.jpg" CopyToOutputDirectory="PreserveNewest"/>
13+
<None Update="Assets\TestFile.txt" CopyToOutputDirectory="PreserveNewest"/>
14+
<None Update="Assets\KoalaÄÖäö.jpg" CopyToOutputDirectory="PreserveNewest"/>
15+
<None Update="Assets\Teståæ.txt" CopyToOutputDirectory="PreserveNewest"/>
1416
</ItemGroup>
1517
<ItemGroup>
16-
<PackageReference Include="HttpTracer" Version="2.1.1" />
17-
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.5" />
18-
<PackageReference Include="Polly" Version="7.2.3" />
19-
<PackageReference Include="Xunit.Extensions.Logging" Version="1.1.0" />
18+
<PackageReference Include="HttpTracer" Version="2.1.1"/>
19+
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.5"/>
20+
<PackageReference Include="Polly" Version="7.2.3"/>
21+
<PackageReference Include="Xunit.Extensions.Logging" Version="1.1.0"/>
2022
</ItemGroup>
2123
<ItemGroup>
22-
<None Update="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
24+
<None Update="xunit.runner.json" CopyToOutputDirectory="PreserveNewest"/>
2325
</ItemGroup>
2426
</Project>

test/RestSharp.Tests.Integrated/UploadFileTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,4 @@ public async Task Should_upload_from_stream() {
5151

5252
response.Should().BeEquivalentTo(expected);
5353
}
54-
}
54+
}

0 commit comments

Comments
 (0)