From 6b94d489977c1cb2eeddded3ee329fe6b9605d5c Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sun, 1 Nov 2009 05:25:14 +0000 Subject: Minor refactoring of read/write functions and primitive procs. Added functions to help store data in memcached. Fixes to HTTP support and more tests. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@831640 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/sca/modules/Makefile.am | 2 +- cpp/sca/modules/atom/atom-test.cpp | 18 +- cpp/sca/modules/atom/atom.hpp | 50 ++- cpp/sca/modules/cache/Makefile.am | 26 ++ cpp/sca/modules/cache/cache-test.cpp | 59 +++ cpp/sca/modules/cache/cache.hpp | 125 ++++++ cpp/sca/modules/cache/memcached-test | 31 ++ cpp/sca/modules/eval/driver.hpp | 23 +- cpp/sca/modules/eval/environment.hpp | 8 - cpp/sca/modules/eval/eval-test.cpp | 30 +- cpp/sca/modules/eval/eval.hpp | 2 +- cpp/sca/modules/eval/io.hpp | 188 +++++++++ cpp/sca/modules/eval/primitive.hpp | 68 ++- cpp/sca/modules/eval/read.hpp | 184 -------- cpp/sca/modules/http/conf/mime.types | 607 +++++++++++++++++++++++++++ cpp/sca/modules/http/curl-test.cpp | 164 +++++++- cpp/sca/modules/http/curl.hpp | 234 +++++++++-- cpp/sca/modules/http/htdocs/entry.xml | 2 + cpp/sca/modules/http/htdocs/feed.xml | 2 + cpp/sca/modules/http/htdocs/index.html | 21 + cpp/sca/modules/http/htdocs/json-request.txt | 1 + cpp/sca/modules/http/htdocs/json-result.txt | 1 + cpp/sca/modules/http/http-test | 22 +- cpp/sca/modules/http/httpd-conf | 36 ++ cpp/sca/modules/http/httpd-test | 57 ++- cpp/sca/modules/http/httpd-test.scm | 33 ++ cpp/sca/modules/http/mod.cpp | 223 +++++----- cpp/sca/modules/http/test-conf/mime.types | 607 --------------------------- cpp/sca/modules/http/test-htdocs/index.html | 21 - cpp/sca/modules/json/json-test.cpp | 22 +- cpp/sca/modules/json/json.hpp | 94 +++-- 31 files changed, 1832 insertions(+), 1129 deletions(-) create mode 100644 cpp/sca/modules/cache/Makefile.am create mode 100644 cpp/sca/modules/cache/cache-test.cpp create mode 100644 cpp/sca/modules/cache/cache.hpp create mode 100755 cpp/sca/modules/cache/memcached-test create mode 100644 cpp/sca/modules/eval/io.hpp delete mode 100644 cpp/sca/modules/eval/read.hpp create mode 100644 cpp/sca/modules/http/conf/mime.types create mode 100644 cpp/sca/modules/http/htdocs/entry.xml create mode 100644 cpp/sca/modules/http/htdocs/feed.xml create mode 100644 cpp/sca/modules/http/htdocs/index.html create mode 100644 cpp/sca/modules/http/htdocs/json-request.txt create mode 100644 cpp/sca/modules/http/htdocs/json-result.txt create mode 100755 cpp/sca/modules/http/httpd-conf create mode 100644 cpp/sca/modules/http/httpd-test.scm delete mode 100644 cpp/sca/modules/http/test-conf/mime.types delete mode 100644 cpp/sca/modules/http/test-htdocs/index.html (limited to 'cpp/sca/modules') diff --git a/cpp/sca/modules/Makefile.am b/cpp/sca/modules/Makefile.am index fef28b5120..dd085903f0 100644 --- a/cpp/sca/modules/Makefile.am +++ b/cpp/sca/modules/Makefile.am @@ -15,5 +15,5 @@ # specific language governing permissions and limitations # under the License. -SUBDIRS = atom eval http json +SUBDIRS = atom cache eval http json diff --git a/cpp/sca/modules/atom/atom-test.cpp b/cpp/sca/modules/atom/atom-test.cpp index 618f534001..7c14b954a0 100644 --- a/cpp/sca/modules/atom/atom-test.cpp +++ b/cpp/sca/modules/atom/atom-test.cpp @@ -33,7 +33,7 @@ namespace tuscany { namespace atom { -std::ostringstream* writer(std::ostringstream* os, const std::string& s) { +std::ostringstream* writer(const std::string& s, std::ostringstream* os) { (*os) << s; return os; } @@ -78,19 +78,19 @@ bool testEntry() { << (list() << element << "price" << std::string("$2.99")); const list a = mklist(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); std::ostringstream os; - writeEntry(writer, &os, a); + writeATOMEntry(writer, &os, a); assert(os.str() == itemEntry); } { const list a = readEntry(mklist(itemEntry)); std::ostringstream os; - writeEntry(writer, &os, a); + writeATOMEntry(writer, &os, a); assert(os.str() == itemEntry); } { const list a = readEntry(mklist(incompleteEntry)); std::ostringstream os; - writeEntry(writer, &os, a); + writeATOMEntry(writer, &os, a); assert(os.str() == completedEntry); } return true; @@ -131,13 +131,13 @@ std::string itemFeed("\n" bool testFeed() { { std::ostringstream os; - writeFeed(writer, &os, mklist("Feed", "1234")); + writeATOMFeed(writer, &os, mklist("Feed", "1234")); assert(os.str() == emptyFeed); } { const list a = readFeed(mklist(emptyFeed)); std::ostringstream os; - writeFeed(writer, &os, a); + writeATOMFeed(writer, &os, a); assert(os.str() == emptyFeed); } { @@ -152,7 +152,7 @@ bool testFeed() { << (list() << element << "price" << "$3.55"))); const list a = cons("Feed", cons("1234", i)); std::ostringstream os; - writeFeed(writer, &os, a); + writeATOMFeed(writer, &os, a); assert(os.str() == itemFeed); } { @@ -167,13 +167,13 @@ bool testFeed() { << (list() << "price" << "$3.55"))); const list a = cons("Feed", cons("1234", i)); std::ostringstream os; - writeFeed(writer, &os, a); + writeATOMFeed(writer, &os, a); assert(os.str() == itemFeed); } { const list a = readFeed(mklist(itemFeed)); std::ostringstream os; - writeFeed(writer, &os, a); + writeATOMFeed(writer, &os, a); assert(os.str() == itemFeed); } return true; diff --git a/cpp/sca/modules/atom/atom.hpp b/cpp/sca/modules/atom/atom.hpp index 78b60da70f..2077081320 100644 --- a/cpp/sca/modules/atom/atom.hpp +++ b/cpp/sca/modules/atom/atom.hpp @@ -38,7 +38,7 @@ namespace atom { /** * Convert a list of elements to a list of values representing an ATOM entry. */ -const list entry(const list& e) { +const list entryValue(const list& e) { const list lt = filter(selector(mklist(element, "title")), e); const value t = isNil(lt)? value(std::string("")) : elementValue(car(lt)); const list li = filter(selector(mklist(element, "id")), e); @@ -50,10 +50,10 @@ const list entry(const list& e) { /** * Convert a list of elements to a list of values representing ATOM entries. */ -const list entries(const list& e) { +const list entriesValues(const list& e) { if (isNil(e)) return list(); - return cons(entry(car(e)), entries(cdr(e))); + return cons(entryValue(car(e)), entriesValues(cdr(e))); } /** @@ -63,7 +63,7 @@ const failable, std::string> readEntry(const list& ilis const list e = readXML(ilist); if (isNil(e)) return std::string("Empty entry"); - return entry(car(e)); + return entryValue(car(e)); } /** @@ -78,7 +78,7 @@ const failable, std::string> readFeed(const list& ilist const list e = filter(selector(mklist(element, "entry")), car(f)); if (isNil(e)) return mklist(elementValue(car(t)), elementValue(car(i))); - return cons(elementValue(car(t)), cons(elementValue(car(i)), entries(e))); + return cons(elementValue(car(t)), cons(elementValue(car(i)), entriesValues(e))); } /** @@ -107,20 +107,12 @@ const list entriesElements(const list& l) { * Convert a list of values representing an ATOM entry to an ATOM entry. * The first two values in the list are the entry id and title. */ -template const failable writeEntry(const lambda& reduce, const R& initial, const list& l) { +template const failable writeATOMEntry(const lambda& reduce, const R& initial, const list& l) { return writeXML(reduce, initial, mklist(entryElement(l))); } -/** - * Convert a list of values representing an ATOM entry to a list of strings. - * The first two values in the list are the entry id and title. - */ -const list writeStrings(const list& listSoFar, const std::string& s) { - return cons(s, listSoFar); -} - -const failable, std::string> writeEntry(const list& l) { - const failable, std::string> ls = writeEntry >(writeStrings, list(), l); +const failable, std::string> writeATOMEntry(const list& l) { + const failable, std::string> ls = writeATOMEntry >(rcons, list(), l); if (!hasValue(ls)) return ls; return reverse(list(ls)); @@ -130,7 +122,7 @@ const failable, std::string> writeEntry(const list& l) * Convert a list of values representing an ATOM feed to an ATOM feed. * The first two values in the list are the feed id and title. */ -template const failable writeFeed(const lambda& reduce, const R& initial, const list& l) { +template const failable writeATOMFeed(const lambda& reduce, const R& initial, const list& l) { const list f = list() << element << "feed" << (list() << attribute << "xmlns" << "http://www.w3.org/2005/Atom") << (list() << element << "title" << (list() << attribute << "type" << "text") << car(l)) @@ -145,13 +137,33 @@ template const failable writeFeed(const lambda, std::string> writeFeed(const list& l) { - const failable, std::string> ls = writeFeed >(writeStrings, list(), l); +const failable, std::string> writeATOMFeed(const list& l) { + const failable, std::string> ls = writeATOMFeed >(rcons, list(), l); if (!hasValue(ls)) return ls; return reverse(list(ls)); } +/** + * Convert an ATOM entry containing a value to an ATOM entry containing an item element. + */ +const list entryValuesToElements(const list val) { + return cons(car(val), cons(cadr(val), valuesToElements(mklist(cons("item", (list)caddr(val)))))); +} + +/** + * Convert an ATOM feed containing values to an ATOM feed containing elements. + */ +const list feedValuesToElementsLoop(const list val) { + if (isNil(val)) + return list(); + return cons(entryValuesToElements(car(val)), feedValuesToElementsLoop(cdr(val))); +} + +const list feedValuesToElements(const list& val) { + return cons(car(val), cons(cadr(val), feedValuesToElementsLoop(cddr(val)))); +} + } } diff --git a/cpp/sca/modules/cache/Makefile.am b/cpp/sca/modules/cache/Makefile.am new file mode 100644 index 0000000000..581b8b6682 --- /dev/null +++ b/cpp/sca/modules/cache/Makefile.am @@ -0,0 +1,26 @@ +# 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. + +noinst_PROGRAMS = cache-test + +INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${APR_INCLUDE} + +cache_test_SOURCES = cache-test.cpp +cache_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 + +TESTS = memcached-test + diff --git a/cpp/sca/modules/cache/cache-test.cpp b/cpp/sca/modules/cache/cache-test.cpp new file mode 100644 index 0000000000..776ac72363 --- /dev/null +++ b/cpp/sca/modules/cache/cache-test.cpp @@ -0,0 +1,59 @@ +/* + * 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$ */ + +/** + * Test Memcached access functions. + */ + +#include +#include +#include +#include "cache.hpp" + +namespace tuscany { +namespace cache { + +bool testCache() { + Cache cache; + addServer("localhost", 11311, cache); + + assert(hasValue(post("a", "AAA", cache))); + assert(get("a", cache) == value(std::string("AAA"))); + assert(hasValue(put("a", "aaa", cache))); + assert(get("a", cache) == value(std::string("aaa"))); + assert(hasValue(del("a", cache))); + assert(!hasValue(get("a", cache))); + + return true; +} + +} +} + +int main() { + std::cout << "Testing..." << std::endl; + + tuscany::cache::testCache(); + + std::cout << "OK" << std::endl; + + return 0; +} diff --git a/cpp/sca/modules/cache/cache.hpp b/cpp/sca/modules/cache/cache.hpp new file mode 100644 index 0000000000..d4a24ca3d9 --- /dev/null +++ b/cpp/sca/modules/cache/cache.hpp @@ -0,0 +1,125 @@ +/* + * 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$ */ + +#ifndef tuscany_cache_hpp +#define tuscany_cache_hpp + +/** + * Memcached access functions. + */ + +#include "apr.h" +#include "apu.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_memcache.h" +#include "apr_network_io.h" + +#include +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" + +namespace tuscany { +namespace cache { + +class Cache { +public: + Cache() { + apr_pool_create(&pool, NULL); + apr_memcache_create(pool, 1, 0, &mc); + } + ~Cache() { + apr_pool_destroy(pool); + } + + operator apr_memcache_t*() const { + return mc; + } + + operator apr_pool_t*() const { + return pool; + } + +private: + apr_pool_t* pool; + apr_memcache_t* mc; + +}; + +const failable addServer(const std::string& host, const int port, Cache& cache) { + apr_memcache_server_t *server; + const apr_status_t sc = apr_memcache_server_create(cache, host.c_str(), port, 0, 1, 1, 60, &server); + if (sc != APR_SUCCESS) + return "Could not create server"; + const apr_status_t as = apr_memcache_add_server(cache, server); + if (as != APR_SUCCESS) + return "Could not add server"; + return true; +} + +const failable post(const value& key, const value& val, Cache& cache) { + const std::string v(val); + const apr_status_t rc = apr_memcache_add(cache, std::string(key).c_str(), const_cast(v.c_str()), v.size(), 0, 27); + if (rc != APR_SUCCESS) + return "Could not add entry"; + return true; +} + +const failable put(const value& key, const value& val, Cache& cache) { + const std::string v(val); + const apr_status_t rc = apr_memcache_replace(cache, std::string(key).c_str(), const_cast(v.c_str()), v.size(), 0, 27); + if (rc != APR_SUCCESS) + return "Could not add entry"; + return true; +} + +const failable get(const value& key, Cache& cache) { + apr_pool_t* vpool; + const apr_status_t pc = apr_pool_create(&vpool, cache); + if (pc != APR_SUCCESS) + return std::string("Could not allocate memory"); + + char *data; + apr_size_t size; + const apr_status_t rc = apr_memcache_getp(cache, cache, std::string(key).c_str(), &data, &size, NULL); + if (rc != APR_SUCCESS) { + apr_pool_destroy(vpool); + return std::string("Could not get entry"); + } + + const value val(std::string(data, size)); + apr_pool_destroy(vpool); + return val; +} + +const failable del(const value& key, Cache& cache) { + const apr_status_t rc = apr_memcache_delete(cache, std::string(key).c_str(), 0); + if (rc != APR_SUCCESS) + return "Could not add entry"; + return true; +} + +} +} + +#endif /* tuscany_cache_hpp */ diff --git a/cpp/sca/modules/cache/memcached-test b/cpp/sca/modules/cache/memcached-test new file mode 100755 index 0000000000..2f9870a49b --- /dev/null +++ b/cpp/sca/modules/cache/memcached-test @@ -0,0 +1,31 @@ +#!/bin/sh + +# 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. + +# Setup +cmd="memcached -l 127.0.0.1 -m 4 -p 11311" +$cmd & +sleep 1 + +# Test +./cache-test +rc=$? + +# Cleanup +ps -f | grep -v grep | grep "$cmd" | awk '{ print $2 }' | xargs kill +return $rc diff --git a/cpp/sca/modules/eval/driver.hpp b/cpp/sca/modules/eval/driver.hpp index f777973ebf..4c69ecb0a1 100644 --- a/cpp/sca/modules/eval/driver.hpp +++ b/cpp/sca/modules/eval/driver.hpp @@ -36,40 +36,39 @@ namespace eval { const std::string evalOutputPrompt("; "); const std::string evalInputPrompt("=> "); -const bool promptForInput(std::ostream& out, const std::string str) { +const bool promptForInput(const std::string str, std::ostream& out) { out << "\n\n" << str; return true; } -const bool announceOutput(std::ostream& out, const std::string str) { +const bool announceOutput(const std::string str, std::ostream& out) { out << "\n" << str; return true; } -const bool userPrint(std::ostream& out, const value object) { - if(isCompoundProcedure(object)) - out << mklist(compoundProcedureSymbol, procedureParameters(object), procedureBody(object), ""); - out << object; +const bool userPrint(const value val, std::ostream& out) { + if(isCompoundProcedure(val)) + writeValue(mklist(compoundProcedureSymbol, procedureParameters(val), procedureBody(val), ""), out); + writeValue(val, out); return true; } const value evalDriverLoop(std::istream& in, std::ostream& out, Env& globalEnv, const gc_pool& pool) { - promptForInput(out, evalInputPrompt); - value input = read(in); + promptForInput(evalInputPrompt, out); + value input = readValue(in); if (isNil(input)) return input; const value output = evalExpr(input, globalEnv, pool); - announceOutput(out, evalOutputPrompt); - userPrint(out, output); + announceOutput(evalOutputPrompt, out); + userPrint(output, out); return evalDriverLoop(in, out, globalEnv, pool); } const bool evalDriverRun(std::istream& in, std::ostream& out) { gc_pool pool; - setupEvalOut(out); + setupDisplay(out); Env globalEnv = setupEnvironment(pool); evalDriverLoop(in, out, globalEnv, pool); - cleanupEnvironment(globalEnv); return true; } diff --git a/cpp/sca/modules/eval/environment.hpp b/cpp/sca/modules/eval/environment.hpp index 90a1d88854..fa9667b1ba 100644 --- a/cpp/sca/modules/eval/environment.hpp +++ b/cpp/sca/modules/eval/environment.hpp @@ -151,14 +151,6 @@ const Env setupEnvironment(const gc_pool& pool) { return env; } -const bool cleanupEnvironment(Env& env) { - if (isNil(env)) - return true; - *firstFrame(env) = list(); - Env enclosing = enclosingEnvironment(env); - return cleanupEnvironment(enclosing); -} - const value lookupEnvLoop(const value& var, const Env& env); const value lookupEnvScan(const value& var, const list& vars, const list& vals, const Env& env) { diff --git a/cpp/sca/modules/eval/eval-test.cpp b/cpp/sca/modules/eval/eval-test.cpp index 584c8470b1..7d92c79eba 100644 --- a/cpp/sca/modules/eval/eval-test.cpp +++ b/cpp/sca/modules/eval/eval-test.cpp @@ -39,7 +39,6 @@ bool testEnv() { defineVariable("x", env, env); assert(lookupVariableValue(value("x"), env) == env); assert(lookupVariableValue("a", env) == value(1)); - cleanupEnvironment(env); return true; } @@ -59,23 +58,41 @@ bool testEnvGC() { bool testRead() { std::istringstream is("abcd"); - assert(read(is) == "abcd"); + assert(readValue(is) == "abcd"); std::istringstream is2("123"); - assert(read(is2) == value(123)); + assert(readValue(is2) == value(123)); std::istringstream is3("(abcd)"); - assert(read(is3) == mklist(value("abcd"))); + assert(readValue(is3) == mklist(value("abcd"))); std::istringstream is4("(abcd xyz)"); - assert(read(is4) == mklist("abcd", "xyz")); + assert(readValue(is4) == mklist("abcd", "xyz")); std::istringstream is5("(abcd (xyz tuv))"); - assert(read(is5) == mklist("abcd", mklist("xyz", "tuv"))); + assert(readValue(is5) == mklist("abcd", mklist("xyz", "tuv"))); return true; } +bool testWrite() { + const list i = list() + << (list() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b" + << (list() << "item" + << (list() << "name" << "Apple") + << (list() << "price" << "$2.99"))) + << (list() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c" + << (list() << "item" + << (list() << "name" << "Orange") + << (list() << "price" << "$3.55"))); + const list a = cons("Feed", cons("feed-1234", i)); + std::ostringstream os; + writeValue(a, os); + std::istringstream is(os.str()); + assert(readValue(is) == a); + return true; +} + const std::string testSchemeNumber( "(define (testNumber) (if (= 1 1) (display \"testNumber ok\") (error \"testNumber\"))) " "(testNumber)"); @@ -178,6 +195,7 @@ int main() { tuscany::eval::testEnv(); tuscany::eval::testEnvGC(); tuscany::eval::testRead(); + tuscany::eval::testWrite(); tuscany::eval::testEval(); tuscany::eval::testEvalExpr(); tuscany::eval::testEvalGC(); diff --git a/cpp/sca/modules/eval/eval.hpp b/cpp/sca/modules/eval/eval.hpp index 78051c5a2b..01d242f07b 100644 --- a/cpp/sca/modules/eval/eval.hpp +++ b/cpp/sca/modules/eval/eval.hpp @@ -30,7 +30,7 @@ #include "list.hpp" #include "value.hpp" #include "primitive.hpp" -#include "read.hpp" +#include "io.hpp" #include "environment.hpp" namespace tuscany { diff --git a/cpp/sca/modules/eval/io.hpp b/cpp/sca/modules/eval/io.hpp new file mode 100644 index 0000000000..2a55e67bbf --- /dev/null +++ b/cpp/sca/modules/eval/io.hpp @@ -0,0 +1,188 @@ +/* + * 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$ */ + +#ifndef tuscany_eval_io_hpp +#define tuscany_eval_io_hpp + +/** + * Script evaluator IO functions. + */ + +#include +#include +#include +#include + +#include "list.hpp" +#include "value.hpp" +#include "primitive.hpp" + +namespace tuscany { +namespace eval { + +const value rightParenthesis(mklist(")")); +const value leftParenthesis(mklist("(")); +const value comment(mklist(";")); + +const double stringToNumber(const std::string& str) { + double d; + std::istringstream is(str); + is >> d; + return d; +} + +const bool isWhitespace(const char ch) { + return ch != -1 && isspace(ch); +} + +const bool isIdentifierStart(const char ch) { + return ch != -1 && !isspace(ch) && !isdigit(ch); +} + +const bool isIdentifierPart(const char ch) { + return ch != -1 && !isspace(ch) && ch != '(' && ch != ')'; +} + +const bool isDigit(const char ch) { + return isdigit(ch) || ch == '.'; +} + +const bool isLeftParenthesis(const value& token) { + return leftParenthesis == token; +} + +const bool isRightParenthesis(const value& token) { + return rightParenthesis == token; +} + +const char readChar(std::istream& in) { + if(in.eof()) { + return -1; + } + char c = in.get(); + return c; +} + +const char peekChar(std::istream& in) { + if(in.eof()) + return -1; + char c = in.peek(); + return c; +} + +const bool isQuote(const value& token) { + return token == quoteSymbol; +} + +const value readQuoted(std::istream& in); +const value readIdentifier(const char chr, std::istream& in); +const value readString(const char chr, std::istream& in); +const value readNumber(const char chr, std::istream& in); +const value readValue(std::istream& in); + +const value readToken(std::istream& in) { + const char firstChar = readChar(in); + if(isWhitespace(firstChar)) + return readToken(in); + if(firstChar == '\'') + return readQuoted(in); + if(firstChar == '(') + return leftParenthesis; + if(firstChar == ')') + return rightParenthesis; + if(firstChar == '"') + return readString(firstChar, in); + if(isIdentifierStart(firstChar)) + return readIdentifier(firstChar, in); + if(isDigit(firstChar)) + return readNumber(firstChar, in); + if(firstChar == -1) + return value(); + std::cout << "Illegal lexical syntax '" << firstChar << "'" << "\n"; + return readToken(in); +} + +const value readQuoted(std::istream& in) { + return mklist(quoteSymbol, readValue(in)); +} + +const list readList(const list& listSoFar, std::istream& in) { + const value token = readToken(in); + if(isNil(token) || isRightParenthesis(token)) + return reverse(listSoFar); + if(isLeftParenthesis(token)) + return readList(cons(value(readList(list (), in)), listSoFar), in); + return readList(cons(token, listSoFar), in); +} + +const std::string listToString(const list& l) { + if(isNil(l)) + return ""; + return car(l) + listToString(cdr(l)); +} + +const list readIdentifierHelper(const list& listSoFar, std::istream& in) { + const char nextChar = peekChar(in); + if(isIdentifierPart(nextChar)) + return readIdentifierHelper(cons(readChar(in), listSoFar), in); + return reverse(listSoFar); +} + +const value readIdentifier(const char chr, std::istream& in) { + return listToString(readIdentifierHelper(mklist(chr), in)).c_str(); +} + +const list readStringHelper(const list& listSoFar, std::istream& in) { + const char nextChar = readChar(in); + if(nextChar != -1 && nextChar != '"') + return readStringHelper(cons(nextChar, listSoFar), in); + return reverse(listSoFar); +} + +const value readString(const char chr, std::istream& in) { + return listToString(readStringHelper(list(), in)); +} + +const list readNumberHelper(const list& listSoFar, std::istream& in) { + const char nextChar = peekChar(in); + if(isDigit(nextChar)) + return readNumberHelper(cons(readChar(in), listSoFar), in); + return reverse(listSoFar); +} + +const value readNumber(const char chr, std::istream& in) { + return stringToNumber(listToString(readNumberHelper(mklist(chr), in))); +} + +const value readValue(std::istream& in) { + const value nextToken = readToken(in); + if(isLeftParenthesis(nextToken)) + return readList(list (), in); + return nextToken; +} + +const bool writeValue(const value& val, std::ostream& out) { + out << val; +} + +} +} +#endif /* tuscany_eval_io_hpp */ diff --git a/cpp/sca/modules/eval/primitive.hpp b/cpp/sca/modules/eval/primitive.hpp index 423e5af07b..9d62d6b1a6 100644 --- a/cpp/sca/modules/eval/primitive.hpp +++ b/cpp/sca/modules/eval/primitive.hpp @@ -40,73 +40,67 @@ const value primitiveSymbol("primitive"); const value quoteSymbol("'"); const value lambdaSymbol("lambda"); -std::ostream* evalOut = &std::cout; +std::ostream* displayOut = &std::cout; -const bool setupEvalOut(std::ostream& out) { - evalOut = &out; +const bool setupDisplay(std::ostream& out) { + displayOut = &out; return true; } -const value valueCar(list& args) { +const value carProc(list& args) { return car((list )car(args)); } -const value valueCdr(list& args) { +const value cdrProc(list& args) { return cdr((list )car(args)); } -const value valueCons(list& args) { +const value consProc(list& args) { return cons(car(args), (list )cadr(args)); } -const value valueList(list& args) { +const value listProc(list& args) { return args; } -const value valueNul(list& args) { +const value nulProc(list& args) { return (bool)isNil(car(args)); } -const value valueEqual(list& args) { +const value equalProc(list& args) { return (bool)(car(args) == cadr(args)); } -const value valueAdd(list& args) { +const value addProc(list& args) { if (isNil(cdr(args))) return (double)car(args); return (double)car(args) + (double)cadr(args); } -const value valueSub(list& args) { +const value subProc(list& args) { if (isNil(cdr(args))) return (double)0 - (double)car(args); return (double)car(args) - (double)cadr(args); } -const value valueMul(list& args) { +const value mulProc(list& args) { return (double)car(args) * (double)cadr(args); } -const value valueDiv(list& args) { +const value divProc(list& args) { return (double)car(args) / (double)cadr(args); } -const value valueDisplay(list& args) { - *evalOut << car(args); +const value displayProc(list& args) { + *displayOut << car(args); return true; } -const value valueComment(list& args) { - *evalOut << "; " << car(args); +const value commentProc(list& args) { return true; } -const value valueError(list& args) { - std::cerr << (std::string)car(args); - return true; -} - -const value valueUuid(list& args) { +const value uuidProc(list& args) { apr_uuid_t uuid; apr_uuid_get(&uuid); char buf[APR_UUID_FORMATTED_LENGTH]; @@ -164,20 +158,20 @@ const list primitiveProcedureNames() { } const list primitiveProcedureObjects() { - list l = mklist(primitiveProcedure(valueCar)); - l = cons(primitiveProcedure(valueCdr), l); - l = cons(primitiveProcedure(valueCons), l); - l = cons(primitiveProcedure(valueList), l); - l = cons(primitiveProcedure(valueNul), l); - l = cons(primitiveProcedure(valueEqual), l); - l = cons(primitiveProcedure(valueAdd), l); - l = cons(primitiveProcedure(valueSub), l); - l = cons(primitiveProcedure(valueMul), l); - l = cons(primitiveProcedure(valueDiv), l); - l = cons(primitiveProcedure(valueEqual), l); - l = cons(primitiveProcedure(valueDisplay), l); - l = cons(primitiveProcedure(valueUuid), l); - l = cons(primitiveProcedure(valueComment), l); + list l = mklist(primitiveProcedure(carProc)); + l = cons(primitiveProcedure(cdrProc), l); + l = cons(primitiveProcedure(consProc), l); + l = cons(primitiveProcedure(listProc), l); + l = cons(primitiveProcedure(nulProc), l); + l = cons(primitiveProcedure(equalProc), l); + l = cons(primitiveProcedure(addProc), l); + l = cons(primitiveProcedure(subProc), l); + l = cons(primitiveProcedure(mulProc), l); + l = cons(primitiveProcedure(divProc), l); + l = cons(primitiveProcedure(equalProc), l); + l = cons(primitiveProcedure(displayProc), l); + l = cons(primitiveProcedure(uuidProc), l); + l = cons(primitiveProcedure(commentProc), l); return l; } diff --git a/cpp/sca/modules/eval/read.hpp b/cpp/sca/modules/eval/read.hpp deleted file mode 100644 index 994462f145..0000000000 --- a/cpp/sca/modules/eval/read.hpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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$ */ - -#ifndef tuscany_eval_read_hpp -#define tuscany_eval_read_hpp - -/** - * Script evaluator read functions. - */ - -#include -#include -#include -#include - -#include "list.hpp" -#include "value.hpp" -#include "primitive.hpp" - -namespace tuscany { -namespace eval { - -const value rightParenthesis(mklist(")")); -const value leftParenthesis(mklist("(")); -const value comment(mklist(";")); - -const double stringToNumber(const std::string& str) { - double d; - std::istringstream is(str); - is >> d; - return d; -} - -const bool isWhitespace(const char ch) { - return ch != -1 && isspace(ch); -} - -const bool isIdentifierStart(const char ch) { - return ch != -1 && !isspace(ch) && !isdigit(ch); -} - -const bool isIdentifierPart(const char ch) { - return ch != -1 && !isspace(ch) && ch != '(' && ch != ')'; -} - -const bool isDigit(const char ch) { - return isdigit(ch) || ch == '.'; -} - -const bool isLeftParenthesis(const value& token) { - return leftParenthesis == token; -} - -const bool isRightParenthesis(const value& token) { - return rightParenthesis == token; -} - -const char readChar(std::istream& in) { - if(in.eof()) { - return -1; - } - char c = in.get(); - return c; -} - -const char peekChar(std::istream& in) { - if(in.eof()) - return -1; - char c = in.peek(); - return c; -} - -const bool isQuote(const value& token) { - return token == quoteSymbol; -} - -const value readQuoted(std::istream& in); -const value readIdentifier(const char chr, std::istream& in); -const value readString(const char chr, std::istream& in); -const value readNumber(const char chr, std::istream& in); -const value read(std::istream& in); - -const value readToken(std::istream& in) { - const char firstChar = readChar(in); - if(isWhitespace(firstChar)) - return readToken(in); - if(firstChar == '\'') - return readQuoted(in); - if(firstChar == '(') - return leftParenthesis; - if(firstChar == ')') - return rightParenthesis; - if(firstChar == '"') - return readString(firstChar, in); - if(isIdentifierStart(firstChar)) - return readIdentifier(firstChar, in); - if(isDigit(firstChar)) - return readNumber(firstChar, in); - if(firstChar == -1) - return value(); - std::cout << "Illegal lexical syntax '" << firstChar << "'" << "\n"; - return readToken(in); -} - -const value readQuoted(std::istream& in) { - return mklist(quoteSymbol, read(in)); -} - -const list readList(const list& listSoFar, std::istream& in) { - const value token = readToken(in); - if(isNil(token) || isRightParenthesis(token)) - return reverse(listSoFar); - if(isLeftParenthesis(token)) - return readList(cons(value(readList(list (), in)), listSoFar), in); - return readList(cons(token, listSoFar), in); -} - -const std::string listToString(const list& l) { - if(isNil(l)) - return ""; - return car(l) + listToString(cdr(l)); -} - -const list readIdentifierHelper(const list& listSoFar, std::istream& in) { - const char nextChar = peekChar(in); - if(isIdentifierPart(nextChar)) - return readIdentifierHelper(cons(readChar(in), listSoFar), in); - return reverse(listSoFar); -} - -const value readIdentifier(const char chr, std::istream& in) { - return listToString(readIdentifierHelper(mklist(chr), in)).c_str(); -} - -const list readStringHelper(const list& listSoFar, std::istream& in) { - const char nextChar = readChar(in); - if(nextChar != -1 && nextChar != '"') - return readStringHelper(cons(nextChar, listSoFar), in); - return reverse(listSoFar); -} - -const value readString(const char chr, std::istream& in) { - return listToString(readStringHelper(list(), in)); -} - -const list readNumberHelper(const list& listSoFar, std::istream& in) { - const char nextChar = peekChar(in); - if(isDigit(nextChar)) - return readNumberHelper(cons(readChar(in), listSoFar), in); - return reverse(listSoFar); -} - -const value readNumber(const char chr, std::istream& in) { - return stringToNumber(listToString(readNumberHelper(mklist(chr), in))); -} - -const value read(std::istream& in) { - const value nextToken = readToken(in); - if(isLeftParenthesis(nextToken)) - return readList(list (), in); - return nextToken; -} - -} -} -#endif /* tuscany_eval_read_hpp */ diff --git a/cpp/sca/modules/http/conf/mime.types b/cpp/sca/modules/http/conf/mime.types new file mode 100644 index 0000000000..4279f51bca --- /dev/null +++ b/cpp/sca/modules/http/conf/mime.types @@ -0,0 +1,607 @@ +# 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. + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# MIME type Extensions +application/activemessage +application/andrew-inset ez +application/applefile +application/atom+xml atom +application/atomicmail +application/batch-smtp +application/beep+xml +application/cals-1840 +application/cnrp+xml +application/commonground +application/cpl+xml +application/cybercash +application/dca-rft +application/dec-dx +application/dvcs +application/edi-consent +application/edifact +application/edi-x12 +application/eshop +application/font-tdpfr +application/http +application/hyperstudio +application/iges +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc +application/mathematica +application/mathml+xml mathml +application/msword doc +application/news-message-id +application/news-transmission +application/ocsp-request +application/ocsp-response +application/octet-stream bin dms lha lzh exe class so dll dmg +application/oda oda +application/ogg ogg +application/parityfec +application/pdf pdf +application/pgp-encrypted +application/pgp-keys +application/pgp-signature +application/pkcs10 +application/pkcs7-mime +application/pkcs7-signature +application/pkix-cert +application/pkix-crl +application/pkixcmp +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww +application/prs.nprend +application/prs.plucker +application/qsig +application/rdf+xml rdf +application/reginfo+xml +application/remote-printing +application/riscos +application/rtf +application/sdp +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog +application/sieve +application/slate +application/smil smi smil +application/srgs gram +application/srgs+xml grxml +application/timestamp-query +application/timestamp-reply +application/tve-trigger +application/vemmi +application/vnd.3gpp.pic-bw-large +application/vnd.3gpp.pic-bw-small +application/vnd.3gpp.pic-bw-var +application/vnd.3gpp.sms +application/vnd.3m.post-it-notes +application/vnd.accpac.simply.aso +application/vnd.accpac.simply.imp +application/vnd.acucobol +application/vnd.acucorp +application/vnd.adobe.xfdf +application/vnd.aether.imp +application/vnd.amiga.ami +application/vnd.anser-web-certificate-issue-initiation +application/vnd.anser-web-funds-transfer-initiation +application/vnd.audiograph +application/vnd.blueice.multipass +application/vnd.bmi +application/vnd.businessobjects +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cinderella +application/vnd.claymore +application/vnd.commerce-battelle +application/vnd.commonspace +application/vnd.contact.cmsg +application/vnd.cosmocaller +application/vnd.criticaltools.wbs+xml +application/vnd.ctc-posml +application/vnd.cups-postscript +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.curl +application/vnd.cybank +application/vnd.data-vision.rdz +application/vnd.dna +application/vnd.dpgraph +application/vnd.dreamfactory +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven +application/vnd.epson.esf +application/vnd.epson.msf +application/vnd.epson.quickanime +application/vnd.epson.salt +application/vnd.epson.ssf +application/vnd.ericsson.quickcall +application/vnd.eudora.data +application/vnd.fdf +application/vnd.ffsns +application/vnd.fints +application/vnd.flographit +application/vnd.framemaker +application/vnd.fsc.weblaunch +application/vnd.fujitsu.oasys +application/vnd.fujitsu.oasys2 +application/vnd.fujitsu.oasys3 +application/vnd.fujitsu.oasysgp +application/vnd.fujitsu.oasysprs +application/vnd.fujixerox.ddd +application/vnd.fujixerox.docuworks +application/vnd.fujixerox.docuworks.binder +application/vnd.fut-misnet +application/vnd.grafeq +application/vnd.groove-account +application/vnd.groove-help +application/vnd.groove-identity-message +application/vnd.groove-injector +application/vnd.groove-tool-message +application/vnd.groove-tool-template +application/vnd.groove-vcard +application/vnd.hbci +application/vnd.hhe.lesson-player +application/vnd.hp-hpgl +application/vnd.hp-hpid +application/vnd.hp-hps +application/vnd.hp-pcl +application/vnd.hp-pclxl +application/vnd.httphone +application/vnd.hzn-3d-crossword +application/vnd.ibm.afplinedata +application/vnd.ibm.electronic-media +application/vnd.ibm.minipay +application/vnd.ibm.modcap +application/vnd.ibm.rights-management +application/vnd.ibm.secure-container +application/vnd.informix-visionary +application/vnd.intercon.formnet +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo +application/vnd.intu.qfx +application/vnd.irepository.package+xml +application/vnd.is-xpr +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.jisp +application/vnd.kde.karbon +application/vnd.kde.kchart +application/vnd.kde.kformula +application/vnd.kde.kivio +application/vnd.kde.kontour +application/vnd.kde.kpresenter +application/vnd.kde.kspread +application/vnd.kde.kword +application/vnd.kenameaapp +application/vnd.koan +application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop +application/vnd.llamagraphics.life-balance.exchange+xml +application/vnd.lotus-1-2-3 +application/vnd.lotus-approach +application/vnd.lotus-freelance +application/vnd.lotus-notes +application/vnd.lotus-organizer +application/vnd.lotus-screencam +application/vnd.lotus-wordpro +application/vnd.mcd +application/vnd.mediastation.cdkey +application/vnd.meridian-slingshot +application/vnd.micrografx.flo +application/vnd.micrografx.igx +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf +application/vnd.mobius.dis +application/vnd.mobius.mbk +application/vnd.mobius.mqy +application/vnd.mobius.msl +application/vnd.mobius.plc +application/vnd.mobius.txf +application/vnd.mophun.application +application/vnd.mophun.certificate +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry +application/vnd.ms-asf +application/vnd.ms-excel xls +application/vnd.ms-lrm +application/vnd.ms-powerpoint ppt +application/vnd.ms-project +application/vnd.ms-tnef +application/vnd.ms-works +application/vnd.ms-wpl +application/vnd.mseq +application/vnd.msign +application/vnd.music-niff +application/vnd.musician +application/vnd.netfpx +application/vnd.noblenet-directory +application/vnd.noblenet-sealer +application/vnd.noblenet-web +application/vnd.novadigm.edm +application/vnd.novadigm.edx +application/vnd.novadigm.ext +application/vnd.obn +application/vnd.osa.netdeploy +application/vnd.palm +application/vnd.pg.format +application/vnd.pg.osasli +application/vnd.powerbuilder6 +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.previewsystems.box +application/vnd.publishare-delta-tree +application/vnd.pvi.ptid1 +application/vnd.pwg-multiplexed +application/vnd.pwg-xhtml-print+xml +application/vnd.quark.quarkxpress +application/vnd.rapid +application/vnd.s3sms +application/vnd.sealed.net +application/vnd.seemail +application/vnd.shana.informed.formdata +application/vnd.shana.informed.formtemplate +application/vnd.shana.informed.interchange +application/vnd.shana.informed.package +application/vnd.smaf +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.street-stream +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.triscape.mxs +application/vnd.trueapp +application/vnd.truedoc +application/vnd.ufdl +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio +application/vnd.visionary +application/vnd.vividence.scriptfile +application/vnd.vsf +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf +application/vnd.wv.csp+wbxml +application/vnd.xara +application/vnd.xfdl +application/vnd.yamaha.hv-dic +application/vnd.yamaha.hv-script +application/vnd.yamaha.hv-voice +application/vnd.yellowriver-custom-menu +application/voicexml+xml vxml +application/watcherinfo+xml +application/whoispp-query +application/whoispp-response +application/wita +application/wordperfect5.1 +application/x-bcpio bcpio +application/x-cdlink vcd +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-javascript js +application/x-koan skp skd skt skm +application/x-latex latex +application/x-netcdf nc cdf +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/x400-bp +application/xhtml+xml xhtml xht +application/xslt+xml xslt +application/xml xml xsl +application/xml-dtd dtd +application/xml-external-parsed-entity +application/zip zip +audio/32kadpcm +audio/amr +audio/amr-wb +audio/basic au snd +audio/cn +audio/dat12 +audio/dsr-es201108 +audio/dvi4 +audio/evrc +audio/evrc0 +audio/g722 +audio/g.722.1 +audio/g723 +audio/g726-16 +audio/g726-24 +audio/g726-32 +audio/g726-40 +audio/g728 +audio/g729 +audio/g729D +audio/g729E +audio/gsm +audio/gsm-efr +audio/l8 +audio/l16 +audio/l20 +audio/l24 +audio/lpc +audio/midi mid midi kar +audio/mpa +audio/mpa-robust +audio/mp4a-latm +audio/mpeg mpga mp2 mp3 +audio/parityfec +audio/pcma +audio/pcmu +audio/prs.sid +audio/qcelp +audio/red +audio/smv +audio/smv0 +audio/telephone-event +audio/tone +audio/vdvi +audio/vnd.3gpp.iufp +audio/vnd.cisco.nse +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds +audio/vnd.everad.plj +audio/vnd.lucent.voice +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 +audio/vnd.nuera.ecelp7470 +audio/vnd.nuera.ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.vmx.cvsd +audio/x-aiff aif aiff aifc +audio/x-alaw-basic +audio/x-mpegurl m3u +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin +application/vnd.rn-realmedia rm +audio/x-wav wav +chemical/x-pdb pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +image/g3fax +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/naplps +image/png png +image/prs.btif +image/prs.pti +image/svg+xml svg +image/t38 +image/tiff tiff tif +image/tiff-fx +image/vnd.cns.inf2 +image/vnd.djvu djvu djv +image/vnd.dwg +image/vnd.dxf +image/vnd.fastbidsheet +image/vnd.fpx +image/vnd.fst +image/vnd.fujixerox.edmics-mmr +image/vnd.fujixerox.edmics-rlc +image/vnd.globalgraphics.pgb +image/vnd.mix +image/vnd.ms-modi +image/vnd.net-fpx +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff +image/x-cmu-raster ras +image/x-icon ico +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/news +message/partial +message/rfc822 +message/s-http +message/sip +message/sipfrag +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf +model/vnd.flatland.3dml +model/vnd.gdl +model/vnd.gs-gdl +model/vnd.gtw +model/vnd.mts +model/vnd.parasolid.transmit.binary +model/vnd.parasolid.transmit.text +model/vnd.vtu +model/vrml wrl vrml +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/calendar ics ifb +text/css css +text/directory +text/enriched +text/html html htm +text/parityfec +text/plain asc txt +text/prs.lines.tag +text/rfc822-headers +text/richtext rtx +text/rtf rtf +text/sgml sgml sgm +text/t140 +text/tab-separated-values tsv +text/uri-list +text/vnd.abc +text/vnd.curl +text/vnd.dmclientscript +text/vnd.fly +text/vnd.fmi.flexstor +text/vnd.in3d.3dml +text/vnd.in3d.spot +text/vnd.iptc.nitf +text/vnd.iptc.newsml +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.net2phone.commcenter.command +text/vnd.sun.j2me.app-descriptor +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-setext etx +text/xml +text/xml-external-parsed-entity +video/bmpeg +video/bt656 +video/celb +video/dv +video/h261 +video/h263 +video/h263-1998 +video/h263-2000 +video/jpeg +video/mp1s +video/mp2p +video/mp2t +video/mp4v-es +video/mpv +video/mpeg mpeg mpg mpe +video/nv +video/parityfec +video/pointer +video/quicktime qt mov +video/smpte292m +video/vnd.fvt +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.nokia.interleaved-multimedia +video/vnd.objectvideo +video/vnd.vivo +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice diff --git a/cpp/sca/modules/http/curl-test.cpp b/cpp/sca/modules/http/curl-test.cpp index 4e23a036da..b02a2fac4d 100644 --- a/cpp/sca/modules/http/curl-test.cpp +++ b/cpp/sca/modules/http/curl-test.cpp @@ -24,6 +24,8 @@ */ #include +#include +#include #include #include #include @@ -37,25 +39,164 @@ bool contains(const std::string& str, const std::string& pattern) { return str.find(pattern) != str.npos; } -std::ostringstream* curlWriter(std::ostringstream* os, const std::string& s) { +std::ostringstream* curlWriter(const std::string& s, std::ostringstream* os) { (*os) << s; return os; } -const bool testCURL() { +const bool testEval() { + CURLHandle ch; + const value val = evalExpr(mklist(std::string("echo"), std::string("Hello")), "http://localhost:8091/test", ch); + assert(val == std::string("Hello")); + return true; +} + +const bool testEvalLoop(const int count, CURLHandle& ch) { + if (count == 0) + return true; + const value val = evalExpr(mklist(std::string("echo"), std::string("Hello")), "http://localhost:8091/test", ch); + assert(val == std::string("Hello")); + return testEvalLoop(count - 1, ch); +} + +const value blob(std::string(3000, 'A')); +const list blobs = mklist(blob, blob, blob, blob, blob); + +const bool testBlobEvalLoop(const int count, CURLHandle& ch) { + if (count == 0) + return true; + const value val = evalExpr(mklist(std::string("echo"), blobs), "http://localhost:8091/test", ch); + assert(val == blobs); + return testBlobEvalLoop(count - 1, ch); +} + +const bool testEvalPerf() { + const int count = 50; + CURLHandle ch; + struct timeval start; + struct timeval end; + { + testEvalLoop(5, ch); + + gettimeofday(&start, NULL); + + testEvalLoop(count, ch); + + gettimeofday(&end, NULL); + long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + std::cout << "JSON-RPC eval echo test " << (t / count) << " ms" << std::endl; + } + { + testBlobEvalLoop(5, ch); + + gettimeofday(&start, NULL); + + testBlobEvalLoop(count, ch); + + gettimeofday(&end, NULL); + long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + std::cout << "JSON-RPC eval blob test " << (t / count) << " ms" << std::endl; + } +} + +const bool testGet() { + CURLHandle ch; { std::ostringstream os; - const failable r = get(curlWriter, &os, "http://localhost:9091"); + const failable, std::string> r = get(curlWriter, &os, "http://localhost:8091", ch); assert(hasValue(r)); + assert(contains(os.str(), "HTTP/1.1 200 OK")); assert(contains(os.str(), "It works")); } { - std::ostringstream os; - const failable, int> r = get("http://localhost:9091"); + const failable r = get("http://localhost:8091", ch); assert(hasValue(r)); - write(r, os); - assert(contains(os.str(), "It works")); + const value val = r; + assert(contains(val, "It works")); + } + return true; +} + +const bool testFeed() { + return true; +} + +bool testPost() { + const list i = list() + << (list() << "name" << std::string("Apple")) + << (list() << "price" << std::string("$2.99")); + const list a = mklist(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + CURLHandle ch; + value rc = post(a, "http://localhost:8091/test", ch); + assert(rc == value(true)); + return true; +} + +const bool testPostLoop(const int count, const value& val, CURLHandle& ch) { + if (count == 0) + return true; + const value rc = post(val, "http://localhost:8091/test", ch); + assert(rc == value(true)); + return testPostLoop(count - 1, val, ch); +} + +const bool testPostPerf() { + const int count = 50; + CURLHandle ch; + struct timeval start; + struct timeval end; + { + const list i = list() + << (list() << "name" << std::string("Apple")) + << (list() << "price" << std::string("$2.99")); + const list val = mklist(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + testPostLoop(5, val, ch); + + gettimeofday(&start, NULL); + + testPostLoop(count, val, ch); + + gettimeofday(&end, NULL); + long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + std::cout << "ATOMPub POST small test " << (t / count) << " ms" << std::endl; + } + { + const list i = list() + << (list() << "name" << std::string("Apple")) + << (list() << "blob1" << blob) + << (list() << "blob2" << blob) + << (list() << "blob3" << blob) + << (list() << "blob4" << blob) + << (list() << "blob5" << blob) + << (list() << "price" << std::string("$2.99")); + const list val = mklist(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + testPostLoop(5, val, ch); + + gettimeofday(&start, NULL); + + testPostLoop(count, val, ch); + + gettimeofday(&end, NULL); + long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + std::cout << "ATOMPub POST blob test " << (t / count) << " ms" << std::endl; } +} + +const bool testPut() { + const list i = list() + << (list() << "name" << std::string("Apple")) + << (list() << "price" << std::string("$2.99")); + const list a = mklist(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + CURLHandle ch; + value rc = put(a, "http://localhost:8091/test", ch); + assert(rc == value(true)); + return true; +} + +const bool testDel() { + CURLHandle ch; + value rc = del("http://localhost:8091/test/123456789", ch); + assert(rc == value(true)); return true; } @@ -65,7 +206,14 @@ const bool testCURL() { int main() { std::cout << "Testing..." << std::endl; - tuscany::http::testCURL(); + tuscany::http::testGet(); + tuscany::http::testPost(); + //tuscany::http::testPostPerf(); + tuscany::http::testEval(); + //tuscany::http::testEvalPerf(); + tuscany::http::testFeed(); + tuscany::http::testPut(); + tuscany::http::testDel(); std::cout << "OK" << std::endl; diff --git a/cpp/sca/modules/http/curl.hpp b/cpp/sca/modules/http/curl.hpp index 2ea23010cb..c0d79cef13 100644 --- a/cpp/sca/modules/http/curl.hpp +++ b/cpp/sca/modules/http/curl.hpp @@ -34,10 +34,17 @@ #include "value.hpp" #include "element.hpp" #include "monad.hpp" +#include "../atom/atom.hpp" +#include "../json/json.hpp" namespace tuscany { namespace http { +/** + * Set to true to log HTTP content. + */ +bool logContent = false; + /** * CURL library context, one per process. */ @@ -71,14 +78,38 @@ private: CURL* h; }; +/** + * Context passed to the read callback function. + */ +class CURLReadContext { +public: + CURLReadContext(const list& ilist) : ilist(ilist) { + } + list ilist; +}; + +/** + * Called by CURL to read data to send. + */ +size_t readCallback(void *ptr, size_t size, size_t nmemb, void *data) { + CURLReadContext& rcx = *static_cast(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(); +} + /** * Context passed to CURL write callback function. */ template class CURLWriteContext { public: - CURLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { + CURLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { } - const lambda reduce; + const lambda reduce; R accum; }; @@ -88,7 +119,7 @@ public: template size_t writeCallback(void *ptr, size_t size, size_t nmemb, void *data) { CURLWriteContext& wcx = *(static_cast*> (data)); const size_t realsize = size * nmemb; - wcx.accum = wcx.reduce(wcx.accum, std::string((const char*)ptr, realsize)); + wcx.accum = wcx.reduce(std::string((const char*)ptr, realsize), wcx.accum); return realsize; } @@ -98,50 +129,199 @@ template size_t writeCallback(void *ptr, size_t size, size_t nmemb, template size_t headerCallback(void *ptr, size_t size, size_t nmemb, void *data) { CURLWriteContext& wcx = *(static_cast*> (data)); const size_t realsize = size * nmemb; - wcx.accum = wcx.reduce(wcx.accum, std::string((const char*)ptr, realsize)); + wcx.accum = wcx.reduce(std::string((const char*)ptr, realsize), wcx.accum); return realsize; } /** - * HTTP GET, get a resource from a URL. + * 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. */ -template const failable get(const lambda& reduce, const R& initial, const std::string& url) { - CURLWriteContext wcx(reduce, initial); +curl_slist* headers(curl_slist* cl, const list h) { + if (isNil(h)) + return cl; + return headers(curl_slist_append(cl, std::string(car(h)).c_str()), cdr(h)); +} + +template const failable, std::string> apply(const list > req, const lambda& reduce, const R& initial, const std::string& url, const std::string& verb, CURLHandle& ch) { // Init the curl session - CURLHandle ch; - curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - curl_easy_setopt(ch, CURLOPT_URL, url.c_str()); + curl_easy_reset(ch); + 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(); + if (sz < 1400) + curl_easy_setopt(ch, CURLOPT_TCP_NODELAY, true); + + // 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 hcx(reduce, initial); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))headerCallback); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, &hcx); + CURLWriteContext wcx(reduce, initial); curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, (size_t (*)(void*, size_t, size_t, void*))writeCallback); curl_easy_setopt(ch, CURLOPT_WRITEDATA, &wcx); - curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))headerCallback); - curl_easy_setopt(ch, CURLOPT_HEADERDATA, &wcx); - - // Perform the HTTP GET + + // Set the request headers + curl_slist* hl = headers(NULL, car(req)); + if (hl != NULL) + curl_easy_setopt(ch, CURLOPT_HTTPHEADER, hl); + + // Apply the HTTP verb + curl_easy_setopt(ch, CURLOPT_URL, url.c_str()); + if (verb == "POST") { + curl_easy_setopt(ch, CURLOPT_POST, true); + curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, sz); + } else if (verb == "PUT") { + curl_easy_setopt(ch, CURLOPT_UPLOAD, true); + curl_easy_setopt(ch, CURLOPT_INFILESIZE, sz); + } else if (verb == "DELETE") + curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, "DELETE"); const CURLcode rc = curl_easy_perform(ch); - if (rc) - return rc; + + if (hl != NULL) + curl_slist_free_all(hl); // Return the HTTP return code or content + if (rc) + return std::string(curl_easy_strerror(rc)); long httprc; curl_easy_getinfo (ch, CURLINFO_RESPONSE_CODE, &httprc); - if (httprc != 200) - return httprc; - return wcx.accum; + if (httprc != 200 && httprc != 201) { + std::ostringstream es; + es << "HTTP code " << httprc; + return es.str(); + } + return mklist(hcx.accum, wcx.accum); } /** - * HTTP GET, get a list of values representing a resource from a URL. + * Evaluate an expression remotely, at the given URL. */ -const list writeStringList(const list& listSoFar, const std::string& s) { - return cons(s, listSoFar); +const failable evalExpr(const value expr, const std::string& url, CURLHandle& ch) { + + // Convert expression to a JSON-RPC request + json::JSONContext cx; + const failable, std::string> jsreq = jsonRequest(1, car(expr), cdr(expr), cx); + if (!hasValue(jsreq)) + return std::string(jsreq); + + if (logContent) { + std::cout<< "content: " << std::endl; + write(jsreq, std::cout); + std::cout<< std::endl; + std::cout.flush(); + } + + // POST it to the URL + const list h = mklist("Content-Type: application/json-rpc"); + const failable >, std::string> res = apply >(mklist >(h, jsreq), rcons, list(), url, "POST", ch); + if (!hasValue(res)) + return std::string(res); + + // Return result + if (logContent) { + std::cout << "content:" << std::endl; + write(cadr >(res), std::cout); + std::cout << std::endl; + } + const list val = elementsToValues(json::readJSON(cadr >(res), cx)); + return cadr(cadr(val)); +} + +/** + * HTTP GET, return the resource at the given URL. + */ +template const failable, std::string> get(const lambda& reduce, const R& initial, const std::string& url, CURLHandle& ch) { + const list > req = mklist(list(), list()); + return apply(req, reduce, initial, url, "GET", ch); +} + +/** + * HTTP GET, return a list of values representing the resource at the given URL. + */ +const failable get(const std::string& url, CURLHandle& ch) { + + // Get the contents of the resource at the given URL + const failable >, std::string> res = get >(rcons, list(), url, ch); + if (!hasValue(res)) + return std::string(res); + const list > ls = res; + + // TODO Return an ATOM feed + const std::string ct; + if (ct.find("application/atom+xml") != std::string::npos) { + } + + // Return the content as a string value + std::ostringstream os; + write(reverse(cadr(ls)), os); + return value(os.str()); } -const failable, int> get(const std::string& url) { - const failable, int> r = get >(writeStringList, list(), url); - if (!hasValue(r)) - return r; - return reverse(list(r)); +/** + * HTTP POST. + */ +const failable post(const value& val, const std::string& url, CURLHandle& ch) { + + // Convert value to an ATOM entry + const failable, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val)); + if (!hasValue(entry)) + return std::string(entry); + if (logContent) { + std::cout << "content:" << std::endl; + write(list(entry), std::cout); + std::cout << std::endl; + } + + // POST it to the URL + const list h = mklist("Content-Type: application/atom+xml"); + const list > req = mklist >(h, entry); + const failable >, std::string> res = apply >(req, rcons, list(), url, "POST", ch); + if (!hasValue(res)) + return std::string(res); + return value(true); +} + +/** + * HTTP PUT. + */ +const failable put(const value& val, const std::string& url, CURLHandle& ch) { + + // Convert value to an ATOM entry + const failable, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val)); + if (!hasValue(entry)) + return std::string(entry); + if (logContent) { + std::cout << "content:" << std::endl; + write(list(entry), std::cout); + std::cout << std::endl; + } + + // POST it to the URL + const list h = mklist("Content-Type: application/atom+xml"); + const list > req = mklist >(h, entry); + const failable >, std::string> res = apply >(req, rcons, list(), url, "PUT", ch); + if (!hasValue(res)) + return std::string(res); + return value(true); +} + +/** + * HTTP DELETE. + */ +const failable del(const std::string& url, CURLHandle& ch) { + const list > req = mklist(list(), list()); + const failable >, std::string> res = apply >(req, rcons, list(), url, "DELETE", ch); + if (!hasValue(res)) + return std::string(res); + return value(true); } } diff --git a/cpp/sca/modules/http/htdocs/entry.xml b/cpp/sca/modules/http/htdocs/entry.xml new file mode 100644 index 0000000000..4906fbedc8 --- /dev/null +++ b/cpp/sca/modules/http/htdocs/entry.xml @@ -0,0 +1,2 @@ + +Item111services.ItemAppleUSD$2.99 diff --git a/cpp/sca/modules/http/htdocs/feed.xml b/cpp/sca/modules/http/htdocs/feed.xml new file mode 100644 index 0000000000..4ca3183739 --- /dev/null +++ b/cpp/sca/modules/http/htdocs/feed.xml @@ -0,0 +1,2 @@ + +Sample Feed123456789Item111javaClassItem222javaClassItem333javaClass diff --git a/cpp/sca/modules/http/htdocs/index.html b/cpp/sca/modules/http/htdocs/index.html new file mode 100644 index 0000000000..1bfb3e30c2 --- /dev/null +++ b/cpp/sca/modules/http/htdocs/index.html @@ -0,0 +1,21 @@ + + +

