From 885b72ee9e3d4aa347aada836f8152e7a3411c46 Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Mon, 22 Feb 2016 05:37:02 -0800 Subject: [PATCH 1/4] provide ssl option to conduit::io::WebServer added test that includes a self signed cert created according civetweb example when using ssl with the visualizer websocket / rest connection isn't working yet. --- src/libs/conduit_io/conduit_web.cpp | 26 +++++++-- src/libs/conduit_io/conduit_web.hpp | 7 ++- src/tests/CMakeLists.txt | 7 +++ src/tests/conduit_io/t_conduit_io_rest.cpp | 46 +++++++++++++++ src/tests/conduit_io/t_ssl_cert.pem | 30 ++++++++++ src/tests/t_config.hpp.in | 66 ++++++++++++++++++++++ 6 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 src/tests/conduit_io/t_ssl_cert.pem create mode 100644 src/tests/t_config.hpp.in diff --git a/src/libs/conduit_io/conduit_web.cpp b/src/libs/conduit_io/conduit_web.cpp index 0d9685535..dd78eed87 100644 --- a/src/libs/conduit_io/conduit_web.cpp +++ b/src/libs/conduit_io/conduit_web.cpp @@ -741,7 +741,8 @@ WebServer::context() //----------------------------------------------------------------------------- void WebServer::serve(const std::string &doc_root, - index_t port) + index_t port, + const std::string &ssl_cert_file) { if(is_running()) { @@ -749,19 +750,36 @@ WebServer::serve(const std::string &doc_root, return; } + m_ssl_cert_file = ssl_cert_file; + + bool use_ssl = m_ssl_cert_file.size() > 0; + // civetweb takes strings as arguments // convert the port number to a string. std::ostringstream oss; oss << port; + // civetweb use s suffix for https servers + if(use_ssl) + { + oss << "s"; + } + m_port = oss.str(); + CONDUIT_INFO("Starting WebServer instance with doc root = " << doc_root); // setup civetweb options const char *options[] = { "document_root", doc_root.c_str(), "listening_ports", m_port.c_str(), "num_threads", "2", + NULL, NULL, NULL}; + if(use_ssl) + { + options[6] = "ssl_certificate"; + options[7] = m_ssl_cert_file.c_str(); + } try { @@ -771,7 +789,7 @@ WebServer::serve(const std::string &doc_root, { // Catch Civet Exception and use Conduit's error handling mech. CONDUIT_ERROR("WebServer failed to bind civet server on port " - << port); + << m_port); } // check for valid context @@ -779,11 +797,11 @@ WebServer::serve(const std::string &doc_root, if(ctx == NULL) { CONDUIT_ERROR("WebServer failed to bind civet server on port " - << port); + << m_port); }else { CONDUIT_INFO("conduit::io::WebServer instance active on port: " - << port); + << m_port); } // setup REST handlers diff --git a/src/libs/conduit_io/conduit_web.hpp b/src/libs/conduit_io/conduit_web.hpp index 61e4ec636..4d44448b4 100644 --- a/src/libs/conduit_io/conduit_web.hpp +++ b/src/libs/conduit_io/conduit_web.hpp @@ -114,9 +114,11 @@ class CONDUIT_IO_API WebServer WebServer(); virtual ~WebServer(); - + void serve(const std::string &doc_root, - index_t port = 8080); + index_t port = 8080, + const std::string &m_ssl_cert_file = std::string("")); + // note: this variant of serve is to specific to the // the visualizer client use case. @@ -143,6 +145,7 @@ class CONDUIT_IO_API WebServer RequestHandler *m_handler; std::string m_port; + std::string m_ssl_cert_file; bool m_running; }; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index b93e6dd8c..0527477d5 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -46,6 +46,13 @@ # Conduit Unit Tests ################################ +# this header allows us to easily use the cmake source and binary paths in +# our unit tests +configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/t_config.hpp.in" + "${CMAKE_CURRENT_BINARY_DIR}/t_config.hpp") + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + add_subdirectory("conduit") add_subdirectory("conduit_io") add_subdirectory("conduit_mpi") diff --git a/src/tests/conduit_io/t_conduit_io_rest.cpp b/src/tests/conduit_io/t_conduit_io_rest.cpp index 822a703b6..30fde61a5 100644 --- a/src/tests/conduit_io/t_conduit_io_rest.cpp +++ b/src/tests/conduit_io/t_conduit_io_rest.cpp @@ -52,6 +52,8 @@ #include #include "gtest/gtest.h" +#include "t_config.hpp" + using namespace conduit; bool launch_server = false; @@ -85,6 +87,50 @@ TEST(conduit_io_rest, rest_server) delete n; } +TEST(conduit_io_rest, rest_server_ssl) +{ + uint32 a_val = 20; + uint32 b_val = 8; + uint32 c_val = 13; + + Node *n = new Node(); + n->fetch("a") = a_val; + n->fetch("b") = b_val; + n->fetch("c") = c_val; + + EXPECT_EQ(n->fetch("a").as_uint32(), a_val); + EXPECT_EQ(n->fetch("b").as_uint32(), b_val); + EXPECT_EQ(n->fetch("c").as_uint32(), c_val); + + if(launch_server) + { + std::string rest_path = utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT, + "rest_client"); + conduit::io::WebServer svr; + std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); + cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); + + // start our server + svr.serve(rest_path, + 8082, + cert_path); + + while(svr.is_running()) + { + utils::sleep(1); + } + } + else + { + std::cout << "provide \"launch\" as a command line arg " + << "to launch a conduit::Node REST test server at " + << "https://localhost:8082s" << std::endl; + } + + delete n; +} + + //----------------------------------------------------------------------------- int main(int argc, char* argv[]) { diff --git a/src/tests/conduit_io/t_ssl_cert.pem b/src/tests/conduit_io/t_ssl_cert.pem new file mode 100644 index 000000000..1fa563f43 --- /dev/null +++ b/src/tests/conduit_io/t_ssl_cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIICUTCCAboCCQD7RIO89X7XbjANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJ1 +czENMAsGA1UECAwEdGVzdDENMAsGA1UEBwwEdGVzdDENMAsGA1UECgwEdGVzdDEN +MAsGA1UECwwEdGVzdDENMAsGA1UEAwwEdGVzdDETMBEGCSqGSIb3DQEJARYEdGVz +dDAeFw0xNjAyMjIxMzEwNTdaFw0yNjAyMTkxMzEwNTdaMG0xCzAJBgNVBAYTAnVz +MQ0wCwYDVQQIDAR0ZXN0MQ0wCwYDVQQHDAR0ZXN0MQ0wCwYDVQQKDAR0ZXN0MQ0w +CwYDVQQLDAR0ZXN0MQ0wCwYDVQQDDAR0ZXN0MRMwEQYJKoZIhvcNAQkBFgR0ZXN0 +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0C/n0zTW7bndjO16CtHmE7HCc +/5+pNtunvr+ylFf2sFnvf4ocAGXG/EW+c+HO/BXV/5Kth03PdACeevpEZCh+XG+V +d9OEj5N7u7FYXMwbRHQF4xicmR+f6Ao2IcfWPMOcHelBENMR4hweUnsdjKrvF1eO +TpYulT50Lb3sKWRb+QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAE3AdHinLrhbUNZe +7gl5sAjWSI22F0Zar2zA9Kgy8sEE+8nGvR4/cyUm3RASJsb2mmO91PBel97pyZpv +jlug+pL0MdE4PbcM5NbWEUFulckrSmlg42I4RcGGzvfnGjlMyjzXJmQ0C0PHW/Kj +EOhr4NphKlm13cQksM1kVZW6YZh7 +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQC0C/n0zTW7bndjO16CtHmE7HCc/5+pNtunvr+ylFf2sFnvf4oc +AGXG/EW+c+HO/BXV/5Kth03PdACeevpEZCh+XG+Vd9OEj5N7u7FYXMwbRHQF4xic +mR+f6Ao2IcfWPMOcHelBENMR4hweUnsdjKrvF1eOTpYulT50Lb3sKWRb+QIDAQAB +AoGAFP6YhP0w2MxGy6FuodsdmGxhrUz5dyfYcTUC8XXu0+s4cX7zwdQiChP8pfqp +SBOJEE0e83Ell501PUWlzTfIqNENpdDbQh+ELVPNT1vn2AOru7nQAMHs349xV9Lb +/Nnm4NRM6/fOf1b67p/L1T8gKwYRqbXLPc+iHu4nekHoRKECQQDvPX/yzMFrzHGM +qrdiXJQey4gCEwG9fFTtPKBTnIAVT9UHgc0hqq+VSez3OfLGpVLRjsORgFRU1V5/ +O7F84bklAkEAwKjo4chr0LCRL4pgFVQg227Cbu7fmblaPqRWwNfMrXUo/9WFmOpf +TXtgXWIYYkgAKK8jmKxpIR/nYHEyp5oRRQJBAJIKUr6eazwo0u/xjnyG0wxxZhcO +DzPiX91p8tzXXgCkeQBaJiR1EzXoqLTKNP86EHJH2e5KDjCzBzpX8CKxj9kCQQCM +125YEJJw34Njw772GKhkghX1zv77fDry7GTXWWsxqyKr1EZ0QXImTHloCxxUTNqA +43gcVn4MTyxwnpAvYjwZAkBJfgJ4CPLRngObZnXb0kdLmlEuCvLjpK5RzPDs+Drd +845IsrGKNXpKvB1wr8UbZSbiblcGZKawWKS+GMeYrwE7 +-----END RSA PRIVATE KEY----- diff --git a/src/tests/t_config.hpp.in b/src/tests/t_config.hpp.in new file mode 100644 index 000000000..5fd82799d --- /dev/null +++ b/src/tests/t_config.hpp.in @@ -0,0 +1,66 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) 2014-2015, Lawrence Livermore National Security, LLC. +// +// Produced at the Lawrence Livermore National Laboratory +// +// LLNL-CODE-666778 +// +// All rights reserved. +// +// This file is part of Conduit. +// +// For details, see: http://llnl.github.io/conduit/. +// +// Please also read conduit/LICENSE +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the LLNS/LLNL nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, +// LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: t_config.hpp +/// +//----------------------------------------------------------------------------- + +#ifndef CONDUIT_T_CONFIG_HPP +#define CONDUIT_T_CONFIG_HPP + +//----------------------------------------------------------------------------- +// +// #define test source and bin dir +// +//----------------------------------------------------------------------------- + +#define CONDUIT_T_SRC_DIR "@CMAKE_CURRENT_SOURCE_DIR@" +#define CONDUIT_T_BIN_DIR "@CMAKE_CURRENT_BINARY_DIR@" + +#endif + + + From df7d05159dc7f6ff4bf91bee1b75402ea531f97c Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Mon, 22 Feb 2016 07:19:02 -0800 Subject: [PATCH 2/4] cleaned up comments in conduit_web --- src/libs/conduit_io/conduit_web.cpp | 50 ++++++++++++++--------------- src/libs/conduit_io/conduit_web.hpp | 7 ++-- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/libs/conduit_io/conduit_web.cpp b/src/libs/conduit_io/conduit_web.cpp index dd78eed87..bf5516ab2 100644 --- a/src/libs/conduit_io/conduit_web.cpp +++ b/src/libs/conduit_io/conduit_web.cpp @@ -221,9 +221,11 @@ class RequestHandler : public CivetHandler, char cpath[2048]; int post_data_len = mg_read(conn, post_data, sizeof(post_data)); - + + // TODO: path instead of cpath? + mg_get_var(post_data, post_data_len, "cpath", cpath, sizeof(cpath)); - + // TODO: value instead of datavalue mg_printf(conn, "{ \"datavalue\": %s }", m_node->fetch(cpath).to_json().c_str()); } @@ -259,12 +261,10 @@ class RequestHandler : public CivetHandler, //---------------------------------------------------------------------------// // Handlers for WebSockets - // These aren't exposed via the CivetWeb C++ interface, so the - // process is a bit more complex. //---------------------------------------------------------------------------// //---------------------------------------------------------------------------// - // callback used when a web socket initially connects + // handler used when a web socket initially connects //---------------------------------------------------------------------------// bool handleConnection(CivetServer *, // server -- unused @@ -275,7 +275,7 @@ class RequestHandler : public CivetHandler, } //---------------------------------------------------------------------------// - // callback used when a web socket connection becomes active + // handler used when a web socket connection becomes active //---------------------------------------------------------------------------// void handleReadyState(CivetServer *, // server -- unused @@ -291,19 +291,10 @@ class RequestHandler : public CivetHandler, } // unlock context m_server->unlock_context(); - - // if(ws != NULL) - // { - // // send connection successful message - // Node n; - // n["type"] = "status"; - // n["message"] = "WebSocket ready!"; - // ws->send(n); - // } } //---------------------------------------------------------------------------// - // callback used when a websocket receives a text payload + // handler used when a websocket receives a text payload //---------------------------------------------------------------------------// bool handleWebSocketText(struct mg_connection *, // conn -- unused @@ -336,7 +327,7 @@ class RequestHandler : public CivetHandler, //---------------------------------------------------------------------------// - // callback used when a websocket receives data + // handler used when a websocket receives data //---------------------------------------------------------------------------// bool handleData(CivetServer *, // server -- unused @@ -405,7 +396,7 @@ class RequestHandler : public CivetHandler, } //---------------------------------------------------------------------------// - // callback used when a websocket connection is closed + // handler used when a websocket connection is closed //---------------------------------------------------------------------------// void handleClose(CivetServer *, // server -- unused @@ -621,7 +612,7 @@ WebSocket::send(const Node &data, { if(m_connection == NULL) { - CONDUIT_INFO("attempt to write to bad websocket connection"); + CONDUIT_WARN("attempt to write to bad websocket connection"); return; } @@ -653,6 +644,7 @@ WebServer::WebServer() : m_server(NULL), m_handler(NULL), m_port(""), + m_ssl_cert_file(""), m_running(false) { m_handler = new RequestHandler(*this); @@ -680,8 +672,6 @@ WebServer::websocket(index_t ms_poll, } - - //----------------------------------------------------------------------------- void WebServer::lock_context() @@ -800,8 +790,16 @@ WebServer::serve(const std::string &doc_root, << m_port); }else { - CONDUIT_INFO("conduit::io::WebServer instance active on port: " - << m_port); + if(!use_ssl) + { + CONDUIT_INFO("conduit::io::WebServer http server instance " + "active on port: " << m_port); + } + else + { + CONDUIT_INFO("conduit::io::WebServer https server instance " + "active on port: " << m_port); + } } // setup REST handlers @@ -824,14 +822,14 @@ WebServer::shutdown() { CONDUIT_INFO("closing conduit::io::WebServer instance on port: " << m_port); - + m_running = false; + delete m_server; delete m_handler; - - m_handler = NULL; m_server = NULL; + m_handler = NULL; } } diff --git a/src/libs/conduit_io/conduit_web.hpp b/src/libs/conduit_io/conduit_web.hpp index 4d44448b4..95b31a9ad 100644 --- a/src/libs/conduit_io/conduit_web.hpp +++ b/src/libs/conduit_io/conduit_web.hpp @@ -131,8 +131,11 @@ class CONDUIT_IO_API WebServer bool is_running() const; - // returns the first active websocket, if non are active, blocks - // until a websocket connection is established. + /// returns the first active websocket, if none are active, blocks + /// until a websocket connection is established. + /// + /// ms_poll specifies the number of microseconds for each poll attempt + /// ms_timeout specifies the total time out in microseconds WebSocket *websocket(index_t ms_poll = 100, index_t ms_timeout = 60000); From e06add7827354bcf1c57466048de8b8bf2448714 Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Tue, 23 Feb 2016 20:54:11 -0800 Subject: [PATCH 3/4] extra warnings and temp fix for rest path (we still need to factor out the visualizer case ) added ssl option to rest and websocket tests --- src/libs/conduit_io/conduit_web.cpp | 23 ++++ src/libs/conduit_io/conduit_web.hpp | 2 + src/tests/conduit_io/t_conduit_io_rest.cpp | 114 +++++++++++------- .../conduit_io/t_conduit_io_websocket.cpp | 23 +++- 4 files changed, 117 insertions(+), 45 deletions(-) diff --git a/src/libs/conduit_io/conduit_web.cpp b/src/libs/conduit_io/conduit_web.cpp index bf5516ab2..8a1076fea 100644 --- a/src/libs/conduit_io/conduit_web.cpp +++ b/src/libs/conduit_io/conduit_web.cpp @@ -205,6 +205,11 @@ class RequestHandler : public CivetHandler, { mg_printf(conn, "%s",m_node->schema().to_json(true).c_str()); } + else + { + CONDUIT_WARN("rest request for schema of NULL Node"); + return false; + } return true; } @@ -229,6 +234,11 @@ class RequestHandler : public CivetHandler, mg_printf(conn, "{ \"datavalue\": %s }", m_node->fetch(cpath).to_json().c_str()); } + else + { + CONDUIT_WARN("rest request for value of NULL Node"); + return false; + } return true; } @@ -245,6 +255,12 @@ class RequestHandler : public CivetHandler, m_node->to_json_stream(oss,"base64_json"); mg_printf(conn, "%s",oss.str().c_str()); } + else + { + CONDUIT_WARN("rest request for base64 json of NULL Node"); + return false; + } + return true; } @@ -719,6 +735,13 @@ WebServer::serve(Node *node, } } +//----------------------------------------------------------------------------- +void +WebServer::set_node(Node *node) +{ + m_handler->set_node(node); +} + //----------------------------------------------------------------------------- mg_context * diff --git a/src/libs/conduit_io/conduit_web.hpp b/src/libs/conduit_io/conduit_web.hpp index 95b31a9ad..a9c9c09a5 100644 --- a/src/libs/conduit_io/conduit_web.hpp +++ b/src/libs/conduit_io/conduit_web.hpp @@ -126,6 +126,8 @@ class CONDUIT_IO_API WebServer bool block=false, index_t port = 8080); + void set_node(Node *data); + void shutdown(); bool is_running() const; diff --git a/src/tests/conduit_io/t_conduit_io_rest.cpp b/src/tests/conduit_io/t_conduit_io_rest.cpp index 30fde61a5..46f46c49f 100644 --- a/src/tests/conduit_io/t_conduit_io_rest.cpp +++ b/src/tests/conduit_io/t_conduit_io_rest.cpp @@ -57,37 +57,10 @@ using namespace conduit; bool launch_server = false; +bool use_ssl = false; -TEST(conduit_io_rest, rest_server) -{ - uint32 a_val = 20; - uint32 b_val = 8; - uint32 c_val = 13; - - Node *n = new Node(); - n->fetch("a") = a_val; - n->fetch("b") = b_val; - n->fetch("c") = c_val; - EXPECT_EQ(n->fetch("a").as_uint32(), a_val); - EXPECT_EQ(n->fetch("b").as_uint32(), b_val); - EXPECT_EQ(n->fetch("c").as_uint32(), c_val); - - if(launch_server) - { - io::rest::serve(n); - } - else - { - std::cout << "provide \"launch\" as a command line arg " - << "to launch a conduit::Node REST test server at " - << "http://localhost:8080" << std::endl; - } - - delete n; -} - -TEST(conduit_io_rest, rest_server_ssl) +TEST(conduit_io_rest, rest_server) { uint32 a_val = 20; uint32 b_val = 8; @@ -104,31 +77,82 @@ TEST(conduit_io_rest, rest_server_ssl) if(launch_server) { - std::string rest_path = utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT, - "rest_client"); - conduit::io::WebServer svr; - std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); - cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); - - // start our server - svr.serve(rest_path, - 8082, - cert_path); - - while(svr.is_running()) + if(!use_ssl) { - utils::sleep(1); + io::rest::serve(n); + } + else // ssl path + { + std::string rest_path = utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT, + "rest_client"); + conduit::io::WebServer svr; + std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); + cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); + + svr.set_node(n); + // start our server + svr.serve(rest_path, + 8080, + cert_path); + + while(svr.is_running()) + { + utils::sleep(1); + } } } else { std::cout << "provide \"launch\" as a command line arg " << "to launch a conduit::Node REST test server at " - << "https://localhost:8082s" << std::endl; + << "http://localhost:8080" << std::endl; } delete n; } +// +// TEST(conduit_io_rest, rest_server_ssl) +// { +// uint32 a_val = 20; +// uint32 b_val = 8; +// uint32 c_val = 13; +// +// Node *n = new Node(); +// n->fetch("a") = a_val; +// n->fetch("b") = b_val; +// n->fetch("c") = c_val; +// +// EXPECT_EQ(n->fetch("a").as_uint32(), a_val); +// EXPECT_EQ(n->fetch("b").as_uint32(), b_val); +// EXPECT_EQ(n->fetch("c").as_uint32(), c_val); +// +// if(launch_server) +// { +// std::string rest_path = utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT, +// "rest_client"); +// conduit::io::WebServer svr; +// std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); +// cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); +// +// // start our server +// svr.serve(rest_path, +// 8082, +// cert_path); +// +// while(svr.is_running()) +// { +// utils::sleep(1); +// } +// } +// else +// { +// std::cout << "provide \"launch\" as a command line arg " +// << "to launch a conduit::Node REST test server at " +// << "https://localhost:8082s" << std::endl; +// } +// +// delete n; +// } //----------------------------------------------------------------------------- @@ -145,6 +169,10 @@ int main(int argc, char* argv[]) { launch_server = true;; } + else if(arg_str == "ssl") + { + use_ssl = true; + } } result = RUN_ALL_TESTS(); diff --git a/src/tests/conduit_io/t_conduit_io_websocket.cpp b/src/tests/conduit_io/t_conduit_io_websocket.cpp index cb9d08e8c..b31fd523e 100644 --- a/src/tests/conduit_io/t_conduit_io_websocket.cpp +++ b/src/tests/conduit_io/t_conduit_io_websocket.cpp @@ -52,12 +52,15 @@ #include #include "gtest/gtest.h" +#include "t_config.hpp" + using namespace conduit; using namespace conduit::utils; using namespace conduit::io; bool launch_server = false; +bool use_ssl = false; TEST(conduit_io_websocket, websocket_test) { @@ -116,7 +119,19 @@ TEST(conduit_io_websocket, websocket_test) WebServer svr; // start our server - svr.serve(wsock_path,8081); + if(!use_ssl) + { + svr.serve(wsock_path,8081); + } + else + { + std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); + cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); + svr.serve(wsock_path, + 8081, + cert_path); + } + // this loop won't be necessary in the strawman lib. while(svr.is_running()) @@ -145,7 +160,11 @@ int main(int argc, char* argv[]) std::string arg_str(argv[i]); if(arg_str == "launch") { - launch_server = true;; + launch_server = true; + } + else if(arg_str == "ssl") + { + use_ssl = true; } } From 839a4efd99cf621a02384cb593f1e54926eb980e Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Tue, 23 Feb 2016 22:50:30 -0800 Subject: [PATCH 4/4] created WebRequestHandler Interface to allow lib users to implement their own server request handers pulled Visualizer server logic out of the main WebServer class, and implemented it using a WebRequestHandler --- src/libs/conduit_io/CMakeLists.txt | 4 +- src/libs/conduit_io/conduit_io.hpp | 2 +- src/libs/conduit_io/conduit_web.cpp | 247 ++++------------ src/libs/conduit_io/conduit_web.hpp | 74 +++-- .../conduit_io/conduit_web_visualizer.cpp | 274 ++++++++++++++++++ .../conduit_io/conduit_web_visualizer.hpp | 133 +++++++++ src/tests/conduit_io/t_conduit_io_rest.cpp | 29 +- .../conduit_io/t_conduit_io_websocket.cpp | 5 +- 8 files changed, 526 insertions(+), 242 deletions(-) create mode 100644 src/libs/conduit_io/conduit_web_visualizer.cpp create mode 100644 src/libs/conduit_io/conduit_web_visualizer.hpp diff --git a/src/libs/conduit_io/CMakeLists.txt b/src/libs/conduit_io/CMakeLists.txt index 0cf76c3f8..f35324253 100644 --- a/src/libs/conduit_io/CMakeLists.txt +++ b/src/libs/conduit_io/CMakeLists.txt @@ -68,6 +68,7 @@ configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/Conduit_IO_Config.hpp.in" set(conduit_io_headers conduit_io.hpp conduit_web.hpp + conduit_web_visualizer.hpp Conduit_IO_Exports.hpp ${CMAKE_CURRENT_BINARY_DIR}/Conduit_IO_Config.hpp) @@ -76,7 +77,8 @@ set(conduit_io_headers # set(conduit_io_sources conduit_io.cpp - conduit_web.cpp) + conduit_web.cpp + conduit_web_visualizer.cpp) if(HDF5_FOUND) list(APPEND conduit_io_headers conduit_hdf5.hpp) diff --git a/src/libs/conduit_io/conduit_io.hpp b/src/libs/conduit_io/conduit_io.hpp index 9231d43e6..5e370fe37 100644 --- a/src/libs/conduit_io/conduit_io.hpp +++ b/src/libs/conduit_io/conduit_io.hpp @@ -61,7 +61,7 @@ #include "conduit_web.hpp" - +#include "conduit_web_visualizer.hpp" // include optional libs diff --git a/src/libs/conduit_io/conduit_web.cpp b/src/libs/conduit_io/conduit_web.cpp index 8a1076fea..411591fd0 100644 --- a/src/libs/conduit_io/conduit_web.cpp +++ b/src/libs/conduit_io/conduit_web.cpp @@ -44,7 +44,7 @@ //----------------------------------------------------------------------------- /// -/// file: conduit_rest.cpp +/// file: conduit_web.cpp /// //----------------------------------------------------------------------------- @@ -63,6 +63,7 @@ // conduit includes //----------------------------------------------------------------------------- #include "conduit_web.hpp" +#include "conduit_web_visualizer.hpp" #include "Conduit_IO_Config.hpp" //----------------------------------------------------------------------------- @@ -79,49 +80,52 @@ namespace io { //----------------------------------------------------------------------------- -// -- begin conduit::io::rest -- +// WebRequestHandler Interface //----------------------------------------------------------------------------- - -namespace rest +WebRequestHandler::WebRequestHandler() { - -//----------------------------------------------------------------------------- -// simple interface to launch a blocking REST server -//----------------------------------------------------------------------------- -void -serve(Node *n, - index_t port) -{ - WebServer srv; - srv.serve(n,true,port); } -}; -//----------------------------------------------------------------------------- -// -- end conduit::io::rest -- //----------------------------------------------------------------------------- +WebRequestHandler::~WebRequestHandler() +{ +} //----------------------------------------------------------------------------- -// -- Internal REST Server Interface Classes - +bool +WebRequestHandler::handle_post(WebServer *server, + struct mg_connection *conn) +{ + return true; +} + //----------------------------------------------------------------------------- +bool +WebRequestHandler::handle_get(WebServer *server, + struct mg_connection *conn) +{ + return true; +} -class RequestHandler : public CivetHandler, - public CivetWebSocketHandler +//----------------------------------------------------------------------------- +// -- Internal Server Interface Classes - +//----------------------------------------------------------------------------- +class CivetDispatchHandler : public CivetHandler, + public CivetWebSocketHandler { public: //---------------------------------------------------------------------------// - RequestHandler(WebServer &server) - : m_server(&server), - m_node(NULL) + CivetDispatchHandler(WebServer &server) + : m_server(&server) { // empty } //---------------------------------------------------------------------------// - ~RequestHandler() + ~CivetDispatchHandler() { // cleanup any alloced web socket instances for(size_t i=0; i < m_sockets.size(); i++) @@ -130,51 +134,11 @@ class RequestHandler : public CivetHandler, } } - //---------------------------------------------------------------------------// - // Bridge to preserve our old interface - //---------------------------------------------------------------------------// - void set_node(Node *node) - { - m_node = node; - } - - //---------------------------------------------------------------------------// - // Main handler, dispatches to proper api handlers. - //---------------------------------------------------------------------------// - bool handle_request(struct mg_connection *conn) + void set_handler(WebRequestHandler *handler) { - const struct mg_request_info *req_info = mg_get_request_info(conn); - - std::string uri(req_info->uri); - std::string uri_cmd; - std::string uri_next; - utils::rsplit_string(uri,"/",uri_cmd,uri_next); - - if(uri_cmd == "get-schema") - { - return handle_rest_get_schema(conn); - } - else if(uri_cmd == "get-value") - { - return handle_rest_get_value(conn); - } - else if(uri_cmd == "get-base64-json") - { - return handle_rest_get_base64_json(conn); - } - else if(uri_cmd == "kill-server") - { - return handle_rest_shutdown(conn); - } - else - { - CONDUIT_INFO("Unknown REST request uri:" << uri_cmd ); - // TODO: what behavior does returning false this trigger? - return false; - } - return true; + m_handler = handler; } - + //---------------------------------------------------------------------------// // wire all CivetHandler handlers to "handle_request" //---------------------------------------------------------------------------// @@ -182,7 +146,7 @@ class RequestHandler : public CivetHandler, handlePost(CivetServer *, // server -- unused struct mg_connection *conn) { - return handle_request(conn); + return m_server->handler()->handle_post(m_server,conn); } //---------------------------------------------------------------------------// @@ -192,86 +156,7 @@ class RequestHandler : public CivetHandler, handleGet(CivetServer *, // server -- unused struct mg_connection *conn) { - return handle_request(conn); - } - - //---------------------------------------------------------------------------// - // Handles a request from the client for the node's schema. - //---------------------------------------------------------------------------// - bool - handle_rest_get_schema(struct mg_connection *conn) - { - if(m_node != NULL) - { - mg_printf(conn, "%s",m_node->schema().to_json(true).c_str()); - } - else - { - CONDUIT_WARN("rest request for schema of NULL Node"); - return false; - } - return true; - } - - //---------------------------------------------------------------------------// - // Handles a request from the client for a specific value in the node. - //---------------------------------------------------------------------------// - bool - handle_rest_get_value(struct mg_connection *conn) - { - if(m_node != NULL) - { - // TODO size checks? - char post_data[2048]; - char cpath[2048]; - - int post_data_len = mg_read(conn, post_data, sizeof(post_data)); - - // TODO: path instead of cpath? - - mg_get_var(post_data, post_data_len, "cpath", cpath, sizeof(cpath)); - // TODO: value instead of datavalue - mg_printf(conn, "{ \"datavalue\": %s }", - m_node->fetch(cpath).to_json().c_str()); - } - else - { - CONDUIT_WARN("rest request for value of NULL Node"); - return false; - } - return true; - } - - //---------------------------------------------------------------------------// - // Handles a request from the client for a compact, base64 encoded version - // of the node. - //---------------------------------------------------------------------------// - bool - handle_rest_get_base64_json(struct mg_connection *conn) - { - if(m_node != NULL) - { - std::ostringstream oss; - m_node->to_json_stream(oss,"base64_json"); - mg_printf(conn, "%s",oss.str().c_str()); - } - else - { - CONDUIT_WARN("rest request for base64 json of NULL Node"); - return false; - } - - return true; - } - - //---------------------------------------------------------------------------// - // Handles a request from the client to shutdown the REST server - //---------------------------------------------------------------------------// - bool - handle_rest_shutdown(struct mg_connection *) // conn -- unused - { - m_server->shutdown(); - return true; + return m_server->handler()->handle_get(m_server,conn); } @@ -549,7 +434,7 @@ class RequestHandler : public CivetHandler, private: WebServer *m_server; - Node *m_node; + WebRequestHandler *m_handler; std::vector m_sockets; }; @@ -657,13 +542,15 @@ WebSocket::send(const Node &data, //----------------------------------------------------------------------------- WebServer::WebServer() -: m_server(NULL), - m_handler(NULL), +: m_handler(NULL), + m_doc_root(""), m_port(""), m_ssl_cert_file(""), - m_running(false) + m_running(false), + m_server(NULL), + m_dispatch(NULL) { - m_handler = new RequestHandler(*this); + // empty } //----------------------------------------------------------------------------- @@ -684,7 +571,7 @@ WebSocket * WebServer::websocket(index_t ms_poll, index_t ms_timeout) { - return m_handler->websocket(ms_poll,ms_timeout); + return m_dispatch->websocket(ms_poll,ms_timeout); } @@ -710,39 +597,13 @@ WebServer::unlock_context() } } - - - -//----------------------------------------------------------------------------- -void -WebServer::serve(Node *node, - bool block, - index_t port) -{ - m_handler->set_node(node); - - // call general serve routine - serve(utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT,"rest_client"), - port); - - if(block) - { - // wait for shutdown() - while(is_running()) - { - utils::sleep(100); - } - } -} - //----------------------------------------------------------------------------- -void -WebServer::set_node(Node *node) +WebRequestHandler * +WebServer::handler() { - m_handler->set_node(node); + return m_handler; } - //----------------------------------------------------------------------------- mg_context * WebServer::context() @@ -754,6 +615,7 @@ WebServer::context() //----------------------------------------------------------------------------- void WebServer::serve(const std::string &doc_root, + WebRequestHandler *handler, index_t port, const std::string &ssl_cert_file) { @@ -762,7 +624,13 @@ WebServer::serve(const std::string &doc_root, CONDUIT_INFO("WebServer instance is already running"); return; } + + m_dispatch = new CivetDispatchHandler(*this); + + m_handler = handler; + m_doc_root = doc_root; + // TODO: check for null? m_ssl_cert_file = ssl_cert_file; bool use_ssl = m_ssl_cert_file.size() > 0; @@ -826,10 +694,10 @@ WebServer::serve(const std::string &doc_root, } // setup REST handlers - m_server->addHandler("/api/*",m_handler); + m_server->addHandler("/api/*",m_dispatch); // setup web socket handler - m_server->addWebSocketHandler("/websocket", m_handler); + m_server->addWebSocketHandler("/websocket", m_dispatch); // signal we are valid @@ -850,16 +718,15 @@ WebServer::shutdown() delete m_server; delete m_handler; + delete m_dispatch; - m_server = NULL; - m_handler = NULL; + m_server = NULL; + m_handler = NULL; + m_dispatch = NULL; } } - - - }; //----------------------------------------------------------------------------- // -- end conduit::io -- diff --git a/src/libs/conduit_io/conduit_web.hpp b/src/libs/conduit_io/conduit_web.hpp index a9c9c09a5..9997c2da1 100644 --- a/src/libs/conduit_io/conduit_web.hpp +++ b/src/libs/conduit_io/conduit_web.hpp @@ -44,12 +44,12 @@ //----------------------------------------------------------------------------- /// -/// file: conduit_rest.hpp +/// file: conduit_web.hpp /// //----------------------------------------------------------------------------- -#ifndef CONDUIT_REST_HPP -#define CONDUIT_REST_HPP +#ifndef CONDUIT_WEB_HPP +#define CONDUIT_WEB_HPP //----------------------------------------------------------------------------- // conduit lib includes @@ -79,24 +79,27 @@ namespace conduit namespace io { + //----------------------------------------------------------------------------- -// -- begin conduit::io::rest -- +// -- Web Server Request Handler Interface - //----------------------------------------------------------------------------- -namespace rest +// forward declare WebServer class +class WebServer; + +// interface used to create concrete server instances. +class CONDUIT_IO_API WebRequestHandler { +public: + WebRequestHandler(); + virtual ~WebRequestHandler(); -//----------------------------------------------------------------------------- -/// Simple interface to launch a blocking REST server -//----------------------------------------------------------------------------- -void CONDUIT_IO_API serve(Node *n, - index_t port = 8080); + virtual bool handle_post(WebServer *server, + struct mg_connection *conn); + virtual bool handle_get(WebServer *server, + struct mg_connection *conn); }; -//----------------------------------------------------------------------------- -// -- end conduit::io::rest -- -//----------------------------------------------------------------------------- - //----------------------------------------------------------------------------- // -- Web Server Interface - @@ -104,9 +107,8 @@ void CONDUIT_IO_API serve(Node *n, // forward declare websocket interface class class WebSocket; - // forward declare internal handler class -class RequestHandler; +class CivetDispatchHandler; class CONDUIT_IO_API WebServer { @@ -116,23 +118,23 @@ class CONDUIT_IO_API WebServer virtual ~WebServer(); void serve(const std::string &doc_root, + WebRequestHandler *dispatch, // takes ownership? index_t port = 8080, - const std::string &m_ssl_cert_file = std::string("")); - + const std::string &ssl_cert_file = std::string("")); - // note: this variant of serve is to specific to the - // the visualizer client use case. - void serve(Node *data, - bool block=false, - index_t port = 8080); - void set_node(Node *data); + // // note: this variant of serve is to specific to the + // // the visualizer client use case. + // void serve(Node *data, + // bool block=false, + // index_t port = 8080); + // + // void set_node(Node *data); void shutdown(); bool is_running() const; - /// returns the first active websocket, if none are active, blocks /// until a websocket connection is established. /// @@ -141,17 +143,23 @@ class CONDUIT_IO_API WebServer WebSocket *websocket(index_t ms_poll = 100, index_t ms_timeout = 60000); + WebRequestHandler *handler(); + mg_context *context(); void lock_context(); void unlock_context(); private: - CivetServer *m_server; - RequestHandler *m_handler; + WebRequestHandler *m_handler; + std::string m_doc_root; std::string m_port; std::string m_ssl_cert_file; bool m_running; + + CivetServer *m_server; + CivetDispatchHandler *m_dispatch; + }; //----------------------------------------------------------------------------- @@ -164,11 +172,13 @@ class CONDUIT_IO_API WebServer class CONDUIT_IO_API WebSocket { public: - friend class RequestHandler; + friend class CivetDispatchHandler; void send(const Node &data, const std::string &protocol="json"); + // todo: receive? + bool is_connected() const; mg_context *context(); @@ -176,10 +186,10 @@ class CONDUIT_IO_API WebSocket void unlock_context(); private: - WebSocket(); - virtual ~WebSocket(); - - void set_connection(mg_connection *connection); + WebSocket(); + virtual ~WebSocket(); + + void set_connection(mg_connection *connection); mg_connection *m_connection; }; diff --git a/src/libs/conduit_io/conduit_web_visualizer.cpp b/src/libs/conduit_io/conduit_web_visualizer.cpp new file mode 100644 index 000000000..940eb0363 --- /dev/null +++ b/src/libs/conduit_io/conduit_web_visualizer.cpp @@ -0,0 +1,274 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) 2014-2015, Lawrence Livermore National Security, LLC. +// +// Produced at the Lawrence Livermore National Laboratory +// +// LLNL-CODE-666778 +// +// All rights reserved. +// +// This file is part of Conduit. +// +// For details, see: http://llnl.github.io/conduit/. +// +// Please also read conduit/LICENSE +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the LLNS/LLNL nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, +// LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: conduit_web_visualizer.cpp +/// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// std lib includes +//----------------------------------------------------------------------------- +#include + +//----------------------------------------------------------------------------- +// external lib includes +//----------------------------------------------------------------------------- +#include "civetweb.h" +#include "CivetServer.h" + +//----------------------------------------------------------------------------- +// conduit includes +//----------------------------------------------------------------------------- +#include "conduit_web.hpp" +#include "conduit_web_visualizer.hpp" +#include "Conduit_IO_Config.hpp" + +//----------------------------------------------------------------------------- +// -- begin conduit:: -- +//----------------------------------------------------------------------------- +namespace conduit +{ + +//----------------------------------------------------------------------------- +// -- begin conduit::io -- +//----------------------------------------------------------------------------- + +namespace io +{ + +//----------------------------------------------------------------------------- +// -- Visualizer Request Handler - +//----------------------------------------------------------------------------- + +VisualizerRequestHandler::VisualizerRequestHandler(Node *node) +: WebRequestHandler(), + m_node(node) +{ + // empty +} + +VisualizerRequestHandler::~VisualizerRequestHandler() +{ + // empty +} + +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_post(WebServer *server, + struct mg_connection *conn) +{ + return handle_request(server,conn); +} + + +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_get(WebServer *server, + struct mg_connection *conn) +{ + return handle_request(server,conn); +} + +//---------------------------------------------------------------------------// +// Main handler, dispatches to proper api requests. +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_request(WebServer *server, + struct mg_connection *conn) +{ + const struct mg_request_info *req_info = mg_get_request_info(conn); + + std::string uri(req_info->uri); + std::string uri_cmd; + std::string uri_next; + utils::rsplit_string(uri,"/",uri_cmd,uri_next); + + if(uri_cmd == "get-schema") + { + return handle_get_schema(conn); + } + else if(uri_cmd == "get-value") + { + return handle_get_value(conn); + } + else if(uri_cmd == "get-base64-json") + { + return handle_get_base64_json(conn); + } + else if(uri_cmd == "kill-server") + { + return handle_shutdown(server); + } + else + { + CONDUIT_INFO("Unknown REST request uri:" << uri_cmd ); + // TODO: what behavior does returning false this trigger? + return false; + } + return true; +} + + +//---------------------------------------------------------------------------// +// Handles a request from the client for the node's schema. +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_get_schema(struct mg_connection *conn) +{ + if(m_node != NULL) + { + mg_printf(conn, "%s",m_node->schema().to_json(true).c_str()); + } + else + { + CONDUIT_WARN("rest request for schema of NULL Node"); + return false; + } + return true; +} + +//---------------------------------------------------------------------------// +// Handles a request from the client for a specific value in the node. +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_get_value(struct mg_connection *conn) +{ + if(m_node != NULL) + { + // TODO size checks? + char post_data[2048]; + char cpath[2048]; + + int post_data_len = mg_read(conn, post_data, sizeof(post_data)); + + // TODO: path instead of cpath? + + mg_get_var(post_data, post_data_len, "cpath", cpath, sizeof(cpath)); + // TODO: value instead of datavalue + mg_printf(conn, "{ \"datavalue\": %s }", + m_node->fetch(cpath).to_json().c_str()); + } + else + { + CONDUIT_WARN("rest request for value of NULL Node"); + return false; + } + return true; +} + +//---------------------------------------------------------------------------// +// Handles a request from the client for a compact, base64 encoded version +// of the node. +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_get_base64_json(struct mg_connection *conn) +{ + if(m_node != NULL) + { + std::ostringstream oss; + m_node->to_json_stream(oss,"base64_json"); + mg_printf(conn, "%s",oss.str().c_str()); + } + else + { + CONDUIT_WARN("rest request for base64 json of NULL Node"); + return false; + } + + return true; +} + +//---------------------------------------------------------------------------// +// Handles a request from the client to shutdown the REST server +//---------------------------------------------------------------------------// +bool +VisualizerRequestHandler::handle_shutdown(WebServer *server) +{ + server->shutdown(); + return true; +} + +//---------------------------------------------------------------------------// +// Helper to easily create a Visualizer instance. +//---------------------------------------------------------------------------// +WebServer * +VisualizerServer::serve(Node *data, + bool block, + index_t port, + const std::string &ssl_cert_file) +{ + VisualizerRequestHandler *rhandler = new VisualizerRequestHandler(data); + + WebServer *res = new WebServer(); + // call general serve routine + res->serve(utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT,"rest_client"), + rhandler, + port, + ssl_cert_file); + + if(block) + { + // wait for shutdown() + while(res->is_running()) + { + utils::sleep(100); + } + } + + return res; +} + + +}; +//----------------------------------------------------------------------------- +// -- end conduit::io -- +//----------------------------------------------------------------------------- + + +}; +//----------------------------------------------------------------------------- +// -- end conduit:: -- +//----------------------------------------------------------------------------- diff --git a/src/libs/conduit_io/conduit_web_visualizer.hpp b/src/libs/conduit_io/conduit_web_visualizer.hpp new file mode 100644 index 000000000..1dd5f4921 --- /dev/null +++ b/src/libs/conduit_io/conduit_web_visualizer.hpp @@ -0,0 +1,133 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) 2014-2015, Lawrence Livermore National Security, LLC. +// +// Produced at the Lawrence Livermore National Laboratory +// +// LLNL-CODE-666778 +// +// All rights reserved. +// +// This file is part of Conduit. +// +// For details, see: http://llnl.github.io/conduit/. +// +// Please also read conduit/LICENSE +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the LLNS/LLNL nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, +// LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: conduit_web_visualizer.hpp +/// +//----------------------------------------------------------------------------- + +#ifndef CONDUIT_WEB_VISUALIZER_HPP +#define CONDUIT_WEB_VISUALIZER_HPP + +//----------------------------------------------------------------------------- +// conduit lib includes +//----------------------------------------------------------------------------- +#include "conduit.hpp" +#include "Conduit_IO_Exports.hpp" + +#include "conduit_web.hpp" + +//----------------------------------------------------------------------------- +// -- begin conduit:: -- +//----------------------------------------------------------------------------- +namespace conduit +{ + +//----------------------------------------------------------------------------- +// -- begin conduit::io -- +//----------------------------------------------------------------------------- + +namespace io +{ + +//----------------------------------------------------------------------------- +// -- Visualizer Web Request Handler - +//----------------------------------------------------------------------------- +class CONDUIT_IO_API VisualizerRequestHandler : public WebRequestHandler +{ +public: + VisualizerRequestHandler(Node *node); + ~VisualizerRequestHandler(); + + virtual bool handle_post(WebServer *server, + struct mg_connection *conn); + + virtual bool handle_get(WebServer *server, + struct mg_connection *conn); + +private: + // catch all, used for any post or get + bool handle_request(WebServer *server, + struct mg_connection *conn); + // handlers for specific commands + bool handle_get_schema(struct mg_connection *conn); + bool handle_get_value(struct mg_connection *conn); + bool handle_get_base64_json(struct mg_connection *conn); + bool handle_shutdown(WebServer *server); + + // holds the node to visualize + Node *m_node; +}; + +//----------------------------------------------------------------------------- +// -- Visualizer Web Request Handler - +//----------------------------------------------------------------------------- + +class CONDUIT_IO_API VisualizerServer +{ +public: + static WebServer *serve(Node *data, + bool block=false, + index_t port = 8080, + const std::string &ssl_cert_file = std::string("")); +}; + + +}; +//----------------------------------------------------------------------------- +// -- end conduit::io -- +//----------------------------------------------------------------------------- + + + +}; +//----------------------------------------------------------------------------- +// -- end conduit:: -- +//----------------------------------------------------------------------------- + +#endif + + + diff --git a/src/tests/conduit_io/t_conduit_io_rest.cpp b/src/tests/conduit_io/t_conduit_io_rest.cpp index 46f46c49f..2357d85f3 100644 --- a/src/tests/conduit_io/t_conduit_io_rest.cpp +++ b/src/tests/conduit_io/t_conduit_io_rest.cpp @@ -79,26 +79,21 @@ TEST(conduit_io_rest, rest_server) { if(!use_ssl) { - io::rest::serve(n); + conduit::io::WebServer *svr = conduit::io::VisualizerServer::serve(n, + true, + 8080); + delete svr; } else // ssl path { - std::string rest_path = utils::join_file_path(CONDUIT_WEB_CLIENT_ROOT, - "rest_client"); - conduit::io::WebServer svr; - std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); - cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); - - svr.set_node(n); - // start our server - svr.serve(rest_path, - 8080, - cert_path); - - while(svr.is_running()) - { - utils::sleep(1); - } + std::string cert_file = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); + cert_file = utils::join_file_path(cert_file,"t_ssl_cert.pem"); + + conduit::io::WebServer *svr = conduit::io::VisualizerServer::serve(n, + true, + 8080, + cert_file); + delete svr; } } else diff --git a/src/tests/conduit_io/t_conduit_io_websocket.cpp b/src/tests/conduit_io/t_conduit_io_websocket.cpp index b31fd523e..cd5709d6d 100644 --- a/src/tests/conduit_io/t_conduit_io_websocket.cpp +++ b/src/tests/conduit_io/t_conduit_io_websocket.cpp @@ -121,13 +121,16 @@ TEST(conduit_io_websocket, websocket_test) // start our server if(!use_ssl) { - svr.serve(wsock_path,8081); + svr.serve(wsock_path, + new WebRequestHandler(), + 8081); } else { std::string cert_path = utils::join_file_path(CONDUIT_T_SRC_DIR,"conduit_io"); cert_path = utils::join_file_path(cert_path,"t_ssl_cert.pem"); svr.serve(wsock_path, + new WebRequestHandler(), 8081, cert_path); }