ZeroEQ  0.7.0
ZeroEQ - Zero Event Queue
zeroeq::http::Server Class Reference

Serves HTTP GET and PUT requests for servus::Serializable objects. More...

#include <server.h>

+ Inheritance diagram for zeroeq::http::Server:
+ Collaboration diagram for zeroeq::http::Server:

Public Member Functions

Object registration for PUT and GET requests
bool handle (servus::Serializable &object)
 Handle PUT and GET for the given object. More...
 
ZEROEQHTTP_API bool remove (const servus::Serializable &object)
 Remove PUT and GET handling for given object. More...
 
ZEROEQHTTP_API bool remove (const std::string &event)
 Remove PUT and GET handling for given event. More...
 
ZEROEQHTTP_API bool handlePUT (servus::Serializable &object)
 Subscribe a serializable object to receive updates from HTTP PUT requests. More...
 
ZEROEQHTTP_API bool handlePUT (const std::string &event, const PUTFunc &func)
 Subscribe an event to receive HTTP PUT requests. More...
 
ZEROEQHTTP_API bool handlePUT (const std::string &event, const std::string &schema, const PUTFunc &func)
 This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. More...
 
ZEROEQHTTP_API bool handlePUT (const std::string &event, const PUTPayloadFunc &func)
 Subscribe an event to receive HTTP PUT requests with payload. More...
 
ZEROEQHTTP_API bool handlePUT (const std::string &event, const std::string &schema, const PUTPayloadFunc &func)
 This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. More...
 
ZEROEQHTTP_API bool handleGET (servus::Serializable &object)
 Subscribe a serializable object to serve HTTP GET requests. More...
 
ZEROEQHTTP_API bool handleGET (const std::string &event, const GETFunc &func)
 Subscribe an event to serve HTTP GET requests. More...
 
ZEROEQHTTP_API bool handleGET (const std::string &event, const std::string &schema, const GETFunc &func)
 This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. More...
 
ZEROEQHTTP_API std::string getSchema (const servus::Serializable &object) const
 
ZEROEQHTTP_API std::string getSchema (const std::string &event) const
 
- Public Member Functions inherited from zeroeq::Receiver
 Receiver ()
 Create a new standalone receiver. More...
 
 Receiver (Receiver &shared)
 Create a shared receiver. More...
 
virtual ~Receiver ()
 Destroy this receiver. More...
 
bool receive (const uint32_t timeout=TIMEOUT_INDEFINITE)
 Receive at least one event from all shared receivers. More...
 

Setup

ZEROEQHTTP_API Server (const URI &uri, Receiver &shared)
 Construct a new HTTP server. More...
 
ZEROEQHTTP_API Server (const URI &uri)
 
ZEROEQHTTP_API Server (Receiver &shared)
 
ZEROEQHTTP_API Server ()
 
ZEROEQHTTP_API Server (Server &shared)
 
ZEROEQHTTP_API ~Server ()
 
ZEROEQHTTP_API const URIgetURI () const
 Get the publisher URI. More...
 
ZEROEQHTTP_API SocketDescriptor getSocketDescriptor () const
 Get the underlying socket descriptor. More...
 
static ZEROEQHTTP_API std::unique_ptr< Serverparse (int argc, const char *const *argv)
 Create a new Server when requested. More...
 
static ZEROEQHTTP_API std::unique_ptr< Serverparse (int argc, const char *const *argv, Receiver &shared)
 

Additional Inherited Members

- Protected Member Functions inherited from zeroeq::Receiver
virtual void update ()
 Update the internal connection list. More...
 
void * getZMQContext ()
 

Detailed Description

Serves HTTP GET and PUT requests for servus::Serializable objects.

Behaves semantically like a Publisher (for GET) and Subscriber (for PUT), except uses HTTP with JSON payload as the protocol. Requests are served synchronously (as per HTTP spec). Objects are available under their Serializable::getTypeName(), with '::' replaced by '/'. The REST API is case insensitive. For example, zerobuf::render::Camera is served at 'GET|PUT [uri]/zerobuf/render/camera'.

