@@ -9,7 +9,6 @@ type SHttpMethod = HttpMethod
99open logibit.hawk
1010open logibit.hawk .Types
1111open logibit.hawk .Server
12- open logibit.hawk .Choice
1312
1413module private Impl =
1514 open Microsoft.FSharp .Reflection
@@ -46,47 +45,88 @@ module private Impl =
4645[<Literal>]
4746let HawkDataKey = " logibit.hawk.data"
4847
49- let auth_ctx ( s : Settings < 'a >) =
50- fun ({ request = s_req } as ctx ) ->
51-
52- let ub = UriBuilder ( s_ req.url)
53- ub.Host <- s_ req.host.value
54-
55- Binding.header " authorization" Choice1Of2 s_ req
56- >>= ( fun header ->
57- Binding.header " host" Choice1Of2 s_ req
58- >>- fun host -> header, host)
48+ /// ReqFactory :: Settings<'a> -> HttpContext -> Choice<Req, string>
49+ ///
50+ /// You can bind the last argument to a function
51+ /// that maps your request changing function into the choice. Or in code:
52+ ///
53+ /// let plx_goto_8080_MR s =
54+ /// bind_req s
55+ /// // when you've bound the request, apply the following function to
56+ /// // the return value (the Choice of req or a string error)
57+ /// >> (fun mreq ->
58+ /// // map over the OK result (non error case), see
59+ /// // https://github.com/logibit/logibit.hawk#logibithawkchoice
60+ /// mreq >>- (fun req ->
61+ /// // and change the port so we can find our way:
62+ /// { req with port = Some 8080us }))
63+ type ReqFactory < 'a > = Settings< 'a> -> HttpContext -> Choice< Req, string>
64+
65+ open logibit.hawk .Choice // Choice's binding of >>=
66+
67+ let bind_req ( s : Settings < 'a >)
68+ ({ request = s_req } as ctx )
69+ : Choice < Req , string > =
70+
71+ let ub = UriBuilder ( s_ req.url)
72+ ub.Host <- s_ req.host.value
73+
74+ Binding.header " authorization" Choice1Of2 s_ req
75+ >>= ( fun header ->
76+ Binding.header " host" Choice1Of2 s_ req
77+ >>- fun host -> header, host)
78+ >>- ( fun ( auth , host ) ->
79+ { `` method `` = Impl.from_ suave_ method s_ req.`` method ``
80+ uri = ub.Uri
81+ authorisation = auth
82+ payload = if s_ req.raw_ form.Length = 0 then None else Some ctx.request.raw_ form
83+ host = None
84+ port = None
85+ content_ type = " content-type" |> HttpRequest.header ctx.request })
86+
87+ // Example functor of the bind_req function:
88+ //let bind_req' s =
89+ // bind_req s >> (fun mreq -> mreq >>- (fun req -> { req with port = Some 8080us }))
90+
91+ let auth_ctx ( s : Settings < 'a >) ( f_req : ReqFactory < 'a >) =
92+ fun ctx ->
93+ f_ req s ctx
5994 >>@ AuthError.Other
60- >>= ( fun ( auth , host ) ->
61- let req =
62- { `` method `` = Impl.from_ suave_ method s_ req.`` method ``
63- uri = ub.Uri
64- authorisation = auth
65- payload = if s_ req.raw_ form.Length = 0 then None else Some ctx.request.raw_ form
66- host = None
67- port = None
68- content_ type = " content-type" |> HttpRequest.header ctx.request }
69- Server.authenticate s req)
95+ >>= Server.authenticate s
96+
97+ let auth_ctx ' s = auth_ ctx s bind_ req
7098
7199open Suave.Http // this changes binding of >>=
72100
73- /// Authenticate the request with the given settings and a
74- /// continuation functor for both the successful case and the
75- /// unauthorised case.
101+ /// Authenticate the request with the given settings, and a request
102+ /// getting function (ReqFactory) and then a continuation functor for
103+ /// both the successful case and the unauthorised case.
76104///
77105/// This will also set ` HawkDataKey ` in the ` user_state ` dictionary.
78- let authenticate ( s : Settings < _ >)
106+ ///
107+ /// You might want to use authenticate' unless you're running behind
108+ /// a load balancer and need to replace your ` bind_req ` function (in this
109+ /// module) with something of your own.
110+ ///
111+ /// Also see the comments on the ReqFactory type for docs on how to contruct
112+ /// your own Req value, or re-map the default one.
113+ let authenticate ( s : Settings < 'a >)
114+ ( f_req : ReqFactory < 'a >)
79115 ( f_cont : _ -> WebPart )
80116 ( f_err : AuthError -> WebPart )
81117 : WebPart =
82118 fun ctx ->
83- match auth_ ctx s ctx with
119+ match auth_ ctx s f _ req ctx with
84120 | Choice1Of2 res ->
85121 ( Writers.set_ user_ data HawkDataKey res
86122 >>= f_ cont res) ctx
87123 | Choice2Of2 err ->
88124 f_ err err ctx
89125
126+ /// Like ` authenticate ` but with the default request factory function.
127+ let authenticate ' s =
128+ authenticate s bind_ req
129+
90130module HttpContext =
91131
92132 /// Find the Hawk auth data from the context.
0 commit comments