Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save panesofglass/1059017 to your computer and use it in GitHub Desktop.
Save panesofglass/1059017 to your computer and use it in GitHub Desktop.
An attempt to improve on OWIN<http://owin.org> in F#.
(*
// # FSCGI - F# Common Gateway Interface
//
// This gist is a response to OWIN <http://owin.org/>.
// This gist is public domain.
//
// See also the discussion stating OWIN rationale and how it is better than FSCGI:
// http://groups.google.com/group/net-http-abstractions/browse_thread/thread/ac3d7c1e3d43c1d4
//
// ## Problem Summary
//
// The goal of OWIN is to provide a low-level .NET standard for web apps to
// communicate with their environments, filling the similar role as Java
// Servlet Specification, FastCGI, SCGI (Python) and the like.
//
// OWIN as of Mar 13, 2011 is problematic in the following respects:
//
// * poor use of static typing, for example uses Dictionary<String,Object>
// * gratuitous complexity of the definition (nested Func<_> callbacks)
// * reliance on prose to communicate invariants that can be type-enforced
//
// ## Solution Summary
//
// * use more explicit typing
// * use an iteratee-based representation for the IO process
// * simplify exception handling by the rule: application code MUST NOT throw
// any exceptions; doing so is indicating a programming error and will be
// treated in a host-dependent way.
//
*)
/// Defines the common gateway interface protocol for F#.
namespace FSCGI
type Data = System.ArraySegment<byte>
type Headers = Map<string,string>
type StatusCode = int
type Status = string
type Request =
{
Headers : Headers
Method : string
Path : string
PathBase : string
QueryString : string
Scheme : string
}
type State =
| Closed
| Open
type Writer =
| Done
| Write of (State -> Data * Writer)
type Response =
| Read of (option<Data> -> Response)
| Respond of StatusCode * Status * Headers * Writer
type Application =
Request -> Response
/// Converts structural encodings to proper FSCGI.* types.
module FSCGI.Structural.Converter
type private Encodings<'R,'W> =
('W -> Writer<'W>) *
('R -> Response<'R,'W>)
let private ConvertRequest (r : FSCGI.Request) : Request =
(
r.Headers,
r.Method,
r.Path,
r.PathBase,
r.QueryString,
r.Scheme
)
let rec private ConvertWriter ((eW, _) as enc : Encodings<'R,'W>)
(w: Writer<'W>) : FSCGI.Writer =
match w with
| Choice1Of2 () ->
FSCGI.Done
| Choice2Of2 f ->
FSCGI.Write (fun state ->
let isOpen =
match state with
| FSCGI.Closed -> false
| FSCGI.Open -> true
let (data, writer) = f isOpen
(data, ConvertWriter enc (eW writer)))
let rec private ConvertResponse ((eW, eR) as enc : Encodings<'R,'W>)
(r: Response<'R,'W>) : FSCGI.Response =
match r with
| Choice1Of2 f ->
FSCGI.Read (fun d -> ConvertResponse enc (eR (f d)))
| Choice2Of2 (a, b, c, d) ->
FSCGI.Respond (a, b, c, ConvertWriter enc (eW d))
let Convert ((eW, eR, run): Application<'R,'W>) : FSCGI.Application =
ConvertResponse (eW, eR) << run << ConvertRequest
/// Provides structural encodings for the FSCGI.* types.
namespace FSCGI.Structural
type Data = System.ArraySegment<byte>
type HeaderName = string
type HeaderValue = string
type Headers = Map<HeaderName,HeaderValue>
type Method = string
type Path = string
type PathBase = string
type QueryString = string
type Scheme = string
type StatusCode = int
type Status = string
type Request =
Headers * Method * Path * PathBase * QueryString * Scheme
type Writer<'W> =
Choice<
unit,
bool -> Data * 'W
>
type Response<'R,'W> =
Choice<
option<Data> -> 'R,
StatusCode * Status * Headers * 'W
>
type Application<'R,'W> =
('W -> Writer<'W>) *
('R -> Response<'R,'W>) *
(Request -> Response<'R,'W>)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment