More changes to get both single and mass dynamic virtual hosting working with HTTP and HTTPS.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@961589 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
jsdelfino 2010-07-08 06:38:07 +00:00
commit 211c686bc6
32 changed files with 457 additions and 243 deletions

View file

@ -20,7 +20,7 @@ INCLUDES = -I${HTTPD_INCLUDE}
incl_HEADERS = *.hpp
incldir = $(prefix)/include/modules/http
dist_mod_SCRIPTS = httpd-conf httpd-start httpd-stop httpd-restart httpd-ca-conf httpd-cert-conf httpd-ssl-conf
dist_mod_SCRIPTS = httpd-conf httpd-start httpd-stop httpd-restart ssl-ca-conf ssl-cert-conf httpd-ssl-conf
moddir=$(prefix)/modules/http
curl_test_SOURCES = curl-test.cpp

View file

@ -30,13 +30,7 @@ htdocs=`readlink -f $4`
user=`id -un`
group=`id -gn`
modules_prefix=`cat $here/httpd-modules.prefix`
if [ "$5" = "vhost" ]; then
vhost="VirtualDocumentRoot $htdocs/domains/%1/"
maxr="MaxRequestsPerChild 1"
else
vhost="#VirtualDocumentRoot $htdocs/domains/%1/"
maxr="#MaxRequestsPerChild 1"
fi
vhost=$5
mkdir -p $root
mkdir -p $root/logs
@ -123,19 +117,34 @@ Options FollowSymLinks
Allow from all
</Location>
# Setup HTTP virtual host
# Setup HTTP virtual hosts
Listen $port
<VirtualHost _default_:$port>
<VirtualHost *:$port>
ServerName http://$host:$pport
UseCanonicalName Off
UseCanonicalPhysicalPort Off
# Setup mass dynamic virtual hosting
$vhost
</VirtualHost>
# Isolate dynamic virtual hosts
$maxr
EOF
# Generate mass dynamic virtual hosting configuration
if [ "$vhost" = "vhost" ]; then
cat >>$root/conf/httpd.conf <<EOF
# Setup mass dynamic virtual hosting
NameVirtualHost *:$port
<VirtualHost *:$port>
ServerName http://vhost.$host:$pport
ServerAlias *.$host
UseCanonicalName Off
VirtualDocumentRoot $htdocs/domains/%1/
</VirtualHost>
# Isolate virtual host based requests
MaxRequestsPerChild 1
EOF
fi

View file

@ -28,6 +28,7 @@ if [ "$sslpport" = "" ]; then
fi
htdocs=`readlink -f $4`
httpd_prefix=`cat $here/httpd.prefix`
vhost=$5
# Extract organization name from our CA certificate
org=`openssl x509 -noout -subject -nameopt multiline -in $root/conf/ca.crt | grep organizationName | awk -F "= " '{ print $2 }'`
@ -51,19 +52,31 @@ SSLMutex "file:$root/logs/ssl_mutex"
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
# HTTPS virtual host
# Setup HTTPS virtual hosts
Listen $sslport
<VirtualHost _default_:$sslport>
ServerName https://$host:$sslpport
UseCanonicalName Off
UseCanonicalPhysicalPort Off
# Enable SSL
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCACertificateFile "$root/conf/ca.crt"
SSLCertificateFile "$root/conf/server.crt"
SSLCertificateKeyFile "$root/conf/server.key"
<VirtualHost *:$sslport>
ServerName https://$host:$sslpport
UseCanonicalName Off
# Enable SSL
Include conf/ssl-vhost.conf
</VirtualHost>
# Route all wiring through HTTPS
SCAWiringServerName https://$host:$sslpport
EOF
# Generate VirtualHost SSL configuration
cat >$root/conf/ssl-vhost.conf <<EOF
# Enable SSL
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
BrowserMatch ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
# Logging
@ -88,12 +101,35 @@ AuthType Basic
AuthName "$host"
AuthUserFile "$root/conf/httpd.passwd"
Require valid-user
</location>
</Location>
EOF
# Generate mass dynamic virtual hosting configuration
if [ "$vhost" = "vhost" ]; then
cat >>$root/conf/httpd.conf <<EOF
# Setup mass dynamic virtual hosting
NameVirtualHost *:$sslport
SSLStrictSNIVHostCheck Off
<VirtualHost *:$sslport>
ServerName https://vhost.$host:$sslpport
ServerAlias *.$host
UseCanonicalName Off
VirtualDocumentRoot $htdocs/domains/%1/
# Enable SSL
SSLCACertificateFile "$root/conf/ca.crt"
SSLCertificateFile "$root/conf/vhost.crt"
SSLCertificateKeyFile "$root/conf/vhost.key"
Include conf/ssl-vhost.conf
</VirtualHost>
EOF
fi
# Create test users for HTTP basic authentication
$httpd_prefix/bin/htpasswd -bc $root/conf/httpd.passwd test test 2>/dev/null
$httpd_prefix/bin/htpasswd -b $root/conf/httpd.passwd foo foo 2>/dev/null

