Fix roundtripping of JSON arrays, booleans and numbers, ATOM / RSS feed detection, and support REST-style JSON and XML payloads in server handler and client proxy.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1052432 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e5f662ac57
commit
74aef8947b
15 changed files with 183 additions and 31 deletions
|
@ -110,4 +110,6 @@ xml-value
|
|||
value-xml
|
||||
json-value
|
||||
value-json
|
||||
element-value
|
||||
value-element
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ const value elementHasValue(const list<value>& l) {
|
|||
if (isSymbol(car(r)))
|
||||
return false;
|
||||
if(isList(car(r)) && !isNil((list<value>)car(r)) && isSymbol(car<value>(car(r))))
|
||||
return false;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ const value valueToElement(const value& t) {
|
|||
// Convert a name value pair
|
||||
if (isList(t) && !isNil((list<value>)t) && isSymbol(car<value>(t))) {
|
||||
const value n = car<value>(t);
|
||||
const value v = cadr<value>(t);
|
||||
const value v = isNil(cdr<value>(t))? value() : cadr<value>(t);
|
||||
|
||||
// Convert a single value to an attribute or an element
|
||||
if (!isList(v)) {
|
||||
|
|
|
@ -82,7 +82,7 @@ ostream& operator<<(ostream& os, const long unsigned int v) {
|
|||
}
|
||||
|
||||
ostream& operator<<(ostream& os, const double v) {
|
||||
return os.vprintf("%g", v);
|
||||
return os.vprintf("%.10g", v);
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream& os, const void* v) {
|
||||
|
|
|
@ -57,12 +57,12 @@ const list<value> entriesElementsToValues(const list<value>& e) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return true if a list of strings contains an RSS feed.
|
||||
* Return true if a list of strings contains an ATOM feed.
|
||||
*/
|
||||
const bool isATOMFeed(const list<string>& ls) {
|
||||
if (!isXML(ls))
|
||||
return false;
|
||||
return contains(car(ls), "<feed");
|
||||
return contains(car(ls), "<feed") && contains(car(ls), "=\"http://www.w3.org/2005/Atom\"");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +179,9 @@ const failable<list<string> > writeATOMFeed(const list<value>& l) {
|
|||
* Convert an ATOM entry containing a value to an ATOM entry containing an item element.
|
||||
*/
|
||||
const list<value> entryValuesToElements(const list<value> val) {
|
||||
return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(cons<value>("item", (list<value>)caddr(val))))));
|
||||
if (isList(caddr(val)))
|
||||
return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(cons<value>("item", (list<value>)caddr(val))))));
|
||||
return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(mklist<value>("item", caddr(val))))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,7 +36,7 @@ const bool testGet(const string& url, const string& ca = "", const string& cert
|
|||
CURLSession ch(ca, cert, key);
|
||||
const failable<value> val = get(url, ch);
|
||||
assert(hasContent(val));
|
||||
cout << val << endl;
|
||||
cout << content(val) << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -399,10 +399,12 @@ const failable<value> get(const string& url, const CURLSession& cs) {
|
|||
const failable<list<list<string> > > res = get<list<string> >(rcons<string>, list<string>(), url, cs);
|
||||
if (!hasContent(res))
|
||||
return mkfailure<value>(reason(res));
|
||||
const list<string> ls(reverse(cadr(content(res))));
|
||||
|
||||
const string ct(content(contentType(car(content(res)))));
|
||||
debug(ct, "http::get::contentType");
|
||||
|
||||
const list<string> ls(reverse(cadr(content(res))));
|
||||
debug(ls, "http::get::content");
|
||||
|
||||
if (contains(ct, "application/atom+xml;type=entry")) {
|
||||
// Read an ATOM entry
|
||||
const value val(atom::entryValue(content(atom::readATOMEntry(ls))));
|
||||
|
@ -421,15 +423,22 @@ const failable<value> get(const string& url, const CURLSession& cs) {
|
|||
debug(val, "http::get::result");
|
||||
return val;
|
||||
}
|
||||
if (contains(ct, "text/javascript") || contains(ct, "application/json")) {
|
||||
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))));
|
||||
debug(val, "http::get::result");
|
||||
return val;
|
||||
}
|
||||
if (contains(ct, "text/xml") || contains(ct, "application/xml") || isXML(ls)) {
|
||||
// Read an XML document
|
||||
const value val(elementsToValues(readXML(ls)));
|
||||
debug(val, "http::get::result");
|
||||
return val;
|
||||
}
|
||||
|
||||
// Return the content as a list of values
|
||||
const value val(mkvalues(ls));
|
||||
// Return the content type and a content list
|
||||
const value val(mklist<value>(ct, mkvalues(ls)));
|
||||
debug(val, "http::get::result");
|
||||
return val;
|
||||
}
|
||||
|
@ -617,11 +626,26 @@ const failable<size_t> recv(char* c, const size_t l, const CURLSession& cs) {
|
|||
struct proxy {
|
||||
proxy(const string& uri, const string& ca, const string& cert, const string& key, const gc_pool& p) : p(p), uri(uri), ca(ca), cert(cert), key(key), cs(*(new (gc_new<CURLSession>(p)) CURLSession(ca, cert, key))) {
|
||||
}
|
||||
|
||||
|
||||
const value operator()(const list<value>& args) const {
|
||||
failable<value> val = evalExpr(args, uri, cs);
|
||||
if (!hasContent(val))
|
||||
return value();
|
||||
const value fun = car(args);
|
||||
if (fun == "get") {
|
||||
const failable<value> val = get(uri + path(cadr(args)), cs);
|
||||
return content(val);
|
||||
}
|
||||
if (fun == "post") {
|
||||
const failable<value> val = post(caddr(args), uri + path(cadr(args)), cs);
|
||||
return content(val);
|
||||
}
|
||||
if (fun == "put") {
|
||||
const failable<value> val = put(caddr(args), uri + path(cadr(args)), cs);
|
||||
return content(val);
|
||||
}
|
||||
if (fun == "delete") {
|
||||
const failable<value> val = del(uri + path(cadr(args)), cs);
|
||||
return content(val);
|
||||
}
|
||||
const failable<value> val = evalExpr(args, uri, cs);
|
||||
return content(val);
|
||||
}
|
||||
|
||||
|
|
|
@ -229,7 +229,9 @@ const jsval valueToJSVal(const value& val, const js::JSContext& cx) {
|
|||
JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const js::JSContext& cx);
|
||||
|
||||
switch(type(val)) {
|
||||
case value::String:
|
||||
case value::String: {
|
||||
return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, c_str((string)val)));
|
||||
}
|
||||
case value::Symbol: {
|
||||
return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, c_str((string)val)));
|
||||
}
|
||||
|
|
|
@ -36,6 +36,16 @@
|
|||
namespace tuscany {
|
||||
namespace json {
|
||||
|
||||
/**
|
||||
* Return true if a list of strings contains a JSON document.
|
||||
*/
|
||||
const bool isJSON(const list<string>& ls) {
|
||||
if (isNil(ls))
|
||||
return false;
|
||||
const string s = substr(car(ls), 0, 1);
|
||||
return s == "[" || s == "{";
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes JSON strings and populates a JS object.
|
||||
*/
|
||||
|
@ -93,7 +103,11 @@ template<typename R> JSBool writeCallback(const jschar *buf, uint32 len, void *d
|
|||
* Convert a list of values to a JSON document.
|
||||
*/
|
||||
template<typename R> const failable<R> writeJSON(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const js::JSContext& cx) {
|
||||
jsval val = OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), l, cx));
|
||||
jsval val;
|
||||
if (js::isJSArray(l))
|
||||
val = OBJECT_TO_JSVAL(valuesToJSElements(JS_NewArrayObject(cx, 0, NULL), l, 0, cx));
|
||||
else
|
||||
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))
|
||||
|
|
|
@ -222,7 +222,6 @@ const list<value> pyTupleToValuesHelper(PyObject* o, const size_t i, const size_
|
|||
}
|
||||
|
||||
const list<value> pyTupleToValues(PyObject* o) {
|
||||
debug(pyRepr(o), "python::pyTupleToValues");
|
||||
return pyTupleToValuesHelper(o, 0, PyTuple_Size(o));
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ const list<value> entriesElementsToValues(const list<value>& e) {
|
|||
const bool isRSSFeed(const list<string>& ls) {
|
||||
if (!isXML(ls))
|
||||
return false;
|
||||
return contains(car(ls), "<rss");
|
||||
return contains(car(ls), "<rss") && contains(car(ls), "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,11 +22,17 @@ eval_test_SOURCES = eval-test.cpp
|
|||
|
||||
eval_shell_SOURCES = eval-shell.cpp
|
||||
|
||||
value_element_SOURCES = value-element.cpp
|
||||
value_element_LDFLAGS =
|
||||
|
||||
element_value_SOURCES = element-value.cpp
|
||||
element_value_LDFLAGS =
|
||||
|
||||
xml_value_SOURCES = xml-value.cpp
|
||||
xml_value_LDFLAGS = -lxml2
|
||||
xml_value_LDFLAGS = -lxml2
|
||||
|
||||
value_xml_SOURCES = value-xml.cpp
|
||||
value_xml_LDFLAGS = -lxml2
|
||||
value_xml_LDFLAGS = -lxml2
|
||||
|
||||
json_value_SOURCES = json-value.cpp
|
||||
json_value_LDFLAGS = -lmozjs
|
||||
|
@ -34,5 +40,5 @@ json_value_LDFLAGS = -lmozjs
|
|||
value_json_SOURCES = value-json.cpp
|
||||
value_json_LDFLAGS = -lmozjs
|
||||
|
||||
noinst_PROGRAMS = eval-test eval-shell xml-value value-xml json-value value-json
|
||||
noinst_PROGRAMS = eval-test eval-shell element-value value-element xml-value value-xml json-value value-json
|
||||
TESTS = eval-test
|
||||
|
|
46
sca-cpp/trunk/modules/scheme/element-value.cpp
Normal file
46
sca-cpp/trunk/modules/scheme/element-value.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* $Rev$ $Date$ */
|
||||
|
||||
/**
|
||||
* Convert a scheme value representing an element to a value.
|
||||
*/
|
||||
|
||||
#include "fstream.hpp"
|
||||
#include "string.hpp"
|
||||
#include "element.hpp"
|
||||
#include "eval.hpp"
|
||||
|
||||
namespace tuscany {
|
||||
namespace scheme {
|
||||
|
||||
int elementValue() {
|
||||
const value v = elementsToValues(readValue(cin));
|
||||
cout << writeValue(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
return tuscany::scheme::elementValue();
|
||||
}
|
||||
|
|
@ -154,7 +154,12 @@ const list<char> readIdentifierHelper(const list<char>& listSoFar, istream& in)
|
|||
}
|
||||
|
||||
const value readIdentifier(const char chr, istream& in) {
|
||||
return c_str(listToString(readIdentifierHelper(mklist(chr), in)));
|
||||
const value val = c_str(listToString(readIdentifierHelper(mklist(chr), in)));
|
||||
if (val == "false")
|
||||
return value((bool)false);
|
||||
if (val == "true")
|
||||
return value((bool)true);
|
||||
return val;
|
||||
}
|
||||
|
||||
const list<char> readStringHelper(const list<char>& listSoFar, istream& in) {
|
||||
|
|
46
sca-cpp/trunk/modules/scheme/value-element.cpp
Normal file
46
sca-cpp/trunk/modules/scheme/value-element.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* $Rev$ $Date$ */
|
||||
|
||||
/**
|
||||
* Convert a scheme value to a value representing an element.
|
||||
*/
|
||||
|
||||
#include "fstream.hpp"
|
||||
#include "string.hpp"
|
||||
#include "element.hpp"
|
||||
#include "eval.hpp"
|
||||
|
||||
namespace tuscany {
|
||||
namespace scheme {
|
||||
|
||||
int valueElement() {
|
||||
const value v = valuesToElements(readValue(cin));
|
||||
cout << writeValue(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
return tuscany::scheme::valueElement();
|
||||
}
|
||||
|
|
@ -130,15 +130,21 @@ const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>&
|
|||
return mkfailure<int>(reason(val));
|
||||
const value c = content(val);
|
||||
|
||||
// Write returned content-type / content-list pair
|
||||
if (isList(cadr<value>(c)))
|
||||
// Write content-type / content-list pair
|
||||
if (isString(car<value>(c)) && isList(cadr<value>(c)))
|
||||
return httpd::writeResult(convertValues<string>(cadr<value>(c)), car<value>(c), r);
|
||||
|
||||
// Write returned ATOM feed or entry
|
||||
if (isNil(cddr(path)))
|
||||
return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(c)), "application/atom+xml;type=feed", r);
|
||||
else
|
||||
return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(c)), "application/atom+xml;type=entry", r);
|
||||
// Write ATOM feed or entry
|
||||
if (isString(car<value>(c)) && isString(cadr<value>(c))) {
|
||||
if (isNil(cddr(path)))
|
||||
return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(c)), "application/atom+xml;type=feed", r);
|
||||
else
|
||||
return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(c)), "application/atom+xml;type=entry", r);
|
||||
}
|
||||
|
||||
// Write JSON value
|
||||
js::JSContext cx;
|
||||
return httpd::writeResult(json::writeJSON(valuesToElements(c), cx), "application/json", r);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue