Skip to content

Commit

Permalink
PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK committed May 14, 2022
1 parent 8d9de0c commit 6c20516
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json;
Expand All @@ -14,6 +15,7 @@
using Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;

Expand Down Expand Up @@ -290,9 +292,6 @@ public static async Task<TRequest> ReadMessage<TRequest>(JsonTranscodingServerCa

private static async ValueTask<IMessage> ReadHttpBodyAsync(JsonTranscodingServerCallContext serverCallContext)
{
var ms = new MemoryStream();
await serverCallContext.HttpContext.Request.Body.CopyToAsync(ms);

var httpBody = (IMessage)Activator.CreateInstance(serverCallContext.DescriptorInfo.BodyDescriptor!.ClrType)!;

var contentType = serverCallContext.HttpContext.Request.ContentType;
Expand All @@ -301,14 +300,40 @@ private static async ValueTask<IMessage> ReadHttpBodyAsync(JsonTranscodingServer
httpBody.Descriptor.Fields[HttpBody.ContentTypeFieldNumber].Accessor.SetValue(httpBody, contentType);
}

var data = ms.TryGetBuffer(out var buffer)
? UnsafeByteOperations.UnsafeWrap(buffer.AsMemory())
: UnsafeByteOperations.UnsafeWrap(ms.ToArray());
httpBody.Descriptor.Fields[HttpBody.DataFieldNumber].Accessor.SetValue(httpBody, data);
var data = await ReadDataAsync(serverCallContext);
httpBody.Descriptor.Fields[HttpBody.DataFieldNumber].Accessor.SetValue(httpBody, UnsafeByteOperations.UnsafeWrap(data));

return httpBody;
}

private static async ValueTask<byte[]> ReadDataAsync(JsonTranscodingServerCallContext serverCallContext)
{
// Buffer to disk if content is larger than 30Kb.
// Based on value in XmlSerializer and NewtonsoftJson input formatters.
const int DefaultMemoryThreshold = 1024 * 30;

var memoryThreshold = DefaultMemoryThreshold;
var contentLength = serverCallContext.HttpContext.Request.ContentLength.GetValueOrDefault();
if (contentLength > 0 && contentLength < memoryThreshold)
{
// If the Content-Length is known and is smaller than the default buffer size, use it.
memoryThreshold = (int)contentLength;
}

using var fs = new FileBufferingReadStream(serverCallContext.HttpContext.Request.Body, memoryThreshold);

// Read the request body into buffer.
// No explicit cancellation token. Request body uses underlying request aborted token.
await fs.DrainAsync(CancellationToken.None);
fs.Seek(0, SeekOrigin.Begin);

var data = new byte[fs.Length];
var read = fs.Read(data);
Debug.Assert(read == data.Length);

return data;
}

private static List<FieldDescriptor>? GetPathDescriptors(JsonTranscodingServerCallContext serverCallContext, IMessage requestMessage, string path)
{
return serverCallContext.DescriptorInfo.PathDescriptorsCache.GetOrAdd(path, p =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,60 @@ public async Task HandleCallAsync_HttpBodyRequest_RawRequestAvailable()
Assert.Equal(@"Hello World!", responseJson.RootElement.GetProperty("message").GetString());
}

[Theory]
[InlineData(1, false)]
[InlineData(1, true)]
[InlineData(16 * 1024, false)]
[InlineData(16 * 1024, true)]
[InlineData(1024 * 1024, false)]
[InlineData(1024 * 1024, true)]
public async Task HandleCallAsync_HttpBodyRequestLarge_RawRequestAvailable(int requestSize, bool sendContentLength)
{
// Arrange
string? requestContentType = null;
byte[]? requestData = null;
UnaryServerMethod<JsonTranscodingGreeterService, HttpBody, HelloReply> invoker = (s, r, c) =>
{
requestContentType = r.ContentType;
requestData = r.Data.ToByteArray();
return Task.FromResult(new HelloReply { Message = $"Hello {requestData.Length}!" });
};

var unaryServerCallHandler = CreateCallHandler(
invoker,
CreateServiceMethod("HttpRequestBody", HttpBody.Parser, HelloReply.Parser),
descriptorInfo: TestHelpers.CreateDescriptorInfo(bodyDescriptor: HttpBody.Descriptor));

var httpContext = TestHelpers.CreateHttpContext();
httpContext.Request.ContentType = "application/octet-stream";

var requestContent = new byte[requestSize];
for (var i = 0; i < requestContent.Length; i++)
{
requestContent[i] = (byte)(i % 10);
}
httpContext.Request.Body = new MemoryStream(requestContent);
if (sendContentLength)
{
httpContext.Request.ContentLength = requestSize;
}

// Act
await unaryServerCallHandler.HandleCallAsync(httpContext);

// Assert
Assert.Equal("application/octet-stream", requestContentType);
Assert.Equal(requestContent, requestData);

Assert.Equal(200, httpContext.Response.StatusCode);
Assert.Equal("application/json; charset=utf-8", httpContext.Response.ContentType);

httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
using var responseJson = JsonDocument.Parse(httpContext.Response.Body);
Assert.Equal($"Hello {requestContent.Length}!", responseJson.RootElement.GetProperty("message").GetString());
}

[Fact]
public async Task HandleCallAsync_NullBody_WrapperType_Error()
{
Expand Down

0 comments on commit 6c20516

Please sign in to comment.