View file

@ -99,6 +99,35 @@ const string serverName(request_rec* r) {
return str(n);
}
/**
* Return the host name for a server.
*/
const string hostName(const server_rec* s) {
return s->server_hostname != NULL? s->server_hostname : "localhost";
}
/**
* Return the host name from an HTTP request.
*/
const string hostName(request_rec* r) {
const char* hn = ap_get_server_name(r);
return hn != NULL? hn : (r->server->server_hostname != NULL? r->server->server_hostname : "localhost");
}
/**
* Return the first subdomain name in a host name.
*/
const string subdomain(const string& host) {
return substr(host, 0, find(host, '.'));
}
/**
* Return true if a request is targeting a virtual host.
*/
const bool isVirtualHostRequest(const server_rec* s, request_rec* r) {
return serverName(r) != serverName(s);
}
/**
* Return the content type of a request.
*/

View file

@ -21,16 +21,21 @@
here=`readlink -f $0`; here=`dirname $here`
root=`readlink -f $1`
host=$2
if [ "$3" != "" ]; then
certname=$3
else
certname="server"
fi
# Don't regenerate the certificate if it already exists
if [ -f $root/conf/server.crt ]; then
if [ -f $root/conf/$certname.crt ]; then
return 0
fi
# Generate openssl configuration
mkdir -p $root/conf
umask 0007
cat >$root/conf/openssl-cert.conf <<EOF
cat >$root/conf/openssl-cert-$certname.conf <<EOF
[ req ]
default_bits = 1024
encrypt_key = no
@ -48,11 +53,11 @@ emailAddress = root@$host
EOF
# Generate a certificate request
openssl req -new -config $root/conf/openssl-cert.conf -out $root/conf/server-req.crt -keyout $root/conf/server.key
openssl req -new -config $root/conf/openssl-cert-$certname.conf -out $root/conf/$certname-req.crt -keyout $root/conf/$certname.key
# Generate a certificate, signed with our test certification authority certificate
openssl ca -batch -config $root/conf/openssl-ca.conf -out $root/conf/server.crt -infiles $root/conf/server-req.crt
openssl ca -batch -config $root/conf/openssl-ca.conf -out $root/conf/$certname.crt -infiles $root/conf/$certname-req.crt
# Export it to PKCS12 format, that's the format Web browsers want to import
openssl pkcs12 -export -passout pass: -out $root/conf/server.p12 -inkey $root/conf/server.key -in $root/conf/server.crt -certfile $root/conf/ca.crt
openssl pkcs12 -export -passout pass: -out $root/conf/$certname.p12 -inkey $root/conf/$certname.key -in $root/conf/$certname.crt -certfile $root/conf/ca.crt

View file

