diff options
Diffstat (limited to '')
-rw-r--r-- | cpp/sca/modules/http/Makefile.am (renamed from cpp/sca/modules/httpd/Makefile.am) | 10 | ||||
-rw-r--r-- | cpp/sca/modules/http/curl-test.cpp | 73 | ||||
-rw-r--r-- | cpp/sca/modules/http/curl.hpp | 150 | ||||
-rwxr-xr-x | cpp/sca/modules/http/http-test | 34 | ||||
-rwxr-xr-x | cpp/sca/modules/http/httpd-test | 38 | ||||
-rw-r--r-- | cpp/sca/modules/http/mod.cpp (renamed from cpp/sca/modules/httpd/mod.cpp) | 334 | ||||
-rw-r--r-- | cpp/sca/modules/http/test-conf/mime.types | 607 | ||||
-rw-r--r-- | cpp/sca/modules/http/test-htdocs/index.html | 21 |
8 files changed, 1161 insertions, 106 deletions
diff --git a/cpp/sca/modules/httpd/Makefile.am b/cpp/sca/modules/http/Makefile.am index 13cb3045f6..d34da0822f 100644 --- a/cpp/sca/modules/httpd/Makefile.am +++ b/cpp/sca/modules/http/Makefile.am @@ -15,10 +15,18 @@ # specific language governing permissions and limitations # under the License. +noinst_PROGRAMS = curl-test + libdir=$(prefix)/lib lib_LTLIBRARIES = libmod_tuscany.la -INCLUDES = -I. -I$(top_builddir)/kernel -I${HTTPD_INCLUDE} -I${APR_INCLUDE} -I${LIBXML2_INCLUDE} -I${LIBMOZJS_INCLUDE} +INCLUDES = -I. -I$(top_builddir)/kernel -I${HTTPD_INCLUDE} -I${APR_INCLUDE} -I${LIBXML2_INCLUDE} -I${LIBMOZJS_INCLUDE} -I${CURL_INCLUDE} libmod_tuscany_la_SOURCES = mod.cpp libmod_tuscany_la_LIBADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${LIBMOZJS_LIB} -lmozjs + +curl_test_SOURCES = curl-test.cpp +curl_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${CURL_LIB} -lcurl + +TESTS = httpd-test http-test + diff --git a/cpp/sca/modules/http/curl-test.cpp b/cpp/sca/modules/http/curl-test.cpp new file mode 100644 index 0000000000..4e23a036da --- /dev/null +++ b/cpp/sca/modules/http/curl-test.cpp @@ -0,0 +1,73 @@ +/* + * 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 JSON data conversion functions. + */ + +#include <assert.h> +#include <iostream> +#include <sstream> +#include <string> +#include "slist.hpp" +#include "curl.hpp" + +namespace tuscany { +namespace http { + +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) { + (*os) << s; + return os; +} + +const bool testCURL() { + { + std::ostringstream os; + const failable<std::ostringstream*, int> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:9091"); + assert(hasValue(r)); + assert(contains(os.str(), "It works")); + } + { + std::ostringstream os; + const failable<list<std::string>, int> r = get("http://localhost:9091"); + assert(hasValue(r)); + write(r, os); + assert(contains(os.str(), "It works")); + } + return true; +} + +} +} + +int main() { + std::cout << "Testing..." << std::endl; + + tuscany::http::testCURL(); + + std::cout << "OK" << std::endl; + + return 0; +} diff --git a/cpp/sca/modules/http/curl.hpp b/cpp/sca/modules/http/curl.hpp new file mode 100644 index 0000000000..2ea23010cb --- /dev/null +++ b/cpp/sca/modules/http/curl.hpp @@ -0,0 +1,150 @@ +/* + * 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_curl_hpp +#define tuscany_curl_hpp + +/** + * CURL HTTP client functions. + */ + +#include <curl/curl.h> +#include <curl/types.h> +#include <curl/easy.h> +#include <string> +#include "list.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" + +namespace tuscany { +namespace http { + +/** + * CURL library context, one per process. + */ +class CURLContext { +public: + CURLContext() { + curl_global_init(CURL_GLOBAL_ALL); + } + ~CURLContext() { + curl_global_cleanup(); + } +}; + +CURLContext curlContext; + +/** + * Represents a CURL session handle. + */ +class CURLHandle { +public: + CURLHandle() : h(curl_easy_init()) { + } + ~CURLHandle() { + curl_easy_cleanup(h); + } + + operator CURL*() const { + return h; + } +private: + CURL* h; +}; + +/** + * Context passed to CURL write callback function. + */ +template<typename R> class CURLWriteContext { +public: + CURLWriteContext(const lambda<R(R, std::string)>& reduce, const R& accum) : reduce(reduce), accum(accum) { + } + const lambda<R(R, std::string)> reduce; + R accum; +}; + +/** + * Called by CURL to write received data. + */ +template<typename R> size_t writeCallback(void *ptr, size_t size, size_t nmemb, void *data) { + CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data)); + const size_t realsize = size * nmemb; + wcx.accum = wcx.reduce(wcx.accum, std::string((const char*)ptr, realsize)); + return realsize; +} + +/** + * Called by CURL to write received header data. + */ +template<typename R> size_t headerCallback(void *ptr, size_t size, size_t nmemb, void *data) { + CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data)); + const size_t realsize = size * nmemb; + wcx.accum = wcx.reduce(wcx.accum, std::string((const char*)ptr, realsize)); + return realsize; +} + +/** + * HTTP GET, get a resource from a URL. + */ +template<typename R> const failable<R, int> get(const lambda<R(R, std::string)>& reduce, const R& initial, const std::string& url) { + CURLWriteContext<R> wcx(reduce, initial); + + // 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_setopt(ch, CURLOPT_WRITEFUNCTION, (size_t (*)(void*, size_t, size_t, void*))writeCallback<R>); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, &wcx); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))headerCallback<R>); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, &wcx); + + // Perform the HTTP GET + const CURLcode rc = curl_easy_perform(ch); + if (rc) + return rc; + + // Return the HTTP return code or content + long httprc; + curl_easy_getinfo (ch, CURLINFO_RESPONSE_CODE, &httprc); + if (httprc != 200) + return httprc; + return wcx.accum; +} + +/** + * HTTP GET, get a list of values representing a resource from a URL. + */ +const list<std::string> writeStringList(const list<std::string>& listSoFar, const std::string& s) { + return cons(s, listSoFar); +} + +const failable<list<std::string>, int> get(const std::string& url) { + const failable<list<std::string>, int> r = get<list<std::string> >(writeStringList, list<std::string>(), url); + if (!hasValue(r)) + return r; + return reverse(list<std::string>(r)); +} + +} +} + +#endif /* tuscany_curl_hpp */ diff --git a/cpp/sca/modules/http/http-test b/cpp/sca/modules/http/http-test new file mode 100755 index 0000000000..b0dd21cbd1 --- /dev/null +++ b/cpp/sca/modules/http/http-test @@ -0,0 +1,34 @@ +#!/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. + +mkdir -p tmp +mkdir -p tmp/conf +cp test-conf/* tmp/conf +cat >tmp/conf/httpd.conf <<EOF +ServerName 127.0.0.1 +Listen 9091 +DocumentRoot `pwd`/test-htdocs +EOF +mkdir -p tmp/logs +apachectl -k start -d `pwd`/tmp +sleep 1 +./curl-test +rc=$? +apachectl -k stop -d `pwd`/tmp +return $rc diff --git a/cpp/sca/modules/http/httpd-test b/cpp/sca/modules/http/httpd-test new file mode 100755 index 0000000000..3e4c5f82de --- /dev/null +++ b/cpp/sca/modules/http/httpd-test @@ -0,0 +1,38 @@ +#!/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. + +echo "Testing..." +mkdir -p tmp +mkdir -p tmp/conf +cp test-conf/* tmp/conf +cat >tmp/conf/httpd.conf <<EOF +ServerName 127.0.0.1 +Listen 9090 +DocumentRoot `pwd`/test-htdocs +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 +rc=$? +apachectl -k stop -d `pwd`/tmp +if [ "$rc" = "0" ]; then + echo "OK" +fi +return $rc diff --git a/cpp/sca/modules/httpd/mod.cpp b/cpp/sca/modules/http/mod.cpp index 81e12934e7..88891a668c 100644 --- a/cpp/sca/modules/httpd/mod.cpp +++ b/cpp/sca/modules/http/mod.cpp @@ -52,6 +52,7 @@ #include "value.hpp" #include "element.hpp" #include "monad.hpp" +#include "../atom/atom.hpp" #include "../json/json.hpp" #include "../eval/driver.hpp" @@ -60,6 +61,7 @@ extern module AP_MODULE_DECLARE_DATA mod_tuscany; } namespace tuscany { +namespace httpd { /** * Server configuration. @@ -106,13 +108,36 @@ const std::string implementation(request_rec* r) { /** * Returns an HTTP request path as a list of strings. */ -const list<std::string> path(const request_rec* r) { +const list<std::string> pathTokens(const request_rec* r) { const char* p = r->path_info; if (p == NULL || p[0] == '\0') return list<std::string>(); return tokenize("/", p + 1); } +const list<value> pathValues(const list<std::string>& l) { + if (isNil(l)) + return list<value>(); + return cons<value>(car(l), pathValues(cdr(l))); +} + +const list<value> path(const request_rec* r) { + return pathValues(pathTokens(r)); +} + +/** + * Return the content type of a request. + */ +const char* optional(const char* s) { + if (s == NULL) + return "(null)"; + return s; +} + +const std::string contentType(const request_rec* r) { + return optional(apr_table_get(r->headers_in, "Content-Type")); +} + /** * Log HTTP request info to standard out for now, for debugging purposes. */ @@ -123,12 +148,6 @@ int logHeader(void* r, const char* key, const char* value) { return 1; } -const char* optional(const char* s) { - if (s == NULL) - return "(null)"; - return s; -} - const bool logRequest(request_rec* r) { std::cout << "mod-tuscany..." << std::endl; std::cout << "tuscany home: " << home(r) << std::endl; @@ -137,23 +156,49 @@ const bool logRequest(request_rec* r) { std::cout << "protocol: " << optional(r->protocol) << std::endl; std::cout << "method: " << optional(r->method) << std::endl; std::cout << "method number: " << r->method_number << std::endl; - std::cout << "content type: " << optional(apr_table_get(r->headers_in, "Content-Type")) << std::endl; + std::cout << "content type: " << contentType(r) << std::endl; std::cout << "content encoding: " << optional(r->content_encoding) << std::endl; apr_table_do(logHeader, r, r->headers_in, NULL); std::cout << "uri: " << optional(r->uri) << std::endl; std::cout << "path info: " << optional(r->path_info) << std::endl; - std::cout << "path: " << path(r) << std::endl; + std::cout << "path: " << pathTokens(r) << std::endl; std::cout << "args: " << optional(r->args) << std::endl; std::cout.flush(); return true; } -const value evalLoop(std::istream& is, const value& req, Env& globalEnv) { - value in = read(is); +/** + * Evaluate an expression against a component implementation. + */ +const value evalExprLoop(std::istream& is, const value& req, eval::Env& globalEnv) { + value in = eval::read(is); if (isNil(in)) - return eval(req, globalEnv); - eval(in, globalEnv); - return evalLoop(is, req, globalEnv); + return eval::evalApply(req, globalEnv); + eval::evalApply(in, globalEnv); + return evalExprLoop(is, req, globalEnv); +} + +const failable<value, int> 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); + + // 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; + + // Evaluate the expr + std::cout<< "expr: " << expr << std::endl; + std::cout.flush(); + const value val = evalExprLoop(is, expr, globalEnv); + std::cout<< "val: " << val << std::endl; + std::cout.flush(); + if (isNil(val)) + return HTTP_INTERNAL_SERVER_ERROR; + return val; } /** @@ -178,67 +223,133 @@ const list<list<value> > queryArgs(const request_rec* r) { const list<value> queryParams(list<list<value> > a) { if (isNil(a)) return list<value>(); - if (car(a) == value("id") || car(a) == value("method")) + const list<value> p = car(a); + if (car(p) == value("id") || car(p) == value("method")) return queryParams(cdr(a)); - return cons(cadr(car(a)), queryParams(cdr(a))); + return cons(cadr(p), queryParams(cdr(a))); } /** - * Handle an HTTP GET request. + * Convert a value to a JSON result. */ -const int get(request_rec* r) { - - // Setup the script evaluator - Env globalEnv = setupEnvironment(); - std::ostringstream nullos; - setupEvalOut(nullos); - - // Open the component implementation - const std::string impl = contribution(r) + implementation(r); - std::ifstream is(impl.c_str(), std::ios_base::in); - if (is.fail() || is.bad()) - return HTTP_NOT_FOUND; +const failable<list<std::string>, int> jsonResult(json::JSONContext& cx, const value& id, const failable<value, int>& val) { + if (!hasValue(val)) + return int(val); + const list<value> r = mklist<value>(mklist<value>("id", id), mklist<value>("result", val)); + failable<list<std::string>, 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<std::string>(ls); +} - // Extract the request id, method and params from the query string - const list<list<value> > args = queryArgs(r); - const value id = cadr(assoc(value("id"), args)); - const value method = std::string(cadr(assoc(value("method"), args))).c_str(); - const list<value> params = queryParams(args); +/** + * Convert a value to an ATOM entry. + */ +const list<value> feedEntryResult(const list<value> e) { + return cons(car(e), cons(cadr(e), valuesToElements(mklist<value>(cons<value>("item", (list<value>)caddr(e)))))); +} - // Build expr to evaluate - const value expr = cons<value>(method, params); - std::cout<< "expr: " << expr << std::endl; - std::cout.flush(); +/** + * Convert a value to an ATOM feed. + */ +const list<value> feedEntriesResults(const list<value> e) { + if (isNil(e)) + return list<value>(); + return cons<value>(feedEntryResult(car(e)), feedEntriesResults(cdr(e))); +} - // Evaluate the expr - const tuscany::value val = evalLoop(is, expr, globalEnv); - if (isNil(val)) +const failable<list<std::string>, int> feedResult(const failable<value, int>& val) { + if (!hasValue(val)) + return int(val); + const value v = val; + list<value> f = cons(car<value>(v), cons<value>(cadr<value>(v), feedEntriesResults(cddr<value>(v)))); + failable<list<std::string>, std::string> ls = atom::writeFeed(f); + if (!hasValue(ls)) return HTTP_INTERNAL_SERVER_ERROR; - std::cout<< "val: " << val << std::endl; - std::cout.flush(); + return list<std::string>(ls); +} - // Convert the expr value to JSON - const JSONContext cx; - failable<list<std::string>, std::string> jsval = writeJSON(cx, mklist<value>(mklist<value>("id", id), mklist<value>("result", val))); - if (!hasValue(jsval)) +/** + * Convert a value to an ATOM entry result. + */ +const failable<list<std::string>, int> entryResult(const failable<value, int>& val) { + if (!hasValue(val)) + return int(val); + const value v = val; + list<value> e = feedEntryResult(v); + std::cout<< "entry: " << e << std::endl; + failable<list<std::string>, std::string> ls = atom::writeEntry(e); + if (!hasValue(ls)) return HTTP_INTERNAL_SERVER_ERROR; + return list<std::string>(ls); +} - // Send the response - ap_set_content_type(r, "application/json-rpc"); +/** + * Write an HTTP result. + */ +const int writeResult(const failable<list<std::string>, int> ls, const std::string& ct, request_rec* r) { + if (!hasValue(ls)) + return ls; std::ostringstream os; - write(jsval, os); - std::string sval = os.str(); - std::string etag(ap_md5(r->pool, (const unsigned char*)sval.c_str())); + write(ls, os); + std::cout<< "content: " << 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"); - if (match != NULL && etag == match) - r->status = HTTP_NOT_MODIFIED; apr_table_setn(r->headers_out, "ETag", etag.c_str()); - ap_rputs(sval.c_str(), r); - + if (match != NULL && etag == match) { + r->status = HTTP_NOT_MODIFIED; + return OK; + } + ap_set_content_type(r, ct.c_str()); + ap_rputs(std::string(os.str()).c_str(), r); return OK; } /** + * Handle an HTTP GET. + */ +const int get(request_rec* r) { + + // Inspect the query string + const list<list<value> > args = queryArgs(r); + const list<value> ia = assoc(value("id"), args); + const list<value> ma = assoc(value("method"), args); + + // Evaluate a JSON-RPC request and return a JSON result + if (!isNil(ia) && !isNil(ma)) { + + // Extract the request id, method and params + const value id = cadr(ia); + const value method = std::string(cadr(ma)).c_str(); + const list<value> params = queryParams(args); + + // Evaluate the request expression + const failable<value, int> val = evalExpr(cons(method, params), contribution(r), implementation(r)); + + // Return JSON result + json::JSONContext cx; + return writeResult(jsonResult(cx, id, val), "application/json-rpc", r); + } + + // Evaluate an ATOM GET request and return an ATOM feed + if (length(path(r)) < 2) { + const failable<value, int> val = evalExpr(cons<value>("getall"), contribution(r), implementation(r)); + return writeResult(feedResult(val), "application/atom+xml", r); + } + + // Evaluate an ATOM GET and return an ATOM entry + const failable<value, int> val = evalExpr(cons<value>("get", cdr(path(r))), contribution(r), implementation(r)); + return writeResult(entryResult(val), "application/atom+xml", r); + +} + +/** * Read the content of a POST. */ const list<std::string> read(request_rec* r) { @@ -259,71 +370,83 @@ const list<list<value> > postArgs(list<value> a) { return cons(l, postArgs(cdr(a))); } +const char* url(const std::string& loc, request_rec* r) { + std::string u = r->uri; + u.append("/"); + u.append(loc); + return ap_construct_url(r->pool, u.c_str(), r); +} + /** - * Handle an HTTP POST request. + * Convert an ATOM entry to a value. */ -const int post(request_rec* r) { - - // Setup the script evaluator - Env globalEnv = setupEnvironment(); - std::ostringstream nullos; - setupEvalOut(nullos); - - // Open the component implementation - const std::string impl = contribution(r) + implementation(r); - std::ifstream is(impl.c_str(), std::ios_base::in); - if (is.fail() || is.bad()) - return HTTP_NOT_FOUND; +const value feedEntry(const list<value> e) { + const list<value> v = elementsToValues(mklist<value>(caddr(e))); + return cons(car(e), mklist<value>(cadr(e), cdr<value>(car(v)))); +} - // Read the JSON request - const list<std::string> req = read(r); - JSONContext cx; - const list<value> json = elementsToValues(readJSON(cx, req)); - const list<list<value> > args = postArgs(json); +/** + * Handle an HTTP POST. + */ +const int post(request_rec* r) { + const std::string ct = contentType(r); - // 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 list<value> params = (list<value>)cadr(assoc(value("params"), args)); + // Evaluate a JSON-RPC request and return a JSON result + if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) { + json::JSONContext cx; + const list<value> json = elementsToValues(json::read(cx, read(r))); + const list<list<value> > args = postArgs(json); - // Build expr to evaluate - const value expr = cons<value>(method, params); - std::cout<< "expr: " << expr << std::endl; - std::cout.flush(); + // 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 list<value> params = (list<value>)cadr(assoc(value("params"), args)); - // Evaluate the expr - const tuscany::value val = evalLoop(is, expr, globalEnv); - if (isNil(val)) - return HTTP_INTERNAL_SERVER_ERROR; - std::cout<< "val: " << val << std::endl; - std::cout.flush(); + // Evaluate the request expression + const failable<value, int> val = evalExpr(cons(method, params), contribution(r), implementation(r)); - // Convert the expr value to JSON - const list<value> result = valuesToElements(mklist<value>(mklist<value>("id", id), mklist<value>("result", val))); - failable<list<std::string>, std::string> jsval = writeJSON(cx, result); - if (!hasValue(jsval)) - return HTTP_INTERNAL_SERVER_ERROR; + // Return JSON result + return writeResult(jsonResult(cx, id, val), "application/json-rpc", r); + } - // Send the JSON response - ap_set_content_type(r, "application/json-rpc"); - std::ostringstream os; - write(jsval, os); - ap_rputs(os.str().c_str(), r); + // Evaluate an ATOM POST request and return the created resource location + if (ct.find("application/atom+xml") != std::string::npos) { + const list<std::string> c = read(r); + std::cout << "POST content: " << c << std::endl; + const list<value> 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<value, int> val = evalExpr(mklist<value>("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; + } - return OK; + return HTTP_NOT_IMPLEMENTED; } /** - * Handle an HTTP PUT request. + * Handle an HTTP PUT. */ const int put(request_rec* r) { + // TODO later return OK; } /** - * Handle an HTTP DELETE request. + * Handle an HTTP DELETE. */ const int del(request_rec* r) { + + // Evaluate an ATOM delete request + const failable<value, int> val = evalExpr(cons<value>("delete", cdr(path(r))), contribution(r), implementation(r)); + if (!hasValue(val)) + return val; return OK; } @@ -426,23 +549,24 @@ void registerHooks(apr_pool_t *p) { } } +} extern "C" { module AP_MODULE_DECLARE_DATA mod_tuscany = { STANDARD20_MODULE_STUFF, // dir config - tuscany::makeDirConf, + tuscany::httpd::makeDirConf, // dir merger, default is to override NULL, // server config - tuscany::makeServerConf, + tuscany::httpd::makeServerConf, // merge server config NULL, // command table - tuscany::commands, + tuscany::httpd::commands, // register hooks - tuscany::registerHooks + tuscany::httpd::registerHooks }; } diff --git a/cpp/sca/modules/http/test-conf/mime.types b/cpp/sca/modules/http/test-conf/mime.types new file mode 100644 index 0000000000..4279f51bca --- /dev/null +++ b/cpp/sca/modules/http/test-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 <http://www.iana.org/assignments/media-types/>. + +# 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 new file mode 100644 index 0000000000..1bfb3e30c2 --- /dev/null +++ b/cpp/sca/modules/http/test-htdocs/index.html @@ -0,0 +1,21 @@ +<!-- + 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. +--> + +<html><body><h1>It works!</h1></body></html> + |