This commit is contained in:
2015-05-27 02:29:05 +02:00
parent 6031718d0e
commit 52ae80523c
9 changed files with 517 additions and 163 deletions
+8 -4
View File
@@ -8,6 +8,7 @@ find_package(catkin REQUIRED COMPONENTS
hos_cosgi_core
hos_cpp_utils
hos_deps
cmake_modules
roscpp
)
@@ -17,6 +18,7 @@ find_package(CELIX REQUIRED)
find_package(Boost REQUIRED)
find_package(libvariant REQUIRED)
find_package(libhttpserver REQUIRED)
find_package(Poco REQUIRED COMPONENTS Net NetSSL)
###################################
@@ -44,6 +46,7 @@ include_directories(
${APR_INCLUDE_DIR}/apr-1.0
${libvariant_INCLUDE_DIRS}
${libhttpserver_INCLUDE_DIRS}
${Poco_INCLUDE_DIRS}
)
set(BUNDLE_SYMBOLICNAME "hos.hos_webserver")
@@ -54,15 +57,16 @@ bundle(hos_cosgi_webserver
SOURCES
${PROJECT_SOURCE_DIR}/src/BundleActivator
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/WebServerServiceImpl
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/DevicesHTTPResource
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/SchemaHTTPResource
# ${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/DevicesHTTPResource
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/SchemaResource
)
target_link_libraries(hos_cosgi_webserver
${catkin_LIBRARIES}
${APR_LIBRARIES}
${libvariant_LIBRARY}
${libhttpserver_LIBRARY}
${libvariant_LIBRARIES}
${libhttpserver_LIBRARIES}
${Poco_LIBRARIES}
)
@@ -6,10 +6,18 @@
#include <Variant/Variant.h>
#include <memory>
#include <vector>
#include <string>
// forward declarations
namespace httpserver { class webserver;}
namespace libvariant { class Variant; }
namespace Poco {
class URI;
namespace Net {
class HTTPRequestHandler;
class HTTPServerRequest;
}}
// service namespace
@@ -23,16 +31,11 @@ namespace webserver {
class WebServerService;
class WebResource
class WebResourceHandlerFactory
: public virtual interface::Object {
public:
virtual void init( const std::vector<std::string>& prefixPath,
const std::string& registeredPath,
const std::string& absolutePath,
httpserver::webserver& webserver,
WebServerService& service ) = 0;
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request, bool ssl = false ) noexcept = 0;
};
@@ -44,7 +47,11 @@ public:
static constexpr const char* SERVICE_NAME = "hos_webserver_service";
virtual void registerWebResource(const std::string& path, std::shared_ptr<WebResource> resource) = 0;
virtual bool registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept = 0;
virtual const Poco::URI& getPrefixPath() noexcept = 0;
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept = 0;
};
@@ -0,0 +1,233 @@
#pragma once
#include <hos/cosgi/service/webserver/WebServerService.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/Net/HTMLForm.h>
#include <Variant/Variant.h>
#include <boost/format.hpp>
#include <functional>
// service namespace
namespace hos {
namespace cosgi {
namespace service {
namespace webserver {
namespace resources {
/**
* Used for internal error handling.
*/
class WebResourceHandlerException
: public std::runtime_error {
protected:
Poco::Net::HTTPResponse::HTTPStatus statusCode;
public:
WebResourceHandlerException(const std::string& msg, Poco::Net::HTTPResponse::HTTPStatus statusCode)
: std::runtime_error(msg), statusCode(statusCode) {}
Poco::Net::HTTPResponse::HTTPStatus getStatusCode() const {
return statusCode;
}
};
class GenericWebResourceHandlerFactory
: public virtual WebResourceHandlerFactory {
public:
typedef std::function<Poco::Net::HTTPRequestHandler*(const Poco::Net::HTTPServerRequest&, bool)> factory_t;
private:
factory_t _factory;
public:
GenericWebResourceHandlerFactory(factory_t factory)
: _factory(factory) {}
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request, bool ssl = false ) noexcept override {
return _factory(request, ssl);
}
};
enum class ResponseDataFormat : int {
JSON,
JSONP,
YAML,
XMLPLIST,
BUNDLEHDR,
MSGPACK,
AUTO_GUESS
};
class WebResourceHandlerImpl
: public Poco::Net::HTTPRequestHandler {
protected:
class NotImplementedException
: public std::exception {};
ResponseDataFormat getResponseDataFormat(const Poco::Net::HTTPServerRequest& request) {
ResponseDataFormat retval = ResponseDataFormat::JSON;
Poco::Net::HTMLForm form(request);
if (form.has("format")) {
std::string formatRaw = form.get("format");
if (formatRaw.compare("json") == 0) {
// do nothing
} else if (formatRaw.compare("jsonp") == 0) {
retval = ResponseDataFormat::JSONP;
} else if (formatRaw.compare("yaml") == 0) {
retval = ResponseDataFormat::YAML;
} else if (formatRaw.compare("xmlplist") == 0) {
retval = ResponseDataFormat::XMLPLIST;
} else if (formatRaw.compare("bundlehdr") == 0) {
retval = ResponseDataFormat::BUNDLEHDR;
} else if (formatRaw.compare("msgpack") == 0) {
retval = ResponseDataFormat::MSGPACK;
} else {
throw WebResourceHandlerException((boost::format("Unknown format parameter \"%1%\"") % formatRaw).str(),
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
}
}
return retval;
}
std::string encodeVariant( const libvariant::Variant& msg,
const Poco::Net::HTTPServerRequest& request,
ResponseDataFormat format = ResponseDataFormat::AUTO_GUESS ) {
if (format == ResponseDataFormat::AUTO_GUESS) {
format = getResponseDataFormat(request);
}
switch (format) {
case ResponseDataFormat::JSON:
return libvariant::SerializeJSON(msg, true);
case ResponseDataFormat::JSONP:
{
Poco::Net::HTMLForm form(request);
std::string padding;
if (form.has("callback")) {
padding = form.get("callback");
} else if (form.has("jsonp")) {
padding = form.get("jsonp");
}
if (padding.empty()) {
throw WebResourceHandlerException("No callback parameter specified for JSONP.",
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
}
std::stringstream ss;
ss << padding << "(" << libvariant::SerializeJSON(msg, false) << ")";
return ss.str();
}
case ResponseDataFormat::YAML:
return libvariant::SerializeYAML(msg);
case ResponseDataFormat::XMLPLIST:
return libvariant::SerializeXMLPLIST(msg, true);
case ResponseDataFormat::BUNDLEHDR:
return libvariant::SerializeBundleHdr(msg);
case ResponseDataFormat::MSGPACK:
return libvariant::Serialize(msg, libvariant::SERIALIZE_MSGPACK);
default:
throw WebResourceHandlerException("Internal Server Error",
Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR);
}
}
void handleResponse( const Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse &resp,
const libvariant::Variant& msg,
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK ) {
resp.setStatusAndReason(status);
auto format = getResponseDataFormat(request);
resp.send() << encodeVariant(msg, request, format);
}
void handleResponse( const Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse &resp,
const std::string& msg,
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK ) {
resp.setStatusAndReason(status);
resp.send() << msg;
}
void handleErrorResponse( const Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse &resp,
const std::string& msg = "Internal Server Error",
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR ) {
resp.setStatusAndReason(status);
resp.send() << "ERROR: " << msg;
}
void handleErrorResponse( const Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse &resp,
const WebResourceHandlerException& e ) {
resp.setStatusAndReason(e.getStatusCode());
resp.send() << "ERROR: " << e.what();
}
void handleErrorResponse( const Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse &resp,
const std::exception& e,
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR ) {
resp.setStatusAndReason(status);
resp.send() << "ERROR: " << e.what();
}
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
throw NotImplementedException();
}
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
throw NotImplementedException();
}
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
throw NotImplementedException();
}
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
try {
try {
_handleRequest(req, resp);
} catch (NotImplementedException& e) {
try {
if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
_handleGET(req, resp);
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
_handlePOST(req, resp);
} else {
std::cout << "Unsupported HTTP Request Method" << std::endl;
handleErrorResponse(req, resp, (boost::format("Unsupported HTTP Request Method %1%") % req.getMethod()).str(),
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
}
} catch (NotImplementedException& e) {
std::cout << "Unsupported HTTP Request Method" << std::endl;
handleErrorResponse(req, resp, (boost::format("Unsupported HTTP Request Method %1%") % req.getMethod()).str(),
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
}
}
} catch (WebResourceHandlerException& e) {
handleErrorResponse(req, resp, e);
} catch (std::exception& e) {
handleErrorResponse(req, resp, e);
} catch (...) {
handleErrorResponse(req, resp, "Unknown exception");
}
}
};
} // namespace resources
} // namespace webserver
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -2,6 +2,7 @@
#include "WebServerServiceImpl.h"
#include <boost/algorithm/string.hpp>
#include <ros/ros.h>
#include "resources/SchemaResource.h"
@@ -13,6 +14,7 @@ namespace webserver {
using namespace libvariant;
using namespace httpserver;
using namespace Poco;
@@ -23,7 +25,12 @@ template<> const int implementation::ServiceInfo<WebServerServiceImpl>::minor =
WebServerServiceImpl::~WebServerServiceImpl() {
webServer->stop();
if (webServer) {
webServer->stop();
}
if (webServerSSL) {
webServerSSL->stop();
}
}
@@ -54,46 +61,104 @@ void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryServ
}
void WebServerServiceImpl::RequestHandlerFactory::DefaultRequestHandler::handleRequest(
Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp ) {
resp.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
resp.setContentType("text/plain");
resp.send()
<< "ERROR: " << resp.getReason() << std::endl
<< "========== DEBUG ==========" << std::endl
<< "getURI: " << req.getURI() << std::endl
<< "getHost: " << req.getHost() << std::endl
<< "getMethod: " << req.getMethod() << std::endl
<< "getTransferEncoding: " << req.getTransferEncoding() << std::endl
<< "getVersion: " << req.getVersion() << std::endl
<< "getContentType: " << req.getContentType() << std::endl
<< "getContentLength: " << req.getContentLength() << std::endl
<< "======== DEBUG END ========" << std::endl ;
}
Poco::Net::HTTPRequestHandler* WebServerServiceImpl::RequestHandlerFactory::createRequestHandler( const Poco::Net::HTTPServerRequest& request) {
// We want a longest prefix match.
// Since we have an ordered map, we just need to iterate it in reverse order and return the first match.
for (auto i = parent->webResourceFactories.rbegin(); i != parent->webResourceFactories.rend(); i++) {
if (boost::algorithm::starts_with(request.getURI(), i->first)) {
return i->second->createRequestHandler(request, ssl);
}
}
// return default handler
return new DefaultRequestHandler();
}
void WebServerServiceImpl::init() noexcept {
// Create and start webserver
create_webserver serverParams(8888);
serverParams.max_threads(5);
webServer.reset(new webserver::webserver(serverParams));
//create_webserver serverParams(8888);
//serverParams.max_threads(5);
//webServer.reset(new webserver::webserver(serverParams));
// Register web resources
registerWebResource( "/schemas",
Net::ServerSocket webServerSocket(8080);
Net::HTTPServerParams::Ptr webServerParams = new Net::HTTPServerParams();
webServerParams->setServerName("Home Operating System");
webServerParams->setSoftwareVersion("Home Operating System alpha");
webServer.reset(new Poco::Net::HTTPServer(new RequestHandlerFactory(this), webServerSocket, webServerParams));
webServer->start();
/*auto& sslManager = Poco::Net::SSLManager::instance();
sslManager.defaultServerContext();
Poco::Net::SecureServerSocket webServerSSLSocket(8090);
webServerSSL.reset(new Poco::Net::HTTPServer(new RequestHandlerFactory(), webServerSocket, webServerParams));
webServerSSL->start();*/
// Register web resources ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service
registerWebResource("/schemas",
std::make_shared<resources::GenericWebResourceHandlerFactory>([=](const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
return new resources::SchemaResourceHandler(nodehandle, &coreService->getSchemaLoader(), this);
})
);
registerWebResource("/default",
std::make_shared<resources::GenericWebResourceHandlerFactory>([=](const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
return new resources::WebResourceHandlerImpl();
})
);
/*registerWebResource( "/schemas",
std::make_shared<resources::SchemaHTTPResource>(nodehandle, &coreService->getSchemaLoader())
);
registerWebResource( "/devices",
std::make_shared<resources::DevicesHTTPResource>(repoService)
);
);*/
webServer->start(false);
//webServer->start(false);
initialized = true;
ROS_INFO_STREAM("WebServerService: Initialized and Ready.");
}
void WebServerServiceImpl::registerWebResource(const std::string& path, std::shared_ptr<WebResource> resource) {
std::string apath = getAbsolutePath(path);
if (webResources.find(apath) == webResources.end()) {
resource->init(prefixPath, path, apath, *webServer, *this);
webResources[apath] = resource;
bool WebServerServiceImpl::registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept {
auto uri = getAbsoluteURI(path);
if (webResourceFactories.find(uri.getPath()) == webResourceFactories.end()) {
webResourceFactories[uri.getPath()] = factory;
return true;
}
return false;
}
std::string WebServerServiceImpl::getAbsolutePath(const std::string& path) {
Poco::URI WebServerServiceImpl::getAbsoluteURI(const std::string& relpath) {
std::stringstream ss;
for (auto p : prefixPath) {
ss << "/" << p;
}
std::string tpath = boost::algorithm::trim_copy(path);
ss << prefixPath.getPath();
std::string tpath = boost::algorithm::trim_copy(relpath);
if (tpath[0] != '/') {
ss << "/";
}
ss << tpath;
return ss.str();
Poco::URI uri(ss.str());
uri.normalize();
return uri;
}
@@ -7,13 +7,33 @@
#include <hos/cosgi/service/core/CoreService.h>
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
#include <mutex>
#include <boost/algorithm/string.hpp>
#include <memory>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <httpserver.hpp>
#include "resources/SchemaHTTPResource.h"
#include "resources/DevicesHTTPResource.h"
//#include "resources/SchemaHTTPResource.h"
//#include "resources/DevicesHTTPResource.h"
#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/HTTPRequestHandlerFactory.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/URI.h>
#include <Poco/Net/HTMLForm.h>
#include <Poco/Net/SecureServerSocket.h>
#include <Poco/Net/SSLManager.h>
@@ -24,6 +44,22 @@ namespace service {
namespace webserver {
/**
* Used for internal error handling.
*/
class WebResourceHandlerException
: public std::runtime_error {
protected:
Poco::Net::HTTPResponse::HTTPStatus statusCode;
public:
WebResourceHandlerException(const std::string& msg, Poco::Net::HTTPResponse::HTTPStatus statusCode)
: std::runtime_error(msg), statusCode(statusCode) {}
Poco::Net::HTTPResponse::HTTPStatus getStatusCode() {
return statusCode;
}
};
class WebServerServiceImpl
: public virtual WebServerService,
@@ -31,19 +67,40 @@ class WebServerServiceImpl
private:
class RequestHandlerFactory
: public Poco::Net::HTTPRequestHandlerFactory {
private:
WebServerServiceImpl* parent;
bool ssl;
class DefaultRequestHandler
: public Poco::Net::HTTPRequestHandler {
public:
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
};
public:
RequestHandlerFactory(WebServerServiceImpl* parent, bool ssl = false)
: parent(parent), ssl(ssl) {}
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request) override;
};
service::core::CoreService* coreService = nullptr;
devicerepository::DeviceRepositoryService* repoService = nullptr;
ros::NodeHandle* nodehandle = nullptr;
std::vector<std::string> prefixPath = { "hos" };
bool initialized = false;
std::unique_ptr<httpserver::webserver> webServer;
std::map<std::string, std::shared_ptr<WebResource>> webResources;
Poco::URI prefixPath = Poco::URI("/hos");
std::vector<std::string> prefixPathPieces;
std::unique_ptr<Poco::Net::HTTPServer> webServer;
std::unique_ptr<Poco::Net::HTTPServer> webServerSSL;
std::map<std::string, std::shared_ptr<WebResourceHandlerFactory>> webResourceFactories;
void init() noexcept;
public:
WebServerServiceImpl() {
prefixPath.getPathSegments(prefixPathPieces);
}
~WebServerServiceImpl();
@@ -56,7 +113,15 @@ public:
/* Public Service Implementations */
virtual void registerWebResource(const std::string& path, std::shared_ptr<WebResource> resource);
virtual bool registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept override;
virtual const Poco::URI& getPrefixPath() noexcept override {
return prefixPath;
}
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept override {
return prefixPathPieces;
}
/* Internal */
@@ -65,7 +130,7 @@ public:
return initialized;
}
std::string getAbsolutePath(const std::string& path);
Poco::URI getAbsoluteURI(const std::string& relpath);
};
@@ -1,63 +0,0 @@
#include "SchemaHTTPResource.h"
#include <boost/format.hpp>
// Service Namespace
namespace hos {
namespace cosgi {
namespace service {
namespace webserver {
namespace resources {
using namespace httpserver;
using namespace libvariant;
void SchemaHTTPResource::init( const std::vector<std::string>& prefixPath,
const std::string& registeredPath,
const std::string& absolutePath,
httpserver::webserver& webserver,
WebServerService& service ) {
webResource.prefixPath = prefixPath;
webResource.disallow_all();
webResource.set_allowing(MHD_HTTP_METHOD_GET, true);
webserver.register_resource(absolutePath, &webResource, true);
}
void SchemaHTTPResource::WebResource::render_GET(const httpserver::http_request& req, httpserver::http_response** res) {
// Requested URL is too short to contain any schema
if (req.get_path_pieces_size() <= prefixPath.size() + 1) {
*res = new http_response(http_response_builder("ERROR: No schema given", 400).string_response());
// Requested URL may contain a valid schema
} else {
// Get requested schema
std::stringstream ss;
for (int i = prefixPath.size() + 1; i < req.get_path_pieces_size(); i++) {
ss << "/" << req.get_path_piece(i);
}
auto schemaPath = (boost::format("hos:schema:/%1%") % ss.str()).str();
// Try to retrieve schema
try {
auto schema = schemaLoader->GetSchema(schemaPath);
*res = new http_response(http_response_builder(SerializeJSON(schema, true), 200).string_response());
} catch(std::exception& e) {
*res = new http_response(http_response_builder((boost::format("ERROR: Could not find schema \"%1%\": %2%") % schemaPath % e.what()).str(), 404).string_response());
}
}
}
} // namespace resources
} // namespace webserver
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -1,62 +0,0 @@
#pragma once
#include <hos/cosgi/service/webserver/WebServerService.h>
#include <hos/utils/SchemaLoader.h>
#include <ros/ros.h>
#include <httpserver.hpp>
#include <vector>
// Service Namespace
namespace hos {
namespace cosgi {
namespace service {
namespace webserver {
namespace resources {
class SchemaHTTPResource
: public virtual webserver::WebResource {
private:
/**
* libhttpserver does a static_cast with any class registered as http resource. Unfortunately this breaks classes
* using virtual inheritance. Therefore we register this inner class which does not use virtual inheritance.
*/
class WebResource
: public httpserver::http_resource<WebResource> {
public:
ros::NodeHandle* nodehandle = nullptr;
utils::SchemaLoader* schemaLoader = nullptr;
std::vector<std::string> prefixPath;
WebResource(ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader)
: nodehandle(nodehandle), schemaLoader(schemaLoader) {}
void render_GET(const httpserver::http_request& req, httpserver::http_response** res);
} webResource;
public:
SchemaHTTPResource(ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader)
: webResource(nodehandle, schemaLoader) {}
virtual void init( const std::vector<std::string>& prefixPath,
const std::string& registeredPath,
const std::string& absolutePath,
httpserver::webserver& webserver,
WebServerService& service );
};
} // namespace resources
} // namespace webserver
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -0,0 +1,61 @@
#include "SchemaResource.h"
#include <boost/format.hpp>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/URI.h>
#include "../WebServerServiceImpl.h"
// Service Namespace
namespace hos {
namespace cosgi {
namespace service {
namespace webserver {
namespace resources {
using namespace httpserver;
using namespace libvariant;
void SchemaResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
// Requested URL is too short to contain any schema
Poco::URI uri(req.getURI());
std::vector<std::string> pathPieces;
uri.getPathSegments(pathPieces);
size_t prefixPathSize = service->getPrefixPathPieces().size();
if (pathPieces.size() <= prefixPathSize + 1) {
throw WebResourceHandlerException("No schema given.", Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
// Requested URL may contain a valid schema
} else {
// Get requested schema
std::stringstream ss;
for (int i = prefixPathSize + 1; i < pathPieces.size(); i++) {
ss << "/" << pathPieces[i];
}
auto schemaPath = (boost::format("hos:schema:/%1%") % ss.str()).str();
// Try to retrieve schema
try {
auto schema = schemaLoader->GetSchema(schemaPath);
handleResponse(req, resp, schema);
} catch(std::exception& e) {
throw WebResourceHandlerException((boost::format("Could not find schema \"%1%\": %2%") % schemaPath % e.what()).str(),
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
}
}
}
} // namespace resources
} // namespace webserver
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -0,0 +1,44 @@
#pragma once
#include <hos/cosgi/service/webserver/WebServerService.h>
#include <hos/cosgi/service/webserver/resources/WebResourceHandlerImpl.h>
#include <hos/utils/SchemaLoader.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <ros/ros.h>
#include <vector>
// Service Namespace
namespace hos {
namespace cosgi {
namespace service {
namespace webserver {
namespace resources {
class SchemaResourceHandler
: public virtual WebResourceHandlerImpl {
private:
ros::NodeHandle* nodehandle;
utils::SchemaLoader* schemaLoader;
WebServerService* service;
public:
SchemaResourceHandler(ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
: nodehandle(nodehandle), schemaLoader(schemaLoader), service(service) {}
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
};
} // namespace resources
} // namespace webserver
} // namespace service
} // namespace cosgi
} // namespace hos