Git Product home page Git Product logo

zebra-1's Introduction

# zebra - REST/HTTP to XRAP gateway.

Build Status

## Contents

Overview

Scope and Goals

Ownership and License

Using zebra

Requirements

Building and Installing

Getting started

User information

Usage

Hints to Contributors

This Document

## Overview ### Scope and Goals

zebra is designed to take HTTP requests for the common HTTP methods GET, POST, PUT and DELETE and convert them into the XRAP format. The converted messages will be passed to the request handlers which compose a response in the XRAP format which will be converted back into HTTP. To allow handler to come and go a they please, they need to register at a broker which will forward XRAP messages both ways.

1

## Ownership and License

The contributors are listed in AUTHORS. This project uses the MPL v2 license, see LICENSE.

zebra uses the C4.1 (Collective Code Construction Contract) process for contributions.

zebra uses the CLASS (C Language Style for Scalabilty) guide for code style.

To report an issue, use the zebra issue tracker at github.com.

## Using zebra ### Requirements
  • libmicrohttpd (>= 0.9.38)
  • libzmq (>= 4.1)
  • czmq (>= 3.0.3)
  • libcurl [optional, to run HTTP tests]
### Building and Installing

Here's how to build zebra, including libmicrohttpd, libzmq and czmq:

wget http://ftpmirror.gnu.org/libmicrohttpd/libmicrohttpd-0.9.38.tar.gz
tar -xvf libmicrohttpd-0.9.38.tar.gz
cd libmicrohttpd-0.9.38
./configure && make check
sudo make install
sudo ldconfig
cd ..

git clone git://github.com/zeromq/libzmq.git
cd libzmq
./autogen.sh
./configure && make check
sudo make install
sudo ldconfig
cd ..

git clone git://github.com/zeromq/czmq.git
cd czmq
./autogen.sh
./configure && make check
sudo make install
sudo ldconfig
cd ..

git clone git://github.com/zeromq/zebra.git
cd zebra
./autogen.sh
./configure && make check
sudo make install
sudo ldconfig
cd ..
### Getting started

Checkout the zebra examples.

### User information #### User Agent Required

All HTTP requests MUST include a valid User-Agent header. Requests with no User-Agent header will be rejected. A good User-Agent header value is the name of your application.

#### Rate Limiting

To allow to compensate hardware limitations or to mitigate DOS attacks zebra has a built in rate limiting which allows to limit the number of request within an time interval.

You can check the returned HTTP headers of any HTTP request to see your current rate limit status:

HTTP/1.1 200 OK
Status: 200 OK
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 5
X-RateLimit-Reset: 22

Once you go over the rate limit you will receive an 403 Forbidden error.

#### Conditional requests

XRAP allows responses to return an ETag header as well as a Last-Modified header. You can use the values of these headers to make subsequent requests to those resources using the If-None-Match and If-Modified-Since headers, respectively. If the resource has not changed, the handler might return a 304 Not Modified. Also note: making a conditional request and receiving a 304 response does not count against the Rate Limit which zebra takes automatically care of.

### Usage

This is the API provided by zebra v0.x, in alphabetical order.

#### - Handler for XRAP requests

zeb_handler - Handler for XRAP requests

Please add @discuss section in ../src/zeb_handler.c.

This is the class interface:

//  This API is a draft, and may change without notice.
#ifdef ZEBRA_BUILD_DRAFT_API
//  To work with zeb_handler, use the CZMQ zactor API:                      
//                                                                          
//  Create new zeb_handler instance, passing the broker endpoint:           
//                                                                          
//      zactor_t *handler = zactor_new (zeb_handler, "inproc://broker");    
//                                                                          
//  Destroy zeb_handler instance                                            
//                                                                          
//      zactor_destroy (&handler);                                          
//                                                                          
//  Enable verbose logging of commands and activity:                        
//                                                                          
//      zstr_send (handler, "VERBOSE");                                     
//                                                                          
//  Receive API calls from zeb_handler:                                     
//                                                                          
//      char *command = zstr_recv (handler);                                
//                                                                          
//  Check if an etag is current, MUST signal 0 if true otherwise 1.         
//                                                                          
//    if (streq (command, "CHECK ETAG")) {                                  
//       char *etag = zstr_recv (handler);                                  
//       zsock_signal (handler, 0);                                         
//    }                                                                     
//                                                                          
//  Check if a last modified timestamp is current, MUST signal 0 if true    
//  otherwise 1.                                                            
//                                                                          
//    if (streq (command, "CHECK LAST MODIFIED")) {                         
//       uint64_t last_modified;                                            
//       zsock_brecv (handler, "8", &last_modified);                        
//       zsock_signal (handler, 0);                                         
//    }                                                                     
//                                                                          
//  Handle incomming request from clients. MUST return a response.          
//                                                                          
//  if (streq (command, "HANDLE REQUEST")) {                                
//      zmsg_t *request = zmsg_recv (handle);                               
//      xrap_msg_t *xrequest = xrap_msg_decode (&request);                  
//      zmsg_t *response = xrap_msg_encode (&xrequest);                     
//      zmsg_send (&response, handler);                                     
//  }                                                                       
//                                                                          
//  This is the handler actor which runs in its own thread and polls its two
//  sockets to process incoming messages.                                   
ZEBRA_EXPORT void
    zeb_handler (zsock_t *pipe, void *args);

