FryProxy 2.0.0-alpha1

This is a prerelease version of FryProxy.
dotnet add package FryProxy --version 2.0.0-alpha1
                    
NuGet\Install-Package FryProxy -Version 2.0.0-alpha1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FryProxy" Version="2.0.0-alpha1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FryProxy" Version="2.0.0-alpha1" />
                    
Directory.Packages.props
<PackageReference Include="FryProxy" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FryProxy --version 2.0.0-alpha1
                    
#r "nuget: FryProxy, 2.0.0-alpha1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FryProxy@2.0.0-alpha1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FryProxy&version=2.0.0-alpha1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FryProxy&version=2.0.0-alpha1&prerelease
                    
Install as a Cake Tool

FryProxy

NuGet Version


A library for building RFC-compatible HTTP proxies. In its core is a customizable request processing pipeline, which consists from a chain of request handlers – each receiving a request object and next handler in chain. The final (last in chain) handler sends the request to its destination and returns the response up the chain. The initial set of handlers implement standard proxy behavior. Any number of handlers can be put in between. Each handler has complete control over produced response as well as other observable proxy behaviors (like connection lifetime).

Key facts

  • RFC compatible HTTP reverse proxy by default;
    • Only HTTP/1.1 for now;
    • HTTP/2.0 is planned for 2.0.0;
  • Composable asynchronous request pipeline;
  • Lightweight and simple HTTP abstraction;
  • Can decrypt tunneled traffic and pass it though the pipeline;
  • Outgoing connection pool (including decrypted tunneled);

Example

using FryProxy;
using FryProxy.Http;
using FryProxy.Pipeline;

using var proxy = new HttpProxy<DefaultContext>(
    LogRequestAndResponse,                  // request handler 
    new Settings(),                         // proxy settings
    OpaqueTunnel.Factory<DefaultContext>()  // creates secured tunnel
);

proxy.Start();                              // ...accept connections
Console.WriteLine($"Started at... {proxy.Endpoint}");
Thread.Sleep(Timeout.Infinite);

return;

async ValueTask<Tuple<Message<StatusLine>, DefaultContext>> LogRequestAndResponse(
    Message<RequestLine> request,           // request message
    RequestHandler<DefaultContext> next     // next handler in chain
)
{
    Console.WriteLine($"->{request}");
    
    var result = await next(request);

    Console.WriteLine($"<-{result.Item1}");

    return result;                          // response and context instance
}

Components

The library APIs are designed to work together, but can also be used individually. Below is an overview ordered by abstraction level from high to low.

FryProxy

FryProxy.HttpProxy is an HTTP proxy server listening for incoming connections and serving HTTP requests. It embeds provided request handler function into the pipeline handling request passing through. It also accepts a tunnel factory function, which is used to establish a secure (TLS) tunnel upon client request. Once established, a tunnel handles all subsequent traffic between client and tunnel destination until either connection times out or closes.

type 'T Tunnel = delegate of handler: 'T RequestHandlerChain * idleTimeout: TimeSpan -> Task
type TunnelConnectionFactory = delegate of (Stream -> Stream ValueTask) * Target -> IConnection ValueTask
type 'T TunnelFactory = delegate of TunnelConnectionFactory * Target * client: ReadBuffer -> 'T Tunnel ValueTask
FryProxy.OpaqueTunnel

Transfers encrypted traffic between client and server blindly (as intended by specification).

FryProxy.TransparentTunnel

Authenticates to both client and server on its own, decrypts the incoming traffic, passes it through the request processing pipeline and encrypts it back when sending to peer. It offers multiple factories:

  • Factory accepts standard dotnet client and server authentication options offering maximum flexibility;
  • NaiveFactoryWithServerCertificate creates tunnel accepting any server certificate and using the provided certificate for authenticating clients;
  • NaiveFactoryWithSelfSignedCertificate creates tunnel accepting any server certificate and using an autogenerated self-signed certificate for authenticating clients;
FryProxy.DefaultContext

Satisfies the content requirements imposed by all built-in request handlers used by the default http proxy.


FryProxy.Pipeline

