diff options
Diffstat (limited to 'sca-cpp/branches/lightweight-sca/modules/http')
56 files changed, 6526 insertions, 0 deletions
diff --git a/sca-cpp/branches/lightweight-sca/modules/http/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/http/Makefile.am new file mode 100644 index 0000000000..a504adcda5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/Makefile.am @@ -0,0 +1,88 @@ +# 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. + +INCLUDES = -I${HTTPD_INCLUDE} + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/modules/http + +dist_mod_SCRIPTS = httpd-conf httpd-addr httpd-start httpd-stop httpd-restart ssl-ca-conf ssl-cert-conf ssl-cert-find httpd-ssl-conf basic-auth-conf cert-auth-conf form-auth-conf open-auth-conf passwd-auth-conf group-auth-conf cache-conf cache-ssl-conf cache-manifest proxy-conf proxy-base-conf proxy-ssl-conf proxy-balancer-conf proxy-member-conf proxy-ssl-member-conf proxy-ssl-nossl-member-conf alt-host-conf mass-host-conf mass-host-ssl-conf httpd-tunnel-ssl-conf tunnel-ssl-conf httpd-worker-conf httpd-event-conf httpd-loglevel-conf minify-html minify-js minify-css +moddir = $(prefix)/modules/http + +curl_test_SOURCES = curl-test.cpp +curl_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +curl_get_SOURCES = curl-get.cpp +curl_get_LDFLAGS = -lxml2 -lcurl -lmozjs + +curl_connect_SOURCES = curl-connect.cpp +curl_connect_LDFLAGS = -lxml2 -lcurl -lmozjs + +mod_LTLIBRARIES = libmod_tuscany_ssltunnel.la libmod_tuscany_openauth.la +noinst_DATA = libmod_tuscany_ssltunnel${libsuffix} libmod_tuscany_openauth${libsuffix} + +libmod_tuscany_ssltunnel_la_SOURCES = mod-ssltunnel.cpp +libmod_tuscany_ssltunnel_la_LDFLAGS = -lxml2 -lcurl -lmozjs +libmod_tuscany_ssltunnel${libsuffix}: + ln -s .libs/libmod_tuscany_ssltunnel${libsuffix} + +libmod_tuscany_openauth_la_SOURCES = mod-openauth.cpp +libmod_tuscany_openauth_la_LDFLAGS = -lxml2 -lcurl -lmozjs +libmod_tuscany_openauth${libsuffix}: + ln -s .libs/libmod_tuscany_openauth${libsuffix} + +mod_DATA = httpd.prefix httpd-apachectl.prefix httpd-modules.prefix curl.prefix pagespeed.prefix +nobase_dist_mod_DATA = conf/* + +EXTRA_DIST = htdocs/index.html htdocs/login/index.html htdocs/logout/index.html + +httpd.prefix: $(top_builddir)/config.status + echo ${HTTPD_PREFIX} >httpd.prefix +httpd-apachectl.prefix: $(top_builddir)/config.status + echo ${HTTPD_APACHECTL_PREFIX} >httpd-apachectl.prefix +httpd-modules.prefix: $(top_builddir)/config.status + echo ${HTTPD_MODULES_PREFIX} >httpd-modules.prefix +curl.prefix: $(top_builddir)/config.status + echo ${CURL_PREFIX} >curl.prefix + +if WANT_PAGESPEED + +pagespeed.prefix: $(top_builddir)/config.status + echo ${PAGESPEED_PREFIX} >pagespeed.prefix + +else + +pagespeed.prefix: $(top_builddir)/config.status + echo "" >pagespeed.prefix + +endif + +if WANT_MODSECURITY + +modsecurity.prefix: $(top_builddir)/config.status + echo ${MODSECURITY_PREFIX} >modsecurity.prefix + +dist_modsecurity_SCRIPTS = mod-security-conf mod-security-audit-conf +modsecurity_DATA = modsecurity.prefix +modsecuritydir = $(prefix)/modules/http + +endif + +dist_noinst_SCRIPTS = httpd-test http-test proxy-test +noinst_PROGRAMS = curl-test curl-get curl-connect +TESTS = httpd-test http-test proxy-test + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/alt-host-conf b/sca-cpp/branches/lightweight-sca/modules/http/alt-host-conf new file mode 100755 index 0000000000..f6148173b4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/alt-host-conf @@ -0,0 +1,32 @@ +#!/bin/sh + +# 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. + +# Generate an alternate host name configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 + +cat >>$root/conf/hostcond.conf <<EOF +# Generated by: alt-host-conf $* +RewriteCond %{HTTP_HOST} !^$host [NC] + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/basic-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/basic-auth-conf new file mode 100755 index 0000000000..8710d1fdf7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/basic-auth-conf @@ -0,0 +1,69 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD basic authentication configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then + loc="/" +else + loc="$3" +fi + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: basic-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate basic authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: basic-auth-conf $* +# Require clients to present a userid + password for HTTP +# basic authentication +<Location $loc> +AuthType Basic +AuthName "$host" +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +Require valid-user +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cache-conf b/sca-cpp/branches/lightweight-sca/modules/http/cache-conf new file mode 100755 index 0000000000..09ad5dc444 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cache-conf @@ -0,0 +1,41 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD cache configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/cache + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: cache-conf $* + +# Enable caching +CacheEnable disk / +CacheQuickHandler Off +CacheRoot $root/cache +CacheHeader On +#CacheDetailHeader On +CacheIgnoreQueryString On +CacheIgnoreCacheControl On +CacheIgnoreHeaders Set-Cookie + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cache-manifest b/sca-cpp/branches/lightweight-sca/modules/http/cache-manifest new file mode 100755 index 0000000000..3752a61dde --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cache-manifest @@ -0,0 +1,26 @@ +#!/bin/sh + +# 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. + +# Generate a cache-manifest.cmf file from a template and the list +# of files in the cached application +root=$1 +shift +sha=`cat $* | shasum | awk '{ print $1 }'` +cat $root/cache-template.cmf | sed -e "s/SHA1/$sha/" >$root/cache-manifest.cmf + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cache-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/cache-ssl-conf new file mode 100755 index 0000000000..7a902c37eb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cache-ssl-conf @@ -0,0 +1,41 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD cache configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/cache + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: cache-conf $* + +# Enable caching +CacheEnable disk / +CacheQuickHandler Off +CacheRoot $root/cache +CacheHeader On +#CacheDetailHeader On +CacheIgnoreQueryString On +CacheIgnoreCacheControl On +CacheIgnoreHeaders Set-Cookie + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cert-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/cert-auth-conf new file mode 100755 index 0000000000..a30fdfff8c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cert-auth-conf @@ -0,0 +1,74 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD certificate-based authentication configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: cert-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: cert-auth-conf $* +# Require clients to present a valid client certificate +SSLVerifyClient require +SSLVerifyDepth 1 + +<Location /> +AuthType Basic +AuthName "$host" +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +Require valid-user +</Location> + +EOF + +# Create password file and certificate-based users +cat >>$root/conf/httpd.passwd <<EOF +/C=US/ST=CA/L=San Francisco/O=$host/OU=server/CN=$host:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=$host/OU=proxy/CN=$host:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=$host/OU=tunnel/CN=$host:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=localhost/OU=server/CN=localhost:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=localhost/OU=tunnel/CN=localhost:xxj31ZMTZzkVA +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/conf/mime.types b/sca-cpp/branches/lightweight-sca/modules/http/conf/mime.types new file mode 100644 index 0000000000..3f083f9a32 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/conf/mime.types @@ -0,0 +1,608 @@ +# 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. + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at <http://www.iana.org/assignments/media-types/>. + +# MIME type Extensions +application/activemessage +application/andrew-inset ez +application/applefile +application/atom+xml atom +application/atomicmail +application/batch-smtp +application/beep+xml +application/cals-1840 +application/cnrp+xml +application/commonground +application/cpl+xml +application/cybercash +application/dca-rft +application/dec-dx +application/dvcs +application/edi-consent +application/edifact +application/edi-x12 +application/eshop +application/font-tdpfr +application/http +application/hyperstudio +application/iges +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc +application/mathematica +application/mathml+xml mathml +application/msword doc +application/news-message-id +application/news-transmission +application/ocsp-request +application/ocsp-response +application/octet-stream bin dms lha lzh exe class so dll dmg +application/oda oda +application/ogg ogg +application/parityfec +application/pdf pdf +application/pgp-encrypted +application/pgp-keys +application/pgp-signature +application/pkcs10 +application/pkcs7-mime +application/pkcs7-signature +application/pkix-cert +application/pkix-crl +application/pkixcmp +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww +application/prs.nprend +application/prs.plucker +application/qsig +application/rdf+xml rdf +application/reginfo+xml +application/remote-printing +application/riscos +application/rtf +application/sdp +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog +application/sieve +application/slate +application/smil smi smil +application/srgs gram +application/srgs+xml grxml +application/timestamp-query +application/timestamp-reply +application/tve-trigger +application/vemmi +application/vnd.3gpp.pic-bw-large +application/vnd.3gpp.pic-bw-small +application/vnd.3gpp.pic-bw-var +application/vnd.3gpp.sms +application/vnd.3m.post-it-notes +application/vnd.accpac.simply.aso +application/vnd.accpac.simply.imp +application/vnd.acucobol +application/vnd.acucorp +application/vnd.adobe.xfdf +application/vnd.aether.imp +application/vnd.amiga.ami +application/vnd.anser-web-certificate-issue-initiation +application/vnd.anser-web-funds-transfer-initiation +application/vnd.audiograph +application/vnd.blueice.multipass +application/vnd.bmi +application/vnd.businessobjects +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cinderella +application/vnd.claymore +application/vnd.commerce-battelle +application/vnd.commonspace +application/vnd.contact.cmsg +application/vnd.cosmocaller +application/vnd.criticaltools.wbs+xml +application/vnd.ctc-posml +application/vnd.cups-postscript +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.curl +application/vnd.cybank +application/vnd.data-vision.rdz +application/vnd.dna +application/vnd.dpgraph +application/vnd.dreamfactory +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven +application/vnd.epson.esf +application/vnd.epson.msf +application/vnd.epson.quickanime +application/vnd.epson.salt +application/vnd.epson.ssf +application/vnd.ericsson.quickcall +application/vnd.eudora.data +application/vnd.fdf +application/vnd.ffsns +application/vnd.fints +application/vnd.flographit +application/vnd.framemaker +application/vnd.fsc.weblaunch +application/vnd.fujitsu.oasys +application/vnd.fujitsu.oasys2 +application/vnd.fujitsu.oasys3 +application/vnd.fujitsu.oasysgp +application/vnd.fujitsu.oasysprs +application/vnd.fujixerox.ddd +application/vnd.fujixerox.docuworks +application/vnd.fujixerox.docuworks.binder +application/vnd.fut-misnet +application/vnd.grafeq +application/vnd.groove-account +application/vnd.groove-help +application/vnd.groove-identity-message +application/vnd.groove-injector +application/vnd.groove-tool-message +application/vnd.groove-tool-template +application/vnd.groove-vcard +application/vnd.hbci +application/vnd.hhe.lesson-player +application/vnd.hp-hpgl +application/vnd.hp-hpid +application/vnd.hp-hps +application/vnd.hp-pcl +application/vnd.hp-pclxl +application/vnd.httphone +application/vnd.hzn-3d-crossword +application/vnd.ibm.afplinedata +application/vnd.ibm.electronic-media +application/vnd.ibm.minipay +application/vnd.ibm.modcap +application/vnd.ibm.rights-management +application/vnd.ibm.secure-container +application/vnd.informix-visionary +application/vnd.intercon.formnet +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo +application/vnd.intu.qfx +application/vnd.irepository.package+xml +application/vnd.is-xpr +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.jisp +application/vnd.kde.karbon +application/vnd.kde.kchart +application/vnd.kde.kformula +application/vnd.kde.kivio +application/vnd.kde.kontour +application/vnd.kde.kpresenter +application/vnd.kde.kspread +application/vnd.kde.kword +application/vnd.kenameaapp +application/vnd.koan +application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop +application/vnd.llamagraphics.life-balance.exchange+xml +application/vnd.lotus-1-2-3 +application/vnd.lotus-approach +application/vnd.lotus-freelance +application/vnd.lotus-notes +application/vnd.lotus-organizer +application/vnd.lotus-screencam +application/vnd.lotus-wordpro +application/vnd.mcd +application/vnd.mediastation.cdkey +application/vnd.meridian-slingshot +application/vnd.micrografx.flo +application/vnd.micrografx.igx +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf +application/vnd.mobius.dis +application/vnd.mobius.mbk +application/vnd.mobius.mqy +application/vnd.mobius.msl +application/vnd.mobius.plc +application/vnd.mobius.txf +application/vnd.mophun.application +application/vnd.mophun.certificate +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry +application/vnd.ms-asf +application/vnd.ms-excel xls +application/vnd.ms-lrm +application/vnd.ms-powerpoint ppt +application/vnd.ms-project +application/vnd.ms-tnef +application/vnd.ms-works +application/vnd.ms-wpl +application/vnd.mseq +application/vnd.msign +application/vnd.music-niff +application/vnd.musician +application/vnd.netfpx +application/vnd.noblenet-directory +application/vnd.noblenet-sealer +application/vnd.noblenet-web +application/vnd.novadigm.edm +application/vnd.novadigm.edx +application/vnd.novadigm.ext +application/vnd.obn +application/vnd.osa.netdeploy +application/vnd.palm +application/vnd.pg.format +application/vnd.pg.osasli +application/vnd.powerbuilder6 +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.previewsystems.box +application/vnd.publishare-delta-tree +application/vnd.pvi.ptid1 +application/vnd.pwg-multiplexed +application/vnd.pwg-xhtml-print+xml +application/vnd.quark.quarkxpress +application/vnd.rapid +application/vnd.s3sms +application/vnd.sealed.net +application/vnd.seemail +application/vnd.shana.informed.formdata +application/vnd.shana.informed.formtemplate +application/vnd.shana.informed.interchange +application/vnd.shana.informed.package +application/vnd.smaf +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.street-stream +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.triscape.mxs +application/vnd.trueapp +application/vnd.truedoc +application/vnd.ufdl +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio +application/vnd.visionary +application/vnd.vividence.scriptfile +application/vnd.vsf +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf +application/vnd.wv.csp+wbxml +application/vnd.xara +application/vnd.xfdl +application/vnd.yamaha.hv-dic +application/vnd.yamaha.hv-script +application/vnd.yamaha.hv-voice +application/vnd.yellowriver-custom-menu +application/voicexml+xml vxml +application/watcherinfo+xml +application/whoispp-query +application/whoispp-response +application/wita +application/wordperfect5.1 +application/x-bcpio bcpio +application/x-cdlink vcd +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-javascript js +application/x-koan skp skd skt skm +application/x-latex latex +application/x-netcdf nc cdf +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/x400-bp +application/xhtml+xml xhtml xht +application/xslt+xml xslt +application/xml xml xsl +application/xml-dtd dtd +application/xml-external-parsed-entity +application/zip zip +audio/32kadpcm +audio/amr +audio/amr-wb +audio/basic au snd +audio/cn +audio/dat12 +audio/dsr-es201108 +audio/dvi4 +audio/evrc +audio/evrc0 +audio/g722 +audio/g.722.1 +audio/g723 +audio/g726-16 +audio/g726-24 +audio/g726-32 +audio/g726-40 +audio/g728 +audio/g729 +audio/g729D +audio/g729E +audio/gsm +audio/gsm-efr +audio/l8 +audio/l16 +audio/l20 +audio/l24 +audio/lpc +audio/midi mid midi kar +audio/mpa +audio/mpa-robust +audio/mp4a-latm +audio/mpeg mpga mp2 mp3 +audio/parityfec +audio/pcma +audio/pcmu +audio/prs.sid +audio/qcelp +audio/red +audio/smv +audio/smv0 +audio/telephone-event +audio/tone +audio/vdvi +audio/vnd.3gpp.iufp +audio/vnd.cisco.nse +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds +audio/vnd.everad.plj +audio/vnd.lucent.voice +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 +audio/vnd.nuera.ecelp7470 +audio/vnd.nuera.ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.vmx.cvsd +audio/x-aiff aif aiff aifc +audio/x-alaw-basic +audio/x-mpegurl m3u +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin +application/vnd.rn-realmedia rm +audio/x-wav wav +chemical/x-pdb pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +image/g3fax +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/naplps +image/png png b64 +image/prs.btif +image/prs.pti +image/svg+xml svg +image/t38 +image/tiff tiff tif +image/tiff-fx +image/vnd.cns.inf2 +image/vnd.djvu djvu djv +image/vnd.dwg +image/vnd.dxf +image/vnd.fastbidsheet +image/vnd.fpx +image/vnd.fst +image/vnd.fujixerox.edmics-mmr +image/vnd.fujixerox.edmics-rlc +image/vnd.globalgraphics.pgb +image/vnd.mix +image/vnd.ms-modi +image/vnd.net-fpx +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff +image/x-cmu-raster ras +image/x-icon ico +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/news +message/partial +message/rfc822 +message/s-http +message/sip +message/sipfrag +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf +model/vnd.flatland.3dml +model/vnd.gdl +model/vnd.gs-gdl +model/vnd.gtw +model/vnd.mts +model/vnd.parasolid.transmit.binary +model/vnd.parasolid.transmit.text +model/vnd.vtu +model/vrml wrl vrml +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/cache-manifest cmf +text/calendar ics ifb +text/css css +text/directory +text/enriched +text/html html htm +text/parityfec +text/plain asc txt +text/prs.lines.tag +text/rfc822-headers +text/richtext rtx +text/rtf rtf +text/sgml sgml sgm +text/t140 +text/tab-separated-values tsv +text/uri-list +text/vnd.abc +text/vnd.curl +text/vnd.dmclientscript +text/vnd.fly +text/vnd.fmi.flexstor +text/vnd.in3d.3dml +text/vnd.in3d.spot +text/vnd.iptc.nitf +text/vnd.iptc.newsml +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.net2phone.commcenter.command +text/vnd.sun.j2me.app-descriptor +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-setext etx +text/xml +text/xml-external-parsed-entity +video/bmpeg +video/bt656 +video/celb +video/dv +video/h261 +video/h263 +video/h263-1998 +video/h263-2000 +video/jpeg +video/mp1s +video/mp2p +video/mp2t +video/mp4v-es +video/mpv +video/mpeg mpeg mpg mpe +video/nv +video/parityfec +video/pointer +video/quicktime qt mov +video/smpte292m +video/vnd.fvt +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.nokia.interleaved-multimedia +video/vnd.objectvideo +video/vnd.vivo +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice diff --git a/sca-cpp/branches/lightweight-sca/modules/http/curl-connect.cpp b/sca-cpp/branches/lightweight-sca/modules/http/curl-connect.cpp new file mode 100644 index 0000000000..9f5ee17368 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/curl-connect.cpp @@ -0,0 +1,98 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +/** + * HTTP connect command line test tool. + */ + +#include <assert.h> +#include <stdio.h> +#include "stream.hpp" +#include "string.hpp" +#include "perf.hpp" +#include "http.hpp" + +namespace tuscany { +namespace http { + +const bool testConnect(const string& url, const string& ca = "", const string& cert = "", const string& key = "") { + gc_scoped_pool p; + + CURLSession cs(ca, cert, key, "", 0); + const failable<bool> crc = connect(url, cs); + assert(hasContent(crc)); + + apr_pollset_t* pollset; + apr_status_t cprc = apr_pollset_create(&pollset, 2, pool(p), 0); + assert(cprc == APR_SUCCESS); + apr_socket_t* csock = sock(0, p); + const apr_pollfd_t* cpollfd = pollfd(csock, APR_POLLIN | APR_POLLERR | APR_POLLNVAL | APR_POLLHUP, p); + apr_pollset_add(pollset, cpollfd); + apr_socket_t* tsock = sock(cs); + const apr_pollfd_t* tpollfd = pollfd(tsock, APR_POLLIN | APR_POLLERR | APR_POLLNVAL | APR_POLLHUP, p); + apr_pollset_add(pollset, tpollfd); + + const apr_pollfd_t* pollfds; + apr_int32_t pollcount; + for(;;) { + apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds); + assert(pollrc == APR_SUCCESS); + + for (; pollcount > 0; pollcount--, pollfds++) { + if (pollfds->rtnevents & APR_POLLIN) { + char data[8192]; + if (pollfds->desc.s == csock) { + const size_t rl = ::read(0, data, sizeof(data)); + if (rl == (size_t)-1) + return false; + if (rl > 0) { + const failable<bool> src = http::send(data, rl, cs); + assert(hasContent(src)); + } + } + else { + const failable<size_t> frl = http::recv(data, sizeof(data), cs); + assert(hasContent(frl)); + const size_t rl = content(frl); + if (rl == 0) + return true; + const size_t wl = ::write(0, data, rl); + assert(wl == rl); + } + continue; + } + assert(!(pollfds->rtnevents & (APR_POLLERR | APR_POLLHUP | APR_POLLNVAL))); + } + } + return true; +} + +} +} + +int main(unused const int argc, const char** argv) { + if (argc > 2) + tuscany::http::testConnect(tuscany::string(argv[1]), tuscany::string(argv[2]), tuscany::string(argv[3]), tuscany::string(argv[4])); + else + tuscany::http::testConnect(tuscany::string(argv[1])); + return 0; +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/curl-get.cpp b/sca-cpp/branches/lightweight-sca/modules/http/curl-get.cpp new file mode 100644 index 0000000000..a16daeeae3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/curl-get.cpp @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +/** + * HTTP GET command line test tool. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "perf.hpp" +#include "http.hpp" + +namespace tuscany { +namespace http { + +const bool testGet(const string& url, const string& ca = "", const string& cert = "", const string& key = "") { + CURLSession ch(ca, cert, key, "", 0); + const failable<value> val = get(url, ch); + assert(hasContent(val)); + cout << content(val) << endl; + return true; +} + +} +} + +int main(unused const int argc, const char** argv) { + if (argc > 2) + tuscany::http::testGet(tuscany::string(argv[1]), tuscany::string(argv[2]), tuscany::string(argv[3]), tuscany::string(argv[4])); + else + tuscany::http::testGet(tuscany::string(argv[1])); + return 0; +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/curl-test.cpp b/sca-cpp/branches/lightweight-sca/modules/http/curl-test.cpp new file mode 100644 index 0000000000..f0806ea577 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/curl-test.cpp @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +/** + * Test HTTP client functions. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "perf.hpp" +#include "http.hpp" + +namespace tuscany { +namespace http { + +string testURI = "http://localhost:8090"; + +ostream* curlWriter(const string& s, ostream* os) { + (*os) << s; + return os; +} + +const bool testGet() { + CURLSession ch("", "", "", "", 0); + { + ostringstream os; + const failable<list<ostream*> > r = get<ostream*>(curlWriter, &os, testURI, ch); + assert(hasContent(r)); + assert(contains(str(os), "HTTP/1.1 200 OK")); + assert(contains(str(os), "It works")); + } + { + const failable<value> r = getcontent(testURI, ch); + assert(hasContent(r)); + assert(contains(car(reverse(list<value>(content(r)))), "It works")); + } + return true; +} + +struct getLoop { + CURLSession& ch; + getLoop(CURLSession& ch) : ch(ch) { + } + const bool operator()() const { + const failable<value> r = getcontent(testURI, ch); + assert(hasContent(r)); + assert(contains(car(reverse(list<value>(content(r)))), "It works")); + return true; + } +}; + +const bool testGetPerf() { + CURLSession ch("", "", "", "", 0); + lambda<bool()> gl = getLoop(ch); + cout << "Static GET test " << time(gl, 5, 200) << " ms" << endl; + return true; +} + +} +} + +int main() { + tuscany::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + //tuscany::http::testURI = tuscany::string("http://") + tuscany::http::hostName() + ":8090"; + + tuscany::http::testGet(); + tuscany::http::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/http/form-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/form-auth-conf new file mode 100755 index 0000000000..fbe943f3d9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/form-auth-conf @@ -0,0 +1,82 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD form authentication configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then + pw=`cat $root/cert/ca.key | head -2 | tail -1` +else + pw="$3" +fi + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: form-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate form authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: form-auth-conf $* +# Require clients to present a userid + password through form-based +# authentication +<Location /> +AuthType Form +AuthName "$host" +AuthFormProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +AuthFormLoginRequiredLocation /login/ +AuthFormLogoutLocation / +Session On +SessionCookieName TuscanyFormAuth domain=.$host; path=/ +SessionCryptoPassphrase $pw +Require valid-user +</Location> + +<Location /login/dologin> +SetHandler form-login-handler +</Location> + +<Location /logout/dologout> +SetHandler form-logout-handler +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/group-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/group-auth-conf new file mode 100755 index 0000000000..e9617f696a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/group-auth-conf @@ -0,0 +1,57 @@ +#!/bin/sh + +# 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. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +user=$2 +group="members" + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: group-auth-conf $* +# Disallow public access to server resources + +EOF + +# Add user to group +cat $root/conf/httpd.groups | awk " BEGIN { found = 0 } /$group: / { printf \"%s %s\n\", \$0, \"$user\"; found = 1 } !/$group: / { printf \"%s\n\", \$0 } END { if (found == 0) printf \"%s: %s\n\", \"$group\", \"$user\" } " >$root/conf/.httpd.groups.tmp 2>/dev/null +cp $root/conf/.httpd.groups.tmp $root/conf/httpd.groups +rm $root/conf/.httpd.groups.tmp + +# Generate HTTPD group authorization configuration +conf=`cat $root/conf/locauth$sslsuffix.conf | grep "Generated by: group-auth-conf"` +if [ "$conf" = "" ]; then + cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: group-auth-conf $1 +# Allow group member access to root location +<Location /> +Require group members +</Location> + +EOF +fi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/htdocs/index.html b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/index.html new file mode 100644 index 0000000000..236864edfb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/index.html @@ -0,0 +1,32 @@ +<!-- + 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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>It works</title> +</head> +<body> +<h1>It works!</h1> +</body> +</html> + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/login/index.html new file mode 100644 index 0000000000..fd3bc21889 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/login/index.html @@ -0,0 +1,51 @@ +<!-- + 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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign in</title> +</head> +<body> +<h1>Sign in</h1> +<br/> + +<script type="text/javascript"> +function submitFormSignin() { + clearauthcookie(); + document.formSignin.httpd_location.value = '/'; + document.formSignin.submit(); +} +</script> + +<form name="formSignin" method="POST" action="/login/dologin"> +<table border="0"> +<tr><td>Username:</td><td><input type="text" name="httpd_username" value=""/></td></tr> +<tr><td>Password:</td><td><input type="password" name="httpd_password" value=""/></td></tr> +<tr><td><input type="button" onclick="submitFormSignin()" value="Sign in"/></td><td></td></tr> +</table> +<input type="hidden" name="httpd_location" value="/"/> +</form> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/modules/http/htdocs/logout/index.html b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/logout/index.html new file mode 100644 index 0000000000..218dd5d52c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/logout/index.html @@ -0,0 +1,44 @@ +<!-- + 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. +--> + +<html> +<body> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign out</title> +</head> +<h1>Sign out</h1> +<br/> + +<form name="signout" action="/login" method="GET"> +<script type="text/javascript"> +function submitSignout() { + clearauthcookie(); + document.signout.submit(); + return true; +} +</script> +<input type="button" onclick="submitSignout()" value="Sign out"/> +</form> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/modules/http/http-test b/sca-cpp/branches/lightweight-sca/modules/http/http-test new file mode 100755 index 0000000000..956b13a516 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/http-test @@ -0,0 +1,34 @@ +#!/bin/sh + +# 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. + +# Setup +rm -rf tmp +./httpd-conf tmp localhost 8090 htdocs +./httpd-event-conf tmp +./httpd-start tmp +sleep 2 + +# Test +./curl-test 2>/dev/null +rc=$? + +# Cleanup +./httpd-stop tmp +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/http/http.hpp b/sca-cpp/branches/lightweight-sca/modules/http/http.hpp new file mode 100644 index 0000000000..408b9fdee5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/http.hpp @@ -0,0 +1,1042 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_http_hpp +#define tuscany_http_hpp + +/** + * CURL HTTP client functions. + */ + +#include <unistd.h> +#include <curl/curl.h> +#include <curl/easy.h> +#include <apr.h> +#include <apr_lib.h> +#include <apr_network_io.h> +#include <apr_portable.h> +#include <apr_poll.h> +#include <apr_uri.h> + +#include "string.hpp" +#include "gc.hpp" +#include "list.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../scheme/io.hpp" +#include "../atom/atom.hpp" +#include "../rss/rss.hpp" +#include "../json/json.hpp" + +namespace tuscany { +namespace http { + +/** + * Enable CURL verbose debug log. + */ +//#define WANT_MAINTAINER_CURL_VERBOSE + +/** + * CURL library runtime, one per process. + */ +class CURLRuntime { +public: + CURLRuntime() { + curl_global_init(CURL_GLOBAL_ALL); + } +} curlRuntime; + +/** + * Represents a CURL session handle. + */ +class CURLSession { +public: + CURLSession() : h(NULL), p(), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL), owner(false), ca(""), cert(""), key(""), cookie(""), timeout(0) { + } + + CURLSession(const string& ca, const string& cert, const string& key, const string& cookie, const int timeout) : h(NULL), p(), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL), owner(true), ca(ca), cert(cert), key(key), cookie(cookie), timeout(timeout) { + } + + CURLSession(const CURLSession& c) : h(c.h), p(c.p), sock(c.sock), wpollset(c.wpollset), wpollfd(c.wpollfd), rpollset(c.rpollset), rpollfd(c.rpollfd), owner(false), ca(c.ca), cert(c.cert), key(c.key), cookie(c.cookie), timeout(c.timeout) { + } + + const CURLSession& operator=(const CURLSession& c) { + if(this == &c) + return *this; + h = c.h; + p = c.p; + sock = c.sock; + wpollset = c.wpollset; + wpollfd = c.wpollfd; + rpollset = c.rpollset; + rpollfd = c.rpollfd; + owner = false; + ca = c.ca; + cert = c.cert; + key = c.key; + cookie = c.cookie; + timeout = c.timeout; + return *this; + } + + ~CURLSession() { + if (!owner) + return; + if (h == NULL) + return; + curl_easy_cleanup(h); + } + +private: + CURL* h; + gc_child_pool p; + apr_socket_t* sock; + apr_pollset_t* wpollset; + apr_pollfd_t* wpollfd; + apr_pollset_t* rpollset; + apr_pollfd_t* rpollfd; + bool owner; + + friend CURL* handle(const CURLSession& cs); + friend apr_socket_t* sock(const CURLSession& cs); + friend const failable<CURL*> setup(const string& url, CURLSession& cs); + friend const failable<bool> cleanup(CURLSession& cs); + friend const failable<bool> connect(const string& url, CURLSession& cs); + friend const failable<bool> send(const char* c, const size_t l, CURLSession& cs); + friend const failable<size_t> recv(char* c, const size_t l, CURLSession& cs); + +public: + string ca; + string cert; + string key; + string cookie; + int timeout; +}; + +/** + * Returns the CURL handle used by a CURL session. + */ +CURL* handle(const CURLSession& cs) { + return cs.h; +} + +/** + * Return an apr_socket_t for the socket used by a CURL session. + */ +apr_socket_t* sock(const CURLSession& cs) { + return cs.sock; +} + +/** + * Convert a socket fd to an apr_socket_t. + */ +apr_socket_t* sock(const int sd, const gc_pool& p) { + int fd = sd; + apr_socket_t* s = NULL; + apr_os_sock_put(&s, &fd, pool(p)); + return s; +} + +/** + * Convert a CURL return code to an error string. + */ +const string curlreason(CURLcode rc) { + return curl_easy_strerror(rc); +} + +/** + * Convert an APR status to an error string. + */ +const string apreason(apr_status_t rc) { + char buf[256]; + return apr_strerror(rc, buf, sizeof(buf)); +} + +/** + * Escape a URI or a query argument. + */ +const char escape_c2x[] = "0123456789ABCDEF"; + +const string escape(const string& unesc, const char* reserv) { + char* copy = (char*)apr_palloc(gc_current_pool(), 3 * length(unesc) + 3); + const unsigned char* s = (const unsigned char *)c_str(unesc); + unsigned char* d = (unsigned char*)copy; + unsigned c; + while ((c = *s)) { + if (!apr_isalnum(c) && !strchr(reserv, c)) { + *d++ = '%'; + *d++ = escape_c2x[c >> 4]; + *d++ = escape_c2x[c & 0xf]; + } + else { + *d++ = (unsigned char)c; + } + ++s; + } + *d = '\0'; + return copy; +} + +const string escapeURI(const string& uri) { + debug(uri, "http::escapeURI::uri"); + const string e = escape(uri, "?$-_.+!*'(),:@&=/~%"); + debug(e, "http::escapeURI::result"); + return e; +} + +const string escapeArg(const string& arg) { + debug(arg, "http::escapeArg::arg"); + const string e = escape(arg, "-_.~"); + debug(e, "http::escapeArg::result"); + return e; +} + +/** + * Return true if a URI is absolute. + */ +const bool isAbsolute(const string& uri) { + return contains(uri, "://"); +} + +/** + * Parse a URI and return its host name. + */ +const string hostName(const string& uri, const gc_pool& p) { + apr_uri_t u; + const apr_status_t rc = apr_uri_parse(pool(p), c_str(uri), &u); + if (rc != APR_SUCCESS) + return ""; + if (u.hostname == NULL) + return ""; + return u.hostname; +} + +/** + * Parse a URI and return its scheme. + */ +const string scheme(const string& uri, const gc_pool& p) { + apr_uri_t u; + const apr_status_t rc = apr_uri_parse(pool(p), c_str(uri), &u); + if (rc != APR_SUCCESS) + return ""; + if (u.scheme == NULL) + return ""; + return u.scheme; +} + +/** + * Return the first subdomain name in a host name. + */ +const string subDomain(const string& host) { + return substr(host, 0, find(host, '.')); +} + +/** + * Return the top domain name in a host name. + */ +const string topDomain(const string& host) { + const size_t d = find(host, '.'); + return d == length(host) ? host : substr(host, d + 1); +} + +/** + * Setup a CURL session + */ +const failable<CURL*> setup(const string& url, CURLSession& cs) { + + // Init CURL session + if (cs.h != NULL) + cleanup(cs); + cs.h = curl_easy_init(); + CURL* ch = cs.h; + curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0"); +#ifdef WANT_MAINTAINER_CURL_VERBOSE + curl_easy_setopt(ch, CURLOPT_VERBOSE, true); +#endif + + // Setup protocol options + curl_easy_setopt(ch, CURLOPT_TCP_NODELAY, true); + curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, true); + curl_easy_setopt(ch, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(ch, CURLOPT_TIMEOUT, cs.timeout); + + // Setup SSL options + if (cs.ca != "") { + debug(cs.ca, "http::setup::ca"); + curl_easy_setopt(ch, CURLOPT_CAINFO, c_str(cs.ca)); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, true); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, 2); + } else + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, false); + if (cs.cert != "") { + debug(cs.cert, "http::setup::cert"); + curl_easy_setopt(ch, CURLOPT_SSLCERT, c_str(cs.cert)); + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + } + if (cs.key != "") { + debug(cs.key, "http::setup::key"); + curl_easy_setopt(ch, CURLOPT_SSLKEY, c_str(cs.key)); + curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM"); + } + if (cs.cookie != "") { + debug(cs.cookie, "http::setup::cookie"); + curl_easy_setopt(ch, CURLOPT_COOKIE, c_str(cs.cookie)); + } + + // Set up HTTP basic auth if requested + apr_uri_t u; + apr_pool_t* p = gc_current_pool(); + const apr_status_t prc = apr_uri_parse(p, c_str(url), &u); + if (prc == APR_SUCCESS) { + if (u.user != NULL) { + debug(u.user, "http::setup::user"); + curl_easy_setopt(ch, CURLOPT_USERNAME, u.user); + } + if (u.password != NULL) { + debug(u.password, "http::setup::pass"); + curl_easy_setopt(ch, CURLOPT_PASSWORD, u.password); + } + if (u.user != NULL || u.password != NULL) { + curl_easy_setopt(ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + + // Set target URL, omitting the user:password part + curl_easy_setopt(ch, CURLOPT_URL, c_str(escapeURI(apr_uri_unparse(p, &u, APR_URI_UNP_OMITUSERINFO)))); + + return ch; + } + } + + // Set target URL + curl_easy_setopt(ch, CURLOPT_URL, c_str(escapeURI(url))); + + return ch; +} + +/** + * Cleanup a CURL session + */ +const failable<bool> cleanup(CURLSession& cs) { + if (cs.h == NULL) + return true; + curl_easy_cleanup(cs.h); + cs.h = NULL; + return true; +} + +/** + * Context passed to the read callback function. + */ +class CURLReadContext { +public: + CURLReadContext(const list<string>& ilist) : ilist(ilist) { + } + list<string> ilist; +}; + +/** + * Called by CURL to read data to send. + */ +size_t readCallback(void *ptr, size_t size, size_t nmemb, void *data) { + CURLReadContext& rcx = *static_cast<CURLReadContext*>(data); + if (isNil(rcx.ilist)) + return 0; + const list<string> f(fragment(rcx.ilist, size * nmemb)); + const string s = car(f); + rcx.ilist = cdr(f); + memcpy(ptr, c_str(s), length(s)); + return length(s); +} + +/** + * Context passed to CURL write callback function. + */ +template<typename R> class CURLWriteContext { +public: + CURLWriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) { + } + const lambda<R(const string&, const R)> reduce; + R accum; +}; + +/** + * Called by CURL to write received data. + */ +template<typename R> size_t writeCallback(void *ptr, size_t size, size_t nmemb, void *data) { + CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data)); + const size_t realsize = size * nmemb; + wcx.accum = wcx.reduce(string((const char*)ptr, realsize), wcx.accum); + return realsize; +} + +/** + * Apply an HTTP verb to a list containing a list of headers and a list of content, and + * a reduce function used to process the response. + */ +curl_slist* headers(curl_slist* cl, const list<string>& h) { + if (isNil(h)) + return cl; + return headers(curl_slist_append(cl, c_str(string(car(h)))), cdr(h)); +} + +template<typename R> const failable<list<R> > apply(const list<list<string> >& hdr, const lambda<R(const string&, const R)>& reduce, const R& initial, const string& url, const string& verb, CURLSession& cs) { + debug(url, "http::apply::url"); + debug(verb, "http::apply::verb"); + + // Setup the CURL session + const failable<CURL*> fch = setup(url, cs); + if (!hasContent(fch)) { + cleanup(cs); + return mkfailure<list<R>>(fch); + } + CURL* ch = content(fch); + + // Set the request headers + curl_slist* hl = headers(NULL, car(hdr)); + if (hl != NULL) + curl_easy_setopt(ch, CURLOPT_HTTPHEADER, hl); + + // Convert request body to a string + // TODO use HTTP chunking instead + ostringstream os; + write(cadr(hdr), os); + const string s = str(os); + const size_t sz = length(s); + + // Setup the read, write header and write data callbacks + CURLReadContext rcx(mklist(s)); + curl_easy_setopt(ch, CURLOPT_READFUNCTION, (size_t (*)(void*, size_t, size_t, void*))readCallback); + curl_easy_setopt(ch, CURLOPT_READDATA, &rcx); + CURLWriteContext<R> hcx(reduce, initial); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))(writeCallback<R>)); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, &hcx); + CURLWriteContext<R> wcx(reduce, initial); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, (size_t (*)(void*, size_t, size_t, void*))(writeCallback<R>)); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, &wcx); + + // Apply the HTTP verb + if (verb == "POST") { + curl_easy_setopt(ch, CURLOPT_POST, true); + curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, sz); + } else if (verb == "PUT") { + curl_easy_setopt(ch, CURLOPT_UPLOAD, true); + curl_easy_setopt(ch, CURLOPT_INFILESIZE, sz); + } else if (verb == "PATCH") { + curl_easy_setopt(ch, CURLOPT_UPLOAD, true); + curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, "PATCH"); + curl_easy_setopt(ch, CURLOPT_INFILESIZE, sz); + } else if (verb == "DELETE") + curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, "DELETE"); + const CURLcode rc = curl_easy_perform(ch); + + // Free the headers + if (hl != NULL) + curl_slist_free_all(hl); + + // Return the HTTP return code or content + if (rc) { + cleanup(cs); + return mkfailure<list<R> >(string(curl_easy_strerror(rc))); + } + long httprc; + curl_easy_getinfo (ch, CURLINFO_RESPONSE_CODE, &httprc); + if (httprc != 200 && httprc != 201) { + cleanup(cs); + ostringstream es; + es << "HTTP code " << httprc; + return mkfailure<list<R> >(str(es)); + } + + cleanup(cs); + return mklist<R>(hcx.accum, wcx.accum); +} + +/** + * Evaluate an expression remotely, at the given URL. + */ +const failable<value> evalExpr(const value& expr, const string& url, CURLSession& cs) { + debug(url, "http::evalExpr::url"); + debug(expr, "http::evalExpr::input"); + + // Convert expression to a JSON-RPC request + js::JSContext cx; + const failable<list<string> > jsreq = json::jsonRequest(1, car<value>(expr), cdr<value>(expr), cx); + if (!hasContent(jsreq)) + return mkfailure<value>(jsreq); + + // POST it to the URL + const list<string> h = mklist<string>("Content-Type: application/json-rpc"); + const failable<list<list<string> > > res = apply<list<string> >(mklist<list<string> >(h, content(jsreq)), rcons<string>, list<string>(), url, "POST", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + // Parse and return JSON-RPC result + const failable<value> rval = json::jsonResultValue(cadr<list<string> >(content(res)), cx); + debug(rval, "http::evalExpr::result"); + if (!hasContent(rval)) + return mkfailure<value>(rval); + return content(rval); +} + +/** + * Find and return a header. + */ +const maybe<string> header(const char* prefix, const list<string>& h) { + if (isNil(h)) + return maybe<string>(); + const string s = car(h); + if (find(s, prefix) != 0) + return header(prefix, cdr(h)); + const string l(substr(s, length(prefix))); + return substr(l, 0, find_first_of(l, "\r\n")); +} + +/** + * Find and return a location header. + */ +const string location(const list<string>& h) { + const maybe<string> l = header("Location: ", h); + return hasContent(l)? content(l) : ""; +} + +/** + * Convert a location to an entry id. + */ +const value entryId(const failable<string> l) { + if (!hasContent(l)) + return list<value>(); + const string ls(content(l)); + return value(mklist<value>(string(substr(ls, find_last(ls, '/') + 1)))); +} + +/** + * Find and return a content-type header. + */ +const string contentType(const list<string>& h) { + const maybe<string> ct = header("Content-Type: ", h); + return hasContent(ct)? content(ct) : ""; +} + +/** + * HTTP GET, return the resource at the given URL. + */ +template<typename R> const failable<list<R> > get(const lambda<R(const string&, const R)>& reduce, const R& initial, const string& url, CURLSession& cs) { + debug(url, "http::get::url"); + const list<list<string> > req = mklist(list<string>(), list<string>()); + return apply(req, reduce, initial, url, "GET", cs); +} + +/** + * HTTP GET, return a list of values representing the resource at the given URL. + */ +const failable<value> getcontent(const string& url, CURLSession& cs) { + debug(url, "http::get::url"); + + // Get the contents of the resource at the given URL + const failable<list<list<string> > > res = get<list<string>>(rcons<string>, list<string>(), url, cs); + if (!hasContent(res)) + return mkfailure<value>(res); + const list<string> ls(reverse(cadr(content(res)))); + + // Return the content as a list of values + const value val(mkvalues(ls)); + debug(val, "http::get::result"); + return val; +} + +/** + * Convert an HTTP content response to a value. + */ +const failable<value> responseValue(const list<list<string> > res) { + + // Parse the returned content + const string ct = contentType(car(res)); + debug(ct, "http::responseValue::contentType"); + + const list<string> ls(reverse(cadr(res))); + debug(ls, "http::responseValue::content"); + + if (atom::isATOMEntry(ls)) { + // Read an ATOM entry + const value val(elementsToValues(content(atom::readATOMEntry(ls)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "application/atom+xml") || atom::isATOMFeed(ls)) { + // Read an ATOM feed + const value val(elementsToValues(content(atom::readATOMFeed(ls)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "application/rss+xml") || rss::isRSSFeed(ls)) { + // Read an RSS feed + const value val(elementsToValues(content(rss::readRSSFeed(ls)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "text/javascript") || contains(ct, "application/json") || json::isJSON(ls)) { + // Read a JSON document + js::JSContext cx; + const value val(json::jsonValues(content(json::readJSON(ls, cx)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "application/x-javascript")) { + // Read a JSON document enclosed in a javascript function call + // Extract the JSON out of the enclosing parenthesis + ostringstream os; + write(ls, os); + const string s = str(os); + const size_t fp = find(s, '('); + const size_t lp = find_last(s, ')'); + const list<string> jls = mklist<string>(substr(s, fp + 1, lp - (fp + 1))); + debug(jls, "http::responseValue::javascript::content"); + + js::JSContext cx; + const value val(json::jsonValues(content(json::readJSON(jls, cx)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "text/xml") || contains(ct, "application/xml") || isXML(ls)) { + // Read an XML document + const value val(elementsToValues(readXML(ls))); + debug(val, "http::responseValue::result"); + return val; + } + + // Return the content type and a content list + const value val(mklist<value>(ct, mkvalues(ls))); + debug(val, "http::responseValue::result"); + return val; +} + +/** + * HTTP GET, return a list of values representing the resource at the given URL. + */ +const failable<value> get(const string& url, CURLSession& cs) { + debug(url, "http::get::url"); + + // Get the contents of the resource at the given URL + const failable<list<list<string> > > res = get<list<string> >(rcons<string>, list<string>(), url, cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + // Parse the returned content + return responseValue(content(res)); +} + +/** + * Form an HTTP content request. + */ +const failable<list<list<string> > > writeRequest(const failable<list<string> >& ls, const string& ct) { + if (!hasContent(ls)) + return mkfailure<list<list<string> > >(ls); + const list<list<string> > req = mklist<list<string> >(mklist<string>(string("Content-Type: ") + ct), content(ls)); + debug(req, "http::writeRequest::req"); + return req; +} + +/** + * Convert a value to an HTTP content request. + */ +const failable<list<list<string> > > contentRequest(const value& c, unused const string& url) { + + // Check if the client requested a specific format + //TODO derive that from given URL + const list<value> fmt = assoc<value>("format", list<value>()); + + // Write as a scheme value if requested by the client + if (!isNil(fmt) && cadr(fmt) == "scheme") + return writeRequest(mklist<string>(scheme::writeValue(c)), "text/plain; charset=utf-8"); + + // Write a simple value as a JSON value + if (!isList(c)) { + js::JSContext cx; + if (isSymbol(c)) { + const list<value> lc = mklist<value>(mklist<value>("name", value(string(c)))); + debug(lc, "http::contentRequest::symbol"); + return writeRequest(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8"); + } + const list<value> lc = mklist<value>(mklist<value>("value", c)); + debug(lc, "http::contentRequest::value"); + return writeRequest(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8"); + } + + // Write an empty list as a JSON empty value + if (isNil((list<value>)c)) { + js::JSContext cx; + debug(list<value>(), "http::contentRequest::empty"); + return writeRequest(json::writeJSON(list<value>(), cx), "application/json; charset=utf-8"); + } + + // Write content-type / content-list pair + if (isString(car<value>(c)) && !isNil(cdr<value>(c)) && isList(cadr<value>(c))) + return writeRequest(convertValues<string>(cadr<value>(c)), car<value>(c)); + + // Write an assoc value as JSON + if (isSymbol(car<value>(c)) && !isNil(cdr<value>(c))) { + js::JSContext cx; + const list<value> lc = mklist<value>(c); + debug(lc, "http::contentRequest::assoc"); + debug(valuesToElements(lc), "http::contentRequest::assoc::element"); + return writeRequest(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8"); + } + + // Write value as JSON if requested by the client + if (!isNil(fmt) && cadr(fmt) == "json") { + js::JSContext cx; + return writeRequest(json::writeJSON(valuesToElements(c), cx), "application/json; charset=utf-8"); + } + + // Convert list of values to element values + const list<value> e = valuesToElements(c); + debug(e, "http::contentRequest::elements"); + + // Write an ATOM feed or entry + if (isList(car<value>(e)) && !isNil(car<value>(e))) { + const list<value> el = car<value>(e); + if (isSymbol(car<value>(el)) && car<value>(el) == element && !isNil(cdr<value>(el)) && isSymbol(cadr<value>(el)) && elementHasChildren(el) && !elementHasValue(el)) { + if (cadr<value>(el) == atom::feed) + return writeRequest(atom::writeATOMFeed(e), "application/atom+xml; charset=utf-8"); + if (cadr<value>(el) == atom::entry) + return writeRequest(atom::writeATOMEntry(e), "application/atom+xml; charset=utf-8"); + } + } + + // Write any other compound value as a JSON value + js::JSContext cx; + return writeRequest(json::writeJSON(e, cx), "application/json; charset=utf-8"); +} + +/** + * HTTP POST. + */ +const failable<value> post(const value& val, const string& url, CURLSession& cs) { + debug(url, "http::post::url"); + + // Convert value to a content request + const failable<list<list<string> > > req = contentRequest(val, url); + if (!hasContent(req)) + return mkfailure<value>(req); + debug(content(req), "http::post::input"); + + // POST it to the URL + const failable<list<list<string> > > res = apply<list<string>>(content(req), rcons<string>, list<string>(), url, "POST", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + // Return the new entry id from the HTTP location header, if any + const string loc = location(car(content(res))); + if (length(loc) != 0) { + const value eid(entryId(location(car(content(res))))); + debug(eid, "http::post::result"); + return eid; + } + + // Return the returned content + return responseValue(content(res)); +} + +/** + * HTTP PUT. + */ +const failable<value> put(const value& val, const string& url, CURLSession& cs) { + debug(url, "http::put::url"); + + // Convert value to a content request + const failable<list<list<string> > > req = contentRequest(val, url); + if (!hasContent(req)) + return mkfailure<value>(req); + debug(content(req), "http::put::input"); + + // PUT it to the URL + const failable<list<list<string> > > res = apply<list<string> >(content(req), rcons<string>, list<string>(), url, "PUT", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + debug(true, "http::put::result"); + return value(true); +} + +/** + * HTTP PATCH. + */ +const failable<value> patch(const value& val, const string& url, CURLSession& cs) { + debug(url, "http::put::patch"); + + // Convert value to a content request + const failable<list<list<string> > > req = contentRequest(val, url); + if (!hasContent(req)) + return mkfailure<value>(req); + debug(content(req), "http::patch::input"); + + // PATCH it to the URL + const failable<list<list<string> > > res = apply<list<string> >(content(req), rcons<string>, list<string>(), url, "PATCH", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + debug(true, "http::patch::result"); + return value(true); +} + +/** + * HTTP DELETE. + */ +const failable<value, string> del(const string& url, CURLSession& cs) { + debug(url, "http::delete::url"); + + const list<list<string> > req = mklist(list<string>(), list<string>()); + const failable<list<list<string> > > res = apply<list<string> >(req, rcons<string>, list<string>(), url, "DELETE", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + debug(true, "http::delete::result"); + return value(true); +} + +/** + * Returns the current host name. + */ +const string hostName() { + char h[256]; + if (gethostname(h, 256) == -1) + return "localhost"; + return h; +} + +/** + * Create an APR pollfd for a socket. + */ +apr_pollfd_t* pollfd(apr_socket_t* s, const int e, const gc_pool& p) { + apr_pollfd_t* pfd = gc_new<apr_pollfd_t>(p); + pfd->p = pool(p); + pfd->desc_type = APR_POLL_SOCKET; + pfd->reqevents = (apr_int16_t)e; + pfd->rtnevents = (apr_int16_t)e; + pfd->desc.s = s; + pfd->client_data = NULL; + return pfd; +} + +/** + * Connect to a URL. + */ +const failable<bool> connect(const string& url, CURLSession& cs) { + debug(url, "http::connect::url"); + + // Setup the CURL session + const failable<CURL*> fch = setup(url, cs); + if (!hasContent(fch)) { + cleanup(cs); + return mkfailure<bool>(fch); + } + CURL* ch = content(fch); + + // Connect + curl_easy_setopt(ch, CURLOPT_CONNECT_ONLY, true); + const CURLcode rc = curl_easy_perform(ch); + if (rc) { + cleanup(cs); + return mkfailure<bool>(string(curl_easy_strerror(rc))); + } + + // Convert the connected socket to an apr_socket_t + int sd; + const CURLcode grc = curl_easy_getinfo(ch, CURLINFO_LASTSOCKET, &sd); + if (grc) { + cleanup(cs); + return mkfailure<bool>(string(curl_easy_strerror(grc))); + } + cs.sock = sock(sd, cs.p); + + // Create pollsets and pollfds which can be used to poll the socket + apr_status_t rpcrc = apr_pollset_create(&cs.rpollset, 1, pool(cs.p), 0); + if (rpcrc != APR_SUCCESS) { + cleanup(cs); + return mkfailure<bool>(apreason(rpcrc)); + } + cs.rpollfd = pollfd(cs.sock, APR_POLLIN, cs.p); + apr_pollset_add(cs.rpollset, cs.rpollfd); + apr_status_t wpcrc = apr_pollset_create(&cs.wpollset, 1, pool(cs.p), 0); + if (wpcrc != APR_SUCCESS) { + cleanup(cs); + return mkfailure<bool>(apreason(wpcrc)); + } + cs.wpollfd = pollfd(cs.sock, APR_POLLOUT, cs.p); + apr_pollset_add(cs.wpollset, cs.wpollfd); + + return true; +} + +/** + * Send an array of chars. + */ +const failable<bool> send(const char* c, const size_t l, CURLSession& cs) { + + // Send the data + size_t wl = 0; + const CURLcode rc = curl_easy_send(cs.h, c, (size_t)l, &wl); + if (rc == CURLE_OK && wl == (size_t)l) + return true; + if (rc != CURLE_AGAIN) { + cleanup(cs); + return mkfailure<bool>(curlreason(rc)); + } + + // If the socket was not ready, wait for it to become ready + const apr_pollfd_t* pollfds; + apr_int32_t pollcount; + apr_status_t pollrc = apr_pollset_poll(cs.wpollset, -1, &pollcount, &pollfds); + if (pollrc != APR_SUCCESS) + return mkfailure<bool>(apreason(pollrc)); + + // Send what's left + return send(c + wl, l - wl, cs); +} + +/** + * Receive an array of chars. + */ +const failable<size_t> recv(char* c, const size_t l, CURLSession& cs) { + + // Receive data + size_t rl; + const CURLcode rc = curl_easy_recv(cs.h, c, (size_t)l, &rl); + if (rc == CURLE_OK) + return (size_t)rl; + if (rc == 1) + return 0; + if (rc != CURLE_AGAIN) { + cleanup(cs); + return mkfailure<size_t>(curlreason(rc)); + } + + // If the socket was not ready, wait for it to become ready + const apr_pollfd_t* pollfds; + apr_int32_t pollcount; + apr_status_t pollrc = apr_pollset_poll(cs.rpollset, -1, &pollcount, &pollfds); + if (pollrc != APR_SUCCESS) { + cleanup(cs); + return mkfailure<size_t>(apreason(pollrc)); + } + + // Receive again + return recv(c, l, cs); +} + +/** + * Converts a list of key value pairs to a query string. + */ +ostringstream& queryString(const list<list<value> > args, ostringstream& os) { + if (isNil(args)) + return os; + const list<value> arg = car(args); + debug(arg, "http::queryString::arg"); + if (isNil(arg) || isNil(cdr(arg))) + return queryString(cdr(args), os); + os << car(arg) << "=" << c_str(cadr(arg)); + if (!isNil(cdr(args))) + os << "&"; + return queryString(cdr(args), os); +} + +const string queryString(const list<list<value> > args) { + ostringstream os; + return str(queryString(args, os)); +} + +/** + * Filter path segment in a list of arguments. + */ +const bool filterPath(const value& arg) { + return isString(arg) || isSymbol(arg); +} + +/** + * Filter query string arguments in a list of arguments. + */ +const bool filterQuery(const value& arg) { + return isList(arg); +} + +/** + * Escape a query string argument. + */ +const value escapeQuery(const value& arg) { + return arg; + //return mklist<value>(car<value>(arg), escapeArg(cadr<value>(arg))); +} + +/** + * HTTP client proxy function. + */ +struct proxy { + proxy(const string& uri, const string& ca, const string& cert, const string& key, const string& cookie, const int timeout, const gc_pool& p) : p(p), uri(uri), ca(ca), cert(cert), key(key), cookie(cookie), cs(*(new (gc_new<CURLSession>(p)) CURLSession(ca, cert, key, cookie, timeout))) { + } + + const value operator()(const list<value>& args) const { + debug(args, "http::proxy::args"); + const value fun = car(args); + if (fun == "get") { + const list<value> lp = filter<value>(filterPath, cadr(args)); + debug(lp, "http::proxy::path"); + const list<value> lq = map<value, value>(escapeQuery, filter<value>(filterQuery, cadr(args))); + debug(lp, "http::proxy::query"); + const value p = path(lp); + const value q = queryString(lq); + const failable<value> val = get(uri + p + (q != ""? string("?") + q : string("")), cs); + return content(val); + } + if (fun == "post") { + const failable<value> val = post(caddr(args), uri + path(cadr(args)), cs); + return content(val); + } + if (fun == "put") { + const failable<value> val = put(caddr(args), uri + path(cadr(args)), cs); + return content(val); + } + if (fun == "patch") { + const failable<value> val = patch(caddr(args), uri + path(cadr(args)), cs); + return content(val); + } + if (fun == "delete") { + const failable<value> val = del(uri + path(cadr(args)), cs); + return content(val); + } + const failable<value> val = evalExpr(args, uri, cs); + return content(val); + } + + const gc_pool p; + const string uri; + const string ca; + const string cert; + const string key; + const string cookie; + CURLSession& cs; +}; + +} +} + +#endif /* tuscany_http_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-addr b/sca-cpp/branches/lightweight-sca/modules/http/httpd-addr new file mode 100755 index 0000000000..735c152f43 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-addr @@ -0,0 +1,53 @@ +#!/bin/sh + +# 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. + +# Parse a string in the form ip-addr:local-port/public-port +addr=`echo $2 | awk -F "/" '{ print $1 }'` +ip=`echo $addr | awk -F ":" '{ print $1 }'` +port=`echo $addr | awk -F ":" '{ print $2 }'` +if [ "$port" = "" ]; then + port=$ip + ip="" + listen=$port + vhost="*:$port" +else + listen="$ip:$port" + vhost="$ip:$port" +fi +pport=`echo $2 | awk -F "/" '{ print $2 }'` +if [ "$pport" = "" ]; then + pport=$port +fi + +# Return the requested part +if [ "$1" = "ip" ]; then + echo $ip +fi +if [ "$1" = "port" ]; then + echo $port +fi +if [ "$1" = "pport" ]; then + echo $pport +fi +if [ "$1" = "listen" ]; then + echo $listen +fi +if [ "$1" = "vhost" ]; then + echo $vhost +fi diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-conf new file mode 100755 index 0000000000..730775fa89 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-conf @@ -0,0 +1,375 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=`$here/httpd-addr port $3` +pport=`$here/httpd-addr pport $3` +listen=`$here/httpd-addr listen $3` +vhost=`$here/httpd-addr vhost $3` +if [ "$pport" = "80" ]; then + pportsuffix="" +else + pportsuffix=":$pport" +fi + +mkdir -p $4 +htdocs=`echo "import os; print os.path.realpath('$4')" | python` + +user=`id -un` +group=`id -gn` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" + sendfile=Off +else + libsuffix=".so" + sendfile=On +fi + +modules_prefix=`cat $here/httpd-modules.prefix` + +mkdir -p $root +mkdir -p $root/logs +mkdir -p $root/conf +cat >$root/conf/httpd.conf <<EOF +# Generated by: httpd-conf $* +# Apache HTTPD server configuration + +# Main server name +ServerName http://$host$pportsuffix +PidFile $root/logs/httpd.pid + +# Load configured MPM +Include conf/mpm.conf + +# Load required modules +Include conf/modules.conf + +# Basic security precautions +User $user +Group $group +ServerSignature Off +ServerTokens Prod +Timeout 45 +RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500 +LimitRequestBody 1048576 +HostNameLookups Off +#MaxKeepAliveRequests 25 +#MaxConnectionsPerChild 100 + +# Log HTTP requests +# [timestamp] [access] remote-host remote-ident remote-user "request-line" +# status response-size "referrer" "user-agent" "user-track" local-IP +# virtual-host response-time bytes-received bytes-sent +LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [access] %h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" combined +Include conf/log.conf + +# Configure Mime types and default charsets +TypesConfig $here/conf/mime.types +AddDefaultCharset utf-8 +AddCharset utf-8 .html .js .css + +# Configure cache control +<Directory /> +ExpiresActive On +ExpiresDefault A604800 +Header onsuccess merge Cache-Control public env=!private-cache +</Directory> + +# Enable Linux Kernel sendfile +EnableSendFile $sendfile + +# Configure auth modules +Include conf/auth.conf + +# Set default document root +DocumentRoot $htdocs +DirectoryIndex index-min.html index.html + +# Protect server files +<Directory /> +Options None +AllowOverride None +Require all denied +</Directory> + +# Configure output filters to enable compression and rate limiting +<Location /> +#SetOutputFilter RATE_LIMIT;DEFLATE +SetOutputFilter DEFLATE + +BrowserMatch ^Mozilla/4 gzip-only-text/html +BrowserMatch ^Mozilla/4\.0[678] no-gzip +BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html +BrowserMatch ^check_http/ check_http +SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary +Header append Vary User-Agent env=!dont-vary + +#SetEnv rate-limit 400 +</Location> + +# Listen on HTTP port +Listen $listen + +# Setup HTTP virtual host +<VirtualHost $vhost> +ServerName http://$host$pportsuffix + +<Location /> +RewriteEngine on +Include conf/hostcond.conf +RewriteCond %{HTTP:X-Forwarded-Server} ^$ [NC] +RewriteCond %{REQUEST_URI} !^/server-status [NC] +RewriteCond %{REQUEST_URI} !^/balancer-manager [NC] +RewriteCond %{REQUEST_URI} !^/proxy/ [NC] +RewriteRule .* http://$host$pportsuffix%{REQUEST_URI} [R] +</Location> + +Include conf/svhost.conf + +# Configure authentication +Include conf/noauth.conf +Include conf/locauth.conf +Include conf/pubauth.conf +Include conf/adminauth.conf + +</VirtualHost> + +EOF + +# Configure logging +cat >$root/conf/log.conf <<EOF +# Generated by: httpd-conf $* +ErrorLog $root/logs/error_log +CustomLog $root/logs/access_log combined + +EOF + +# Run with the prefork MPM +cat >$root/conf/mpm.conf <<EOF +# Generated by: httpd-conf $* +LoadModule mpm_prefork_module ${modules_prefix}/modules/mod_mpm_prefork.so + +EOF + +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 +# Generated by: httpd-conf $* +# Load a minimal set of modules, the load order is important +# (e.g. load mod_headers before mod_rewrite, so its hooks execute +# after mod_rewrite's hooks) +LoadModule headers_module ${modules_prefix}/modules/mod_headers.so +LoadModule alias_module ${modules_prefix}/modules/mod_alias.so +LoadModule authn_file_module ${modules_prefix}/modules/mod_authn_file.so +LoadModule authn_socache_module ${modules_prefix}/modules/mod_authn_socache.so +LoadModule authn_core_module ${modules_prefix}/modules/mod_authn_core.so +LoadModule authz_host_module ${modules_prefix}/modules/mod_authz_host.so +LoadModule authz_groupfile_module ${modules_prefix}/modules/mod_authz_groupfile.so +LoadModule authz_user_module ${modules_prefix}/modules/mod_authz_user.so +LoadModule authz_core_module ${modules_prefix}/modules/mod_authz_core.so +LoadModule auth_basic_module ${modules_prefix}/modules/mod_auth_basic.so +LoadModule auth_digest_module ${modules_prefix}/modules/mod_auth_digest.so +LoadModule auth_form_module ${modules_prefix}/modules/mod_auth_form.so +LoadModule request_module ${modules_prefix}/modules/mod_request.so +LoadModule deflate_module ${modules_prefix}/modules/mod_deflate.so +LoadModule filter_module ${modules_prefix}/modules/mod_filter.so +LoadModule proxy_module ${modules_prefix}/modules/mod_proxy.so +LoadModule proxy_connect_module ${modules_prefix}/modules/mod_proxy_connect.so +LoadModule proxy_http_module ${modules_prefix}/modules/mod_proxy_http.so +LoadModule proxy_balancer_module ${modules_prefix}/modules/mod_proxy_balancer.so +LoadModule lbmethod_byrequests_module ${modules_prefix}/modules/mod_lbmethod_byrequests.so +LoadModule socache_shmcb_module ${modules_prefix}/modules/mod_socache_shmcb.so +LoadModule cache_module ${modules_prefix}/modules/mod_cache.so +LoadModule cache_disk_module ${modules_prefix}/modules/mod_cache_disk.so +LoadModule rewrite_module ${modules_prefix}/modules/mod_rewrite.so +LoadModule mime_module ${modules_prefix}/modules/mod_mime.so +LoadModule status_module ${modules_prefix}/modules/mod_status.so +LoadModule negotiation_module ${modules_prefix}/modules/mod_negotiation.so +LoadModule dir_module ${modules_prefix}/modules/mod_dir.so +LoadModule setenvif_module ${modules_prefix}/modules/mod_setenvif.so +LoadModule env_module ${modules_prefix}/modules/mod_env.so +LoadModule expires_module ${modules_prefix}/modules/mod_expires.so +<IfModule !log_config_module> +LoadModule log_config_module ${modules_prefix}/modules/mod_log_config.so +</IfModule> +LoadModule logio_module ${modules_prefix}/modules/mod_logio.so +LoadModule usertrack_module ${modules_prefix}/modules/mod_usertrack.so +LoadModule vhost_alias_module ${modules_prefix}/modules/mod_vhost_alias.so +LoadModule cgi_module ${modules_prefix}/modules/mod_cgi.so +LoadModule actions_module ${modules_prefix}/modules/mod_actions.so +LoadModule unixd_module ${modules_prefix}/modules/mod_unixd.so +LoadModule session_module ${modules_prefix}/modules/mod_session.so +LoadModule session_crypto_module ${modules_prefix}/modules/mod_session_crypto.so +LoadModule slotmem_shm_module ${modules_prefix}/modules/mod_slotmem_shm.so +LoadModule ratelimit_module ${modules_prefix}/modules/mod_ratelimit.so +LoadModule reqtimeout_module ${modules_prefix}/modules/mod_reqtimeout.so +LoadModule ssl_module ${modules_prefix}/modules/mod_ssl.so + +EOF + +# Generate auth configuration +cat >$root/conf/auth.conf <<EOF +# Generated by: httpd-conf $* + +EOF + +cat >$root/conf/locauth.conf <<EOF +# Generated by: httpd-conf $* +# Authentication and authorization configuration + +# Allow authorized access to document root +<Directory "$htdocs"> +Options FollowSymLinks +Require all granted +</Directory> + +# Allow authorized access to root location +<Location /> +Options FollowSymLinks +AuthUserFile "$root/conf/httpd.passwd" +AuthGroupFile "$root/conf/httpd.groups" +Require all granted +</Location> + +EOF + +cat >$root/conf/pubauth.conf <<EOF +# Generated by: httpd-conf $* +# Allow everyone to access public locations +<Location /login> +AuthType None +Require all granted +# Mark login page with a header +Header set X-Login open-auth +</Location> +<Location /logout> +AuthType None +Require all granted +</Location> +<Location /public> +AuthType None +Require all granted +</Location> +<Location /proxy/public> +AuthType None +Require all granted +</Location> +<Location /favicon.ico> +AuthType None +Require all granted +</Location> +<Location /robots.txt> +AuthType None +Require all granted +</Location> + +EOF + +cat >$root/conf/adminauth.conf <<EOF + +# Allow the server admin to view the server status +<Location /server-status> +Require user admin +</Location> + +EOF + +# Create password and group files +cat >$root/conf/httpd.passwd <<EOF +# Generated by: httpd-conf $* +EOF + +cat >$root/conf/httpd.groups <<EOF +# Generated by: httpd-conf $* +EOF + +# Allow public access to server resources +cat >$root/conf/noauth.conf <<EOF +# Generated by: httpd-conf $* +# Allow public access to server resources + +# Allow access to document root +<Directory "$htdocs"> +AuthType None +Require all granted +</Directory> + +# Allow everyone to access root location +<Location /> +AuthType None +Require all granted +</Location> + +EOF + +# Generate vhost configuration +cat >$root/conf/vhost.conf <<EOF +# Generated by: httpd-conf $* +# Virtual host configuration +UseCanonicalName Off + +# Enable HTTP reverse proxy +ProxyRequests Off +ProxyPreserveHost On +ProxyStatus On + +# Enable server status +<Location /server-status> +SetHandler server-status +HostnameLookups on +</Location> + +EOF + +cat >$root/conf/svhost.conf <<EOF +# Generated by: httpd-conf $* +# Static virtual host configuration +Include conf/vhost.conf + +EOF + +cat >$root/conf/dvhost.conf <<EOF +# Generated by: httpd-conf $* +# Mass dynamic virtual host configuration +Include conf/vhost.conf + +EOF + +# Generate host name check condition +cat >$root/conf/hostcond.conf <<EOF +# Generated by: httpd-conf $* +RewriteCond %{HTTP_HOST} !^$host [NC] + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-debug b/sca-cpp/branches/lightweight-sca/modules/http/httpd-debug new file mode 100755 index 0000000000..df0d21fbe5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-debug @@ -0,0 +1,25 @@ +#!/bin/sh + +# 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. + +# Start httpd server +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +httpd=`cat $here/httpd.prefix` +$httpd/bin/httpd -X -E $root/logs/error_log -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-event-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-event-conf new file mode 100755 index 0000000000..093bbe78d9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-event-conf @@ -0,0 +1,45 @@ +#!/bin/sh + +# 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. + +# Configure HTTPD to run with the event MPM +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +modules_prefix=`cat $here/httpd-modules.prefix` + +mkdir -p $root +mkdir -p $root/conf +cat >$root/conf/mpm.conf <<EOF +# Generated by: httpd-event-conf $* +# 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-conf $* +# Set thread stack size +ThreadStackSize 2097152 + +EOF +fi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-loglevel-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-loglevel-conf new file mode 100755 index 0000000000..c9d2ad81d5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-loglevel-conf @@ -0,0 +1,32 @@ +#!/bin/sh + +# 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. + +# Configure HTTPD log level +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +level=$2 + +# Configure log level +cat >>$root/conf/log.conf <<EOF +# Generated by: httpd-loglevel-conf $* +LogLevel $level + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-memgrind b/sca-cpp/branches/lightweight-sca/modules/http/httpd-memgrind new file mode 100755 index 0000000000..55e113bbd3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-memgrind @@ -0,0 +1,25 @@ +#!/bin/sh + +# 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. + +# Start httpd server +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +httpd=`cat $here/httpd.prefix` +$here/../../etc/memgrind $httpd/bin/httpd -X -E $root/logs/error_log -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-restart b/sca-cpp/branches/lightweight-sca/modules/http/httpd-restart new file mode 100755 index 0000000000..81b098d85d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-restart @@ -0,0 +1,25 @@ +#!/bin/sh + +# 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. + +# Restart httpd server +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +apachectl=`cat $here/httpd-apachectl.prefix` +$apachectl -k graceful -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-ssl-conf new file mode 100755 index 0000000000..f99a10071c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-ssl-conf @@ -0,0 +1,259 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD SSL configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` +gport=`echo $conf | awk '{ print $7 }'` +port=`$here/httpd-addr port $gport` +pport=`$here/httpd-addr pport $gport` + +sslpport=`$here/httpd-addr pport $2` +sslport=`$here/httpd-addr listen $2` +sslvhost=`$here/httpd-addr vhost $2` +if [ "$sslpport" = "443" ]; then + sslpportsuffix="" +else + sslpportsuffix=":$sslpport" +fi + +dothost=`echo $host | grep "\."` + +htdocs=`echo $conf | awk '{ print $8 }'` +mkdir -p $htdocs +htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +modules_prefix=`cat $here/httpd-modules.prefix` + +# Extract organization name from our CA certificate +org=`openssl x509 -noout -subject -nameopt multiline -in $root/cert/ca.crt | grep organizationName | awk -F "= " '{ print $2 }'` + +# Generate HTTPD configuration +cat >>$root/conf/httpd.conf <<EOF +# Generated by: httpd-ssl-conf $* + +# Configure SSL support +AddType application/x-x509-ca-cert .crt +AddType application/x-pkcs7-crl .crl +SSLPassPhraseDialog builtin +SSLSessionCache "shmcb:$root/logs/ssl_scache(512000)" +SSLSessionCacheTimeout 300 +Mutex "file:$root/logs" ssl-cache +SSLRandomSeed startup builtin +SSLRandomSeed connect builtin + +# Listen on HTTPS port +Listen $sslport + +# HTTPS virtual host +<VirtualHost $sslvhost> +ServerName https://$host$sslpportsuffix + +<Location /> +RewriteEngine on +Include conf/hostcond.conf +RewriteCond %{HTTP:X-Forwarded-Server} ^$ [NC] +RewriteCond %{REQUEST_URI} !^/server-status [NC] +RewriteCond %{REQUEST_URI} !^/balancer-manager [NC] +RewriteCond %{REQUEST_URI} !^/proxy/ [NC] +RewriteRule .* https://$host$sslpportsuffix%{REQUEST_URI} [R] +</Location> + +Include conf/svhost-ssl.conf + +# Configure authentication +Include conf/noauth-ssl.conf +Include conf/locauth-ssl.conf +Include conf/pubauth-ssl.conf +Include conf/adminauth-ssl.conf + +# Configure tracking +Include conf/tracking-ssl.conf + +</VirtualHost> + +EOF + +# Generate auth configuration +cat >$root/conf/locauth-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Authentication and authorization configuration +Include conf/locauth.conf + +EOF + +cat >$root/conf/pubauth-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Allow everyone to access public locations +Include conf/pubauth.conf + +EOF + +cat >$root/conf/adminauth-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Allow admin access +Include conf/adminauth.conf + +EOF + +# Allow public access to server resources +cat >$root/conf/noauth-ssl.conf <<EOF +# Generated by: httpd-conf $* +# Allow public access to server resources +Include conf/noauth.conf + +EOF + +# Generate HTTP vhost configuration +cat >>$root/conf/svhost.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Redirect HTTP traffic to HTTPS +<Location /> +RewriteEngine on +RewriteCond %{SERVER_PORT} ^$port$ [OR] +RewriteCond %{SERVER_PORT} ^$pport$ +RewriteRule .* https://$host$sslpportsuffix%{REQUEST_URI} [R] +</Location> + +EOF + +# Redirect HTTP traffic to HTTPS in HTTP vhost +cat >>$root/conf/dvhost.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Redirect HTTP traffic to HTTPS +<Location /> +RewriteEngine on +RewriteCond %{SERVER_PORT} ^$port$ [OR] +RewriteCond %{SERVER_PORT} ^$pport$ +RewriteRule .* https://%{SERVER_NAME}$sslpportsuffix%{REQUEST_URI} [R] +</Location> + +EOF + +# Generate HTTPS vhost configuration +cat >$root/conf/vhost-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Virtual host configuration +UseCanonicalName Off + +# 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 +SSLOptions +StrictRequire +OptRenegotiate +FakeBasicAuth + +# Require clients to use SSL and authenticate +<Location /> +SSLRequireSSL +SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128 +</Location> + +# Log SSL requests +# [timestamp] [sslaccess] remote-host remote-ident remote-user SSL-protocol +# SSL-cipher "request-line" status response-size "referrer" "user-agent" +# "SSL-client-I-DN" "SSL-client-S-DN" "user-track" local-IP virtual-host +# response-time bytes-received bytes-sent +LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [sslaccess] %h %l %u %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{SSL_CLIENT_I_DN}x\" \"%{SSL_CLIENT_S_DN}x\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" sslcombined +Include conf/log-ssl.conf + +# Enable HTTPS reverse proxy +ProxyRequests Off +ProxyPreserveHost On +ProxyStatus On +SSLProxyEngine on +SSLProxyCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL + +# Verify server certificates +SSLProxyVerify require +SSLProxyVerifyDepth 1 +SSLProxyCheckPeerCN Off + +# Enable server status +<Location /server-status> +SetHandler server-status +HostnameLookups on +</Location> + +EOF + +# Generate tracking configuration +cat >$root/conf/tracking-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Configure tracking +CookieTracking on +CookieName TuscanyVisitorId +CookieStyle Cookie +CookieExpires 31556926 + +EOF + +if [ "$dothost" != "" ]; then + cat >>$root/conf/tracking-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +CookieDomain .$dothost + +EOF + +fi + +# Configure logging +cat >$root/conf/log-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +CustomLog $root/logs/ssl_access_log sslcombined + +EOF + +# Configure virtual hosts +cat >$root/conf/svhost-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Static virtual host configuration +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/server.crt" +SSLCertificateKeyFile "$root/cert/server.key" + +EOF + +cat >$root/conf/dvhost-ssl.conf <<EOF +# Mass dynamic virtual host configuration +# Generated by: httpd-ssl-conf $* +Include conf/vhost-ssl.conf + +# Declare wildcard 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" + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-start b/sca-cpp/branches/lightweight-sca/modules/http/httpd-start new file mode 100755 index 0000000000..e38c2f9a94 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-start @@ -0,0 +1,25 @@ +#!/bin/sh + +# 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. + +# Start httpd server +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +apachectl=`cat $here/httpd-apachectl.prefix` +$apachectl -E $root/logs/error_log -k start -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-stop b/sca-cpp/branches/lightweight-sca/modules/http/httpd-stop new file mode 100755 index 0000000000..9010e4dd17 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-stop @@ -0,0 +1,25 @@ +#!/bin/sh + +# 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. + +# Stop httpd server +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +apachectl=`cat $here/httpd-apachectl.prefix` +$apachectl -k graceful-stop -d $root -f $root/conf/httpd.conf 2>/dev/null diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-test b/sca-cpp/branches/lightweight-sca/modules/http/httpd-test new file mode 100755 index 0000000000..ab6ab5ad41 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-test @@ -0,0 +1,42 @@ +#!/bin/sh + +# 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. + +echo "Testing..." +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../http/curl.prefix` + +# Setup +rm -rf tmp +./httpd-conf tmp localhost 8090 htdocs +./httpd-event-conf tmp +./httpd-start tmp +sleep 2 + +# Test HTTP GET +$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html +diff tmp/index.html htdocs/index.html +rc=$? + +# Cleanup +./httpd-stop tmp +sleep 2 +if [ "$rc" = "0" ]; then + echo "OK" +fi +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-tunnel-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-tunnel-ssl-conf new file mode 100755 index 0000000000..0028576364 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-tunnel-ssl-conf @@ -0,0 +1,38 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD SSL Tunnel configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +# Generate required modules list +cat >>$root/conf/modules.conf <<EOF +# Generated by: httpd-tunnel-ssl-conf $* +LoadModule mod_tuscany_ssltunnel $here/libmod_tuscany_ssltunnel$libsuffix + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-worker-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-worker-conf new file mode 100755 index 0000000000..0a061dbffa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-worker-conf @@ -0,0 +1,45 @@ +#!/bin/sh + +# 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. + +# Configure HTTPD to run with the worker MPM +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +modules_prefix=`cat $here/httpd-modules.prefix` + +mkdir -p $root +mkdir -p $root/conf +cat >$root/conf/mpm.conf <<EOF +# Generated by: httpd-worker-conf $* +# 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-conf $* +# Set thread stack size +ThreadStackSize 2097152 + +EOF +fi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd.hpp b/sca-cpp/branches/lightweight-sca/modules/http/httpd.hpp new file mode 100644 index 0000000000..6470d6c587 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd.hpp @@ -0,0 +1,753 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_httpd_hpp +#define tuscany_httpd_hpp + +/** + * HTTPD module implementation functions. + */ + +extern "C" { +#include <apr_strings.h> +#include <apr_fnmatch.h> +#include <apr_lib.h> +#define APR_WANT_STRFUNC +#include <apr_want.h> +#include <apr_base64.h> + +#include <httpd.h> +// Hack to workaround compile error with CLang/LLVM +#undef strtoul +// Hack to workaround compile error with HTTPD 2.3.8 +#define new new_ +#include <http_config.h> +#undef new +#include <http_core.h> +#include <http_connection.h> +#include <http_request.h> +// Ignore conversion warnings in HTTPD 2.3.15 header +#ifdef WANT_MAINTAINER_WARNINGS +#ifndef IS_DARWIN +#pragma GCC diagnostic ignored "-Wconversion" +#endif +#endif +#include <http_protocol.h> +// Re-enable conversion warnings +#ifdef WANT_MAINTAINER_WARNINGS +#ifndef IS_DARWIN +#pragma GCC diagnostic warning "-Wconversion" +#endif +#endif +// Hack to workaround compile error with HTTPD 2.3.8 +#define aplog_module_index aplog_module_index = 0 +#include <http_log.h> +#undef aplog_module_index +#undef APLOG_MODULE_INDEX +#define APLOG_MODULE_INDEX (aplog_module_index ? *aplog_module_index : APLOG_NO_MODULE) +#include <http_main.h> +#include <util_script.h> +#include <util_md5.h> +#include <http_config.h> +#include <http_log.h> +#include <ap_mpm.h> +#include <mod_core.h> +#include <ap_provider.h> +#include <mod_auth.h> +#include <mod_session.h> +} + +#include "string.hpp" +#include "stream.hpp" +#include "sstream.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "http.hpp" + + +namespace tuscany { +namespace httpd { + +/** + * Returns a server-scoped module configuration. + */ +template<typename C> void* makeServerConf(apr_pool_t* p, server_rec* s) { + return new (gc_new<C>(p)) C(p, s); +} + +template<typename C> const C& serverConf(const request_rec* r, const module* mod) { + return *(C*)ap_get_module_config(r->server->module_config, mod); +} + +template<typename C> C& serverConf(const server_rec* s, const module* mod) { + return *(C*)ap_get_module_config(s->module_config, mod); +} + +template<typename C> C& serverConf(const cmd_parms* cmd, const module* mod) { + return *(C*)ap_get_module_config(cmd->server->module_config, mod); +} + +/** + * Returns a directory-scoped module configuration. + */ +template<typename C> void* makeDirConf(apr_pool_t *p, char* d) { + return new (gc_new<C>(p)) C(p, d); +} + +template<typename C> const C& dirConf(const request_rec* r, const module* mod) { + return *(C*)ap_get_module_config(r->per_dir_config, mod); +} + +template<typename C> C& dirConf(const void* c) { + return *(C*)c; +} + +/** + * Returns a request-scoped module configuration. + */ +template<typename C> C& makeRequestConf(const request_rec* r, const module* mod) { + C* c = new (gc_new<C>(r->pool)) C(r->pool, r); + ap_set_module_config(r->request_config, mod, c); + return *c; +} + +template<typename C> C& requestConf(const request_rec* r, const module* mod) { + C* c = (C*)ap_get_module_config(r->request_config, mod); + if (c == NULL) + return makeRequestConf<C>(r, mod); + return *c; +} + +/** + * Return the host name for a server. + */ +const string hostName(const server_rec* s, const string& def = "localhost") { + return s->server_hostname != NULL? s->server_hostname : def; +} + +/** + * Return the host name from an HTTP request. + */ +const string hostName(request_rec* r, const string& def = "localhost") { + const char* fh = apr_table_get(r->headers_in, "X-Forwarded-Server"); + if (fh != NULL) + return fh; + const char* h = ap_get_server_name(r); + return h != NULL? h : (r->server->server_hostname != NULL? r->server->server_hostname : def); +} + +/** + * Convert a host name to a realm. + */ +const string realm(const string& host) { + const string pre = substr(host, 0, 4); + return pre == "www." || pre == "ww1." || pre == "ww2." || pre == "ww3."? substr(host, 4) : host; +} + +/** + * Return the protocol scheme for a server. + */ +const string scheme(const server_rec* s, const string& def = "http") { + return s->server_scheme != NULL? s->server_scheme : def; +} + +/** + * Return the protocol scheme from an HTTP request. + */ +const string scheme(request_rec* r, const string& def = "http") { + const char* fs = apr_table_get(r->headers_in, "X-Forwarded-HTTPS"); + if (fs != NULL) + return !strcmp(fs, "on")? "https" : "http"; + return r->server->server_scheme != NULL? r->server->server_scheme : def; +} + +/** + * Return the port number for a server. + */ +const int port(const server_rec* s, const int def = 80) { + return s->port != 0? s->port : def; +} + +/** + * Return the port number from an HTTP request. + */ +const int port(request_rec* r, const int def = 80) { + const char* fp = apr_table_get(r->headers_in, "X-Forwarded-Port"); + if (fp != NULL) + return atoi(fp); + const int p = ap_get_server_port(r); + return p != 0? p : def; +} + +/** + * Return the name of a server. + */ +const string serverName(const server_rec* s, const string& def = "localhost") { + ostringstream n; + const string sc = scheme(s); + const string h = hostName(s, def); + const int p = port(s, sc == "https"? 443 : 80); + n << sc << "://" << h; + if (!((sc == "http" && p == 80) || (sc == "https" && p == 443))) + n << ":" << p; + n << (s->path != NULL? string(s->path, s->pathlen) : ""); + return str(n); +} + +/** + * Determine the name of a server from an HTTP request. + */ +const string serverName(request_rec* r, const string& def = "localhost") { + ostringstream n; + const string s = scheme(r); + const string h = hostName(r, def); + const int p = port(r, s == "https"? 443 : 80); + n << s << "://" << h; + if (!((s == "http" && p == 80) || (s == "https" && p == 443))) + n << ":" << p; + n << (r->server->path != NULL? string(r->server->path, r->server->pathlen) : ""); + return str(n); +} + +/** + * Return true if a request is targeting a virtual host. + */ +const bool isVhostRequest(const server_rec* s, const string& d, request_rec* r) { + const string rh = hostName(r); + return rh != hostName(s) && http::topDomain(rh) == d; +} + +/** + * Return the content type of a request. + */ +const string contentType(const request_rec* r) { + const char* ct = apr_table_get(r->headers_in, "Content-Type"); + if (ct == NULL) + return ""; + return ct; +} + +/** + * Return the cookie header of a request. + */ +const string cookie(const request_rec* r) { + const char* c = apr_table_get(r->headers_in, "Cookie"); + if (c == NULL) + return ""; + return c; +} + +/** + * Return the remaining part of a uri after the given path (aka the path info.) + */ +const list<value> pathInfo(const list<value>& uri, const list<value>& path) { + if (isNil(path)) + return uri; + return pathInfo(cdr(uri), cdr(path)); +} + +/** + * Convert a URI to an absolute URL. + */ +const string url(const string& uri, request_rec* r) { + if (contains(uri, "://")) + return uri; + ostringstream n; + const string s = scheme(r); + const string h = hostName(r, "localhost"); + const int p = port(r, s == "https"? 443 : 80); + n << s << "://" << h; + if (!((s == "http" && p == 80) || (s == "https" && p == 443))) + n << ":" << p; + n << uri; + return str(n); +} + +/** + * Convert a URI and a path to an absolute URL. + */ +const string url(const string& uri, const list<value>& p, request_rec* r) { + return url(uri + path(p), r); +} + +/** + * Escape a URI. + */ +const char escape_c2x[] = "0123456789ABCDEF"; +const string escape(const string& uri) { + debug(uri, "httpd::escape::uri"); + char* copy = (char*)apr_palloc(gc_current_pool(), 3 * length(uri) + 3); + const unsigned char* s = (const unsigned char *)c_str(uri); + unsigned char* d = (unsigned char*)copy; + unsigned c; + while ((c = *s)) { + if (apr_isalnum(c) || c == '_') + *d++ = (unsigned char)c; + else if (c == ' ') + *d++ = '+'; + else { + *d++ = '%'; + *d++ = escape_c2x[c >> 4]; + *d++ = escape_c2x[c & 0xf]; + } + ++s; + } + *d = '\0'; + debug(copy, "httpd::escape::result"); + return copy; +} + +/** + * Unescape a URI. + */ +const string unescape(const string& uri) { + debug(uri, "httpd::unescape::uri"); + char* b = const_cast<char*>(c_str(string(c_str(uri)))); + ap_unescape_url(b); + debug(b, "httpd::unescape::result"); + return b; +} + +/** + * Unescape a list of key of value pairs representing query args. + */ +const list<value> unescapeArg(const list<value> a) { + return mklist<value>(car(a), unescape(cadr(a))); +} + +const list<list<value> > unescapeArgs(const list<list<value> > args) { + debug(args, "httpd::unescape::args"); + const list<list<value> > uargs = map<list<value>, list<value>>(unescapeArg, args); + debug(uargs, "httpd::unescape::result"); + return uargs; +} + +/** + * Returns a list of key value pairs from the args in a query string. + */ +const list<value> queryArg(const string& s) { + debug(s, "httpd::queryArg::string"); + const list<string> t = tokenize("=", s); + if (isNil(cdr(t))) + return mklist<value>(c_str(car(t)), ""); + return mklist<value>(c_str(car(t)), cadr(t)); +} + +const string fixupQueryArgs(const string& a) { + const list<string> t = tokenize("?", a); + if (isNil(t) || isNil(cdr(t))) + return a; + return join("&", t); +} + +const list<list<value> > queryArgs(const string& a) { + return map<string, list<value>>(queryArg, tokenize("&", fixupQueryArgs(a))); +} + +/** + * Returns a list of key value pairs from the args in an HTTP request. + */ +const list<list<value> > queryArgs(const request_rec* r) { + if (r->args == NULL) + return list<list<value> >(); + return queryArgs(r->args); +} + +/** + * Converts the args received in a POST to a list of key value pairs. + */ +const list<list<value> > postArgs(const list<value>& a) { + if (isNil(a)) + return list<list<value> >(); + const list<value> l = car(a); + return cons(l, postArgs(cdr(a))); +} + +/** + * Setup the HTTP read policy. + */ +const int setupReadPolicy(request_rec* r) { + const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); + if(rc != OK) + return rc; + ap_should_client_block(r); + if(r->read_chunked == true && r->remaining == 0) + r->chunked = true; + //apr_table_setn(r->headers_out, "Connection", "close"); + return OK; +} + +/** + * Read the content of a POST or PUT. + */ +const list<string> read(request_rec* r) { + char b[1024]; + const size_t n = ap_get_client_block(r, b, sizeof(b)); + if (n <= 0) + return list<string>(); + return cons(string(b, n), read(r)); +} + +/** + * Write an HTTP result. + */ +const failable<int> writeResult(const failable<list<string> >& ls, const string& ct, request_rec* r) { + if (!hasContent(ls)) + return mkfailure<int>(ls); + ostringstream os; + write(content(ls), os); + const string ob(str(os)); + + // Make sure browsers come back and check for updated dynamic content + apr_table_set(r->headers_out, "Cache-Control", "must-revalidate, max-age=0"); + apr_table_set(r->headers_out, "Expires", "Tue, 01 Jan 1980 00:00:00 GMT"); + apr_table_set(r->subprocess_env, "private-cache", "1"); + + // Compute and return an Etag for the returned content + const string etag(ap_md5_binary(r->pool, (const unsigned char*)c_str(ob), (int)length(ob))); + + // Check for an If-None-Match header and just return a 304 not-modified status + // if the Etag matches the Etag presented by the client, to save bandwith + const char* match = apr_table_get(r->headers_in, "If-None-Match"); + apr_table_setn(r->headers_out, "ETag", apr_pstrdup(r->pool, c_str(etag))); + if (match != NULL && etag == match) { + r->status = HTTP_NOT_MODIFIED; + debug(r->status, "httpd::writeResult::status"); + return OK; + } + + debug(r->status, "httpd::writeResult::status"); + debug(ct, "httpd::writeResult::contentType"); + debug(ob, "httpd::writeResult::content"); + ap_set_content_type(r, apr_pstrdup(r->pool, c_str(ct))); + ap_rwrite(c_str(ob), (int)length(ob), r); + return OK; +} + +/** + * Report a request execution status. + */ +const int reportStatus(const failable<int>& rc) { + debug(rc, "httpd::reportStatus::rc"); + if (!hasContent(rc)) { + const int r = rcode(rc); + return r == -1 ? HTTP_INTERNAL_SERVER_ERROR : r; + } + return content(rc); +} + +/** + * Convert a value to an HTTPD request struc + */ +request_rec* request(const value& v) { + return (request_rec*)(long)(double)v; +} + +/** + * Convert an HTTPD request struct to a value + */ +const value requestValue(request_rec* r) { + return value((double)(long)r); +} + +/** + * Update request filters in an HTTPD redirect request. + * Similar to httpd/modules/http/http_request.c::update_r_in_filters. + */ +const bool redirectFilters(ap_filter_t* f, request_rec* from, request_rec* to) { + if (f == NULL) + return true; + if (f->r == from) + f->r = to; + return redirectFilters(f->next, from, to); +} + +/** + * Create an HTTPD internal redirect request. + * Similar to httpd/modules/http/http_request.c::internal_internal_redirect. + */ +const failable<request_rec*> internalRedirectRequest(const string& nr_uri, request_rec* r) { + if (ap_is_recursion_limit_exceeded(r)) + return mkfailure<request_rec*>("Redirect recursion limit exceeded", HTTP_INTERNAL_SERVER_ERROR); + + // Create a new request + request_rec* nr = (request_rec*)apr_pcalloc(r->pool, sizeof(request_rec)); + nr->connection = r->connection; + nr->server = r->server; + nr->pool = r->pool; + nr->method = r->method; + nr->method_number = r->method_number; + nr->allowed_methods = ap_make_method_list(nr->pool, 2); + ap_parse_uri(nr, apr_pstrdup(nr->pool, c_str(nr_uri))); + nr->filename = apr_pstrdup(nr->pool, c_str(string("/redirected:") + nr_uri)); + nr->request_config = ap_create_request_config(r->pool); + nr->per_dir_config = r->server->lookup_defaults; + nr->prev = r; + r->next = nr; + + // Run create request hook + ap_run_create_request(nr); + + // Inherit protocol info from the original request + nr->the_request = r->the_request; + nr->allowed = r->allowed; + nr->status = r->status; + nr->assbackwards = r->assbackwards; + nr->header_only = r->header_only; + nr->protocol = r->protocol; + nr->proto_num = r->proto_num; + nr->hostname = r->hostname; + nr->request_time = r->request_time; + nr->main = r->main; + nr->headers_in = r->headers_in; + nr->headers_out = apr_table_make(r->pool, 12); + nr->err_headers_out = r->err_headers_out; + nr->subprocess_env = r->subprocess_env; + nr->notes = apr_table_make(r->pool, 5); + nr->allowed_methods = ap_make_method_list(nr->pool, 2); + nr->htaccess = r->htaccess; + nr->no_cache = r->no_cache; + nr->expecting_100 = r->expecting_100; + nr->no_local_copy = r->no_local_copy; + nr->read_length = r->read_length; + nr->vlist_validator = r->vlist_validator; + nr->user = r->user; + + // Setup input and output filters + nr->proto_output_filters = r->proto_output_filters; + nr->proto_input_filters = r->proto_input_filters; + nr->output_filters = nr->proto_output_filters; + nr->input_filters = nr->proto_input_filters; + if (nr->main) + ap_add_output_filter_handle(ap_subreq_core_filter_handle, NULL, nr, nr->connection); + redirectFilters(nr->input_filters, r, nr); + redirectFilters(nr->output_filters, r, nr); + const int rrc = ap_run_post_read_request(nr); + if (rrc != OK && rrc != DECLINED) + return mkfailure<request_rec*>("Error handling internal redirect", rrc); + + return nr; +} + +/** + * Process an HTTPD internal redirect request. + * Similar to httpd/modules/http/http_request.c::ap_internal_redirect. + */ +const int internalRedirect(request_rec* nr) { + int status = ap_run_quick_handler(nr, 0); + if (status == DECLINED) { + status = ap_process_request_internal(nr); + if (status == OK) + status = ap_invoke_handler(nr); + } + if (status != OK) { + nr->status = status; + return OK; + } + ap_finalize_request_protocol(nr); + return OK; +} + +/** + * Create and process an HTTPD internal redirect request. + */ +const int internalRedirect(const string& uri, request_rec* r) { + debug(uri, "httpd::internalRedirect"); + const failable<request_rec*> nr = httpd::internalRedirectRequest(uri, r); + if (!hasContent(nr)) + return rcode(nr); + return httpd::internalRedirect(content(nr)); +} + +/** + * Create an HTTPD sub request. + * Similar to httpd/server/request.c::make_sub_request + */ +const failable<request_rec*> internalSubRequest(const string& nr_uri, request_rec* r) { + if (ap_is_recursion_limit_exceeded(r)) + return mkfailure<request_rec*>("Redirect recursion limit exceeded", HTTP_INTERNAL_SERVER_ERROR); + + // Create a new sub pool + apr_pool_t *nrp; + apr_pool_create(&nrp, r->pool); + apr_pool_tag(nrp, "subrequest"); + + // Create a new POST request + request_rec* nr = (request_rec*)apr_pcalloc(nrp, sizeof(request_rec)); + nr->connection = r->connection; + nr->server = r->server; + nr->pool = nrp; + nr->method = "POST"; + nr->method_number = M_POST; + nr->allowed_methods = ap_make_method_list(nr->pool, 2); + ap_parse_uri(nr, apr_pstrdup(nr->pool, c_str(nr_uri))); + nr->filename = apr_pstrdup(nr->pool, c_str(string("/subreq:") + nr_uri)); + nr->request_config = ap_create_request_config(r->pool); + nr->per_dir_config = r->server->lookup_defaults; + + // Inherit some of the protocol info from the parent request + nr->the_request = r->the_request; + nr->hostname = r->hostname; + nr->request_time = r->request_time; + nr->allowed = r->allowed; + nr->status = HTTP_OK; + nr->assbackwards = r->assbackwards; + nr->header_only = r->header_only; + nr->protocol = const_cast<char*>("INCLUDED"); + nr->hostname = r->hostname; + nr->request_time = r->request_time; + nr->main = r; + nr->headers_in = apr_table_make(r->pool, 12); + nr->headers_out = apr_table_make(r->pool, 12); + nr->err_headers_out = apr_table_make(nr->pool, 5); + nr->subprocess_env = r->subprocess_env; + nr->subprocess_env = apr_table_copy(nr->pool, r->subprocess_env); + nr->notes = apr_table_make(r->pool, 5); + nr->htaccess = r->htaccess; + nr->no_cache = r->no_cache; + nr->expecting_100 = r->expecting_100; + nr->no_local_copy = r->no_local_copy; + nr->read_length = 0; + nr->vlist_validator = r->vlist_validator; + nr->user = r->user; + + // Setup input and output filters + nr->proto_output_filters = r->proto_output_filters; + nr->proto_input_filters = r->proto_input_filters; + nr->output_filters = nr->proto_output_filters; + nr->input_filters = nr->proto_input_filters; + ap_add_output_filter_handle(ap_subreq_core_filter_handle, NULL, nr, nr->connection); + + // Run create request hook + ap_run_create_request(nr); + nr->used_path_info = AP_REQ_DEFAULT_PATH_INFO; + + return nr; +} + +/** + * Return an HTTP external redirect request. + */ +const int externalRedirect(const string& uri, request_rec* r) { + debug(uri, "httpd::externalRedirect"); + r->status = HTTP_MOVED_TEMPORARILY; + apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, c_str(uri))); + apr_table_setn(r->headers_out, "Cache-Control", "no-store"); + apr_table_addn(r->err_headers_out, "Cache-Control", "no-store"); + r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/") + uri)); + return HTTP_MOVED_TEMPORARILY; +} + +/** + * Put a value in the process user data. + */ +const bool putUserData(const string& k, const void* v, const server_rec* s) { + apr_pool_userdata_set((const void *)v, c_str(k), apr_pool_cleanup_null, s->process->pool); + return true; +} + +/** + * Return a user data value. + */ +const void* userData(const string& k, const server_rec* s) { + void* v = NULL; + apr_pool_userdata_get(&v, c_str(k), s->process->pool); + return v; +} + +#ifdef WANT_MAINTAINER_LOG + +/** + * Debug log. + */ + +/** + * Log an optional value. + */ +const char* debugOptional(const char* s) { + if (s == NULL) + return ""; + return s; +} + +/** + * Log a header + */ +int debugHeader(unused void* r, const char* key, const char* value) { + cdebug << " header key: " << key << ", value: " << value << endl; + return 1; +} + +/** + * Log an environment variable + */ +int debugEnv(unused void* r, const char* key, const char* value) { + cdebug << " var key: " << key << ", value: " << value << endl; + return 1; +} + +/** + * Log a note. + */ +int debugNote(unused void* r, const char* key, const char* value) { + cdebug << " note key: " << key << ", value: " << value << endl; + return 1; +} + +/** + * Log a request. + */ +const bool debugRequest(request_rec* r, const string& msg) { + gc_scoped_pool pool; + cdebug << msg << ":" << endl; + cdebug << " unparsed uri: " << debugOptional(r->unparsed_uri) << endl; + cdebug << " uri: " << debugOptional(r->uri) << endl; + cdebug << " path info: " << debugOptional(r->path_info) << endl; + cdebug << " filename: " << debugOptional(r->filename) << endl; + cdebug << " uri tokens: " << pathTokens(r->uri) << endl; + cdebug << " args: " << debugOptional(r->args) << endl; + cdebug << " server: " << debugOptional(r->server->server_hostname) << endl; + cdebug << " protocol: " << debugOptional(r->protocol) << endl; + cdebug << " method: " << debugOptional(r->method) << endl; + cdebug << " method number: " << r->method_number << endl; + cdebug << " content type: " << contentType(r) << endl; + cdebug << " content encoding: " << debugOptional(r->content_encoding) << endl; + apr_table_do(debugHeader, r, r->headers_in, NULL); + cdebug << " user: " << debugOptional(r->user) << endl; + cdebug << " auth type: " << debugOptional(r->ap_auth_type) << endl; + apr_table_do(debugEnv, r, r->subprocess_env, NULL); + apr_table_do(debugNote, r, r->notes, NULL); + return true; +} + +#define debug_httpdRequest(r, msg) do { if (debug_islogging()) httpd::debugRequest(r, msg); } while(0) + +#else + +#define debug_httpdRequest(r, msg) + +#endif + +} +} + +#endif /* tuscany_httpd_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mass-host-conf b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-conf new file mode 100755 index 0000000000..2da8f4f836 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-conf @@ -0,0 +1,62 @@ +#!/bin/sh + +# 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. + +# Generate mass dynamic virtual hosting configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +vroot=`echo "import os; print os.path.realpath('$2')" | python` +vhtdocs=$3 + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` +addr=`echo $conf | awk '{ print $7 }'` +port=`$here/httpd-addr port $addr` +pport=`$here/httpd-addr pport $addr` +vhost=`$here/httpd-addr vhost $addr` + +htdocs=`echo $conf | awk '{ print $8 }'` +mkdir -p $htdocs +htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python` + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: mass-host-conf $* +# Enable mass dynamic virtual hosting +NameVirtualHost $vhost + +<VirtualHost $vhost> +ServerName http://vhost.$host:$pport +ServerAlias *.$host + +# Map /v/<app-name>/<path> to vroot/<app-name>/vhtdocs/<path> +AliasMatch /v/([^/]+)(.*)$ $vroot/\$1/$vhtdocs/\$2 + +Include conf/dvhost.conf + +# Configure authentication +Include conf/noauth.conf +Include conf/locauth.conf +Include conf/pubauth.conf +Include conf/adminauth.conf + +</VirtualHost> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mass-host-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-ssl-conf new file mode 100755 index 0000000000..68bd5b4606 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-ssl-conf @@ -0,0 +1,68 @@ +#!/bin/sh + +# 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. + +# Generate mass dynamic virtual hosting configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +ssladdr=`echo $sslconf | awk '{ print $6 }'` +sslport=`$here/httpd-addr port $ssladdr` +sslpport=`$here/httpd-addr pport $ssladdr` +sslvhost=`$here/httpd-addr vhost $ssladdr` + +vhostconf=`cat $root/conf/httpd.conf | grep "# Generated by: mass-host-conf"` +vroot=`echo $vhostconf | awk '{ print $6 }'`; vroot=`echo "import os; print os.path.realpath('$vroot')" | python` +vhtdocs=`echo $vhostconf | awk '{ print $7 }'` + +htdocs=`echo $conf | awk '{ print $8 }'` +mkdir -p $htdocs +htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python` + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: mass-host-ssl-conf $* +# Enable mass dynamic virtual hosting over HTTPS +SSLStrictSNIVHostCheck Off + +# HTTPS dynamic virtual host +NameVirtualHost $sslvhost +<VirtualHost $sslvhost> +ServerName https://vhost.$host:$sslpport +ServerAlias *.$host + +# Map /v/<app-name>/<path> to vroot/<app-name>/vhtdocs/<path> +AliasMatch /v/([^/]+)(.*)$ $vroot/\$1/$vhtdocs/\$2 + +Include conf/dvhost-ssl.conf + +# Configure authentication +Include conf/noauth-ssl.conf +Include conf/locauth-ssl.conf +Include conf/pubauth-ssl.conf +Include conf/adminauth-ssl.conf + +# Configure tracking +Include conf/tracking-ssl.conf + +</VirtualHost> + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/minify-css b/sca-cpp/branches/lightweight-sca/modules/http/minify-css new file mode 100755 index 0000000000..734d041aba --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/minify-css @@ -0,0 +1,34 @@ +#!/bin/sh + +# 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. + +# Minify a CSS file +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pagespeed_prefix=`cat $here/pagespeed.prefix` + +if [ "${pagespeed_prefix}" = "" ]; then + minify_css="cat" +else + minify_css="${pagespeed_prefix}/jsmin_bin" +fi + +css="$1" +mincss="$2" + +${minify_css} <${css} >${mincss} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/minify-html b/sca-cpp/branches/lightweight-sca/modules/http/minify-html new file mode 100755 index 0000000000..31bb329d94 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/minify-html @@ -0,0 +1,34 @@ +#!/bin/sh + +# 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. + +# Minify an HTML file +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pagespeed_prefix=`cat $here/pagespeed.prefix` + +if [ "${pagespeed_prefix}" = "" ]; then + minify_html="cp" +else + minify_html="${pagespeed_prefix}/minify_html_bin" +fi + +html="$1" +minhtml="$2" + +${minify_html} ${html} ${minhtml} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/minify-js b/sca-cpp/branches/lightweight-sca/modules/http/minify-js new file mode 100755 index 0000000000..5e7cbb1bc0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/minify-js @@ -0,0 +1,34 @@ +#!/bin/sh + +# 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. + +# Minify a JS file +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pagespeed_prefix=`cat $here/pagespeed.prefix` + +if [ "${pagespeed_prefix}" = "" ]; then + minify_js="cat" +else + minify_js="${pagespeed_prefix}/jsmin_bin" +fi + +js="$1" +minjs="$2" + +${minify_js} <${js} >${minjs} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-openauth.cpp b/sca-cpp/branches/lightweight-sca/modules/http/mod-openauth.cpp new file mode 100644 index 0000000000..2e308ecedb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-openauth.cpp @@ -0,0 +1,478 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +/** + * HTTPD module for Tuscany Open authentication. + * + * This module allows multiple authentication mechanisms to co-exist in a + * single Web site: + * - OAuth1 using Tuscany's mod-tuscany-oauth1 + * - OAuth2 using Tuscany's mod-tuscany-oauth2 + * - OpenID using mod_auth_openid + * - Form-based using HTTPD's mod_auth_form + * - SSL certificate using SSLFakeBasicAuth and mod_auth_basic + */ + +#include <sys/stat.h> + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "stream.hpp" +#include "list.hpp" +#include "tree.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "httpd.hpp" +#include "http.hpp" +#include "openauth.hpp" + + +extern "C" { +extern module AP_MODULE_DECLARE_DATA mod_tuscany_openauth; +} + +namespace tuscany { +namespace openauth { + +/** + * Server configuration. + */ +class ServerConf { +public: + ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) { + } + + const gc_pool p; + server_rec* server; +}; + +/** + * Authentication provider configuration. + */ +class AuthnProviderConf { +public: + AuthnProviderConf() : name(), provider(NULL) { + } + AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) { + } + + string name; + const authn_provider* provider; +}; + +/** + * Directory configuration. + */ +class DirConf { +public: + DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") { + } + + const gc_pool p; + const char* dir; + bool enabled; + string login; + list<AuthnProviderConf> apcs; +}; + +#ifdef WANT_MAINTAINER_LOG + +/** + * Log session entries. + */ +int debugSessionEntry(unused void* r, const char* key, const char* value) { + cdebug << " session key: " << key << ", value: " << value << endl; + return 1; +} + +const bool debugSession(request_rec* r, session_rec* z) { + apr_table_do(debugSessionEntry, r, z->entries, NULL); + return true; +} + +#define debug_authSession(r, z) if (debug_islogging()) openauth::debugSession(r, z) + +#else + +#define debug_authSession(r, z) + +#endif + +/** + * Run the authnz hooks to authenticate a request. + */ +const failable<int> checkAuthnzProviders(const string& user, const string& pw, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (isNil(apcs)) + return mkfailure<int>("Authentication failure for: " + user); + const AuthnProviderConf apc = car<AuthnProviderConf>(apcs); + if (apc.provider == NULL || !apc.provider->check_password) + return checkAuthnzProviders(user, pw, r, cdr(apcs)); + + apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name)); + const authn_status auth_result = apc.provider->check_password(r, c_str(user), c_str(pw)); + apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); + if (auth_result != AUTH_GRANTED) + return checkAuthnzProviders(user, pw, r, cdr(apcs)); + return OK; +} + +const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r, const DirConf& dc) { + if (substr(user, 0, 1) == "/" && pw == "password") + return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + + if (isNil(dc.apcs)) { + const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); + return checkAuthnzProviders(user, pw, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, pw, r, dc.apcs); +} + +/** + * Return the user info from a form auth encrypted session cookie. + */ +static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL; +static int (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL; + +const failable<value> userInfoFromSession(const string& realm, request_rec* r) { + debug("modopenauth::userInfoFromSession"); + if (ap_session_load_fn == NULL) + ap_session_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load); + session_rec *z = NULL; + ap_session_load_fn(r, &z); + if (z == NULL) + return mkfailure<value>("Couldn't retrieve user session"); + debug_authSession(r, z); + + if (ap_session_get_fn == NULL) + ap_session_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get); + const char* user = NULL; + ap_session_get_fn(r, z, c_str(realm + "-user"), &user); + if (user == NULL) + return mkfailure<value>("Couldn't retrieve user id"); + const char* pw = NULL; + ap_session_get_fn(r, z, c_str(realm + "-pw"), &pw); + if (pw == NULL) + return mkfailure<value>("Couldn't retrieve password"); + return value(mklist<value>(mklist<value>("realm", realm), mklist<value>("id", string(user)), mklist<value>("password", string(pw)))); +} + +/** + * Return the user info from a form auth session cookie. + */ +const failable<value> userInfoFromCookie(const value& sid, const string& realm, request_rec* r) { + const list<list<value>> info = httpd::queryArgs(sid); + debug(info, "modopenauth::userInfoFromCookie::info"); + const list<value> user = assoc<value>(realm + "-user", info); + if (isNil(user)) + return userInfoFromSession(realm, r); + const list<value> pw = assoc<value>(realm + "-pw", info); + if (isNil(pw)) + return mkfailure<value>("Couldn't retrieve password"); + return value(mklist<value>(mklist<value>("realm", realm), mklist<value>("id", cadr(user)), mklist<value>("password", cadr(pw)))); +} + +/** + * Return the user info from a basic auth header. + */ +const failable<value> userInfoFromHeader(const char* header, const string& realm, request_rec* r) { + debug(header, "modopenauth::userInfoFromHeader::header"); + if (strcasecmp(ap_getword(r->pool, &header, ' '), "Basic")) + return mkfailure<value>("Wrong authentication scheme"); + + while (apr_isspace(*header)) + header++; + char *decoded_line = (char*)apr_palloc(r->pool, apr_base64_decode_len(header) + 1); + int length = apr_base64_decode(decoded_line, header); + decoded_line[length] = '\0'; + + const string user(ap_getword_nulls(r->pool, const_cast<const char**>(&decoded_line), ':')); + const string pw(decoded_line); + + return value(mklist<value>(mklist<value>("realm", realm), mklist<value>("id", user), mklist<value>("password", pw))); +} + +/** + * Handle an authenticated request. + */ +const failable<int> authenticated(const list<list<value> >& info, request_rec* r) { + debug(info, "modopenauth::authenticated::info"); + + // Store user info in the request + const list<value> realm = assoc<value>("realm", info); + if (isNil(realm) || isNil(cdr(realm))) + return mkfailure<int>("Couldn't retrieve realm"); + apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm)))); + + const list<value> id = assoc<value>("id", info); + if (isNil(id) || isNil(cdr(id))) + return mkfailure<int>("Couldn't retrieve user id"); + r->user = apr_pstrdup(r->pool, c_str(cadr(id))); + + apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(id)))); + return OK; +} + +/** + * Check user authentication. + */ +static int checkAuthn(request_rec *r) { + gc_scoped_pool pool(r->pool); + + // Decline if we're not enabled or AuthType is not set to Open + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; + const char* atype = ap_auth_type(r); + if (atype == NULL || strcasecmp(atype, "Open")) + return DECLINED; + debug_httpdRequest(r, "modopenauth::checkAuthn::input"); + debug(atype, "modopenauth::checkAuthn::auth_type"); + + // Get the request args + const list<list<value> > args = httpd::queryArgs(r); + + // Get session id from the request + const maybe<string> sid = sessionID(r, "TuscanyOpenAuth"); + if (hasContent(sid)) { + // Decline if the session id was not created by this module + const string stype = substr(content(sid), 0, 7); + if (stype == "OAuth2_" || stype == "OAuth1_" || stype == "OpenID_") + return DECLINED; + + // Retrieve the auth realm + const char* aname = ap_auth_name(r); + if (aname == NULL) + return httpd::reportStatus(mkfailure<int>("Missing AuthName")); + + // Extract user info from the session id + const failable<value> userinfo = userInfoFromCookie(content(sid), aname, r); + if (hasContent(userinfo)) { + + // Try to authenticate the request + const value uinfo = content(userinfo); + const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc); + if (!hasContent(authz)) { + + // Authentication failed, redirect to login page + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(login(dc.login, value(), 1, r)); + } + + // Successfully authenticated, store the user info in the request + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(authenticated(uinfo, r)); + } + } + + // Get basic auth header from the request + const char* header = apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authorization" : "Authorization"); + if (header != NULL) { + + // Retrieve the auth realm + const char* aname = ap_auth_name(r); + if (aname == NULL) + return httpd::reportStatus(mkfailure<int>("Missing AuthName")); + + // Extract user info from the session id + const failable<value> info = userInfoFromHeader(header, aname, r); + if (hasContent(info)) { + + // Try to authenticate the request + const value uinfo = content(info); + const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc); + if (!hasContent(authz)) { + + // Authentication failed, redirect to login page + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(login(dc.login, value(), 1, r)); + } + + // Successfully authenticated, store the user info in the request + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(authenticated(uinfo, r)); + } + } + + // Decline if the request is for another authentication provider + if (!isNil(assoc<value>("openid_identifier", args))) + return DECLINED; + + // Redirect to the login page, unless we have a session id from another module + if (hasContent(sessionID(r, "TuscanyOpenIDAuth")) || + hasContent(sessionID(r, "TuscanyOAuth1")) || + hasContent(sessionID(r, "TuscanyOAuth2"))) + return DECLINED; + + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(login(dc.login, value(), value(), r)); +} + +/** + * Save the auth session cookie in the response. + */ +static int sessionCookieSave(request_rec* r, session_rec* z) { + gc_scoped_pool pool(r->pool); + + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; + + debug(c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))), "modopenauth::setcookie"); + apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r)))); + return OK; +} + +/** + * Load the auth session cookie from the request. Similar + */ +static int sessionCookieLoad(request_rec* r, session_rec** z) { + gc_scoped_pool pool(r->pool); + + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; + + // First look in the notes + const char* note = apr_pstrcat(r->pool, "mod_openauth", "TuscanyOpenAuth", NULL); + session_rec* zz = (session_rec*)(void*)apr_table_get(r->notes, note); + if (zz != NULL) { + *z = zz; + return OK; + } + + // Parse the cookie + const maybe<string> sid = openauth::sessionID(r, "TuscanyOpenAuth"); + + // Create a new session + zz = (session_rec*)apr_pcalloc(r->pool, sizeof(session_rec)); + zz->pool = r->pool; + zz->entries = apr_table_make(r->pool, 10); + zz->encoded = hasContent(sid)? c_str(content(sid)) : NULL; + zz->uuid = (apr_uuid_t *) apr_pcalloc(r->pool, sizeof(apr_uuid_t)); + *z = zz; + + // Store it in the notes + apr_table_setn(r->notes, note, (char*)zz); + + return OK; +} + +/** + * Process the module configuration. + */ +int postConfigMerge(ServerConf& mainsc, server_rec* s) { + if (s == NULL) + return OK; + debug(httpd::serverName(s), "modopenauth::postConfigMerge::serverName"); + + return postConfigMerge(mainsc, s->next); +} + +int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) { + gc_scoped_pool pool(p); + + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_openauth); + debug(httpd::serverName(s), "modopenauth::postConfig::serverName"); + + // Merge server configurations + return postConfigMerge(sc, s); +} + +/** + * Child process initialization. + */ +void childInit(apr_pool_t* p, server_rec* s) { + gc_scoped_pool pool(p); + + ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_openauth); + if(psc == NULL) { + cfailure << "[Tuscany] Due to one or more errors mod_tuscany_openauth loading failed. Causing apache to stop loading." << endl; + exit(APEXIT_CHILDFATAL); + } + ServerConf& sc = *psc; + + // Merge the updated configuration into the virtual hosts + postConfigMerge(sc, s->next); +} + +/** + * Configuration commands. + */ +const char* confEnabled(cmd_parms *cmd, void *c, const int arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + dc.enabled = (bool)arg; + return NULL; +} +const char* confLogin(cmd_parms *cmd, void *c, const char* arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + dc.login = arg; + return NULL; +} +const char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + + // Lookup and cache the Authn provider + const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION); + if (provider == NULL) + return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg); + if (!provider->check_password) + return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg); + dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider))); + return NULL; +} + +/** + * HTTP server module declaration. + */ +const command_rec commands[] = { + AP_INIT_ITERATE("AuthOpenAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"), + AP_INIT_FLAG("AuthOpenAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "Tuscany Open Auth authentication On | Off"), + AP_INIT_TAKE1("AuthOpenAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "Tuscany Open Auth login page"), + {NULL, NULL, NULL, 0, NO_ARGS, NULL} +}; + +void registerHooks(unused apr_pool_t *p) { + ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF); + ap_hook_session_load(sessionCookieLoad, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_session_save(sessionCookieSave, NULL, NULL, APR_HOOK_MIDDLE); +} + +} +} + +extern "C" { + +module AP_MODULE_DECLARE_DATA mod_tuscany_openauth = { + STANDARD20_MODULE_STUFF, + // dir config and merger + tuscany::httpd::makeDirConf<tuscany::openauth::DirConf>, NULL, + // server config and merger + tuscany::httpd::makeServerConf<tuscany::openauth::ServerConf>, NULL, + // commands and hooks + tuscany::openauth::commands, tuscany::openauth::registerHooks +}; + +} diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-security-audit-conf b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-audit-conf new file mode 100755 index 0000000000..5914bd1df4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-audit-conf @@ -0,0 +1,44 @@ +#!/bin/sh + +# 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. + +# Generate a minimal mod-security audit configuration. +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/tmp + +cat >>$root/conf/mod-security.conf <<EOF +# Generated by: mod-security-audit-conf $* +# Enable mod-security audit log +SecAuditEngine RelevantOnly +SecAuditLogRelevantStatus "^(?:5|4(?!04))" +SecAuditLogParts ABIJDEFHKZ +SecAuditLogType Serial +Include conf/mod-security-audit-log.conf + +EOF + +# Configure audit logging +cat >$root/conf/mod-security-audit-log.conf <<EOF +# Generated by: mod-security-audit-conf $* +SecAuditLog $root/logs/secaudit_log + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-security-conf b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-conf new file mode 100755 index 0000000000..5d03fc5cfb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-conf @@ -0,0 +1,184 @@ +#!/bin/sh + +# 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. + +# Generate a minimal mod-security configuration. +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +modules_prefix=`cat $here/httpd-modules.prefix` +modsecurity_prefix=`cat $here/modsecurity.prefix` + +mkdir -p $root/tmp + +cat >>$root/conf/modules.conf <<EOF +# Generated by: mod-security-conf $* +# Load support for mod-security +LoadModule unique_id_module ${modules_prefix}/modules/mod_unique_id.so +LoadModule security2_module $modsecurity_prefix/lib/mod_security2.so + +EOF + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: mod-security-conf $* +# Enable mod-security +Include conf/mod-security.conf + +EOF + +cat >$root/conf/mod-security.conf <<EOF +# Generated by: mod-security-conf $* +# Enable mod-security rules +SecRuleEngine On +SecDefaultAction "phase:2,pass,nolog,auditlog" + +#SecDebugLog $root/logs//modsec_debug_log +#SecDebugLogLevel 3 + +# Process request bodies +SecRequestBodyAccess Off +SecRule REQUEST_HEADERS:Content-Type "text/xml" "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" +SecRule REQUEST_HEADERS:Content-Type "application/xml" "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" +SecRequestBodyLimit 13107200 +SecRequestBodyNoFilesLimit 131072 +SecRequestBodyInMemoryLimit 131072 +SecRequestBodyLimitAction Reject + +# Verify that we've correctly processed the request body +SecRule REQBODY_ERROR "!@eq 0" "phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + +# By default be strict with what we accept in multipart/form-data request body +SecRule MULTIPART_STRICT_ERROR "!@eq 0" "phase:2,t:none,log,deny,status:44,msg:'Multipart request body failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_SEMICOLON_MISSING}, \ +IQ %{MULTIPART_INVALID_QUOTING}, \ +IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ +IH %{MULTIPART_FILE_LIMIT_EXCEEDED}'" + +# Did we see anything that might be a boundary? +SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" "phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'" + +# Avoid a potential RegEx DoS condition +SecPcreMatchLimit 50000 +SecPcreMatchLimitRecursion 50000 +SecRule TX:/^MSC_/ "!@streq 0" "phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + +# Detect slow DoS attacks +SecRule RESPONSE_STATUS "@streq 408" "phase:5,t:none,nolog,pass, setvar:ip.slow_dos_counter=+1,expirevar:ip.slow_dos_counter=60" +SecRule IP:SLOW_DOS_COUNTER "@gt 5" "phase:1,t:none,log,drop, msg:'Client Connection Dropped due to high # of slow DoS alerts'" +SecWriteStateLimit 50 + +# Process response bodies +SecResponseBodyAccess Off +SecResponseBodyMimeType text/plain text/html text/xml application/xml +SecResponseBodyLimit 524288 +SecResponseBodyLimitAction ProcessPartial + +# The location where mod-security stores temporary files +SecTmpDir $root/tmp/ +SecDataDir $root/tmp/ + +# Use & as application/x-www-form-urlencoded parameter separator +SecArgumentSeparator & + +# Settle on version 0 (zero) cookies. +SecCookieFormat 0 + +# Enable anomaly scoring +SecAction "phase:1,id:'981206',t:none,nolog,pass,setvar:tx.anomaly_score_blocking=on" +SecAction "phase:1,id:'981207',t:none,nolog,pass, \ +setvar:tx.critical_anomaly_score=5, \ +setvar:tx.error_anomaly_score=4, \ +setvar:tx.warning_anomaly_score=3, \ +setvar:tx.notice_anomaly_score=2" +SecAction "phase:1,id:'981208',t:none,nolog,pass,setvar:tx.inbound_anomaly_score_level=10" +SecAction "phase:1,id:'981209',t:none,nolog,pass,setvar:tx.outbound_anomaly_score_level=8" + +# Paranoid mode +SecAction "phase:1,id:'981210',t:none,nolog,pass,setvar:tx.paranoid_mode=0" + +# HTTP policy settings +SecAction "phase:1,id:'981211',t:none,nolog,pass,setvar:tx.max_num_args=255" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.arg_name_length=100" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.arg_length=400" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.total_arg_length=64000" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.max_file_size=1048576" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.combined_file_sizes=1048576" +SecAction "phase:1,id:'981212',t:none,nolog,pass, \ +setvar:'tx.allowed_methods=GET HEAD POST PUT OPTIONS DELETE CONNECT', \ +setvar:'tx.allowed_request_content_type=application/x-www-form-urlencoded multipart/form-data text/xml application/xml application/json application/json-rpc application/atom+xml', \ +setvar:'tx.allowed_http_versions=HTTP/0.9 HTTP/1.0 HTTP/1.1', \ +setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/', \ +setvar:'tx.restricted_headers=/Proxy-Connection/ /Lock-Token/ /Content-Range/ /Translate/ /via/ /if/'" + +# Brute force protection +SecAction "phase:1,id:'981214',t:none,nolog,pass, \ +setvar:'tx.brute_force_protected_urls=/login', \ +setvar:'tx.brute_force_burst_time_slice=60', \ +setvar:'tx.brute_force_counter_threshold=10', \ +setvar:'tx.brute_force_block_timeout=300'" + +# DoS protection +SecAction "phase:1,id:'981215',t:none,nolog,pass, \ +setvar:'tx.dos_burst_time_slice=60', \ +setvar:'tx.dos_counter_threshold=100', \ +setvar:'tx.dos_block_timeout=600'" + +# Check UTF-8 encoding +SecAction "phase:1,id:'981216',t:none,nolog,pass,setvar:tx.crs_validate_utf8_encoding=1" + +# Global and IP collections +SecRule REQUEST_HEADERS:User-Agent "^(.*)$" "phase:1,id:'981217',t:none,pass,nolog,t:sha1,t:hexEncode,setvar:tx.ua_hash=%{matched_var}" +SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" "phase:1,id:'981225',t:none,pass,nolog,capture,setvar:tx.real_ip=%{tx.1}" +SecRule &TX:REAL_IP "!@eq 0" "phase:1,id:'981226',t:none,pass,nolog,initcol:global=global,initcol:ip=%{tx.real_ip}_%{tx.ua_hash}" +SecRule &TX:REAL_IP "@eq 0" "phase:1,id:'981218',t:none,pass,nolog,initcol:global=global,initcol:ip=%{remote_addr}_%{tx.ua_hash}" + +# Include all base mod-security CRS rules +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_20_protocol_violations.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_xss_attacks.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_50_outbound.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_35_bad_robots.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_47_common_exceptions.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_60_correlation.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_40_generic_attacks.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_21_protocol_anomalies.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_30_http_policy.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_49_inbound_blocking.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_sql_injection_attacks.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_45_trojans.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_59_outbound_blocking.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_23_request_limits.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_42_tight_security.conf + +# Include some optional mod-security CRS rules +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_10_ignore_static.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_13_xml_enabler.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_25_cc_known.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_42_comment_spam.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_47_skip_outbound_checks.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_55_application_defects.conf + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-ssltunnel.cpp b/sca-cpp/branches/lightweight-sca/modules/http/mod-ssltunnel.cpp new file mode 100644 index 0000000000..b66cd29959 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-ssltunnel.cpp @@ -0,0 +1,379 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +/** + * HTTPD module used to tunnel traffic over an HTTPS connection. + */ + +#include <sys/stat.h> + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "stream.hpp" +#include "list.hpp" +#include "tree.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "httpd.hpp" +#include "http.hpp" + +// Ignore cast align warnings in APR macros +#ifdef WANT_MAINTAINER_WARNINGS +#pragma GCC diagnostic ignored "-Wcast-align" +#endif + +extern "C" { +extern module AP_MODULE_DECLARE_DATA mod_tuscany_ssltunnel; +} + +namespace tuscany { +namespace httpd { +namespace modssltunnel { + +/** + * Server configuration. + */ +class ServerConf { +public: + ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) { + } + + const gc_pool p; + server_rec* server; + string pass; + string host; + string path; + string ca; + string cert; + string key; +}; + +extern "C" { +extern module AP_DECLARE_DATA core_module; +} + +/** + * Process the module configuration. + */ +int M_SSLTUNNEL; +int postConfigMerge(ServerConf& mainsc, apr_pool_t* p, server_rec* s) { + if (s == NULL) + return OK; + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_ssltunnel); + debug(httpd::serverName(s), "modssltunnel::postConfigMerge::serverName"); + + // Merge configuration from main server + if (length(sc.ca) == 0 && length(mainsc.ca) !=0) + sc.ca = mainsc.ca; + if (length(sc.cert) == 0 && length(mainsc.cert) !=0) + sc.cert = mainsc.cert; + if (length(sc.key) == 0 && length(mainsc.key) !=0) + sc.key = mainsc.key; + + // Parse the configured TunnelPass URI + if (length(sc.pass) != 0) { + apr_uri_t uri; + apr_status_t prc = apr_uri_parse(p, c_str(sc.pass), &uri); + if (prc != APR_SUCCESS) { + mkfailure<int>("Couldn't parse TunnelPass: " + sc.pass + ", " + http::apreason(prc)); + return prc; + } + sc.host = uri.hostname; + sc.path = uri.path; + } + return postConfigMerge(mainsc, p, s->next); +} + +int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) { + gc_scoped_pool pool(p); + + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_ssltunnel); + debug(httpd::serverName(s), "modssltunnel::postConfig::serverName"); + + // Register the SSLTUNNEL method + M_SSLTUNNEL = ap_method_register(p, "SSLTUNNEL"); + + // Merge and process server configurations + return postConfigMerge(sc, p, s); +} + +/** + * Close a connection. + */ +const int close(conn_rec* conn, apr_socket_t* csock) { + debug("modssltunnel::close"); + apr_socket_close(csock); + conn->aborted = 1; + return OK; +} + +/** + * Abort a connection. + */ +const int abort(conn_rec* conn, apr_socket_t* csock, const string& reason) { + debug("modssltunnel::abort"); + apr_socket_close(csock); + conn->aborted = 1; + return httpd::reportStatus(mkfailure<int>(reason)); +} + +/** + * Tunnel traffic from a client connection to a target URL. + */ +int tunnel(conn_rec* conn, const string& ca, const string& cert, const string& key, const string& url, const string& preamble, const gc_pool& p, unused ap_filter_t* ifilter, ap_filter_t* ofilter) { + + // Create input/output bucket brigades + apr_bucket_brigade* ib = apr_brigade_create(pool(p), conn->bucket_alloc); + apr_bucket_brigade* ob = apr_brigade_create(pool(p), conn->bucket_alloc); + + // Get client connection socket + apr_socket_t* csock = (apr_socket_t*)ap_get_module_config(conn->conn_config, &core_module); + + // Open connection to target + http::CURLSession cs(ca, cert, key, "", 0); + const failable<bool> crc = http::connect(url, cs); + if (!hasContent(crc)) + return abort(conn, csock, reason(crc)); + apr_socket_t* tsock = http::sock(cs); + + // Send preamble + if (length(preamble) != 0) { + debug(preamble, "modssltunnel::tunnel::sendPreambleToTarget"); + const failable<bool> src = http::send(c_str(preamble), length(preamble), cs); + if (!hasContent(src)) + return abort(conn, csock, string("Couldn't send to target: ") + reason(src)); + } + + // Create a pollset for the client and target sockets + apr_pollset_t* pollset; + apr_status_t cprc = apr_pollset_create(&pollset, 2, pool(p), 0); + if (cprc != APR_SUCCESS) + return abort(conn, csock, http::apreason(cprc)); + const apr_pollfd_t* cpollfd = http::pollfd(csock, APR_POLLIN, p); + apr_pollset_add(pollset, cpollfd); + const apr_pollfd_t* tpollfd = http::pollfd(tsock, APR_POLLIN, p); + apr_pollset_add(pollset, tpollfd); + + // Relay traffic in both directions until end of stream + const apr_pollfd_t* pollfds = cpollfd; + apr_int32_t pollcount = 1; + for(;;) { + for (; pollcount > 0; pollcount--, pollfds++) { + if (pollfds->rtnevents & APR_POLLIN) { + if (pollfds->desc.s == csock) { + + // Receive buckets from client + const apr_status_t getrc = ap_get_brigade(conn->input_filters, ib, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); + if (getrc != APR_SUCCESS) + return abort(conn, csock, string("Couldn't receive from client")); + + for (apr_bucket* bucket = APR_BRIGADE_FIRST(ib); bucket != APR_BRIGADE_SENTINEL(ib); bucket = APR_BUCKET_NEXT(bucket)) { + if (APR_BUCKET_IS_FLUSH(bucket)) + continue; + + // Client connection closed + if (APR_BUCKET_IS_EOS(bucket)) + return close(conn, csock); + + const char *data; + apr_size_t rl; + apr_bucket_read(bucket, &data, &rl, APR_BLOCK_READ); + if (rl > 0) { + debug(string(data, rl), "modssltunnel::tunnel::sendToTarget"); + + // Send to target + const failable<bool> src = http::send(data, rl, cs); + if (!hasContent(src)) + return abort(conn, csock, string("Couldn't send to target: ") + reason(src)); + } + } + apr_brigade_cleanup(ib); + } else { + + // Receive from target + char data[8192]; + const failable<size_t> frl = http::recv(data, sizeof(data), cs); + if (!hasContent(frl)) + return abort(conn, csock, string("Couldn't receive from target") + reason(frl)); + const size_t rl = content(frl); + + // Target connection closed + if (rl == 0) + return close(conn, csock); + + + // Send bucket to client + debug(string(data, rl), "modssltunnel::tunnel::sendToClient"); + APR_BRIGADE_INSERT_TAIL(ob, apr_bucket_transient_create(data, rl, conn->bucket_alloc)); + APR_BRIGADE_INSERT_TAIL(ob, apr_bucket_flush_create(conn->bucket_alloc)); + if (ap_pass_brigade(ofilter, ob) != APR_SUCCESS) + return abort(conn, csock, "Couldn't send data bucket to client"); + apr_brigade_cleanup(ob); + } + } + + // Error + if (pollfds->rtnevents & (APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) { + if (pollfds->desc.s == csock) + return abort(conn, csock, "Couldn't receive from client"); + else + return abort(conn, csock, "Couldn't receive from target"); + } + } + + // Poll the client and target sockets + debug("modssltunnel::tunnel::poll"); + apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds); + if (pollrc != APR_SUCCESS) + return abort(conn, csock, "Couldn't poll sockets"); + debug(pollcount, "modssltunnel::tunnel::pollfds"); + } + + // Close client connection + return close(conn, csock); +} + +/** + * Return the first connection filter in a list of filters. + */ +ap_filter_t* connectionFilter(ap_filter_t* f) { + if (f == NULL) + return f; + if (f->frec->ftype < AP_FTYPE_CONNECTION) + return connectionFilter(f->next); + return f; +} + +/** + * Process a client connection and relay it to a tunnel. + */ +int processConnection(conn_rec *conn) { + // Only allow configured virtual hosts + if (!conn->base_server->is_virtual) + return DECLINED; + if (ap_get_module_config(conn->base_server->module_config, &mod_tuscany_ssltunnel) == NULL) + return DECLINED; + + gc_scoped_pool pool(conn->pool); + + // Get the server configuration + const ServerConf& sc = httpd::serverConf<ServerConf>(conn->base_server, &mod_tuscany_ssltunnel); + if (length(sc.pass) == 0) + return DECLINED; + debug(sc.pass, "modssltunnel::processConnection::pass"); + + // Run the tunnel + const string preamble = string("SSLTUNNEL ") + sc.path + string(" HTTP/1.1\r\nHost: ") + sc.host + string("\r\n\r\n"); + debug(preamble, "modssltunnel::processConnection::preamble"); + return tunnel(conn, sc.ca, sc.cert, sc.key, sc.pass, preamble, gc_pool(conn->pool), connectionFilter(conn->input_filters), connectionFilter(conn->output_filters)); +} + +/** + * Tunnel a SSLTUNNEL request to a target host/port. + */ +int handler(request_rec* r) { + if (r->method_number != M_SSLTUNNEL) + return DECLINED; + + // Only allow HTTPS + if (strcmp(r->server->server_scheme, "https")) + return DECLINED; + + gc_scoped_pool pool(r->pool); + + // Build the target URL + debug(r->uri, "modssltunnel::handler::uri"); + const list<value> path(pathValues(r->uri)); + const string url = string(cadr(path)) + ":" + caddr(path); + debug(url, "modssltunnel::handler::target"); + + // Run the tunnel + return tunnel(r->connection, "", "", "", url, "", gc_pool(r->pool), connectionFilter(r->proto_input_filters), connectionFilter(r->proto_output_filters)); +} + +/** + * Configuration commands. + */ +const char* confTunnelPass(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel); + sc.pass = arg; + return NULL; +} +const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel); + sc.ca = arg; + return NULL; +} +const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel); + sc.cert = arg; + return NULL; +} +const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel); + sc.key = arg; + return NULL; +} + +/** + * HTTP server module declaration. + */ +const command_rec commands[] = { + AP_INIT_TAKE1("TunnelPass", (const char*(*)())confTunnelPass, NULL, RSRC_CONF, "Tunnel server name"), + AP_INIT_TAKE1("TunnelSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "Tunnel SSL CA certificate file"), + AP_INIT_TAKE1("TunnelSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "Tunnel SSL certificate file"), + AP_INIT_TAKE1("TunnelSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "Tunnel SSL certificate key file"), + {NULL, NULL, NULL, 0, NO_ARGS, NULL} +}; + +void registerHooks(unused apr_pool_t *p) { + ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_process_connection(processConnection, NULL, NULL, APR_HOOK_MIDDLE); +} + +} +} +} + +extern "C" { + +module AP_MODULE_DECLARE_DATA mod_tuscany_ssltunnel = { + STANDARD20_MODULE_STUFF, + // dir config and merger + NULL, NULL, + // server config and merger + tuscany::httpd::makeServerConf<tuscany::httpd::modssltunnel::ServerConf>, NULL, + // commands and hooks + tuscany::httpd::modssltunnel::commands, tuscany::httpd::modssltunnel::registerHooks +}; + +} + +// Reenable cast align warnings +#ifdef WANT_MAINTAINER_WARNINGS +#pragma GCC diagnostic warning "-Wcast-align" +#endif + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/open-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/open-auth-conf new file mode 100755 index 0000000000..f4715b3a1c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/open-auth-conf @@ -0,0 +1,100 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD form authentication configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then + pw=`cat $root/cert/ca.key | head -2 | tail -1` +else + pw="$3" +fi + +# Configure HTTPD mod_tuscany_openauth module +cat >>$root/conf/modules.conf <<EOF +# Generated by: open-auth-conf $* +# Load support for Open authentication +LoadModule mod_tuscany_openauth $here/libmod_tuscany_openauth$libsuffix + +EOF + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: open-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate form authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: open-auth-conf $* +# Enable Tuscany open authentication +<Location /> +AuthType Open +AuthName "$host" +AuthOpenAuthProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +Session On +SessionCryptoPassphrase $pw +AuthOpenAuth On +AuthOpenAuthLoginPage /login/ +Require valid-user +</Location> + +# Use HTTPD form-based authentication +<Location /login/dologin> +AuthType Form +AuthName "$host" +AuthFormProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +AuthFormLoginRequiredLocation /login/?openauth_attempt=1 +AuthFormLogoutLocation / +Require valid-user +SetHandler form-login-handler +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/openauth.hpp b/sca-cpp/branches/lightweight-sca/modules/http/openauth.hpp new file mode 100644 index 0000000000..3ffa88d362 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/openauth.hpp @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_openauth_hpp +#define tuscany_openauth_hpp + +/** + * Tuscany Open auth support utility functions. + */ + +#include "string.hpp" +#include "stream.hpp" +#include "list.hpp" +#include "tree.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../json/json.hpp" +#include "../http/httpd.hpp" +#include "../http/http.hpp" + +namespace tuscany { +namespace openauth { + +/** + * Return the session id from a request. + */ +const char* cookieName(const char* cs) { + if (*cs != ' ') + return cs; + return cookieName(cs + 1); +} +const maybe<string> sessionID(const list<string>& c, const string& key) { + if (isNil(c)) + return maybe<string>(); + const string cn = cookieName(c_str(car(c))); + const size_t i = find(cn, "="); + if (i < length(cn)) { + const list<string> kv = mklist<string>(substr(cn, 0, i), substr(cn, i+1)); + if (!isNil(kv) && !isNil(cdr(kv))) { + if (car(kv) == key) + return cadr(kv); + } + } + return sessionID(cdr(c), key); +} + +const maybe<string> sessionID(const request_rec* r, const string& key) { + const string c = httpd::cookie(r); + debug(c, "openauth::sessionid::cookies"); + if (length(c) == 0) + return maybe<string>(); + return sessionID(tokenize(";", c), key); +} + +/** + * Convert a session id to a cookie string. + */ +const string cookie(const string& key, const string& sid, const string& domain) { + const time_t t = time(NULL) + 86400; + char exp[32]; + strftime(exp, 32, "%a, %d-%b-%Y %H:%M:%S GMT", gmtime(&t)); + const string c = key + string("=") + sid + "; expires=" + string(exp) + "; domain=." + httpd::realm(domain) + "; path=/"; + debug(c, "openauth::cookie"); + return c; +} + +/** + * Redirect to the configured login page. + */ +const failable<int> login(const string& page, const value& ref, const value& attempt, request_rec* r) { + const list<list<value> > rarg = ref == string("/")? list<list<value> >() : mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(isNil(ref)? r->uri : ref, r)))); + const list<list<value> > aarg = isNil(attempt)? list<list<value> >() : mklist<list<value> >(mklist<value>("openauth_attempt", attempt)); + const list<list<value> > largs = append<list<value> >(rarg, aarg); + const string loc = isNil(largs)? httpd::url(page, r) : httpd::url(page, r) + string("?") + http::queryString(largs); + debug(loc, "openauth::login::uri"); + return httpd::externalRedirect(loc, r); +} + +} +} + +#endif /* tuscany_openauth_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/http/passwd-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/passwd-auth-conf new file mode 100755 index 0000000000..718b96de0a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/passwd-auth-conf @@ -0,0 +1,31 @@ +#!/bin/sh + +# 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. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +user=$2 +pass=$3 + +httpd_prefix=`cat $here/httpd.prefix` + +# Create password file +touch $root/conf/httpd.passwd +$httpd_prefix/bin/htpasswd -b $root/conf/httpd.passwd "$user" "$pass" 2>/dev/null + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-balancer-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-balancer-conf new file mode 100755 index 0000000000..0b63c9e481 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-balancer-conf @@ -0,0 +1,50 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD proxy balancer configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +bal=$2 +if [ "$bal" = "" ]; then + bal="cluster" +fi +loc=$3 +if [ "$loc" = "" ]; then + loc="/" +fi + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-pass-conf $* +# Enable load balancing +ProxyPass $loc balancer://$bal/ + +<Proxy balancer://$bal> +Require all granted +ProxySet lbmethod=byrequests +</Proxy> + +<Location $loc> +RequestHeader set X-Forwarded-HTTPS %{HTTPS}s +RequestHeader set X-Forwarded-Port %{SERVER_PORT}s +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-base-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-base-conf new file mode 100755 index 0000000000..377175328d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-base-conf @@ -0,0 +1,48 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD proxy balancer configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-base-conf $* +# Do not proxy admin pages +ProxyPass /balancer-manager ! +ProxyPass /server-status ! +ProxyPass /proxy ! + +# Enable balancer manager +<Location /balancer-manager> +SetHandler balancer-manager +HostnameLookups on +</Location> + +EOF + +cat >>$root/conf/adminauth.conf <<EOF +# Generated by: proxy-base-conf $* +# Allow the server admin to manage the load balancer +<Location /balancer-manager> +Require user admin +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-conf new file mode 100755 index 0000000000..ce990bbfd3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-conf @@ -0,0 +1,60 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD proxy balancer configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-conf $* +# Do not proxy admin pages +ProxyPass /balancer-manager ! +ProxyPass /server-status ! +ProxyPass /proxy ! + +# Enable load balancing +ProxyPass / balancer://cluster/ +<Proxy balancer://cluster> +Require all granted +ProxySet lbmethod=byrequests +</Proxy> + +<Location /> +RequestHeader set X-Forwarded-HTTPS %{HTTPS}s +RequestHeader set X-Forwarded-Port %{SERVER_PORT}s +</Location> + +# Enable balancer manager +<Location /balancer-manager> +SetHandler balancer-manager +HostnameLookups on +</Location> + +EOF + +cat >>$root/conf/adminauth.conf <<EOF +# Generated by: proxy-conf $* +# Allow the server admin to manage the load balancer +<Location /balancer-manager> +Require user admin +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-member-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-member-conf new file mode 100755 index 0000000000..a046a4fd08 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-member-conf @@ -0,0 +1,45 @@ +#!/bin/sh + +# 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. + +# Add a proxy balancer member +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=`$here/httpd-addr port $3` +if [ "$port" = "80" ]; then + portsuffix="" +else + portsuffix=":$port" +fi + +bal=$4 +if [ "$bal" = "" ]; then + bal="cluster" +fi + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-member-conf $* +# Add proxy balancer member +BalancerMember balancer://$bal http://$host$portsuffix +ProxyPassReverse / http://$host$portsuffix/ + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-conf new file mode 100755 index 0000000000..ad7f26d83a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-conf @@ -0,0 +1,67 @@ +#!/bin/sh + +# 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. + +# Generate a minimal HTTPD proxy balancer configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: proxy-ssl-conf $* +# Do not proxy admin pages +ProxyPass /balancer-manager ! +ProxyPass /server-status ! +ProxyPass /proxy ! + +# Enable load balancing +ProxyPass / balancer://sslcluster/ +<Proxy balancer://sslcluster> +Require all granted +ProxySet lbmethod=byrequests +</Proxy> + +<Location /> +RequestHeader set X-Forwarded-HTTPS %{HTTPS}s +RequestHeader set X-Forwarded-Port %{SERVER_PORT}s +</Location> + +# Enable balancer manager +<Location /balancer-manager> +SetHandler balancer-manager +HostnameLookups on +</Location> + +EOF + +cat >>$root/conf/svhost-ssl.conf <<EOF +# Generated by: proxy-ssl-conf $* +# Declare proxy SSL client certificates +#SSLProxyCACertificateFile "$root/cert/ca.crt" +#SSLProxyMachineCertificateFile "$root/cert/proxy.pem" + +EOF + +cat >>$root/conf/dvhost-ssl.conf <<EOF +# Generated by: proxy-ssl-conf $* +# Declare proxy SSL client certificates +#SSLProxyCACertificateFile "$root/cert/ca.crt" +#SSLProxyMachineCertificateFile "$root/cert/proxy.pem" + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-member-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-member-conf new file mode 100755 index 0000000000..cb42a1e9db --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-member-conf @@ -0,0 +1,40 @@ +#!/bin/sh + +# 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. + +# Add a proxy balancer member +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +sslport=`$here/httpd-addr port $3` +if [ "$sslport" = "443" ]; then + sslportsuffix="" +else + sslportsuffix=":$sslport" +fi + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: proxy-ssl-member-conf $* +# Add proxy balancer member +BalancerMember balancer://sslcluster https://$host$sslportsuffix +ProxyPassReverse / https://$host$sslportsuffix/ + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-nossl-member-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-nossl-member-conf new file mode 100755 index 0000000000..17b766d986 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-nossl-member-conf @@ -0,0 +1,40 @@ +#!/bin/sh + +# 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. + +# Add a proxy balancer member +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=`$here/httpd-addr port $3` +if [ "$port" = "80" ]; then + portsuffix="" +else + portsuffix=":$port" +fi + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: proxy-ssl-nossl-member-conf $* +# Add proxy balancer member +BalancerMember balancer://sslcluster http://$host$portsuffix +ProxyPassReverse / http://$host$portsuffix/ + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-test b/sca-cpp/branches/lightweight-sca/modules/http/proxy-test new file mode 100755 index 0000000000..0333dd280b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-test @@ -0,0 +1,40 @@ +#!/bin/sh + +# 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. + +# Setup +rm -rf tmp +./httpd-conf tmp localhost 8091/8090 htdocs +./httpd-event-conf tmp +./httpd-start tmp +./httpd-conf tmp/proxy localhost 8090 tmp/proxy/htdocs +./httpd-event-conf tmp/proxy +./proxy-conf tmp/proxy +./proxy-member-conf tmp/proxy localhost 8091 +./httpd-start tmp/proxy +sleep 2 + +# Test +./curl-test 2>/dev/null +rc=$? + +# Cleanup +./httpd-stop tmp/proxy +./httpd-stop tmp +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/http/ssl-ca-conf b/sca-cpp/branches/lightweight-sca/modules/http/ssl-ca-conf new file mode 100755 index 0000000000..bceca8f300 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/ssl-ca-conf @@ -0,0 +1,96 @@ +#!/bin/sh + +# 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. + +# Generate a test certification authority certificate +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 + +# Don't override existing certificate +if [ -f $root/cert/ca.crt ]; then + exit 0 +fi + +# Generate openssl configuration +mkdir -p $root/cert +umask 0007 +cat >$root/cert/openssl-ca.conf <<EOF +[ req ] +default_bits = 1024 +encrypt_key = no +prompt = no +distinguished_name = req_distinguished_name +x509_extensions = v3_ca + +[ req_distinguished_name ] +C = US +ST = CA +L = San Francisco +O = $host +OU = authority +CN = $host +emailAddress = admin@$host + +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = CA:true + +[ca] +default_ca = ca_default + +[ca_default] +certificate = $root/cert/ca.crt +private_key = $root/cert/ca.key +serial = $root/cert/ca-serial +database = $root/cert/ca-database +new_certs_dir = $root/cert +default_md = sha1 +email_in_dn = no +default_days = 365 +default_crl_days = 30 +policy = policy_any +copy_extensions = none + +[ policy_any ] +countryName = supplied +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +EOF + +rm -rf $root/cert/*.crt $root/cert/*.pem $root/cert/hash +rm -f $root/cert/ca-database +echo 1000 > $root/cert/ca-serial +touch $root/cert/ca-database + +# Generate the certification authority certificate +openssl req -new -x509 -config $root/cert/openssl-ca.conf -out $root/cert/ca.crt -keyout $root/cert/ca.key + +# Add to the hash directory and rehash +mkdir -p $root/cert/hash +cp $root/cert/ca.crt $root/cert/hash +perl /usr/bin/c_rehash $root/cert/hash + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-conf b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-conf new file mode 100755 index 0000000000..9e785ec86e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-conf @@ -0,0 +1,76 @@ +#!/bin/sh + +# 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. + +# Generate a test certificate +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +if [ "$3" != "" ]; then + certname=$3 +else + certname="server" +fi + +# Don't regenerate the certificate if it already exists +if [ -f $root/cert/$certname.crt ]; then + exit 0 +fi + +# Generate openssl configuration +mkdir -p $root/cert +umask 0007 +cat >$root/cert/openssl-cert-$certname.conf <<EOF +[ req ] +default_bits = 1024 +encrypt_key = no +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = US +ST = CA +L = San Francisco +O = $host +OU = $certname +CN = $host +emailAddress = admin@$host +EOF + +# Generate a certificate request +openssl req -new -config $root/cert/openssl-cert-$certname.conf -out $root/cert/$certname-req.crt -keyout $root/cert/$certname.key + +# Generate a certificate, signed with our test certification authority certificate +openssl ca -batch -config $root/cert/openssl-ca.conf -out $root/cert/$certname.crt -infiles $root/cert/$certname-req.crt + +# Export it to PKCS12 format, that's the format Web browsers want to import +openssl pkcs12 -export -passout pass: -out $root/cert/$certname.p12 -inkey $root/cert/$certname.key -in $root/cert/$certname.crt -certfile $root/cert/ca.crt + +# Convert the certificate to PEM format and concatenate the key to it, for use +# by mod_proxy +openssl x509 -in $root/cert/$certname.crt -out $root/cert/$certname.pem +cat $root/cert/$certname.key >> $root/cert/$certname.pem + +# Add to the hash directory and rehash +mkdir -p $root/cert/hash +cp $root/cert/$certname.crt $root/cert/hash +cp $root/cert/$certname.pem $root/cert/hash +perl /usr/bin/c_rehash $root/cert/hash + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-find b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-find new file mode 100755 index 0000000000..7a4b4f0220 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-find @@ -0,0 +1,30 @@ +#!/bin/sh + +# 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. + +# List certificate files, useful to distribute them to another host +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +cd $root +find . -name "*.crt" +find . -name "*.pem" +find . -name "*.p12" +find . -name "*.key" +find . -name "*.0" + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/tunnel-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/tunnel-ssl-conf new file mode 100755 index 0000000000..021d205ed9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/tunnel-ssl-conf @@ -0,0 +1,55 @@ +#!/bin/sh + +# 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. + +# Generate an SSL tunnel configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +port=`$here/httpd-addr port $2` +sslhost=$3 +sslport=$4 +tport=$5 + +# Generate HTTPD configuration +cat >>$root/conf/httpd.conf <<EOF +# Generated by: tunnel-ssl-conf $* +# Tunnel TCP/IP traffic over HTTPS + +# Listen on local port +Listen 127.0.0.1:$port + +# Tunnel virtual host +<VirtualHost 127.0.0.1:$port> +ServerName http://localhost:$port + +TunnelPass https://$sslhost:$sslport/tunnel/localhost/$tport + +# Declare SSL certificates used in this virtual host +#TunnelSSLCACertificateFile "$root/cert/ca.crt" +TunnelSSLCertificateFile "$root/cert/tunnel.crt" +TunnelSSLCertificateKeyFile "$root/cert/tunnel.key" + +</VirtualHost> + +EOF + |