//  *** Draft method, for development use, may change without warning ***
//  Add a new offer this handler will handle. Returns 0 if successful,       
//  otherwise -1.                                                            
//  The content type parameter is optional and is used to                    
//  filter requests upon their requested (GET) or provided (POST/PUT)        
//  content's type. The content type parameter may be a regex which is       
//  useful for GET offers that can supply resources in different formats.    
//  If the client did request multiple content types then the first match    
//  will be chosen and applied to the request. All other content types are   
//  drooped. If the request's content type does not match it is automatically
//  rejected with the error code 406 (Not acceptable).                       
ZEBRA_EXPORT int
    zeb_handler_add_offer (zactor_t *self, int method, const char *uri, const char *content_type);

//  *** Draft method, for development use, may change without warning ***
//  Self test of this class.
ZEBRA_EXPORT void
    zeb_handler_test (bool verbose);

#endif // ZEBRA_BUILD_DRAFT_API

This is the class self test code:

//  Simple create/destroy test

//  Start a server to test against, and bind to endpoint
zactor_t *server = zactor_new (zeb_broker, "zeb_client_test");
if (verbose)
    zstr_send (server, "VERBOSE");
zstr_sendx (server, "LOAD", "src/zeb_client.cfg", NULL);

//  Create a client and connect it to the server
zeb_client_t *client = zeb_client_new ();
int rc = zeb_client_connect (client, "tcp://127.0.0.1:9999", 1000, "client");
assert (rc == 0);
assert (zeb_client_connected (client) == true);

//  Create a handler
zactor_t *handler = zactor_new (zeb_handler, (void *) "tcp://127.0.0.1:9999");
assert (handler);

//  Offer a service
rc = zeb_handler_add_offer (handler, XRAP_MSG_GET, "/dummy", "application/(xml|json)");
assert (rc == 0);
rc = zeb_handler_add_offer (handler, XRAP_MSG_PUT, "/dummy", "application/(xml|json)");
assert (rc == 0);

//  Provide Rubbish Offering
rc = zeb_handler_add_offer (handler, XRAP_MSG_GET, "/dummy", NULL);
assert (rc == -1);

//  ================================
//  GET Tests

//  1.1 Send Request
xrap_msg_t *xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/xml");
zmsg_t *msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  1.2 Receive request and Echo response
char *command;
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  1.3 Receive Response (is echo)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET);
assert (streq (xrap_msg_resource (xmsg), "/dummy"));
assert (streq (xrap_msg_content_type (xmsg), "application/xml"));
xrap_msg_destroy (&xmsg);
zuuid_t *sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  2.1 Send Request with default Firefox accept header
xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg,
        "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  2.2 Receive request and Echo response
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  2.3 Receive Response (is echo)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET);
assert (streq (xrap_msg_resource (xmsg), "/dummy"));
//  zeb_handler choose the first matching accept type
assert (streq (xrap_msg_content_type (xmsg), "application/xml"));
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  3.1 Send Request without ACCEPT
xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  3.2 Receive Request without ACCEPT
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_ERROR);
assert (xrap_msg_status_code (xmsg) == XRAP_TRAFFIC_NOT_ACCEPTABLE);
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  4.1 Send Request with conditionals (not changed)
xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/json");
xrap_msg_set_if_none_match (xmsg, "MATCH");
xrap_msg_set_if_modified_since (xmsg, 10);
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  4.2 Check etag (match)
char *etag;
zsock_recv (handler, "ss", &command, &etag);
assert (streq (command, "CHECK ETAG"));
zstr_free (&command);
assert (streq (etag, "MATCH"));
zstr_free (&etag);
zsock_signal (handler, 0);

//  4.3 Check last modified (not modified)
uint64_t last_modified;
zsock_recv (handler, "s8", &command, &last_modified);
assert (streq (command, "CHECK LAST MODIFIED"));
zstr_free (&command);
zsock_signal (handler, 0);

