PageRenderTime 1075ms CodeModel.GetById 713ms app.highlight 85ms RepoModel.GetById 190ms app.codeStats 0ms

/ucengine/src/core/uce_appmod.erl

http://github.com/AF83/ucengine
Erlang | 135 lines | 103 code | 8 blank | 24 comment | 0 complexity | 4a87ba5687c7dee823e1020f5b2f0ca1 MD5 | raw file
  1%%
  2%%  U.C.Engine - Unified Collaboration Engine
  3%%  Copyright (C) 2011 af83
  4%%
  5%%  This program is free software: you can redistribute it and/or modify
  6%%  it under the terms of the GNU Affero General Public License as published by
  7%%  the Free Software Foundation, either version 3 of the License, or
  8%%  (at your option) any later version.
  9%%
 10%%  This program is distributed in the hope that it will be useful,
 11%%  but WITHOUT ANY WARRANTY; without even the implied warranty of
 12%%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13%%  GNU Affero General Public License for more details.
 14%%
 15%%  You should have received a copy of the GNU Affero General Public License
 16%%  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17%%
 18-module(uce_appmod).
 19
 20-include("uce.hrl").
 21-include_lib("yaws/include/yaws_api.hrl").
 22
 23-export([out/1]).
 24
 25convert2(string, Value) ->
 26    Value;
 27convert2(integer, Value) when is_integer(Value) ->
 28    Value;
 29convert2(integer, Value) ->
 30    case string:to_integer(Value) of
 31        {error, _} ->
 32            {error, bad_parameters};
 33        {Integer, _} ->
 34            Integer
 35    end;
 36convert2(atom, Value) when is_atom(Value) ->
 37    Value;
 38convert2(atom, Value) ->
 39    list_to_atom(Value);
 40convert2(dictionary, Value) ->
 41    Value;
 42convert2(file, Value) when is_record(Value, file_upload) ->
 43    Value;
 44convert2(file, _Value) ->
 45    {error, bad_parameters}.
 46
 47convert(Param, Type)
 48  when is_atom(Type) ->
 49    convert(Param, [Type]);
 50convert(_, []) ->
 51    throw({error, bad_parameters});
 52convert(Param, [Type|Tail]) ->
 53    Result = convert2(Type, Param),
 54    case Result of
 55        {error, _} ->
 56            convert(Param, Tail);
 57        _ ->
 58            Result
 59    end.
 60
 61validate(_, []) ->
 62    [];
 63validate(Query, [{Name, Default, Types}|ParamsSpecList]) ->
 64    case utils:get(Query, [Name], [Default]) of
 65        [required] ->
 66            throw({error, missing_parameters, lists:flatten(io_lib:format("Parameter '~s' is missing", [Name]))});
 67        [RawValue] ->
 68            [convert(RawValue, Types)] ++ validate(Query, ParamsSpecList)
 69    end.
 70
 71call_handlers(Domain, {Module, Function, ParamsSpecList}, Query, Match, Arg) ->
 72    case catch validate(Query, ParamsSpecList) of
 73        {error, Reason} ->
 74            json_helpers:error(Domain, Reason);
 75        {error, Reason, Infos} ->
 76            ?ERROR_MSG("~p: error: ~p:~p: ~p ~p~n", [Domain, Module, Function, Reason, Infos]),
 77            json_helpers:error(Domain, Reason, Infos);
 78        Params ->
 79            ?DEBUG("~p: call ~p:~p matching ~p with ~p~n", [Domain, Module, Function, Match, Params]),
 80            Now = now(),
 81            try Module:Function(Domain, Match, Params, Arg) of
 82                {streamcontent_with_timeout, _, _, _} = Stream ->
 83                    cors_helpers:format_cors_headers(Domain) ++ [Stream];
 84                Response when is_list(Response) ->
 85                    ?TIMER_APPEND(atom_to_list(Module) ++ "_" ++ atom_to_list(Function), Now),
 86                    Response
 87            catch
 88                {error, Reason} ->
 89                    ?ERROR_MSG("~p: error: ~p:~p: ~p ~p~n", [Domain, Module, Function, Reason, Params]),
 90                    json_helpers:error(Domain, Reason);
 91                E ->
 92                    ?ERROR_MSG("~p: error: ~p:~p: ~p ~p~n", [Domain, Module, Function, Params, E]),
 93                    json_helpers:unexpected_error(Domain)
 94            end
 95    end.
 96
 97%%
 98%% Function called by yaws
 99%% For each vhost we support, we store to the opaque field the current domain
100%%
101out(#arg{} = Arg) ->
102    ?COUNTER('http:request'),
103    Host = Arg#arg.opaque,
104    case uce_http:parse(Host, Arg) of
105        {error, Reason} ->
106            json_helpers:error(Host, Reason);
107        {get_more, _, _} = State ->
108            State;
109        {Method, Path, Query} ->
110            process(Host, Method, Path, Query, Arg)
111    end.
112
113% Handle options method. If one route match, return ok
114process(Host, 'OPTIONS', Path, _Query, _Arg) ->
115    case routes:get(Path) of
116        {ok, _Match, _Handlers} ->
117            json_helpers:ok(Host);
118        {error, not_found} ->
119            ?ERROR_MSG("options ~p: no route found", [Path]),
120            json_helpers:error(Host, not_found)
121    end;
122% Handle head method. If a 'GET' route match, normal process
123% Yaws will strip the content
124process(Host, 'HEAD', Path, Query, Arg) ->
125    process(Host, 'GET', Path, Query, Arg);
126process(Host, Method, Path, Query, Arg) ->
127    ContentType = Arg#arg.headers#headers.content_type,
128    case routes:get(Method, Path, ContentType) of
129        {ok, Match, Handlers} ->
130            call_handlers(Host, Handlers, Query, Match, Arg);
131        {error, not_found} ->
132            Description = lists:flatten(io_lib:format("~s on ~s did not match any route.", [Method, Path])),
133            ?ERROR_MSG(Description, []),
134            json_helpers:error(Host, not_found, Description)
135    end.