tuscany-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jsdelf...@apache.org
Subject svn commit: r1419987 [1/5] - in /tuscany/sca-cpp/trunk/modules: http/ java/ oauth/ opencl/ python/ server/ server/htdocs/test/ wsgi/
Date Tue, 11 Dec 2012 04:03:35 GMT
Author: jsdelfino
Date: Tue Dec 11 04:03:29 2012
New Revision: 1419987

URL: http://svn.apache.org/viewvc?rev=1419987&view=rev
Log:
More changes to port to C++11, adjust to use the new JSON support, and cleanup rest of the modules.

Added:
    tuscany/sca-cpp/trunk/modules/http/httpd-callgrind
      - copied, changed from r1419986, tuscany/sca-cpp/trunk/modules/server/server-conf
Modified:
    tuscany/sca-cpp/trunk/modules/http/Makefile.am
    tuscany/sca-cpp/trunk/modules/http/curl-connect.cpp
    tuscany/sca-cpp/trunk/modules/http/curl-get.cpp
    tuscany/sca-cpp/trunk/modules/http/curl-test.cpp
    tuscany/sca-cpp/trunk/modules/http/http.hpp
    tuscany/sca-cpp/trunk/modules/http/httpd.hpp
    tuscany/sca-cpp/trunk/modules/http/mod-openauth.cpp
    tuscany/sca-cpp/trunk/modules/http/mod-ssltunnel.cpp
    tuscany/sca-cpp/trunk/modules/http/openauth.hpp
    tuscany/sca-cpp/trunk/modules/java/Makefile.am
    tuscany/sca-cpp/trunk/modules/java/driver.hpp
    tuscany/sca-cpp/trunk/modules/java/eval.hpp
    tuscany/sca-cpp/trunk/modules/java/java-shell.cpp
    tuscany/sca-cpp/trunk/modules/java/java-test.cpp
    tuscany/sca-cpp/trunk/modules/java/jni-test.cpp
    tuscany/sca-cpp/trunk/modules/java/mod-java.cpp
    tuscany/sca-cpp/trunk/modules/java/mod-java.hpp
    tuscany/sca-cpp/trunk/modules/oauth/Makefile.am
    tuscany/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp
    tuscany/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp
    tuscany/sca-cpp/trunk/modules/opencl/Makefile.am
    tuscany/sca-cpp/trunk/modules/opencl/driver.hpp
    tuscany/sca-cpp/trunk/modules/opencl/eval.hpp
    tuscany/sca-cpp/trunk/modules/opencl/opencl-shell.cpp
    tuscany/sca-cpp/trunk/modules/opencl/opencl-test.cpp
    tuscany/sca-cpp/trunk/modules/python/Makefile.am
    tuscany/sca-cpp/trunk/modules/python/driver.hpp
    tuscany/sca-cpp/trunk/modules/python/eval.hpp
    tuscany/sca-cpp/trunk/modules/python/mod-python.cpp
    tuscany/sca-cpp/trunk/modules/python/mod-python.hpp
    tuscany/sca-cpp/trunk/modules/python/python-shell.cpp
    tuscany/sca-cpp/trunk/modules/python/python-test.cpp
    tuscany/sca-cpp/trunk/modules/server/Makefile.am
    tuscany/sca-cpp/trunk/modules/server/client-test.hpp
    tuscany/sca-cpp/trunk/modules/server/htdocs/test/entry.xml
    tuscany/sca-cpp/trunk/modules/server/htdocs/test/feed.xml
    tuscany/sca-cpp/trunk/modules/server/htdocs/test/json-properties.txt
    tuscany/sca-cpp/trunk/modules/server/htdocs/test/json-result.txt
    tuscany/sca-cpp/trunk/modules/server/impl-test.cpp
    tuscany/sca-cpp/trunk/modules/server/mod-cpp.hpp
    tuscany/sca-cpp/trunk/modules/server/mod-eval.cpp
    tuscany/sca-cpp/trunk/modules/server/mod-eval.hpp
    tuscany/sca-cpp/trunk/modules/server/mod-scheme.hpp
    tuscany/sca-cpp/trunk/modules/server/server-conf
    tuscany/sca-cpp/trunk/modules/wsgi/Makefile.am
    tuscany/sca-cpp/trunk/modules/wsgi/client-test.cpp

Modified: tuscany/sca-cpp/trunk/modules/http/Makefile.am
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/Makefile.am?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/Makefile.am (original)
+++ tuscany/sca-cpp/trunk/modules/http/Makefile.am Tue Dec 11 04:03:29 2012
@@ -20,28 +20,28 @@ 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
+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 base64-encode 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_test_LDFLAGS = -lxml2 -lcurl -ljansson
 
 curl_get_SOURCES = curl-get.cpp
-curl_get_LDFLAGS = -lxml2 -lcurl -lmozjs
+curl_get_LDFLAGS = -lxml2 -lcurl -ljansson
 
 curl_connect_SOURCES = curl-connect.cpp
-curl_connect_LDFLAGS = -lxml2 -lcurl -lmozjs
+curl_connect_LDFLAGS = -lxml2 -lcurl -ljansson
 
 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_la_LDFLAGS = -lxml2 -lcurl -ljansson
 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_la_LDFLAGS = -lxml2 -lcurl -ljansson
 libmod_tuscany_openauth${libsuffix}:
 	ln -s .libs/libmod_tuscany_openauth${libsuffix}
 
@@ -82,7 +82,7 @@ modsecuritydir = $(prefix)/modules/http
 
 endif
 
-dist_noinst_SCRIPTS = httpd-test http-test proxy-test
+dist_noinst_SCRIPTS = httpd-test http-test proxy-test httpd-memgrind httpd-callgrind
 noinst_PROGRAMS = curl-test curl-get curl-connect
 TESTS = httpd-test http-test proxy-test
 

Modified: tuscany/sca-cpp/trunk/modules/http/curl-connect.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/curl-connect.cpp?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/curl-connect.cpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/curl-connect.cpp Tue Dec 11 04:03:29 2012
@@ -34,14 +34,14 @@ namespace tuscany {
 namespace http {
 
 const bool testConnect(const string& url, const string& ca = "", const string& cert = "", const string& key = "") {
-    gc_scoped_pool p;
+    const gc_scoped_pool p;
 
-    CURLSession cs(ca, cert, key, "", 0);
+    const 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);
+    const 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);
@@ -53,7 +53,7 @@ const bool testConnect(const string& url
     const apr_pollfd_t* pollfds;
     apr_int32_t pollcount;
     for(;;) {
-        apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds);
+        const apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds);
         assert(pollrc == APR_SUCCESS);
 
         for (; pollcount > 0; pollcount--, pollfds++) {
@@ -88,7 +88,7 @@ const bool testConnect(const string& url
 }
 }
 
-int main(unused const int argc, const char** argv) {
+int main(unused const int argc, const char** const argv) {
     if (argc > 2)
         tuscany::http::testConnect(tuscany::string(argv[1]), tuscany::string(argv[2]), tuscany::string(argv[3]), tuscany::string(argv[4]));
     else

Modified: tuscany/sca-cpp/trunk/modules/http/curl-get.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/curl-get.cpp?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/curl-get.cpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/curl-get.cpp Tue Dec 11 04:03:29 2012
@@ -33,7 +33,7 @@ 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 CURLSession ch(ca, cert, key, "", 0);
     const failable<value> val = get(url, ch);
     assert(hasContent(val));
     cout << content(val) << endl;
@@ -43,7 +43,7 @@ const bool testGet(const string& url, co
 }
 }
 
-int main(unused const int argc, const char** argv) {
+int main(unused const int argc, const char** const argv) {
     if (argc > 2)
         tuscany::http::testGet(tuscany::string(argv[1]), tuscany::string(argv[2]), tuscany::string(argv[3]), tuscany::string(argv[4]));
     else

Modified: tuscany/sca-cpp/trunk/modules/http/curl-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/curl-test.cpp?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/curl-test.cpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/curl-test.cpp Tue Dec 11 04:03:29 2012
@@ -40,7 +40,7 @@ ostream* curlWriter(const string& s, ost
 }
 
 const bool testGet() {
-    CURLSession ch("", "", "", "", 0);
+    const CURLSession ch("", "", "", "", 0);
     {
         ostringstream os;
         const failable<list<ostream*> > r = get<ostream*>(curlWriter, &os, testURI, ch);
@@ -56,21 +56,14 @@ const bool testGet() {
     return true;
 }
 
-struct getLoop {
-    CURLSession& ch;
-    getLoop(CURLSession& ch) : ch(ch) {
-    }
-    const bool operator()() const {
+const bool testGetPerf() {
+    const CURLSession ch("", "", "", "", 0);
+    blambda gl = [ch]() -> const bool {
         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;
 }
@@ -79,7 +72,7 @@ const bool testGetPerf() {
 }
 
 int main() {
-    tuscany::gc_scoped_pool p;
+    const tuscany::gc_scoped_pool p;
     tuscany::cout << "Testing..." << tuscany::endl;
     //tuscany::http::testURI = tuscany::string("http://") + tuscany::http::hostName() + ":8090";
 

Modified: tuscany/sca-cpp/trunk/modules/http/http.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/http.hpp?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/http.hpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/http.hpp Tue Dec 11 04:03:29 2012
@@ -71,86 +71,91 @@ public:
  */
 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() : p(), h(*(new (gc_new<handles>()) handles())), owner(false), ca(emptyString), cert(emptyString), key(emptyString), cookie(emptyString), 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 string& ca, const string& cert, const string& key, const string& cookie, const int timeout) : p(), h(*(new (gc_new<handles>()) handles())), 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) {
+    CURLSession(const CURLSession& c) : p(c.p), h(c.h), 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& operator=(const CURLSession& c) = delete;
 
     ~CURLSession() {
         if (!owner)
             return;
-        if (h == NULL)
+        if (h.h == NULL)
             return;
-        curl_easy_cleanup(h);
+        debug(h.h, "http::~CURLSession::cleanup::h");
+        curl_easy_cleanup(h.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);
+    class handles {
+    public:
+        handles() : h(NULL), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL) {
+        }
+
+        handles(const handles& c) : h(c.h), sock(c.sock), wpollset(c.wpollset), wpollfd(c.wpollfd), rpollset(c.rpollset), rpollfd(c.rpollfd) {
+        }
+
+    private:
+        CURL* h;
+        apr_socket_t* sock;
+        apr_pollset_t* wpollset;
+        apr_pollfd_t* wpollfd;
+        apr_pollset_t* rpollset;
+        apr_pollfd_t* rpollfd;
+
+        friend class CURLSession;
+        friend CURL* const handle(const CURLSession& cs);
+        friend apr_socket_t* const sock(const CURLSession& cs);
+        friend const failable<CURL*> setup(const string& url, const CURLSession& cs);
+        friend const failable<bool> cleanup(const CURLSession& cs);
+        friend const failable<bool> connect(const string& url, const CURLSession& cs);
+        friend const failable<bool> send(const char* const c, const size_t l, const CURLSession& cs);
+        friend const failable<size_t> recv(char* const c, const size_t l, const CURLSession& cs);
+    };
+
+    const gc_child_pool p;
+    handles& h;
+    const bool owner;
+
+    friend CURL* const handle(const CURLSession& cs);
+    friend apr_socket_t* const sock(const CURLSession& cs);
+    friend const failable<CURL*> setup(const string& url, const CURLSession& cs);
+    friend const failable<bool> cleanup(const CURLSession& cs);
+    friend const failable<bool> connect(const string& url, const CURLSession& cs);
+    friend const failable<bool> send(const char* const c, const size_t l, const CURLSession& cs);
+    friend const failable<size_t> recv(char* const c, const size_t l, const CURLSession& cs);
 
 public:
-    string ca;
-    string cert;
-    string key;
-    string cookie;
-    int timeout;
+    const string ca;
+    const string cert;
+    const string key;
+    const string cookie;
+    const int timeout;
 };
 
 /**
  * Returns the CURL handle used by a CURL session.
  */
-CURL* handle(const CURLSession& cs) {
-    return cs.h;
+CURL* const handle(const CURLSession& cs) {
+    return cs.h.h;
 }
 
 /**
  * Return an apr_socket_t for the socket used by a CURL session.
  */
-apr_socket_t* sock(const CURLSession& cs) {
-    return cs.sock;
+apr_socket_t* const sock(const CURLSession& cs) {
+    return cs.h.sock;
 }
 
 /**
  * Convert a socket fd to an apr_socket_t.
  */
-apr_socket_t* sock(const int sd, const gc_pool& p) {
+apr_socket_t* const sock(const int sd, const gc_pool& p) {
     int fd = sd;
     apr_socket_t* s = NULL;
     apr_os_sock_put(&s, &fd, pool(p));
@@ -160,14 +165,14 @@ apr_socket_t* sock(const int sd, const g
 /**
  * Convert a CURL return code to an error string.
  */
-const string curlreason(CURLcode rc) {
+const string curlreason(const CURLcode rc) {
     return curl_easy_strerror(rc);
 }
 
 /**
  * Convert an APR status to an error string.
  */
-const string apreason(apr_status_t rc) {
+const string apreason(const apr_status_t rc) {
     char buf[256];
     return apr_strerror(rc, buf, sizeof(buf));
 }
@@ -178,7 +183,7 @@ const string apreason(apr_status_t rc) {
 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);
+    char* const 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;
@@ -225,9 +230,9 @@ const string hostName(const string& uri,
     apr_uri_t u;
     const apr_status_t rc = apr_uri_parse(pool(p), c_str(uri), &u);
     if (rc != APR_SUCCESS)
-        return "";
+        return emptyString;
     if (u.hostname == NULL)
-        return "";
+        return emptyString;
     return u.hostname;
 }
 
@@ -238,9 +243,9 @@ const string scheme(const string& uri, c
     apr_uri_t u;
     const apr_status_t rc = apr_uri_parse(pool(p), c_str(uri), &u);
     if (rc != APR_SUCCESS)
-        return "";
+        return emptyString;
     if (u.scheme == NULL)
-        return "";
+        return emptyString;
     return u.scheme;
 }
 
@@ -262,13 +267,14 @@ const string topDomain(const string& hos
 /**
  * Setup a CURL session
  */
-const failable<CURL*> setup(const string& url, CURLSession& cs) {
+const failable<CURL*> setup(const string& url, const CURLSession& cs) {
 
     // Init CURL session
-    if (cs.h != NULL)
+    if (cs.h.h != NULL)
         cleanup(cs);
-    cs.h = curl_easy_init();
-    CURL* ch = cs.h;
+    cs.h.h = curl_easy_init();
+    debug(cs.h.h, "http::setup::init::h");
+    CURL* const ch = cs.h.h;
     curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0");
 #ifdef WANT_MAINTAINER_CURL_VERBOSE
     curl_easy_setopt(ch, CURLOPT_VERBOSE, true);
@@ -279,34 +285,35 @@ const failable<CURL*> setup(const string
     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_DNS_USE_GLOBAL_CACHE, 0);
     curl_easy_setopt(ch, CURLOPT_TIMEOUT, cs.timeout);
 
     // Setup SSL options
-    if (cs.ca != "") {
+    if (cs.ca != emptyString) {
         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 != "") {
+    if (cs.cert != emptyString) {
         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 != "") {
+    if (cs.key != emptyString) {
         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 != "") {
+    if (cs.cookie != emptyString) {
         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();
+    apr_pool_t* const 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) {
@@ -336,11 +343,12 @@ const failable<CURL*> setup(const string
 /**
  * Cleanup a CURL session
  */
-const failable<bool> cleanup(CURLSession& cs) {
-    if (cs.h == NULL)
+const failable<bool> cleanup(const CURLSession& cs) {
+    if (cs.h.h == NULL)
         return true;
-    curl_easy_cleanup(cs.h);
-    cs.h = NULL;
+    debug(cs.h.h, "http::cleanup::cleanup::h");
+    curl_easy_cleanup(cs.h.h);
+    cs.h.h = NULL;
     return true;
 }
 
@@ -351,15 +359,16 @@ class CURLReadContext {
 public:
     CURLReadContext(const list<string>& ilist) : ilist(ilist) {
     }
-    list<string> ilist;
+
+    gc_mutable_ref<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))
+    CURLReadContext& rcx = *(CURLReadContext*)data;
+    if (isNil((const list<string>)rcx.ilist))
         return 0;
     const list<string> f(fragment(rcx.ilist, size * nmemb));
     const string s = car(f);
@@ -373,17 +382,18 @@ size_t readCallback(void *ptr, size_t si
  */
 template<typename R> class CURLWriteContext {
 public:
-    CURLWriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
+    CURLWriteContext(const lambda<const R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
     }
-    const lambda<R(const string&, const R)> reduce;
-    R accum;
+
+    const lambda<const R(const string&, const R)> reduce;
+    gc_mutable_ref<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));
+    CURLWriteContext<R>& wcx = *(CURLWriteContext<R>*)data;
     const size_t realsize = size * nmemb;
     wcx.accum = wcx.reduce(string((const char*)ptr, realsize), wcx.accum);
     return realsize;
@@ -393,13 +403,13 @@ template<typename R> size_t writeCallbac
  * 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) {
+curl_slist* headers(curl_slist* const 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) {
+template<typename R> const failable<list<R> > apply(const list<list<string> >& hdr, const lambda<const R(const string&, const R)>& reduce, const R& initial, const string& url, const string& verb, const CURLSession& cs) {
     debug(url, "http::apply::url");
     debug(verb, "http::apply::verb");
 
@@ -409,12 +419,12 @@ template<typename R> const failable<list
         cleanup(cs);
         return mkfailure<list<R>>(fch);
     }
-    CURL* ch = content(fch);
+    CURL* const ch = content(fch);
 
     // Set the request headers
     curl_slist* hl = headers(NULL, car(hdr));
-    if (hl != NULL)
-        curl_easy_setopt(ch, CURLOPT_HTTPHEADER, hl);
+    hl = curl_slist_append(hl, "X-Accept: text/x-scheme; charset=utf-8");
+    curl_easy_setopt(ch, CURLOPT_HTTPHEADER, hl);
 
     // Convert request body to a string
     // TODO use HTTP chunking instead
@@ -462,9 +472,7 @@ template<typename R> const failable<list
     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));
+        return mkfailure<list<R> >(string("HTTP code not 200"), (int)httprc, (httprc != 301 && httprc != 302 && httprc != 404));
     }
 
     cleanup(cs);
@@ -474,13 +482,12 @@ template<typename R> const failable<list
 /**
  * Evaluate an expression remotely, at the given URL.
  */
-const failable<value> evalExpr(const value& expr, const string& url, CURLSession& cs) {
+const failable<value> evalExpr(const value& expr, const string& url, const 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);
+    const failable<list<string> > jsreq = json::jsonRequest(1, car<value>(expr), cdr<value>(expr));
     if (!hasContent(jsreq))
         return mkfailure<value>(jsreq);
 
@@ -491,7 +498,7 @@ const failable<value> evalExpr(const val
         return mkfailure<value>(res);
 
     // Parse and return JSON-RPC result
-    const failable<value> rval = json::jsonResultValue(cadr<list<string> >(content(res)), cx);
+    const failable<value> rval = json::jsonResultValue(cadr<list<string> >(content(res)));
     debug(rval, "http::evalExpr::result");
     if (!hasContent(rval))
         return mkfailure<value>(rval);
@@ -501,7 +508,7 @@ const failable<value> evalExpr(const val
 /**
  * Find and return a header.
  */
-const maybe<string> header(const char* prefix, const list<string>& h) {
+const maybe<string> header(const char* const prefix, const list<string>& h) {
     if (isNil(h))
         return maybe<string>();
     const string s = car(h);
@@ -516,7 +523,7 @@ const maybe<string> header(const char* p
  */
 const string location(const list<string>& h) {
     const maybe<string> l = header("Location: ", h);
-    return hasContent(l)? content(l) : "";
+    return hasContent(l)? content(l) : emptyString;
 }
 
 /**
@@ -524,7 +531,7 @@ const string location(const list<string>
  */
 const value entryId(const failable<string> l) {
     if (!hasContent(l))
-        return list<value>();
+        return nilListValue;
     const string ls(content(l));
     return value(mklist<value>(string(substr(ls, find_last(ls, '/') + 1))));
 }
@@ -534,13 +541,13 @@ const value entryId(const failable<strin
  */
 const string contentType(const list<string>& h) {
     const maybe<string> ct = header("Content-Type: ", h);
-    return hasContent(ct)? content(ct) : "";
+    return hasContent(ct)? content(ct) : emptyString;
 }
 
 /**
  * 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) {
+template<typename R> const failable<list<R> > get(const lambda<const R(const string&, const R)>& reduce, const R& initial, const string& url, const 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);
@@ -549,7 +556,7 @@ template<typename R> const failable<list
 /**
  * HTTP GET, return a list of values representing the resource at the given URL.
  */
-const failable<value> getcontent(const string& url, CURLSession& cs) {
+const failable<value> getcontent(const string& url, const CURLSession& cs) {
     debug(url, "http::get::url");
 
     // Get the contents of the resource at the given URL
@@ -576,6 +583,15 @@ const failable<value> responseValue(cons
     const list<string> ls(reverse(cadr(res)));
     debug(ls, "http::responseValue::content");
 
+    if (contains(ct, "text/x-scheme")) {
+        // Read a Scheme value
+        ostringstream os;
+        write(ls, os);
+        istringstream is(str(os));
+        const value val(content(scheme::readValue(is)));
+        debug(val, "http::responseValue::result");
+        return val;
+    }
     if (atom::isATOMEntry(ls)) {
         // Read an ATOM entry
         const value val(elementsToValues(content(atom::readATOMEntry(ls))));
@@ -596,8 +612,7 @@ const failable<value> responseValue(cons
     }
     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))));
+        const value val(content(json::readValue(ls)));
         debug(val, "http::responseValue::result");
         return val;
     }
@@ -612,14 +627,13 @@ const failable<value> responseValue(cons
         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))));
+        const value val(content(json::readValue(jls)));
         debug(val, "http::responseValue::result");
         return val;
     }
-    if (contains(ct, "text/xml") || contains(ct, "application/xml") || isXML(ls)) {
+    if (contains(ct, "text/xml") || contains(ct, "application/xml") || xml::isXML(ls)) {
         // Read an XML document
-        const value val(elementsToValues(readXML(ls)));
+        const value val(elementsToValues(content(xml::readElements(ls))));
         debug(val, "http::responseValue::result");
         return val;
     }
@@ -633,7 +647,7 @@ const failable<value> responseValue(cons
 /**
  * HTTP GET, return a list of values representing the resource at the given URL.
  */
-const failable<value> get(const string& url, CURLSession& cs) {
+const failable<value> get(const string& url, const CURLSession& cs) {
     debug(url, "http::get::url");
 
     // Get the contents of the resource at the given URL
@@ -661,58 +675,41 @@ const failable<list<list<string> > > wri
  */
 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 in the format requested by the client, if any
+    const list<value> fmt = assoc<value>("format", nilListValue);
+    if (!isNil(fmt)) {
+        if (cadr(fmt) == "scheme")
+            return writeRequest(scheme::writeValue(c), "text/x-scheme; charset=utf-8");
+        if (cadr(fmt) == "json")
+            return writeRequest(json::writeValue(c), "application/json; charset=utf-8");
+        if (cadr(fmt) == "xml")
+            return writeRequest(xml::writeElements(valuesToElements(c)), "text/xml; 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");
+        debug(c, "http::contentRequest::value");
+        return writeRequest(json::writeValue(c), "application/json; charset=utf-8");
     }
 
-    // Write an empty list as a JSON empty value
+    // Write an empty list as a JSON 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");
+        debug(nilListValue, "http::contentRequest::empty");
+        return writeRequest(json::writeValue(c), "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
+    // Write an assoc value as a JSON value
     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");
+        debug(c, "http::contentRequest::assoc");
+        return writeRequest(json::writeValue(c), "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
+    const list<value> e = valuesToElements(c);
     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)) {
@@ -724,14 +721,13 @@ const failable<list<list<string> > > con
     }
 
     // Write any other compound value as a JSON value
-    js::JSContext cx;
-    return writeRequest(json::writeJSON(e, cx), "application/json; charset=utf-8");
+    return writeRequest(json::writeValue(c), "application/json; charset=utf-8");
 }
 
 /**
  * HTTP POST.
  */
-const failable<value> post(const value& val, const string& url, CURLSession& cs) {
+const failable<value> post(const value& val, const string& url, const CURLSession& cs) {
     debug(url, "http::post::url");
 
     // Convert value to a content request
@@ -760,7 +756,7 @@ const failable<value> post(const value& 
 /**
  * HTTP PUT.
  */
-const failable<value> put(const value& val, const string& url, CURLSession& cs) {
+const failable<value> put(const value& val, const string& url, const CURLSession& cs) {
     debug(url, "http::put::url");
 
     // Convert value to a content request
@@ -775,13 +771,13 @@ const failable<value> put(const value& v
         return mkfailure<value>(res);
 
     debug(true, "http::put::result");
-    return value(true);
+    return trueValue;
 }
 
 /**
  * HTTP PATCH.
  */
-const failable<value> patch(const value& val, const string& url, CURLSession& cs) {
+const failable<value> patch(const value& val, const string& url, const CURLSession& cs) {
     debug(url, "http::put::patch");
 
     // Convert value to a content request
@@ -796,13 +792,13 @@ const failable<value> patch(const value&
         return mkfailure<value>(res);
 
     debug(true, "http::patch::result");
-    return value(true);
+    return trueValue;
 }
 
 /**
  * HTTP DELETE.
  */
-const failable<value, string> del(const string& url, CURLSession& cs) {
+const failable<value, string> del(const string& url, const CURLSession& cs) {
     debug(url, "http::delete::url");
 
     const list<list<string> > req = mklist(list<string>(), list<string>());
@@ -811,7 +807,7 @@ const failable<value, string> del(const 
         return mkfailure<value>(res);
 
     debug(true, "http::delete::result");
-    return value(true);
+    return trueValue;
 }
 
 /**
@@ -827,7 +823,7 @@ const string hostName() {
 /**
  * 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* const pollfd(apr_socket_t* const 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;
@@ -841,7 +837,7 @@ apr_pollfd_t* pollfd(apr_socket_t* s, co
 /**
  * Connect to a URL.
  */
-const failable<bool> connect(const string& url, CURLSession& cs) {
+const failable<bool> connect(const string& url, const CURLSession& cs) {
     debug(url, "http::connect::url");
 
     // Setup the CURL session
@@ -850,7 +846,7 @@ const failable<bool> connect(const strin
         cleanup(cs);
         return mkfailure<bool>(fch);
     }
-    CURL* ch = content(fch);
+    CURL* const ch = content(fch);
 
     // Connect
     curl_easy_setopt(ch, CURLOPT_CONNECT_ONLY, true);
@@ -867,23 +863,23 @@ const failable<bool> connect(const strin
         cleanup(cs);
         return mkfailure<bool>(string(curl_easy_strerror(grc)));
     }
-    cs.sock = sock(sd, cs.p);
+    cs.h.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);
+    const apr_status_t rpcrc = apr_pollset_create(&cs.h.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);
+    cs.h.rpollfd = pollfd(cs.h.sock, APR_POLLIN, cs.p);
+    apr_pollset_add(cs.h.rpollset, cs.h.rpollfd);
+    const apr_status_t wpcrc = apr_pollset_create(&cs.h.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);
+    cs.h.wpollfd = pollfd(cs.h.sock, APR_POLLOUT, cs.p);
+    apr_pollset_add(cs.h.wpollset, cs.h.wpollfd);
 
     return true;
 }
@@ -891,11 +887,11 @@ const failable<bool> connect(const strin
 /**
  * Send an array of chars.
  */
-const failable<bool> send(const char* c, const size_t l, CURLSession& cs) {
+const failable<bool> send(const char* const c, const size_t l, const CURLSession& cs) {
 
     // Send the data
     size_t wl = 0;
-    const CURLcode rc = curl_easy_send(cs.h, c, (size_t)l, &wl);
+    const CURLcode rc = curl_easy_send(cs.h.h, c, (size_t)l, &wl);
     if (rc == CURLE_OK && wl == (size_t)l)
         return true;
     if (rc != CURLE_AGAIN) {
@@ -906,7 +902,7 @@ const failable<bool> send(const char* c,
     // 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);
+    const apr_status_t pollrc = apr_pollset_poll(cs.h.wpollset, -1, &pollcount, &pollfds);
     if (pollrc != APR_SUCCESS)
         return mkfailure<bool>(apreason(pollrc));
 
@@ -917,11 +913,11 @@ const failable<bool> send(const char* c,
 /**
  * Receive an array of chars.
  */
-const failable<size_t> recv(char* c, const size_t l, CURLSession& cs) {
+const failable<size_t> recv(char* const c, const size_t l, const CURLSession& cs) {
 
     // Receive data
     size_t rl;
-    const CURLcode rc = curl_easy_recv(cs.h, c, (size_t)l, &rl);
+    const CURLcode rc = curl_easy_recv(cs.h.h, c, (size_t)l, &rl);
     if (rc == CURLE_OK)
         return (size_t)rl;
     if (rc == 1)
@@ -934,7 +930,7 @@ const failable<size_t> recv(char* c, con
     // 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);
+    const apr_status_t pollrc = apr_pollset_poll(cs.h.rpollset, -1, &pollcount, &pollfds);
     if (pollrc != APR_SUCCESS) {
         cleanup(cs);
         return mkfailure<size_t>(apreason(pollrc));
@@ -990,8 +986,9 @@ const value escapeQuery(const 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))) {
+class proxy {
+public:
+    proxy(const string& uri, const string& ca, const string& cert, const string& key, const string& cookie, const int timeout) : uri(uri), cs(mksession(ca, cert, key, cookie, timeout)) {
     }
     
     const value operator()(const list<value>& args) const {
@@ -1001,39 +998,44 @@ struct proxy {
             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);
+            debug(lq, "http::proxy::query");
             const value q = queryString(lq);
-            const failable<value> val = get(uri + p + (q != ""? string("?") + q : string("")), cs);
+            const failable<value> val = get(uri + (string)path(lp) + (q != emptyString? string("?") + (string)q : emptyString), *cs);
             return content(val);
         }
         if (fun == "post") {
-            const failable<value> val = post(caddr(args), uri + path(cadr(args)), cs);
+            const failable<value> val = post(caddr(args), uri + (string)path(cadr(args)), *cs);
             return content(val);
         }
         if (fun == "put") {
-            const failable<value> val = put(caddr(args), uri + path(cadr(args)), cs);
+            const failable<value> val = put(caddr(args), uri + (string)path(cadr(args)), *cs);
             return content(val);
         }
         if (fun == "patch") {
-            const failable<value> val = patch(caddr(args), uri + path(cadr(args)), cs);
+            const failable<value> val = patch(caddr(args), uri + (string)path(cadr(args)), *cs);
             return content(val);
         }
         if (fun == "delete") {
-            const failable<value> val = del(uri + path(cadr(args)), cs);
+            const failable<value> val = del(uri + (string)path(cadr(args)), *cs);
             return content(val);
         }
-        const failable<value> val = evalExpr(args, uri, cs);
+        const failable<value> val = evalExpr(args, uri, *cs);
         return content(val);
     }
 
-    const gc_pool p;
+private:
     const string uri;
-    const string ca;
-    const string cert;
-    const string key;
-    const string cookie;
-    CURLSession& cs;
+    const perthread_ptr<http::CURLSession> cs;
+
+    
+    const perthread_ptr<http::CURLSession> mksession(const string& ca, const string& cert, const string& key, const string& cookie, const int timeout) {
+        const gc_pool cp = gc_current_pool();
+        const lambda<const gc_ptr<http::CURLSession>()> newsession = [ca, cert, key, cookie, timeout, cp]() -> const gc_ptr<http::CURLSession> {
+            const gc_scoped_pool sp(pool(cp));
+            return new (gc_new<http::CURLSession>()) http::CURLSession(ca, cert, key, cookie, timeout);
+        };
+        return *(new (gc_new<perthread_ptr<http::CURLSession> >()) perthread_ptr<CURLSession>(newsession));
+    }
 };
 
 }

Copied: tuscany/sca-cpp/trunk/modules/http/httpd-callgrind (from r1419986, tuscany/sca-cpp/trunk/modules/server/server-conf)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/httpd-callgrind?p2=tuscany/sca-cpp/trunk/modules/http/httpd-callgrind&p1=tuscany/sca-cpp/trunk/modules/server/server-conf&r1=1419986&r2=1419987&rev=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/server/server-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/httpd-callgrind Tue Dec 11 04:03:29 2012
@@ -17,24 +17,9 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# Generate a server conf
+# Start httpd server
 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`
 
-# Serve Javascript scripts and CSS
-$here/../js/js-conf $1
-
-# Configure SSL cert used for wiring
-ssl=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"`
-if [ "$ssl" != "" ]; then
-    cat >>$root/conf/httpd.conf <<EOF
-# Configure SSL certificates
-SCAWiringSSLCACertificateFile "$root/cert/ca.crt"
-SCAWiringSSLCertificateFile "$root/cert/server.crt"
-SCAWiringSSLCertificateKeyFile "$root/cert/server.key"
-
-EOF
-
-fi
-
+httpd=`cat $here/httpd.prefix`
+$here/../../etc/callgrind $httpd/bin/httpd -X -E $root/logs/error_log -d $root -f $root/conf/httpd.conf

Modified: tuscany/sca-cpp/trunk/modules/http/httpd.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/httpd.hpp?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/httpd.hpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/httpd.hpp Tue Dec 11 04:03:29 2012
@@ -46,14 +46,14 @@ extern "C" {
 #include <http_request.h>
 // Ignore conversion warnings in HTTPD 2.3.15 header
 #ifdef WANT_MAINTAINER_WARNINGS
-#ifndef IS_DARWIN
+#ifndef __clang__
 #pragma GCC diagnostic ignored "-Wconversion"
 #endif
 #endif
 #include <http_protocol.h>
 // Re-enable conversion warnings
 #ifdef WANT_MAINTAINER_WARNINGS
-#ifndef IS_DARWIN
+#ifndef __clang__
 #pragma GCC diagnostic warning "-Wconversion"
 #endif
 #endif
@@ -94,15 +94,15 @@ template<typename C> void* makeServerCon
     return new (gc_new<C>(p)) C(p, s);
 }
 
-template<typename C> const C& serverConf(const request_rec* r, const module* mod) {
+template<typename C> const C& serverConf(const request_rec* const r, const module* const mod) {
     return *(C*)ap_get_module_config(r->server->module_config, mod);
 }
 
-template<typename C> C& serverConf(const server_rec* s, const module* mod) {
+template<typename C> C& serverConf(const server_rec* const s, const module* const mod) {
     return *(C*)ap_get_module_config(s->module_config, mod);
 }
 
-template<typename C> C& serverConf(const cmd_parms* cmd, const module* mod) {
+template<typename C> C& serverConf(const cmd_parms* const cmd, const module* const mod) {
     return *(C*)ap_get_module_config(cmd->server->module_config, mod);
 }
 
@@ -113,25 +113,25 @@ template<typename C> void* makeDirConf(a
     return new (gc_new<C>(p)) C(p, d);
 }
 
-template<typename C> const C& dirConf(const request_rec* r, const module* mod) {
+template<typename C> const C& dirConf(const request_rec* const r, const module* const mod) {
     return *(C*)ap_get_module_config(r->per_dir_config, mod);
 }
 
-template<typename C> C& dirConf(const void* c) {
+template<typename C> C& dirConf(const void* const 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);
+template<typename C> C& makeRequestConf(const request_rec* const r, const module* const mod) {
+    C* const 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);
+template<typename C> C& requestConf(const request_rec* const r, const module* const mod) {
+    C* const c = (C*)ap_get_module_config(r->request_config, mod);
     if (c == NULL)
         return makeRequestConf<C>(r, mod);
     return *c;
@@ -140,18 +140,18 @@ template<typename C> C& requestConf(cons
 /**
  * Return the host name for a server.
  */
-const string hostName(const server_rec* s, const string& def = "localhost") {
+const string hostName(const server_rec* const 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");
+const string hostName(request_rec* const r, const string& def = "localhost") {
+    const char* const fh = apr_table_get(r->headers_in, "X-Forwarded-Server");
     if (fh != NULL)
         return fh;
-    const char* h = ap_get_server_name(r);
+    const char* const h = ap_get_server_name(r);
     return h != NULL? h : (r->server->server_hostname != NULL? r->server->server_hostname : def);
 }
 
@@ -166,15 +166,15 @@ const string realm(const string& host) {
 /**
  * Return the protocol scheme for a server.
  */
-const string scheme(const server_rec* s, const string& def = "http") {
+const string scheme(const server_rec* const 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");
+const string scheme(const request_rec* const r, const string& def = "http") {
+    const char* const 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;
@@ -183,15 +183,15 @@ const string scheme(request_rec* r, cons
 /**
  * Return the port number for a server.
  */
-const int port(const server_rec* s, const int def = 80) {
+const int port(const server_rec* const 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");
+const int port(const request_rec* const r, const int def = 80) {
+    const char* const fp = apr_table_get(r->headers_in, "X-Forwarded-Port");
     if (fp != NULL)
         return atoi(fp);
     const int p = ap_get_server_port(r);
@@ -201,7 +201,7 @@ const int port(request_rec* r, const int
 /**
  * Return the name of a server.
  */
-const string serverName(const server_rec* s, const string& def = "localhost") {
+const string serverName(server_rec* const s, const string& def = "localhost") {
     ostringstream n;
     const string sc = scheme(s);
     const string h = hostName(s, def);
@@ -209,14 +209,14 @@ const string serverName(const server_rec
     n << sc << "://" << h;
     if (!((sc == "http" && p == 80) || (sc == "https" && p == 443)))
         n << ":" << p;
-    n << (s->path != NULL? string(s->path, s->pathlen) : "");
+    n << (s->path != NULL? string(s->path, s->pathlen) : emptyString);
     return str(n);
 }
 
 /**
  * Determine the name of a server from an HTTP request.
  */
-const string serverName(request_rec* r, const string& def = "localhost") {
+const string serverName(request_rec* const r, const string& def = "localhost") {
     ostringstream n;
     const string s = scheme(r);
     const string h = hostName(r, def);
@@ -224,14 +224,14 @@ const string serverName(request_rec* r, 
     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) : "");
+    n << (r->server->path != NULL? string(r->server->path, r->server->pathlen) : emptyString);
     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 bool isVhostRequest(const server_rec* const s, const string& d, request_rec* const r) {
     const string rh = hostName(r);
     return rh != hostName(s) && http::topDomain(rh) == d;
 }
@@ -239,20 +239,20 @@ const bool isVhostRequest(const server_r
 /**
  * Return the content type of a request.
  */
-const string contentType(const request_rec* r) {
+const string contentType(const request_rec* const r) {
     const char* ct = apr_table_get(r->headers_in, "Content-Type");
     if (ct == NULL)
-        return "";
+        return emptyString;
     return ct;
 }
 
 /**
  * Return the cookie header of a request.
  */
-const string cookie(const request_rec* r) {
+const string cookie(const request_rec* const r) {
     const char* c = apr_table_get(r->headers_in, "Cookie");
     if (c == NULL)
-        return "";
+        return emptyString;
     return c;
 }
 
@@ -268,7 +268,7 @@ const list<value> pathInfo(const list<va
 /**
  * Convert a URI to an absolute URL.
  */
-const string url(const string& uri, request_rec* r) {
+const string url(const string& uri, request_rec* const r) {
     if (contains(uri, "://"))
         return uri;
     ostringstream n;
@@ -285,8 +285,8 @@ const string url(const string& uri, requ
 /**
  * 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);
+const string url(const string& uri, const list<value>& p, request_rec* const r) {
+    return url(uri + (string)path(p), r);
 }
 
 /**
@@ -295,7 +295,7 @@ const string url(const string& uri, cons
 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);
+    char* const 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;
@@ -321,7 +321,7 @@ const string escape(const string& uri) {
  */
 const string unescape(const string& uri) {
     debug(uri, "httpd::unescape::uri");
-    char* b = const_cast<char*>(c_str(string(c_str(uri))));
+    char* const b = const_cast<char*>(c_str(string(c_str(uri))));
     ap_unescape_url(b);
     debug(b, "httpd::unescape::result");
     return b;
@@ -348,7 +348,7 @@ const list<value> queryArg(const string&
     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)), emptyString);
     return mklist<value>(c_str(car(t)), cadr(t));
 }
 
@@ -366,7 +366,7 @@ const list<list<value> > queryArgs(const
 /**
  * Returns a list of key value pairs from the args in an HTTP request.
  */
-const list<list<value> > queryArgs(const request_rec* r) {
+const list<list<value> > queryArgs(const request_rec* const r) {
     if (r->args == NULL)
         return list<list<value> >();
     return queryArgs(r->args);
@@ -385,7 +385,7 @@ const list<list<value> > postArgs(const 
 /**
  * Setup the HTTP read policy.
  */
-const int setupReadPolicy(request_rec* r) {
+const int setupReadPolicy(request_rec* const r) {
     const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
     if(rc != OK)
         return rc;
@@ -399,7 +399,7 @@ const int setupReadPolicy(request_rec* r
 /**
  * Read the content of a POST or PUT.
  */
-const list<string> read(request_rec* r) {
+const list<string> read(request_rec* const r) {
     char b[1024];
     const size_t n = ap_get_client_block(r, b, sizeof(b));
     if (n <= 0)
@@ -410,7 +410,7 @@ const list<string> read(request_rec* r) 
 /**
  * Write an HTTP result.
  */
-const failable<int> writeResult(const failable<list<string> >& ls, const string& ct, request_rec* r) {
+const failable<int> writeResult(const failable<list<string> >& ls, const string& ct, request_rec* const r) {
     if (!hasContent(ls))
         return mkfailure<int>(ls);
     ostringstream os;
@@ -456,16 +456,16 @@ const int reportStatus(const failable<in
 }
 
 /**
- * Convert a value to an HTTPD request struc
+ * Convert a value to an HTTPD request struct.
  */
 request_rec* request(const value& v) {
     return (request_rec*)(long)(double)v;
 }
 
 /**
- * Convert an HTTPD request struct to a value
+ * Convert an HTTPD request struct to a value.
  */
-const value requestValue(request_rec* r) {
+const value requestValue(const request_rec* const r) {
     return value((double)(long)r);
 }
 
@@ -473,19 +473,37 @@ const value requestValue(request_rec* 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);
+const bool internalUpdateFilters(ap_filter_t *f, const request_rec* const from,  request_rec* const to) {
+    while(f) {
+        if(f->r == from)
+            f->r = to;
+        f = f->next;
+    }
+    return true;
+}
+
+/**
+ * Rename original env in an HTTPD redirect request.
+ * Similar to httpd/modules/http/http_request.c::rename_original_env.
+ */
+apr_table_t* const internalRenameOriginalEnv(apr_pool_t* const p, apr_table_t* const t) {
+    const apr_array_header_t *env_arr = apr_table_elts(t);
+    const apr_table_entry_t *elts = (const apr_table_entry_t *) (void*)env_arr->elts;
+    apr_table_t *nt = apr_table_make(p, env_arr->nalloc);
+    int i;
+    for(i = 0; i < env_arr->nelts; ++i) {
+        if (!elts[i].key)
+            continue;
+        apr_table_setn(nt, apr_pstrcat(p, "REDIRECT_", elts[i].key, NULL), elts[i].val);
+    }
+    return nt;
 }
 
 /**
  * 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) {
+const failable<request_rec*> internalRedirectRequest(const string& nr_uri, request_rec* const r) {
     if (ap_is_recursion_limit_exceeded(r))
         return mkfailure<request_rec*>("Redirect recursion limit exceeded", HTTP_INTERNAL_SERVER_ERROR);
 
@@ -498,11 +516,15 @@ const failable<request_rec*> internalRed
     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->parsed_uri.port_str = r->parsed_uri.port_str;
+    nr->parsed_uri.port = r->parsed_uri.port;
     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;
+    nr->useragent_addr = r->useragent_addr;
+    nr->useragent_ip = r->useragent_ip;
 
     // Run create request hook
     ap_run_create_request(nr);
@@ -520,10 +542,15 @@ const failable<request_rec*> internalRed
     nr->main = r->main;
     nr->headers_in = r->headers_in;
     nr->headers_out = apr_table_make(r->pool, 12);
+    if (ap_is_HTTP_REDIRECT(nr->status)) {
+        const char *location = apr_table_get(r->headers_out, "Location");
+        if (location)
+            apr_table_setn(nr->headers_out, "Location", location);
+    }
     nr->err_headers_out = r->err_headers_out;
     nr->subprocess_env = r->subprocess_env;
+    nr->subprocess_env  = internalRenameOriginalEnv(r->pool, 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;
@@ -537,10 +564,28 @@ const failable<request_rec*> internalRed
     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);
+    if (nr->main) {
+        ap_filter_t *f, *nextf;
+        nr->output_filters = r->output_filters;
+        f = nr->output_filters;
+        do {
+            nextf = f->next;
+            if (f->r == r && f->frec != ap_subreq_core_filter_handle) {
+                f->r = nr;
+                ap_remove_output_filter(f);
+            }
+            f = nextf;
+        } while(f && f != nr->proto_output_filters);
+    }
+    else {
+        nr->output_filters  = nr->proto_output_filters;
+    }
+    internalUpdateFilters(nr->input_filters, r, nr);
+    internalUpdateFilters(nr->output_filters, r, nr);
+
+    apr_table_setn(nr->subprocess_env, "REDIRECT_STATUS", apr_itoa(r->pool, r->status));
+    nr->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
+
     const int rrc = ap_run_post_read_request(nr);
     if (rrc != OK && rrc != DECLINED)
         return mkfailure<request_rec*>("Error handling internal redirect", rrc);
@@ -552,7 +597,7 @@ const failable<request_rec*> internalRed
  * Process an HTTPD internal redirect request.
  * Similar to httpd/modules/http/http_request.c::ap_internal_redirect.
  */
-const int internalRedirect(request_rec* nr) {
+const int internalRedirect(request_rec* const nr) {
     int status = ap_run_quick_handler(nr, 0);
     if (status == DECLINED) {
         status = ap_process_request_internal(nr);
@@ -570,8 +615,10 @@ const int internalRedirect(request_rec* 
 /**
  * Create and process an HTTPD internal redirect request.
  */
-const int internalRedirect(const string& uri, request_rec* r) {
+const int internalRedirect(const string& uri, request_rec* const r) {
     debug(uri, "httpd::internalRedirect");
+    //ap_internal_redirect(c_str(uri), r);
+    //return OK;
     const failable<request_rec*> nr = httpd::internalRedirectRequest(uri, r);
     if (!hasContent(nr))
         return rcode(nr);
@@ -582,7 +629,7 @@ const int internalRedirect(const string&
  * 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) {
+const failable<request_rec*> internalSubRequest(const string& nr_uri, request_rec* const r) {
     if (ap_is_recursion_limit_exceeded(r))
         return mkfailure<request_rec*>("Redirect recursion limit exceeded", HTTP_INTERNAL_SERVER_ERROR);
 
@@ -647,7 +694,7 @@ const failable<request_rec*> internalSub
 /**
  * Return an HTTP external redirect request.
  */
-const int externalRedirect(const string& uri, request_rec* r) {
+const int externalRedirect(const string& uri, request_rec* const r) {
     debug(uri, "httpd::externalRedirect");
     r->status = HTTP_MOVED_TEMPORARILY;
     apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, c_str(uri)));
@@ -660,7 +707,7 @@ const int externalRedirect(const string&
 /**
  * Put a value in the process user data.
  */
-const bool putUserData(const string& k, const void* v, const server_rec* s) {
+const bool putUserData(const string& k, const void* const v, const server_rec* const s) {
     apr_pool_userdata_set((const void *)v, c_str(k), apr_pool_cleanup_null, s->process->pool);
     return true;
 }
@@ -668,7 +715,7 @@ const bool putUserData(const string& k, 
 /**
  * Return a user data value.
  */
-const void* userData(const string& k, const server_rec* s) {
+const void* const userData(const string& k, const server_rec* const s) {
     void* v = NULL;
     apr_pool_userdata_get(&v, c_str(k), s->process->pool);
     return v;
@@ -683,7 +730,7 @@ const void* userData(const string& k, co
 /**
  * Log an optional value.
  */
-const char* debugOptional(const char* s) {
+const char* const debugOptional(const char* const s) {
     if (s == NULL)
         return "";
     return s;
@@ -692,7 +739,7 @@ const char* debugOptional(const char* s)
 /**
  * Log a header
  */
-int debugHeader(unused void* r, const char* key, const char* value) {
+int debugHeader(unused void* r, const char* const key, const char* const value) {
     cdebug << "  header key: " << key << ", value: " << value << endl;
     return 1;
 }
@@ -700,7 +747,7 @@ int debugHeader(unused void* r, const ch
 /**
  * Log an environment variable
  */
-int debugEnv(unused void* r, const char* key, const char* value) {
+int debugEnv(unused void* r, const char* const key, const char* const value) {
     cdebug << "  var key: " << key << ", value: " << value << endl;
     return 1;
 }
@@ -708,7 +755,7 @@ int debugEnv(unused void* r, const char*
 /**
  * Log a note.
  */
-int debugNote(unused void* r, const char* key, const char* value) {
+int debugNote(unused void* r, const char* const key, const char* const value) {
     cdebug << "  note key: " << key << ", value: " << value << endl;
     return 1;
 }
@@ -716,8 +763,8 @@ int debugNote(unused void* r, const char
 /**
  * Log a request.
  */
-const bool debugRequest(request_rec* r, const string& msg) {
-    gc_scoped_pool pool;
+const bool debugRequest(request_rec* const r, const string& msg) {
+    const gc_scoped_pool pool;
     cdebug << msg << ":" << endl;
     cdebug << "  unparsed uri: " << debugOptional(r->unparsed_uri) << endl;
     cdebug << "  uri: " << debugOptional(r->uri) << endl;

Modified: tuscany/sca-cpp/trunk/modules/http/mod-openauth.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/mod-openauth.cpp?rev=1419987&r1=1419986&r2=1419987&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/mod-openauth.cpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/mod-openauth.cpp Tue Dec 11 04:03:29 2012
@@ -57,11 +57,11 @@ namespace openauth {
  */
 class ServerConf {
 public:
-    ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+    ServerConf(apr_pool_t* const p, server_rec* const s) : p(p), server(s) {
     }
 
     const gc_pool p;
-    server_rec* server;
+    server_rec* const server;
 };
 
 /**
@@ -71,11 +71,11 @@ class AuthnProviderConf {
 public:
     AuthnProviderConf() : name(), provider(NULL) {
     }
-    AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) {
+    AuthnProviderConf(const string name, const authn_provider* const provider) : name(name), provider(provider) {
     }
 
-    string name;
-    const authn_provider* provider;
+    const string name;
+    const authn_provider* const provider;
 };
 
 /**
@@ -83,14 +83,14 @@ public:
  */
 class DirConf {
 public:
-    DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") {
+    DirConf(apr_pool_t* const p, const char* d) : p(p), dir(d), enabled(false), login(emptyString) {
     }
 
     const gc_pool p;
-    const char* dir;
+    const char* const dir;
     bool enabled;
-    string login;
-    list<AuthnProviderConf> apcs;
+    gc_mutable_ref<string> login;
+    gc_mutable_ref<list<AuthnProviderConf> > apcs;
 };
 
 #ifdef WANT_MAINTAINER_LOG
@@ -98,17 +98,17 @@ public:
 /**
  * Log session entries.
  */
-int debugSessionEntry(unused void* r, const char* key, const char* value) {
+int debugSessionEntry(unused void* r, const char* const key, const char* const value) {
     cdebug << "  session key: " << key << ", value: " << value << endl;
     return 1;
 }
 
-const bool debugSession(request_rec* r, session_rec* z) {
+const bool debugSession(request_rec* const r, const session_rec* const z) {
     apr_table_do(debugSessionEntry, r, z->entries, NULL);
     return true;
 }
 
-#define debug_authSession(r, z) if (debug_islogging()) openauth::debugSession(r, z)
+#define debug_authSession(r, z) if(debug_islogging()) openauth::debugSession(r, z)
 
 #else
 
@@ -117,28 +117,35 @@ const bool debugSession(request_rec* r, 
 #endif
 
 /**
+ * Session hook functions.
+ */
+static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL;
+static apr_status_t (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL;
+static apr_status_t (*ap_session_set_fn)(request_rec * r, session_rec * z, const char *key, const char *value) = NULL;
+
+/**
  * 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 failable<int> checkAuthnzProviders(const string& user, const string& pw, request_rec* const r, const list<AuthnProviderConf>& apcs) {
+    if(isNil(apcs))
+        return mkfailure<int>("Authentication failure for: " + user, HTTP_UNAUTHORIZED);
     const AuthnProviderConf apc = car<AuthnProviderConf>(apcs);
-    if (apc.provider == NULL || !apc.provider->check_password)
+    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)
+    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")
+const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* const 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)) {
+    if(isNil((const list<AuthnProviderConf>)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)));
     }
@@ -148,54 +155,47 @@ const failable<int> checkAuthnz(const st
 /**
  * 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) {
+const failable<value> userInfoFromSession(const string& realm, request_rec* const 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");
+    if(z == NULL)
+        return mkfailure<value>("Couldn't retrieve user session", HTTP_UNAUTHORIZED);
     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");
+    if(user == NULL)
+        return mkfailure<value>("Couldn't retrieve user id", HTTP_UNAUTHORIZED);
     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");
+    if(pw == NULL)
+        return mkfailure<value>("Couldn't retrieve password", HTTP_UNAUTHORIZED);
     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 failable<value> userInfoFromCookie(const value& sid, const string& realm, request_rec* const 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))
+    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");
+    if(isNil(pw))
+        return mkfailure<value>("Couldn't retrieve password", HTTP_UNAUTHORIZED);
     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) {
+const failable<value> userInfoFromHeader(const char* header, const string& realm, request_rec* const r) {
     debug(header, "modopenauth::userInfoFromHeader::header");
-    if (strcasecmp(ap_getword(r->pool, &header, ' '), "Basic"))
-        return mkfailure<value>("Wrong authentication scheme");
+    if(strcasecmp(ap_getword(r->pool, &header, ' '), "Basic"))
+        return mkfailure<value>("Wrong authentication scheme", HTTP_UNAUTHORIZED);
 
     while (apr_isspace(*header))
         header++;
@@ -212,18 +212,18 @@ const failable<value> userInfoFromHeader
 /**
  * Handle an authenticated request.
  */
-const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+const failable<int> authenticated(const list<list<value> >& info, request_rec* const 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");
+    if(isNil(realm) || isNil(cdr(realm)))
+        return mkfailure<int>("Couldn't retrieve realm", HTTP_UNAUTHORIZED);
     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");
+    if(isNil(id) || isNil(cdr(id)))
+        return mkfailure<int>("Couldn't retrieve user id", HTTP_UNAUTHORIZED);
     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))));
@@ -233,127 +233,113 @@ const failable<int> authenticated(const 
 /**
  * Check user authentication.
  */
-static int checkAuthn(request_rec *r) {
-    gc_scoped_pool pool(r->pool);
+static int checkAuthn(request_rec* const r) {
+    const gc_scoped_pool sp(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)
+    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");
+    if(atype == NULL || strcasecmp(atype, "Open"))
+        return DECLINED;
+    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)) {
+    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_")
+        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"));
+        if(aname == NULL)
+            return reportStatus(mkfailure<int>("Missing AuthName", HTTP_UNAUTHORIZED), dc.login, nilValue, r);
 
         // Extract user info from the session id
         const failable<value> userinfo = userInfoFromCookie(content(sid), aname, r);
-        if (hasContent(userinfo)) {
+        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)) {
+            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));
+                return reportStatus(authz, dc.login, 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));
+            return reportStatus(authenticated(uinfo, r), dc.login, nilValue, 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) {
+    const char* const 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"));
+        const char* const aname = ap_auth_name(r);
+        if(aname == NULL)
+            return reportStatus(mkfailure<int>("Missing AuthName", HTTP_UNAUTHORIZED), dc.login, nilValue, r);
 
         // Extract user info from the session id
         const failable<value> info = userInfoFromHeader(header, aname, r);
-        if (hasContent(info)) {
+        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)) {
+            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));
+                return reportStatus(authz, dc.login, 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));
+            return reportStatus(authenticated(uinfo, r), dc.login, nilValue, r);
         }
     }
 
     // Decline if the request is for another authentication provider
-    if (!isNil(assoc<value>("openid_identifier", args)))
+    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")) ||
+    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));
+    return httpd::reportStatus(login(dc.login, nilValue, nilValue, r));
 }
 
 /**
- * Save the auth session cookie in the response.
+ * Load the auth session cookie from the request.
  */
-static int sessionCookieSave(request_rec* r, session_rec* z) {
-    gc_scoped_pool pool(r->pool);
+static int sessionCookieLoad(request_rec* const r, session_rec** const z) {
+    const gc_scoped_pool sp(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)
+    if(!dc.enabled)
         return DECLINED;
 
     // First look in the notes
-    const char* note = apr_pstrcat(r->pool, "mod_openauth", "TuscanyOpenAuth", NULL);
+    const char* const note = apr_pstrcat(r->pool, "mod_openauth", "TuscanyOpenAuth", NULL);
     session_rec* zz = (session_rec*)(void*)apr_table_get(r->notes, note);
-    if (zz != NULL) {
+    if(zz != NULL) {
         *z = zz;
         return OK;
     }
@@ -376,22 +362,86 @@ static int sessionCookieLoad(request_rec
 }
 
 /**
+ * Save the auth session cookie in the response.
+ */
+static int sessionCookieSave(request_rec* const r, session_rec* const z) {
+    const gc_scoped_pool sp(r->pool);
+
+    const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth);
+    if(!dc.enabled)
+        return DECLINED;
+    if(z->encoded == NULL || *(z->encoded) == '\0') {
+        const maybe<string> sid = sessionID(r, "TuscanyOpenAuth");
+        if(!hasContent(sid))
+            return OK;
+    }
+
+    debug(c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))), "modopenauth::sessioncookiesave::setcookie");
+    apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))));
+    return OK;
+}
+
+/**
+ * Logout request handler.
+ */
+int logoutHandler(request_rec* const r) {
+    if(r->handler == NULL || strcmp(r->handler, "mod_tuscany_openauth_logout"))
+        return DECLINED;
+
+    const gc_scoped_pool sp(r->pool);
+    debug_httpdRequest(r, "modopenauth::handler::input");
+    const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth);
+    if(!dc.enabled)
+        return DECLINED;
+
+    // Clear the current session
+    if(hasContent(sessionID(r, "TuscanyOpenAuth"))) {
+        const char* const authname = ap_auth_name(r);
+        session_rec* z = NULL;
+        ap_session_load_fn(r, &z);
+        if(z != NULL && authname != NULL) {
+            ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-user", NULL), NULL);
+            ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-pw", NULL), NULL);
+            ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-site", NULL), NULL);
+        } else
+            apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenAuth", emptyString, httpd::hostName(r))));
+    }
+    if(hasContent(sessionID(r, "TuscanyOpenIDAuth")))
+        apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenIDAuth", emptyString, httpd::hostName(r))));
+    if(hasContent(sessionID(r, "TuscanyOAuth1")))
+        apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOAuth1", emptyString, httpd::hostName(r))));
+    if(hasContent(sessionID(r, "TuscanyOAuth2")))
+        apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOAuth2", emptyString, httpd::hostName(r))));
+
+    // Redirect to the login page
+    return httpd::reportStatus(login(dc.login, "/", nilValue, r));
+}
+
+/**
  * Process the module configuration.
  */
-int postConfigMerge(ServerConf& mainsc, server_rec* s) {
-    if (s == NULL)
+int postConfigMerge(const ServerConf& mainsc, server_rec* const 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);
+int postConfig(apr_pool_t* const p, unused apr_pool_t* const plog, unused apr_pool_t* const ptemp, server_rec* const s) {
+    const gc_scoped_pool sp(p);
 
-    ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_openauth);
+    const ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_openauth);
     debug(httpd::serverName(s), "modopenauth::postConfig::serverName");
 
+    // Retrieve session hook functions
+    if(ap_session_load_fn == NULL)
+        ap_session_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load);
+    if(ap_session_get_fn == NULL)
+        ap_session_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get);
+    if(ap_session_set_fn == NULL)
+        ap_session_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set);
+
     // Merge server configurations
     return postConfigMerge(sc, s);
 }
@@ -399,15 +449,15 @@ int postConfig(apr_pool_t* p, unused apr
 /**
  * Child process initialization.
  */
-void childInit(apr_pool_t* p, server_rec* s) {
-    gc_scoped_pool pool(p);
+void childInit(apr_pool_t* const p, server_rec* const s) {
+    const gc_scoped_pool sp(p);
 
-    ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_openauth);
+    const ServerConf* const 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;
+    const ServerConf& sc = *psc;
 
     // Merge the updated configuration into the virtual hosts
     postConfigMerge(sc, s->next);
@@ -416,27 +466,27 @@ void childInit(apr_pool_t* p, server_rec
 /**
  * Configuration commands.
  */
-const char* confEnabled(cmd_parms *cmd, void *c, const int arg) {
-    gc_scoped_pool pool(cmd->pool);
+char* confEnabled(cmd_parms* cmd, void *c, const int arg) {
+    const gc_scoped_pool sp(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);
+char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
+    const gc_scoped_pool sp(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);
+char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) {
+    const gc_scoped_pool sp(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)
+    if(provider == NULL)
         return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg);
-    if (!provider->check_password)
+    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;
@@ -458,6 +508,7 @@ void registerHooks(unused apr_pool_t *p)
     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);
+    ap_hook_handler(logoutHandler, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 }



Mime
View raw message