//  4.4 Receive Request with conditionals
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET_EMPTY);
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  5.1 Send Request with conditionals (changed)
xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/json");
xrap_msg_set_if_none_match (xmsg, "NONE MATCH");
xrap_msg_set_if_modified_since (xmsg, 20);
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  5.2 Check etag (none match)
zsock_recv (handler, "ss", &command, &etag);
assert (streq (command, "CHECK ETAG"));
zstr_free (&command);
assert (streq (etag, "NONE MATCH"));
zstr_free (&etag);
zsock_signal (handler, 1);

//  5.3 Check last modified (modified)
zsock_recv (handler, "s8", &command, &last_modified);
assert (streq (command, "CHECK LAST MODIFIED"));
zstr_free (&command);
assert (last_modified == 20);
zsock_signal (handler, 1);

//  5.4 Receive request and Echo response
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  5.5 Receive response with conditionals
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET);
assert (streq (xrap_msg_resource (xmsg), "/dummy"));
assert (streq (xrap_msg_content_type (xmsg), "application/json"));
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  ================================
//  PUT Tests

//  1.1 Send Request
xmsg = xrap_msg_new (XRAP_MSG_PUT);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/xml");
xrap_msg_set_content_body (xmsg, "application/xml");
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  1.2 Receive request and Echo response
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  1.3 Receive response (is echo)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_PUT);
assert (streq (xrap_msg_resource (xmsg), "/dummy"));
assert (streq (xrap_msg_content_type (xmsg), "application/xml"));
assert (streq (xrap_msg_content_body (xmsg), "application/xml"));
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  2.1 Send Request with conditionals (update, both)
xmsg = xrap_msg_new (XRAP_MSG_PUT);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/json");
xrap_msg_set_if_match (xmsg, "MATCH");
xrap_msg_set_if_unmodified_since (xmsg, 10);
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  2.2 Check etag (match)
zsock_recv (handler, "ss", &command, &etag);
assert (streq (command, "CHECK ETAG"));
zstr_free (&command);
assert (streq (etag, "MATCH"));
zstr_free (&etag);
zsock_signal (handler, 0);

//  2.3 Check last modified (not modified)
zsock_recv (handler, "s8", &command, &last_modified);
assert (streq (command, "CHECK LAST MODIFIED"));
zstr_free (&command);
zsock_signal (handler, 0);

//  2.4 Receive request and Echo response
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  2.5 Receive response with conditionals (update, both)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_PUT);
assert (streq (xrap_msg_resource (xmsg), "/dummy"));
assert (streq (xrap_msg_content_type (xmsg), "application/json"));
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  3.1 Send Request with conditionals (update, etag)
xmsg = xrap_msg_new (XRAP_MSG_PUT);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/json");
xrap_msg_set_if_match (xmsg, "MATCH");
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  3.2 Check etag (match)
zsock_recv (handler, "ss", &command, &etag);
assert (streq (command, "CHECK ETAG"));
zstr_free (&command);
assert (streq (etag, "MATCH"));
zstr_free (&etag);
zsock_signal (handler, 0);

//  3.3 Receive request and Echo response
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  3.4 Receive response with conditionals (update, etag)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_PUT);
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  4.1 Send Request with conditionals (update, last_modified)
xmsg = xrap_msg_new (XRAP_MSG_PUT);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/json");
xrap_msg_set_if_unmodified_since (xmsg, 10);
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  4.2 Check last modified (not modified)
zsock_recv (handler, "s8", &command, &last_modified);
assert (streq (command, "CHECK LAST MODIFIED"));
zstr_free (&command);
zsock_signal (handler, 0);

//  4.3 Receive request and Echo response
zsock_recv (handler, "sm", &command, &msg);
assert (streq (command, "HANDLE REQUEST"));
zstr_free (&command);
zmsg_send (&msg, handler);

//  4.4 Receive response with conditionals (update, last_modified)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_PUT);
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  5.1 Send Request with conditionals (no update)
xmsg = xrap_msg_new (XRAP_MSG_PUT);
xrap_msg_set_resource (xmsg, "%s", "/dummy");
xrap_msg_set_content_type (xmsg, "application/json");
xrap_msg_set_if_match (xmsg, "NONE MATCH");
xrap_msg_set_if_unmodified_since (xmsg, 20);
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  5.2 Check etag (none match)
zsock_recv (handler, "ss", &command, &etag);
assert (streq (command, "CHECK ETAG"));
zstr_free (&command);
assert (streq (etag, "NONE MATCH"));
zstr_free (&etag);
zsock_signal (handler, 1);

//  5.3 Check last modified (modified)
zsock_recv (handler, "s8", &command, &last_modified);
assert (streq (command, "CHECK LAST MODIFIED"));
zstr_free (&command);
assert (last_modified == 20);
zsock_signal (handler, 1);

//  5.4 Receive Request with conditionals (no update)
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_ERROR);
assert (xrap_msg_status_code (xmsg) == XRAP_TRAFFIC_PRECONDITION_FAILED);
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  ================================
//  Invalid Tests

//  1.1 Send Request
xmsg = xrap_msg_new (XRAP_MSG_GET_EMPTY);
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == XRAP_TRAFFIC_NOT_FOUND);

//  Cleanup
zeb_client_destroy (&client);
zactor_destroy (&handler);

//  Done, shut down
zactor_destroy (&server);
#### - Simple HTTP web server

Simple HTTP webserver implementation using the libmicrohttpd library. Incomming HTTP request are converted to XRAP and send to the broker. Responses from the broker are converted back into HTTP.

Please add @discuss section in ../src/zeb_microhttpd.c.

This is the class interface:

//  Create new zeb_microhttpd actor instance. It will start a HTTP webserver
//  and convert incomming request from HTTP to XRAP.
//
//      zactor_t *microhttpd = zactor_new (zeb_microhttpd, NULL);
//
//  Destroy zeb_microhttpd instance.
//
//      zactor_destroy (&microhttpd);
//
//  Enable verbose logging of commands and activity:
//
//      zstr_send (microhttpd, "VERBOSE");
//      zsock_wait (microhttpd);
//
//  Start zeb_microhttpd actor.
//
//      zstr_sendx (microhttpd, "START", NULL);
//      zsock_wait (microhttpd);
//
//  Stop zeb_microhttpd actor.
//
//      zstr_sendx (microhttpd, "STOP", NULL);
//      zsock_wait (microhttpd);
//
//  Attach the endpoint socket to endpoints, see zsock_attach ().
//
//      zstr_sendx (microhttpd, "ENDPOINT", endpoints, NULL);
//      zsock_wait (microhttpd);
//
//  Set the port on which the http server shall listen for requests.
//  The default port is 8888.
//  Note: The port is passed as string!
//  Note: If the server is already started, the server will be stopped
//        and restarted on the new port.
//
//      zstr_sendx (microhttpd, "PORT", "8888", NULL);
//      zsock_wait (microhttpd);
//
//  Set the ratelimit for HTTP request per user agent. The default limit is 10
//  and the default reset interval is 60000ms.
//  Note: Both limit and reset interval are passed as string!
//  Note: If the server is already started, the behavior is undefined!
//
//       zstr_sendx (microhttpd, "RATELIMIT", "100", "3600000", NULL);
//       zsock_wait (microhttpd);
//
//  All settings can be configured by using a configuration file in the czmq
//  cfg format.
//
//  ------------------------ zeb_microhttpd.cfg -------------------------------
//  | 1 | zeb_microhttpd
//  | 2 |     endpoint = tcp://192.168.178.1:7777  # Broker endpoint
//  | 3 |     port = 8888                          # Webserver port
//  | 4 |     verbose = 0
//  | 5 |     ratelimit
//  | 6 |        limit = 999
//  | 7 |        interval = 3600000
//  ---------------------------------------------------------------------------
//
//       zstr_sendx (microhttpd, "LOAD", filename, NULL);
//
//  This is the zeb_microhttpd constructor as a zactor_fn;
ZEBRA_EXPORT void
    zeb_microhttpd_actor (zsock_t *pipe, void *args);

//  Self test of this actor
ZEBRA_EXPORT void
    zeb_microhttpd_test (bool verbose);

This is the class self test code:

//  Start and configure http server and broker
//  ------------------------------------------
zactor_t *zeb_microhttpd = zactor_new (zeb_microhttpd_actor, NULL);

zstr_send (zeb_microhttpd, "START");
rc = zsock_wait (zeb_microhttpd);             //  Wait until actor started
assert (rc == 0);

zstr_sendx (zeb_microhttpd, "PORT", "8081", NULL);
rc = zsock_wait (zeb_microhttpd);             //  Wait until port is configured
assert (rc == 0);

zstr_sendx (zeb_microhttpd, "RATELIMIT", "3", "10000", NULL);
rc = zsock_wait (zeb_microhttpd);             //  Wait until port is configured
assert (rc == 0);

zstr_sendx (zeb_microhttpd, "ENDPOINT", "inproc://http_broker", NULL);
rc = zsock_wait (zeb_microhttpd);             //  Wait until endpoint configured
assert (rc == 0);

zactor_t *broker = zactor_new (zeb_broker, "broker");

if (verbose)
    zstr_send (broker, "VERBOSE");
zstr_sendx (broker, "BIND", "inproc://http_broker", NULL);

//  Create a XRAP hander and connect it to broker
//  ---------------------------------------------
zeb_client_t *handler = zeb_client_new ();
assert (handler);

//  Connect handler to server
rc = zeb_client_connect (handler, "inproc://http_broker",  1000, "handler");
assert (rc == 0);
assert (zeb_client_connected (handler) == true);

