diff options
Diffstat (limited to '')
-rw-r--r-- | sca-cpp/trunk/modules/http/curl.hpp | 190 |
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; }; } |