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 0d9685535..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) + void set_handler(WebRequestHandler *handler) { - m_node = node; + m_handler = handler; } - - //---------------------------------------------------------------------------// - // Main handler, dispatches to proper api handlers. - //---------------------------------------------------------------------------// - bool handle_request(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_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; - } - + //---------------------------------------------------------------------------// // 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,79 +156,16 @@ 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()); - } - 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)); - - mg_get_var(post_data, post_data_len, "cpath", cpath, sizeof(cpath)); - - mg_printf(conn, "{ \"datavalue\": %s }", - m_node->fetch(cpath).to_json().c_str()); - } - 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()); - } - 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); } //---------------------------------------------------------------------------// // 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 +176,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 +192,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 +228,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 +297,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 @@ -542,7 +434,7 @@ class RequestHandler : public CivetHandler, private: WebServer *m_server; - Node *m_node; + WebRequestHandler *m_handler; std::vector m_sockets; }; @@ -621,7 +513,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; } @@ -650,12 +542,15 @@ WebSocket::send(const Node &data, //----------------------------------------------------------------------------- WebServer::WebServer() -: m_server(NULL), - m_handler(NULL), +: m_handler(NULL), + m_doc_root(""), m_port(""), - m_running(false) + m_ssl_cert_file(""), + m_running(false), + m_server(NULL), + m_dispatch(NULL) { - m_handler = new RequestHandler(*this); + // empty } //----------------------------------------------------------------------------- @@ -676,12 +571,10 @@ 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); } - - //----------------------------------------------------------------------------- void WebServer::lock_context() @@ -704,32 +597,13 @@ WebServer::unlock_context() } } - - - //----------------------------------------------------------------------------- -void -WebServer::serve(Node *node, - bool block, - index_t port) +WebRequestHandler * +WebServer::handler() { - 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); - } - } + return m_handler; } - //----------------------------------------------------------------------------- mg_context * WebServer::context() @@ -741,27 +615,52 @@ WebServer::context() //----------------------------------------------------------------------------- void WebServer::serve(const std::string &doc_root, - index_t port) + WebRequestHandler *handler, + index_t port, + const std::string &ssl_cert_file) { if(is_running()) { 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; // 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 +670,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,18 +678,26 @@ 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); + 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 - 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 @@ -806,21 +713,20 @@ WebServer::shutdown() { CONDUIT_INFO("closing conduit::io::WebServer instance on port: " << m_port); - + m_running = false; + delete m_server; delete m_handler; + delete m_dispatch; - - m_handler = NULL; - m_server = 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 61e4ec636..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 { @@ -114,36 +116,50 @@ class CONDUIT_IO_API WebServer WebServer(); virtual ~WebServer(); - - void serve(const std::string &doc_root, - index_t port = 8080); - - // 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 serve(const std::string &doc_root, + WebRequestHandler *dispatch, // takes ownership? + index_t port = 8080, + 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); + void shutdown(); 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); + 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; + }; //----------------------------------------------------------------------------- @@ -156,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(); @@ -168,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/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..2357d85f3 100644 --- a/src/tests/conduit_io/t_conduit_io_rest.cpp +++ b/src/tests/conduit_io/t_conduit_io_rest.cpp @@ -52,9 +52,13 @@ #include #include "gtest/gtest.h" +#include "t_config.hpp" + using namespace conduit; bool launch_server = false; +bool use_ssl = false; + TEST(conduit_io_rest, rest_server) { @@ -73,7 +77,24 @@ TEST(conduit_io_rest, rest_server) if(launch_server) { - io::rest::serve(n); + if(!use_ssl) + { + conduit::io::WebServer *svr = conduit::io::VisualizerServer::serve(n, + true, + 8080); + delete svr; + } + else // ssl path + { + 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 { @@ -84,6 +105,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[]) @@ -99,6 +164,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..cd5709d6d 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,22 @@ TEST(conduit_io_websocket, websocket_test) WebServer svr; // start our server - svr.serve(wsock_path,8081); + if(!use_ssl) + { + 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); + } + // this loop won't be necessary in the strawman lib. while(svr.is_running()) @@ -145,7 +163,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; } } 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 + + +