//  Provide GET Offering
rc = zeb_client_set_handler (handler, "GET", "/foo/{[^/]}");
assert (rc == 0);

//  Simple GET example
//  ------------------

//  Send GET Request
zeb_curl_client_t *curl = zeb_curl_client_new ();
zeb_curl_client_send_get (curl, "http://localhost:8081/foo/bar?page=10");

//  Receive Request
zmsg_t *request = zeb_client_recv (handler);
assert (request);
xrap_msg_t *xrap_msg = xrap_msg_decode (&request);
assert (xrap_msg_id (xrap_msg) == XRAP_MSG_GET);
assert (streq ("/foo/bar", xrap_msg_resource (xrap_msg)));
xrap_msg_destroy (&xrap_msg);

//  Send Response
xrap_msg = xrap_msg_new (XRAP_MSG_GET_OK);
xrap_msg_set_status_code (xrap_msg, 200);
xrap_msg_set_content_type (xrap_msg, "text/hello");
xrap_msg_set_content_body (xrap_msg, "Hello World!");
zmsg_t *response = xrap_msg_encode (&xrap_msg);
zeb_client_deliver (handler, zeb_client_sender (handler), &response);
zuuid_t *sender = zeb_client_sender (handler);
zuuid_destroy (&sender);

//  Receive GET Response
zeb_curl_client_verify_response (curl, 200, "Hello World!");
zeb_curl_client_destroy (&curl);

//  Simple GET not found example
//  ----------------------------

//  Send GET Request 2
curl = zeb_curl_client_new ();
zeb_curl_client_send_get (curl, "http://localhost:8081/foo/bar/baz");

//  Receive GET Response 2
zeb_curl_client_verify_response (curl, 404, PAGE_NOT_FOUND);
zeb_curl_client_destroy (&curl);

//  Simple POST example
//  -------------------

//  Provide POST Offering
rc = zeb_client_set_handler (handler, "POST", "/foo/{[^/]}");
assert (rc == 0);

curl = zeb_curl_client_new ();
zeb_curl_client_send_post (curl, "http://localhost:8081/foo/bar", "abc");

//  Receive Request
request = zeb_client_recv (handler);
assert (request);
xrap_msg = xrap_msg_decode (&request);
assert (xrap_msg_id (xrap_msg) == XRAP_MSG_POST);
assert (streq (xrap_msg_content_type (xrap_msg), "text/plain"));
assert (streq (xrap_msg_content_body (xrap_msg), "abc"));
assert (streq ("/foo/bar", xrap_msg_parent (xrap_msg)));
xrap_msg_destroy (&xrap_msg);

//  Send Response
xrap_msg = xrap_msg_new (XRAP_MSG_POST_OK);
xrap_msg_set_status_code (xrap_msg, 201);
xrap_msg_set_location (xrap_msg, "/foo/bar");
xrap_msg_set_etag (xrap_msg, "a3fsd3");
xrap_msg_set_date_modified (xrap_msg, 0);
xrap_msg_set_content_type (xrap_msg, "text/hello");
xrap_msg_set_content_body (xrap_msg, "Hello World!");
response = xrap_msg_encode (&xrap_msg);
zeb_client_deliver (handler, zeb_client_sender (handler), &response);
sender = zeb_client_sender (handler);
zuuid_destroy (&sender);

//  Give response time to arrive
zclock_sleep (250);

zeb_curl_client_verify_response (curl, 201, "Hello World!");
zeb_curl_client_destroy (&curl);

//  Simple PUT example
//  ------------------

//  Provide PUT Offering
rc = zeb_client_set_handler (handler, "PUT", "/foo/{[^/]}");
assert (rc == 0);

curl = zeb_curl_client_new ();
zeb_curl_client_send_put (curl, "http://localhost:8081/foo/bar", "abc");

//  Receive Request
request = zeb_client_recv (handler);
assert (request);
xrap_msg = xrap_msg_decode (&request);
assert (xrap_msg_id (xrap_msg) == XRAP_MSG_PUT);
assert (streq (xrap_msg_content_type (xrap_msg), "text/plain"));
assert (streq (xrap_msg_content_body (xrap_msg), "abc"));
assert (streq ("/foo/bar", xrap_msg_resource (xrap_msg)));
xrap_msg_destroy (&xrap_msg);

//  Send Response
xrap_msg = xrap_msg_new (XRAP_MSG_POST_OK);
xrap_msg_set_status_code (xrap_msg, 200);
xrap_msg_set_location (xrap_msg, "/foo/bar");
xrap_msg_set_etag (xrap_msg, "a3fsd3");
xrap_msg_set_date_modified (xrap_msg, 0);
response = xrap_msg_encode (&xrap_msg);
zeb_client_deliver (handler, zeb_client_sender (handler), &response);
sender = zeb_client_sender (handler);
zuuid_destroy (&sender);

