• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ThreeMammals / Ocelot / 26241073880

21 May 2026 05:06PM UTC coverage: 95.327% (+0.6%) from 94.721%
26241073880

push

github

raman-m
Ref SDK 10.0.300 (Runtime 10.0.8) to release Ocelot v25 beta 3 and Ocelot.Testing v25 beta 8+ (#2389)

* Prepare to release Ocelot.Testing v25.0.0-beta.8 package
* Bump all packages to the latest versions, including .NET SDK 10.0.203 (Runtime 10.0.7) released April 21, 2026
* Migrate unit testing from VSTest framework to Microsoft.Testing.Platform
* Do not use 'Cake Build' step in PR workflow, use plain dotnet scripting instead
* Fix "Unit Tests" step in PR workflow
* Rename job to "build" since it's not Cake anymore
* Suppress non-zero result and check test running status
* Update "Acceptance Tests" step
* Don't collect Coverlet code coverage data in "Acceptance Tests" step
* Update prepare-coveralls.sh
* Prepare Coveralls script v2
* Prepare Coveralls script v3
* Prepare Coveralls script v4
* Prepare Coveralls script v5 -> Add 2nd BUILD_CONFIGURATION argument
* Upgrade to SDK 10.0.300 aka Runtime 10.0.8
* Update samples
* Update workflows: prefer plain dotnet scripting over Cake Build

6752 of 7083 relevant lines covered (95.33%)

2730.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.58
src/Ocelot/Request/Mapper/StreamHttpContent.cs
1
using Microsoft.AspNetCore.Http;
2
using System.Buffers;
3

4
namespace Ocelot.Request.Mapper;
5

6
public class StreamHttpContent : HttpContent
7
{
8
    private const int DefaultBufferSize = 65536;
9
    public const long UnknownLength = -1;
10
    private readonly HttpContext _context;
11
    private readonly long _contentLength;
12

13
    public StreamHttpContent(HttpContext context)
10✔
14
    {
10✔
15
        _context = context ?? throw new ArgumentNullException(nameof(context));
10✔
16
        _contentLength = context.Request.ContentLength ?? UnknownLength;
10✔
17
    }
10✔
18

19
    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
20
        => CopyAsync(_context.Request.Body, stream, _contentLength, false, cancellationToken);
5✔
21

22
    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
23
        => CopyAsync(_context.Request.Body, stream, _contentLength, false, CancellationToken.None);
×
24

25
    protected override bool TryComputeLength(out long length)
26
    {
2✔
27
        length = _contentLength;
2✔
28
        return length >= 0;
2✔
29
    }
2✔
30

31
    // This is used internally by HttpContent.ReadAsStreamAsync(...)
32
    protected override Task<Stream> CreateContentReadStreamAsync()
33
    {
×
34
        // Nobody should be calling this...
35
        throw new NotImplementedException();
×
36
    }
37

38
    private static async Task CopyAsync(Stream input, Stream output, long announcedContentLength,
39
        bool autoFlush, CancellationToken cancellation)
40
    {
8✔
41
        // For smaller payloads, avoid allocating a buffer that is larger than the announced content length
42
        var minBufferSize = announcedContentLength != UnknownLength && announcedContentLength < DefaultBufferSize
8✔
43
            ? (int)announcedContentLength
8✔
44
            : DefaultBufferSize;
8✔
45

46
        var buffer = ArrayPool<byte>.Shared.Rent(minBufferSize);
8✔
47
        long contentLength = 0;
8✔
48
        try
49
        {
8✔
50
            while (true)
14✔
51
            {
14✔
52
                // Issue a zero-byte read to the input stream to defer buffer allocation until data is available.
53
                // Note that if the underlying stream does not supporting blocking on zero byte reads, then this will
54
                // complete immediately and won't save any memory, but will still function correctly.
55
                var zeroByteReadTask = input.ReadAsync(Memory<byte>.Empty, cancellation);
14✔
56
                if (zeroByteReadTask.IsCompletedSuccessfully)
14✔
57
                {
14✔
58
                    // Consume the ValueTask's result in case it is backed by an IValueTaskSource
59
                    // It is save to read the Result once after the ValueTask has completed, and we've checked for complition by IsCompletedSuccessfully property
60
                    // See remarks: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1.result?view=net-8.0#remarks
61
                    _ = zeroByteReadTask.Result; // No need to await the task by .GetAwaiter().GetResult()
14✔
62
                }
14✔
63
                else
64
                {
×
65
                    // Take care not to return the same buffer to the pool twice in case zeroByteReadTask throws
66
                    var bufferToReturn = buffer;
×
67
                    buffer = null;
×
68
                    ArrayPool<byte>.Shared.Return(bufferToReturn);
×
69

70
                    await zeroByteReadTask;
×
71

72
                    buffer = ArrayPool<byte>.Shared.Rent(minBufferSize);
×
73
                }
×
74

75
                var read = await input.ReadAsync(buffer.AsMemory(), cancellation);
14✔
76
                contentLength += read;
14✔
77

78
                // Normally this is enforced by the server, but it could get out of sync if something in the proxy modified the body.
79
                if (announcedContentLength != UnknownLength && contentLength > announcedContentLength)
14✔
80
                {
1✔
81
                    throw new InvalidOperationException($"More data ({contentLength} bytes) received than the specified Content-Length of {announcedContentLength} bytes.");
1✔
82
                }
83

84
                // End of the source stream.
85
                if (read == 0)
13✔
86
                {
7✔
87
                    if (announcedContentLength == UnknownLength || contentLength == announcedContentLength)
7✔
88
                    {
7✔
89
                        return;
7✔
90
                    }
91
                    else
92
                    {
×
93
                        throw new InvalidOperationException($"Sent {contentLength} request content bytes, but Content-Length promised {announcedContentLength}.");
×
94
                    }
95
                }
96

97
                await output.WriteAsync(buffer.AsMemory(0, read), cancellation);
6✔
98
                if (autoFlush)
6✔
99
                {
×
100
                    // HttpClient doesn't always flush outgoing data unless the buffer is full or the caller asks.
101
                    // This is a problem for streaming protocols like WebSockets and gRPC.
102
                    await output.FlushAsync(cancellation);
×
103
                }
×
104
            }
6✔
105
        }
106
        finally
107
        {
8✔
108
            if (buffer != null)
8✔
109
            {
8✔
110
                ArrayPool<byte>.Shared.Return(buffer);
8✔
111
            }
8✔
112
        }
8✔
113
    }
7✔
114
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc