Skip to content

Commit

Permalink
feat: Add initial support for gRPC integration.
Browse files Browse the repository at this point in the history
  • Loading branch information
mayuki committed Oct 10, 2019
1 parent 55e38ae commit e004feb
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 9 deletions.
11 changes: 5 additions & 6 deletions src/Rin/Extensions/ResponseDataCaptureStreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
using Microsoft.AspNetCore.Http;
using Rin.Features;
using Rin.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;

namespace Rin.Extensions
{
public static class ResponseDataCaptureStreamExtensions
{
public static void EnableResponseDataCapturing(this HttpContext context)
{
var captureDataStream = new DataCaptureStream(context.Response.Body);
context.Response.Body = captureDataStream;
var originalResponseBodyFeature = context.Features.Get<IHttpResponseBodyFeature>();
var captureFeature = new CaptureHttpResponseBodyFeature(originalResponseBodyFeature);
context.Features.Set<IHttpResponseBodyFeature>(captureFeature);

context.Features.Get<IRinRequestRecordingFeature>().ResponseDataStream = captureDataStream;
context.Features.Get<IRinRequestRecordingFeature>().ResponseDataStream = captureFeature.CaptureStream;
}
}
}
51 changes: 51 additions & 0 deletions src/Rin/Features/CaptureHttpResponseBodyFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.IO;
using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Rin.IO;

namespace Rin.Features
{
public class CaptureHttpResponseBodyFeature : IHttpResponseBodyFeature
{
private readonly IHttpResponseBodyFeature _responseBodyFeature;
private readonly CapturePipeWriter _capturePipeWriter;
private readonly DataCaptureStream _captureStream;
private readonly MemoryStream _capturedDataStream;

public DataCaptureStream CaptureStream => _captureStream;

public CaptureHttpResponseBodyFeature(IHttpResponseBodyFeature responseBodyFeature)
{
_responseBodyFeature = responseBodyFeature;
_capturedDataStream = new MemoryStream();
_captureStream = new DataCaptureStream(responseBodyFeature.Stream, _capturedDataStream);
_capturePipeWriter = new CapturePipeWriter(responseBodyFeature.Writer, _capturedDataStream);
}

public Task CompleteAsync()
{
return _responseBodyFeature.CompleteAsync();
}

public void DisableBuffering()
{
_responseBodyFeature.DisableBuffering();
}

public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellationToken = default)
{
return _responseBodyFeature.SendFileAsync(path, offset, count, cancellationToken);
}

public Task StartAsync(CancellationToken cancellationToken = default)
{
return _responseBodyFeature.StartAsync(cancellationToken);
}

public Stream Stream => _captureStream;

public PipeWriter Writer => _capturePipeWriter;
}
}
52 changes: 52 additions & 0 deletions src/Rin/IO/CapturePipeWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.IO;
using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;

namespace Rin.IO
{
public class CapturePipeWriter : PipeWriter
{
private readonly PipeWriter _pipeWriter;
private readonly MemoryStream _capturedDataStream;

public CapturePipeWriter(PipeWriter pipeWriter, MemoryStream capturedDataStream)
{
_pipeWriter = pipeWriter;
_capturedDataStream = capturedDataStream;
}

public override void Advance(int bytes)
{
_capturedDataStream.Write(_pipeWriter.GetSpan(bytes).Slice(0, bytes));

_pipeWriter.Advance(bytes);
}

public override Memory<byte> GetMemory(int sizeHint = 0)
{
return _pipeWriter.GetMemory(sizeHint);
}

public override Span<byte> GetSpan(int sizeHint = 0)
{
return _pipeWriter.GetSpan(sizeHint);
}

public override void CancelPendingFlush()
{
_pipeWriter.CancelPendingFlush();
}

public override void Complete(Exception exception = null)
{
_pipeWriter.Complete(exception);
}

public override ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken = new CancellationToken())
{
return _pipeWriter.FlushAsync(cancellationToken);
}
}
}
6 changes: 3 additions & 3 deletions src/Rin/IO/DataCaptureStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ namespace Rin.IO
{
public class DataCaptureStream : Stream
{
private readonly MemoryStream _capturedData = new MemoryStream();
private readonly MemoryStream _capturedData;
private readonly Stream _innerStream;

public DataCaptureStream(Stream stream)
public DataCaptureStream(Stream stream, MemoryStream capturedDataStream = null)
{
_innerStream = stream;
_capturedData = new MemoryStream();
_capturedData = capturedDataStream ?? new MemoryStream();
}

public byte[] GetCapturedData() => _capturedData.ToArray();
Expand Down

0 comments on commit e004feb

Please sign in to comment.