Not thread safe.

Example:

/* Copyright (c) 2016, Human Brain Project
* Stefan.Eilemann@epfl.ch
* Daniel.Nachbaur@epfl.ch
*/
#define BOOST_TEST_MODULE http_server
#include <zeroeq/http/server.h>
#include <zeroeq/subscriber.h>
#include <zeroeq/uri.h>
#include <servus/serializable.h>
#include <servus/uri.h>
#include <boost/test/unit_test.hpp>
#include <thread>
#include <boost/network/protocol/http/client.hpp>
#include <boost/network/protocol/http/server.hpp>
namespace
{
namespace http = boost::network::http;
// default client from cppnetlib is asynchronous, not handy for tests
using HTTPClient =
http::basic_client< http::tags::http_default_8bit_tcp_resolve, 1, 1 >;
using ServerReponse = http::basic_response<http::tags::http_server>;
void _addCorsHeaders( HTTPClient::response& response )
{
response.add_header( std::make_pair( "Access-Control-Allow-Headers",
"Content-Type" ));
response.add_header( std::make_pair( "Access-Control-Allow-Methods",
"GET,PUT,OPTIONS" ));
response.add_header( std::make_pair( "Access-Control-Allow-Origin",
"*" ));
}
HTTPClient::response _buildResponse( const std::string& body = std::string( ))
{
HTTPClient::response response;
response.status( ServerReponse::ok );
_addCorsHeaders( response );
if( !body.empty( ))
{
response.add_header( std::make_pair( "Content-Length",
std::to_string( body.size( ))));
}
response.body( body );
return response;
}
HTTPClient::response _buildError( const ServerReponse::status_type status,
const bool cors = true )
{
HTTPClient::response response;
response.status( status );
if( cors )
_addCorsHeaders( response );
const auto stockReply = ServerReponse::stock_reply( status );
for( const auto& i : stockReply.headers )
response.add_header( std::make_pair( i.name, i.value ));
response.body( stockReply.content );
return response;
}
const HTTPClient::response response200( _buildResponse( ));
const HTTPClient::response error400( _buildError( ServerReponse::bad_request ));
// bad_request for PUT with empty body is handled by cppnetlib directly, so
// no CORS headers there...
const HTTPClient::response error400_nocors(
_buildError( ServerReponse::bad_request, false ));
const HTTPClient::response error404( _buildError( ServerReponse::not_found ));
const HTTPClient::response error405(
_buildError( ServerReponse::method_not_allowed ));
const HTTPClient::response error411(
_buildError( ServerReponse::length_required ));
const std::string jsonGet( "Not JSON, just want to see that the is data a-ok" );
const std::string jsonPut( "See what my stepbrother jsonGet says" );
class Foo : public servus::Serializable
{
public:
Foo() { _notified = false; }
void setNotified() { _notified = true; }
bool getNotified() const { return _notified; }
std::string getSchema() const final
{
return "{\n '_notified' : 'bool'\n}";
}
private:
std::string getTypeName() const final { return "test::Foo"; }
virtual zeroeq::uint128_t getTypeIdentifier() const final
{ return servus::make_uint128( getTypeName( )); }
bool _fromJSON( const std::string& json ) final
{
return jsonPut == json;
}
std::string _toJSON() const final
{
return jsonGet;
}
bool _notified;
};
class Client : private HTTPClient
{
public:
Client( const zeroeq::URI& uri )
{
std::ostringstream url;
url << "http://" << uri.getHost() << ":" << uri.getPort();
_baseURL = url.str();
}
~Client()
{
}
void checkGET( const std::string& request,
const HTTPClient::response& expected, const int line )
{
_checkImpl( Method::GET, request, "", expected, line );
}
void checkPUT( const std::string& request, const std::string& data,
const HTTPClient::response& expected, const int line )
{
_checkImpl( Method::PUT, request, data, expected, line );
}
void checkPOST( const std::string& request, const std::string& data,
const HTTPClient::response& expected, const int line )
{
_checkImpl( Method::POST, request, data, expected, line );
}
void sendGET( const std::string& request )
{
HTTPClient::request request_( _baseURL + request );
get( request_ );
}
private:
std::string _baseURL;
enum class Method
{
GET,
POST,
PUT
};
void _checkImpl( const Method method, const std::string& request,
const std::string& data,
const HTTPClient::response& expected, const int line )
{
HTTPClient::request request_( _baseURL + request );
HTTPClient::response response;
switch( method )
{
case Method::GET:
response = get( request_ );
break;
case Method::POST:
response = post( request_, data );
break;
case Method::PUT:
response = put( request_, data );
break;
}
BOOST_CHECK_EQUAL( response.headers().size(),
expected.headers().size( ));
auto i = response.headers().begin();
auto j = expected.headers().begin();
for( ; i != response.headers().end(); ++i, ++j )
{
BOOST_CHECK_EQUAL( i->first, j->first );
BOOST_CHECK_EQUAL( i->second, j->second );
}
BOOST_CHECK_MESSAGE( response.body() == expected.body(),
"At l." + std::to_string( line ) + ": " +
response.body() + " != " + expected.body( ));
}
};
}
BOOST_AUTO_TEST_CASE(construction)
{
BOOST_CHECK_NE( server1.getURI().getHost(), "" );
BOOST_CHECK_NE( server1.getURI().getHost(), "*" );
BOOST_CHECK_NE( server1.getURI().getPort(), 0 );
BOOST_CHECK_NO_THROW( server1.getSocketDescriptor( ));
BOOST_CHECK_GT( server1.getSocketDescriptor(), 0 );
const zeroeq::URI uri( "tcp://" );
zeroeq::http::Server server2( uri );
zeroeq::http::Server server3( uri );
BOOST_CHECK_NE( server2.getURI(), server3.getURI( ));
BOOST_CHECK_NE( server2.getURI().getPort(), 0 );
BOOST_CHECK_THROW( zeroeq::http::Server( server2.getURI( )),
std::runtime_error );
BOOST_CHECK_NO_THROW( server2.getSocketDescriptor( ));
BOOST_CHECK_GT( server1.getSocketDescriptor(), 0 );
}
BOOST_AUTO_TEST_CASE(construction_argv_host_port)
{
const char* app = boost::unit_test::framework::master_test_suite().argv[0];
const char* argv[] = { app, "--zeroeq-http-server", "127.0.0.1:0" };
const int argc = sizeof(argv)/sizeof(char*);
std::unique_ptr< zeroeq::http::Server > server1 =
BOOST_REQUIRE( server1 );
BOOST_CHECK_EQUAL( server1->getURI().getHost(), "127.0.0.1" );
BOOST_CHECK_NE( server1->getURI().getPort(), 0 );
std::unique_ptr< zeroeq::http::Server > server2 =
zeroeq::http::Server::parse( argc, argv, shared );
BOOST_REQUIRE( server2 );
BOOST_CHECK_EQUAL( server2->getURI().getHost(), "127.0.0.1" );
BOOST_CHECK_NE( server2->getURI().getPort(), 0 );
}
BOOST_AUTO_TEST_CASE(construction_argv)
{
const char* app = boost::unit_test::framework::master_test_suite().argv[0];
const char* argv[] = { app, "--zeroeq-http-server" };
const int argc = sizeof(argv)/sizeof(char*);
std::unique_ptr< zeroeq::http::Server > server1 =
BOOST_REQUIRE( server1 );
BOOST_CHECK( !server1->getURI().getHost().empty( ));
BOOST_CHECK_NE( server1->getURI().getPort(), 0 );
std::unique_ptr< zeroeq::http::Server > server2 =
zeroeq::http::Server::parse( argc, argv, shared );
BOOST_CHECK( !server2->getURI().getHost().empty( ));
BOOST_CHECK_NE( server2->getURI().getPort(), 0 );
}
BOOST_AUTO_TEST_CASE(construction_empty_argv)
{
const char* app = boost::unit_test::framework::master_test_suite().argv[0];
const char* argv[] = { app };
const int argc = sizeof(argv)/sizeof(char*);
std::unique_ptr< zeroeq::http::Server > server1 =
BOOST_CHECK( !server1 );
std::unique_ptr< zeroeq::http::Server > server2 =
zeroeq::http::Server::parse( argc, argv, shared );
BOOST_CHECK( !server2 );
}
BOOST_AUTO_TEST_CASE(registration)
{
Foo foo;
BOOST_CHECK( server.handleGET( foo ));
BOOST_CHECK( !server.handleGET( foo ));
BOOST_CHECK( server.remove( foo ));
BOOST_CHECK( !server.remove( foo ));
BOOST_CHECK( server.handleGET( "foo", [](){ return "bla"; } ));
BOOST_CHECK( !server.handleGET( "foo", [](){ return "bla"; } ));
BOOST_CHECK( server.remove( "foo" ));
BOOST_CHECK( !server.remove( "foo" ));
BOOST_CHECK( server.handleGET( "bar", "schema", [](){ return "bla"; } ));
BOOST_CHECK( !server.handleGET( "bar", "schema", [](){ return "bla"; } ));
BOOST_CHECK( server.remove( "bar" ));
BOOST_CHECK( !server.remove( "bar" ));
BOOST_CHECK( server.handlePUT( foo ));
BOOST_CHECK( !server.handlePUT( foo ));
BOOST_CHECK( server.remove( foo ));
BOOST_CHECK( !server.remove( foo ));
BOOST_CHECK( server.handlePUT( "foo", zeroeq::PUTPayloadFunc
([]( const std::string& ) { return true; })));
BOOST_CHECK( !server.handlePUT( "foo", zeroeq::PUTPayloadFunc
([]( const std::string& ) { return true; })));
BOOST_CHECK( server.remove( "foo" ));
BOOST_CHECK( !server.remove( "foo" ));
BOOST_CHECK( server.handlePUT( "bar", "schema", zeroeq::PUTPayloadFunc
([]( const std::string& ) { return true; })));
BOOST_CHECK( !server.handlePUT( "bar", "schema", zeroeq::PUTPayloadFunc
([]( const std::string& ) { return true; })));
BOOST_CHECK_EQUAL( server.getSchema( "bar" ), "schema" );
BOOST_CHECK( server.handleGET( "bar", "schema", [](){ return "bla"; } ));
BOOST_CHECK( !server.handleGET( "bar", "schema", [](){ return "bla"; } ));
BOOST_CHECK_EQUAL( server.getSchema( "bar" ), "schema" );
BOOST_CHECK( server.remove( "bar" ));
BOOST_CHECK( !server.remove( "bar" ));
BOOST_CHECK_EQUAL( server.getSchema( "bar" ), "" );
BOOST_CHECK( server.handle( foo ));
BOOST_CHECK( !server.handle( foo ));
BOOST_CHECK( server.remove( foo ));
BOOST_CHECK( !server.remove( foo ));
BOOST_CHECK( server.handle( foo ));
BOOST_CHECK_EQUAL( server.getSchema( foo ), foo.getSchema( ));
BOOST_CHECK( server.remove( foo ));
BOOST_CHECK_EQUAL( server.getSchema( foo ), std::string( ));
}
BOOST_AUTO_TEST_CASE(get_serializable)
{
bool running = true;
Foo foo;
foo.registerSerializeCallback( [&]{ foo.setNotified(); });
server.handleGET( foo );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/unknown", error404, __LINE__ );
BOOST_CHECK( !foo.getNotified( ));
client.checkGET( "/test/Foo", _buildResponse( jsonGet ), __LINE__ );
BOOST_CHECK( foo.getNotified( ));
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(get_event)
{
bool running = true;
bool requested = false;
server.handleGET( "test::Foo", [&](){ requested = true; return jsonGet; } );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/unknown", error404, __LINE__ );
BOOST_CHECK( !requested );
client.checkGET( "/test/Foo", _buildResponse( jsonGet ), __LINE__ );
BOOST_CHECK( requested );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(shared)
{
bool running = true;
zeroeq::Subscriber subscriber;
zeroeq::http::Server server1( subscriber );
zeroeq::http::Server server2( server1 );
Foo foo;
server2.handleGET( foo );
std::thread thread( [&]() { while( running ) subscriber.receive( 100 );});
Client client1( server1.getURI( ));
Client client2( server2.getURI( ));
client1.checkGET( "/test/Foo", error404, __LINE__ );
client2.checkGET( "/test/Foo", _buildResponse( jsonGet ), __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(put_serializable)
{
bool running = true;
Foo foo;
foo.registerDeserializedCallback( [&]{ foo.setNotified(); });
server.handlePUT( foo );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkPUT( "/test/Foo", "", error400_nocors, __LINE__ );
client.checkPUT( "/test/Foo", "Foo", error400, __LINE__ );
client.checkPUT( "/test/Bar", jsonPut, error404, __LINE__ );
BOOST_CHECK( !foo.getNotified( ));
client.checkPUT( "/test/Foo", jsonPut, response200, __LINE__ );
BOOST_CHECK( foo.getNotified( ));
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(put_event)
{
bool running = true;
bool receivedEmpty = false;
server.handlePUT( "empty", zeroeq::PUTFunc
([&]() { receivedEmpty = true; return true; } ));
([&]( const std::string& received )
{ return jsonPut == received; } ));
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkPUT( "/foo", "", error400_nocors, __LINE__ );
client.checkPUT( "/foo", "Foo", error400, __LINE__ );
client.checkPUT( "/test/Bar", jsonPut, error404, __LINE__ );
client.checkPUT( "/foo", jsonPut, response200, __LINE__ );
client.checkPUT( "/empty", " ", response200, __LINE__ );
BOOST_CHECK( receivedEmpty );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(post)
{
bool running = true;
Foo foo;
server.handleGET( foo );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkPOST( "/test/Foo", jsonPut, error405, __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(largeGet)
{
bool running = true;
Foo foo;
server.handleGET( foo );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
const auto request = std::string( "/test/Foo?" ) + std::string( 4096, 'o' );
client.checkGET( request, _buildResponse( jsonGet ), __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(issue157)
{
bool running = true;
Foo foo;
server.handleGET( foo );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
// Close client before receiving request to provoke #157
{
Client client( server.getURI( ));
const auto request = std::string( "/test/Foo?" ) +
std::string( 4096, 'o' );
client.sendGET( request );
}
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(urlcasesensitivity)
{
bool running = true;
Foo foo;
server.handleGET( foo );
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/TEST/FOO", _buildResponse( jsonGet ), __LINE__ );
client.checkGET( "/test/foo", _buildResponse( jsonGet ), __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(empty_registry)
{
bool running = true;
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/registry", _buildResponse( "{}\n" ), __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(filled_registry)
{
Foo foo;
server.handle( foo );
server.handlePUT( "bla/bar", zeroeq::PUTFunc( [] { return true; } ));
bool running = true;
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/registry",
_buildResponse( "{\n \"bla/bar\" : [ \"PUT\" ],\n"\
" \"test/foo\" : [ \"GET\", \"PUT\" ]\n}\n" ),
__LINE__ );
client.checkGET( "/bla/bar/registry", error404, __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(object_schema)
{
Foo foo;
server.handleGET( foo );
bool running = true;
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/test/foo/schema",
_buildResponse( "{\n '_notified' : 'bool'\n}" ),
__LINE__ );
client.checkGET( "/test/foo/schema/schema", error404, __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(event_schema)
{
const std::string schema = "{ \"value\" : \"boolean\" }";
server.handleGET( "bla/bar", schema,
zeroeq::GETFunc( [] { return std::string( "{ \"value\" : true }"); } ));
server.handlePUT( "bla/foo", schema,
zeroeq::PUTFunc( [] { return true; } ));
bool running = true;
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/bla/bar/schema", _buildResponse( schema ), __LINE__ );
client.checkGET( "/bla/foo/schema", _buildResponse( schema ), __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(event_no_schema)
{
server.handleGET( "bla/bar",
zeroeq::GETFunc( [] { return std::string( "{ \"value\" : true }"); } ));
bool running = true;
std::thread thread( [&] { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/bla/bar/schema", error404, __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(event_wrong_schema)
{
BOOST_CHECK( server.handlePUT( "bla/foo", "schema",
zeroeq::PUTFunc( [] { return true; } )));
BOOST_CHECK_THROW( server.handleGET( "bla/foo", "bad",
zeroeq::GETFunc( [] { return std::string(); } )),
std::runtime_error );
BOOST_CHECK( server.handleGET( "bar", "schema",
zeroeq::GETFunc( [] { return std::string(); } )));
BOOST_CHECK_THROW( server.handlePUT( "bar", "bad",
zeroeq::PUTFunc( [] { return true; } )),
std::runtime_error );
}
BOOST_AUTO_TEST_CASE(event_registry_name)
{
BOOST_CHECK_THROW( server.handleGET( "registry",
zeroeq::GETFunc( [] { return std::string(); } )),
std::runtime_error );
BOOST_CHECK_THROW( server.handlePUT( "registry",
zeroeq::PUTFunc( [] { return true; } )),
std::runtime_error );
BOOST_CHECK( server.handleGET( "foo/registry",
zeroeq::GETFunc( [] { return std::string( "bar" ); } )));
BOOST_CHECK( server.handlePUT( "foo/registry",
zeroeq::PUTFunc( [] { return true; } )));
bool running = true;
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/foo/registry", _buildResponse( "bar" ), __LINE__ );
running = false;
thread.join();
}
BOOST_AUTO_TEST_CASE(event_schema_name)
{
BOOST_CHECK( server.handleGET( "schema", "dummy_schema",
zeroeq::GETFunc( [] { return std::string( "bar" ); } )));
BOOST_CHECK( server.handlePUT( "schema", "dummy_schema",
zeroeq::PUTFunc( [] { return true; } )));
bool running = true;
std::thread thread( [&]() { while( running ) server.receive( 100 ); });
Client client( server.getURI( ));
client.checkGET( "/schema", _buildResponse( "bar" ), __LINE__ );
client.checkGET( "/schema/schema", _buildResponse( "dummy_schema" ),
__LINE__ );
running = false;
thread.join();
}

Definition at line 32 of file server.h.

Constructor & Destructor Documentation

ZEROEQHTTP_API zeroeq::http::Server::Server ( const URI uri,
Receiver shared 
)

Construct a new HTTP server.

To process requests on the incoming port, call receive(). If no hostname is given, the server listens on all interfaces (INADDR_ANY). If no port is given, the server selects a random port. Use getURI() to retrieve the chosen parameters.

Parameters
uriThe server address in the form "[tcp://][hostname][:port]"
shareda shared receiver, see Receiver constructor.
Exceptions
std::runtime_erroron malformed URI or connection issues.

Member Function Documentation

ZEROEQHTTP_API std::string zeroeq::http::Server::getSchema ( const servus::Serializable &  object) const
Returns
the registered schema for the given object, or empty if not registered.

Referenced by handle().

+ Here is the caller graph for this function:

ZEROEQHTTP_API std::string zeroeq::http::Server::getSchema ( const std::string &  event) const

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

ZEROEQHTTP_API SocketDescriptor zeroeq::http::Server::getSocketDescriptor ( ) const

Get the underlying socket descriptor.

Can be used by client code to be notified when new data is available and subsequently call receive. Due to implementation details, the socket notifies on write, not on read.

Returns
the socket descriptor.
Exceptions
std::runtime_errorif the descriptor could not be obtained.
ZEROEQHTTP_API const URI& zeroeq::http::Server::getURI ( ) const

Get the publisher URI.

Contains the used hostname and port, if none where given in the constructor uri.

Returns
the publisher URI.
bool zeroeq::http::Server::handle ( servus::Serializable &  object)
inline

Handle PUT and GET for the given object.

Definition at line 97 of file server.h.

References getSchema(), handleGET(), and handlePUT().

+ Here is the call graph for this function:

ZEROEQHTTP_API bool zeroeq::http::Server::handleGET ( servus::Serializable &  object)

Subscribe a serializable object to serve HTTP GET requests.

Every request will be directly handled during receive() by using toJSON(). To track updates on the object, the serializable's received function is called accordingly.

The subscribed object instance has to be valid until removeGET().

Parameters
objectthe object to serve during receive()
Returns
true if subscription was successful, false otherwise

Referenced by handle().

+ Here is the caller graph for this function:

ZEROEQHTTP_API bool zeroeq::http::Server::handleGET ( const std::string &  event,
const GETFunc func 
)

Subscribe an event to serve HTTP GET requests.

Every request will be directly handled during receive() by calling the registered GET function.

Parameters
eventthe event name to serve during receive()
functhe callback function for serving the GET request
Returns
true if subscription was successful, false otherwise
ZEROEQHTTP_API bool zeroeq::http::Server::handleGET ( const std::string &  event,
const std::string &  schema,
const GETFunc func 
)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Parameters
eventthe event name to serve during receive()
schemadescribes data layout of event
functhe callback function for serving the GET request
ZEROEQHTTP_API bool zeroeq::http::Server::handlePUT ( servus::Serializable &  object)

Subscribe a serializable object to receive updates from HTTP PUT requests.

Every update will be directly applied on the object during receive() using fromJSON(). To track updates on the object, the serializable's updated function is called accordingly.

The subscribed object instance has to be valid until removePUT().

Parameters
objectthe object to update on receive()
Returns
true if subscription was successful, false otherwise

Referenced by handle().

+ Here is the caller graph for this function:

ZEROEQHTTP_API bool zeroeq::http::Server::handlePUT ( const std::string &  event,
const PUTFunc func 
)

Subscribe an event to receive HTTP PUT requests.

Every receival of the event will call the registered callback function.

Parameters
eventthe event name to receive PUT requests for during receive()
functhe callback function for serving the PUT request
Returns
true if subscription was successful, false otherwise
ZEROEQHTTP_API bool zeroeq::http::Server::handlePUT ( const std::string &  event,
const std::string &  schema,
const PUTFunc func 
)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Parameters
eventthe event name to receive PUT requests for during receive()
schemadescribes data layout of event
functhe callback function for serving the PUT request
ZEROEQHTTP_API bool zeroeq::http::Server::handlePUT ( const std::string &  event,
const PUTPayloadFunc func 
)

Subscribe an event to receive HTTP PUT requests with payload.

Every receival of the event will call the registered callback function.

Parameters
eventthe event name to receive PUT requests for during receive()
functhe callback function for serving the PUT request
Returns
true if subscription was successful, false otherwise
ZEROEQHTTP_API bool zeroeq::http::Server::handlePUT ( const std::string &  event,
const std::string &  schema,
const PUTPayloadFunc func 
)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Parameters
eventthe event name to receive PUT requests for during receive()
schemadescribes data layout of event
functhe callback function for serving the PUT request
static ZEROEQHTTP_API std::unique_ptr< Server > zeroeq::http::Server::parse ( int  argc,
const char *const *  argv 
)
static

Create a new Server when requested.

The creation and parameters depend on the following command line parameters:

  • –zeroeq-http-server [host][:port]: Enable the server. The optional parameters configure the web server, running by default on INADDR_ANY and a randomly chosen port
ZEROEQHTTP_API bool zeroeq::http::Server::remove ( const servus::Serializable &  object)

Remove PUT and GET handling for given object.

ZEROEQHTTP_API bool zeroeq::http::Server::remove ( const std::string &  event)

Remove PUT and GET handling for given event.


The documentation for this class was generated from the following file: