Correctly pass query strings through component wiring redirects and improve format of XML and JSON response documents.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1074924 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
jsdelfino 2011-02-26 20:59:35 +00:00
commit 7c018c6fb6
22 changed files with 500 additions and 221 deletions

View file

@ -45,6 +45,10 @@ const string customerElement =
"<account><id>4567</id><balance>3000</balance></account>"
"</customer>";
const string echo("<ns1:echoString xmlns:ns1=\"http://ws.apache.org/axis2/services/echo\">\n"
" <text>Hello World!</text>\n"
"</ns1:echoString>");
bool testAxiom() {
const Axis2Context ax;
{
@ -63,7 +67,7 @@ bool testAxiom() {
assert(hasContent(n));
const failable<const string> x = axiomNodeToString(content(n), ax);
assert(hasContent(x));
assert(content(x) == "<ns1:echoString xmlns:ns1=\"http://ws.apache.org/axis2/services/echo\"><text>Hello World!</text></ns1:echoString>");
assert(content(x) == echo);
const failable<const list<value> > l = axiomNodeToValues(content(n), ax);
assert(hasContent(l));
assert(l == arg);

View file

@ -240,7 +240,7 @@ public:
return true;
switch(type) {
case value::Undefined:
return true;
return v.type == value::Undefined;
case value::List:
return v.type == value::List && lst()() == v.lst()();
case value::Lambda:

View file

@ -347,6 +347,7 @@ template<typename R> const failable<R> writeXML(const lambda<R(const string&, co
xmlTextWriterPtr xml = xmlNewTextWriter(out);
if (xml == NULL)
return mkfailure<R>("xmlNewTextWriter failed");
xmlTextWriterSetIndent(xml, 1);
const failable<bool> w = write(l, xml, xmlTag);
xmlFreeTextWriter(xml);

View file

@ -36,52 +36,56 @@ ostream* writer(const string& s, ostream* os) {
return os;
}
string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">item</title>"
"<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
"<content type=\"application/xml\">"
"<item>"
"<name>Apple</name><price>$2.99</price>"
"</item>"
"</content>"
"<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
const string itemEntry(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
" <content type=\"application/xml\">\n"
" <item>\n"
" <name>Apple</name>\n"
" <price>$2.99</price>\n"
" </item>\n"
" </content>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
"</entry>\n");
string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">item</title>"
"<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
"<content type=\"text\">Apple</content>"
"<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
const string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
" <content type=\"text\">Apple</content>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
"</entry>\n");
string itemNoContentEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">item</title>"
"<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
"<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
const string itemNoContentEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
"</entry>\n");
string incompleteEntry("<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title>item</title><content type=\"text/xml\">"
"<Item xmlns=\"http://services/\">"
"<name xmlns=\"\">Orange</name>"
"<price xmlns=\"\">3.55</price>"
"</Item>"
"</content>"
"</entry>");
const string incompleteEntry("<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title>item</title>\n"
" <content type=\"text/xml\">\n"
" <Item xmlns=\"http://services/\">\n"
" <name xmlns=\"\">Orange</name>\n"
" <price xmlns=\"\">3.55</price>\n"
" </Item>\n"
" </content>\n"
"</entry>\n");
string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">item</title>"
"<id></id>"
"<content type=\"application/xml\">"
"<Item xmlns=\"http://services/\">"
"<name xmlns=\"\">Orange</name>"
"<price xmlns=\"\">3.55</price>"
"</Item>"
"</content><link href=\"\"/>"
const string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id></id>\n"
" <content type=\"application/xml\">\n"
" <Item xmlns=\"http://services/\">\n"
" <name xmlns=\"\">Orange</name>\n"
" <price xmlns=\"\">3.55</price>\n"
" </Item>\n"
" </content>\n"
" <link href=\"\"/>\n"
"</entry>\n");
bool testEntry() {
@ -133,36 +137,38 @@ bool testEntry() {
return true;
}
string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<feed xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">Feed</title>"
"<id>1234</id>"
const string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">Feed</title>\n"
" <id>1234</id>\n"
"</feed>\n");
string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<feed xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">Feed</title>"
"<id>1234</id>"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">item</title>"
"<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
"<content type=\"application/xml\">"
"<item>"
"<name>Apple</name><price>$2.99</price>"
"</item>"
"</content>"
"<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
"</entry>"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">"
"<title type=\"text\">item</title>"
"<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>"
"<content type=\"application/xml\">"
"<item>"
"<name>Orange</name><price>$3.55</price>"
"</item>"
"</content>"
"<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c\"/>"
"</entry>"
const string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">Feed</title>\n"
" <id>1234</id>\n"
" <entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
" <content type=\"application/xml\">\n"
" <item>\n"
" <name>Apple</name>\n"
" <price>$2.99</price>\n"
" </item>\n"
" </content>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
" </entry>\n"
" <entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>\n"
" <content type=\"application/xml\">\n"
" <item>\n"
" <name>Orange</name>\n"
" <price>$3.55</price>\n"
" </item>\n"
" </content>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c\"/>\n"
" </entry>\n"
"</feed>\n");
bool testFeed() {

View file

@ -620,6 +620,39 @@ const failable<size_t> recv(char* c, const size_t l, const CURLSession& cs) {
return recv(c, l, cs);
}
/**
* Filter path segment in a list of arguments.
*/
const bool filterPath(const value& arg) {
return isString(arg);
}
/**
* Filter query string arguments in a list of arguments.
*/
const bool filterQuery(const value& arg) {
return isList(arg);
}
/**
* Converts a list of key value pairs to a query string.
*/
ostringstream& queryString(const list<list<value> > args, ostringstream& os) {
if (isNil(args))
return os;
debug(car(args), "http::queryString::arg");
os << car(car(args)) << "=" << c_str(cadr(car(args)));
if (!isNil(cdr(args)))
os << "&";
return queryString(cdr(args), os);
}
const string queryString(const list<list<value> > args) {
ostringstream os;
return str(queryString(args, os));
}
/**
* HTTP client proxy function.
*/
@ -630,7 +663,13 @@ struct proxy {
const value operator()(const list<value>& args) const {
const value fun = car(args);
if (fun == "get") {
const failable<value> val = get(uri + path(cadr(args)), cs);
const list<value> lp = filter<value>(filterPath, cadr(args));
debug(lp, "http::queryString::arg");
const list<value> lq = filter<value>(filterQuery, cadr(args));
debug(lq, "http::get::query");
const value p = path(lp);
const value q = queryString(lq);
const failable<value> val = get(uri + p + (q != ""? string("?") + q : string("")), cs);
return content(val);
}
if (fun == "post") {

View file

@ -282,24 +282,6 @@ const list<list<value> > queryArgs(const request_rec* r) {
return queryArgs(r->args);
}
/**
* Converts a list of key value pairs to a query string.
*/
ostringstream& queryString(const list<list<value> > args, ostringstream& os) {
if (isNil(args))
return os;
debug(car(args), "httpd::queryString::arg");
os << car(car(args)) << "=" << c_str(cadr(car(args)));
if (!isNil(cdr(args)))
os << "&";
return queryString(cdr(args), os);
}
const string queryString(const list<list<value> > args) {
ostringstream os;
return str(queryString(args, os));
}
/**
* Converts the args received in a POST to a list of key value pairs.
*/

View file

@ -87,7 +87,7 @@ const string cookie(const string& sid) {
*/
const failable<int> login(const string& page, request_rec* r) {
const list<list<value> > largs = mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(r->uri, r))));
const string loc = httpd::url(page, r) + string("?") + httpd::queryString(largs);
const string loc = httpd::url(page, r) + string("?") + http::queryString(largs);
debug(loc, "openauth::login::uri");
return httpd::externalRedirect(loc, r);
}

View file

@ -61,7 +61,10 @@ function childElements(e) {
* Return the child text nodes of an element.
*/
function childText(e) {
return filter(function(n) { return n.nodeType == 3; }, nodeList(e.childNodes));
function trim(s) {
return s.replace(/^\s*/, '').replace(/\s*$/, '');
}
return filter(function(n) { return n.nodeType == 3 && trim(n.nodeValue) != ''; }, nodeList(e.childNodes));
}
/**

View file

@ -36,6 +36,35 @@ ostream* jsonWriter(const string& s, ostream* os) {
return os;
}
const string jscustomer("{\n"
" \"customer\":{\n"
" \"@name\":\"jdoe\",\n"
" \"address\":{\n"
" \"@city\":\"san francisco\",\n"
" \"@state\":\"ca\"\n"
" },\n"
" \"account\":{\n"
" \"id\":\"1234\",\n"
" \"@balance\":1000\n"
" }\n"
" }\n"
"}");
const string jsphones("{\n"
" \"phones\":[\"408-1234\",\n"
" \"650-1234\"\n"
" ],\n"
" \"lastName\":\"test\\u0009tab\",\n"
" \"@firstName\":\"test1\"\n"
"}");
const string jsecho("{\n"
" \"ns1:echoString\":{\n"
" \"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\n"
" \"text\":\"Hello World!\"\n"
" }\n"
"}");
bool testJSON() {
const js::JSContext cx;
@ -47,7 +76,7 @@ bool testJSON() {
ostringstream os;
writeJSON<ostream*>(jsonWriter, &os, c, cx);
assert(str(os) == "{\"customer\":{\"@name\":\"jdoe\",\"address\":{\"@city\":\"san francisco\",\"@state\":\"ca\"},\"account\":{\"id\":\"1234\",\"@balance\":1000}}}");
assert(str(os) == jscustomer);
}
{
const list<value> phones = mklist<value> (string("408-1234"), string("650-1234"));
@ -55,7 +84,7 @@ bool testJSON() {
ostringstream os;
writeJSON<ostream*>(jsonWriter, &os, l, cx);
assert(str(os) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"@firstName\":\"test1\"}");
assert(str(os) == jsphones);
istringstream is(str(os));
const list<string> il = streamList(is);
@ -70,7 +99,7 @@ bool testJSON() {
const list<value> l = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
ostringstream wos;
write(content(writeJSON(valuesToElements(l), cx)), wos);
assert(str(wos) == "{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}");
assert(str(wos) == jsecho);
istringstream is(str(wos));
const list<string> il = streamList(is);
@ -80,6 +109,86 @@ bool testJSON() {
return true;
}
const string jsitem("{\n"
" \"id\":3,\n"
" \"result\":[{\n"
" \"price\":\"$2.99\",\n"
" \"name\":\"Apple\"\n"
" },\n"
" {\n"
" \"price\":\"$3.55\",\n"
" \"name\":\"Orange\"\n"
" },\n"
" {\n"
" \"price\":\"$1.55\",\n"
" \"name\":\"Pear\"\n"
" }\n"
" ]\n"
"}");
const string jsresult("{\n"
" \"id\":1,\n"
" \"result\":[\"Service.get\",\n"
" \"Service.getTotal\"\n"
" ]\n"
"}");
const string jsfeed("{\n"
" \"id\":1,\n"
" \"result\":[\"Sample Feed\",\n"
" \"123456789\",\n"
" [\"Item\",\n"
" \"111\",\n"
" {\n"
" \"name\":\"Apple\",\n"
" \"currencyCode\":\"USD\",\n"
" \"currencySymbol\":\"$\",\n"
" \"price\":2.99\n"
" }\n"
" ],\n"
" [\"Item\",\n"
" \"222\",\n"
" {\n"
" \"name\":\"Orange\",\n"
" \"currencyCode\":\"USD\",\n"
" \"currencySymbol\":\"$\",\n"
" \"price\":3.55\n"
" }\n"
" ],\n"
" [\"Item\",\n"
" \"333\",\n"
" {\n"
" \"name\":\"Pear\",\n"
" \"currencyCode\":\"USD\",\n"
" \"currencySymbol\":\"$\",\n"
" \"price\":1.55\n"
" }\n"
" ]\n"
" ]\n"
"}");
const string jsechoreq("{\n"
" \"id\":1,\n"
" \"method\":\"echo\",\n"
" \"params\":[{\n"
" \"ns1:echoString\":{\n"
" \"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\n"
" \"text\":\"Hello World!\"\n"
" }\n"
" }\n"
" ]\n"
"}");
const string jsechores("{\n"
" \"id\":1,\n"
" \"result\":{\n"
" \"ns1:echoString\":{\n"
" \"@xmlns:ns1\":\"http://ws.apache.org/axis2/c/samples\",\n"
" \"text\":\"Hello World!\"\n"
" }\n"
" }\n"
"}");
bool testJSONRPC() {
js::JSContext cx;
{
@ -91,18 +200,16 @@ bool testJSONRPC() {
assert(assoc<value>("params", v) == mklist<value>("params", list<value>()));
}
{
const string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
const list<value> e = content(readJSON(mklist(i), cx));
const string i2("{\"id\":3,\"result\":{\"0\":{\"price\":\"$2.99\",\"name\":\"Apple\"},\"1\":{\"price\":\"$3.55\",\"name\":\"Orange\"},\"2\":{\"price\":\"$1.55\",\"name\":\"Pear\"}}}");
const list<value> e2 = content(readJSON(mklist(i), cx));
const string i2 = "{\"id\":3,\"result\":{\"0\":{\"price\":\"$2.99\",\"name\":\"Apple\"},\"1\":{\"price\":\"$3.55\",\"name\":\"Orange\"},\"2\":{\"price\":\"$1.55\",\"name\":\"Pear\"}}}";
const list<value> e = content(readJSON(mklist(jsitem), cx));
const list<value> e2 = content(readJSON(mklist(i2), cx));
assert(e == e2);
}
{
const string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
const list<value> e = content(readJSON(mklist(i), cx));
const list<value> e = content(readJSON(mklist(jsitem), cx));
ostringstream os;
write(content(writeJSON(e, cx)), os);
assert(str(os) == i);
assert(str(os) == jsitem);
const list<value> v = elementsToValues(e);
const list<value> r = valuesToElements(v);
assert(r == e);
@ -112,23 +219,22 @@ bool testJSONRPC() {
const list<value> e = valuesToElements(r);
ostringstream os;
write(content(writeJSON(e, cx)), os);
assert(str(os) == "{\"id\":1,\"result\":[\"Service.get\",\"Service.getTotal\"]}");
assert(str(os) == jsresult);
}
{
const string f("{\"id\":1,\"result\":[\"Sample Feed\",\"123456789\",[\"Item\",\"111\",{\"name\":\"Apple\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":2.99}],[\"Item\",\"222\",{\"name\":\"Orange\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":3.55}],[\"Item\",\"333\",{\"name\":\"Pear\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":1.55}]]}");
const list<value> r = content(readJSON(mklist(f), cx));
const list<value> r = content(readJSON(mklist(jsfeed), cx));
const list<value> v = elementsToValues(r);
const list<value> e = valuesToElements(v);
ostringstream os;
write(content(writeJSON(e, cx)), os);
assert(str(os) == f);
assert(str(os) == jsfeed);
}
{
const list<value> arg = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
const failable<list<string> > r = jsonRequest(1, "echo", mklist<value>(arg), cx);
ostringstream os;
write(content(r), os);
assert(str(os) == "{\"id\":1,\"method\":\"echo\",\"params\":[{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}]}");
assert(str(os) == jsechoreq);
istringstream is(str(os));
const list<string> il = streamList(is);
@ -140,7 +246,7 @@ bool testJSONRPC() {
const failable<list<string> > r = jsonResult(1, res, cx);
ostringstream os;
write(content(r), os);
assert(str(os) == "{\"id\":1,\"result\":{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/c/samples\",\"text\":\"Hello World!\"}}}");
assert(str(os) == jsechores);
istringstream is(str(os));
const list<string> il = streamList(is);

View file

@ -110,7 +110,7 @@ template<typename R> const failable<R> writeJSON(const lambda<R(const string&, c
val = OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), l, cx));
WriteContext<R> wcx(reduce, initial, cx);
if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx))
if (!JS_Stringify(cx, &val, NULL, INT_TO_JSVAL(1), writeCallback<R>, &wcx))
return mkfailure<R>("JS_Stringify failed");
return wcx.accum;
}

View file

@ -193,7 +193,7 @@ const failable<int> authorize(const list<list<value> >& args, request_rec* r, co
// Build the redirect URI
const list<list<value> > redirargs = mklist<list<value> >(mklist<value>("mod_oauth1_step", "access_token"), tok, cid, info);
const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(redirargs);
const string redir = httpd::url(r->uri, r) + string("?") + http::queryString(redirargs);
debug(redir, "modoauth1::authorize::redir");
// Lookup client app configuration
@ -203,7 +203,7 @@ const failable<int> authorize(const list<list<value> >& args, request_rec* r, co
list<value> appkey = cadr(app);
// Build and sign the request token URI
const string requri = httpd::unescape(cadr(req)) + string("&") + httpd::queryString(mklist<list<value> >(mklist<value>("oauth_callback", httpd::escape(redir))));
const string requri = httpd::unescape(cadr(req)) + string("&") + http::queryString(mklist<list<value> >(mklist<value>("oauth_callback", httpd::escape(redir))));
const list<string> srequri = sign("POST", requri, appkey, "", "");
debug(srequri, "modoauth1::authorize::srequri");
@ -236,7 +236,7 @@ const failable<int> authorize(const list<list<value> >& args, request_rec* r, co
return mkfailure<int>(reason(prc));
// Redirect to the authorize URI
const string authuri = httpd::unescape(cadr(auth)) + string("?") + httpd::queryString(mklist<list<value> >(tv));
const string authuri = httpd::unescape(cadr(auth)) + string("?") + http::queryString(mklist<list<value> >(tv));
debug(authuri, "modoauth1::authorize::authuri");
return httpd::externalRedirect(authuri, r);
}
@ -325,7 +325,7 @@ const failable<int> access_token(const list<list<value> >& args, request_rec* r,
return mkfailure<int>(reason(sv));
// Build and sign access token request URI
const string tokuri = httpd::unescape(cadr(tok)) + string("?") + httpd::queryString(mklist<list<value> >(vv));
const string tokuri = httpd::unescape(cadr(tok)) + string("?") + http::queryString(mklist<list<value> >(vv));
const list<string> stokuri = sign("POST", tokuri, appkey, cadr(tv), content(sv));
debug(stokuri, "modoauth1::access_token::stokuri");

View file

@ -141,7 +141,7 @@ const failable<int> authorize(const list<list<value> >& args, request_rec* r, co
// Build the redirect URI
const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(rargs);
const string redir = httpd::url(r->uri, r) + string("?") + http::queryString(rargs);
debug(redir, "modoauth2::authorize::redir");
// Lookup client app configuration
@ -152,7 +152,7 @@ const failable<int> authorize(const list<list<value> >& args, request_rec* r, co
// Redirect to the authorize URI
const list<list<value> > aargs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("scope", "email"), mklist<value>("redirect_uri", httpd::escape(redir)));
const string uri = httpd::unescape(cadr(auth)) + string("?") + httpd::queryString(aargs);
const string uri = httpd::unescape(cadr(auth)) + string("?") + http::queryString(aargs);
debug(uri, "modoauth2::authorize::uri");
return httpd::externalRedirect(uri, r);
}
@ -192,12 +192,12 @@ const failable<int> access_token(const list<list<value> >& args, request_rec* r,
// Build the redirect URI
const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(rargs);
const string redir = httpd::url(r->uri, r) + string("?") + http::queryString(rargs);
debug(redir, "modoauth2::access_token::redir");
// Request access token
const list<list<value> > targs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("redirect_uri", httpd::escape(redir)), mklist<value>("client_secret", cadr(appkey)), code);
const string turi = httpd::unescape(cadr(tok)) + string("?") + httpd::queryString(targs);
const string turi = httpd::unescape(cadr(tok)) + string("?") + http::queryString(targs);
debug(turi, "modoauth2::access_token::tokenuri");
const failable<value> tr = http::get(turi, sc.cs);
if (!hasContent(tr))
@ -211,7 +211,7 @@ const failable<int> access_token(const list<list<value> >& args, request_rec* r,
// Request user info
// TODO Make this step configurable
const list<list<value> > iargs = mklist<list<value> >(tv);
const string iuri = httpd::unescape(cadr(info)) + string("?") + httpd::queryString(iargs);
const string iuri = httpd::unescape(cadr(info)) + string("?") + http::queryString(iargs);
debug(iuri, "modoauth2::access_token::infouri");
const failable<value> profres = http::get(iuri, sc.cs);
if (!hasContent(profres))

View file

@ -36,49 +36,51 @@ ostream* writer(const string& s, ostream* os) {
return os;
}
string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>"
"<title>fruit</title>"
"<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
"<description>"
"<item>"
"<name>Apple</name><price>$2.99</price>"
"</item>"
"</description>"
const string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>\n"
" <title>fruit</title>\n"
" <link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>\n"
" <description>\n"
" <item>\n"
" <name>Apple</name>\n"
" <price>$2.99</price>\n"
" </item>\n"
" </description>\n"
"</item>\n");
string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>"
"<title>fruit</title>"
"<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
"<description>Apple</description>"
const string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>\n"
" <title>fruit</title>\n"
" <link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>\n"
" <description>Apple</description>\n"
"</item>\n");
string itemNoDescriptionEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>"
"<title>fruit</title>"
"<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
const string itemNoDescriptionEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>\n"
" <title>fruit</title>\n"
" <link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>\n"
"</item>\n");
string incompleteEntry("<item>"
"<title>fruit</title><description>"
"<Item xmlns=\"http://services/\">"
"<name xmlns=\"\">Orange</name>"
"<price xmlns=\"\">3.55</price>"
"</Item>"
"</description>"
const string incompleteEntry("<item>\n"
" <title>fruit</title>\n"
" <description>\n"
" <Item xmlns=\"http://services/\">\n"
" <name xmlns=\"\">Orange</name>\n"
" <price xmlns=\"\">3.55</price>\n"
" </Item>\n"
" </description>\n"
"</item>");
string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>"
"<title>fruit</title>"
"<link></link>"
"<description>"
"<Item xmlns=\"http://services/\">"
"<name xmlns=\"\">Orange</name>"
"<price xmlns=\"\">3.55</price>"
"</Item>"
"</description>"
const string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<item>\n"
" <title>fruit</title>\n"
" <link></link>\n"
" <description>\n"
" <Item xmlns=\"http://services/\">\n"
" <name xmlns=\"\">Orange</name>\n"
" <price xmlns=\"\">3.55</price>\n"
" </Item>\n"
" </description>\n"
"</item>\n");
bool testEntry() {
@ -130,40 +132,42 @@ bool testEntry() {
return true;
}
string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<rss version=\"2.0\">"
"<channel>"
"<title>Feed</title>"
"<link>1234</link>"
"<description>Feed</description>"
"</channel>"
const string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<rss version=\"2.0\">\n"
" <channel>\n"
" <title>Feed</title>\n"
" <link>1234</link>\n"
" <description>Feed</description>\n"
" </channel>\n"
"</rss>\n");
string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<rss version=\"2.0\">"
"<channel>"
"<title>Feed</title>"
"<link>1234</link>"
"<description>Feed</description>"
"<item>"
"<title>fruit</title>"
"<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
"<description>"
"<item>"
"<name>Apple</name><price>$2.99</price>"
"</item>"
"</description>"
"</item>"
"<item>"
"<title>fruit</title>"
"<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</link>"
"<description>"
"<item>"
"<name>Orange</name><price>$3.55</price>"
"</item>"
"</description>"
"</item>"
"</channel>"
const string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<rss version=\"2.0\">\n"
" <channel>\n"
" <title>Feed</title>\n"
" <link>1234</link>\n"
" <description>Feed</description>\n"
" <item>\n"
" <title>fruit</title>\n"
" <link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>\n"
" <description>\n"
" <item>\n"
" <name>Apple</name>\n"
" <price>$2.99</price>\n"
" </item>\n"
" </description>\n"
" </item>\n"
" <item>\n"
" <title>fruit</title>\n"
" <link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</link>\n"
" <description>\n"
" <item>\n"
" <name>Orange</name>\n"
" <price>$3.55</price>\n"
" </item>\n"
" </description>\n"
" </item>\n"
" </channel>\n"
"</rss>\n");
bool testFeed() {

View file

@ -47,8 +47,8 @@ bool testComponents() {
const value store = car(c);
assert(name(store) == string("Store"));
const value impl = implementation(store);
assert(uri(impl) == string("store.html"));
assert(implementationType(impl) == "t:implementation.scheme");
assert(attributeValue("script", impl) == string("store.scm"));
const value catalog = named(string("Catalog"), c);
assert(name(catalog) == string("Catalog"));

View file

@ -1,2 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111"/></entry>
<entry xmlns="http://www.w3.org/2005/Atom">
<title type="text">Item</title>
<id>111</id>
<content type="application/xml">
<item>
<name>Apple</name>
<currencyCode>USD</currencyCode>
<currencySymbol>$</currencySymbol>
<price>2.99</price>
</item>
</content>
<link href="111"/>
</entry>

View file

@ -1,2 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Sample Feed</title><id>123456789</id><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111"/></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>222</id><content type="application/xml"><item><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content><link href="222"/></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>333</id><content type="application/xml"><item><name>Pear</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>1.55</price></item></content><link href="333"/></entry></feed>
<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">Sample Feed</title>
<id>123456789</id>
<entry xmlns="http://www.w3.org/2005/Atom">
<title type="text">Item</title>
<id>111</id>
<content type="application/xml">
<item>
<name>Apple</name>
<currencyCode>USD</currencyCode>
<currencySymbol>$</currencySymbol>
<price>2.99</price>
</item>
</content>
<link href="111"/>
</entry>
<entry xmlns="http://www.w3.org/2005/Atom">
<title type="text">Item</title>
<id>222</id>
<content type="application/xml">
<item>
<name>Orange</name>
<currencyCode>USD</currencyCode>
<currencySymbol>$</currencySymbol>
<price>3.55</price>
</item>
</content>
<link href="222"/>
</entry>
<entry xmlns="http://www.w3.org/2005/Atom">
<title type="text">Item</title>
<id>333</id>
<content type="application/xml">
<item>
<name>Pear</name>
<currencyCode>USD</currencyCode>
<currencySymbol>$</currencySymbol>
<price>1.55</price>
</item>
</content>
<link href="333"/>
</entry>
</feed>

View file

@ -1 +1,13 @@
{"id":"1","result":{"host":"localhost","path":["components","property-test"],"query":{"id":"1","method":"print"}}}
{
"id":"1",
"result":{
"host":"localhost",
"path":["components",
"property-test"
],
"query":{
"id":"1",
"method":"print"
}
}
}

View file

@ -1 +1,4 @@
{"id":1,"result":"Hello"}
{
"id":1,
"result":"Hello"
}

View file

@ -125,24 +125,43 @@ const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>&
// Evaluate the GET expression
const list<value> path(pathValues(r->uri));
const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(cddr(path)))));
const list<value> params(append<value>(cddr(path), mkvalues(args)));
const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(params))));
if (!hasContent(val))
return mkfailure<int>(reason(val));
const value c = content(val);
// Write a simple value as a JSON value
if (!isList(c)) {
js::JSContext cx;
return httpd::writeResult(json::writeJSON(valuesToElements(mklist<value>(mklist<value>("value", c))), cx), "application/json", r);
}
// Write an empty list as a JSON empty value
if (isNil(c)) {
js::JSContext cx;
return httpd::writeResult(json::writeJSON(list<value>(), cx), "application/json", r);
}
// Write an assoc value as a JSON result
if (isSymbol(car<value>(c)) && !isNil(cdr<value>(c))) {
js::JSContext cx;
return httpd::writeResult(json::writeJSON(valuesToElements(mklist<value>(c)), cx), "application/json", r);
}
// Write content-type / content-list pair
if (isString(car<value>(c)) && isList(cadr<value>(c)))
if (isString(car<value>(c)) && !isNil(cdr<value>(c)) && isList(cadr<value>(c)))
return httpd::writeResult(convertValues<string>(cadr<value>(c)), car<value>(c), r);
// Write ATOM feed or entry
if (isString(car<value>(c)) && isString(cadr<value>(c))) {
// Write an ATOM feed or entry
if (isString(car<value>(c)) && !isNil(cdr<value>(c)) && isString(cadr<value>(c))) {
if (isNil(cddr(path)))
return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(c)), "application/atom+xml", r);
else
return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(c)), "application/atom+xml", r);
}
// Write JSON value
// Write any other compound value as a JSON value
js::JSContext cx;
return httpd::writeResult(json::writeJSON(valuesToElements(c), cx), "application/json", r);
}
@ -419,27 +438,29 @@ struct userPropProxy {
};
const value mkpropProxy(const value& prop) {
if (scdl::name(prop) == "host")
return lambda<value(const list<value>&)>(hostPropProxy(elementValue(prop)));
if (scdl::name(prop) == "path")
return lambda<value(const list<value>&)>(pathPropProxy(elementValue(prop)));
if (scdl::name(prop) == "query")
return lambda<value(const list<value>&)>(queryPropProxy(elementValue(prop)));
if (scdl::name(prop) == "user")
return lambda<value(const list<value>&)>(userPropProxy(elementValue(prop)));
if (scdl::name(prop) == "realm")
return lambda<value(const list<value>&)>(envPropProxy("REALM", elementValue(prop)));
if (scdl::name(prop) == "email")
return lambda<value(const list<value>&)>(envPropProxy("EMAIL", elementValue(prop)));
if (scdl::name(prop) == "nickname")
return lambda<value(const list<value>&)>(envPropProxy("NICKNAME", elementValue(prop)));
if (scdl::name(prop) == "fullname")
return lambda<value(const list<value>&)>(envPropProxy("FULLNAME", elementValue(prop)));
if (scdl::name(prop) == "firstname")
return lambda<value(const list<value>&)>(envPropProxy("FIRSTNAME", elementValue(prop)));
if (scdl::name(prop) == "lastname")
return lambda<value(const list<value>&)>(envPropProxy("LASTNAME", elementValue(prop)));
return lambda<value(const list<value>&)>(propProxy(elementValue(prop)));
const value n = scdl::name(prop);
const value v = elementHasValue(prop)? elementValue(prop):value(string(""));
if (n == "host")
return lambda<value(const list<value>&)>(hostPropProxy(v));
if (n == "path")
return lambda<value(const list<value>&)>(pathPropProxy(v));
if (n == "query")
return lambda<value(const list<value>&)>(queryPropProxy(v));
if (n == "user")
return lambda<value(const list<value>&)>(userPropProxy(v));
if (n == "realm")
return lambda<value(const list<value>&)>(envPropProxy("REALM", v));
if (n == "email")
return lambda<value(const list<value>&)>(envPropProxy("EMAIL", v));
if (n == "nickname")
return lambda<value(const list<value>&)>(envPropProxy("NICKNAME", v));
if (n == "fullname")
return lambda<value(const list<value>&)>(envPropProxy("FULLNAME", v));
if (n == "firstname")
return lambda<value(const list<value>&)>(envPropProxy("FIRSTNAME", v));
if (n == "lastname")
return lambda<value(const list<value>&)>(envPropProxy("LASTNAME", v));
return lambda<value(const list<value>&)>(propProxy(v));
}
const list<value> propProxies(const list<value>& props) {
@ -675,8 +696,10 @@ int handler(request_rec *r) {
// Get the component implementation lambda
const list<value> path(pathValues(r->uri));
const list<value> impl(assoctree<value>(cadr(path), usevh? vhc.vsc.implTree : sc.implTree));
if (isNil(impl))
return httpd::reportStatus(mkfailure<int>(string("Couldn't find component implementation: ") + cadr(path)));
if (isNil(impl)) {
mkfailure<int>(string("Couldn't find component implementation: ") + cadr(path));
return HTTP_NOT_FOUND;
}
// Handle HTTP method
const lambda<value(const list<value>&)> l(cadr<value>(impl));

View file

@ -107,7 +107,7 @@ int translateReference(const ServerConf& sc, request_rec *r) {
if (useModProxy) {
// Build proxy URI
// current request's protocol scheme, reference target uri and request path info
string turi = httpd::scheme(r) + substr(target, find(target, "://")) + path(pathInfo);
string turi = httpd::scheme(r) + substr(target, find(target, "://")) + path(pathInfo) + (r->args != NULL? string("?") + r->args : string(""));
r->filename = apr_pstrdup(r->pool, c_str(string("proxy:") + turi));
debug(r->filename, "modwiring::translateReference::filename");
r->proxyreq = PROXYREQ_REVERSE;
@ -124,7 +124,7 @@ int translateReference(const ServerConf& sc, request_rec *r) {
// Route to a relative target URI using a local internal redirect
// /components/, target component name and request path info
const value tname = substr(target, 0, find(target, '/'));
const string tpath = path(cons(tname, pathInfo));
const string tpath = path(cons(tname, pathInfo)) + (r->args != NULL? string("?") + r->args : string(""));
r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/components") + tpath));
debug(r->filename, "modwiring::translateReference::filename");
r->handler = "mod_tuscany_wiring";

View file

@ -1 +1,22 @@
{"id":1,"result":[{"name":"Apple","currencyCode":"USD","currencySymbol":"$","price":2.99},{"name":"Orange","currencyCode":"USD","currencySymbol":"$","price":3.55},{"name":"Pear","currencyCode":"USD","currencySymbol":"$","price":1.55}]}
{
"id":1,
"result":[{
"name":"Apple",
"currencyCode":"USD",
"currencySymbol":"$",
"price":2.99
},
{
"name":"Orange",
"currencyCode":"USD",
"currencySymbol":"$",
"price":3.55
},
{
"name":"Pear",
"currencyCode":"USD",
"currencySymbol":"$",
"price":1.55
}
]
}

View file

@ -1 +1,22 @@
{"id":1,"result":[{"name":"Mango","currencyCode":"USD","currencySymbol":"$","price":2.99},{"name":"Passion","currencyCode":"USD","currencySymbol":"$","price":3.55},{"name":"Kiwi","currencyCode":"USD","currencySymbol":"$","price":1.55}]}
{
"id":1,
"result":[{
"name":"Mango",
"currencyCode":"USD",
"currencySymbol":"$",
"price":2.99
},
{
"name":"Passion",
"currencyCode":"USD",
"currencySymbol":"$",
"price":3.55
},
{
"name":"Kiwi",
"currencyCode":"USD",
"currencySymbol":"$",
"price":1.55
}
]
}