@ -77,6 +77,13 @@ const bool hasCompositeConf(const ServerConf& sc) {
return sc.contributionPath != "" && sc.compositeName != "";
}
/**
* Return true if a server contains a virtual host composite configuration.
*/
const bool hasVirtualCompositeConf(const ServerConf& sc) {
return sc.virtualHostContributionPath != "" && sc.virtualHostCompositeName != "";
}
/**
* Convert a result represented as a content + failure pair to a
* failable monad.
@ -421,6 +428,11 @@ const failable<list<value> > applyLifecycleExpr(const list<value>& impls, const
const failable<bool> confComponents(ServerConf& sc) {
if (!hasCompositeConf(sc))
return false;
debug(sc.contributionPath, "modeval::confComponents::contributionPath");
debug(sc.compositeName, "modeval::confComponents::compositeName");
if (sc.ca != "") debug(sc.ca, "modeval::confComponents::sslCA");
if (sc.cert != "") debug(sc.cert, "modeval::confComponents::sslCert");
if (sc.key != "") debug(sc.key, "modeval::confComponents::sslKey");
// Chdir to the deployed contribution
if (chdir(c_str(sc.contributionPath)) != 0)
@ -462,9 +474,8 @@ const failable<bool> startComponents(ServerConf& sc) {
class VirtualHostConf {
public:
VirtualHostConf(const ServerConf& ssc) : sc(ssc.server) {
sc.contributionPath = ssc.virtualHostContributionPath;
sc.compositeName = ssc.virtualHostCompositeName;
sc.wiringServerName = ssc.wiringServerName;
sc.virtualHostContributionPath = ssc.virtualHostContributionPath;
sc.virtualHostCompositeName = ssc.virtualHostCompositeName;
sc.ca = ssc.ca;
sc.cert = ssc.cert;
sc.key = ssc.key;
@ -489,10 +500,14 @@ const failable<bool> virtualHostConfig(ServerConf& sc, request_rec* r) {
debug(httpd::serverName(r), "modeval::virtualHostConfig::virtualHostName");
sc.wiringServerName = httpd::serverName(r);
debug(sc.wiringServerName, "modeval::virtualHostConfig::wiringServerName");
debug(sc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
// Resolve the configured virtual contribution under
// the virtual host's SCA contribution root
sc.contributionPath = sc.virtualHostContributionPath + httpd::subdomain(httpd::hostName(r)) + "/";
sc.compositeName = sc.virtualHostCompositeName;
// Configure the deployed components
debug(sc.contributionPath, "modeval::virtualHostConfig::contributionPath");
debug(sc.compositeName, "modeval::virtualHostConfig::compositeName");
const failable<bool> cr = confComponents(sc);
if (!hasContent(cr))
return cr;
@ -529,8 +544,8 @@ int handler(request_rec *r) {
// Process dynamic virtual host configuration, if any
VirtualHostConf vhc(sc);
const bool hasv = hasCompositeConf(vhc.sc);
if (hasv) {
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 httpd::reportStatus(mkfailure<int>(reason(cr)));
@ -538,7 +553,7 @@ int handler(request_rec *r) {
// Get the component implementation lambda
const list<value> path(pathValues(r->uri));
const list<value> impl(assoctree<value>(cadr(path), hasv? vhc.sc.implTree : sc.implTree));
const list<value> impl(assoctree<value>(cadr(path), usevh? vhc.sc.implTree : sc.implTree));
if (isNil(impl))
return httpd::reportStatus(mkfailure<int>(string("Couldn't find component implementation")));
@ -584,17 +599,17 @@ apr_status_t serverCleanup(void* v) {
const int postConfigMerge(const ServerConf& mainsc, server_rec* s) {
if (s == NULL)
return OK;
ostringstream sname;
debug(httpd::serverName(s), "modeval::postConfigMerge::serverName");
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval);
sc.wiringServerName = mainsc.wiringServerName;
debug(httpd::serverName(s), "modeval::postConfigMerge::serverName");
if (sc.wiringServerName == "") sc.wiringServerName = httpd::serverName(s);
debug(httpd::serverName(s), "modeval::postConfigMerge::wiringServerName");
sc.contributionPath = mainsc.contributionPath;
sc.compositeName = mainsc.compositeName;
sc.virtualHostContributionPath = mainsc.virtualHostContributionPath;
sc.virtualHostCompositeName = mainsc.virtualHostCompositeName;
sc.ca = mainsc.ca;
sc.cert = mainsc.cert;
sc.key = mainsc.key;
if (sc.ca == "") sc.ca = mainsc.ca;
if (sc.cert == "") sc.cert = mainsc.cert;
if (sc.key == "") sc.key = mainsc.key;
sc.implementations = mainsc.implementations;
sc.implTree = mainsc.implTree;
return postConfigMerge(mainsc, s->next);
@ -608,8 +623,7 @@ 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);
if (sc.wiringServerName == "") sc.wiringServerName = httpd::serverName(s);
debug(sc.wiringServerName, "modeval::postConfig::wiringServerName");
// Count the calls to post config
@ -638,8 +652,6 @@ int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp,
}
// Configure the deployed components
debug(sc.contributionPath, "modeval::postConfig::contributionPath");
debug(sc.compositeName, "modeval::postConfig::compositeName");
const failable<bool> res = confComponents(sc);
if (!hasContent(res)) {
cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
@ -649,7 +661,7 @@ int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp,
// Register a cleanup callback, called when the server is stopped or restarted
apr_pool_pre_cleanup_register(p, (void*)&sc, serverCleanup);
// Merge the config into any virtual hosts
// Merge the configuration into the virtual hosts
return postConfigMerge(sc, s->next);
}
@ -670,6 +682,9 @@ void childInit(apr_pool_t* p, server_rec* s) {
cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
exit(APEXIT_CHILDFATAL);
}
// Merge the updated configuration into the virtual hosts
postConfigMerge(*sc, s->next);
// Register a cleanup callback, called when the child is stopped or restarted
apr_pool_pre_cleanup_register(p, (void*)sc, serverCleanup);
@ -743,9 +758,9 @@ const command_rec commands[] = {
AP_INIT_TAKE1("SCAVirtualContribution", (const char*(*)())confVirtualContribution, NULL, RSRC_CONF, "SCA virtual host contribution location"),
AP_INIT_TAKE1("SCAVirtualComposite", (const char*(*)())confVirtualComposite, NULL, RSRC_CONF, "SCA virtual composite location"),
AP_INIT_TAKE12("SCASetEnv", (const char*(*)())confEnv, NULL, OR_FILEINFO, "Environment variable name and optional value"),
AP_INIT_TAKE1("SCASSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "SSL CA certificate file"),
AP_INIT_TAKE1("SCASSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "SSL certificate file"),
AP_INIT_TAKE1("SCASSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "SSL certificate key file"),
AP_INIT_TAKE1("SSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "SSL CA certificate file"),
AP_INIT_TAKE1("SSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "SSL certificate file"),
AP_INIT_TAKE1("SSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "SSL certificate key file"),
{NULL, NULL, NULL, 0, NO_ARGS, NULL}
};

View file

@ -71,6 +71,13 @@ const bool hasCompositeConf(const ServerConf& sc) {
return sc.contributionPath != "" && sc.compositeName != "";
}
/**
* Return true if a server contains a virtual host composite configuration.
*/
const bool hasVirtualCompositeConf(const ServerConf& sc) {
return sc.virtualHostContributionPath != "" && sc.virtualHostCompositeName != "";
}
/**
* Returns true if a URI is absolute.
*/
@ -235,6 +242,8 @@ const list<value> uriToComponentAssoc(const list<value>& c) {
const bool confComponents(ServerConf& sc) {
if (!hasCompositeConf(sc))
return true;
debug(sc.contributionPath, "modwiring::confComponents::contributionPath");
debug(sc.compositeName, "modwiring::confComponents::compositeName");
// Read the component configuration and store the references and service URIs
// in trees for fast retrieval later
@ -257,8 +266,8 @@ const bool confComponents(ServerConf& sc) {
class VirtualHostConf {
public:
VirtualHostConf(const ServerConf& ssc) : sc(ssc.server) {
sc.contributionPath = ssc.virtualHostContributionPath;
sc.compositeName = ssc.virtualHostCompositeName;
sc.virtualHostContributionPath = ssc.virtualHostContributionPath;
sc.virtualHostCompositeName = ssc.virtualHostCompositeName;
}
~VirtualHostConf() {
@ -273,10 +282,14 @@ public:
const failable<bool> virtualHostConfig(ServerConf& sc, request_rec* r) {
debug(httpd::serverName(sc.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 + httpd::subdomain(httpd::hostName(r)) + "/";
sc.compositeName = sc.virtualHostCompositeName;
// Configure the wiring for the deployed components
debug(sc.contributionPath, "modwiring::virtualHostConfig::contributionPath");
debug(sc.compositeName, "modwiring::virtualHostConfig::compositeName");
confComponents(sc);
return true;
}
@ -297,8 +310,8 @@ int translate(request_rec *r) {
// Process dynamic virtual host configuration, if any
VirtualHostConf vhc(sc);
const bool hasv = hasCompositeConf(vhc.sc);
if (hasv) {
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;
@ -306,10 +319,10 @@ int translate(request_rec *r) {
// Translate a component reference request
if (!strncmp(r->uri, "/references/", 12))
return translateReference(hasv? vhc.sc: sc, r);
return translateReference(usevh? vhc.sc: sc, r);
// Translate a service request
return translateService(hasv? vhc.sc : sc, r);
return translateService(usevh? vhc.sc : sc, r);
}
/**
@ -340,7 +353,6 @@ int handler(request_rec *r) {
const int postConfigMerge(const ServerConf& mainsc, server_rec* s) {
if (s == NULL)
return OK;
ostringstream sname;
debug(httpd::serverName(s), "modwiring::postConfigMerge::serverName");
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_wiring);
sc.contributionPath = mainsc.contributionPath;
@ -364,10 +376,8 @@ int postConfig(unused apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t
return OK;
// Configure the wiring for the deployed components
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_wiring);
debug(httpd::serverName(s), "modwiring::postConfig::serverName");
debug(sc.contributionPath, "modwiring::postConfig::contributionPath");
debug(sc.compositeName, "modwiring::postConfig::compositeName");
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_wiring);
confComponents(sc);
// Merge the config into any virtual hosts

View file

@ -21,25 +21,9 @@
here=`readlink -f $0`; here=`dirname $here`
root=`readlink -f $1`
servername=`cat $root/conf/httpd.conf | grep ServerName | tail -1 | awk '{ print $2 }'`
host=`echo $servername | awk -F ":" '{ printf "%s:%s", $1, $2 }'`
port=`cat $root/conf/httpd.conf | grep Listen | tail -1 | awk '{ print $2 }'`
ssl=`cat $root/conf/httpd.conf | grep "SSLEngine" | awk '{ print $2 }'`
if [ "$ssl" = "on" ]; then
cat >>$root/conf/httpd.conf <<EOF
# Configure SCA SSL support
SCASSLCACertificateFile "$root/conf/ca.crt"
SCASSLCertificateFile "$root/conf/server.crt"
SCASSLCertificateKeyFile "$root/conf/server.key"
EOF
fi
cat >>$root/conf/httpd.conf <<EOF
# Support for SCA component wiring
LoadModule mod_tuscany_wiring $here/libmod_tuscany_wiring.so
#SCAWiringServerName $host:$port
# Serve HTTP binding JavaScript client code
Alias /js/tuscany-ref.js $here/htdocs/js/tuscany-ref.js

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/ssl-ca-conf tmp localhost
../../modules/http/ssl-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
../../modules/server/server-conf tmp

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/ssl-ca-conf tmp localhost
../../modules/http/ssl-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
../../modules/server/server-conf tmp

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/ssl-ca-conf tmp localhost
../../modules/http/ssl-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
../../modules/server/server-conf tmp

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/ssl-ca-conf tmp localhost
../../modules/http/ssl-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
../../modules/server/server-conf tmp

View file

@ -28,8 +28,8 @@ fi
sudo ../../ubuntu/ip-redirect 80 8090
sudo ../../ubuntu/ip-redirect 443 8453
../../modules/http/httpd-ca-conf tmp $host
../../modules/http/httpd-cert-conf tmp $host
../../modules/http/ssl-ca-conf tmp $host
../../modules/http/ssl-cert-conf tmp $host
../../modules/http/httpd-conf tmp $host 8090/80 htdocs
../../modules/http/httpd-ssl-conf tmp $host 8453/443 htdocs
../../modules/server/server-conf tmp

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/ssl-ca-conf tmp localhost
../../modules/http/ssl-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
../../modules/server/server-conf tmp

View file

@ -17,8 +17,8 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/ssl-ca-conf tmp localhost
../../modules/http/ssl-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
../../modules/server/server-conf tmp

View file

@ -20,7 +20,7 @@ if WANT_PYTHON
dist_sample_SCRIPTS = start stop ssl-start uec2-start
sampledir = $(prefix)/samples/store-vhost
nobase_dist_sample_DATA = currency-converter.py fruits-catalog.py shopping-cart.py store.py store.composite htdocs/*.html htdocs/domains/joe/*.html htdocs/domains/jane/*.html
nobase_dist_sample_DATA = htdocs/*.html htdocs/domains/*/*.html domains/*/*.py domains/*/*.composite
dist_noinst_SCRIPTS = server-test
#TESTS = server-test

View file

@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Catalog implementation
def getcatalog(converter, currencyCode):
code = currencyCode()
def convert(price):
return converter("convert", "USD", code, price)
symbol = converter("symbol", code)
return (
(("'javaClass", "services.Item"), ("'name", "Passion"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
(("'javaClass", "services.Item"), ("'name", "Mango"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
(("'javaClass", "services.Item"), ("'name", "Pineapple"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
)

View file

@ -60,7 +60,7 @@
</component>
<component name="Cache">
<implementation.cpp path="../../components/cache" library="libmemcache"/>
<implementation.cpp path="../../../../components/cache" library="libmemcache"/>
<service name="Cache">
<t:binding.atom uri="cache"/>
</service>

View file

@ -0,0 +1,29 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Currency converter implementation
def convert(fr, to, amount):
if to == "EUR":
return amount * 0.70
return amount
def symbol(currency):
if currency == "EUR":
return "E"
return "$"

View file

@ -0,0 +1,75 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Shopping cart implementation
import uuid
import sys
cartId = "1234"
# Get the shopping cart from the cache
# Return an empty cart if not found
def getcart(id, cache):
cart = cache("get", (id,))
if cart is None:
return ()
return cart
# Post a new item to the cart, create a new cart if necessary
def post(collection, item, cache):
id = str(uuid.uuid1())
cart = ((item[0], id, item[2]),) + getcart(cartId, cache)
cache("put", (cartId,), cart)
return (id,)
# Find an item in the cart
def find(id, cart):
if cart == ():
return ("Item", "0", ())
elif id == cart[0][1]:
return cart[0]
else:
return find(id, cart[1:])
# Get items from the cart
def get(id, cache):
if id == ():
return ("Your Cart", cartId) + getcart(cartId, cache)
return find(id[0], getcart(cartId, cache))
# Delete items from the cart
def delete(id, cache):
if id == ():
return cache("delete", (cartId,))
return True
# Return the price of an item
def price(item):
return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
# Sum the prices of a list of items
def sum(items):
if items == ():
return 0
return price(items[0]) + sum(items[1:])
# Return the total price of the items in the cart
def gettotal(cache):
cart = getcart(cartId, cache)
return sum(cart)

View file

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
-->
<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
targetNamespace="http://store"
name="store">
<component name="Store">
<t:implementation.python script="store.py"/>
<service name="Widget">
<t:binding.http uri="store"/>
</service>
<reference name="catalog" target="Catalog"/>
<reference name="shoppingCart" target="ShoppingCart/Cart"/>
<reference name="shoppingTotal" target="ShoppingCart/Total"/>
</component>
<component name="Catalog">
<t:implementation.python script="fruits-catalog.py"/>
<property name="currencyCode">USD</property>
<service name="Catalog">
<t:binding.jsonrpc uri="catalog"/>
</service>
<reference name="currencyConverter" target="CurrencyConverter"/>
</component>
<component name="ShoppingCart">
<t:implementation.python script="shopping-cart.py"/>
<service name="ShoppingCart">
<t:binding.atom uri="shoppingCart"/>
</service>
<service name="Total">
<t:binding.jsonrpc uri="total"/>
</service>
<reference name="cache" target="Cache"/>
</component>
<component name="CurrencyConverter">
<t:implementation.python script="currency-converter.py"/>
<service name="CurrencyConverter">
<t:binding.jsonrpc uri="currencyConverter"/>
</service>
</component>
<component name="Cache">
<implementation.cpp path="../../../../components/cache" library="libmemcache"/>
<service name="Cache">
<t:binding.atom uri="cache"/>
</service>
</component>
</composite>

View file

@ -0,0 +1,40 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Store implementation
def post(item, catalog, shoppingCart, shoppingTotal):
return shoppingCart("post", item)
def getall(catalog, shoppingCart, shoppingTotal):
return shoppingCart("getall")
def get(id, catalog, shoppingCart, shoppingTotal):
return shoppingCart("get", id)
def getcatalog(catalog, shoppingCart, shoppingTotal):
return catalog("getcatalog")
def gettotal(catalog, shoppingCart, shoppingTotal):
return shoppingCart("gettotal")
def deleteall(catalog, shoppingCart, shoppingTotal):
return shoppingCart("deleteall")
def delete(id, catalog, shoppingCart, shoppingTotal):
return shoppingCart("delete", id)

View file

@ -19,139 +19,16 @@
<html>
<head>
<title>Store</title>
<script type="text/javascript" src="/js/tuscany-ref.js"></script>
<script type="text/javascript">
var component = new tuscany.sca.Component("Store");
//@Reference
var catalog = new tuscany.sca.Reference("catalog");
//@Reference
var shoppingCart = new tuscany.sca.Reference("shoppingCart");
//@Reference
var shoppingTotal = new tuscany.sca.Reference("shoppingTotal");
var catalogItems;
function catalog_getcatalogResponse(items, exception) {
if (exception){
alert(exception.message);
return;
}
var catalog = "";
for (var i=0; i<items.length; i++) {
var item = items[i].name + ' - ' + items[i].price;
catalog += '<input name="items" type="checkbox" value="' +
item + '">' + item + ' <br>';
}
document.getElementById('catalog').innerHTML=catalog;
catalogItems = items;
}
function shoppingCart_getResponse(feed) {
if (feed != null) {
var entries = feed.getElementsByTagName("entry");
var list = "";
for (var i=0; i<entries.length; i++) {
var content = entries[i].getElementsByTagName("content")[0];
var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
list += name + ' - ' + price + ' <br>';
}
document.getElementById("shoppingCart").innerHTML = list;
shoppingTotal.apply("gettotal", shoppingTotal_gettotalResponse);
}
}
function shoppingTotal_gettotalResponse(total, exception) {
if (exception) {
alert(exception.message);
return;
}
document.getElementById('total').innerHTML = total;
}
function shoppingCart_postResponse(entry) {
shoppingCart.get("", shoppingCart_getResponse);
}
function addToCart() {
var items = document.catalogForm.items;
var j = 0;
for (var i=0; i<items.length; i++)
if (items[i].checked) {
var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
'<item>' +
'<javaClass>' + catalogItems[i].javaClass + '</javaClass>' +
'<name>' + catalogItems[i].name + '</name>' +
'<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
'<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
'<price>' + catalogItems[i].price + '</price>' +
'</item>' +
'</content></entry>';
shoppingCart.post(entry, shoppingCart_postResponse);
items[i].checked = false;
}
}
function checkoutCart() {
document.getElementById('store').innerHTML='<h2>' +
'Thanks for Shopping With Us!</h2>'+
'<h2>Your Order</h2>'+
'<form name="orderForm">'+
document.getElementById('shoppingCart').innerHTML+
'<br>'+
document.getElementById('total').innerHTML+
'<br>'+
'<br>'+
'<input type="submit" value="Continue Shopping">'+
'</form>';
shoppingCart.del("", null);
}
function deleteCart() {
shoppingCart.del("", null);
document.getElementById('shoppingCart').innerHTML = "";
document.getElementById('total').innerHTML = "";
}
function init() {
try {
catalog.apply("getcatalog", catalog_getcatalogResponse);
shoppingCart.get("", shoppingCart_getResponse);
} catch(e){
alert(e);
}
}
</script>
</head>
<body onload="init()">
<body>
<h1>Store</h1>
<div id="store">
<h2>Catalog</h2>
<form name="catalogForm">
<div id="catalog" ></div>
<br>
<input type="button" onClick="addToCart()" value="Add to Cart">
</form>
<br>
<h2>Your Shopping Cart</h2>
<form name="shoppingCartForm">
<div id="shoppingCart"></div>
<br>
<div id="total"></div>
<br>
<input type="button" onClick="checkoutCart()" value="Checkout">
<input type="button" onClick="deleteCart()" value="Empty">
<a href="shoppingCart/">(feed)</a>
</form>
</div>
<p>For this sample to work, add the sample domain to your /etc/hosts as follows:<br/>
127.0.0.1 sca-store.com jane.sca-store.com joe.sca-store.com</p>
<p/>
<p>Jane's store at <a href="http://jane.sca-store.com:8090/">jane.sca-store.com</a>
<br/>Joe's store at <a href="http://joe.sca-store.com:8090/">joe.sca-store.com</a></p>
</body>
</html>

View file

@ -25,11 +25,11 @@ curl_prefix=`cat $here/../../modules/http/curl.prefix`
./start
sleep 2
# For this test to work, add the following line to your etc/hosts
127.0.0.1 jane.store.com joe.store.com
# For this test to work, add the test domain to your etc/hosts as follows:
# 127.0.0.1 sca-store.com jane.sca-store.com joe.sca-store.com
# Test HTTP GET
$curl_prefix/bin/curl http://jane.store.com:8090/ 2>/dev/null >tmp/jane.html
$curl_prefix/bin/curl http://jane.sca-store.com:8090/ 2>/dev/null >tmp/jane.html
diff tmp/jane.html htdocs/domains/jane/index.html
rc=$?

View file

@ -17,16 +17,20 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-ca-conf tmp localhost
../../modules/http/httpd-cert-conf tmp localhost
../../modules/http/httpd-conf tmp localhost 8090 htdocs
../../modules/http/httpd-ssl-conf tmp localhost 8453 htdocs
# For this sample to work, add the sample domain to your /etc/hosts as follows:
# 127.0.0.1 sca-store.com jane.sca-store.com joe.sca-store.com
../../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
../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs vhost
../../modules/http/httpd-ssl-conf tmp sca-store.com 8453 htdocs vhost
../../modules/server/server-conf tmp
../../modules/python/python-conf tmp
cat >>tmp/conf/httpd.conf <<EOF
# Configure SCA Composite
SCAContribution `pwd`/
SCAComposite store.composite
# Configure SCA Composite for mass dynamic virtual Hosting
SCAVirtualContribution `pwd`/domains/
SCAVirtualComposite store.composite
EOF

View file

@ -17,12 +17,12 @@
# specific language governing permissions and limitations
# under the License.
../../modules/http/httpd-conf tmp localhost 8090 htdocs vhost
../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs vhost
../../modules/server/server-conf tmp
../../modules/python/python-conf tmp
cat >>tmp/conf/httpd.conf <<EOF
# Configure SCA Composite for mass dynamic virtual Hosting
SCAVirtualContribution `pwd`/
# Configure SCA Composite for mass dynamic virtual hosting
SCAVirtualContribution `pwd`/domains/
SCAVirtualComposite store.composite
EOF

View file

@ -21,23 +21,25 @@
if [ "$1" != "" ]; then
host=$1
else
host="localhost"
# Default to dummy test domain
host="sca-store.com"
fi
# Ports 80, 443, 8090, 8453 need to be open
sudo ../../ubuntu/ip-redirect 80 8090
sudo ../../ubuntu/ip-redirect 443 8453
../../modules/http/httpd-ca-conf tmp $host
../../modules/http/httpd-cert-conf tmp $host
../../modules/http/httpd-conf tmp $host 8090/80 htdocs
../../modules/http/httpd-ssl-conf tmp $host 8453/443 htdocs
../../modules/http/ssl-ca-conf tmp $host
../../modules/http/ssl-cert-conf tmp $host server
../../modules/http/ssl-cert-conf tmp "*.$host" vhost
../../modules/http/httpd-conf tmp $host 8090/80 htdocs vhost
../../modules/http/httpd-ssl-conf tmp $host 8453/443 htdocs vhost
../../modules/server/server-conf tmp
../../modules/python/python-conf tmp
cat >>tmp/conf/httpd.conf <<EOF
# Configure SCA Composite
SCAContribution `pwd`/
SCAComposite store.composite
# Configure SCA Composite for mass dynamic virtual Hosting
SCAVirtualContribution `pwd`/domains/
SCAVirtualComposite store.composite
EOF