summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/http/http.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/modules/http/http.hpp')
-rw-r--r--sca-cpp/trunk/modules/http/http.hpp358
1 files changed, 180 insertions, 178 deletions
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));
+ }
};
}