22% % @copyright 2016-2022 Marc Worrell
33% %
44% % @doc Cowmachine: webmachine middleware for Cowboy/Zotonic
5+ % % @end
56
67% % Copyright 2016-2022 Marc Worrell
78% %
3435-include (" cowmachine_state.hrl" ).
3536-include (" cowmachine_log.hrl" ).
3637
38+ % % @private
39+ -export_type ([cmstate / 0 ]).
40+
3741% % @doc Cowboy middleware, route the new request. Continue with the cowmachine,
3842% % requests a redirect or return a 400 on an unknown host.
39- -spec execute (Req , Env ) -> { ok , Req , Env } | { stop , Req }
43+ -spec execute (Req , Env ) -> Result
4044 when Req :: cowboy_req :req (),
41- Env :: cowboy_middleware :env ().
45+ Env :: cowboy_middleware :env (),
46+ Result :: {ok , Req , Env } | {stop , Req }.
4247execute (Req , #{ cowmachine_controller := _Controller } = Env ) ->
4348 ContextEnv = maps :get (cowmachine_context , Env , undefined ),
4449 Context = cowmachine_req :init_context (Req , Env , ContextEnv ),
@@ -47,10 +52,13 @@ execute(Req, #{ cowmachine_controller := _Controller } = Env) ->
4752
4853% % @doc Handle a request, executes the cowmachine http states. Can be used by middleware
4954% % functions to add some additional initialization of controllers or context.
50- -spec request (Context , Options :: map ()) -> {ok , Req , Env } | {stop , Req }
55+
56+ -spec request (Context , Options ) -> Result
5157 when Context :: cowmachine_req :context (),
52- Req :: cowboy_req :req (),
53- Env :: cowboy_middleware :env ().
58+ Options :: map (),
59+ Req :: cowboy_req :req (),
60+ Env :: cowboy_middleware :env (),
61+ Result :: {ok , Req , Env } | {stop , Req }.
5462request (Context , Options ) ->
5563 Req = cowmachine_req :req (Context ),
5664 Env = cowmachine_req :env (Context ),
@@ -62,14 +70,23 @@ request(Context, Options) ->
6270 Other
6371 end .
6472
73+ -spec request_1 (Controller , Req , Env , Options , Context ) -> Result when
74+ Controller :: atom (),
75+ Req :: cowboy_req :req (),
76+ Env :: cowboy_middleware :env (),
77+ Options :: map (),
78+ Context :: cowmachine_req :context (),
79+ Result :: {upgrade , UpgradeFun , State , Context } | cowboy_middleware :env () | any (),
80+ UpgradeFun :: atom (),
81+ State :: cmstate ().
6582request_1 (Controller , Req , Env , Options , Context ) ->
6683 State = # cmstate {
6784 controller = Controller ,
6885 cache = #{},
6986 options = Options
7087 },
7188 Site = maps :get (site , Env , undefined ),
72- try
89+ ReqResult = try
7390 EnvInit = cowmachine_req :init_env (Req , Env ),
7491 Context1 = cowmachine_req :set_env (EnvInit , Context ),
7592 case cowmachine_decision_core :handle_request (State , Context1 ) of
@@ -116,9 +133,21 @@ request_1(Controller, Req, Env, Options, Context) ->
116133 class => Class , reason => Reason ,
117134 stack => Stacktrace }, Req ),
118135 handle_stop_request (500 , Site , {throw , {Reason , Stacktrace }}, Req , Env , State , Context )
119- end .
136+ end ,
137+ ReqResult .
138+
120139
121140% @todo add the error controller as an application env, if not defined then just terminate with the corresponding error code.
141+
142+ -spec handle_stop_request (ResponseCode , Site , Reason , Req , Env , State , Context ) -> Result when
143+ ResponseCode :: integer (),
144+ Site :: atom () | undefined ,
145+ Reason :: any (),
146+ Req :: cowboy_req :req (),
147+ Env :: cowboy_middleware :env (),
148+ State :: cmstate (),
149+ Context :: cowmachine_req :context (),
150+ Result :: {ok , Req , Env } | {stop , Req }.
122151handle_stop_request (ResponseCode , _Site , Reason , Req , Env , State , Context ) ->
123152 State1 = State # cmstate {
124153 controller = controller_http_error
@@ -154,13 +183,19 @@ handle_stop_request(ResponseCode, _Site, Reason, Req, Env, State, Context) ->
154183% %
155184% % Logging
156185% %
157-
186+ -spec log (Report ) -> Result when
187+ Report :: map (),
188+ Result :: any ().
158189log (#{ level := Level } = Report ) ->
159190 log_report (Level , Report #{
160191 in => cowmachine ,
161192 node => node ()
162193 }).
163194
195+ -spec log (Report , Req ) -> Result when
196+ Report :: map (),
197+ Req :: map (),
198+ Result :: any ().
164199log (#{ level := Level } = Report , Req ) when is_map (Req ) ->
165200 Report1 = lists :foldl (fun ({Key , Fun }, Acc ) ->
166201 case Fun (Req ) of
@@ -175,6 +210,10 @@ log(#{ level := Level } = Report, Req) when is_map(Req) ->
175210 node => node ()
176211 }).
177212
213+ -spec log_report (LogLevel , Report ) -> Result when
214+ LogLevel :: debug | info | notice | warning | error ,
215+ Report :: map (),
216+ Result :: any ().
178217log_report (debug , Report ) when is_map (Report ) ->
179218 ? LOG_DEBUG (Report );
180219log_report (info , Report ) when is_map (Report ) ->
@@ -186,16 +225,36 @@ log_report(warning, Report) when is_map(Report) ->
186225log_report (error , Report ) when is_map (Report ) ->
187226 ? LOG_ERROR (Report ).
188227
228+ -spec src (IpInfo ) -> Result when
229+ IpInfo :: #{ peer := {IP , Port } } | any (),
230+ Port :: integer (),
231+ IP :: tuple (),
232+ Result :: {ok , map ()} | undefined .
189233src (#{ peer := {IP , Port } }) -> {ok , ip_info (IP , Port )};
190234src (_ ) -> undefined .
191235
236+ -spec dst (DstInfo ) -> Result when
237+ DstInfo :: #{ sock := {IP , Port } } | #{ port := Port } | any (),
238+ IP :: tuple (),
239+ Port :: integer (),
240+ Result :: {ok , #{IPType => string (), port => Port }} | {ok , #{ port => Port }} | undefined ,
241+ IPType :: ip4 | ip6 .
192242dst (#{ sock := {IP , Port } } ) -> {ok , ip_info (IP , Port )};
193243dst (#{ port := Port }) -> {ok , #{ port => Port }};
194244dst (_ ) -> undefined .
195245
246+ -spec path (PathInfo ) -> Result when
247+ PathInfo :: #{ path := Path } | any (),
248+ Path :: any (),
249+ Result :: {ok , Path } | undefined .
196250path (#{ path := Path }) -> {ok , Path };
197251path (_ ) -> undefined .
198252
253+ -spec ip_info (IP , Port ) -> Result when
254+ IP :: tuple (),
255+ Port :: integer (),
256+ IPType :: ip4 | ip6 ,
257+ Result :: #{IPType => string (), port => Port }.
199258ip_info (IP , Port ) ->
200259 IPType = case tuple_size (IP ) of 4 -> ip4 ; 8 -> ip6 end ,
201260 #{IPType => inet_parse :ntoa (IP ), port => Port }.
0 commit comments