//  Give response time to arrive
zclock_sleep (250);

zeb_curl_client_verify_response (curl, 200, NULL);
zeb_curl_client_destroy (&curl);

//  Cleanup
//  -------
zeb_client_destroy (&handler);
zactor_destroy (&broker);

zstr_send (zeb_microhttpd, "STOP");
rc = zsock_wait (zeb_microhttpd);             //  Wait until actor stopped
assert (rc == 0);

zactor_destroy (&zeb_microhttpd);
#### - zebra service broker

The zeb_broker implements the zproto server. This broker connects client requests to handler offers.

Please add @discuss section in ../src/zeb_broker.c.

This is the class interface:

//  To work with zeb_broker, use the CZMQ zactor API:
//
//  Create new zeb_broker instance, passing logging prefix:
//
//      zactor_t *zeb_broker = zactor_new (zeb_broker, "myname");
//
//  Destroy zeb_broker instance
//
//      zactor_destroy (&zeb_broker);
//
//  Enable verbose logging of commands and activity:
//
//      zstr_send (zeb_broker, "VERBOSE");
//
//  Bind zeb_broker to specified endpoint. TCP endpoints may specify
//  the port number as "*" to aquire an ephemeral port:
//
//      zstr_sendx (zeb_broker, "BIND", endpoint, NULL);
//
//  Return assigned port number, specifically when BIND was done using an
//  an ephemeral port:
//
//      zstr_sendx (zeb_broker, "PORT", NULL);
//      char *command, *port_str;
//      zstr_recvx (zeb_broker, &command, &port_str, NULL);
//      assert (streq (command, "PORT"));
//
//  Specify configuration file to load, overwriting any previous loaded
//  configuration file or options:
//
//      zstr_sendx (zeb_broker, "LOAD", filename, NULL);
//
//  Set configuration path value:
//
//      zstr_sendx (zeb_broker, "SET", path, value, NULL);
//
//  Save configuration data to config file on disk:
//
//      zstr_sendx (zeb_broker, "SAVE", filename, NULL);
//
//  Send zmsg_t instance to zeb_broker:
//
//      zactor_send (zeb_broker, &msg);
//
//  Receive zmsg_t instance from zeb_broker:
//
//      zmsg_t *msg = zactor_recv (zeb_broker);
//
//  This is the zeb_broker constructor as a zactor_fn:
//
ZEBRA_EXPORT void
    zeb_broker (zsock_t *pipe, void *args);

//  Self test of this class
ZEBRA_EXPORT void
    zeb_broker_test (bool verbose);

This is the class self test code:

zactor_t *server = zactor_new (zeb_broker, "broker");
if (verbose)
    zstr_send (server, "VERBOSE");

zstr_sendx (server, "BIND", "tcp://127.0.0.1:9999", NULL);

zsock_t* client = zsock_new_dealer (">tcp://127.0.0.1:9999");
zsock_t* worker = zsock_new_dealer (">tcp://127.0.0.1:9999");
assert (client);
assert (worker);

xrap_traffic_t *traffic = xrap_traffic_new ();

//  Invalid Command
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_XRAP_OFFER);
xrap_traffic_send (traffic, client);
xrap_traffic_recv (traffic, client);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_ERROR);
assert (xrap_traffic_status_code (traffic) == XRAP_TRAFFIC_COMMAND_INVALID);

//  Open Connections for client & worker
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_CONNECTION_OPEN);
xrap_traffic_send (traffic, client);
xrap_traffic_recv (traffic, client);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_OK);

xrap_traffic_set_id (traffic, XRAP_TRAFFIC_CONNECTION_OPEN);
xrap_traffic_send (traffic, worker);
xrap_traffic_recv (traffic, worker);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_OK);

//  Provide Rubish Offering
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_XRAP_OFFER);
xrap_traffic_set_route (traffic, "///");
xrap_traffic_set_method (traffic, "GET");
xrap_traffic_send (traffic, worker);
xrap_traffic_recv (traffic, worker);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_FAIL);
assert (xrap_traffic_status_code (traffic) == XRAP_TRAFFIC_CONFLICT);

//  Provide Offering
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_XRAP_OFFER);
xrap_traffic_set_route (traffic, "/foo/{[^/]}");
xrap_traffic_set_method (traffic, "GET");
xrap_traffic_send (traffic, worker);
xrap_traffic_recv (traffic, worker);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_OK);

//  Send Request
xrap_msg_t *xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/foo/bar");
zmsg_t *msg = xrap_msg_encode (&xmsg);
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_XRAP_SEND);
xrap_traffic_set_content (traffic, &msg);
xrap_traffic_send (traffic, client);
xrap_traffic_recv (traffic, client);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_OK);

