[fix] Fix handling for Streams in IConnection for raw content (#2791)

* Fix handling for Streams

Fix `NullReferenceException` if raw content was handled as a string rather than a stream by `HttpClientAdapter.BuildResponse()`.
Resolves #2789.

* Add Connection.GetRaw tests

Add tests for `Connection.GetRaw()` and for #2789.

---------

Co-authored-by: Keegan Campbell <me@kfcampbell.com>
This commit is contained in:
Martin Costello
2023-11-07 00:47:30 +00:00
committed by GitHub
parent c015d8ce53
commit 4f826bc65b
2 changed files with 117 additions and 2 deletions
+110
View File
@@ -416,6 +416,116 @@ namespace Octokit.Tests.Http
}
}
public class TheGetRawMethod
{
[Fact]
public async Task SendsProperlyFormattedRequestWithProperAcceptHeader()
{
var httpClient = Substitute.For<IHttpClient>();
var response = CreateResponse(HttpStatusCode.OK);
httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response));
var connection = new Connection(new ProductHeaderValue("OctokitTests"),
_exampleUri,
Substitute.For<ICredentialStore>(),
httpClient,
Substitute.For<IJsonSerializer>());
await connection.GetRaw(new Uri("endpoint", UriKind.Relative), new Dictionary<string, string>());
httpClient.Received(1).Send(Arg.Is<IRequest>(req =>
req.BaseAddress == _exampleUri &&
req.ContentType == null &&
req.Body == null &&
req.Method == HttpMethod.Get &&
req.Headers["Accept"] == "application/vnd.github.v3.raw" &&
req.Endpoint == new Uri("endpoint", UriKind.Relative)), Args.CancellationToken);
}
[Fact]
public async Task SendsProperlyFormattedRequestWithProperAcceptHeaderAndTimeout()
{
var httpClient = Substitute.For<IHttpClient>();
var response = CreateResponse(HttpStatusCode.OK);
httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response));
var connection = new Connection(new ProductHeaderValue("OctokitTests"),
_exampleUri,
Substitute.For<ICredentialStore>(),
httpClient,
Substitute.For<IJsonSerializer>());
await connection.GetRaw(new Uri("endpoint", UriKind.Relative), new Dictionary<string, string>(), TimeSpan.FromSeconds(1));
httpClient.Received(1).Send(Arg.Is<IRequest>(req =>
req.BaseAddress == _exampleUri &&
req.Timeout == TimeSpan.FromSeconds(1) &&
req.ContentType == null &&
req.Body == null &&
req.Method == HttpMethod.Get &&
req.Headers["Accept"] == "application/vnd.github.v3.raw" &&
req.Endpoint == new Uri("endpoint", UriKind.Relative)), Args.CancellationToken);
}
[Fact]
public async Task ReturnsCorrectContentForNull()
{
object body = null;
var httpClient = Substitute.For<IHttpClient>();
var response = CreateResponse(HttpStatusCode.OK, body);
httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response));
var connection = new Connection(new ProductHeaderValue("OctokitTests"),
_exampleUri,
Substitute.For<ICredentialStore>(),
httpClient,
Substitute.For<IJsonSerializer>());
var actual = await connection.GetRaw(new Uri("endpoint", UriKind.Relative), new Dictionary<string, string>());
Assert.NotNull(actual);
Assert.Null(actual.Body);
}
[Fact]
public async Task ReturnsCorrectContentForByteArray()
{
var body = new byte[] { 1, 2, 3 };
var httpClient = Substitute.For<IHttpClient>();
var response = CreateResponse(HttpStatusCode.OK, body);
httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response));
var connection = new Connection(new ProductHeaderValue("OctokitTests"),
_exampleUri,
Substitute.For<ICredentialStore>(),
httpClient,
Substitute.For<IJsonSerializer>());
var actual = await connection.GetRaw(new Uri("endpoint", UriKind.Relative), new Dictionary<string, string>());
Assert.NotNull(actual);
Assert.Equal(body, actual.Body);
}
[Fact]
public async Task ReturnsCorrectContentForStream()
{
var bytes = new byte[] { 1, 2, 3 };
var body = new MemoryStream(bytes);
var httpClient = Substitute.For<IHttpClient>();
var response = CreateResponse(HttpStatusCode.OK, body);
httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response));
var connection = new Connection(new ProductHeaderValue("OctokitTests"),
_exampleUri,
Substitute.For<ICredentialStore>(),
httpClient,
Substitute.For<IJsonSerializer>());
var actual = await connection.GetRaw(new Uri("endpoint", UriKind.Relative), new Dictionary<string, string>());
Assert.NotNull(actual);
Assert.Equal(bytes, actual.Body);
}
}
public class ThePatchMethod
{
[Fact]
+7 -2
View File
@@ -714,8 +714,13 @@ namespace Octokit
{
request.Headers.Add("Accept", AcceptHeaders.RawContentMediaType);
var response = await RunRequest(request, CancellationToken.None).ConfigureAwait(false);
return new ApiResponse<byte[]>(response, await StreamToByteArray(response.Body as Stream));
if (response.Body is Stream stream)
{
return new ApiResponse<byte[]>(response, await StreamToByteArray(stream));
}
return new ApiResponse<byte[]>(response, response.Body as byte[]);
}
async Task<IApiResponse<Stream>> GetRawStream(IRequest request)