Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 227 lines (196 sloc) 8.377 kb
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
1 %% Copyright (C) 2003 Joakim Grebenö <jocke@gleipnir.com>.
2 %% All rights reserved.
3 %%
4 %% Copyright (C) 2006 Gaspar Chilingarov <nm@web.am>
5 %% Gurgen Tumanyan <barbarian@armkb.com>
6 %% All rights reserved.
7 %%
8 %%
9 %% Redistribution and use in source and binary forms, with or without
10 %% modification, are permitted provided that the following conditions
455578a @vinoski major trailing whitespace cleanup
vinoski authored
11 %% are met:
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
12 %%
13 %% 1. Redistributions of source code must retain the above copyright
455578a @vinoski major trailing whitespace cleanup
vinoski authored
14 %% notice, this list of conditions and the following disclaimer.
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
15 %% 2. Redistributions in binary form must reproduce the above
16 %% copyright notice, this list of conditions and the following
17 %% disclaimer in the documentation and/or other materials provided
18 %% with the distribution.
19 %%
20 %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
21 %% OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 %% WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 %% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24 %% DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 %% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26 %% GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 %% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 %% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 %% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 %% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 -module(yaws_jsonrpc).
455578a @vinoski major trailing whitespace cleanup
vinoski authored
33 -author("Gaspar Chilingarov <nm@web.am>, Gurgen Tumanyan <barbarian@armkb.com>").
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
34 -export([handler/2]).
35 -export([handler_session/2, handler_session/3]).
36
6e96a14 @klacke indendation cleanup
authored
37 %%-define(debug, 1).
38 -include("../../yaws/src/yaws_debug.hrl").
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
39
1aad2b4 Corrected reference to yaws_api.hrl so that they now compile properly.
Tobbe Tornquist authored
40 -include("../include/yaws_api.hrl").
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
41
455578a @vinoski major trailing whitespace cleanup
vinoski authored
42 %%% ######################################################################
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
43 %%% public interface
44 %%%
45
46 %%%
47 %%% use jsonrpc handler which can automagically start sessions if we need
48 %%%
49 handler_session(Args, Handler) ->
50 handler_session(Args, Handler, 'SID').
51
52 %%%
53 %%% allow overriding session Cookie name
54 %%%
55 handler_session(Args, Handler, SID_NAME) when is_atom(SID_NAME) ->
56 handler_session(Args, Handler, atom_to_list(SID_NAME));
57
58 handler_session(Args, Handler, SID_NAME) ->
59 handler(Args, Handler, {session, SID_NAME}). % go to generic handler
60
61 %%%
62 %%% xmlrpc:handler compatible call
63 %%% no session support will be available
64 handler(Args, Handler) ->
65 handler(Args, Handler, simple).
66
67
455578a @vinoski major trailing whitespace cleanup
vinoski authored
68 %%% ######################################################################
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
69 %%% private functions
70 %%%
71
72 %%% we should be called from yaws page or module
6e96a14 @klacke indendation cleanup
authored
73 handler(Args, Handler, Type) when is_record(Args, arg) ->
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
74 case parse_request(Args) of
6e96a14 @klacke indendation cleanup
authored
75 ok ->
76 handle_payload(Args, Handler, Type);
77 {status, StatusCode} -> % cannot parse request
78 send(Args, StatusCode)
79 end.
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
80
81 -define(ERROR_LOG(Reason),
6e96a14 @klacke indendation cleanup
authored
82 error_logger:error_report({?MODULE, ?LINE, Reason})).
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
83
84 %%%
85 %%% check that request come in reasonable protocol version and reasonable method
86 %%%
6e96a14 @klacke indendation cleanup
authored
87 parse_request(Args) ->
455578a @vinoski major trailing whitespace cleanup
vinoski authored
88 case {(Args#arg.req)#http_request.method,
6e96a14 @klacke indendation cleanup
authored
89 (Args#arg.req)#http_request.version} of
90 {'POST', {1,0}} ->
91 ?Debug("HTTP Version 1.0~n", []),
92 ok;
93 {'POST', {1,1}} ->
94 ?Debug("HTTP Version 1.1~n", []),
95 ok;
96 {'POST', _HTTPVersion} -> {status, 505};
97 {_Method, {1,1}} -> {status, 501};
98 _ -> {status, 400}
99 end.
100
101 handle_payload(Args, Handler, Type) ->
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
102 Payload = binary_to_list(Args#arg.clidata),
6e96a14 @klacke indendation cleanup
authored
103 ?Debug("jsonrpc plaintext call ~p ~n", [Payload]),
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
104 case decode_handler_payload(Payload) of
6e96a14 @klacke indendation cleanup
authored
105 {ok, DecodedPayload, ID} ->
106 ?Debug("json2erl decoded call ~p ~n", [DecodedPayload]),
107 eval_payload(Args, Handler, DecodedPayload, Type, ID);
108 {error, Reason} ->
109 ?ERROR_LOG({html, json2erl, Payload, Reason}),
110 send(Args, 400)
111 end.
112
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
113 %%%
114 %%% call handler/3 and provide session support
455578a @vinoski major trailing whitespace cleanup
vinoski authored
115 eval_payload(Args, {M, F}, Payload, {session, CookieName},ID) ->
116 {SessionValue, Cookie} =
117 case yaws_api:find_cookie_val(CookieName,
6e96a14 @klacke indendation cleanup
authored
118 (Args#arg.headers)#headers.cookie) of
119 [] -> % have no session started, just call handler
120 {undefined, undefined};
121 Cookie2 -> % get old session data
122 case yaws_api:cookieval_to_opaque(Cookie2) of
123 {ok, OP} ->
124 yaws_api:cookieval_to_opaque(Cookie2),
125 {OP, Cookie2};
126 {error, _ErrMsg} -> % cannot get corresponding session
127 {undefined, undefined}
128 end
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
129 end,
455578a @vinoski major trailing whitespace cleanup
vinoski authored
130
6e96a14 @klacke indendation cleanup
authored
131 case catch M:F(Args#arg.state, Payload, SessionValue) of
132 {'EXIT', Reason} ->
133 ?ERROR_LOG({M, F, {'EXIT', Reason}}),
134 send(Args, 500);
135 {error, Reason} ->
136 ?ERROR_LOG({M, F, Reason}),
137 send(Args, 500);
138 {false, ResponsePayload} ->
139 %% do not have updates in session data
140 encode_send(Args, 200, ResponsePayload, [], ID);
455578a @vinoski major trailing whitespace cleanup
vinoski authored
141 {true, _NewTimeout, NewSessionValue, ResponsePayload} ->
6e96a14 @klacke indendation cleanup
authored
142 %% be compatible with xmlrpc module
143 CO = case NewSessionValue of
144 undefined when Cookie == undefined -> []; % nothing to do
145 undefined -> % rpc handler requested session delete
455578a @vinoski major trailing whitespace cleanup
vinoski authored
146 yaws_api:delete_cookie_session(Cookie), [];
6e96a14 @klacke indendation cleanup
authored
147 %% XXX: may be return set-cookie with empty val?
455578a @vinoski major trailing whitespace cleanup
vinoski authored
148 _ ->
6e96a14 @klacke indendation cleanup
authored
149 %% any other value will stored in session
150 case SessionValue of
455578a @vinoski major trailing whitespace cleanup
vinoski authored
151 undefined ->
152 %% got session data and should start
6e96a14 @klacke indendation cleanup
authored
153 %% new session now
154 Cookie1 = yaws_api:new_cookie_session(
155 NewSessionValue),
455578a @vinoski major trailing whitespace cleanup
vinoski authored
156 yaws_api:setcookie(CookieName, Cookie1, "/");
157 _ ->
6e96a14 @klacke indendation cleanup
authored
158 yaws_api:replace_cookie_session(
159 Cookie, NewSessionValue),
160 [] % nothing to add to yaws data
161 end
162 end,
163 encode_send(Args, 200, ResponsePayload, CO, ID)
164 end;
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
165
166 %%%
167 %%% call handler/2 without session support
168 %%%
6e96a14 @klacke indendation cleanup
authored
169 eval_payload(Args, {M, F}, Payload, simple, ID) ->
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
170 case catch M:F(Args#arg.state, Payload) of
6e96a14 @klacke indendation cleanup
authored
171 {'EXIT', Reason} ->
172 ?ERROR_LOG({M, F, {'EXIT', Reason}}),
173 send(Args, 500);
174 {error, Reason} ->
175 ?ERROR_LOG({M, F, Reason}),
176 send(Args, 500);
177 {false, ResponsePayload} ->
178 encode_send(Args, 200, ResponsePayload, [],ID);
179 {true, _NewTimeout, _NewState, ResponsePayload} ->
180 encode_send(Args, 200, ResponsePayload, [],ID)
181 end.
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
182
183
184 %%% XXX compatibility with XMLRPC handlers
185 %%% XXX - potential bug here?
6e96a14 @klacke indendation cleanup
authored
186 encode_send(Args, StatusCode, [Payload], AddOn, ID) ->
187 encode_send(Args, StatusCode, Payload, AddOn, ID);
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
188
6e96a14 @klacke indendation cleanup
authored
189 encode_send(Args, StatusCode, Payload, AddOn, ID) ->
b45c0a4 @klacke dialyzer work
authored
190 {ok, EncodedPayload} = encode_handler_payload(Payload, ID),
191 send(Args, StatusCode, EncodedPayload, AddOn).
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
192
6e96a14 @klacke indendation cleanup
authored
193 send(Args, StatusCode) -> send(Args, StatusCode, "", []).
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
194
195 send(Args, StatusCode, Payload, AddOnData) when not is_list(AddOnData) ->
196 send(Args, StatusCode, Payload, [AddOnData]);
197
198 send(_Args, StatusCode, Payload, AddOnData) ->
199 A = [
455578a @vinoski major trailing whitespace cleanup
vinoski authored
200 {status, StatusCode},
201 {content, "text/xml", Payload},
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
202 {header, {content_length, lists:flatlength(Payload) }}
203 ] ++ AddOnData,
6e96a14 @klacke indendation cleanup
authored
204 A.
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
205
6e96a14 @klacke indendation cleanup
authored
206
455578a @vinoski major trailing whitespace cleanup
vinoski authored
207 encode_handler_payload({response, [ErlStruct]},ID) ->
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
208 encode_handler_payload({response, ErlStruct}, ID);
455578a @vinoski major trailing whitespace cleanup
vinoski authored
209
210 encode_handler_payload({response, ErlStruct},ID) ->
96534b2 @vinoski replace json.erl with json2.erl to fix issue 50
vinoski authored
211 StructStr = json2:encode({struct, [{result, ErlStruct}, {id, ID}]}),
6e96a14 @klacke indendation cleanup
authored
212 {ok, StructStr}.
455578a @vinoski major trailing whitespace cleanup
vinoski authored
213
6e96a14 @klacke indendation cleanup
authored
214 decode_handler_payload(JSonStr) ->
455578a @vinoski major trailing whitespace cleanup
vinoski authored
215 try
96534b2 @vinoski replace json.erl with json2.erl to fix issue 50
vinoski authored
216 {ok, JSON} = json2:decode_string(JSonStr),
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
217 Method = list_to_atom(jsonrpc:s(JSON, method)),
218 {array, Args} = jsonrpc:s(JSON, params),
219 ID = jsonrpc:s(JSON, id),
220
221 {ok, {call, Method, Args}, ID}
455578a @vinoski major trailing whitespace cleanup
vinoski authored
222 catch
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
223 error:Err -> {error, Err}
6e96a14 @klacke indendation cleanup
authored
224 end.
225
47e5a7c @klacke JSON ajax code from Gaspar Chilingarov, I added docs describing an examp...
authored
226
Something went wrong with that request. Please try again.