Skip to content

Commit

Permalink
Setting the form boundary for #1716
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeyzimarev committed Jan 24, 2022
1 parent 6c7b73b commit 6091d72
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 127 deletions.
42 changes: 0 additions & 42 deletions src/RestSharp/Request/HttpContentExtensions.cs

This file was deleted.

28 changes: 10 additions & 18 deletions src/RestSharp/Request/RequestContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ class RequestContent : IDisposable {
var postParameters = _request.Parameters.GetContentParameters(_request.Method);
AddBody(!postParameters.IsEmpty());
AddPostParameters(postParameters);

if (Content is MultipartFormDataContent && _request.FormatMultipartContentType != null) {
ReplaceHeader(ContentType, GetContentTypeHeader(Content.Headers.ContentType!.MediaType!));
}

AddHeaders();

return Content!;
Expand All @@ -57,7 +52,7 @@ class RequestContent : IDisposable {
void AddFiles() {
if (!_request.HasFiles() && !_request.AlwaysMultipartFormData) return;

var mpContent = new MultipartFormDataContent();
var mpContent = new MultipartFormDataContent(GetOrSetFormBoundary());

foreach (var file in _request.Files) {
var stream = file.GetFile();
Expand Down Expand Up @@ -122,6 +117,8 @@ class RequestContent : IDisposable {
return bodyParameter.Name.IsNotEmpty() && bodyParameter.Name != bodyContentType;
}

string GetOrSetFormBoundary() => _request.FormBoundary ?? (_request.FormBoundary = Guid.NewGuid().ToString());

void AddBody(bool hasPostParameters) {
if (!_request.TryGetBodyParameter(out var bodyParameter)) return;

Expand All @@ -130,7 +127,7 @@ class RequestContent : IDisposable {
// 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();
var mpContent = Content as MultipartFormDataContent ?? new MultipartFormDataContent(GetOrSetFormBoundary());
var ct = bodyContent.Headers.ContentType?.MediaType;
var name = bodyParameter!.Name.IsEmpty() ? ct : bodyParameter.Name;

Expand Down Expand Up @@ -167,7 +164,7 @@ class RequestContent : IDisposable {
var formContent = new FormUrlEncodedContent(
_request.Parameters
.Where(x => x.Type == ParameterType.GetOrPost)
.Select(x => new KeyValuePair<string, string>(x.Name!, x.Value!.ToString()!))!
.Select(x => new KeyValuePair<string, string>(x.Name!, x.Value!.ToString()!))
);
Content = formContent;
}
Expand Down Expand Up @@ -195,23 +192,18 @@ class RequestContent : IDisposable {
var pName = Ensure.NotNull(parameter.Name, nameof(parameter.Name));
ReplaceHeader(pName, value);
}

string GetContentTypeHeader(string contentType)
=> Content is MultipartFormDataContent
? $"{contentType}; boundary=\"{GetOrSetFormBoundary()}\""
: contentType;
}

void ReplaceHeader(string name, string? value) {
Content!.Headers.Remove(name);
Content!.Headers.TryAddWithoutValidation(name, value);
}

static readonly FormatContentTypeHeader DefaultContentTypeHeader = (contentType, boundary) => $"{contentType}; boundary=\"{boundary}\"";

string GetContentTypeHeader(string contentType) {
return Content is MultipartFormDataContent mpContent
? ContentTypeValue()(contentType, mpContent.GetFormBoundary())
: contentType;

FormatContentTypeHeader ContentTypeValue() => _request.FormatMultipartContentType ?? DefaultContentTypeHeader;
}

public void Dispose() {
_streams.ForEach(x => x.Dispose());
Content?.Dispose();
Expand Down
9 changes: 2 additions & 7 deletions src/RestSharp/Request/RestRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

namespace RestSharp;

public delegate string FormatContentTypeHeader(string contentType, string formBoundary);

/// <summary>
/// Container for data used to make requests
/// </summary>
Expand Down Expand Up @@ -69,6 +67,8 @@ public RestRequest(Uri resource, Method method = Method.Get)
/// Always send a multipart/form-data request - even when no Files are present.
/// </summary>
public bool AlwaysMultipartFormData { get; set; }

public string? FormBoundary { get; set; }

/// <summary>
/// Container of all HTTP parameters to be passed with the request.
Expand Down Expand Up @@ -147,11 +147,6 @@ public RestRequest(Uri resource, Method method = Method.Get)
/// </summary>
public HttpCompletionOption CompletionOption { get; set; } = HttpCompletionOption.ResponseContentRead;

/// <summary>
/// Function that formats the content type header for multipart form fata
/// </summary>
public FormatContentTypeHeader? FormatMultipartContentType { get; set; }

/// <summary>
/// Set this to write response to Stream rather than reading into memory.
/// </summary>
Expand Down
67 changes: 7 additions & 60 deletions test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,9 @@ static class RequestHandler {

AddParameters(request);

string boundary = null;

request.OnBeforeRequest = http => {
boundary = ((MultipartFormDataContent)http.Content)!.GetFormBoundary();
return default;
};

var response = await _client.ExecuteAsync(request);

var expected = string.Format(Expected, boundary);
var expected = string.Format(Expected, request.FormBoundary);

_output.WriteLine($"Expected: {expected}");
_output.WriteLine($"Actual: {response.Content}");
Expand All @@ -110,15 +103,10 @@ static class RequestHandler {

request.AddParameter(new BodyParameter("controlName", "test", "application/json"));

string boundary = null;

request.OnBeforeRequest = http => {
boundary = ((MultipartFormDataContent)http.Content)!.GetFormBoundary();
return default;
};

var response = await _client.ExecuteAsync(request);

var boundary = request.FormBoundary;

var expectedFileAndBodyRequestContent = string.Format(ExpectedFileAndBodyRequestContent, boundary);
var expectedDefaultMultipartContentType = string.Format(ExpectedDefaultMultipartContentType, boundary);

Expand All @@ -140,14 +128,8 @@ static class RequestHandler {
request.AddFile("fileName", path);
request.AddParameter(new BodyParameter("controlName", "test", "application/json"));

string boundary = null;

request.OnBeforeRequest = http => {
boundary = ((MultipartFormDataContent)http.Content)!.GetFormBoundary();
return default;
};

var response = await _client.ExecuteAsync(request);
var boundary = request.FormBoundary;

var expectedFileAndBodyRequestContent = string.Format(ExpectedFileAndBodyRequestContent, boundary);
var expectedCustomMultipartContentType = string.Format(ExpectedCustomMultipartContentType, boundary);
Expand All @@ -167,58 +149,23 @@ static class RequestHandler {

request.AddParameter(new BodyParameter("controlName", "test", "application/json"));

string boundary = null;

request.OnBeforeRequest = http => {
boundary = ((MultipartFormDataContent)http.Content)!.GetFormBoundary();
return default;
};

var response = await _client.ExecuteAsync(request);
var boundary = request.FormBoundary;

var expectedFileAndBodyRequestContent = string.Format(ExpectedFileAndBodyRequestContent, boundary);

response.Content.Should().Be(expectedFileAndBodyRequestContent);
}

[Fact]
public async Task MultipartFormDataWithBoundaryOverride() {
var request = new RestRequest("/", Method.Post) {
AlwaysMultipartFormData = true,
FormatMultipartContentType = (ct, b) => $"{ct}; boundary=--------{b}"
};

AddParameters(request);

HttpContent content = null;
var boundary = "";

request.OnBeforeRequest = http => {
content = http.Content;
boundary = ((MultipartFormDataContent)http.Content)!.GetFormBoundary();
return default;
};

await _client.ExecuteAsync(request);

var contentType = content.Headers.ContentType!.ToString();
contentType.Should().Be($"multipart/form-data; boundary=--------{boundary}");
}

[Fact]
public async Task MultipartFormDataAsync() {
var request = new RestRequest("/", Method.Post) { AlwaysMultipartFormData = true };

AddParameters(request);

string boundary = null;

request.OnBeforeRequest = http => {
boundary = ((MultipartFormDataContent)http.Content)!.GetFormBoundary();
return default;
};

var response = await _client.ExecuteAsync(request);

var boundary = request.FormBoundary;
var expected = string.Format(Expected, boundary);

response.Content.Should().Be(expected);
Expand Down

0 comments on commit 6091d72

Please sign in to comment.