summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/http
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/modules/http')
-rw-r--r--sca-cpp/trunk/modules/http/curl-test.cpp6
-rw-r--r--sca-cpp/trunk/modules/http/curl.hpp166
-rwxr-xr-xsca-cpp/trunk/modules/http/http-test2
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-test2
-rw-r--r--sca-cpp/trunk/modules/http/httpd.hpp91
5 files changed, 148 insertions, 119 deletions
diff --git a/sca-cpp/trunk/modules/http/curl-test.cpp b/sca-cpp/trunk/modules/http/curl-test.cpp
index 0a6fbcd8a6..59944546a1 100644
--- a/sca-cpp/trunk/modules/http/curl-test.cpp
+++ b/sca-cpp/trunk/modules/http/curl-test.cpp
@@ -50,7 +50,7 @@ std::ostringstream* curlWriter(const std::string& s, std::ostringstream* os) {
}
const bool testGet() {
- CURLHandle ch;
+ CURLSession ch;
{
std::ostringstream os;
const failable<list<std::ostringstream*>, std::string> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
@@ -66,7 +66,7 @@ const bool testGet() {
return true;
}
-const bool testGetLoop(const int count, CURLHandle& ch) {
+const bool testGetLoop(const int count, CURLSession& ch) {
if (count == 0)
return true;
const failable<value, std::string> r = get("http://localhost:8090", ch);
@@ -77,7 +77,7 @@ const bool testGetLoop(const int count, CURLHandle& ch) {
const bool testGetPerf() {
const int count = 50;
- CURLHandle ch;
+ CURLSession ch;
struct timeval start;
struct timeval end;
{
diff --git a/sca-cpp/trunk/modules/http/curl.hpp b/sca-cpp/trunk/modules/http/curl.hpp
index 6c3a3a47dc..fd2e9857d1 100644
--- a/sca-cpp/trunk/modules/http/curl.hpp
+++ b/sca-cpp/trunk/modules/http/curl.hpp
@@ -30,6 +30,7 @@
#include <curl/types.h>
#include <curl/easy.h>
#include <string>
+#include "gc.hpp"
#include "list.hpp"
#include "value.hpp"
#include "element.hpp"
@@ -41,11 +42,6 @@ namespace tuscany {
namespace http {
/**
- * Set to true to log HTTP content.
- */
-bool logContent = false;
-
-/**
* CURL library context, one per process.
*/
class CURLContext {
@@ -63,22 +59,45 @@ CURLContext curlContext;
/**
* Represents a CURL session handle.
*/
-class CURLHandle {
+class CURLSession {
public:
- CURLHandle() : h(curl_easy_init()) {
+ CURLSession() : ch(new CURLHandle()) {
}
- ~CURLHandle() {
- curl_easy_cleanup(h);
+
+ ~CURLSession() {
}
- operator CURL*() const {
- return h;
+ CURLSession(const CURLSession& c) : ch(c.ch) {
}
+
private:
- CURL* h;
+ class CURLHandle {
+ public:
+ CURLHandle() : h(curl_easy_init()) {
+ }
+ ~CURLHandle() {
+ curl_easy_cleanup(h);
+ h = NULL;
+ }
+ private:
+ CURL* h;
+
+ friend CURL* handle(const CURLSession& c);
+ };
+
+ const gc_ptr<CURLHandle> ch;
+
+ friend CURL* handle(const CURLSession& c);
};
/**
+ * Returns the CURL handle used by a CURL session.
+ */
+CURL* handle(const CURLSession& c) {
+ return c.ch->h;
+}
+
+/**
* Context passed to the read callback function.
*/
class CURLReadContext {
@@ -143,9 +162,10 @@ curl_slist* headers(curl_slist* cl, const list<std::string>& h) {
return headers(curl_slist_append(cl, std::string(car(h)).c_str()), cdr(h));
}
-template<typename R> const failable<list<R>, std::string> apply(const list<list<std::string> >& req, const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const std::string& verb, const CURLHandle& ch) {
+template<typename R> const failable<list<R>, std::string> apply(const list<list<std::string> >& req, const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const std::string& verb, const CURLSession& cs) {
// Init the curl session
+ CURL* ch = handle(cs);
curl_easy_reset(ch);
curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0");
@@ -204,7 +224,9 @@ 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 CURLHandle& ch) {
+const failable<value, std::string> evalExpr(const value& expr, const std::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;
@@ -212,13 +234,6 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
if (!hasContent(jsreq))
return mkfailure<value, std::string>(reason(jsreq));
- if (logContent) {
- std::cout<< "content: " << std::endl;
- write(content(jsreq), std::cout);
- std::cout<< std::endl;
- std::cout.flush();
- }
-
// 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);
@@ -226,19 +241,58 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
return mkfailure<value, std::string>(reason(res));
// Return result
- if (logContent) {
- std::cout << "content:" << std::endl;
- write(cadr<list<std::string> >(content(res)), std::cout);
- std::cout << std::endl;
- }
- const list<value> val = elementsToValues(content(json::readJSON(cadr<list<std::string> >(content(res)), cx)));
- return cadr<value>(cadr<value>(val));
+ failable<list<value>, std::string> jsres = json::readJSON(cadr<list<std::string> >(content(res)), cx);
+ if (!hasContent(jsres))
+ return mkfailure<value, std::string>(reason(jsres));
+ const list<value> val = elementsToValues(content(jsres));
+
+ const value rval(cadr<value>(cadr<value>(val)));
+ debug(rval, "http::evalExpr::result");
+ return rval;
+}
+
+/**
+ * Find and return a header.
+ */
+const failable<std::string, std::string> header(const std::string& prefix, const list<std::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 header(prefix, cdr(h));
+ const std::string l(s.substr(prefix.length()));
+ return l.substr(0, l.find_first_of("\r\n"));
+}
+
+/**
+ * Find and return a location header.
+ */
+const failable<std::string, std::string> location(const list<std::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) {
+ 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));
+}
+
+/**
+ * Find and return a content-type header.
+ */
+const failable<std::string, std::string> contentType(const list<std::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(std::string, R)>& reduce, const R& initial, const std::string& url, const CURLHandle& ch) {
+template<typename R> const failable<list<R>, std::string> get(const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const CURLSession& ch) {
+ debug(url, "http::get::url");
const list<list<std::string> > req = mklist(list<std::string>(), list<std::string>());
return apply(req, reduce, initial, url, "GET", ch);
}
@@ -246,38 +300,41 @@ template<typename R> const failable<list<R>, std::string> get(const lambda<R(std
/**
* 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 CURLHandle& ch) {
+const failable<value, std::string> get(const std::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);
if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
+ const list<std::string> ls(reverse(cadr(content(res))));
- const std::string ct;
- if (ct.find("application/atom+xml") != std::string::npos) {
- // TODO Return an ATOM feed
+ const std::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(reverse(cadr(content(res))), os);
- return value(os.str());
+ write(ls, os);
+ const value val(os.str());
+ debug(val, "http::get::result");
+ return val;
}
/**
* HTTP POST.
*/
-const failable<value, std::string> post(const value& val, const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> post(const value& val, const std::string& url, const CURLSession& ch) {
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
- if (logContent) {
- std::cout << "content:" << std::endl;
- write(list<std::string>(content(entry)), std::cout);
- std::cout << std::endl;
- }
+ 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");
@@ -285,23 +342,24 @@ const failable<value, std::string> post(const value& val, const std::string& url
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "POST", ch);
if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
- return value(true);
+
+ // Return the new entry id from the HTTP location header
+ const failable<value, std::string> eid(entryId(location(car(content(res)))));
+ debug(eid, "http::post::result");
+ return eid;
}
/**
* HTTP PUT.
*/
-const failable<value, std::string> put(const value& val, const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> put(const value& val, const std::string& url, const CURLSession& ch) {
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
- if (logContent) {
- std::cout << "content:" << std::endl;
- write(list<std::string>(content(entry)), std::cout);
- std::cout << std::endl;
- }
+ 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");
@@ -309,17 +367,23 @@ const failable<value, std::string> put(const value& val, const std::string& url,
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "PUT", ch);
if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
+
+ debug(true, "http::put::result");
return value(true);
}
/**
* HTTP DELETE.
*/
-const failable<value, std::string> del(const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> del(const std::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);
if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
+
+ debug(true, "http::delete::result");
return value(true);
}
@@ -327,7 +391,7 @@ const failable<value, std::string> del(const std::string& url, const CURLHandle&
* HTTP client proxy function.
*/
struct proxy {
- proxy(const std::string& url, const CURLHandle& ch) : url(url), ch(ch) {
+ proxy(const std::string& url, const CURLSession& ch) : url(url), ch(ch) {
}
const value operator()(const list<value>& args) const {
@@ -338,7 +402,7 @@ struct proxy {
}
const std::string url;
- const CURLHandle& ch;
+ const CURLSession ch;
};
}
diff --git a/sca-cpp/trunk/modules/http/http-test b/sca-cpp/trunk/modules/http/http-test
index 1ab0da64b9..0aaaec48df 100755
--- a/sca-cpp/trunk/modules/http/http-test
+++ b/sca-cpp/trunk/modules/http/http-test
@@ -28,5 +28,5 @@ rc=$?
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
return $rc
diff --git a/sca-cpp/trunk/modules/http/httpd-test b/sca-cpp/trunk/modules/http/httpd-test
index 57c35c5cc9..8e1d681d84 100755
--- a/sca-cpp/trunk/modules/http/httpd-test
+++ b/sca-cpp/trunk/modules/http/httpd-test
@@ -31,7 +31,7 @@ rc=$?
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
if [ "$rc" = "0" ]; then
echo "OK"
fi
diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp
index a9ced05208..05b959f1d2 100644
--- a/sca-cpp/trunk/modules/http/httpd.hpp
+++ b/sca-cpp/trunk/modules/http/httpd.hpp
@@ -50,18 +50,13 @@
#include "list.hpp"
#include "value.hpp"
+#include "debug.hpp"
namespace tuscany {
namespace httpd {
/**
- * Set to true to log requests and content.
- */
-bool logRequests = false;
-bool logContent = false;
-
-/**
* Returns a server-scoped module configuration.
*/
template<typename C> void* makeServerConf(apr_pool_t *p, server_rec *s) {
@@ -120,7 +115,7 @@ const std::string path(const list<value>& p) {
*/
const char* optional(const char* s) {
if (s == NULL)
- return "(null)";
+ return "";
return s;
}
@@ -128,59 +123,40 @@ const std::string contentType(const request_rec* r) {
return optional(apr_table_get(r->headers_in, "Content-Type"));
}
+#ifdef _DEBUG
+
/**
- * Log HTTP request info.
+ * Debug log.
*/
-int logHeader(void* r, const char* key, const char* value) {
- std::cout << "header key: " << key << ", value: " << value << std::endl;
+int debugHeader(unused void* r, const char* key, const char* value) {
+ std::cerr << " header key: " << key << ", value: " << value << std::endl;
return 1;
}
-const bool logRequest(request_rec* r, const std::string& msg) {
- if (!logRequests)
- return true;
- std::cout << msg << std::endl;
- std::cout << "protocol: " << optional(r->protocol) << std::endl;
- std::cout << "method: " << optional(r->method) << std::endl;
- std::cout << "method number: " << r->method_number << std::endl;
- std::cout << "content type: " << contentType(r) << std::endl;
- std::cout << "content encoding: " << optional(r->content_encoding) << std::endl;
- apr_table_do(logHeader, r, r->headers_in, NULL);
- std::cout << "uri: " << optional(r->unparsed_uri) << std::endl;
- std::cout << "path: " << optional(r->uri) << std::endl;
- std::cout << "path info: " << optional(r->path_info) << std::endl;
- std::cout << "filename: " << optional(r->filename) << std::endl;
- std::cout << "path tokens: " << pathTokens(r->uri) << std::endl;
- std::cout << "args: " << optional(r->args) << std::endl;
- std::cout.flush();
+const bool debugRequest(request_rec* r, const std::string& msg) {
+ std::cerr << msg << ":" << std::endl;
+ std::cerr << " protocol: " << optional(r->protocol) << std::endl;
+ std::cerr << " method: " << optional(r->method) << std::endl;
+ std::cerr << " method number: " << r->method_number << std::endl;
+ std::cerr << " content type: " << contentType(r) << std::endl;
+ std::cerr << " content encoding: " << optional(r->content_encoding) << std::endl;
+ apr_table_do(debugHeader, r, r->headers_in, NULL);
+ std::cerr << " uri: " << optional(r->unparsed_uri) << std::endl;
+ std::cerr << " path: " << optional(r->uri) << std::endl;
+ std::cerr << " path info: " << optional(r->path_info) << std::endl;
+ std::cerr << " filename: " << optional(r->filename) << std::endl;
+ std::cerr << " path tokens: " << pathTokens(r->uri) << std::endl;
+ std::cerr << " args: " << optional(r->args) << std::endl;
return true;
}
-const bool logValue(const value& v, const std::string& msg) {
- if (!logContent)
- return true;
- std::cout<< msg << ": " << v << std::endl;
- std::cout.flush();
- return true;
-}
+#define httpdDebugRequest(r, msg) httpd::debugRequest(r, msg)
-const bool logValue(const failable<value, std::string>& v, const std::string& msg) {
- if (!logContent)
- return true;
- std::cout<< msg << ": " << v << std::endl;
- std::cout.flush();
- return true;
-}
+#else
-const bool logStrings(const list<std::string>& ls, const std::string& msg) {
- if (!logContent)
- return true;
- std::cout<< msg << ": " << std::endl;
- write(ls, std::cout);
- std::cout<< std::endl;
- std::cout.flush();
- return true;
-}
+#define httpdDebugRequest(r, msg)
+
+#endif
/**
* Returns a list of key value pairs from the args in a query string.
@@ -256,14 +232,6 @@ const char* url(const value& v, request_rec* r) {
}
/**
- * Convert an ATOM entry to a value.
- */
-const value feedEntry(const list<value>& e) {
- const list<value> v = elementsToValues(mklist<value>(caddr(e)));
- return cons(car(e), mklist<value>(cadr(e), cdr<value>(car(v))));
-}
-
-/**
* Write an HTTP result.
*/
const failable<int, std::string> writeResult(const failable<list<std::string>, std::string>& ls, const std::string& ct, request_rec* r) {
@@ -271,10 +239,7 @@ const failable<int, std::string> writeResult(const failable<list<std::string>, s
return mkfailure<int, std::string>(reason(ls));
std::ostringstream os;
write(content(ls), os);
- if (logContent) {
- std::cout<< "content: " << std::endl << os.str() << std::endl;
- std::cout.flush();
- }
+ debug(os.str(), "httpd::result");
const std::string etag(ap_md5(r->pool, (const unsigned char*)std::string(os.str()).c_str()));
const char* match = apr_table_get(r->headers_in, "If-None-Match");
@@ -283,7 +248,7 @@ const failable<int, std::string> writeResult(const failable<list<std::string>, s
r->status = HTTP_NOT_MODIFIED;
return OK;
}
- ap_set_content_type(r, ct.c_str());
+ ap_set_content_type(r, apr_pstrdup(r->pool, ct.c_str()));
ap_rputs(std::string(os.str()).c_str(), r);
return OK;
}