]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/jsolait/lib/jsonrpclite.js
Release 6.2.1
[Github/sugarcrm.git] / jssource / src_files / include / jsolait / lib / jsonrpclite.js
1 /*
2
3 Modification information for LGPL compliance
4
5 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
6
7 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
8
9 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
10
11 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system 
12
13 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
14
15 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
16
17 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
18
19 r21575 - 2007-04-09 16:28:53 -0700 (Mon, 09 Apr 2007) - chris - Bug 12274 - SECURITY: CSRF (cross-site request forgery) fix.
20 Fix back-ported to:
21 Maint 451
22 SecFix 451c
23 Maint 450
24 Portal Maint 450
25 SecFix 421b
26 Touched:
27         ./index.php
28         ./json.php
29         ./json_server.php
30         ./include/jsclass_async.js
31         ./include/jsclass_base.js
32         ./include/javascript/yui/connection.js
33         ./include/jsolait/lib/jsonrpc.js
34         ./include/jsolait/lib/jsonrpclite.js
35         ./include/JSON.js
36         ./include/JSON.php
37         ./modules/Emails/Email.js
38
39 r10487 - 2005-12-12 03:57:07 -0800 (Mon, 12 Dec 2005) - robert - fixed: 3478
40 also changed jsonrpc on the client side so that javascript classes
41 will no longer get the toJSON method added to it.
42
43
44 */
45
46 /*
47   Copyright (c) 2003-2004 Jan-Klaas Kollhof
48   
49   This file is part of the JavaScript o lait library(jsolait).
50   
51   jsolait is free software; you can redistribute it and/or modify
52   it under the terms of the GNU Lesser General Public License as published by
53   the Free Software Foundation; either version 2.1 of the License, or
54   (at your option) any later version.
55  
56   This software is distributed in the hope that it will be useful,
57   but WITHOUT ANY WARRANTY; without even the implied warranty of
58   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
59   GNU Lesser General Public License for more details.
60  
61   You should have received a copy of the GNU Lesser General Public License
62   along with this software; if not, write to the Free Software
63   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
64 */
65
66 /**
67     // SUGARCRM:
68     // USES the langlite.php instead of lang.php
69     Provides an JSON-RPC imlementation.
70 */
71 Module("jsonrpclite", "0.3.2", function(mod){
72     
73     // SUGARCRM:
74     var lang = importModule("langlite");
75     // END SUGARCRM
76     var tokens =  lang.tokens;
77     
78     var ObjectBuffer=Class("ObjectBuffer", function(publ, supr){
79         publ.init=function(){
80             this.data="";
81         }
82         publ.getObjects=function(data){
83             this.data += data;
84             var t = new lang.Tokenizer(this.data);
85             var brCnt= 0;
86             var objects = [];
87             var readCnt = 0
88             while(! t.finished()){
89                 var n = t.next();
90                 if(n.type != tokens.ERR){
91                     if(n.value == "{"){
92                         brCnt+=1;
93                     }else if(n.value == "}"){
94                         brCnt-=1;
95                         if(brCnt==0){
96                             var s = this.data.slice(readCnt, n.pos+1);
97                             readCnt += s.length;
98                             objects.push(s);
99                         }
100                     }
101                 }else{
102                     break;
103                 }
104             }
105             this.data = this.data.slice(readCnt);
106             return objects;
107         }
108     })
109     
110     var nameAllowed=function(name){
111         return name.match(/^[a-zA-Z]\w*$/) != null;
112     }
113     
114     var getMethodByName=function(obj, name){
115         try{//to get a method by asking the service
116             obj = obj._getMethodByName(name)
117         }catch(e){
118             var names = name.split(".");
119             for(var i=0;i<names.length;i++){
120                 name = names[i];
121                 if(nameAllowed(name)){
122                     obj = obj[name];
123                 }
124             }
125         }
126         return obj;
127     }
128     
129     var Response=Class("Response", function(publ, supr){
130         publ.init=function(id, result, error){
131             this.id=id;
132             this.result = result;
133             this.error = error;
134         }
135         publ._toJSON=function(){
136             var p = [lang.objToJson(this.id), lang.objToJson(this.result),lang.objToJson(this.error)];
137             return '{"id":' + p[0] + ', "result":' + p[1] + ', "error":' + p[2] + "}";
138         }
139     })
140     
141     var Request=Class("Request", function(publ, supr){
142         publ.init=function(id, method, params){
143             this.id=id;
144             this.method = method;
145             this.params = params;
146 /*
147  var str = '';
148 for(hello in this.params)
149 {
150   str += "var:"+hello+":"+this.params[hello]+":\n";
151 }
152 alert(str);
153 */
154         }
155         publ._toJSON=function(){
156             var p = [lang.objToJson(this.id), lang.objToJson(this.method),lang.objToJson(this.params)];
157             return '{"id":' + p[0] + ', "method":' + p[1] + ', "params":' + p[2] + "}";
158         }
159     })
160     
161     var Notification=Class("Notification", function(publ, supr){
162         publ.init=function(method, params){
163             this.method = method;
164             this.params = params;
165         }
166         publ._toJSON=function(){
167             var p = [lang.objToJson(this.method),lang.objToJson(this.params)];
168             return '{"method":' + p[0] + ', "params":' + p[1] + "}";
169         }
170     })
171     
172     var ResponseHandler=Class("ResponseHandler", function(publ, supr){
173         publ.init=function(callback){
174             this.callback=callback;
175         }
176         publ.handleResponse=function(resp){
177             this.callback(resp.result, resp.error);
178         }
179     })
180     
181     var RPCLib = Class("RPCLib", function(publ, supr){
182         
183     })
184     
185     var BaseConnectionHandler = Class("BaseConnectionHandler",  function(publ, supr){
186         publ.init=function(service){
187             this.service = service;
188             this.jsonParser = new lang.JSONParser();
189             this.jsonParser.addLib(new RPCLib(), "rpc", []);
190             this.respHandlers = [];
191             this.objBuffer = new ObjectBuffer();
192         }
193                 
194         publ.addResponseHandler=function(cb){
195             var id=1;
196             while(this.respHandlers[""+id] ){
197                 id+=1;
198             }
199             id="" + id;
200             this.respHandlers[id] = new ResponseHandler(cb);
201             return id;
202         }
203         
204         publ.send = function(data){
205         }
206         
207         publ.sendNotify = function(name, args){
208             var n = new Notification(name, args);
209             n = this.jsonParser.objToJson(n);
210             this.send(n)
211         }
212         
213         publ.sendRequest = function(name, args, callback){
214             var id = this.addResponseHandler(callback);
215             var r = new Request(id, name, args);
216             r = this.jsonParser.objToJson(r);
217             this.send(r);
218         }
219         
220         publ.sendResponse = function(id, result, error){
221             var r = new Response(id, result, error);
222             r = this.jsonParser.objToJson(r);
223             this.send(r);
224         }
225         
226         publ.handleRequest = function(req){
227             var name = req.method;
228             var params = req.params;
229             var id=req.id;
230             if(this.service[name]){
231                 try{
232                     var rslt = this.service[name].apply(this.service,params);
233                     this.sendResponse(id, rslt, null)
234                 }catch(e){
235                     this.sendResponse(id, null, new ApplicationError("" + e))
236                 }
237             }else{
238                 this.sendResponse(id, null, new MethodNotFound());
239             }
240         }
241         
242         publ.handleNotification = function(notif){
243             if(this.service[notif.method]){
244                 try{
245                     this.service[notif.method].apply(this.service, notif.params);
246                 }catch(e){
247                 }
248             }
249         }
250         
251         publ.handleResponse = function(resp){
252             var id=resp.id;
253             var h = this.respHandlers[id];
254             h.handleResponse(resp)
255             delete this.respHandlers[id]
256         }
257         
258         publ.handleData = function(data){
259             var objs = this.objBuffer.getObjects(data);
260             for(var i=0;i<objs.length;i++){
261                 try{
262                     var obj = this.jsonParser.jsonToObj(objs[i]);
263                 }catch(e){
264                     throw "Not well formed";
265                 }
266                 if(obj.method != null){ 
267                     if(obj.id != null){
268                         this.handleRequest(new Request(obj.id, obj.method, obj.params));
269                     }else{
270                         this.handleNotification(new Notification(obj.method, obj.params));
271                     }
272                 }else if(obj.id != null){
273                      this.handleResponse(new Response(obj.id, obj.result, obj.error));
274                 }else{
275                    throw "Unknown Data";
276                 }
277             }
278         }
279     })
280     
281     var SocketConnectionHandler = Class("SocketConnectionHandler", BaseConnectionHandler, function(publ, supr){
282         publ.init=function(socket, localService){
283             this.socket = socket;
284             socket.addEventListener("connectionData", this, false);
285             supr(this).init( localService);
286         }
287         
288         publ.handleEvent=function(evt){
289             this.handleData(evt.data);
290         }
291         
292         publ.send=function(data){
293             this.socket.send(data);
294         }
295         
296         publ.close=function(data){
297             this.socket.close();
298         }
299     })
300     
301     var HTTPConnectionHandler = Class("HTTPConnectionHandler", BaseConnectionHandler, function(publ, supr){
302         var urllib;
303         publ.request_id = 1;
304         publ.init=function(url, localService){
305             urllib=importModule("urllib");
306             this.url = url;
307             supr(this).init( localService);
308         }
309                 
310         publ.handleData = function(data){
311
312             try{                
313                 var obj = JSON.parse(data);
314             }catch(e){;
315                 throw " Not well formed\n\n" + e + "\n\nResponse from server:\n\n " + data;
316             }
317             if(obj.id != null){
318                 return obj;
319             }else{
320                 throw "Unknown Data (No id property found)";
321             }  
322         }
323         
324         publ.sendRequest = function(name, args, callback){
325             var sync = false;
326             if(typeof callback != "function"){//see if it is sync
327                 args.push(callback); 
328                 sync=true;
329             }
330             var data = new Request(this.request_id++, name, args);
331             // cn: bug 12274 - defend against CSRF
332             data = JSON.stringify(data); // creates security envelope wrapped JSON object
333
334             if(sync){
335                 var rsp = urllib.postURL(this.url, data, [["Content-Type", "text/plain"]]);
336                 rsp = this.handleData(rsp.responseText);
337                 if(rsp.error){
338                     throw rsp.error;
339                 }else{
340                     return rsp.result;
341                 }
342             }else{//async connection uses the respHandler to handle the repsonse
343                 var self = this;
344                 var request_id = this.request_id;
345                 urllib.postURL(this.url, data, [["Content-Type", "text/plain"]], function(rsp){
346                     try{
347                         rsp = self.handleData(rsp.responseText);
348                     }catch(e){
349                         //callback(null,e);
350                         callback(request_id,null,e);
351                         return;
352                     }
353                     callback(request_id,rsp.result, rsp.error);
354                     //callback(this.request_id,rsp.result, rsp.error);
355                     //callback(rsp.result, rsp.error);
356                 });
357             }
358         }
359         
360         publ.sendNotify = function(name, args){
361             var data = new Notification(name, args);
362             data = this.jsonParser.objToJson(data);
363             urllib.postURL(this.url, data, [["Content-Type", "text/plain"]], function(rsp){});
364         }
365     })
366     
367     var PeerObject=Class("PeerObject", function(publ, supr){
368         publ.init=function(name, conn){
369             var fn=function(){
370                 var args=[];
371                 for(var i=0;i<arguments.length;i++){
372                     args[i] = arguments[i];
373                 }
374                 var cb=args.pop();
375                 return conn.sendRequest(name, args, cb);
376             }
377             return fn;
378         }
379     })
380      
381     var PeerNotifyObject=Class("PeerNotifyObject", function(publ, supr){
382         publ.init=function(name, conn){
383             var fn=function(){
384                 var args=[];
385                 for(var i=0;i<arguments.length;i++){
386                     args[i] = arguments[i];
387                 }
388                 conn.sendNotify(name, args);
389             }
390             return fn;
391         }
392     })
393     
394     var BasePeer = Class("BasePeer", function(publ, supr){
395         publ.init=function(conn, methodNames){
396             this._conn = conn;
397             this.notify = new PeerObject("notify", conn);
398             this._add(methodNames);
399         }
400         
401         var setupPeerMethod=function(root, methodName, conn, MethClass){
402             var names = methodName.split(".");
403             var obj = root;
404             for(var n=0;n<names.length-1;n++){
405                 var name = names[n];
406                 if(obj[name]){
407                     obj = obj[name];
408                 }else{
409                     obj[name] = new Object();
410                     obj = obj[name];
411                 }
412             }
413             var name = names[names.length-1];
414             if(obj[name]){
415             }else{
416                 var mth = new MethClass(methodName, conn);
417                 obj[name] = mth;
418             }
419         }
420         
421         publ._add = function(methodNames){
422             for(var i=0;i<methodNames.length;i++){
423                 setupPeerMethod(this, methodNames[i], this._conn, PeerObject);
424                 setupPeerMethod(this.notify, methodNames[i], this._conn, PeerNotifyObject);
425             }
426         }
427     })
428     
429     
430     mod.ServiceProxy = Class("ServiceProxy", BasePeer, function(publ, supr){
431         publ.init = function(url, methodNames, localService){
432               
433             var n = url.match(/^jsonrpc:\/\/(.*:\d*)$/);
434             if(n!=null){//is it  json-rpc over TCP protocoll 
435                 var hostaddr = n[1];
436                 try{
437                     var socket = createConnection();
438                 }catch(e){
439                     throw "Can't create a socket connection."
440                 }
441                 socket.connect(hostaddr);
442                 supr(this).init( new SocketConnectionHandler(socket, localService), methodNames);
443             }else{//or is it json-rpc over http
444                 this.httpConn = new HTTPConnectionHandler(url, localService);
445                 supr(this).init( this.httpConn, methodNames);
446             }
447         }
448     })
449 })
450  
451