summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/http/curl.hpp
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-01-02 10:27:26 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-01-02 10:27:26 +0000
commit95fa76f5f3208d913320c13a05171ecdcd7134c2 (patch)
tree872e101cd2fb1505baf313940e48c6b615fd6725 /sca-cpp/trunk/modules/http/curl.hpp
parent1d04916fda43146fb62488c20ba03b7b3006c8e9 (diff)
Performance improvements when running both in multi-threaded and pre-forked HTTPD. Changed memory management to use Apache APR pools instead of ref counting pointers as it's much faster and easier to integrate with the Python and Ruby interpreters. Changed to use simple pool-based string and stream implementations instead of the STL ones, which cause a lots of mutex locks in a multi-threaded environment. Added build options to compile with threading and profiling.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@895165 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r--sca-cpp/trunk/modules/http/curl.hpp190
1 files changed, 98 insertions, 92 deletions
diff --git a/sca-cpp/trunk/modules/http/curl.hpp b/sca-cpp/trunk/modules/http/curl.hpp
index 85665c2785..3478a590fd 100644
--- a/sca-cpp/trunk/modules/http/curl.hpp
+++ b/sca-cpp/trunk/modules/http/curl.hpp
@@ -29,7 +29,7 @@
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
-#include <string>
+#include "string.hpp"
#include "gc.hpp"
#include "list.hpp"
#include "value.hpp"
@@ -62,7 +62,7 @@ CURLContext curlContext;
*/
class CURLSession {
public:
- CURLSession() : ch(new CURLHandle()) {
+ CURLSession() : ch(new (gc_new<CURLHandle>()) CURLHandle()) {
}
~CURLSession() {
@@ -103,9 +103,9 @@ CURL* handle(const CURLSession& c) {
*/
class CURLReadContext {
public:
- CURLReadContext(const list<std::string>& ilist) : ilist(ilist) {
+ CURLReadContext(const list<string>& ilist) : ilist(ilist) {
}
- list<std::string> ilist;
+ list<string> ilist;
};
/**
@@ -115,11 +115,11 @@ size_t readCallback(void *ptr, size_t size, size_t nmemb, void *data) {
CURLReadContext& rcx = *static_cast<CURLReadContext*>(data);
if (isNil(rcx.ilist))
return 0;
- rcx.ilist = fragment(rcx.ilist, size * nmemb);
- const std::string s = car(rcx.ilist);
- rcx.ilist = cdr(rcx.ilist);
- s.copy((char*)ptr, s.length());
- return s.length();
+ const list<string> f(fragment(rcx.ilist, size * nmemb));
+ const string s = car(f);
+ rcx.ilist = cdr(f);
+ memcpy(ptr, c_str(s), length(s));
+ return length(s);
}
/**
@@ -127,9 +127,9 @@ size_t readCallback(void *ptr, size_t size, size_t nmemb, void *data) {
*/
template<typename R> class CURLWriteContext {
public:
- CURLWriteContext(const lambda<R(const std::string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
+ CURLWriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
}
- const lambda<R(const std::string&, const R)> reduce;
+ const lambda<R(const string&, const R)> reduce;
R accum;
};
@@ -137,33 +137,23 @@ public:
* Called by CURL to write received data.
*/
template<typename R> size_t writeCallback(void *ptr, size_t size, size_t nmemb, void *data) {
- CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data));
- const size_t realsize = size * nmemb;
- wcx.accum = wcx.reduce(std::string((const char*)ptr, realsize), wcx.accum);
- return realsize;
-}
-
-/**
- * Called by CURL to write received header data.
- */
-template<typename R> size_t headerCallback(void *ptr, size_t size, size_t nmemb, void *data) {
- CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data));
- const size_t realsize = size * nmemb;
- wcx.accum = wcx.reduce(std::string((const char*)ptr, realsize), wcx.accum);
- return realsize;
+ CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data));
+ const size_t realsize = size * nmemb;
+ wcx.accum = wcx.reduce(string((const char*)ptr, realsize), wcx.accum);
+ return realsize;
}
/**
* Apply an HTTP verb to a list containing a list of headers and a list of content, and
* a reduce function used to process the response.
*/
-curl_slist* headers(curl_slist* cl, const list<std::string>& h) {
+curl_slist* headers(curl_slist* cl, const list<string>& h) {
if (isNil(h))
return cl;
- return headers(curl_slist_append(cl, std::string(car(h)).c_str()), cdr(h));
+ return headers(curl_slist_append(cl, c_str(string(car(h)))), cdr(h));
}
-template<typename R> const failable<list<R>, std::string> apply(const list<list<std::string> >& req, const lambda<R(const std::string&, const R)>& reduce, const R& initial, const std::string& url, const std::string& verb, const CURLSession& cs) {
+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, const CURLSession& cs) {
// Init the curl session
CURL* ch = handle(cs);
@@ -171,30 +161,30 @@ template<typename R> const failable<list<R>, std::string> apply(const list<list<
curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0");
//TODO use HTTP chunking, for now just convert request to a single string
- std::ostringstream os;
- write(cadr(req), os);
- const std::string s = os.str();
- const int sz = s.length();
+ ostringstream os;
+ write(cadr(hdr), os);
+ const string s = str(os);
+ const int sz = length(s);
// Setup the read, header and write callbacks
CURLReadContext rcx(mklist(s));
curl_easy_setopt(ch, CURLOPT_READFUNCTION, (size_t (*)(void*, size_t, size_t, void*))readCallback);
curl_easy_setopt(ch, CURLOPT_READDATA, &rcx);
CURLWriteContext<R> hcx(reduce, initial);
- curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))headerCallback<R>);
+ curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))(writeCallback<R>));
curl_easy_setopt(ch, CURLOPT_HEADERDATA, &hcx);
CURLWriteContext<R> wcx(reduce, initial);
- curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, (size_t (*)(void*, size_t, size_t, void*))writeCallback<R>);
+ curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, (size_t (*)(void*, size_t, size_t, void*))(writeCallback<R>));
curl_easy_setopt(ch, CURLOPT_WRITEDATA, &wcx);
curl_easy_setopt(ch, CURLOPT_TCP_NODELAY, true);
// Set the request headers
- curl_slist* hl = headers(NULL, car(req));
+ curl_slist* hl = headers(NULL, car(hdr));
if (hl != NULL)
curl_easy_setopt(ch, CURLOPT_HTTPHEADER, hl);
// Apply the HTTP verb
- curl_easy_setopt(ch, CURLOPT_URL, url.c_str());
+ curl_easy_setopt(ch, CURLOPT_URL, c_str(url));
if (verb == "POST") {
curl_easy_setopt(ch, CURLOPT_POST, true);
curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, sz);
@@ -210,13 +200,13 @@ template<typename R> const failable<list<R>, std::string> apply(const list<list<
// Return the HTTP return code or content
if (rc)
- return mkfailure<list<R>, std::string>(curl_easy_strerror(rc));
+ return mkfailure<list<R> >(string(curl_easy_strerror(rc)));
long httprc;
curl_easy_getinfo (ch, CURLINFO_RESPONSE_CODE, &httprc);
if (httprc != 200 && httprc != 201) {
- std::ostringstream es;
+ ostringstream es;
es << "HTTP code " << httprc;
- return mkfailure<list<R>, std::string>(es.str());
+ return mkfailure<list<R> >(str(es));
}
return mklist<R>(hcx.accum, wcx.accum);
}
@@ -224,26 +214,26 @@ template<typename R> const failable<list<R>, std::string> apply(const list<list<
/**
* Evaluate an expression remotely, at the given URL.
*/
-const failable<value, std::string> evalExpr(const value& expr, const std::string& url, const CURLSession& ch) {
+const failable<value> evalExpr(const value& expr, const string& url, const CURLSession& ch) {
debug(url, "http::evalExpr::url");
debug(expr, "http::evalExpr::input");
// Convert expression to a JSON-RPC request
json::JSONContext cx;
- const failable<list<std::string>, std::string> jsreq = jsonRequest(1, car<value>(expr), cdr<value>(expr), cx);
+ const failable<list<string> > jsreq = json::jsonRequest(1, car<value>(expr), cdr<value>(expr), cx);
if (!hasContent(jsreq))
- return mkfailure<value, std::string>(reason(jsreq));
+ return mkfailure<value>(reason(jsreq));
// POST it to the URL
- const list<std::string> h = mklist<std::string>("Content-Type: application/json-rpc");
- const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(mklist<list<std::string> >(h, content(jsreq)), rcons<std::string>, list<std::string>(), url, "POST", ch);
+ const list<string> h = mklist<string>("Content-Type: application/json-rpc");
+ const failable<list<list<string> > > res = apply<list<string> >(mklist<list<string> >(h, content(jsreq)), rcons<string>, list<string>(), url, "POST", ch);
if (!hasContent(res))
- return mkfailure<value, std::string>(reason(res));
+ return mkfailure<value>(reason(res));
// Return result
- failable<list<value>, std::string> jsres = json::readJSON(cadr<list<std::string> >(content(res)), cx);
+ failable<list<value> > jsres = json::readJSON(cadr<list<string> >(content(res)), cx);
if (!hasContent(jsres))
- return mkfailure<value, std::string>(reason(jsres));
+ return mkfailure<value>(reason(jsres));
const list<value> val = elementsToValues(content(jsres));
const value rval(cadr<value>(cadr<value>(val)));
@@ -254,72 +244,88 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
/**
* Find and return a header.
*/
-const failable<std::string, std::string> header(const std::string& prefix, const list<std::string>& h) {
+const failable<string> header(const char* prefix, const list<string>& h) {
if (isNil(h))
- return mkfailure<std::string, std::string>(std::string("Couldn't find header: ") + prefix);
- const std::string s = car(h);
- if (s.find(prefix) != 0)
+ return mkfailure<string>(string("Couldn't find header: ") + prefix);
+ const string s = car(h);
+ if (find(s, prefix) != 0)
return header(prefix, cdr(h));
- const std::string l(s.substr(prefix.length()));
- return l.substr(0, l.find_first_of("\r\n"));
+ const string l(substr(s, length(prefix)));
+ return substr(l, 0, find_first_of(l, "\r\n"));
}
/**
* Find and return a location header.
*/
-const failable<std::string, std::string> location(const list<std::string>& h) {
+const failable<string> location(const list<string>& h) {
return header("Location: ", h);
}
/**
* Convert a location to an entry id.
*/
-const failable<value, std::string> entryId(const failable<std::string, std::string> l) {
+const failable<value> entryId(const failable<string> l) {
if (!hasContent(l))
- return mkfailure<value, std::string>(reason(l));
- const std::string ls(content(l));
- return value(ls.substr(ls.find_last_of("/") + 1));
+ return mkfailure<value>(reason(l));
+ const string ls(content(l));
+ return value(string(substr(ls, find_last(ls, '/') + 1)));
}
/**
* Find and return a content-type header.
*/
-const failable<std::string, std::string> contentType(const list<std::string>& h) {
+const failable<string> contentType(const list<string>& h) {
return header("Content-Type: ", h);
}
/**
* HTTP GET, return the resource at the given URL.
*/
-template<typename R> const failable<list<R>, std::string> get(const lambda<R(const std::string&, const R)>& reduce, const R& initial, const std::string& url, const CURLSession& ch) {
+template<typename R> const failable<list<R> > get(const lambda<R(const string&, const R)>& reduce, const R& initial, const string& url, const CURLSession& ch) {
debug(url, "http::get::url");
- const list<list<std::string> > req = mklist(list<std::string>(), list<std::string>());
+ const list<list<string> > req = mklist(list<string>(), list<string>());
return apply(req, reduce, initial, url, "GET", ch);
}
/**
* HTTP GET, return a list of values representing the resource at the given URL.
*/
-const failable<value, std::string> get(const std::string& url, const CURLSession& ch) {
+const failable<value> getcontent(const string& url, const CURLSession& ch) {
+ debug(url, "http::get::url");
+
+ // Get the contents of the resource at the given URL
+ const failable<list<list<string> > > res = get<list<string>>(rcons<string>, list<string>(), url, ch);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+ const list<string> ls(reverse(cadr(content(res))));
+
+ // Return the content as a list of values
+ const value val(mkvalues(ls));
+ debug(val, "http::get::result");
+ return val;
+}
+
+/**
+ * HTTP GET, return a list of values representing the resource at the given URL.
+ */
+const failable<value> get(const string& url, const CURLSession& ch) {
debug(url, "http::get::url");
// Get the contents of the resource at the given URL
- const failable<list<list<std::string> >, std::string> res = get<list<std::string> >(rcons<std::string>, list<std::string>(), url, ch);
+ const failable<list<list<string> > > res = get<list<string> >(rcons<string>, list<string>(), url, ch);
if (!hasContent(res))
- return mkfailure<value, std::string>(reason(res));
- const list<std::string> ls(reverse(cadr(content(res))));
+ return mkfailure<value>(reason(res));
+ const list<string> ls(reverse(cadr(content(res))));
- const std::string ct(content(contentType(car(content(res)))));
+ const string ct(content(contentType(car(content(res)))));
if (ct == "application/atom+xml;type=entry") {
const value val(atom::entryValue(content(atom::readEntry(ls))));
debug(val, "http::get::result");
return val;
}
- // Return the content as a string value
- std::ostringstream os;
- write(ls, os);
- const value val(os.str());
+ // Return the content as a list of values
+ const value val(mkvalues(ls));
debug(val, "http::get::result");
return val;
}
@@ -327,24 +333,24 @@ const failable<value, std::string> get(const std::string& url, const CURLSession
/**
* HTTP POST.
*/
-const failable<value, std::string> post(const value& val, const std::string& url, const CURLSession& ch) {
+const failable<value> post(const value& val, const string& url, const CURLSession& ch) {
// Convert value to an ATOM entry
- const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
+ const failable<list<string> > entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
if (!hasContent(entry))
- return mkfailure<value, std::string>(reason(entry));
+ return mkfailure<value>(reason(entry));
debug(url, "http::post::url");
debug(content(entry), "http::post::input");
// POST it to the URL
- const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
- const list<list<std::string> > req = mklist<list<std::string> >(h, content(entry));
- const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "POST", ch);
+ const list<string> h = mklist<string>("Content-Type: application/atom+xml");
+ const list<list<string> > req = mklist<list<string> >(h, content(entry));
+ const failable<list<list<string> > > res = apply<list<string>>(req, rcons<string>, list<string>(), url, "POST", ch);
if (!hasContent(res))
- return mkfailure<value, std::string>(reason(res));
+ return mkfailure<value>(reason(res));
// Return the new entry id from the HTTP location header
- const failable<value, std::string> eid(entryId(location(car(content(res)))));
+ const failable<value> eid(entryId(location(car(content(res)))));
debug(eid, "http::post::result");
return eid;
}
@@ -352,21 +358,21 @@ const failable<value, std::string> post(const value& val, const std::string& url
/**
* HTTP PUT.
*/
-const failable<value, std::string> put(const value& val, const std::string& url, const CURLSession& ch) {
+const failable<value> put(const value& val, const string& url, const CURLSession& ch) {
// Convert value to an ATOM entry
- const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
+ const failable<list<string> > entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
if (!hasContent(entry))
- return mkfailure<value, std::string>(reason(entry));
+ return mkfailure<value>(reason(entry));
debug(url, "http::put::url");
debug(content(entry), "http::put::input");
// PUT it to the URL
- const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
- const list<list<std::string> > req = mklist<list<std::string> >(h, content(entry));
- const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "PUT", ch);
+ const list<string> h = mklist<string>("Content-Type: application/atom+xml");
+ const list<list<string> > req = mklist<list<string> >(h, content(entry));
+ const failable<list<list<string> > > res = apply<list<string> >(req, rcons<string>, list<string>(), url, "PUT", ch);
if (!hasContent(res))
- return mkfailure<value, std::string>(reason(res));
+ return mkfailure<value>(reason(res));
debug(true, "http::put::result");
return value(true);
@@ -375,13 +381,13 @@ const failable<value, std::string> put(const value& val, const std::string& url,
/**
* HTTP DELETE.
*/
-const failable<value, std::string> del(const std::string& url, const CURLSession& ch) {
+const failable<value, string> del(const string& url, const CURLSession& ch) {
debug(url, "http::delete::url");
- const list<list<std::string> > req = mklist(list<std::string>(), list<std::string>());
- const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "DELETE", ch);
+ const list<list<string> > req = mklist(list<string>(), list<string>());
+ const failable<list<list<string> > > res = apply<list<string> >(req, rcons<string>, list<string>(), url, "DELETE", ch);
if (!hasContent(res))
- return mkfailure<value, std::string>(reason(res));
+ return mkfailure<value>(reason(res));
debug(true, "http::delete::result");
return value(true);
@@ -391,18 +397,18 @@ const failable<value, std::string> del(const std::string& url, const CURLSession
* HTTP client proxy function.
*/
struct proxy {
- proxy(const std::string& url) : url(url) {
+ proxy(const string& url) : url(url) {
}
const value operator()(const list<value>& args) const {
CURLSession cs;
- failable<value, std::string> val = evalExpr(args, url, cs);
+ failable<value> val = evalExpr(args, url, cs);
if (!hasContent(val))
return value();
return content(val);
}
- const std::string url;
+ const string url;
};
}