Enable multiple apps to co-exist under different paths in a single Virtual Host and Internet domain.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1200105 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
jsdelfino 2011-11-10 02:36:40 +00:00
commit 52cd682405
28 changed files with 378 additions and 429 deletions

View file

@ -89,6 +89,18 @@ const bool free(const buffer&b) {
return true;
}
/**
* Convert a database name to an absolute path.
*/
const string absdbname(const string& name) {
if (length(name) == 0 || c_str(name)[0] == '/')
return name;
char cwd[512];
if (getcwd(cwd, sizeof(cwd)) == NULL)
return name;
return string(cwd) + "/" + name;
}
/**
* Represents a TinyCDB connection.
*/
@ -99,7 +111,7 @@ public:
st.st_ino = 0;
}
TinyCDB(const string& name) : owner(true), name(name), fd(-1) {
TinyCDB(const string& name) : owner(true), name(absdbname(name)), fd(-1) {
debug(name, "tinycdb::tinycdb::name");
st.st_ino = 0;
}

View file

@ -103,7 +103,8 @@ const failable<value> start(const list<value>& params) {
// Connect to the configured database and table
const value dbname = ((lambda<value(list<value>)>)car(params))(list<value>());
const value format = ((lambda<value(list<value>)>)cadr(params))(list<value>());
filedb::FileDB& db = *(new (gc_new<filedb::FileDB>()) filedb::FileDB(dbname, format));
filedb::FileDB& db = *(new (gc_new<filedb::FileDB>()) filedb::FileDB(absdbname(dbname), format));
// Return the component implementation lambda function
return value(lambda<value(const list<value>&)>(applyfiledb(db)));

View file

@ -39,6 +39,18 @@
namespace tuscany {
namespace filedb {
/**
* Convert a database name to an absolute path.
*/
const string absdbname(const string& name) {
if (length(name) == 0 || c_str(name)[0] == '/')
return name;
char cwd[512];
if (getcwd(cwd, sizeof(cwd)) == NULL)
return name;
return string(cwd) + "/" + name;
}
/**
* Represents a FileDB connection.
*/
@ -48,7 +60,7 @@ public:
debug("filedb::filedb");
}
FileDB(const string& name, const string& format) : owner(true), name(name), format(format) {
FileDB(const string& name, const string& format) : owner(true), name(absdbname(name)), format(format) {
debug(name, "filedb::filedb::name");
debug(format, "filedb::filedb::format");
}

View file

@ -89,6 +89,18 @@ const bool free(const buffer&b) {
return true;
}
/**
* Convert a database name to an absolute path.
*/
const string absdbname(const string& name) {
if (length(name) == 0 || c_str(name)[0] == '/')
return name;
char cwd[512];
if (getcwd(cwd, sizeof(cwd)) == NULL)
return name;
return string(cwd) + "/" + name;
}
/**
* Represents a LevelDB connection.
*/
@ -99,7 +111,7 @@ public:
st.st_ino = 0;
}
LevelDB(const string& name) : owner(true), name(name), fd(-1) {
LevelDB(const string& name) : owner(true), name(absdbname(name)), fd(-1) {
debug(name, "leveldb::leveldb::name");
st.st_ino = 0;
}

View file

@ -48,6 +48,13 @@
<reference name="log" target="Log"/>
</component>
<component name="AppWidget">
<implementation.widget location="/app/index.html"/>
<reference name="user" target="User"/>
<reference name="pages" target="Pages"/>
<reference name="log" target="Log"/>
</component>
<component name="Accounts">
<implementation.python script="accounts.py"/>
<service name="Accounts">

View file

@ -3,7 +3,6 @@ CACHE MANIFEST
# Version 5
# App resources
/
/favicon.ico
/notauth/
/notfound/

View file

@ -17,7 +17,7 @@
* specific language governing permissions and limitations
* under the License.
-->
<html manifest="/cache-manifest.cmf">
<html manifest="cache-manifest.cmf">
<head>
<title></title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/>
@ -87,8 +87,13 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
<script type="text/javascript">
// Set the document title
document.title = location.hostname.split('.')[0];
/**
* Get the app name
*/
var appname = location.pathname.split('/')[1];
// Set page title
document.title = appname;
/**
* The main page div.
@ -98,12 +103,13 @@ var contentdiv = $('content');
/**
* Initialize the app HTTP clients.
*/
var pagecomp = sca.httpclient('page', '');
var startcomp = sca.httpclient('start', '/start');
var stopcomp = sca.httpclient('stop', '/stop');
var timercomp = sca.httpclient('timer', '/timer');
var animationcomp = sca.httpclient('animation', '/animation');
var locationcomp = sca.httpclient('location', '/location');
var appWidget = sca.component('AppWidget');
var pagecomp = sca.reference(appWidget, 'pages');
var startcomp = sca.httpclient('start', '/' + appname + '/start');
var stopcomp = sca.httpclient('stop', '/' + appname + '/stop');
var timercomp = sca.httpclient('timer', '/' + appname + '/timer');
var animationcomp = sca.httpclient('animation', '/' + appname + '/animation');
var locationcomp = sca.httpclient('location', '/' + appname + '/location');
/**
* Pre-fetch app resources.
@ -414,11 +420,11 @@ function docdata(doc) {
/**
* Bind a handler to a widget.
*/
function bindwidgethandler(e) {
function bindwidgethandler(e, appname) {
if (e.className == 'button') {
var b = car(childElements(e));
b.name = e.id;
b.onclick = function() { return buttonClickHandler(b.value); };
b.onclick = function() { return buttonClickHandler(b.value, appname); };
return e;
}
if (e.className == 'link') {
@ -427,7 +433,7 @@ function bindwidgethandler(e) {
if (hr.substring(0, 5) == 'link:' && hr.indexOf('://') == -1) {
var f = function(e) {
e.preventDefault();
return buttonClickHandler(hr.substring(5));
return buttonClickHandler(hr.substring(5), appname);
};
l.ontouchstart = l.onclick = f;
l.href = 'javascript:void()';
@ -528,7 +534,7 @@ function initwidget(e) {
/**
* Get app data from the main app page component.
*/
function getpagedata() {
function getpagedata(appname) {
try {
// Display component data on the page
@ -552,7 +558,7 @@ function getpagedata() {
function setupwidget(e) {
initwidget(e);
fixupwidget(e);
bindwidgethandler(e);
bindwidgethandler(e, appname);
}
// Setup the widgets
@ -634,10 +640,10 @@ function compquery() {
/**
* Handle a button click event.
*/
function buttonClickHandler(id) {
function buttonClickHandler(id, appname) {
try {
var uri = compquery();
return sca.component(id).get(uri, function(doc, e) {
return sca.component(id, appname).get(uri, function(doc, e) {
if (isNil(doc)) {
log('error on get(button, ' + uri + ')', e);
return false;
@ -824,8 +830,21 @@ function setupLocationHandler() {
return true;
}
/**
* Return the page in an ATOM entry.
*/
function atompage(doc) {
var entry = atom.readATOMEntry(mklist(doc));
if (isNil(entry))
return mklist();
var content = namedElementChild("'content", car(entry));
if (content == null)
return mklist();
return elementChildren(content);
}
// Load the app page
pagecomp.get('app.html', function(doc, e) {
pagecomp.get(appname, function(doc, e) {
//log('page get');
if (isNil(doc)) {
log('error getting app page', e);
@ -833,10 +852,12 @@ pagecomp.get('app.html', function(doc, e) {
}
// Set the app HTML page into the content div
contentdiv.innerHTML = doc;
//log('page', doc);
var el = atompage(doc);
contentdiv.innerHTML = writeStrings(writeXML(el, false));
// Merge in the app data
getpagedata();
getpagedata(appname);
});
/**

View file

@ -35,7 +35,7 @@
<form id="cloneAppForm">
<table style="width: 100%;">
<tr><td><b>New App Name:</b></td></tr>
<tr><td><input type="text" id="appName" size="15" autocapitalize="off" placeholder="Your app name"/>&nbsp;<span id="appDomain"></span></td></tr>
<tr><td><input type="text" id="appName" size="15" autocapitalize="off" placeholder="Your app name"/></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr>
<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>Sharing:</b></td></tr>
@ -56,23 +56,10 @@
// Get the app name
var appname = ui.fragmentParams(location)['app'];
/**
* Return the link to an app.
*/
function applink(appname) {
var protocol = location.protocol;
var host = location.hostname;
var port = ':' + location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/';
return link;
}
// Set page titles
var tclone = isNil(config.clone)? 'Clone' : config.clone;
document.title = ui.windowtitle(location.hostname) + ' - ' + tclone + ' - ' + appname;
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
$('appNameHeader').innerHTML = '<a href=\"/' + appname + '/\" target=\"' + '_blank' + '\">' + appname + '</a>';
$('th').innerHTML = tclone + ' this App';
$('cloneAppOKButton').value = tclone;
$('cloneAppOKButton').title = tclone + ' this app';
@ -80,9 +67,6 @@ $('cloneAppOKButton').title = tclone + ' this app';
// Set images
$('appimg').src = ui.b64img(appcache.get('/public/app.b64'));
// Init form
$('appDomain').innerHTML = '.' + location.hostname;
// Init service references
var editWidget = sca.component("EditWidget");
var dashboards = sca.reference(editWidget, "dashboards");

View file

@ -35,7 +35,7 @@
<form id="createAppForm">
<table style="width: 100%;">
<tr><td><b>App Name:</b></td></tr>
<tr><td><input type="text" id="appName" size="15" autocapitalize="off" placeholder="Your app name"/>&nbsp;<span id="appDomain"></span></td></tr>
<tr><td><input type="text" id="appName" size="15" autocapitalize="off" placeholder="Your app name"/></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr>
<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>Sharing:</b></td></tr>
@ -60,9 +60,6 @@ $('h1').innerHTML = ui.hometitle(location.hostname);
// Set images
$('appimg').src = ui.b64img(appcache.get('/public/app.b64'));
// Init form
$('appDomain').innerHTML = '.' + location.hostname;
// Init service references
var editWidget = sca.component("EditWidget");
var dashboards = sca.reference(editWidget, "dashboards");

View file

@ -68,22 +68,9 @@ if (isNil(appname)) {
ispalette = true;
}
/**
* Return the link to an app.
*/
function applink(appname) {
var protocol = location.protocol;
var host = location.hostname;
var port = ':' + location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/';
return link;
}
// Set page titles
document.title = ui.windowtitle(location.hostname) + ' - ' + (isNil(config.compose)? 'Composition' : config.compose) + ' - ' + appname;
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
$('appNameHeader').innerHTML = '<a href=\"/' + appname + '/\" target=\"' + '_blank' + '\">' + appname + '</a>';
/**
* Component value field, add, delete and play buttons.
@ -2060,7 +2047,7 @@ function complink(appname, cname) {
var port = ':' + location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/c/' + cname;
var link = protocol + '//' + host + port + '/' + appname + '/c/' + cname;
return link;
}
@ -2090,8 +2077,7 @@ function showdata(gcomp) {
return true;
if (isNil(gcomp))
return true;
var clink = complink(appname, gcomp.id);
cvalue.value = clink;
cvalue.value = complink(appname, gcomp.id);
cplay.innerHTML = '&lt;';
gvisible = false;
pdiv.innerHTML = '';

View file

@ -113,7 +113,7 @@ function showmenu(mdiv) {
mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
}
showmenu($('menu'));
showmenu(mdiv);
cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight);
/**

View file

@ -115,7 +115,7 @@ function showmenu(mdiv) {
}
showmenu(mdiv);
div.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight);
cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight);
/**
* Handle orientation change.

View file

@ -114,7 +114,7 @@ function showmenu(mdiv) {
mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
}
showmenu($('menu'));
showmenu(mdiv);
cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight);
/**

View file

@ -113,7 +113,7 @@ function showmenu(mdiv) {
mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
}
showmenu($('menu'));
showmenu(mdiv);
cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight);
/**

View file

@ -100,13 +100,13 @@ function applink(appname) {
var port = ':' + location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/';
var link = protocol + '//' + host + port + '/' + appname + '/';
return link;
}
// Set page titles
document.title = ui.windowtitle(location.hostname) + ' - Page - ' + appname;
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
$('appNameHeader').innerHTML = '<a href=\"/' + appname + '/\" target=\"' + '_blank' + '\">' + appname + '</a>';
/**
* Page editor area, widget value field, add, delete and play page buttons.
@ -149,8 +149,8 @@ resizeFields();
window.onresize = resizeFields;
// Init component references
var editWidget = sca.component("EditWidget");
var pages = sca.reference(editWidget, "pages");
var editWidget = sca.component('EditWidget');
var pages = sca.reference(editWidget, 'pages');
/**
* Page editing functions.
@ -763,7 +763,7 @@ function getpage(name, ediv) {
if (isNil(el))
buffer.innerHTML = '<div id="page"></div>';
else
buffer.innerHTML = writeStrings(writeXML(atompage(doc), false));
buffer.innerHTML = writeStrings(writeXML(el, false));
// Remove any existing page nodes from the editor div
var fnodes = filter(function(e) {
@ -941,8 +941,8 @@ function playpage() {
evisible = false;
pdiv.style.visibility = 'visible';
pdiv.innerHTML = '';
pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="' +
applink(appname) + '"></iframe>';
pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="/' +
appname + '"></iframe>';
setTimeout(function() {
ediv.style.visibility = 'hidden'
}, 0);

View file

@ -56,22 +56,9 @@
// Get the app name
var appname = ui.fragmentParams(location)['app'];
/**
* Return the link to an app.
*/
function applink(appname) {
var protocol = location.protocol;
var host = location.hostname;
var port = ':' + location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/';
return link;
}
// Set page titles
document.title = ui.windowtitle(location.hostname) + ' - Stats - ' + appname;
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
$('appNameHeader').innerHTML = '<a href=\"/' + appname + '/\" target=\"' + '_blank' + '\">' + appname + '</a>';
var tclone = isNil(config.clone)? 'Clone' : config.clone;
$('cloneApp').value = tclone;
$('cloneApp').title = tclone + ' this app';

View file

@ -77,19 +77,6 @@ var editWidget = sca.component("EditWidget");
var store = sca.reference(editWidget, "store");
var dashboards = sca.reference(editWidget, "dashboards");
/**
* Return the link to an app.
*/
function applink(appname) {
var protocol = location.protocol;
var host = location.hostname;
var port = ':' + location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/';
return link;
}
/**
* Edit an app.
*/
@ -151,7 +138,7 @@ function getapps(category) {
apps += '<div>' + ui.ahref('/#view=stats&app=' + name, '_view', '<img src="' + appimg + '" width="50" height="50" style="height: 50px; width: 50px; vertical-align: top; margin: 0px; padding: 0px;"></img>') + '</div>';
apps += '</td>';
apps += '<td class="tdw">';
apps += '<div style="font-weight: bold">' + ui.ahref(applink(name), '_blank', name) + '</div>';
apps += '<div style="font-weight: bold">' + ui.ahref('/' + name + '/', '_blank', name) + '</div>';
if (category == 'myapps')
apps += '<div style="color: #808080;">Shared</div>';
else

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
# For this module to work, add the app domains to your /etc/hosts as follows:
# 127.0.0.1 sca-store.com abc.sca-store.com xyz.sca-store.com ...
# For this module to work, add the sca-store.com domain to your /etc/hosts as follows:
# 127.0.0.1 sca-store.com
here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here`
jsprefix=`echo "import os; print os.path.realpath('$here/../js')" | python`
@ -26,14 +26,11 @@ jsprefix=`echo "import os; print os.path.realpath('$here/../js')" | python`
# Create SSL certificates
../../modules/http/ssl-ca-conf tmp sca-store.com
../../modules/http/ssl-cert-conf tmp sca-store.com server
../../modules/http/ssl-cert-conf tmp *.sca-store.com vhost
# Configure server with virtual hosting
# Configure server
../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs
../../modules/http/httpd-event-conf tmp
../../modules/http/vhost-conf tmp apps htdocs
../../modules/http/httpd-ssl-conf tmp 8453
../../modules/http/vhost-ssl-conf tmp
# Configure authentication
../../modules/http/open-auth-conf tmp
@ -55,15 +52,6 @@ ErrorDocument 404 /notfound/
ErrorDocument 401 /notauth/
ErrorDocument 500 /oops/
EOF
# Configure app home pages
cat >>tmp/conf/dvhost-ssl.conf <<EOF
# App error pages
ErrorDocument 404 /notfound/
ErrorDocument 401 /notauth/
ErrorDocument 500 /oops/
# Redirect www to main home page
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.sca-store\.com [NC]
@ -74,17 +62,6 @@ RewriteRule .* https://sca-store.com%{REQUEST_URI} [L,R]
EOF
cat >>tmp/conf/dvhost.conf <<EOF
# Redirect www to main home page
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.sca-store\.com [NC]
RewriteCond %{SERVER_PORT} !^80$
RewriteRule .* http://sca-store.com:%{SERVER_PORT}%{REQUEST_URI} [L,R]
RewriteCond %{HTTP_HOST} ^www\.sca-store\.com [NC]
RewriteRule .* http://sca-store.com%{REQUEST_URI} [L,R]
EOF
# Configure SCA contributions
cat >>tmp/conf/httpd.conf <<EOF
@ -98,7 +75,7 @@ SCAVirtualComposite app.composite
EOF
# Configure main aliases
# Configure resource aliases
cat >>tmp/conf/httpd.conf <<EOF
Alias /home/home.png $here/htdocs/home/home.png
@ -109,24 +86,21 @@ EOF
# Create app links and sub-directories if needed
./mkapplinks
# Configure app aliases
cat >>tmp/conf/dvhost-ssl.conf <<EOF
# Configure aliases
Alias /cache-manifest.cmf $here/htdocs/app/cache-manifest.cmf
Alias /data $here/htdocs/data
Alias /favicon.ico $here/htdocs/favicon.ico
Alias /footconfig.js $here/htdocs/footconfig.js
Alias /frame.html $here/htdocs/app/frame.html
Alias /headconfig.js $here/htdocs/headconfig.js
Alias /index.html $here/htdocs/app/index.html
Alias /login $here/htdocs/login
Alias /logout $here/htdocs/logout
Alias /notauth $here/htdocs/notauth
Alias /notfound $here/htdocs/notfound
Alias /notyet $here/htdocs/notyet
Alias /oops $here/htdocs/oops
Alias /public $here/htdocs/public
Alias /robots.txt $here/htdocs/robots.txt
# Configure app resource aliases
cat >>tmp/conf/svhost-ssl.conf <<EOF
<Location /v>
RewriteEngine on
# Map /v/<app-name>/<path> to htdocs/app/<path>
RewriteCond %{REQUEST_URI} ^/v/.+/.*$
RewriteRule /v/(.+)/(.*)$ $here/htdocs/app/\$2 [L]
# Redirect /v/<app-name> to /<app-name>/
RewriteCond %{REQUEST_URI} ^/v/[^/]+$
RewriteRule /v/([^/]+)$ /\$1/ [L,R]
</Location>
EOF
@ -137,5 +111,5 @@ mkdir -p tmp/appdata/filedb
../../components/cache/memcached-start
# Start server
../../modules/http/httpd-start tmp
../http/httpd-start tmp

View file

@ -17,16 +17,15 @@
# specific language governing permissions and limitations
# under the License.
# For this module to work, add the app domains to your /etc/hosts as follows:
# 127.0.0.1 sca-store.com abc.sca-store.com xyz.sca-store.com ...
# For this module to work, add the sca-store.com domain to your /etc/hosts as follows:
# 127.0.0.1 sca-store.com
here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here`
jsprefix=`echo "import os; print os.path.realpath('$here/../js')" | python`
# Configure server with virtual hosting
# Configure server
../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs
../../modules/http/httpd-event-conf tmp
../../modules/http/vhost-conf tmp apps htdocs
# Configure Python component support
../server/server-conf tmp
@ -39,15 +38,6 @@ ErrorDocument 404 /notfound/
ErrorDocument 401 /notauth/
ErrorDocument 500 /oops/
EOF
# Configure app home pages
cat >>tmp/conf/dvhost.conf <<EOF
# App error pages
ErrorDocument 404 /notfound/
ErrorDocument 401 /notauth/
ErrorDocument 500 /oops/
# Redirect www to main home page
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.sca-store\.com [NC]
@ -70,7 +60,7 @@ SCAVirtualComposite app.composite
EOF
# Configure main aliases
# Configure resource aliases
cat >>tmp/conf/httpd.conf <<EOF
Alias /home/home.png $here/htdocs/home/home.png
@ -81,24 +71,21 @@ EOF
# Create app links and sub-directories if needed
./mkapplinks
# Configure app aliases
cat >>tmp/conf/dvhost.conf <<EOF
# Configure aliases
Alias /cache-manifest.cmf $here/htdocs/app/cache-manifest.cmf
Alias /data $here/htdocs/data
Alias /favicon.ico $here/htdocs/favicon.ico
Alias /footconfig.js $here/htdocs/footconfig.js
Alias /frame.html $here/htdocs/app/frame.html
Alias /headconfig.js $here/htdocs/headconfig.js
Alias /index.html $here/htdocs/app/index.html
Alias /login $here/htdocs/login
Alias /logout $here/htdocs/logout
Alias /notauth $here/htdocs/notauth
Alias /notfound $here/htdocs/notfound
Alias /notyet $here/htdocs/notyet
Alias /oops $here/htdocs/oops
Alias /public $here/htdocs/public
Alias /robots.txt $here/htdocs/robots.txt
# Configure app resource aliases
cat >>tmp/conf/svhost.conf <<EOF
<Location /v>
RewriteEngine on
# Map /v/<app-name>/<path> to htdocs/app/<path>
RewriteCond %{REQUEST_URI} ^/v/.+/.*$
RewriteRule /v/(.+)/(.*)$ $here/htdocs/app/\$2 [L]
# Redirect /v/<app-name> to /<app-name>/
RewriteCond %{REQUEST_URI} ^/v/[^/]+$
RewriteRule /v/([^/]+)$ /\$1/ [L,R]
</Location>
EOF

View file

@ -181,17 +181,11 @@ cat >$root/conf/mpm.conf <<EOF
# Generated by: httpd-conf $*
LoadModule mpm_prefork_module ${modules_prefix}/modules/mod_mpm_prefork.so
EOF
uname=`uname -s`
if [ $uname = "Darwin" ]; then
cat >>$root/conf/mpm.conf <<EOF
# Generated by: httpd-conf $*
# Set thread stack size
ThreadStackSize 2097152
EOF
fi
# Generate modules list
cat >$root/conf/modules.conf <<EOF

View file

@ -31,15 +31,9 @@ cat >$root/conf/mpm.conf <<EOF
# Use HTTPD event MPM
LoadModule mpm_event_module ${modules_prefix}/modules/mod_mpm_event.so
EOF
uname=`uname -s`
if [ $uname = "Darwin" ]; then
cat >>$root/conf/mpm.conf <<EOF
# Generated by: httpd-event-conf $*
# Set thread stack size
ThreadStackSize 2097152
EOF
fi

View file

@ -156,8 +156,8 @@ Include conf/vhost-ssl.conf
# Declare SSL certificates used in this virtual host
SSLCACertificateFile "$root/cert/ca.crt"
SSLCertificateChainFile "$root/cert/ca.crt"
SSLCertificateFile "$root/cert/vhost.crt"
SSLCertificateKeyFile "$root/cert/vhost.key"
SSLCertificateFile "$root/cert/server.crt"
SSLCertificateKeyFile "$root/cert/server.key"
# Declare proxy SSL client certificates
SSLProxyCACertificateFile "$root/cert/ca.crt"

View file

@ -31,15 +31,9 @@ cat >$root/conf/mpm.conf <<EOF
# Use HTTPD worker MPM
LoadModule mpm_worker_module ${modules_prefix}/modules/mod_mpm_worker.so
EOF
uname=`uname -s`
if [ $uname = "Darwin" ]; then
cat >>$root/conf/mpm.conf <<EOF
# Generated by: httpd-event-conf $*
# Set thread stack size
ThreadStackSize 2097152
EOF
fi

View file

@ -580,7 +580,7 @@ sca.httpclient = function(name, uri, domain) {
sca.component = function(name, domain) {
if (!domain)
return new HTTPBindingClient(name, '/c/' + name, domain);
return new HTTPBindingClient(name, '/a/' + domain + '/c/' + name, domain);
return new HTTPBindingClient(name, '/' + domain + '/c/' + name, domain);
};
/**
@ -589,7 +589,7 @@ sca.component = function(name, domain) {
sca.reference = function(comp, rname) {
if (!comp.domain)
return new HTTPBindingClient(comp.name + '/' + rname, '/r/' + comp.name + '/' + rname, comp.domain);
return new HTTPBindingClient(comp.name + '/' + rname, '/a/' + comp.domain + '/r/' + comp.name + '/' + rname, comp.domain);
return new HTTPBindingClient(comp.name + '/' + rname, '/' + comp.domain + '/r/' + comp.name + '/' + rname, comp.domain);
};
/**

View file

@ -3,7 +3,7 @@
"result": {
"host": "localhost",
"path": [
"components",
"c",
"property-test"
],
"query": {

View file

@ -26,6 +26,8 @@
* HTTPD module used to eval component implementations.
*/
#include <sys/stat.h>
#include "string.hpp"
#include "stream.hpp"
#include "function.hpp"
@ -54,13 +56,15 @@ namespace modeval {
*/
class ServerConf {
public:
ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s), wiringServerName(""), contributionPath(""), compositeName(""), virtualHostContributionPath(""), virtualHostCompositeName(""), ca(""), cert(""), key("") {
ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s), contributionPath(""), compositeName(""), virtualHostContributionPath(""), virtualHostCompositeName(""), ca(""), cert(""), key("") {
}
ServerConf(apr_pool_t* p, const ServerConf& ssc, const string& name) : p(p), server(ssc.server), lifecycle(ssc.lifecycle), contributionPath(ssc.virtualHostContributionPath + name + "/"), compositeName(ssc.virtualHostCompositeName), virtualHostContributionPath(""), virtualHostCompositeName(""), ca(ssc.ca), cert(ssc.cert), key(ssc.key) {
}
const gc_pool p;
server_rec* server;
lambda<value(const list<value>&)> lifecycle;
string wiringServerName;
string contributionPath;
string compositeName;
string virtualHostContributionPath;
@ -119,7 +123,7 @@ public:
/**
* Handle an HTTP GET.
*/
const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>& impl) {
const failable<int> get(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) {
debug(r->uri, "modeval::get::uri");
// Inspect the query string
@ -145,8 +149,7 @@ const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>&
}
// Evaluate the GET expression
const list<value> path(pathValues(r->uri));
const list<value> params(append<value>(cddr(path), mkvalues(args)));
const list<value> params(append<value>(cddr(rpath), mkvalues(args)));
const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(params))));
if (!hasContent(val))
return mkfailure<int>(reason(val));
@ -222,7 +225,7 @@ const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>&
/**
* Handle an HTTP POST.
*/
const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>& impl) {
const failable<int> post(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) {
debug(r->uri, "modeval::post::url");
// Evaluate a JSON-RPC request and return a JSON result
@ -257,7 +260,6 @@ const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>
if (contains(ct, "application/atom+xml")) {
// Read the ATOM entry
const list<value> path(pathValues(r->uri));
const int rc = httpd::setupReadPolicy(r);
if(rc != OK)
return rc;
@ -266,7 +268,7 @@ const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>
const value entry = elementsToValues(content(atom::readATOMEntry(ls)));
// Evaluate the POST expression
const failable<value> val = failableResult(impl(cons<value>("post", mklist<value>(cddr(path), entry))));
const failable<value> val = failableResult(impl(cons<value>("post", mklist<value>(cddr(rpath), entry))));
if (!hasContent(val))
return mkfailure<int>(reason(val));
@ -288,11 +290,10 @@ const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>
/**
* Handle an HTTP PUT.
*/
const failable<int> put(request_rec* r, const lambda<value(const list<value>&)>& impl) {
const failable<int> put(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) {
debug(r->uri, "modeval::put::url");
// Read the ATOM entry
const list<value> path(pathValues(r->uri));
const int rc = httpd::setupReadPolicy(r);
if(rc != OK)
return rc;
@ -301,7 +302,7 @@ const failable<int> put(request_rec* r, const lambda<value(const list<value>&)>&
const value entry = elementsToValues(content(atom::readATOMEntry(ls)));
// Evaluate the PUT expression and update the corresponding resource
const failable<value> val = failableResult(impl(cons<value>("put", mklist<value>(cddr(path), entry))));
const failable<value> val = failableResult(impl(cons<value>("put", mklist<value>(cddr(rpath), entry))));
if (!hasContent(val))
return mkfailure<int>(reason(val));
if (val == value(false))
@ -312,12 +313,11 @@ const failable<int> put(request_rec* r, const lambda<value(const list<value>&)>&
/**
* Handle an HTTP DELETE.
*/
const failable<int> del(request_rec* r, const lambda<value(const list<value>&)>& impl) {
const failable<int> del(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) {
debug(r->uri, "modeval::delete::url");
// Evaluate an ATOM delete request
const list<value> path(pathValues(r->uri));
const failable<value> val = failableResult(impl(cons<value>("delete", mklist<value>(cddr(path)))));
const failable<value> val = failableResult(impl(cons<value>("delete", mklist<value>(cddr(rpath)))));
if (!hasContent(val))
return mkfailure<int>(reason(val));
if (val == value(false))
@ -325,16 +325,55 @@ const failable<int> del(request_rec* r, const lambda<value(const list<value>&)>&
return OK;
}
/**
* Translate a component request.
*/
const int translateRequest(const ServerConf& sc, const list<value>& rpath, request_rec *r) {
debug(rpath, "modeval::translateRequest::path");
if (isNil(rpath))
return DECLINED;
// Translate a component request
const value c = car(rpath);
if (c == string("components") || c == string("c")) {
r->handler = "mod_tuscany_eval";
return OK;
}
// Translate a request targeting a virtual host or virtual app
if (hasVirtualCompositeConf(sc) && !isNil(cdr(rpath))) {
const string cp = sc.virtualHostContributionPath + string(c) + "/" + sc.virtualHostCompositeName;
struct stat st;
const int s = stat(c_str(cp), &st);
if (s != -1) {
const value d = cadr(rpath);
if (d == string("components") || d == string("c")) {
r->handler = "mod_tuscany_eval";
return OK;
}
}
}
return DECLINED;
}
/**
* Translate a component request.
*/
int translate(request_rec *r) {
if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE)
return DECLINED;
if (strncmp(r->uri, "/components/", 12) != 0 && strncmp(r->uri, "/c/", 3) != 0)
return DECLINED;
r->handler = "mod_tuscany_eval";
return OK;
// Create a scoped memory pool
gc_scoped_pool pool(r->pool);
httpdDebugRequest(r, "modeval::translate::input");
// Get the server configuration
const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval);
// Translate the request
return translateRequest(sc, pathValues(r->uri), r);
}
/**
@ -473,7 +512,7 @@ const value mkunwiredProxy(const string& ref) {
/**
* Convert a list of component references to a list of proxy lambdas.
*/
const value mkrefProxy(const ServerConf& sc, const value& ref, unused const string& base) {
const value mkrefProxy(const ServerConf& sc, const value& ref) {
const value target = scdl::target(ref);
const bool wbyimpl = scdl::wiredByImpl(ref);
debug(ref, "modeval::mkrefProxy::ref");
@ -490,10 +529,10 @@ const value mkrefProxy(const ServerConf& sc, const value& ref, unused const stri
return mkimplProxy(sc, car(pathValues(target)));
}
const list<value> refProxies(const ServerConf& sc, const list<value>& refs, const string& base) {
const list<value> refProxies(const ServerConf& sc, const list<value>& refs) {
if (isNil(refs))
return refs;
return cons(mkrefProxy(sc, car(refs), base), refProxies(sc, cdr(refs), base));
return cons(mkrefProxy(sc, car(refs)), refProxies(sc, cdr(refs)));
}
/**
@ -525,7 +564,8 @@ struct pathPropProxy {
pathPropProxy(unused const value& v) {
}
const value operator()(unused const list<value>& params) const {
const value v = pathValues(currentRequest->uri);
const char* u = apr_table_get(currentRequest->headers_in, "X-Request-URI");
const value v = u != NULL? pathValues(string(u)) : list<value>();
debug(v, "modeval::pathPropProxy::value");
return v;
}
@ -624,9 +664,7 @@ const value evalComponent(ServerConf& sc, const value& comp) {
debug(impl, "modeval::evalComponent::impl");
// Convert component references to configured proxy lambdas
ostringstream base;
base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/";
const list<value> rpx(refProxies(sc, scdl::references(comp), str(base)));
const list<value> rpx(refProxies(sc, scdl::references(comp)));
// Convert component properties to configured proxy lambdas
const list<value> ppx(propProxies(scdl::properties(comp)));
@ -718,83 +756,112 @@ const failable<bool> startComponents(ServerConf& sc) {
return true;
}
/**
* Virtual host scoped server configuration.
*/
class VirtualHostConf {
public:
VirtualHostConf(const gc_pool& p, const ServerConf& sc) : sc(sc), vsc(pool(p), sc.server) {
vsc.lifecycle = sc.lifecycle;
vsc.virtualHostContributionPath = sc.virtualHostContributionPath;
vsc.virtualHostCompositeName = sc.virtualHostCompositeName;
vsc.ca = sc.ca;
vsc.cert = sc.cert;
vsc.key = sc.key;
}
~VirtualHostConf() {
extern const failable<bool> virtualHostCleanup(const ServerConf& vsc, const ServerConf& sc);
virtualHostCleanup(vsc, sc);
}
const ServerConf& sc;
ServerConf vsc;
};
/**
* Configure and start the components deployed in a virtual host.
*/
const failable<bool> virtualHostConfig(ServerConf& vsc, const ServerConf& sc, request_rec* r) {
// Determine the server name and wiring server name
debug(httpd::serverName(vsc.server), "modeval::virtualHostConfig::serverName");
const failable<bool> virtualHostConfig(ServerConf& sc, const ServerConf& ssc, request_rec* r) {
debug(httpd::serverName(ssc.server), "modeval::virtualHostConfig::serverName");
debug(httpd::serverName(r), "modeval::virtualHostConfig::virtualHostName");
vsc.wiringServerName = httpd::serverName(r);
debug(vsc.wiringServerName, "modeval::virtualHostConfig::wiringServerName");
debug(vsc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
// Resolve the configured virtual contribution under
// the virtual host's SCA contribution root
vsc.contributionPath = vsc.virtualHostContributionPath + http::subDomain(httpd::hostName(r)) + "/";
vsc.compositeName = vsc.virtualHostCompositeName;
debug(ssc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
debug(sc.contributionPath, "modeval::virtualHostConfig::contributionPath");
// Chdir to the virtual host's contribution
if (chdir(c_str(sc.contributionPath)) != 0)
return mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + sc.contributionPath);
// Configure the deployed components
const failable<bool> cr = confComponents(vsc);
const failable<bool> cr = confComponents(sc);
if (!hasContent(cr))
return cr;
// Start the configured components
const failable<bool> sr = startComponents(vsc);
const failable<bool> sr = startComponents(sc);
if (!hasContent(sr))
return sr;
// Store the implementation lambda functions (from both the virtual host and the
// main server) in a tree for fast retrieval
vsc.implTree = mkbtree(sort(append(vsc.implementations, sc.implementations)));
sc.implTree = mkbtree(sort(append(sc.implementations, ssc.implementations)));
return true;
}
/**
* Cleanup a virtual host.
*/
const failable<bool> virtualHostCleanup(const ServerConf& vsc, const ServerConf& sc) {
if (!hasCompositeConf(vsc))
const failable<bool> virtualHostCleanup(const ServerConf& sc, const ServerConf& ssc) {
if (!hasCompositeConf(sc))
return true;
debug("modeval::virtualHostCleanup");
// Stop the component implementations
applyLifecycleExpr(vsc.implementations, mklist<value>("stop"));
applyLifecycleExpr(sc.implementations, mklist<value>("stop"));
// Chdir back to the main server's contribution
if (chdir(c_str(sc.contributionPath)) != 0)
return mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + sc.contributionPath);
if (chdir(c_str(ssc.contributionPath)) != 0)
return mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + ssc.contributionPath);
return true;
}
/**
* Handle a component request.
*/
const int handleRequest(const ServerConf& sc, const list<value>& rpath, request_rec *r) {
debug(rpath, "modeval::handleRequest::path");
if (isNil(cdr(rpath)))
return HTTP_NOT_FOUND;
// Handle a request targeting a virtual host or virtual app
if (hasVirtualCompositeConf(sc)) {
if (httpd::isVirtualHostRequest(sc.server, r)) {
ServerConf vsc(r->pool, sc, http::subDomain(httpd::hostName(r)));
if (!hasContent(virtualHostConfig(vsc, sc, r)))
return HTTP_INTERNAL_SERVER_ERROR;
const int rc = handleRequest(vsc, rpath, r);
virtualHostCleanup(vsc, sc);
return rc;
}
const value c = car(rpath);
if (c != string("components") && c != string("c")) {
const string cp = sc.virtualHostContributionPath + string(c) + "/" + sc.virtualHostCompositeName;
struct stat st;
const int s = stat(c_str(cp), &st);
if (s != -1) {
ServerConf vsc(r->pool, sc, string(c));
if (!hasContent(virtualHostConfig(vsc, sc, r)))
return HTTP_INTERNAL_SERVER_ERROR;
const int rc = handleRequest(vsc, cdr(rpath), r);
virtualHostCleanup(vsc, sc);
return rc;
}
}
}
// Store the request uri path in a header
apr_table_setn(r->headers_in, "X-Request-URI", apr_pstrdup(r->pool, c_str(path(rpath))));
// Get the component implementation lambda
const list<value> impl(assoctree<value>(cadr(rpath), sc.implTree));
if (isNil(impl)) {
mkfailure<int>(string("Couldn't find component implementation: ") + cadr(rpath));
return HTTP_NOT_FOUND;
}
// Handle HTTP method
const lambda<value(const list<value>&)> l(cadr<value>(impl));
if (r->header_only)
return OK;
if(r->method_number == M_GET)
return httpd::reportStatus(get(rpath, r, l));
if(r->method_number == M_POST)
return httpd::reportStatus(post(rpath, r, l));
if(r->method_number == M_PUT)
return httpd::reportStatus(put(rpath, r, l));
if(r->method_number == M_DELETE)
return httpd::reportStatus(del(rpath, r, l));
return HTTP_NOT_IMPLEMENTED;
}
/**
* HTTP request handler.
*/
@ -813,38 +880,8 @@ int handler(request_rec *r) {
// Get the server configuration
const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval);
// Process dynamic virtual host configuration, if any
VirtualHostConf vhc(gc_pool(r->pool), sc);
const bool usevh = hasVirtualCompositeConf(vhc.vsc) && httpd::isVirtualHostRequest(sc.server, r);
if (usevh) {
const failable<bool> cr = virtualHostConfig(vhc.vsc, sc, r);
if (!hasContent(cr))
return httpd::reportStatus(mkfailure<int>(reason(cr)));
}
// Get the component implementation lambda
const list<value> path(pathValues(r->uri));
if (isNil(cdr(path)))
return HTTP_NOT_FOUND;
const list<value> impl(assoctree<value>(cadr(path), usevh? vhc.vsc.implTree : sc.implTree));
if (isNil(impl)) {
mkfailure<int>(string("Couldn't find component implementation: ") + cadr(path));
return HTTP_NOT_FOUND;
}
// Handle HTTP method
const lambda<value(const list<value>&)> l(cadr<value>(impl));
if (r->header_only)
return OK;
if(r->method_number == M_GET)
return httpd::reportStatus(get(r, l));
if(r->method_number == M_POST)
return httpd::reportStatus(post(r, l));
if(r->method_number == M_PUT)
return httpd::reportStatus(put(r, l));
if(r->method_number == M_DELETE)
return httpd::reportStatus(del(r, l));
return HTTP_NOT_IMPLEMENTED;
// Handle the request
return handleRequest(sc, pathValues(r->uri), r);
}
/**
@ -876,9 +913,6 @@ const int postConfigMerge(const ServerConf& mainsc, server_rec* s) {
return OK;
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval);
debug(httpd::serverName(s), "modeval::postConfigMerge::serverName");
if (sc.wiringServerName == "")
sc.wiringServerName = mainsc.wiringServerName != ""? mainsc.wiringServerName : httpd::serverName(s);
debug(sc.wiringServerName, "modeval::postConfigMerge::wiringServerName");
sc.lifecycle = mainsc.lifecycle;
sc.contributionPath = mainsc.contributionPath;
sc.compositeName = mainsc.compositeName;
@ -900,8 +934,6 @@ int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp,
// Get the server configuration and determine the wiring server name
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval);
debug(httpd::serverName(s), "modeval::postConfig::serverName");
if (sc.wiringServerName == "") sc.wiringServerName = httpd::serverName(s);
debug(sc.wiringServerName, "modeval::postConfig::wiringServerName");
// Count the calls to post config
const string k("tuscany::modeval::postConfig");
@ -982,12 +1014,6 @@ void childInit(apr_pool_t* p, server_rec* s) {
/**
* Configuration commands.
*/
const char* confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) {
gc_scoped_pool pool(cmd->pool);
ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
sc.wiringServerName = arg;
return NULL;
}
const char* confContribution(cmd_parms *cmd, unused void *c, const char *arg) {
gc_scoped_pool pool(cmd->pool);
ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
@ -1040,7 +1066,6 @@ const char* confEnv(unused cmd_parms *cmd, unused void *c, const char *name, con
* HTTP server module declaration.
*/
const command_rec commands[] = {
AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, RSRC_CONF, "SCA wiring server name"),
AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, RSRC_CONF, "SCA contribution location"),
AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"),
AP_INIT_TAKE1("SCAVirtualContribution", (const char*(*)())confVirtualContribution, NULL, RSRC_CONF, "SCA virtual host contribution location"),

View file

@ -57,6 +57,9 @@ public:
ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s), contributionPath(""), compositeName(""), virtualHostContributionPath(""), virtualHostCompositeName("") {
}
ServerConf(apr_pool_t* p, const ServerConf& ssc, const string& name) : p(p), server(ssc.server), contributionPath(ssc.virtualHostContributionPath + name + "/"), compositeName(ssc.virtualHostCompositeName), virtualHostContributionPath(""), virtualHostCompositeName("") {
}
const gc_pool p;
server_rec* server;
string contributionPath;
@ -85,12 +88,13 @@ const bool hasVirtualCompositeConf(const ServerConf& sc) {
* Route a /references/component-name/reference-name request,
* to the target of the component reference.
*/
int translateReference(const ServerConf& sc, request_rec *r) {
int translateReference(const ServerConf& sc, request_rec *r, const list<value>& rpath, const list<value>& apath) {
httpdDebugRequest(r, "modwiring::translateReference::input");
debug(r->uri, "modwiring::translateReference::uri");
debug(apath, "modwiring::translateReference::apath");
debug(rpath, "modwiring::translateReference::rpath");
// Find the requested component
const list<value> rpath(pathValues(r->uri));
if (isNil(cdr(rpath)))
return HTTP_NOT_FOUND;
const list<value> comp(assoctree(cadr(rpath), sc.references));
@ -110,8 +114,9 @@ int translateReference(const ServerConf& sc, request_rec *r) {
if (useModProxy) {
// Build proxy URI
string turi = target + path(pathInfo) + (r->args != NULL? string("?") + r->args : string(""));
r->filename = apr_pstrdup(r->pool, c_str(string("proxy:") + turi));
debug(r->filename, "modwiring::translateReference::filename");
const string proxy(string("proxy:") + turi);
debug(proxy, "modwiring::translateReference::proxy");
r->filename = apr_pstrdup(r->pool, c_str(proxy));
r->proxyreq = PROXYREQ_REVERSE;
r->handler = "proxy-server";
apr_table_setn(r->notes, "proxy-nocanon", "1");
@ -126,9 +131,10 @@ int translateReference(const ServerConf& sc, request_rec *r) {
// Route to a relative target URI using a local internal redirect
// /components/, target component name and request path info
const value tname = substr(target, 0, find(target, '/'));
const string tpath = path(cons(tname, pathInfo)) + (r->args != NULL? string("?") + r->args : string(""));
r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/components") + tpath));
debug(r->filename, "modwiring::translateReference::filename");
const string tp = path(append(apath, cons<value>(string("c"), cons(tname, pathInfo)))) + (r->args != NULL? string("?") + r->args : string(""));
const string redir(string("/redirect:") + tp);
debug(redir, "modwiring::translateReference::redirect");
r->filename = apr_pstrdup(r->pool, c_str(redir));
r->handler = "mod_tuscany_wiring";
return OK;
}
@ -159,64 +165,30 @@ const list<value> assocPath(const value& k, const list<value>& tree) {
/**
* Route a service request to the component providing the requested service.
*/
int translateService(const ServerConf& sc, request_rec *r) {
int translateService(const ServerConf& sc, request_rec *r, const list<value>& rpath, const list<value>& apath) {
httpdDebugRequest(r, "modwiring::translateService::input");
debug(r->uri, "modwiring::translateService::uri");
// Find the requested component
debug(sc.services, "modwiring::translateService::services");
const list<value> p(pathValues(r->uri));
const list<value> svc(assocPath(p, sc.services));
const list<value> svc(assocPath(rpath, sc.services));
if (isNil(svc))
return DECLINED;
debug(svc, "modwiring::translateService::service");
// Build a component-name + path-info URI
const list<value> target(cons<value>(cadr(svc), httpd::pathInfo(p, car(svc))));
const list<value> target(append(apath, cons<value>(string("c"), cons<value>(cadr(svc), httpd::pathInfo(rpath, car(svc))))));
debug(target, "modwiring::translateService::target");
// Dispatch to the target component using a local internal redirect
const string tp(path(target));
debug(tp, "modwiring::translateService::path");
const string redir(string("/redirect:/components") + tp);
const string tp(path(target) + (r->args != NULL? string("?") + r->args : string("")));
const string redir(string("/redirect:") + tp);
debug(redir, "modwiring::translateService::redirect");
r->filename = apr_pstrdup(r->pool, c_str(redir));
r->handler = "mod_tuscany_wiring";
return OK;
}
/**
* Route an /apps/app-name/... request to the target app domain.
*/
int translateDomain(request_rec *r) {
httpdDebugRequest(r, "modwiring::translateDomain::input");
debug(r->uri, "modwiring::translateDomain::uri");
// Extract the requested app name
const list<value> apath(pathValues(r->uri));
if (isNil(cdr(apath)))
return HTTP_NOT_FOUND;
// Compute the target uri in the target app domain
ostringstream turi;
turi << httpd::scheme(r) << "://" << string(cadr(apath)) << "." << httpd::hostName(r) << ":" << httpd::port(r) << string(path(cddr(apath))) << (r->args != NULL? string("?") + r->args : string(""));
debug(str(turi), "modwiring::translateDomain::appuri");
// Route to an absolute target URI using mod_proxy or an HTTP client redirect
if (useModProxy) {
r->filename = apr_pstrdup(r->pool, c_str(string("proxy:") + str(turi)));
debug(r->filename, "modwiring::translateDomain::filename");
r->proxyreq = PROXYREQ_REVERSE;
r->handler = "proxy-server";
apr_table_setn(r->notes, "proxy-nocanon", "1");
return OK;
}
debug(str(turi), "modwiring::translateDomain::location");
r->handler = "mod_tuscany_wiring";
return httpd::externalRedirect(str(turi), r);
}
/**
* Read the components declared in a composite.
*/
@ -298,38 +270,84 @@ const bool confComponents(ServerConf& sc) {
return true;
}
/**
* Virtual host scoped server configuration.
*/
class VirtualHostConf {
public:
VirtualHostConf(const gc_pool& p, const ServerConf& ssc) : sc(pool(p), ssc.server) {
sc.virtualHostContributionPath = ssc.virtualHostContributionPath;
sc.virtualHostCompositeName = ssc.virtualHostCompositeName;
}
~VirtualHostConf() {
}
ServerConf sc;
};
/**
* Configure and start the components deployed in a virtual host.
*/
const failable<bool> virtualHostConfig(ServerConf& sc, request_rec* r) {
debug(httpd::serverName(sc.server), "modwiring::virtualHostConfig::serverName");
const failable<ServerConf> virtualHostConfig(ServerConf& sc, const ServerConf& ssc, request_rec* r) {
debug(httpd::serverName(ssc.server), "modwiring::virtualHostConfig::serverName");
debug(httpd::serverName(r), "modwiring::virtualHostConfig::virtualHostName");
debug(sc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
// Resolve the configured virtual contribution under
// the virtual host's SCA contribution root
sc.contributionPath = sc.virtualHostContributionPath + http::subDomain(httpd::hostName(r)) + "/";
sc.compositeName = sc.virtualHostCompositeName;
debug(ssc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
debug(sc.contributionPath, "modwiring::virtualHostConfig::contributionPath");
// Configure the wiring for the deployed components
confComponents(sc);
return true;
return sc;
}
/**
* Translate an HTTP service or reference request and route it
* to the target component.
*/
const int translateRequest(const ServerConf& sc, request_rec *r, const list<value>& rpath, const list<value>& apath) {
debug(apath, "modwiring::translateRequest::apath");
debug(rpath, "modwiring::translateRequest::rpath");
if (isNil(apath) && isNil(rpath))
return DECLINED;
if (!isNil(rpath)) {
// No translation needed for a component or resource request
const value c = car(rpath);
if (c == string("components") || c == string("c") || c == string("vhosts") || c == string("v"))
return DECLINED;
// If the request is targeting a virtual host, use the corresponding
// virtual host configuration
const bool vcc = hasVirtualCompositeConf(sc);
if (vcc && httpd::isVirtualHostRequest(sc.server, r)) {
ServerConf vsc(r->pool, sc, http::subDomain(httpd::hostName(r)));
if (!hasContent(virtualHostConfig(vsc, sc, r)))
return HTTP_INTERNAL_SERVER_ERROR;
return translateRequest(vsc, r, rpath, list<value>());
}
// Translate a component reference request
if (c == string("references") || c == string("r"))
return translateReference(sc, r, rpath, apath);
// Attempt to translate the request to a service request
if (translateService(sc, r, rpath, apath) == OK)
return OK;
// If the request is targeting a virtual app, use the corresponding
// virtual host configuration
if (vcc) {
const string cp = sc.virtualHostContributionPath + string(c) + "/" + sc.virtualHostCompositeName;
struct stat st;
const int s = stat(c_str(cp), &st);
if (s == -1)
return DECLINED;
ServerConf vsc(r->pool, sc, string(c));
if (!hasContent(virtualHostConfig(vsc, sc, r)))
return HTTP_INTERNAL_SERVER_ERROR;
return translateRequest(vsc, r, cdr(rpath), mklist<value>(car(rpath)));
}
}
// If we're in a virtual app and the request is targeting a regular
// resource, redirect it to /v/<uri>. This will allow mapping to the
// actual resources using HTTPD aliases.
if (!isNil(apath)) {
const string tp = string("/v") + string(r->uri) + (r->args != NULL? string("?") + r->args : string(""));
const string redir = string("/redirect:") + tp;
debug(redir, "modwiring::translateRequest::redirect");
r->filename = apr_pstrdup(r->pool, c_str(redir));
r->handler = "mod_tuscany_wiring";
return OK;
}
return DECLINED;
}
/**
@ -340,35 +358,15 @@ int translate(request_rec *r) {
if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE)
return DECLINED;
// No translation needed for a component or tunnel request
if (!strncmp(r->uri, "/components/", 12) || !strncmp(r->uri, "/c/", 3))
return DECLINED;
// Create a scoped memory pool
gc_scoped_pool pool(r->pool);
// Translate an app domain request
if (!strncmp(r->uri, "/apps/", 6) || !strncmp(r->uri, "/a/", 3))
return translateDomain(r);
httpdDebugRequest(r, "modwiring::translate::input");
// Get the server configuration
const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_wiring);
// Process dynamic virtual host configuration
VirtualHostConf vhc(gc_pool(r->pool), sc);
const bool usevh = hasVirtualCompositeConf(vhc.sc) && httpd::isVirtualHostRequest(sc.server, r);
if (usevh) {
const failable<bool> cr = virtualHostConfig(vhc.sc, r);
if (!hasContent(cr))
return -1;
}
// Translate a component reference request
if (!strncmp(r->uri, "/references/", 12) || !strncmp(r->uri, "/r/", 3))
return translateReference(usevh? vhc.sc: sc, r);
// Translate a service request
return translateService(usevh? vhc.sc : sc, r);
// Translate the request
return translateRequest(sc, r, pathValues(r->uri), list<value>());
}
/**
@ -389,12 +387,12 @@ int handler(request_rec *r) {
// Create a scoped memory pool
gc_scoped_pool pool(r->pool);
// Do an internal redirect
httpdDebugRequest(r, "modwiring::handler::input");
debug(r->uri, "modwiring::handler::uri");
debug(r->filename, "modwiring::handler::filename");
debug(r->path_info, "modwiring::handler::path info");
// Do an internal redirect
if (r->args == NULL)
return httpd::internalRedirect(httpd::redirectURI(string(r->filename + 10), string(r->path_info)), r);
return httpd::internalRedirect(httpd::redirectURI(string(r->filename + 10), string(r->path_info), string(r->args)), r);

View file

@ -31,25 +31,6 @@ else
libsuffix=".so"
fi
conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
host=`echo $conf | awk '{ print $6 }'`
port=`echo $conf | awk '{ print $7 }' | awk -F "/" '{ print $1 }'`
pport=`echo $conf | awk '{ print $7 }' | awk -F "/" '{ print $2 }'`
if [ "$pport" = "" ]; then
pport=$port
fi
servername="http://$host:$pport"
sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"`
if [ "$sslconf" != "" ]; then
sslport=`echo $sslconf | awk '{ print $6 }' | awk -F "/" '{ print $1 }'`
sslpport=`echo $sslconf | awk '{ print $6 }' | awk -F "/" '{ print $2 }'`
if [ "$sslpport" = "" ]; then
sslpport=$sslport
fi
servername="https://$host:$sslpport"
fi
cat >>$root/conf/modules.conf <<EOF
# Generated by: server-conf $*
# Support for SCA component wiring
@ -59,9 +40,6 @@ EOF
cat >>$root/conf/httpd.conf <<EOF
# Generated by: server-conf $*
# Route all wiring through the configured server name
SCAWiringServerName $servername
# Serve JavaScript client scripts
Alias /component.js $jsprefix/htdocs/component.js
Alias /util.js $jsprefix/htdocs/util.js