Skip to content

Commit 27272f3

Browse files
committed
Fixing the file upload test
1 parent 1d289f9 commit 27272f3

File tree

16 files changed

+216
-136
lines changed

16 files changed

+216
-136
lines changed

src/RestSharp/Request/RestRequest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ namespace RestSharp;
2525
/// Container for data used to make requests
2626
/// </summary>
2727
public class RestRequest {
28-
readonly Func<HttpResponseMessage, RestResponse>? _advancedResponseHandler;
29-
readonly Func<Stream, Stream?>? _responseWriter;
28+
readonly Func<HttpResponseMessage, RestRequest, RestResponse>? _advancedResponseHandler;
29+
readonly Func<Stream, Stream?>? _responseWriter;
3030

3131
/// <summary>
3232
/// Default constructor
@@ -195,7 +195,7 @@ public RestRequest(Uri resource, Method method = Method.Get)
195195
/// <summary>
196196
/// Set this to handle the response stream yourself, based on the response details
197197
/// </summary>
198-
public Func<HttpResponseMessage, RestResponse>? AdvancedResponseWriter {
198+
public Func<HttpResponseMessage, RestRequest, RestResponse>? AdvancedResponseWriter {
199199
get => _advancedResponseHandler;
200200
init {
201201
if (ResponseWriter != null) throw new ArgumentException("ResponseWriter is not null. Only one response writer can be used.");

src/RestSharp/Response/RestResponse.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class RestResponse<T> : RestResponse {
3333
public T? Data { get; set; }
3434

3535
public static RestResponse<T> FromResponse(RestResponse response)
36-
=> new() {
36+
=> new(response.Request) {
3737
Content = response.Content,
3838
RawBytes = response.RawBytes,
3939
ContentEncoding = response.ContentEncoding,
@@ -50,9 +50,10 @@ public static RestResponse<T> FromResponse(RestResponse response)
5050
Server = response.Server,
5151
StatusCode = response.StatusCode,
5252
StatusDescription = response.StatusDescription,
53-
Request = response.Request,
5453
RootElement = response.RootElement
5554
};
55+
56+
public RestResponse(RestRequest request) : base(request) { }
5657
}
5758

5859
/// <summary>
@@ -68,7 +69,7 @@ internal static async Task<RestResponse> FromHttpResponse(
6869
CalculateResponseStatus calculateResponseStatus,
6970
CancellationToken cancellationToken
7071
) {
71-
return request.AdvancedResponseWriter?.Invoke(httpResponse) ?? await GetDefaultResponse().ConfigureAwait(false);
72+
return request.AdvancedResponseWriter?.Invoke(httpResponse, request) ?? await GetDefaultResponse().ConfigureAwait(false);
7273

7374
async Task<RestResponse> GetDefaultResponse() {
7475
var readTask = request.ResponseWriter == null ? ReadResponse() : ReadAndConvertResponse();
@@ -81,7 +82,7 @@ async Task<RestResponse> GetDefaultResponse() {
8182
var bytes = request.ResponseWriter != null || stream == null ? null : await stream.ReadAsBytes(cancellationToken).ConfigureAwait(false);
8283
var content = bytes == null ? null : httpResponse.GetResponseString(bytes, encoding);
8384

84-
return new RestResponse {
85+
return new RestResponse(request) {
8586
Content = content,
8687
RawBytes = bytes,
8788
ContentEncoding = httpResponse.Content.Headers.ContentEncoding,
@@ -95,7 +96,6 @@ async Task<RestResponse> GetDefaultResponse() {
9596
StatusCode = httpResponse.StatusCode,
9697
StatusDescription = httpResponse.ReasonPhrase,
9798
IsSuccessStatusCode = httpResponse.IsSuccessStatusCode,
98-
Request = request,
9999
Headers = httpResponse.Headers.GetHeaderParameters(),
100100
ContentHeaders = httpResponse.Content.Headers.GetHeaderParameters(),
101101
Cookies = cookieCollection,
@@ -114,6 +114,10 @@ async Task<RestResponse> GetDefaultResponse() {
114114
}
115115
}
116116
}
117+
118+
public RestResponse(RestRequest request) : base(request) { }
119+
120+
public RestResponse() : base(new RestRequest()) { }
117121
}
118122

119123
public delegate ResponseStatus CalculateResponseStatus(HttpResponseMessage httpResponse);

src/RestSharp/Response/RestResponseBase.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,19 @@ public abstract class RestResponseBase {
2525
/// <summary>
2626
/// Default constructor
2727
/// </summary>
28-
protected RestResponseBase() => ResponseStatus = ResponseStatus.None;
28+
protected RestResponseBase(RestRequest request) {
29+
ResponseStatus = ResponseStatus.None;
30+
Request = request;
31+
Request.IncreaseNumAttempts();
32+
}
2933

3034
/// <summary>
3135
/// The RestRequest that was made to get this RestResponse
3236
/// </summary>
3337
/// <remarks>
3438
/// Mainly for debugging if ResponseStatus is not OK
3539
/// </remarks>
36-
public RestRequest? Request { get; set; }
40+
public RestRequest Request { get; set; }
3741

3842
/// <summary>
3943
/// MIME content type of response
@@ -125,7 +129,7 @@ public abstract class RestResponseBase {
125129
/// HTTP protocol version of the request
126130
/// </summary>
127131
public Version? Version { get; set; }
128-
132+
129133
/// <summary>
130134
/// Root element of the serialized response content, only works if deserializer supports it
131135
/// </summary>
@@ -146,4 +150,9 @@ public abstract class RestResponseBase {
146150
ResponseStatus.Completed => null,
147151
_ => throw ErrorException ?? new ArgumentOutOfRangeException(nameof(ResponseStatus))
148152
};
149-
}
153+
154+
internal void AddException(Exception exception) {
155+
ErrorException = exception;
156+
ErrorMessage = exception.Message;
157+
}
158+
}

src/RestSharp/RestClient.Async.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ public partial class RestClient {
2222
public async Task<RestResponse> ExecuteAsync(RestRequest request, CancellationToken cancellationToken = default) {
2323
var internalResponse = await ExecuteRequestAsync(request, cancellationToken).ConfigureAwait(false);
2424

25-
var response = new RestResponse();
26-
27-
response = internalResponse.Exception == null
25+
var response = internalResponse.Exception == null
2826
? await RestResponse.FromHttpResponse(
2927
internalResponse.ResponseMessage!,
3028
request,
@@ -34,10 +32,7 @@ public async Task<RestResponse> ExecuteAsync(RestRequest request, CancellationTo
3432
cancellationToken
3533
)
3634
.ConfigureAwait(false)
37-
: AddError(response, internalResponse.Exception, internalResponse.TimeoutToken);
38-
39-
response.Request = request;
40-
response.Request.IncreaseNumAttempts();
35+
: GetErrorResponse(request, internalResponse.Exception, internalResponse.TimeoutToken);
4136

4237
return Options.ThrowOnAnyError ? response.ThrowIfError() : response;
4338
}
@@ -69,13 +64,14 @@ public async Task<RestResponse> ExecuteAsync(RestRequest request, CancellationTo
6964
return await response.ResponseMessage.ReadResponse(cancellationToken).ConfigureAwait(false);
7065
}
7166

72-
static RestResponse AddError(RestResponse response, Exception exception, CancellationToken timeoutToken) {
73-
response.ResponseStatus = exception is OperationCanceledException
74-
? TimedOut() ? ResponseStatus.TimedOut : ResponseStatus.Aborted
75-
: ResponseStatus.Error;
76-
77-
response.ErrorMessage = exception.Message;
78-
response.ErrorException = exception;
67+
static RestResponse GetErrorResponse(RestRequest request, Exception exception, CancellationToken timeoutToken) {
68+
var response = new RestResponse(request) {
69+
ResponseStatus = exception is OperationCanceledException
70+
? TimedOut() ? ResponseStatus.TimedOut : ResponseStatus.Aborted
71+
: ResponseStatus.Error,
72+
ErrorMessage = exception.Message,
73+
ErrorException = exception
74+
};
7975

8076
return response;
8177

@@ -155,6 +151,6 @@ static HttpMethod AsHttpMethod(Method method)
155151
Method.Merge => new HttpMethod("MERGE"),
156152
Method.Copy => new HttpMethod("COPY"),
157153
Method.Search => new HttpMethod("SEARCH"),
158-
_ => throw new ArgumentOutOfRangeException()
154+
_ => throw new ArgumentOutOfRangeException(nameof(method))
159155
};
160156
}

src/RestSharp/RestClient.Extensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ [EnumeratorCancellation] CancellationToken cancellationToken
338338
#endif
339339
if (string.IsNullOrWhiteSpace(line)) continue;
340340

341-
var response = new RestResponse { Content = line };
341+
var response = new RestResponse(request) { Content = line };
342342
yield return serializer.Deserializer.Deserialize<T>(response)!;
343343
}
344344
}

src/RestSharp/RestSharp.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
44
</PropertyGroup>
55
<ItemGroup Condition="$(TargetFramework) != 'net6.0' And $(TargetFramework) != 'net7.0'">
6-
<PackageReference Include="System.Text.Json" Version="5.0.1"/>
6+
<PackageReference Include="System.Text.Json" Version="5.0.1" />
77
</ItemGroup>
88
<ItemGroup>
9-
<None Remove="RestSharp.csproj.DotSettings"/>
9+
<None Remove="RestSharp.csproj.DotSettings" />
1010
</ItemGroup>
1111
<ItemGroup Condition="'$(TargetFramework)' == 'net471'">
12-
<Reference Include="System.Net.Http"/>
13-
<Reference Include="System.Web"/>
14-
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All"/>
12+
<Reference Include="System.Net.Http" />
13+
<Reference Include="System.Web" />
14+
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All" />
1515
</ItemGroup>
1616
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
17-
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All"/>
17+
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All" />
1818
</ItemGroup>
1919
<ItemGroup>
2020
<Compile Update="RestClient.Extensions.Config.cs">
@@ -31,6 +31,6 @@
3131
</Compile>
3232
</ItemGroup>
3333
<ItemGroup>
34-
<ProjectReference Include="..\..\gen\SourceGenerator\SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
34+
<ProjectReference Include="..\..\gen\SourceGenerator\SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
3535
</ItemGroup>
3636
</Project>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright (c) .NET Foundation and Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
using System.Collections.ObjectModel;
17+
using RestSharp.Extensions;
18+
using RestSharp.Serializers.Xml;
19+
20+
namespace RestSharp.Serializers;
21+
22+
public class RestSerializers {
23+
public IReadOnlyDictionary<DataFormat, SerializerRecord> Serializers { get; }
24+
25+
public RestSerializers(Dictionary<DataFormat, SerializerRecord> records)
26+
=> Serializers = new ReadOnlyDictionary<DataFormat, SerializerRecord>(records);
27+
28+
public RestSerializers(SerializerConfig config) : this(config.Serializers) { }
29+
30+
public IRestSerializer GetSerializer(DataFormat dataFormat)
31+
=> Serializers.TryGetValue(dataFormat, out var value)
32+
? value.GetSerializer()
33+
: throw new InvalidOperationException($"Unable to find a serializer for {dataFormat}");
34+
35+
internal RestResponse<T> Deserialize<T>(RestRequest request, RestResponse raw, ReadOnlyRestClientOptions options) {
36+
var response = RestResponse<T>.FromResponse(raw);
37+
38+
try {
39+
request.OnBeforeDeserialization?.Invoke(raw);
40+
response.Data = DeserializeContent<T>(raw);
41+
}
42+
catch (Exception ex) {
43+
if (options.ThrowOnAnyError) throw;
44+
45+
if (options.FailOnDeserializationError || options.ThrowOnDeserializationError) response.ResponseStatus = ResponseStatus.Error;
46+
47+
response.AddException(ex);
48+
49+
if (options.ThrowOnDeserializationError) throw new DeserializationException(response, ex);
50+
}
51+
52+
return response;
53+
}
54+
55+
/// <summary>
56+
/// Deserialize the response content into the specified type
57+
/// </summary>
58+
/// <param name="response">Response instance</param>
59+
/// <typeparam name="T">Deserialized model type</typeparam>
60+
/// <returns></returns>
61+
[PublicAPI]
62+
public T? DeserializeContent<T>(RestResponse response) {
63+
// Only attempt to deserialize if the request has not errored due
64+
// to a transport or framework exception. HTTP errors should attempt to
65+
// be deserialized
66+
if (response.Content == null) {
67+
return default;
68+
}
69+
70+
// Only continue if there is a handler defined else there is no way to deserialize the data.
71+
// This can happen when a request returns for example a 404 page instead of the requested JSON/XML resource
72+
var deserializer = GetContentDeserializer(response);
73+
74+
if (deserializer is IXmlDeserializer xml && response.Request is RestXmlRequest xmlRequest) {
75+
if (xmlRequest.XmlNamespace.IsNotEmpty()) xml.Namespace = xmlRequest.XmlNamespace!;
76+
77+
if (xml is IWithDateFormat withDateFormat && xmlRequest.DateFormat.IsNotEmpty()) withDateFormat.DateFormat = xmlRequest.DateFormat!;
78+
}
79+
80+
return deserializer != null ? deserializer.Deserialize<T>(response) : default;
81+
}
82+
83+
IDeserializer? GetContentDeserializer(RestResponseBase response) {
84+
if (string.IsNullOrWhiteSpace(response.Content)) return null;
85+
86+
var contentType = response.ContentType ?? DetectContentType()?.Value;
87+
if (contentType == null) return null;
88+
89+
var serializer = Serializers.Values.FirstOrDefault(x => x.SupportsContentType(contentType));
90+
91+
var factory = serializer ??
92+
(Serializers.ContainsKey(response.Request.RequestFormat) ? Serializers[response.Request.RequestFormat] : null);
93+
return factory?.GetSerializer().Deserializer;
94+
95+
ContentType? DetectContentType()
96+
=> response.Content[0] switch {
97+
'<' => ContentType.Xml,
98+
'{' or '[' => ContentType.Json,
99+
_ => null
100+
};
101+
}
102+
}

0 commit comments

Comments
 (0)