HTTP request processing pipeline is composed of individual handlers forming chain of responsibility. Each handler is an asynchronous function from request message to response message and context values, which are propagated up the chain. Context values are used by proxy server (below) to decide the lifetime of incoming and outgoing connections and for establishing a secure tunnel. APIs allow modifying those built-in values to certain extent, as well as adding custom values (for coordinating complex handler chain).

type 'Context ContextualResponse = (ResponseMessage * 'Context) ValueTask
type 'O RequestHandler = delegate of request: RequestMessage -> 'O ContextualResponse
type 'O RequestHandlerChain = delegate of request: RequestMessage * next: 'O RequestHandler -> 'O ContextualResponse

FryProxy.Http

Set of simple and lightweight HTTP abstractions closely following HTTP semantic as define in specifications:

  • request and status lines;
  • generic field (headers);
  • specific fields models (FryProxy.Http.Fields);
  • request and response messages;
  • predefined parsers for the above (FryProxy.Http.Parse).

While HTTP header (first line + fields) is read completely when HTTP message is parsed from a stream, message content (unless empty) – is not. It is read only when needed – either when message is written to a different stream or content is copied explicitly.

[<Struct>]
type 'L MessageHeader when 'L :> StartLine = { StartLine: 'L; Fields: Field List }

[<Struct>]
type MessageBody =
    | Empty
    | Sized of Content: IByteBuffer
    | Chunked of Chunks: Chunk IAsyncEnumerable
    
[<Struct>]
type 'L Message when 'L :> StartLine = { Header: 'L MessageHeader; Body: MessageBody }

type RequestMessage = RequestLine Message
type ResponseMessage = StatusLine Message

FryProxy.IO

Operates on raw sequence or stream of bytes and provides facilities (FryProxy.IO.BufferedParser) for parsing buffered byte stream (FryProxy.IO.ReadBuffer) into something else. Notable types include:

  • FryProxy.IO.ReadBuffer – wraps a stream and memory buffer and allows incrementally reading and exploring the stream content through buffer;
  • FryProxy.IO.IByteBuffer – lazy loaded (copied) sequence of bytes of a known lenght; useful for representing HTTP message body without eagerly reading it into memory;
  • FryProxy.IO.ConnectionPool – pool of outgoing network connections;
  • FryProxy.IO.BufferedParser – parser and combinators incrementally consuming bytes from ReadBuffer and transforming them into something else (like HTTP message below);
[<Struct>]
type ActiveState = { Offset: uint16 }

[<Struct>]
type ParseState =
    | Running of Active: ActiveState
    | Yielded of Paused: IConsumable

type 'a ParseResult = (ParseState * 'a) ValueTask
type 'a Parser = ReadBuffer * ParseState -> 'a ParseResult
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0-alpha1 190 10/24/2024
1.2.1 1,471 6/5/2019
1.2.0 1,278 9/21/2018
1.1.18 15,554 1/13/2017
1.1.15 2,173 8/30/2015
1.1.14 1,552 8/16/2015
1.1.13 1,809 8/2/2015
1.1.12 1,652 6/21/2015
1.1.11 1,795 3/29/2015
1.1.10 1,660 3/22/2015
1.1.9 1,632 3/21/2015
1.1.8 1,577 3/17/2015
1.1.7 1,595 3/15/2015
1.1.6 2,054 12/9/2014
1.1.5 1,860 12/9/2014
1.1.4 1,881 12/9/2014
1.1.3 1,852 12/9/2014
1.1.2 1,835 12/5/2014
1.1.1 1,829 12/5/2014
1.1.0 1,848 12/5/2014
1.0.9 1,866 11/21/2014
1.0.8 1,818 11/21/2014
1.0.7 2,106 11/19/2014
1.0.6 1,897 11/19/2014
1.0.5 1,976 11/14/2014
1.0.4 2,344 11/12/2014
1.0.3 2,324 11/11/2014
1.0.2 1,972 11/11/2014
1.0.1 1,950 11/11/2014
1.0.0 2,020 11/9/2014

Complete revrite in F#