It works!

+ diff --git a/cpp/sca/modules/http/htdocs/json-request.txt b/cpp/sca/modules/http/htdocs/json-request.txt new file mode 100644 index 0000000000..b4bd07fc46 --- /dev/null +++ b/cpp/sca/modules/http/htdocs/json-request.txt @@ -0,0 +1 @@ +{"id":1,"method":"echo","params":["Hello"]} diff --git a/cpp/sca/modules/http/htdocs/json-result.txt b/cpp/sca/modules/http/htdocs/json-result.txt new file mode 100644 index 0000000000..121bf74902 --- /dev/null +++ b/cpp/sca/modules/http/htdocs/json-result.txt @@ -0,0 +1 @@ +{"id":1,"result":"Hello"} \ No newline at end of file diff --git a/cpp/sca/modules/http/http-test b/cpp/sca/modules/http/http-test index b0dd21cbd1..e369cc34f7 100755 --- a/cpp/sca/modules/http/http-test +++ b/cpp/sca/modules/http/http-test @@ -17,18 +17,24 @@ # specific language governing permissions and limitations # under the License. -mkdir -p tmp -mkdir -p tmp/conf -cp test-conf/* tmp/conf -cat >tmp/conf/httpd.conf <>tmp/conf/httpd.conf < +SetHandler mod_tuscany +SCAContribution `pwd`/ +SCAComponent httpd-test +SCAImplementation httpd-test.scm + EOF -mkdir -p tmp/logs apachectl -k start -d `pwd`/tmp sleep 1 + +# Test ./curl-test rc=$? + +# Cleanup apachectl -k stop -d `pwd`/tmp +sleep 1 return $rc diff --git a/cpp/sca/modules/http/httpd-conf b/cpp/sca/modules/http/httpd-conf new file mode 100755 index 0000000000..e076e22bb1 --- /dev/null +++ b/cpp/sca/modules/http/httpd-conf @@ -0,0 +1,36 @@ +#!/bin/sh + +# 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. + +# Generate a minimal httpd.conf +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` +port=$2 +htdocs=`readlink -f $3` + +mkdir -p $root +mkdir -p $root/logs +mkdir -p $root/conf +cat >$root/conf/httpd.conf <tmp/conf/httpd.conf <>tmp/conf/httpd.conf < +SetHandler mod_tuscany +SCAContribution `pwd`/ +SCAComponent httpd-test +SCAImplementation httpd-test.scm + EOF -mkdir -p tmp/logs apachectl -k start -d `pwd`/tmp sleep 1 -curl http://localhost:9090/index.html 2>&1 | grep "It works" >/dev/null + +# Test HTTP GET +curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html +diff tmp/index.html htdocs/index.html rc=$? + +# Test ATOMPub +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/ >tmp/feed.xml 2>/dev/null + diff tmp/feed.xml htdocs/feed.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/111 >tmp/entry.xml 2>/dev/null + diff tmp/entry.xml htdocs/entry.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/111 -X DELETE 2>/dev/null + rc=$? +fi + +# Test JSON-RPC +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null + diff tmp/json-result.txt htdocs/json-result.txt + rc=$? +fi + +# Cleanup apachectl -k stop -d `pwd`/tmp +sleep 1 if [ "$rc" = "0" ]; then echo "OK" fi diff --git a/cpp/sca/modules/http/httpd-test.scm b/cpp/sca/modules/http/httpd-test.scm new file mode 100644 index 0000000000..a3ddf8dda8 --- /dev/null +++ b/cpp/sca/modules/http/httpd-test.scm @@ -0,0 +1,33 @@ +(; "JSON-RPC test case") + +(define (echo x) x) + +(; "ATOMPub test case") + +(define (getall) + '("Sample Feed" "123456789" + ("Item" "111" (javaClass "services.Item") (name "Apple") (currency "USD") (symbol "$") (price 2.99)) + ("Item" "222" (javaClass "services.Item") (name "Orange") (currency "USD") (symbol "$") (price 3.55)) + ("Item" "333" (javaClass "services.Item") (name "Pear") (currency "USD") (symbol "$") (price 1.55))) +) + +(define (get id) + (define entry '((javaClass "services.Item") (name "Apple") (currency "USD") (symbol "$") (price 2.99))) + (cons "Item" (list id entry)) +) + +(define (post entry) + (display entry) + "123456789" +) + +(define (put entry) + (display entry) + true +) + +(define (delete . args) + (display args) + true +) + diff --git a/cpp/sca/modules/http/mod.cpp b/cpp/sca/modules/http/mod.cpp index 88891a668c..811ee0c633 100644 --- a/cpp/sca/modules/http/mod.cpp +++ b/cpp/sca/modules/http/mod.cpp @@ -63,6 +63,12 @@ extern module AP_MODULE_DECLARE_DATA mod_tuscany; namespace tuscany { namespace httpd { +/** + * Set to true to log requests and content. + */ +bool logRequests = false; +bool logContent = false; + /** * Server configuration. */ @@ -139,10 +145,8 @@ const std::string contentType(const request_rec* r) { } /** - * Log HTTP request info to standard out for now, for debugging purposes. + * Log HTTP request info. */ -bool logRequests = true; - int logHeader(void* r, const char* key, const char* value) { std::cout << "header key: " << key << ", value: " << value << std::endl; return 1; @@ -161,6 +165,7 @@ const bool logRequest(request_rec* r) { apr_table_do(logHeader, r, r->headers_in, NULL); std::cout << "uri: " << 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: " << pathTokens(r) << std::endl; std::cout << "args: " << optional(r->args) << std::endl; std::cout.flush(); @@ -170,34 +175,32 @@ const bool logRequest(request_rec* r) { /** * Evaluate an expression against a component implementation. */ -const value evalExprLoop(std::istream& is, const value& req, eval::Env& globalEnv) { - value in = eval::read(is); +const value evalExprLoop(std::istream& is, const value& expr, eval::Env& globalEnv, const gc_pool& pool) { + value in = eval::readValue(is); if (isNil(in)) - return eval::evalApply(req, globalEnv); - eval::evalApply(in, globalEnv); - return evalExprLoop(is, req, globalEnv); + return eval::evalExpr(expr, globalEnv, pool); + eval::evalExpr(in, globalEnv, pool); + return evalExprLoop(is, expr, globalEnv, pool); } -const failable evalExpr(const value& expr, const std::string& contrib, const std::string& impl) { - // Setup the evaluator - eval::Env globalEnv = eval::setupEnvironment(); - std::ostringstream nullos; - eval::setupEvalOut(nullos); - +const failable evalExpr(const value& expr, const std::string& contrib, const std::string& impl) { // Retrieve the component implementation const std::string path = contrib + impl; std::ifstream is(path.c_str(), std::ios_base::in); if (is.fail() || is.bad()) - return HTTP_NOT_FOUND; + return std::string("HTTP_NOT_FOUND"); // Evaluate the expr + gc_pool pool; + eval::Env globalEnv = eval::setupEnvironment(pool); std::cout<< "expr: " << expr << std::endl; std::cout.flush(); - const value val = evalExprLoop(is, expr, globalEnv); + const value val = evalExprLoop(is, expr, globalEnv, pool); std::cout<< "val: " << val << std::endl; std::cout.flush(); + if (isNil(val)) - return HTTP_INTERNAL_SERVER_ERROR; + return std::string("Could not evaluate expression"); return val; } @@ -229,75 +232,18 @@ const list queryParams(list > a) { return cons(cadr(p), queryParams(cdr(a))); } -/** - * Convert a value to a JSON result. - */ -const failable, int> jsonResult(json::JSONContext& cx, const value& id, const failable& val) { - if (!hasValue(val)) - return int(val); - const list r = mklist(mklist("id", id), mklist("result", val)); - failable, std::string> ls = json::write(cx, valuesToElements(r)); - if (!hasValue(ls)) - return HTTP_INTERNAL_SERVER_ERROR; - std::cout<< "content: " << std::endl; - write(ls, std::cout); - std::cout<< std::endl; - std::cout.flush(); - return list(ls); -} - -/** - * Convert a value to an ATOM entry. - */ -const list feedEntryResult(const list e) { - return cons(car(e), cons(cadr(e), valuesToElements(mklist(cons("item", (list)caddr(e)))))); -} - -/** - * Convert a value to an ATOM feed. - */ -const list feedEntriesResults(const list e) { - if (isNil(e)) - return list(); - return cons(feedEntryResult(car(e)), feedEntriesResults(cdr(e))); -} - -const failable, int> feedResult(const failable& val) { - if (!hasValue(val)) - return int(val); - const value v = val; - list f = cons(car(v), cons(cadr(v), feedEntriesResults(cddr(v)))); - failable, std::string> ls = atom::writeFeed(f); - if (!hasValue(ls)) - return HTTP_INTERNAL_SERVER_ERROR; - return list(ls); -} - -/** - * Convert a value to an ATOM entry result. - */ -const failable, int> entryResult(const failable& val) { - if (!hasValue(val)) - return int(val); - const value v = val; - list e = feedEntryResult(v); - std::cout<< "entry: " << e << std::endl; - failable, std::string> ls = atom::writeEntry(e); - if (!hasValue(ls)) - return HTTP_INTERNAL_SERVER_ERROR; - return list(ls); -} - /** * Write an HTTP result. */ -const int writeResult(const failable, int> ls, const std::string& ct, request_rec* r) { +const failable writeResult(const failable, std::string> ls, const std::string& ct, request_rec* r) { if (!hasValue(ls)) - return ls; + return std::string(ls); std::ostringstream os; write(ls, os); - std::cout<< "content: " << os.str() << std::endl; - std::cout.flush(); + if (logContent) { + std::cout<< "content: " << std::endl << os.str() << std::endl; + std::cout.flush(); + } 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"); @@ -314,7 +260,7 @@ const int writeResult(const failable, int> ls, const std::stri /** * Handle an HTTP GET. */ -const int get(request_rec* r) { +const failable get(request_rec* r) { // Inspect the query string const list > args = queryArgs(r); @@ -326,26 +272,34 @@ const int get(request_rec* r) { // Extract the request id, method and params const value id = cadr(ia); - const value method = std::string(cadr(ma)).c_str(); + const value func = std::string(cadr(ma)).c_str(); const list params = queryParams(args); // Evaluate the request expression - const failable val = evalExpr(cons(method, params), contribution(r), implementation(r)); + const failable val = evalExpr(cons(func, eval::quotedParameters(params)), contribution(r), implementation(r)); + if (!hasValue(val)) + return std::string(val); // Return JSON result json::JSONContext cx; - return writeResult(jsonResult(cx, id, val), "application/json-rpc", r); + return writeResult(json::jsonResult(id, val, cx), "application/json-rpc", r); } // Evaluate an ATOM GET request and return an ATOM feed - if (length(path(r)) < 2) { - const failable val = evalExpr(cons("getall"), contribution(r), implementation(r)); - return writeResult(feedResult(val), "application/atom+xml", r); + if (isNil(path(r))) { + const failable val = evalExpr(mklist("getall"), contribution(r), implementation(r)); + if (!hasValue(val)) + return std::string(val); + const value feed = val; + return writeResult(atom::writeATOMFeed(atom::feedValuesToElements(feed)), "application/atom+xml;type=feed", r); } // Evaluate an ATOM GET and return an ATOM entry - const failable val = evalExpr(cons("get", cdr(path(r))), contribution(r), implementation(r)); - return writeResult(entryResult(val), "application/atom+xml", r); + const failable val = evalExpr(cons("get", path(r)), contribution(r), implementation(r)); + if (!hasValue(val)) + return std::string(val); + const value entry = val; + return writeResult(atom::writeATOMEntry(atom::entryValuesToElements(entry)), "application/atom+xml;type=entry", r); } @@ -370,10 +324,10 @@ const list > postArgs(list a) { return cons(l, postArgs(cdr(a))); } -const char* url(const std::string& loc, request_rec* r) { +const char* url(const value& v, request_rec* r) { std::string u = r->uri; u.append("/"); - u.append(loc); + u.append(v); return ap_construct_url(r->pool, u.c_str(), r); } @@ -388,43 +342,49 @@ const value feedEntry(const list e) { /** * Handle an HTTP POST. */ -const int post(request_rec* r) { - const std::string ct = contentType(r); +const failable post(request_rec* r) { + const list ls = read(r); + if (logContent) { + std::cout<< "content: " << std::endl; + write(ls, std::cout); + std::cout<< std::endl; + std::cout.flush(); + } // Evaluate a JSON-RPC request and return a JSON result + const std::string ct = contentType(r); if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) { json::JSONContext cx; - const list json = elementsToValues(json::read(cx, read(r))); + const list json = elementsToValues(json::readJSON(ls, cx)); const list > args = postArgs(json); // Extract the request id, method and params const value id = cadr(assoc(value("id"), args)); - const value method = std::string(cadr(assoc(value("method"), args))).c_str(); + const value func = std::string(cadr(assoc(value("method"), args))).c_str(); const list params = (list)cadr(assoc(value("params"), args)); // Evaluate the request expression - const failable val = evalExpr(cons(method, params), contribution(r), implementation(r)); + const failable val = evalExpr(cons(func, eval::quotedParameters(params)), contribution(r), implementation(r)); + if (!hasValue(val)) + return std::string(val); // Return JSON result - return writeResult(jsonResult(cx, id, val), "application/json-rpc", r); + return writeResult(json::jsonResult(id, val, cx), "application/json-rpc", r); } // Evaluate an ATOM POST request and return the created resource location if (ct.find("application/atom+xml") != std::string::npos) { - const list c = read(r); - std::cout << "POST content: " << c << std::endl; - const list e = atom::readEntry(c); - std::cout << "POST entry: " << e << std::endl; - const value v = feedEntry(e); - std::cout << "POST param: " << v << std::endl; // Evaluate the request expression - const failable val = evalExpr(mklist("post", mklist(v)), contribution(r), implementation(r)); - - const char* u = url("abcd", r); - apr_table_setn(r->headers_out, "Location", u); - apr_table_setn(r->headers_out, "Content-Location", u); - return HTTP_CREATED; + const value entry = feedEntry(atom::readEntry(ls)); + const failable val = evalExpr(cons("post", eval::quotedParameters(mklist(entry))), contribution(r), implementation(r)); + if (!hasValue(val)) + return std::string(val); + + // Return the created resource location + apr_table_setn(r->headers_out, "Location", url(val, r)); + r->status = HTTP_CREATED; + return OK; } return HTTP_NOT_IMPLEMENTED; @@ -433,25 +393,48 @@ const int post(request_rec* r) { /** * Handle an HTTP PUT. */ -const int put(request_rec* r) { - // TODO later +const failable put(request_rec* r) { + const list ls = read(r); + std::cout<< "content: " << std::endl; + write(ls, std::cout); + std::cout<< std::endl; + std::cout.flush(); + + // Evaluate an ATOM PUT request + const value entry = feedEntry(atom::readEntry(ls)); + const failable val = evalExpr(cons("put", eval::quotedParameters(mklist(entry))), contribution(r), implementation(r)); + if (!hasValue(val)) + return std::string(val); + if (val == value(false)) + return HTTP_NOT_FOUND; return OK; } /** * Handle an HTTP DELETE. */ -const int del(request_rec* r) { +const failable del(request_rec* r) { // Evaluate an ATOM delete request - const failable val = evalExpr(cons("delete", cdr(path(r))), contribution(r), implementation(r)); + const failable val = evalExpr(cons("delete", path(r)), contribution(r), implementation(r)); if (!hasValue(val)) - return val; + return std::string(val); + if (val == value(false)) + return HTTP_NOT_FOUND; return OK; } /** - * HTTP handler entry point. + * Report request execution status. + */ +const int reportStatus(const failable rc) { + if (!hasValue(rc)) + return HTTP_INTERNAL_SERVER_ERROR; + return rc; +} + +/** + * HTTP request handler entry point. */ int handler(request_rec *r) { if(strcmp(r->handler, "mod_tuscany")) @@ -468,19 +451,19 @@ int handler(request_rec *r) { ap_should_client_block(r); if(r->read_chunked == true && r->remaining == 0) r->chunked = true; - apr_table_setn(r->headers_out, "Connection", "close"); + //apr_table_setn(r->headers_out, "Connection", "close"); // Handle HTTP method if (r->header_only) return OK; if(r->method_number == M_GET) - return get(r); + return reportStatus(get(r)); if(r->method_number == M_POST) - return post(r); + return reportStatus(post(r)); if(r->method_number == M_PUT) - return put(r); + return reportStatus(put(r)); if(r->method_number == M_DELETE) - return del(r); + return reportStatus(del(r)); return HTTP_NOT_IMPLEMENTED; } diff --git a/cpp/sca/modules/http/test-conf/mime.types b/cpp/sca/modules/http/test-conf/mime.types deleted file mode 100644 index 4279f51bca..0000000000 --- a/cpp/sca/modules/http/test-conf/mime.types +++ /dev/null @@ -1,607 +0,0 @@ -# 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. - -# This file controls what Internet media types are sent to the client for -# given file extension(s). Sending the correct media type to the client -# is important so they know how to handle the content of the file. -# Extra types can either be added here or by using an AddType directive -# in your config files. For more information about Internet media types, -# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type -# registry is at . - -# MIME type Extensions -application/activemessage -application/andrew-inset ez -application/applefile -application/atom+xml atom -application/atomicmail -application/batch-smtp -application/beep+xml -application/cals-1840 -application/cnrp+xml -application/commonground -application/cpl+xml -application/cybercash -application/dca-rft -application/dec-dx -application/dvcs -application/edi-consent -application/edifact -application/edi-x12 -application/eshop -application/font-tdpfr -application/http -application/hyperstudio -application/iges -application/index -application/index.cmd -application/index.obj -application/index.response -application/index.vnd -application/iotp -application/ipp -application/isup -application/mac-binhex40 hqx -application/mac-compactpro cpt -application/macwriteii -application/marc -application/mathematica -application/mathml+xml mathml -application/msword doc -application/news-message-id -application/news-transmission -application/ocsp-request -application/ocsp-response -application/octet-stream bin dms lha lzh exe class so dll dmg -application/oda oda -application/ogg ogg -application/parityfec -application/pdf pdf -application/pgp-encrypted -application/pgp-keys -application/pgp-signature -application/pkcs10 -application/pkcs7-mime -application/pkcs7-signature -application/pkix-cert -application/pkix-crl -application/pkixcmp -application/postscript ai eps ps -application/prs.alvestrand.titrax-sheet -application/prs.cww -application/prs.nprend -application/prs.plucker -application/qsig -application/rdf+xml rdf -application/reginfo+xml -application/remote-printing -application/riscos -application/rtf -application/sdp -application/set-payment -application/set-payment-initiation -application/set-registration -application/set-registration-initiation -application/sgml -application/sgml-open-catalog -application/sieve -application/slate -application/smil smi smil -application/srgs gram -application/srgs+xml grxml -application/timestamp-query -application/timestamp-reply -application/tve-trigger -application/vemmi -application/vnd.3gpp.pic-bw-large -application/vnd.3gpp.pic-bw-small -application/vnd.3gpp.pic-bw-var -application/vnd.3gpp.sms -application/vnd.3m.post-it-notes -application/vnd.accpac.simply.aso -application/vnd.accpac.simply.imp -application/vnd.acucobol -application/vnd.acucorp -application/vnd.adobe.xfdf -application/vnd.aether.imp -application/vnd.amiga.ami -application/vnd.anser-web-certificate-issue-initiation -application/vnd.anser-web-funds-transfer-initiation -application/vnd.audiograph -application/vnd.blueice.multipass -application/vnd.bmi -application/vnd.businessobjects -application/vnd.canon-cpdl -application/vnd.canon-lips -application/vnd.cinderella -application/vnd.claymore -application/vnd.commerce-battelle -application/vnd.commonspace -application/vnd.contact.cmsg -application/vnd.cosmocaller -application/vnd.criticaltools.wbs+xml -application/vnd.ctc-posml -application/vnd.cups-postscript -application/vnd.cups-raster -application/vnd.cups-raw -application/vnd.curl -application/vnd.cybank -application/vnd.data-vision.rdz -application/vnd.dna -application/vnd.dpgraph -application/vnd.dreamfactory -application/vnd.dxr -application/vnd.ecdis-update -application/vnd.ecowin.chart -application/vnd.ecowin.filerequest -application/vnd.ecowin.fileupdate -application/vnd.ecowin.series -application/vnd.ecowin.seriesrequest -application/vnd.ecowin.seriesupdate -application/vnd.enliven -application/vnd.epson.esf -application/vnd.epson.msf -application/vnd.epson.quickanime -application/vnd.epson.salt -application/vnd.epson.ssf -application/vnd.ericsson.quickcall -application/vnd.eudora.data -application/vnd.fdf -application/vnd.ffsns -application/vnd.fints -application/vnd.flographit -application/vnd.framemaker -application/vnd.fsc.weblaunch -application/vnd.fujitsu.oasys -application/vnd.fujitsu.oasys2 -application/vnd.fujitsu.oasys3 -application/vnd.fujitsu.oasysgp -application/vnd.fujitsu.oasysprs -application/vnd.fujixerox.ddd -application/vnd.fujixerox.docuworks -application/vnd.fujixerox.docuworks.binder -application/vnd.fut-misnet -application/vnd.grafeq -application/vnd.groove-account -application/vnd.groove-help -application/vnd.groove-identity-message -application/vnd.groove-injector -application/vnd.groove-tool-message -application/vnd.groove-tool-template -application/vnd.groove-vcard -application/vnd.hbci -application/vnd.hhe.lesson-player -application/vnd.hp-hpgl -application/vnd.hp-hpid -application/vnd.hp-hps -application/vnd.hp-pcl -application/vnd.hp-pclxl -application/vnd.httphone -application/vnd.hzn-3d-crossword -application/vnd.ibm.afplinedata -application/vnd.ibm.electronic-media -application/vnd.ibm.minipay -application/vnd.ibm.modcap -application/vnd.ibm.rights-management -application/vnd.ibm.secure-container -application/vnd.informix-visionary -application/vnd.intercon.formnet -application/vnd.intertrust.digibox -application/vnd.intertrust.nncp -application/vnd.intu.qbo -application/vnd.intu.qfx -application/vnd.irepository.package+xml -application/vnd.is-xpr -application/vnd.japannet-directory-service -application/vnd.japannet-jpnstore-wakeup -application/vnd.japannet-payment-wakeup -application/vnd.japannet-registration -application/vnd.japannet-registration-wakeup -application/vnd.japannet-setstore-wakeup -application/vnd.japannet-verification -application/vnd.japannet-verification-wakeup -application/vnd.jisp -application/vnd.kde.karbon -application/vnd.kde.kchart -application/vnd.kde.kformula -application/vnd.kde.kivio -application/vnd.kde.kontour -application/vnd.kde.kpresenter -application/vnd.kde.kspread -application/vnd.kde.kword -application/vnd.kenameaapp -application/vnd.koan -application/vnd.liberty-request+xml -application/vnd.llamagraphics.life-balance.desktop -application/vnd.llamagraphics.life-balance.exchange+xml -application/vnd.lotus-1-2-3 -application/vnd.lotus-approach -application/vnd.lotus-freelance -application/vnd.lotus-notes -application/vnd.lotus-organizer -application/vnd.lotus-screencam -application/vnd.lotus-wordpro -application/vnd.mcd -application/vnd.mediastation.cdkey -application/vnd.meridian-slingshot -application/vnd.micrografx.flo -application/vnd.micrografx.igx -application/vnd.mif mif -application/vnd.minisoft-hp3000-save -application/vnd.mitsubishi.misty-guard.trustweb -application/vnd.mobius.daf -application/vnd.mobius.dis -application/vnd.mobius.mbk -application/vnd.mobius.mqy -application/vnd.mobius.msl -application/vnd.mobius.plc -application/vnd.mobius.txf -application/vnd.mophun.application -application/vnd.mophun.certificate -application/vnd.motorola.flexsuite -application/vnd.motorola.flexsuite.adsi -application/vnd.motorola.flexsuite.fis -application/vnd.motorola.flexsuite.gotap -application/vnd.motorola.flexsuite.kmr -application/vnd.motorola.flexsuite.ttc -application/vnd.motorola.flexsuite.wem -application/vnd.mozilla.xul+xml xul -application/vnd.ms-artgalry -application/vnd.ms-asf -application/vnd.ms-excel xls -application/vnd.ms-lrm -application/vnd.ms-powerpoint ppt -application/vnd.ms-project -application/vnd.ms-tnef -application/vnd.ms-works -application/vnd.ms-wpl -application/vnd.mseq -application/vnd.msign -application/vnd.music-niff -application/vnd.musician -application/vnd.netfpx -application/vnd.noblenet-directory -application/vnd.noblenet-sealer -application/vnd.noblenet-web -application/vnd.novadigm.edm -application/vnd.novadigm.edx -application/vnd.novadigm.ext -application/vnd.obn -application/vnd.osa.netdeploy -application/vnd.palm -application/vnd.pg.format -application/vnd.pg.osasli -application/vnd.powerbuilder6 -application/vnd.powerbuilder6-s -application/vnd.powerbuilder7 -application/vnd.powerbuilder7-s -application/vnd.powerbuilder75 -application/vnd.powerbuilder75-s -application/vnd.previewsystems.box -application/vnd.publishare-delta-tree -application/vnd.pvi.ptid1 -application/vnd.pwg-multiplexed -application/vnd.pwg-xhtml-print+xml -application/vnd.quark.quarkxpress -application/vnd.rapid -application/vnd.s3sms -application/vnd.sealed.net -application/vnd.seemail -application/vnd.shana.informed.formdata -application/vnd.shana.informed.formtemplate -application/vnd.shana.informed.interchange -application/vnd.shana.informed.package -application/vnd.smaf -application/vnd.sss-cod -application/vnd.sss-dtf -application/vnd.sss-ntf -application/vnd.street-stream -application/vnd.svd -application/vnd.swiftview-ics -application/vnd.triscape.mxs -application/vnd.trueapp -application/vnd.truedoc -application/vnd.ufdl -application/vnd.uplanet.alert -application/vnd.uplanet.alert-wbxml -application/vnd.uplanet.bearer-choice -application/vnd.uplanet.bearer-choice-wbxml -application/vnd.uplanet.cacheop -application/vnd.uplanet.cacheop-wbxml -application/vnd.uplanet.channel -application/vnd.uplanet.channel-wbxml -application/vnd.uplanet.list -application/vnd.uplanet.list-wbxml -application/vnd.uplanet.listcmd -application/vnd.uplanet.listcmd-wbxml -application/vnd.uplanet.signal -application/vnd.vcx -application/vnd.vectorworks -application/vnd.vidsoft.vidconference -application/vnd.visio -application/vnd.visionary -application/vnd.vividence.scriptfile -application/vnd.vsf -application/vnd.wap.sic -application/vnd.wap.slc -application/vnd.wap.wbxml wbxml -application/vnd.wap.wmlc wmlc -application/vnd.wap.wmlscriptc wmlsc -application/vnd.webturbo -application/vnd.wrq-hp3000-labelled -application/vnd.wt.stf -application/vnd.wv.csp+wbxml -application/vnd.xara -application/vnd.xfdl -application/vnd.yamaha.hv-dic -application/vnd.yamaha.hv-script -application/vnd.yamaha.hv-voice -application/vnd.yellowriver-custom-menu -application/voicexml+xml vxml -application/watcherinfo+xml -application/whoispp-query -application/whoispp-response -application/wita -application/wordperfect5.1 -application/x-bcpio bcpio -application/x-cdlink vcd -application/x-chess-pgn pgn -application/x-compress -application/x-cpio cpio -application/x-csh csh -application/x-director dcr dir dxr -application/x-dvi dvi -application/x-futuresplash spl -application/x-gtar gtar -application/x-gzip -application/x-hdf hdf -application/x-javascript js -application/x-koan skp skd skt skm -application/x-latex latex -application/x-netcdf nc cdf -application/x-sh sh -application/x-shar shar -application/x-shockwave-flash swf -application/x-stuffit sit -application/x-sv4cpio sv4cpio -application/x-sv4crc sv4crc -application/x-tar tar -application/x-tcl tcl -application/x-tex tex -application/x-texinfo texinfo texi -application/x-troff t tr roff -application/x-troff-man man -application/x-troff-me me -application/x-troff-ms ms -application/x-ustar ustar -application/x-wais-source src -application/x400-bp -application/xhtml+xml xhtml xht -application/xslt+xml xslt -application/xml xml xsl -application/xml-dtd dtd -application/xml-external-parsed-entity -application/zip zip -audio/32kadpcm -audio/amr -audio/amr-wb -audio/basic au snd -audio/cn -audio/dat12 -audio/dsr-es201108 -audio/dvi4 -audio/evrc -audio/evrc0 -audio/g722 -audio/g.722.1 -audio/g723 -audio/g726-16 -audio/g726-24 -audio/g726-32 -audio/g726-40 -audio/g728 -audio/g729 -audio/g729D -audio/g729E -audio/gsm -audio/gsm-efr -audio/l8 -audio/l16 -audio/l20 -audio/l24 -audio/lpc -audio/midi mid midi kar -audio/mpa -audio/mpa-robust -audio/mp4a-latm -audio/mpeg mpga mp2 mp3 -audio/parityfec -audio/pcma -audio/pcmu -audio/prs.sid -audio/qcelp -audio/red -audio/smv -audio/smv0 -audio/telephone-event -audio/tone -audio/vdvi -audio/vnd.3gpp.iufp -audio/vnd.cisco.nse -audio/vnd.cns.anp1 -audio/vnd.cns.inf1 -audio/vnd.digital-winds -audio/vnd.everad.plj -audio/vnd.lucent.voice -audio/vnd.nortel.vbk -audio/vnd.nuera.ecelp4800 -audio/vnd.nuera.ecelp7470 -audio/vnd.nuera.ecelp9600 -audio/vnd.octel.sbc -audio/vnd.qcelp -audio/vnd.rhetorex.32kadpcm -audio/vnd.vmx.cvsd -audio/x-aiff aif aiff aifc -audio/x-alaw-basic -audio/x-mpegurl m3u -audio/x-pn-realaudio ram ra -audio/x-pn-realaudio-plugin -application/vnd.rn-realmedia rm -audio/x-wav wav -chemical/x-pdb pdb -chemical/x-xyz xyz -image/bmp bmp -image/cgm cgm -image/g3fax -image/gif gif -image/ief ief -image/jpeg jpeg jpg jpe -image/naplps -image/png png -image/prs.btif -image/prs.pti -image/svg+xml svg -image/t38 -image/tiff tiff tif -image/tiff-fx -image/vnd.cns.inf2 -image/vnd.djvu djvu djv -image/vnd.dwg -image/vnd.dxf -image/vnd.fastbidsheet -image/vnd.fpx -image/vnd.fst -image/vnd.fujixerox.edmics-mmr -image/vnd.fujixerox.edmics-rlc -image/vnd.globalgraphics.pgb -image/vnd.mix -image/vnd.ms-modi -image/vnd.net-fpx -image/vnd.svf -image/vnd.wap.wbmp wbmp -image/vnd.xiff -image/x-cmu-raster ras -image/x-icon ico -image/x-portable-anymap pnm -image/x-portable-bitmap pbm -image/x-portable-graymap pgm -image/x-portable-pixmap ppm -image/x-rgb rgb -image/x-xbitmap xbm -image/x-xpixmap xpm -image/x-xwindowdump xwd -message/delivery-status -message/disposition-notification -message/external-body -message/http -message/news -message/partial -message/rfc822 -message/s-http -message/sip -message/sipfrag -model/iges igs iges -model/mesh msh mesh silo -model/vnd.dwf -model/vnd.flatland.3dml -model/vnd.gdl -model/vnd.gs-gdl -model/vnd.gtw -model/vnd.mts -model/vnd.parasolid.transmit.binary -model/vnd.parasolid.transmit.text -model/vnd.vtu -model/vrml wrl vrml -multipart/alternative -multipart/appledouble -multipart/byteranges -multipart/digest -multipart/encrypted -multipart/form-data -multipart/header-set -multipart/mixed -multipart/parallel -multipart/related -multipart/report -multipart/signed -multipart/voice-message -text/calendar ics ifb -text/css css -text/directory -text/enriched -text/html html htm -text/parityfec -text/plain asc txt -text/prs.lines.tag -text/rfc822-headers -text/richtext rtx -text/rtf rtf -text/sgml sgml sgm -text/t140 -text/tab-separated-values tsv -text/uri-list -text/vnd.abc -text/vnd.curl -text/vnd.dmclientscript -text/vnd.fly -text/vnd.fmi.flexstor -text/vnd.in3d.3dml -text/vnd.in3d.spot -text/vnd.iptc.nitf -text/vnd.iptc.newsml -text/vnd.latex-z -text/vnd.motorola.reflex -text/vnd.ms-mediapackage -text/vnd.net2phone.commcenter.command -text/vnd.sun.j2me.app-descriptor -text/vnd.wap.si -text/vnd.wap.sl -text/vnd.wap.wml wml -text/vnd.wap.wmlscript wmls -text/x-setext etx -text/xml -text/xml-external-parsed-entity -video/bmpeg -video/bt656 -video/celb -video/dv -video/h261 -video/h263 -video/h263-1998 -video/h263-2000 -video/jpeg -video/mp1s -video/mp2p -video/mp2t -video/mp4v-es -video/mpv -video/mpeg mpeg mpg mpe -video/nv -video/parityfec -video/pointer -video/quicktime qt mov -video/smpte292m -video/vnd.fvt -video/vnd.motorola.video -video/vnd.motorola.videop -video/vnd.mpegurl mxu m4u -video/vnd.nokia.interleaved-multimedia -video/vnd.objectvideo -video/vnd.vivo -video/x-msvideo avi -video/x-sgi-movie movie -x-conference/x-cooltalk ice diff --git a/cpp/sca/modules/http/test-htdocs/index.html b/cpp/sca/modules/http/test-htdocs/index.html deleted file mode 100644 index 1bfb3e30c2..0000000000 --- a/cpp/sca/modules/http/test-htdocs/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - -

It works!

- diff --git a/cpp/sca/modules/json/json-test.cpp b/cpp/sca/modules/json/json-test.cpp index bf0ecab1f4..0d4e8f6a16 100644 --- a/cpp/sca/modules/json/json-test.cpp +++ b/cpp/sca/modules/json/json-test.cpp @@ -43,7 +43,7 @@ bool testJSEval() { return true; } -std::ostringstream* jsonWriter(std::ostringstream* os, const std::string& s) { +std::ostringstream* jsonWriter(const std::string& s, std::ostringstream* os) { (*os) << s; return os; } @@ -57,7 +57,7 @@ bool testJSON() { const list cr = mklist(mklist (attribute, "name", std::string("jdoe")), cons(element, cons("address", ad)), cons(element, cons("account", ac))); const list c = mklist(cons(element, cons("customer", cr))); std::ostringstream os; - write(cx, jsonWriter, &os, c); + writeJSON(jsonWriter, &os, c, cx); assert(os.str() == "{\"customer\":{\"name\":\"jdoe\",\"address\":{\"city\":\"san francisco\",\"state\":\"ca\"},\"account\":{\"id\":\"1234\",\"balance\":1000}}}"); } { @@ -65,16 +65,16 @@ bool testJSON() { const list l = mklist (mklist (element, "phones", phones), mklist (element, "lastName", std::string("test\ttab")), mklist (element, "firstName", std::string("test1"))); std::ostringstream os; - write(cx, jsonWriter, &os, l); + writeJSON(jsonWriter, &os, l, cx); assert(os.str() == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"firstName\":\"test1\"}"); std::istringstream is(os.str()); const list il = streamList(is); - const list r = read(cx, il); + const list r = readJSON(il, cx); assert(r == l); std::ostringstream wos; - write(write(cx, r), wos); + write(writeJSON(r, cx), wos); assert(wos.str() == os.str()); } return true; @@ -84,7 +84,7 @@ bool testJSONRPC() { JSONContext cx; { const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}"); - const list e = read(cx, mklist(lm)); + const list e = readJSON(mklist(lm), cx); const list v = elementsToValues(e); assert(assoc("id", v) == mklist("id", 1)); assert(assoc("method", v) == mklist("method", std::string("system.listMethods"))); @@ -92,16 +92,16 @@ bool testJSONRPC() { } { const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}"); - const list e = read(cx, mklist(i)); + const list e = readJSON(mklist(i), cx); const std::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 e2 = read(cx, mklist(i)); + const list e2 = readJSON(mklist(i), cx); assert(e == e2); } { const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}"); - const list e = read(cx, mklist(i)); + const list e = readJSON(mklist(i), cx); std::ostringstream os; - write(write(cx, e), os); + write(writeJSON(e, cx), os); assert(os.str() == i); const list v = elementsToValues(e); const list r = valuesToElements(v); @@ -111,7 +111,7 @@ bool testJSONRPC() { const list r = mklist(mklist("id", 1), mklist("result", mklist(std::string("Service.get"), std::string("Service.getTotal")))); const list e = valuesToElements(r); std::ostringstream os; - write(write(cx, e), os); + write(writeJSON(e, cx), os); assert(os.str() == "{\"id\":1,\"result\":[\"Service.get\",\"Service.getTotal\"]}"); } return true; diff --git a/cpp/sca/modules/json/json.hpp b/cpp/sca/modules/json/json.hpp index 8e4666196e..0d21cfe359 100644 --- a/cpp/sca/modules/json/json.hpp +++ b/cpp/sca/modules/json/json.hpp @@ -142,9 +142,9 @@ private: /** * Converts JS properties to values. */ -const list jsPropertiesToValues(const JSONContext& cx, const list& propertiesSoFar, JSObject* o, JSObject* i) { +const list jsPropertiesToValues(const list& propertiesSoFar, JSObject* o, JSObject* i, const JSONContext& cx) { - const value jsValToValue(const JSONContext& cx, const jsval& jsv); + const value jsValToValue(const jsval& jsv, const JSONContext& cx); jsid id; if(!JS_NextProperty(cx, i, &id) || id == JSVAL_VOID) @@ -152,20 +152,20 @@ const list jsPropertiesToValues(const JSONContext& cx, const list& jsval jsv; if(!JS_GetPropertyById(cx, o, id, &jsv)) return propertiesSoFar; - const value val = jsValToValue(cx, jsv); + const value val = jsValToValue(jsv, cx); jsval idv; JS_IdToValue(cx, id, &idv); if(JSVAL_IS_STRING(idv)) { const value type = isList(val)? element : element; - return jsPropertiesToValues(cx, cons (mklist (type, JS_GetStringBytes(JSVAL_TO_STRING(idv)), val), propertiesSoFar), o, i); + return jsPropertiesToValues(cons (mklist (type, JS_GetStringBytes(JSVAL_TO_STRING(idv)), val), propertiesSoFar), o, i, cx); } - return jsPropertiesToValues(cx, cons(val, propertiesSoFar), o, i); + return jsPropertiesToValues(cons(val, propertiesSoFar), o, i, cx); } /** * Converts a JS val to a value. */ -const value jsValToValue(const JSONContext& cx, const jsval& jsv) { +const value jsValToValue(const jsval& jsv, const JSONContext& cx) { switch(JS_TypeOfValue(cx, jsv)) { case JSTYPE_STRING: { return value(std::string(JS_GetStringBytes(JSVAL_TO_STRING(jsv)))); @@ -183,7 +183,7 @@ const value jsValToValue(const JSONContext& cx, const jsval& jsv) { JSObject* i = JS_NewPropertyIterator(cx, o); if(i == NULL) return value(list ()); - const value pv = jsPropertiesToValues(cx, list (), o, i); + const value pv = jsPropertiesToValues(list (), o, i, cx); return pv; } default: { @@ -195,44 +195,44 @@ const value jsValToValue(const JSONContext& cx, const jsval& jsv) { /** * Consumes JSON strings and populates a JS object. */ -failable consume(const JSONContext& cx, JSONParser* parser, const list& ilist) { +failable consume(JSONParser* parser, const list& ilist, const JSONContext& cx) { if (isNil(ilist)) return true; JSString* jstr = JS_NewStringCopyZ(cx, car(ilist).c_str()); if(!JS_ConsumeJSONText(cx, parser, JS_GetStringChars(jstr), JS_GetStringLength(jstr))) return "JS_ConsumeJSONText failed"; - return consume(cx, parser, cdr(ilist)); + return consume(parser, cdr(ilist), cx); } /** * Convert a list of strings representing a JSON document to a list of values. */ -const failable, std::string> read(const JSONContext& cx, const list& ilist) { +const failable, std::string> readJSON(const list& ilist, const JSONContext& cx) { jsval val; JSONParser* parser = JS_BeginJSONParse(cx, &val); if(parser == NULL) return std::string("JS_BeginJSONParse failed"); - const failable consumed = consume(cx, parser, ilist); + const failable consumed = consume(parser, ilist, cx); if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL)) return std::string("JS_FinishJSONParse failed"); if(!hasValue(consumed)) return std::string(consumed); - return list(jsValToValue(cx, val)); + return list(jsValToValue(val, cx)); } /** * Converts a list of values to JS array elements. */ -JSObject* valuesToJSElements(const JSONContext& cx, JSObject* a, const list& l, int i) { - const jsval valueToJSVal(const JSONContext& cx, const value& val); +JSObject* valuesToJSElements(JSObject* a, const list& l, int i, const JSONContext& cx) { + const jsval valueToJSVal(const value& val, const JSONContext& cx); if (isNil(l)) return a; - jsval pv = valueToJSVal(cx, car(l)); + jsval pv = valueToJSVal(car(l), cx); JS_SetElement(cx, a, i, &pv); - return valuesToJSElements(cx, a, cdr(l), ++i); + return valuesToJSElements(a, cdr(l), ++i, cx); } /** @@ -255,26 +255,26 @@ const bool isJSArray(const list& l) { /** * Converts a list of values to JS properties. */ -JSObject* valuesToJSProperties(const JSONContext& cx, JSObject* o, const list& l) { - const jsval valueToJSVal(const JSONContext& cx, const value& val); +JSObject* valuesToJSProperties(JSObject* o, const list& l, const JSONContext& cx) { + const jsval valueToJSVal(const value& val, const JSONContext& cx); if(isNil(l)) return o; const list p = car(l); - jsval pv = valueToJSVal(cx, caddr(p)); + jsval pv = valueToJSVal(caddr(p), cx); JS_SetProperty(cx, o, ((std::string)cadr(p)).c_str(), &pv); - return valuesToJSProperties(cx, o, cdr(l)); + return valuesToJSProperties(o, cdr(l), cx); } /** * Converts a value to a JS val. */ -const jsval valueToJSVal(const JSONContext& cx, const value& val) { +const jsval valueToJSVal(const value& val, const JSONContext& cx) { switch(type(val)) { case value::String: case value::Symbol: { return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, ((std::string)val).c_str())); } - case value::Boolean: { + case value::Bool: { return BOOLEAN_TO_JSVAL((bool)val); } case value::Number: { @@ -282,8 +282,8 @@ const jsval valueToJSVal(const JSONContext& cx, const value& val) { } case value::List: { if (isJSArray(val)) - return OBJECT_TO_JSVAL(valuesToJSElements(cx, JS_NewArrayObject(cx, 0, NULL), val, 0)); - return OBJECT_TO_JSVAL(valuesToJSProperties(cx, JS_NewObject(cx, NULL, NULL, NULL), val)); + return OBJECT_TO_JSVAL(valuesToJSElements(JS_NewArrayObject(cx, 0, NULL), val, 0, cx)); + return OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), val, cx)); } default: { return JSVAL_VOID; @@ -291,7 +291,7 @@ const jsval valueToJSVal(const JSONContext& cx, const value& val) { } } -const failable writeList(const JSONContext& cx, const list& l, JSObject* o) { +const failable writeList(const list& l, JSObject* o, const JSONContext& cx) { if (isNil(l)) return true; @@ -299,14 +299,14 @@ const failable writeList(const JSONContext& cx, const list writeList(const JSONContext& cx, const list w = writeList(cx, elementChildren(token), child); + const failable w = writeList(elementChildren(token), child, cx); if (!hasValue(w)) return w; } } // Go on - return writeList(cx, cdr(l), o); + return writeList(cdr(l), o, cx); } /** @@ -332,10 +332,10 @@ const failable writeList(const JSONContext& cx, const list class WriteContext { public: - WriteContext(const JSONContext& cx, const lambda& reduce, const R& accum) : cx(cx), reduce(reduce), accum(accum) { + WriteContext(const lambda& reduce, const R& accum, const JSONContext& cx) : cx(cx), reduce(reduce), accum(accum) { } const JSONContext& cx; - const lambda reduce; + const lambda reduce; R accum; }; @@ -345,21 +345,21 @@ public: template JSBool writeCallback(const jschar *buf, uint32 len, void *data) { WriteContext& wcx = *(static_cast*> (data)); JSString* jstr = JS_NewUCStringCopyN(wcx.cx, buf, len); - wcx.accum = wcx.reduce(wcx.accum, std::string(JS_GetStringBytes(jstr), JS_GetStringLength(jstr))); + wcx.accum = wcx.reduce(std::string(JS_GetStringBytes(jstr), JS_GetStringLength(jstr)), wcx.accum); return JS_TRUE; } /** * Convert a list of values to a JSON document. */ -template const failable write(const JSONContext& cx, const lambda& reduce, const R& initial, const list& l) { +template const failable writeJSON(const lambda& reduce, const R& initial, const list& l, const JSONContext& cx) { JSObject* o = JS_NewObject(cx, NULL, NULL, NULL); jsval val = OBJECT_TO_JSVAL(o); - const failable w = writeList(cx, l, o); + const failable w = writeList(l, o, cx); if (!hasValue(w)) return std::string(w); - WriteContext wcx(cx, reduce, initial); + WriteContext wcx(reduce, initial, cx); if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback, &wcx)) return std::string("JS_Stringify failed"); return wcx.accum; @@ -368,17 +368,29 @@ template const failable write(const JSONContext& cx, /** * Convert a list of values to a list of strings representing a JSON document. */ -const list writeStrings(const list& listSoFar, const std::string& s) { - return cons(s, listSoFar); -} - -const failable, std::string> write(const JSONContext& cx, const list& l) { - const failable, std::string> ls = write >(cx, writeStrings, list(), l); +const failable, std::string> writeJSON(const list& l, const JSONContext& cx) { + const failable, std::string> ls = writeJSON >(rcons, list(), l, cx); if (!hasValue(ls)) return ls; return reverse(list(ls)); } +/** + * Convert a function + params to a JSON request. + */ +const failable, std::string> jsonRequest(const value& id, const value& func, const value& params, json::JSONContext& cx) { + const list r = mklist(mklist("id", id), mklist("method", func), mklist("params", params)); + failable, std::string> ls = writeJSON(valuesToElements(r), cx); + return ls; +} + +/** + * Convert a value to a JSON result. + */ +const failable, std::string> jsonResult(const value& id, const value& val, JSONContext& cx) { + return writeJSON(valuesToElements(mklist(mklist("id", id), mklist("result", val))), cx); +} + } } -- cgit v1.2.3