//  Receive Request
xrap_traffic_recv (traffic, worker);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_XRAP_DELIVER);
msg = zmsg_dup (xrap_traffic_content (traffic));
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET);
assert (streq ("/foo/bar", xrap_msg_resource (xmsg)));
xrap_msg_destroy (&xmsg);

//  Send Response
xmsg = xrap_msg_new (XRAP_MSG_GET_OK);
xrap_msg_set_status_code (xmsg, 200);
xrap_msg_set_content_type (xmsg, "text/hello");
xrap_msg_set_content_body (xmsg, "Hello World!");
msg = xrap_msg_encode (&xmsg);
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_XRAP_DELIVER);
xrap_traffic_set_content (traffic, &msg);
xrap_traffic_send (traffic, worker);

//  Receive Response
xrap_traffic_recv (traffic, client);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_XRAP_DELIVER);
msg = zmsg_dup (xrap_traffic_content (traffic));
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET_OK);
assert (xrap_msg_status_code (xmsg) == 200);
assert (streq ("text/hello", xrap_msg_content_type (xmsg)));
assert (streq ("Hello World!", xrap_msg_content_body (xmsg)));
xrap_msg_destroy (&xmsg);

//  Send Request 2
xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/fou/baz");
msg = xrap_msg_encode (&xmsg);
xrap_traffic_set_id (traffic, XRAP_TRAFFIC_XRAP_SEND);
xrap_traffic_set_content (traffic, &msg);
xrap_traffic_send (traffic, client);
xrap_traffic_recv (traffic, client);
assert (xrap_traffic_id (traffic) == XRAP_TRAFFIC_FAIL);
assert (xrap_traffic_status_code (traffic) == XRAP_TRAFFIC_NOT_FOUND);

xrap_traffic_destroy (&traffic);

//  Finished, we can clean up
zsock_destroy (&client);
zsock_destroy (&worker);
zactor_destroy (&server);
#### - Broker client

Client implementation to communicate with the broker. This implementation is used by both clients (i.e. zeb_microhttpd) and the handlers.

Please add @discuss section in ../src/zeb_client.c.

This is the class interface:

//  This API is a draft, and may change without notice.
#ifdef ZEBRA_BUILD_DRAFT_API
//  *** Draft method, for development use, may change without warning ***
//  Create a new zeb_client, return the reference if successful,   
//  or NULL if construction failed due to lack of available memory.
ZEBRA_EXPORT zeb_client_t *
    zeb_client_new (void);

//  *** Draft method, for development use, may change without warning ***
//  Destroy the zeb_client and free all memory used by the object.
ZEBRA_EXPORT void
    zeb_client_destroy (zeb_client_t **self_p);

