Author: jan Date: 2006-02-09 09:48:31 -0600 (Thu, 09 Feb 2006) New Revision: 8154
Added: trunk/gnue-appserver/extensions/webfrontend/rpcproxy.cgi Modified: trunk/gnue-appserver/extensions/webfrontend/README trunk/gnue-appserver/extensions/webfrontend/gnue-forms.js trunk/gnue-appserver/extensions/webfrontend/vcXMLRPC.js Log: updated webfrontend to work with last production appserver (0.4.3) add proxy to circumvent removed direct download ability from appserver correct error handling in vcXMLRPC Modified: trunk/gnue-appserver/extensions/webfrontend/README =================================================================== --- trunk/gnue-appserver/extensions/webfrontend/README 2006-02-06 19:33:53 UTC (rev 8153) +++ trunk/gnue-appserver/extensions/webfrontend/README 2006-02-09 15:48:31 UTC (rev 8154) @@ -9,49 +9,39 @@ ------------- Server side: -GNUe Appserver (>0.0.4) +GNUe Appserver (<=0.4.3) * Changes in CVS after 0.4.3 not adapted yet (switch to object rpc) GNUe Common (>0.5.0) client side: Mozilla or other Gecko based Browser -or IE > 5.0 +or IE > 5.0 (Konqueror or Opera don't work because of missing XMLRPC functionality) +* IE currently broken Installation: ------------- 1. Install GNUe Appserver -2. Copy the contents of this directory into a directory of your choice. - I would recommend: /usr/share/gnue/webfrontend/ for global and - ~/gnue/webfrontend/ for a local install. +2. Setup a webserver and copy the rpcproxyi.cgi script to your webserver. + It has to be available at http://<host>/cgi-bin/rpcproxy.cgi . -3. Then add the option 'httpdir' in the [appserver] group of gnue.conf. - set it to the path of the directory where you have copied the files to. - f.e. +3. Add the hostname to the list of allowed services in the beginning of the + rpcproxy.cgi file. - [appserver] - httpdir = /usr/share/gnue/webfrontend/ or - - httpdir = ~/gnue/webfrontend/ +4. Add sample.html, gnue-forms.js and vcXMLRPC.js to the same webserver as above. + (same host + port required) -4. now you can startup appserver passing the option --web-frontend - to enable the builtin http server. +5. Point your webbrowser to the location of sample.html. Now you should be able + to do querys, add and change data. -5. then you can try the webfrontend out by pointing your Gecko based Browser to - http://gnue_host:8765/ (depends on xmlrpc settings) and loading sample.html. - - -Further steps: +Next steps -------------- - create new html forms by building GFD files and transform them via GNUe-Designer (Tools->Extra->Compile Form for GNUe JsForms) -- put normal gfd files in the webfrontend directory and start them via - gnue-forms http://gnue_host:8765/myform.gfd +- modify settings in gnueforms.js, like default user name etc. -- you can modify some settings in gnueforms.js, like default user name etc. - -- improve the gnueforms.js +- improve gnueforms.js Modified: trunk/gnue-appserver/extensions/webfrontend/gnue-forms.js =================================================================== --- trunk/gnue-appserver/extensions/webfrontend/gnue-forms.js 2006-02-06 19:33:53 UTC (rev 8153) +++ trunk/gnue-appserver/extensions/webfrontend/gnue-forms.js 2006-02-09 15:48:31 UTC (rev 8154) @@ -322,40 +322,40 @@ this.version = '0.0.1'; this.host=host; this.open = function (authentification) { - return XMLRPC.call(this.host,'Session.open',authentification); + return XMLRPC.call(this.host,'open',authentification); }; this.close = function (session_id,commit) { - return XMLRPC.call(this.host,'Session.close',session_id,commit); + return XMLRPC.call(this.host,'close',session_id,commit); }; this.commit = function (session_id) { - return XMLRPC.call(this.host,'Session.commit',session_id); + return XMLRPC.call(this.host,'commit',session_id); }; this.rollback = function (session_id) { - return XMLRPC.call(this.host,'Session.rollback',session_id); + return XMLRPC.call(this.host,'rollback',session_id); }; this.request = function (sessionid,classname,conditions,sortorder,propertylist) { - return XMLRPC.call(this.host,'Session.request',sessionid,classname,conditions,sortorder,propertylist); + return XMLRPC.call(this.host,'request',sessionid,classname,conditions,sortorder,propertylist); }; this.count = function (sessionid,listid) { - return XMLRPC.call(this.host,'Session.count',sessionid,listid); + return XMLRPC.call(this.host,'count',sessionid,listid); }; this.fetch = function (sessionid,listid,start,count) { - return XMLRPC.call(this.host,'Session.fetch',sessionid,listid,start,count); + return XMLRPC.call(this.host,'fetch',sessionid,listid,start,count); }; this.load = function (sessionid,classname,objids,propertylist) { - return XMLRPC.call(this.host,'Session.load',sessionid,classname,objids,propertylist); + return XMLRPC.call(this.host,'load',sessionid,classname,objids,propertylist); }; this.store = function (sessionid,classname,objids,propertylist,data) { - return XMLRPC.call(this.host,'Session.store',sessionid,classname,objids,propertylist,data); + return XMLRPC.call(this.host,'store',sessionid,classname,objids,propertylist,data); }; this.call = function (sessionid,classname,objids,methodname,parameters) { - return XMLRPC.call(this.host,'Session.call',sessionid,classname,objids,methodname,parameters); + return XMLRPC.call(this.host,'call',sessionid,classname,objids,methodname,parameters); }; this.dodelete = function (sessionid,classname,objids) { - return XMLRPC.call(this.host,'Session.delete',sessionid,classname,objids); + return XMLRPC.call(this.host,'delete',sessionid,classname,objids); }; this.getFilters = function (language) { - return XMLRPC.call(this.host,'Session.getFilters',language); + return XMLRPC.call(this.host,'getFilters',language); } } @@ -737,7 +737,8 @@ if (rpc_addr==undefined) { // autodetect connection rpc_addr=location.protocol+location.host; - proxy=""; + rpc_addr="http://"+location.host+":8765/"; + proxy="http://"+location.host+"/cgi-bin/rpcproxy.cgi"; } // 3. if that doesnt work, ask user // TODO: Implement fetchrpc addr+login test loop Added: trunk/gnue-appserver/extensions/webfrontend/rpcproxy.cgi =================================================================== --- trunk/gnue-appserver/extensions/webfrontend/rpcproxy.cgi 2006-02-06 19:33:53 UTC (rev 8153) +++ trunk/gnue-appserver/extensions/webfrontend/rpcproxy.cgi 2006-02-09 15:48:31 UTC (rev 8154) @@ -0,0 +1,275 @@ +#!/usr/bin/perl +################################################################################ +# rpcproxy.cgi (1.41) +# 00:18 2001-08-31 +# Copyright (c) 2001, Saltstorm.net <[EMAIL PROTECTED]> +# License : GNU GPL (http://www.gnu.org/licenses/gpl.txt) +# +################################################################################ +# Simple XML-RPC proxy-hack for side-stepping client-side security +# restrictions when using the 'XMLHttpRequest' object in Moz�lla 0.8.2+ +# and MSIE's 5+ 'Microsoft.XMLHTTP' object, thus giving possibilities of +# accessing public services hosted on remote domains. +# +# The Mozilla browser ships with a native XMLHttpRequest object making it +# possible to implement HTTP request functionality from within a page using +# javascript. This object is very much alike the 'Microsoft.XMLHTTP' object +# bundled with MS Internet Explorer 5+ in terms of the API design, but has +# a different security context. While MSIE's 'Microsoft.XMLHTTP' availability +# is based on "Security Zones" and "Trusted Sites", Mozilla has taken another +# security approach, whereas you can only issue XMLHttpRequests to the same +# domain:port from where the parent document originated. While some might say +# this is feasible in regards for the variuos cross-site scripting exploits, +# other find it very frustrating as they can't access/incorporate services +# from the outside world into their web-apps without having to depend on +# a through and through serverside solution. +# +# This piece came about as Ruben Daniels from Virtual Cowboys +# (http://www.virtualcowboys.com) and I concurrently were struggling with +# client-side Javascript implementations of XML-RPC clients. We found ourselves +# very annoyed with these restrictions as we couldn't take advantage of the +# increasing number of great RPC-services outthere, so I decided to knock +# up this rpc-proxy to overcome this shortcoming. +# +# The idea is very simple. Once placed on your server, it will take a POST +# request coming in from the local domain and pass it along as-is to the real +# RPC-server and then proxy back the response to the client. As of version 1.40 +# rpcproxy will even gzip-compress the proxied XML response-stream to make it +# far more manageable in terms of bandwidth. A vanilla XML-document can be +# reduced with up to some 90% of its original size simply by compressing it. +# Gzip-encoded documents are supported by MSIE and Mozilla out-of-the-box, +# so you don't have to care more about it, other than that you have gained +# 9/10's of bandwidth. If you are on a slow connection that makes a big +# difference. But the most important thing here, a request like this, +# as far as Mozilla and MSIE concerns, no security exception was raised +# since the request was seemingly served at the local domain. +# +# MS Explorer 5+ note. +# ----------------------------------------------------------------------------- +# While utilizing rpcproxy.cgi as a proxy for Mozilla XMLHttpRequests is crucial +# for making non-local HTTP requests, it also have the effect to MSIE in the +# matter that the 'Microsoft.XMLHTTP' object also consider requests to the +# current domain:port as safe and will gladly go for it WITHOUT having the +# current domain present in the list of "Trusted sites" in security settings. +# +# +# Setting up. +# ----------------------------------------------------------------------------- +# Obviously, since this thing is written in PERL, you'll need an +# PERL-interpreter on your server. If you are on a *nix/Linux system you most +# certainly have one there by default. If running on a Win32 system +# (e.g Win NT/2k) there is great distribution of PERL available freely at +# http://www.activestate.com. +# +# +# 1. Put this script accessible from your HTTP-server and make sure it is +# marked executable. (e.g /cgi-bin/...) +# +# 2. Modify the topmost line of this script to match the path to your PERL +# executable. (on most Win32 boxes '#!perl' should be sufficient) +# +# 3. Making sure it is setup alright, open up your favorite browser and +# try to request it. (http://www.mydomain.tld/cgi-bin/rpcproxy.cgi) +# If nothing happens, (a HTTP 204 response) all should be fine. +# If you get a 40x or even a 500/501 you should step back and re-check +# step 1 and 2 again. +# +# 4. Now, the world of remote RPC-services is yours... +# Of course you need to know a fair piece of the DOM, XML and the XML-RPC +# service specification, but that is horse of different color not covered +# here. To get you started, a client-side example: +# +# // Mozilla 0.8.2+ +# var sRPCService = 'http://rpc.remote.tld/object/method'; +# var sRPCProxy = 'http://www.local.tld/cgi-bin/rpcproxy.cgi'; +# var oXML = new XMLHttpRequest(); +# oXML.open('POST', sRPCProxy, false); +# oXML.setRequestHeader('X-Proxy-Request', sRPCService); +# oXML.setRequestHeader('X-Compress-Response', 'gzip'); +# oXML.send([object XMLDomDocument]); +# var oDomDoc = oXML.responseXML; +# // ... do stuff with oDomDoc ... +# +# // to make the above snippet runnable in MSIE 5+ (Win32) you just +# // need to change the assignment of the 'oXML' variable as follows: +# var oXML = new ActiveXObject('Microsoft.XMLHTTP'); +# +# +# ! About security ! +# ----------------------------------------------------------------------------- +# This script will only proxy POST requests having a HTTP header named +# 'X-Proxy-Request' containing the URL to the real rpc-service. If this +# header isn't present OR the service-URL isn't in the list of allowed +# services, rpcproxy will blackhole the request and respond with a +# simple HTTP status 204. +# +# +# Resources. +# ----------------------------------------------------------------------------- +# XML-RPC Home Page. +# http://www.xml-rpc.com +# XML-RPC HOWTO +# http://xmlrpc-c.sourceforge.net/xmlrpc-howto/xmlrpc-howto.html +# Core JavaScript Guide 1.5 +# http://developer.netscape.com/docs/manuals/js/core/jsguide15/contents.html +# +# news://comp.lang.javascript +# secnews.netscape.com +# news://netscape.devs-javascript +# news://netscape.public.mozilla.dom +# +# ---------------------------------------------------------------------------- +# 2001-08-26, Thomas Loo / Saltstorm +# [EMAIL PROTECTED] | http://www.saltstorm.net +################################################################################ + +use strict; +use Compress::Zlib; +use HTTP::Request; +use LWP::UserAgent; +use URI::Escape; +#use CGI::Carp qw(fatalsToBrowser); + + +## User definables ############################################################# +# +# Enable/Disable (1/0) logging of the requests/responses +my $log_traffic = 0; + +# remote request timeout in seconds. +my $rpc_service_timeout = 15; + +# this name must match the header name set on the client side. +my $magic_header_name = "X-Proxy-Request"; + +# the name of the header that decides if the response should be gzip compressed. +my $do_gzip_header_name = "X-Compress-Response"; + +# to prevent this script from being used as a general proxy by a malicious +# user, requests to the following services will only be passed through. +my @allowed_services = ( + "http://www.oreillynet.com/meerkat/xml-rpc/server.php", + "http://www.stuffeddog.com/speller/speller-rpc.cgi", + "http://plant.blogger.com/api/RPC2", + "http://localhost:8765/", + # ...additional services here... + ); +############################################################################### + + my ($mhn, $reqbody, $do_proxy_request); + ($mhn = uc $magic_header_name) =~ tr/-/_/; + my $remote_rpc_server = $ENV{'HTTP_' . $mhn} || ''; + ($mhn = $do_gzip_header_name) =~ tr/-/_/; + my $do_gzip = ($ENV{'HTTP_' . $mhn}) ? 1 : 0; + + # try match the supplied service URL with one in the allowed-list. + foreach(@allowed_services){ + $do_proxy_request = 1 and last if /^$remote_rpc_server$/i; + } + + # kill off any request of type non-POST or having a missing $magic_header or + # not being present in the allowed-list. + print "Status: 204 No Response\r\n\r\n" and exit + unless ($ENV{REQUEST_METHOD} eq 'POST' && length($remote_rpc_server) > 0 && $do_proxy_request); + + # create a new user-agen blend it with the original user-agent string and set the timeout. + my $ua = new LWP::UserAgent; + $ua->agent($ENV{HTTP_USER_AGENT}); + $ua->timeout($rpc_service_timeout); + + # create a new URI object + my $ruri = URI->new($remote_rpc_server); + + # create a new HTTP header object. + my $rhd = new HTTP::Headers( + Content_Length => read(STDIN, $reqbody, $ENV{CONTENT_LENGTH}), + Content_Type => $ENV{CONTENT_TYPE}, + # Host => ($ruri->port == 80 ? $ruri->host : $ruri->host_port), + Referer => $ENV{HTTP_REFERER}, + X_Forwarded_For => $ENV{REMOTE_ADDR}); + + # create the remote rpc request + my $rreq = new HTTP::Request($ENV{REQUEST_METHOD}, $ruri, $rhd, $reqbody); + + if($log_traffic){ + open (REQLOG, ">>rpcproxy-request.log") || die $!; + print REQLOG $rreq->as_string, "\r\n", ("-" x 79), "\r\n"; + close REQLOG; + } + + # trig the rpc + my $rres = $ua->request($rreq); + + # !! This is THE weirdest thing !! + # For MSIE's XMLDOM-parser to pick up large (+60 KB) proxied responses + # from this script and actually have it recognized as a text/xml stream + # it appears binmode STDOUT must be set when run from a Win-box. + # This is totally beyond me since xml/text content is 100% ASCII. + # Small XML-files blends in fine without binmode, but the DOM parser + # totally bombs out on big ones with parseErrors all over the place... + # If anyone could fill in the blanks here and explain this MSIE feature + # for me I'd be most grateful, since it took me about 4 hours to + # figure this one out. + binmode STDOUT if ($^O =~ /Win32/i || $do_gzip || $rres->headers->content_encoding); + + # alles ok ? ...then shove the result from the remote rpc-call + # back to the client as-is. (gzip-encoded if requested) + if($rres->is_success && $rres->code == 200){ + my $already_encoded = $rres->headers->content_encoding; + $rres->headers->content_encoding('gzip') + if($do_gzip && !$already_encoded && $rres->headers->content_length > 1024); + $rres->headers->expires($rres->headers->date); + + my $body = ($do_gzip && !$already_encoded && $rres->headers->content_length > 1024 ? + Compress::Zlib::memGzip($rres->content) : $rres->content); + + $rres->headers->content_length(length($body)); + + print $rres->headers->as_string, "\r\n", $body; + + if($log_traffic){ + open (RESLOG, ">>rpcproxy-response.log") || die $!; + print RESLOG $rres->headers->as_string, "\r\n", $body, "\r\n", ("-" x 79), "\r\n"; + close RESLOG; + } + } + + # something has gone wrong, bring aforth a faultpage instead. + else { + my $faultbody = get_faultpage($remote_rpc_server, $rres->code); + my $res = new HTTP::Headers( + Server => $ENV{SERVER_SOFTWARE}, + Connection => 'close', + Content_Length => length($faultbody), + Content_Type => 'text/xml', + Expires => HTTP::Date::time2str(time - 3600 * 24)); + print $res->as_string, "\r\n", $faultbody; + } + + +sub get_faultpage { + my $server = shift; + my $status_code = shift || "Timed out"; + + return <<XML_BODY +<?xml version="1.0"?> + <methodResponse> + <fault> + <value> + <struct> + <member> + <name>faultCode</name> + <value><int>65535</int></value> + </member> + <member> + <name>faultString</name> + <value><string>rpcproxy error [$server \: $status_code] </string></value> + </member> + </struct> + </value> + </fault> + </methodResponse> +XML_BODY + } + + exit; Property changes on: trunk/gnue-appserver/extensions/webfrontend/rpcproxy.cgi ___________________________________________________________________ Name: svn:executable + * Modified: trunk/gnue-appserver/extensions/webfrontend/vcXMLRPC.js =================================================================== --- trunk/gnue-appserver/extensions/webfrontend/vcXMLRPC.js 2006-02-06 19:33:53 UTC (rev 8153) +++ trunk/gnue-appserver/extensions/webfrontend/vcXMLRPC.js 2006-02-09 15:48:31 UTC (rev 8154) @@ -361,8 +361,12 @@ case "value": child = this.getNode(data, [0]); return (!child) ? ((data.firstChild) ? new String(data.firstChild.nodeValue) : "") : this.toObject(child); - break; + + case "nil": + return undefined + break; + default: this.handleError(new Error("Malformed XMLRPC Message: " + data.tagName)); return false; @@ -591,12 +595,12 @@ //Check for XMLRPC Errors rpcErr = dom.getElementsByTagName("fault"); if(rpcErr.length > 0){ - alert("Error occured:"+http.responseText); - return false - alert(rpcErr[0].firstChild); - rpcErr = this.toObject(rpcErr[0]); - alert(rpcErr) - this.handleError(new Error(rpcErr.faultCode, rpcErr.faultString)); + rpcErr=rpcErr[0].firstChild // skip textnodes and find first element node + while (rpcErr.nodeType!=rpcErr.ELEMENT_NODE){ + rpcErr=rpcErr.nextSibling; + } + rpcErr = this.toObject(rpcErr); + this.handleError(new Error("RPC Fault: ("+rpcErr.faultCode+") "+rpcErr.faultString)); return false } _______________________________________________ Commit-gnue mailing list [email protected] http://lists.gnu.org/mailman/listinfo/commit-gnue
