-
-
Save panesofglass/1059017 to your computer and use it in GitHub Desktop.
An attempt to improve on OWIN<http://owin.org> in F#.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
// # 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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