//  *** Draft method, for development use, may change without warning ***
//  Return actor, when caller wants to work with multiple actors and/or
//  input sockets asynchronously.                                      
ZEBRA_EXPORT zactor_t *
    zeb_client_actor (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return message pipe for asynchronous message I/O. In the high-volume case,
//  we send methods and get replies to the actor, in a synchronous manner, and
//  we send/recv high volume message data to a second pipe, the msgpipe. In   
//  the low-volume case we can do everything over the actor pipe, if traffic  
//  is never ambiguous.                                                       
ZEBRA_EXPORT zsock_t *
    zeb_client_msgpipe (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return true if client is currently connected, else false. Note that the   
//  client will automatically re-connect if the server dies and restarts after
//  a successful first connection.                                            
ZEBRA_EXPORT bool
    zeb_client_connected (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Connect to server endpoint, with specified timeout in msecs (zero means wait    
//  forever). Constructor succeeds if connection is successful. The caller may      
//  specify its address.                                                            
//  Returns >= 0 if successful, -1 if interrupted.                                  
ZEBRA_EXPORT int
    zeb_client_connect (zeb_client_t *self, const char *endpoint, uint32_t timeout, const char *address);

//  *** Draft method, for development use, may change without warning ***
//  Offer to handle particular XRAP requests, where the route matches request's     
//  resource.                                                                       
//  Returns >= 0 if successful, -1 if interrupted.                                  
ZEBRA_EXPORT int
    zeb_client_set_handler (zeb_client_t *self, const char *method, const char *route);

//  *** Draft method, for development use, may change without warning ***
//  No explanation                                                                  
//  Returns >= 0 if successful, -1 if interrupted.                                  
ZEBRA_EXPORT int
    zeb_client_request (zeb_client_t *self, uint32_t timeout, zmsg_t **content);

//  *** Draft method, for development use, may change without warning ***
//  Send XRAP DELIVER message to server, takes ownership of message
//  and destroys message when done sending it.                     
ZEBRA_EXPORT int
    zeb_client_deliver (zeb_client_t *self, zuuid_t *sender, zmsg_t **content);

//  *** Draft method, for development use, may change without warning ***
//  Receive message from server; caller destroys message when done
ZEBRA_EXPORT zmsg_t *
    zeb_client_recv (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return last received command. Can be one of these values:
//      "XRAP DELIVER"                                       
ZEBRA_EXPORT const char *
    zeb_client_command (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return last received status
ZEBRA_EXPORT int
    zeb_client_status (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return last received reason
ZEBRA_EXPORT const char *
    zeb_client_reason (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return last received sender
ZEBRA_EXPORT zuuid_t *
    zeb_client_sender (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Return last received content
ZEBRA_EXPORT zmsg_t *
    zeb_client_content (zeb_client_t *self);

//  *** Draft method, for development use, may change without warning ***
//  Enable verbose tracing (animation) of state machine activity.
ZEBRA_EXPORT void
    zeb_client_set_verbose (zeb_client_t *self, bool verbose);

//  *** Draft method, for development use, may change without warning ***
//  Self test of this class.
ZEBRA_EXPORT void
    zeb_client_test (bool verbose);

#endif // ZEBRA_BUILD_DRAFT_API

This is the class self test code:

//  Start a server to test against, and bind to endpoint
zactor_t *server = zactor_new (zeb_broker, "zeb_client_test");
if (verbose)
    zstr_send (server, "VERBOSE");
zstr_sendx (server, "LOAD", "src/zeb_client.cfg", NULL);

//  Create clients for testing
zeb_client_t *client = zeb_client_new ();
zeb_client_t *handler = zeb_client_new ();
assert (client);
assert (handler);

//  Enable verbose logging
zeb_client_set_verbose (client, verbose);

//  Connect clients to server
int rc = zeb_client_connect (client, "tcp://127.0.0.1:9999", 1000, "client");
assert (rc == 0);
assert (zeb_client_connected (client) == true);

rc = zeb_client_connect (handler, "tcp://127.0.0.1:9999", 1000, "handler");
assert (rc == 0);
assert (zeb_client_connected (handler) == true);

//  Provide Rubbish Offering
rc = zeb_client_set_handler (handler, "GET", "///");
assert (rc != 0);
assert (zeb_client_status (handler) == XRAP_TRAFFIC_CONFLICT);

//  Provide Offering
rc = zeb_client_set_handler (handler, "GET", "/foo/{[^/]}");
assert (rc == 0);

//  Send Request
xrap_msg_t *xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/foo/bar");
zmsg_t *msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == 0);

//  Receive Request
msg = zeb_client_recv (handler);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET);
assert (streq ("/foo/bar", xrap_msg_resource (xmsg)));
xrap_msg_destroy (&xmsg);

//  Send Response
xmsg = xrap_msg_new (XRAP_MSG_GET_OK);
xrap_msg_set_status_code (xmsg, 200);
xrap_msg_set_content_type (xmsg, "text/hello");
xrap_msg_set_content_body (xmsg, "Hello World!");
msg = xrap_msg_encode (&xmsg);
zeb_client_deliver (handler, handler->sender, &msg);
zuuid_t *sender = zeb_client_sender (handler);
zuuid_destroy (&sender);

//  Receive Response
msg = zeb_client_recv (client);
xmsg = xrap_msg_decode (&msg);
assert (xrap_msg_id (xmsg) == XRAP_MSG_GET_OK);
assert (xrap_msg_status_code (xmsg) == 200);
assert (streq ("text/hello", xrap_msg_content_type (xmsg)));
assert (streq ("Hello World!", xrap_msg_content_body (xmsg)));
xrap_msg_destroy (&xmsg);
sender = zeb_client_sender (client);
zuuid_destroy (&sender);

//  Send Request 2
xmsg = xrap_msg_new (XRAP_MSG_GET);
xrap_msg_set_resource (xmsg, "%s", "/fou/baz");
msg = xrap_msg_encode (&xmsg);
rc = zeb_client_request (client, 0, &msg);
assert (rc == XRAP_TRAFFIC_NOT_FOUND);

zeb_client_destroy (&client);
zeb_client_destroy (&handler);

//  Done, shut down
zactor_destroy (&server);
### Hints to Contributors

Read the CLASS style guide please, and write your code to make it indistinguishable from the rest of the code in the library. That is the only real criteria for good style: it's invisible.

Do read your code after you write it and ask, "Can I make this simpler?" We do use a nice minimalist and yet readable style. Learn it, adopt it, use it.

Before opening a pull request read our contribution guidelines. Thanks!

### This Document

This documentation was generated from zebra/README.txt using Gitdown

zebra-1's People

Contributors

bluca avatar c-rack avatar gotcha avatar sappo avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.