diff options
Diffstat (limited to 'sca-cpp/trunk/modules/http')
-rw-r--r-- | sca-cpp/trunk/modules/http/Makefile.am | 14 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/curl-connect.cpp | 10 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/curl-get.cpp | 4 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/curl-test.cpp | 19 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/http.hpp | 358 | ||||
-rwxr-xr-x | sca-cpp/trunk/modules/http/httpd-callgrind | 25 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/httpd.hpp | 181 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/mod-openauth.cpp | 269 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/mod-ssltunnel.cpp | 72 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/http/openauth.hpp | 39 |
10 files changed, 570 insertions, 421 deletions
diff --git a/sca-cpp/trunk/modules/http/Makefile.am b/sca-cpp/trunk/modules/http/Makefile.am index a504adcda5..42504d57ec 100644 --- a/sca-cpp/trunk/modules/http/Makefile.am +++ b/sca-cpp/trunk/modules/http/Makefile.am @@ -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 diff --git a/sca-cpp/trunk/modules/http/curl-connect.cpp b/sca-cpp/trunk/modules/http/curl-connect.cpp index 9f5ee17368..6e16da7163 100644 --- a/sca-cpp/trunk/modules/http/curl-connect.cpp +++ b/sca-cpp/trunk/modules/http/curl-connect.cpp @@ -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 string& ca = "", const string& c 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, const string& ca = "", const string& c } } -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 diff --git a/sca-cpp/trunk/modules/http/curl-get.cpp b/sca-cpp/trunk/modules/http/curl-get.cpp index a16daeeae3..983dd20fc5 100644 --- a/sca-cpp/trunk/modules/http/curl-get.cpp +++ b/sca-cpp/trunk/modules/http/curl-get.cpp @@ -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, const string& ca = "", const string& cert } } -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 diff --git a/sca-cpp/trunk/modules/http/curl-test.cpp b/sca-cpp/trunk/modules/http/curl-test.cpp index f0806ea577..6a1174a404 100644 --- a/sca-cpp/trunk/modules/http/curl-test.cpp +++ b/sca-cpp/trunk/modules/http/curl-test.cpp @@ -40,7 +40,7 @@ ostream* curlWriter(const string& s, ostream* os) { } 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"; diff --git a/sca-cpp/trunk/modules/http/http.hpp b/sca-cpp/trunk/modules/http/http.hpp index 408b9fdee5..1153f61840 100644 --- a/sca-cpp/trunk/modules/http/http.hpp +++ b/sca-cpp/trunk/modules/http/http.hpp @@ -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 gc_pool& p) { /** * 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, 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 ""; + return emptyString; if (u.hostname == NULL) - return ""; + return emptyString; return u.hostname; } @@ -238,9 +243,9 @@ 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 ""; + return emptyString; if (u.scheme == NULL) - return ""; + return emptyString; return u.scheme; } @@ -262,13 +267,14 @@ const string topDomain(const string& host) { /** * 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& url, CURLSession& cs) { 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& url, CURLSession& cs) { /** * 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 size, size_t nmemb, void *data) { */ 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 writeCallback(void *ptr, size_t size, size_t nmemb, * 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<R> > apply(const list<list<string> >& h 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<R> > apply(const list<list<string> >& h 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<R> > apply(const list<list<string> >& h /** * 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 value& expr, const string& url, CURLSession 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 value& expr, const string& url, CURLSession /** * 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* prefix, const list<string>& h) { */ 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>& h) { */ 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<string> l) { */ 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<R> > get(const lambda<R(const string&, /** * 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(const list<list<string> > res) { 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(const list<list<string> > res) { } 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(const list<list<string> > res) { 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(const list<list<string> > res) { /** * 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> > > writeRequest(const failable<list<string> >& */ 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"); - } - - // 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"); + debug(c, "http::contentRequest::assoc"); + return writeRequest(json::writeValue(c), "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> > > contentRequest(const value& c, unused const } // 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& val, const string& url, CURLSession& cs) /** * 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& val, const string& url, CURLSession& cs) 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& val, const string& url, CURLSession& cs 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 string& url, CURLSession& cs) { 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, const int e, const gc_pool& p) { /** * 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 string& url, CURLSession& cs) { 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 string& url, CURLSession& cs) { 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 string& url, CURLSession& cs) { /** * 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, const size_t l, CURLSession& cs) { // 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, const size_t l, CURLSession& cs) { /** * 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, const size_t l, CURLSession& cs) { // 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)); + } }; } diff --git a/sca-cpp/trunk/modules/http/httpd-callgrind b/sca-cpp/trunk/modules/http/httpd-callgrind new file mode 100755 index 0000000000..964b046638 --- /dev/null +++ b/sca-cpp/trunk/modules/http/httpd-callgrind @@ -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/callgrind $httpd/bin/httpd -X -E $root/logs/error_log -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp index 6470d6c587..e090c2fc35 100644 --- a/sca-cpp/trunk/modules/http/httpd.hpp +++ b/sca-cpp/trunk/modules/http/httpd.hpp @@ -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* 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) { +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(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) { +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(const request_rec* r, const module* mod) { /** * 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, const string& def = "http") { /** * 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 def = 80) { /** * 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* s, const string& def = "localhost") { 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, const string& def = "localhost") { 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_rec* s, const string& d, request_rec* 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<value>& uri, const list<value>& path) { /** * 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, request_rec* r) { /** * 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, const list<value>& p, request_rec* r) { 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& 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)), emptyString); return mklist<value>(c_str(car(t)), cadr(t)); } @@ -366,7 +366,7 @@ const list<list<value> > queryArgs(const string& a) { /** * 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 list<value>& a) { /** * 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<int>& rc) { } /** - * 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*> internalRedirectRequest(const string& nr_uri, reque 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*> internalRedirectRequest(const string& nr_uri, reque 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*> internalRedirectRequest(const string& nr_uri, reque 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*> internalRedirectRequest(const string& nr_uri, reque * 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* nr) { /** * 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& uri, request_rec* r) { * 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*> internalSubRequest(const string& nr_uri, request_re /** * 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& uri, request_rec* r) { /** * 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, const void* v, const server_rec* s) { /** * 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, const server_rec* s) { /** * 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 char* key, const char* value) { /** * 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* key, const char* value) { /** * 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* key, const char* value) { /** * 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; diff --git a/sca-cpp/trunk/modules/http/mod-openauth.cpp b/sca-cpp/trunk/modules/http/mod-openauth.cpp index 2e308ecedb..797e8c10b5 100644 --- a/sca-cpp/trunk/modules/http/mod-openauth.cpp +++ b/sca-cpp/trunk/modules/http/mod-openauth.cpp @@ -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, session_rec* z) { #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 string& user, const string& pw, request_re /** * 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(const char* header, const string& realm /** * 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 list<list<value> >& info, request_rec* r /** * 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. - */ -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 + * Load the auth session cookie from the request. */ -static int sessionCookieLoad(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) + 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* r, session_rec** z) { } /** + * 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_pool_t* plog, unused apr_pool_t* ptemp, /** * 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* s) { /** * 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); } } diff --git a/sca-cpp/trunk/modules/http/mod-ssltunnel.cpp b/sca-cpp/trunk/modules/http/mod-ssltunnel.cpp index b66cd29959..0a9ebc1a80 100644 --- a/sca-cpp/trunk/modules/http/mod-ssltunnel.cpp +++ b/sca-cpp/trunk/modules/http/mod-ssltunnel.cpp @@ -53,17 +53,17 @@ namespace modssltunnel { */ 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; - string pass; - string host; - string path; - string ca; - string cert; - string key; + server_rec* const server; + gc_mutable_ref<string> pass; + gc_mutable_ref<string> host; + gc_mutable_ref<string> path; + gc_mutable_ref<string> ca; + gc_mutable_ref<string> cert; + gc_mutable_ref<string> key; }; extern "C" { @@ -74,7 +74,7 @@ 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) { +int postConfigMerge(const ServerConf& mainsc, apr_pool_t* const p, server_rec* const s) { if (s == NULL) return OK; ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_ssltunnel); @@ -102,10 +102,10 @@ int postConfigMerge(ServerConf& mainsc, apr_pool_t* p, server_rec* s) { 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); +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_ssltunnel); + const ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_ssltunnel); debug(httpd::serverName(s), "modssltunnel::postConfig::serverName"); // Register the SSLTUNNEL method @@ -118,7 +118,7 @@ int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, /** * Close a connection. */ -const int close(conn_rec* conn, apr_socket_t* csock) { +const int close(conn_rec* const conn, apr_socket_t* const csock) { debug("modssltunnel::close"); apr_socket_close(csock); conn->aborted = 1; @@ -128,7 +128,7 @@ const int close(conn_rec* conn, apr_socket_t* csock) { /** * Abort a connection. */ -const int abort(conn_rec* conn, apr_socket_t* csock, const string& reason) { +const int abort(conn_rec* const conn, apr_socket_t* const csock, const string& reason) { debug("modssltunnel::abort"); apr_socket_close(csock); conn->aborted = 1; @@ -138,21 +138,21 @@ const int abort(conn_rec* conn, apr_socket_t* csock, const string& 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) { +int tunnel(conn_rec* const conn, const string& ca, const string& cert, const string& key, const string& url, const string& preamble, const gc_pool& p, unused ap_filter_t* const ifilter, ap_filter_t* const 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); + apr_bucket_brigade* const ib = apr_brigade_create(pool(p), conn->bucket_alloc); + apr_bucket_brigade* const 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); + apr_socket_t* const 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 http::CURLSession cs(ca, cert, key, emptyString, 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); + apr_socket_t* const tsock = http::sock(cs); // Send preamble if (length(preamble) != 0) { @@ -164,7 +164,7 @@ int tunnel(conn_rec* conn, const string& ca, const string& cert, const string& k // 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); + const 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); @@ -241,7 +241,7 @@ int tunnel(conn_rec* conn, const string& ca, const string& cert, const string& k // Poll the client and target sockets debug("modssltunnel::tunnel::poll"); - apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds); + const 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"); @@ -254,7 +254,7 @@ int tunnel(conn_rec* conn, const string& ca, const string& cert, const string& k /** * Return the first connection filter in a list of filters. */ -ap_filter_t* connectionFilter(ap_filter_t* f) { +ap_filter_t* const connectionFilter(ap_filter_t* const f) { if (f == NULL) return f; if (f->frec->ftype < AP_FTYPE_CONNECTION) @@ -265,14 +265,14 @@ ap_filter_t* connectionFilter(ap_filter_t* f) { /** * Process a client connection and relay it to a tunnel. */ -int processConnection(conn_rec *conn) { +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); + const gc_scoped_pool sp(conn->pool); // Get the server configuration const ServerConf& sc = httpd::serverConf<ServerConf>(conn->base_server, &mod_tuscany_ssltunnel); @@ -297,41 +297,41 @@ int handler(request_rec* r) { if (strcmp(r->server->server_scheme, "https")) return DECLINED; - gc_scoped_pool pool(r->pool); + const gc_scoped_pool sp(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); + const string url = string(cadr(path)) + ":" + (string)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)); + return tunnel(r->connection, emptyString, emptyString, emptyString, url, emptyString, 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); +char* confTunnelPass(cmd_parms *cmd, unused void *c, const char *arg) { + const gc_scoped_pool sp(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); +char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) { + const gc_scoped_pool sp(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); +char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) { + const gc_scoped_pool sp(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); +char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) { + const gc_scoped_pool sp(cmd->pool); ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel); sc.key = arg; return NULL; diff --git a/sca-cpp/trunk/modules/http/openauth.hpp b/sca-cpp/trunk/modules/http/openauth.hpp index 3ffa88d362..dcf405d487 100644 --- a/sca-cpp/trunk/modules/http/openauth.hpp +++ b/sca-cpp/trunk/modules/http/openauth.hpp @@ -42,11 +42,12 @@ namespace openauth { /** * Return the session id from a request. */ -const char* cookieName(const char* cs) { +const char* const cookieName(const char* const 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>(); @@ -62,7 +63,7 @@ const maybe<string> sessionID(const list<string>& c, const string& key) { return sessionID(cdr(c), key); } -const maybe<string> sessionID(const request_rec* r, const string& key) { +const maybe<string> sessionID(const request_rec* const r, const string& key) { const string c = httpd::cookie(r); debug(c, "openauth::sessionid::cookies"); if (length(c) == 0) @@ -74,10 +75,15 @@ const maybe<string> sessionID(const request_rec* r, const string& key) { * Convert a session id to a cookie string. */ const string cookie(const string& key, const string& sid, const string& domain) { + if (length(sid) == 0) { + const string c = key + string("=") + "; max-age=0; domain=." + httpd::realm(domain) + "; path=/; secure; httponly"; + debug(c, "openauth::cookie"); + return c; + } 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=/"; + const string c = key + string("=") + sid + "; expires=" + string(exp) + "; domain=." + httpd::realm(domain) + "; path=/; secure; httponly"; debug(c, "openauth::cookie"); return c; } @@ -85,7 +91,7 @@ const string cookie(const string& key, const string& sid, const string& domain) /** * Redirect to the configured login page. */ -const failable<int> login(const string& page, const value& ref, const value& attempt, request_rec* r) { +const failable<int> login(const string& page, const value& ref, const value& attempt, request_rec* const 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); @@ -94,6 +100,31 @@ const failable<int> login(const string& page, const value& ref, const value& att return httpd::externalRedirect(loc, r); } +/** + * Report a request auth status. + */ +const int reportStatus(const failable<int>& authrc, const string& page, const value& attempt, request_rec* const r) { + debug(authrc, "openauth::reportStatus::authrc"); + + // Redirect to the login page if not authorized + if (!hasContent(authrc) && rcode(authrc) == HTTP_UNAUTHORIZED) { + + // Clear any auth cookies + if(hasContent(sessionID(r, "TuscanyOpenAuth"))) + 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)))); + + return httpd::reportStatus(login(page, string("/"), attempt, r)); + } + + return httpd::reportStatus(authrc); +} + } } |