rest server wip
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
NADAL Jean-Baptiste
2020-02-18 17:56:15 +01:00
parent cf9decf7b8
commit c7b9e005e8
12 changed files with 681 additions and 83 deletions

View File

@@ -77,7 +77,7 @@ typedef struct restd_http_s restd_http_t;
#define RESTD_HOOK_ON_BODY (1 << 4) /*!< call on every time body data received */
#define RESTD_HOOK_ON_REQUEST (1 << 5) /*!< call with complete request */
#define RESTD_HOOK_ON_CLOSE (1 << 6) /*!< call right before closing or next request */
#if 0
enum restd_http_request_status_e
{
RESTD_HTTP_REQ_INIT = 0, /*!< initial state */
@@ -87,7 +87,7 @@ enum restd_http_request_status_e
RESTD_HTTP_ERROR, /*!< unrecoverable error found. */
};
#endif
/*----------------------------------------------------------------------------*\
| PUBLIC FUNCTIONS |
\*----------------------------------------------------------------------------*/

View File

@@ -32,6 +32,7 @@ file(
devices/shutter.c
devices/sprinkler.c
rest/restd.c
rest/http_resp.c
rest/rest_devices_handlers.c
rest/rest_server.c
)
@@ -62,6 +63,7 @@ endif()
# Tests
if(DOMO_BUILD_TEST)
add_definitions("-fprofile-arcs -ftest-coverage")
add_definitions (-g -DBUILD_DEBUG)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov --coverage")
add_executable (test_device tests/test_main.c ${source_files})

68
src/rest/http_resp.c Normal file
View File

@@ -0,0 +1,68 @@
/*!
* http_resp.c
*
* Copyright (c) 2015-2020, NADAL Jean-Baptiste. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* @Author: NADAL Jean-Baptiste
* @Date: 07/02/2020
*
*/
/*------------------------------- INCLUDES ----------------------------------*/
#include <stdlib.h>
#include "http_resp.h"
#include "macro.h"
/*--------------------------------------------------------------------------*/
http_resp_t *http_resp_new(void)
{
http_resp_t *resp = NEW_OBJECT(http_resp_t);
if (resp == NULL)
{
return NULL;
}
resp->ev_req = NULL;
resp->ev_uri = NULL;
//resp->path_params = 0;
resp->head_params = NULL;
//resp->post_params = {0};
resp->post_param_parsed = false;
resp->str_body = NULL;
resp->resp_headers = NULL;
resp->resp_buf = NULL;
resp->resp_code = HTTP_OK;
DEBUG("Created an http response object.");
return resp;
}
/*--------------------------------------------------------------------------*/
void http_resp_free(http_resp_t *resp)
{
if (resp == NULL)
{
return;
}
}

94
src/rest/http_resp.h Normal file
View File

@@ -0,0 +1,94 @@
/*!
* http_resp.h
*
* Copyright (c) 2015-2020, NADAL Jean-Baptiste. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* @Author: NADAL Jean-Baptiste
* @Date: 07/02/2020
*
*/
#ifndef _HTTP_RESP_H
#define _HTTP_RESP_H
/*------------------------------- INCLUDES ----------------------------------*/
#include <stdbool.h>
#include <evhttp.h>
typedef struct http_resp_s http_resp_t;
/**
* Server info container.
*/
struct http_resp_s
{
struct evhttp_request *ev_req;
const struct evhttp_uri *ev_uri;
struct evkeyvalq path_params;
struct evkeyvalq *head_params;
struct evkeyvalq post_params;
bool post_param_parsed;
char *str_body;
struct evkeyvalq *resp_headers;
struct evbuffer *resp_buf;
int resp_code;
};
extern http_resp_t *http_resp_new(void);
extern void http_resp_free(http_resp_t *resp);
#if 0
EvHttpResp(struct evhttp_request *req) throw(EvHttpRespRTEXCP);
~EvHttpResp();
std::string GetRequestUri();
std::string GetUriHost(); //#TODO add const of this
/// It will return -1 if no port set
int GetUriPort();
std::string GetUriPath();
std::string GetUriQuery();
/// Useless to get from a request url, fragment is only for browser to locate sth.
std::string GetUriFragment();
std::string GetHeadParam(std::string const &strKey);
std::string GetPathParam(std::string const &strKey);
std::string GetPostParam(std::string const &strKey);
std::string GetPostMsg();
bool AddRespHeadParam(std::string const &key, std::string const &val);
void AddRespHeaders(HttpHeaders& headers);
bool AddRespString(std::string const &str);
/// This will cause data memcpy, if not so, user have to make sure data lifetime last until be read
/// #TODO: This func is dangerious, NOT RECOMMEND to use, for if len is larger than actual, cause overflow
bool AddRespBuf(void const *data, std::size_t len);
bool AddRespFile(std::string const &fileName);
void SetRespCode(int code);
/// Make sure code and all response body has finished set
void SendResponse();
void QuickResponse(int code, std::string const &strBody);
void SimpleResponse(int code, HttpHeaders &headers, std::string const &strBody);
/// If strMsg is empty, libevent will use default error code message instead
void RespError(int nCode, std::string const &strMsg);
#endif
#endif /* _HTTP_RESP_H */

View File

@@ -31,7 +31,7 @@
#include "devices/devices_manager.h"
#include "domo.h"
#include "rest_devices_handlers.h"
//#include "rest_devices_handlers.h"
// Code Description
// 204 Success. No content.

View File

@@ -28,7 +28,7 @@
/*------------------------------- INCLUDES ----------------------------------*/
#include "rest_devices_handlers.h"
//#include "rest_devices_handlers.h"
#include "rest_server.h"

View File

@@ -28,7 +28,7 @@
/*------------------------------- INCLUDES ----------------------------------*/
#include <restd.h>
#include <rest/restd.h>
extern int setup_rest_server(restd_server_t *rest_server, const char *port, const char *root_path, void *dm);

View File

@@ -35,12 +35,25 @@
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <evhttp.h>
#include <event2/http.h>
#include <event2/listener.h>
#ifdef __linux__
#include <sys/eventfd.h>
#else
#include <sys/event.h>
#endif
#include "macro.h"
#include "restd.h"
struct mimetype_s
{
const char *extn;
const char *mime;
};
/*
* Local variables.
*/
@@ -51,6 +64,77 @@ static bool initialized = false;
*/
int _restd_log_level = RESTD_LOG_WARN;
/*--------------------------------------------------------------------------*/
static const struct mimetype_s g_mime_types[] = {
{"txt", "text/plain"},
{"log", "text/plain"},
{"js", "text/javascript"},
{"css", "text/css"},
{"htm", "text/html"},
{"html", "text/html"},
{"diff", "text/x-patch"},
{"patch", "text/x-patch"},
{"c", "text/x-csrc"},
{"h", "text/x-chdr"},
{"o", "text/x-object"},
{"ko", "text/x-object"},
{"bmp", "image/bmp"},
{"gif", "image/gif"},
{"png", "image/png"},
{"jpg", "image/jpeg"},
{"jpeg", "image/jpeg"},
{"svg", "image/svg+xml"},
{"json", "application/json"},
{"jsonp", "application/javascript"},
{"zip", "application/zip"},
{"pdf", "application/pdf"},
{"xml", "application/xml"},
{"xsl", "application/xml"},
{"doc", "application/msword"},
{"ppt", "application/vnd.ms-powerpoint"},
{"xls", "application/vnd.ms-excel"},
{"odt", "application/vnd.oasis.opendocument.text"},
{"odp", "application/vnd.oasis.opendocument.presentation"},
{"pl", "application/x-perl"},
{"sh", "application/x-shellscript"},
{"php", "application/x-php"},
{"deb", "application/x-deb"},
{"iso", "application/x-cd-image"},
{"tar.gz", "application/x-compressed-tar"},
{"tgz", "application/x-compressed-tar"},
{"gz", "application/x-gzip"},
{"tar.bz2", "application/x-bzip-compressed-tar"},
{"tbz", "application/x-bzip-compressed-tar"},
{"bz2", "application/x-bzip"},
{"tar", "application/x-tar"},
{"rar", "application/x-rar-compressed"},
{"mp3", "audio/mpeg"},
{"ogg", "audio/x-vorbis+ogg"},
{"wav", "audio/x-wav"},
{"mpg", "video/mpeg"},
{"mpeg", "video/mpeg"},
{"avi", "video/x-msvideo"},
{"README", "text/plain"},
{"log", "text/plain"},
{"cfg", "text/plain"},
{"conf", "text/plain"},
{"pac", "application/x-ns-proxy-autoconfig"},
{"wpad.dat", "application/x-ns-proxy-autoconfig"},
{"appcache", "text/cache-manifest"},
{"manifest", "text/cache-manifest"},
{NULL, NULL}};
/*--------------------------------------------------------------------------*/
/**
* Server option names and default values.
*/
@@ -85,8 +169,11 @@ static int set_undefined_options(restd_server_t *server);
char *restd_server_get_option(restd_server_t *server, const char *key);
int restd_server_get_option_int(restd_server_t *server, const char *key);
static void close_server(restd_server_t *server);
static void *server_loop(void *instance);
static void libevent_log_cb(int severity, const char *msg);
static int notify_loopexit(restd_server_t *server);
static void notify_cb(struct bufferevent *buffer, void *userdata);
void rest_request_cb(struct evhttp_request *req, void *arg);
/*--------------------------- PUBLIC FUNCTIONS -------------------------------*/
@@ -160,16 +247,16 @@ void restd_server_free(restd_server_t *server)
close_server(server);
}
if (server->evbase)
{
event_base_free(server->evbase);
}
if (server->evhttp)
{
evhttp_free(server->evhttp);
}
if (server->evbase)
{
event_base_free(server->evbase);
}
if (server->options)
{
server->options->free(server->options);
@@ -184,8 +271,6 @@ void restd_server_free(restd_server_t *server)
restd_hook_t *hook;
while ((hook = tbl->popfirst(tbl, NULL)))
{
if (hook->method)
free(hook->method);
if (hook->path)
free(hook->path);
free(hook);
@@ -283,7 +368,8 @@ int restd_server_start(restd_server_t *server)
return -2;
}
#if 0
evhttp_set_gencb(server->evhttp, rest_request_cb, server);
ret = evhttp_bind_socket(server->evhttp, addr, port);
if (ret != 0)
@@ -291,8 +377,41 @@ int restd_server_start(restd_server_t *server)
ERROR("Http bind server addr:%s & port:%d failed!\n", addr, port);
return -3;
}
// Listen
INFO("Listening on %s:%d", addr, port);
// Create a eventfd for notification channel.
#ifdef __linux__
int notifyfd = eventfd(0, 0);
#else
int notifyfd = kqueue();
#endif
return 0;
server->notify_buffer = bufferevent_socket_new(server->evbase, notifyfd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(server->notify_buffer, NULL, notify_cb, NULL, server);
int exitstatus = 0;
if (restd_server_get_option_int(server, "server.thread"))
{
DEBUG("Launching server as a thread.\n");
server->thread = NEW_OBJECT(pthread_t);
pthread_create(server->thread, NULL, &server_loop, (void *)server);
//pthread_detach(server->thread);
}
else
{
int *retval = server_loop(server);
exitstatus = *retval;
free(retval);
close_server(server);
if (restd_server_get_option_int(server, "server.free_on_stop"))
{
restd_server_free(server);
}
}
return exitstatus;
}
/*--------------------------------------------------------------------------*/
@@ -315,12 +434,12 @@ void restd_server_set_option(restd_server_t *server, const char *key, const char
/*--------------------------------------------------------------------------*/
void restd_server_register_hook_on_path(restd_server_t *server, const char *method, const char *path,
void restd_server_register_hook_on_path(restd_server_t *server, enum evhttp_cmd_type method, const char *path,
restd_callback cb, void *userdata)
{
restd_hook_t hook;
bzero((void *)&hook, sizeof(restd_hook_t));
hook.method = (method) ? strdup(method) : NULL;
hook.method = method;
hook.path = (path) ? strdup(path) : NULL;
hook.cb = cb;
hook.userdata = userdata;
@@ -328,6 +447,27 @@ void restd_server_register_hook_on_path(restd_server_t *server, const char *meth
server->hooks->addlast(server->hooks, (void *)&hook, sizeof(restd_hook_t));
}
/*--------------------------------------------------------------------------*/
void restd_http_response(struct evhttp_request *req, int code, const char *contenttype, const char *data)
{
struct evbuffer *resp_buf;
struct evkeyvalq *resp_headers;
resp_buf = evhttp_request_get_output_buffer(req);
resp_headers = evhttp_request_get_output_headers(req);
if (data != NULL)
{
evbuffer_add_printf(resp_buf, "%s", data);
}
evhttp_add_header(resp_headers, "Content-Type", contenttype);
evhttp_send_reply(req, code, NULL ,resp_buf);
}
/*--------------------------- LOCAL FUNCTIONS -------------------------------*/
/*--------------------------------------------------------------------------*/
@@ -398,6 +538,21 @@ static void close_server(restd_server_t *server)
/*--------------------------------------------------------------------------*/
static void *server_loop(void *instance)
{
restd_server_t *server = (restd_server_t *)instance;
int *retval = NEW_OBJECT(int);
DEBUG("Loop start\n");
event_base_loop(server->evbase, 0);
DEBUG("Loop finished\n");
*retval = (event_base_got_break(server->evbase)) ? -1 : 0;
return retval;
}
/*--------------------------------------------------------------------------*/
static void libevent_log_cb(int severity, const char *msg)
{
switch (severity)
@@ -435,3 +590,271 @@ static int notify_loopexit(restd_server_t *server)
uint64_t x = 0;
return bufferevent_write(server->notify_buffer, &x, sizeof(uint64_t));
}
/*--------------------------------------------------------------------------*/
static void notify_cb(struct bufferevent *buffer, void *userdata)
{
restd_server_t *server = (restd_server_t *)userdata;
event_base_loopexit(server->evbase, NULL);
DEBUG("Existing loop.");
}
/*--------------------------------------------------------------------------*/
static const char *file_mime_lookup(const char *path)
{
const struct mimetype_s *m = &g_mime_types[0];
const char *e;
while (m->extn)
{
e = &path[strlen(path) - 1];
while (e >= path)
{
if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
return m->mime;
e--;
}
m++;
}
return "application/octet-stream";
}
/*--------------------------------------------------------------------------*/
static bool contain(const char *src, const char *dest, int len)
{
int len_src, len_dest;
int i = 0;
len_src = strlen(src);
if (len_src < len)
return false;
len_dest = strlen(dest);
if (len_dest < len)
return false;
while (i < len)
{
if (src[i] != dest[i])
return false;
i++;
}
return true;
}
/*--------------------------------------------------------------------------*/
void rest_request_cb(struct evhttp_request *req, void *arg)
{
const char *cmdtype;
restd_server_t *server = (restd_server_t *)arg;
printf("request.\n");
switch (evhttp_request_get_command(req))
{
case EVHTTP_REQ_GET:
cmdtype = "GET";
break;
case EVHTTP_REQ_POST:
cmdtype = "POST";
break;
case EVHTTP_REQ_HEAD:
cmdtype = "HEAD";
break;
case EVHTTP_REQ_PUT:
cmdtype = "PUT";
break;
case EVHTTP_REQ_DELETE:
cmdtype = "DELETE";
break;
case EVHTTP_REQ_OPTIONS:
cmdtype = "OPTIONS";
break;
case EVHTTP_REQ_TRACE:
cmdtype = "TRACE";
break;
case EVHTTP_REQ_CONNECT:
cmdtype = "CONNECT";
break;
case EVHTTP_REQ_PATCH:
cmdtype = "PATCH";
break;
default:
cmdtype = "unknown";
break;
}
printf("Received a %s request for %s\nHeaders:\n",
cmdtype, evhttp_request_get_uri(req));
qlist_t *hooks = server->hooks;
//int reason = RESTD_ERROR_PATH_NOT_FOUND;
qlist_obj_t obj;
bzero((void *)&obj, sizeof(qlist_obj_t));
while (hooks->getnext(hooks, &obj, false) == true)
{
restd_hook_t *hook = (restd_hook_t *)obj.data;
if (hook->cb)
{
const char *request_path = evhttp_request_get_uri(req);
printf("==== call_hooks: method: %d - %d \n", hook->method, evhttp_request_get_command(req));
printf("==== call_hooks: path: %s - %s\n", hook->path, request_path);
printf("==== HOOK FOUND !!!!\n");
if (hook->method != evhttp_request_get_command(req))
{
printf("==== Hook found but method failed -> next.\n");
//reason = RESTD_ERROR_METHOD_NOT_ALLOWED;
continue;
}
if ((hook->path != NULL) && (request_path != NULL))
{
int i = 0;
int pos = -1;
while (hook->path[i])
{
if (hook->path[i] == ':')
pos = i;
i++;
}
if (pos != -1 && contain(hook->path, request_path, pos))
{
const char *buffer = &request_path[pos];
// printf("buffer: <%s>\n", buffer);
// TODO conn->id = atoi(buffer);
hook->cb(req, hook->userdata);
return;
}
else
{
int rett = strcmp(hook->path, request_path);
if (rett == 0)
{
hook->cb(req, hook->userdata);
return;
}
}
}
}
}
evhttp_send_reply(req, 200, "OK", NULL);
}
#if 0
int restd_rest_handler(short event, restd_conn_t *conn)
{
if (event & RESTD_EVENT_INIT)
{
DEBUG("==> HTTP INIT");
restd_http_t *http = http_new(conn->out);
if (http == NULL)
return RESTD_CLOSE;
restd_conn_set_extra(conn, http, http_free_cb);
return RESTD_OK;
}
else if (event & RESTD_EVENT_CLOSE)
{
DEBUG("==> HTTP CLOSE=%x (TIMEOUT=%d, SHUTDOWN=%d)",
event, event & RESTD_EVENT_TIMEOUT, event & RESTD_EVENT_SHUTDOWN);
return RESTD_OK;
}
else if ((event & RESTD_EVENT_READ) || (event & RESTD_EVENT_WRITE))
{
restd_http_t *http = (restd_http_t *)restd_conn_get_extra(conn);
int status = http_parser(http, conn->in);
if (conn->method == NULL && http->request.method != NULL)
{
restd_conn_set_method(conn, http->request.method);
}
DEBUG("==> HTTP READ || HTTP WRITE");
int reason = RESTD_ERROR_PATH_NOT_FOUND;
DEBUG("********restd_rest_handler: event 0x%x", event);
char *root_path;
qlist_t *hooks = conn->server->hooks;
qlist_obj_t obj;
bzero((void *)&obj, sizeof(qlist_obj_t));
while (hooks->getnext(hooks, &obj, false) == true)
{
restd_hook_t *hook = (restd_hook_t *)obj.data;
if (hook->cb)
{
printf("==== call_hooks: method: %s - %s \n", hook->method, conn->method);
printf("==== call_hooks: path: %s - %s\n", hook->path, http->request.path);
printf("==== HOOK FOUND !!!!\n");
if ((hook->method == NULL) || (conn->method == NULL) || (strcmp(hook->method, conn->method) != 0))
{
printf("==== Hook found but method failed -> next.\n");
reason = RESTD_ERROR_METHOD_NOT_ALLOWED;
continue;
}
if ((hook->path != NULL) && (http->request.path != NULL))
{
int i = 0;
int pos = -1;
while (hook->path[i])
{
if (hook->path[i] == ':')
pos = i;
i++;
}
if (pos != -1 && contain(hook->path, http->request.path, pos))
{
const char *buffer = &http->request.path[pos];
// printf("buffer: <%s>\n", buffer);
conn->id = atoi(buffer);
return hook->cb(event, conn, hook->userdata);
}
else
{
int rett = strcmp(hook->path, http->request.path);
if (rett == 0)
return hook->cb(event, conn, hook->userdata);
}
}
}
}
// No Hook Found check if it's a real file into document root.
root_path = restd_server_get_option(conn->server, "server.root_path");
if ((root_path != NULL) && (strlen(root_path) != 0))
{
FILE *file;
char buf[1024] = "";
qstrcatf(buf, "%s%s", root_path, http->request.path);
if ((file = fopen(buf, "r")))
{
long fsize;
char *file_buf;
fseek(file, 0, SEEK_END);
fsize = ftell(file);
fseek(file, 0, SEEK_SET);
file_buf = malloc(fsize + 1);
fread(file_buf, 1, fsize, file);
fclose(file);
file_buf[fsize] = 0;
printf("mime type:%s\n", file_mime_lookup(buf));
restd_http_response(conn, 200, file_mime_lookup(buf), file_buf, fsize);
return RESTD_CLOSE;
}
}
if (conn->server->error_handler != NULL)
return conn->server->error_handler(reason, conn, NULL);
return RESTD_CLOSE;
}
BUG_EXIT();
return RESTD_CLOSE;
}
#endif

View File

@@ -30,6 +30,8 @@
#include <pthread.h>
#include <event2/http.h>
#include <qlibc/qlibc.h>
/*------------------------------- TYPEDEFS ----------------------------------*/
@@ -37,7 +39,12 @@
typedef struct restd_server_s restd_server_t;
typedef struct restd_hook_s restd_hook_t;
typedef int (*restd_callback)(short event, void *conn, void *userdata);
/**
* User callback(hook) prototype.
*/
typedef int (*restd_call_hook_cb)(short event, void *conn);
typedef int (*restd_callback)(struct evhttp_request *req, void *arg);
typedef void (*restd_userdata_free_cb)(void *conn, void *userdata);
/*------------------------------- INCLUDES ----------------------------------*/
@@ -47,9 +54,12 @@ extern int restd_server_start(restd_server_t *server);
extern int restd_server_attach_event_loop(restd_server_t *server, struct event_base *ev_base);
extern void restd_server_set_option(restd_server_t *server, const char *key, const char *value);
extern void restd_server_register_hook_on_path(restd_server_t *server, const char *method, const char *path,
extern void restd_server_register_hook_on_path(restd_server_t *server, enum evhttp_cmd_type method, const char *path,
restd_callback cb, void *userdata);
extern void restd_http_response(struct evhttp_request *req, int code, const char *contenttype, const char *data);
/*------------------------------- DEFINES ------------------------------------*/
/*
@@ -65,16 +75,16 @@ enum restd_log_e
RESTD_LOG_DEBUG2,
};
#define RESTD_OK (0) /*!< I'm done with this request. Escalate to other hooks. */
#define RESTD_FAILED (1) /*!< I'm done with this request. But the Process failed. */
/*---------------------------------------------------------------------------*\
| USER-CALLBACK |
\*---------------------------------------------------------------------------*/
/**
* User callback(hook) prototype.
*/
typedef int (*restd_call_hook_cb)(short event, void *conn);
typedef int (*restd_callback)(short event, void *conn, void *userdata);
typedef void (*restd_userdata_free_cb)(void *conn, void *userdata);
/*---------------------------------------------------------------------------*\
| DATA STRUCTURES |
@@ -107,7 +117,7 @@ struct restd_server_s
*/
struct restd_hook_s
{
char *method;
enum evhttp_cmd_type method;
char *path;
restd_callback cb;
void *userdata;

View File

@@ -34,7 +34,7 @@
#include <curl/curl.h>
#include <restd.h>
#include <rest/restd.h>
#include "qunit.h"

View File

@@ -39,7 +39,7 @@
/*--------------------------------------------------------------------------*/
int my_error_handler(short event, restd_conn_t *conn, void *userdata)
int my_error_handler(struct evhttp_request *req, void *arg)
{
//restd_http_response(conn, 200, "application/json", "{\"status\":\"error\"}", 18);
//return RESTD_CLOSE; // Close connection.
@@ -47,43 +47,35 @@ int my_error_handler(short event, restd_conn_t *conn, void *userdata)
/*--------------------------------------------------------------------------*/
int my_success_http_handler(short event, restd_conn_t *conn, void *userdata)
int my_success_http_handler(struct evhttp_request *req, void *arg)
{
#if 0
if (event & RESTD_EVENT_READ)
{
restd_http_response(conn, 200, "application/json", ksuccess_get_body, strlen(ksuccess_get_body));
return RESTD_CLOSE; // Close connection.
}
restd_http_response(req, 200, "application/json", ksuccess_get_body);
return RESTD_OK;
#endif
}
#if 0
/*--------------------------------------------------------------------------*/
int my_success_rest_get_handler(short event, restd_conn_t *conn, void *userdata)
int my_success_rest_get_handler(struct evhttp_request *req, void *arg)
{
restd_http_response(conn, 200, "application/json", ksuccess_get_body, strlen(ksuccess_get_body));
return RESTD_CLOSE; // Close connection.
restd_http_response(req, 200, "application/json", ksuccess_get_body);
return RESTD_OK;
}
/*--------------------------------------------------------------------------*/
int my_success_rest_delete_handler(short event, restd_conn_t *conn, void *userdata)
int my_success_rest_delete_handler(struct evhttp_request *req, void *arg)
{
restd_http_response(conn, 200, "application/json", ksuccess_delete_body, strlen(ksuccess_delete_body));
return RESTD_CLOSE; // Close connection.
restd_http_response(req, 200, "application/json", ksuccess_delete_body);
return RESTD_OK;
}
/*--------------------------------------------------------------------------*/
int my_success_rest_put_handler(short event, restd_conn_t *conn, void *userdata)
int my_success_rest_put_handler(struct evhttp_request *req, void *arg)
{
printf("put event: %d\n", event);
restd_http_response(conn, 200, "application/json", ksuccess_put_body, strlen(ksuccess_put_body));
return RESTD_CLOSE; // Close connection.
restd_http_response(req, 200, "application/json", ksuccess_put_body);
return RESTD_OK;
}
/*--------------------------------------------------------------------------*/
@@ -154,6 +146,8 @@ int exec_request(const char *request, const char *path, int expected_code, const
curl_easy_setopt(curl_handle, CURLOPT_POST, 0);
}
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 2);
// Debug Only
//curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
@@ -169,11 +163,18 @@ int exec_request(const char *request, const char *path, int expected_code, const
printf("Error: %d\n", res);
}
ASSERT_EQUAL_INT(res, CURLE_OK);
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_result_code);
ASSERT_EQUAL_INT(http_result_code, expected_code);
res = strcmp(expected_body, body);
if (body == NULL)
{
res = 1;
}
else
{
res = strcmp(expected_body, body);
}
//printf ("body: %s != expected_body: %s\n", body, expected_body);
if (res != 0)
{
@@ -193,10 +194,10 @@ exit:
return ret;
}
#endif
/*--------------------------------------------------------------------------*/
bool found_route(restd_server_t *server, const char *method, const char *path)
bool found_route(restd_server_t *server, enum evhttp_cmd_type method, const char *path)
{
qlist_t *hooks = server->hooks;
@@ -205,7 +206,7 @@ bool found_route(restd_server_t *server, const char *method, const char *path)
while (hooks->getnext(hooks, &obj, false) == true)
{
restd_hook_t *hook = (restd_hook_t *)obj.data;
if (hook->method && method && strcmp(hook->method, method) == 0)
if (hook->method == method)
{
if (hook->path && path && strcmp(hook->path, path) == 0)
return true;
@@ -242,7 +243,7 @@ bool contain(const char *src, const char *dest, int len)
/*--------------------------------------------------------------------------*/
bool found_special_route(restd_server_t *server, const char *method, const char *path, int *id)
bool found_special_route(restd_server_t *server, enum evhttp_cmd_type method, const char *path, int *id)
{
qlist_t *hooks = server->hooks;
@@ -251,7 +252,7 @@ bool found_special_route(restd_server_t *server, const char *method, const char
while (hooks->getnext(hooks, &obj, false) == true)
{
restd_hook_t *hook = (restd_hook_t *)obj.data;
if (hook->method && method && strcmp(hook->method, method) == 0)
if (hook->method == method)
{
if (hook->path && path)
{
@@ -293,7 +294,7 @@ TEST("Rest - create free\t")
restd_server_set_option(rest_server, "server.port", kserver_port);
restd_server_register_hook_on_path(rest_server, "POST", "/api/v1/test", my_error_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_POST, "/api/v1/test", my_error_handler, NULL);
restd_server_free(rest_server);
}
@@ -309,21 +310,21 @@ TEST("Rest - create access regular route free\t")
restd_server_set_option(rest_server, "server.port", kserver_port);
restd_server_register_hook_on_path(rest_server, "POST", "/api/v1/test", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_POST, "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, "POST", "/api/v1/test"));
ASSERT_FALSE(found_route(rest_server, "POST", "/api/v1/notfound"));
ASSERT_TRUE(found_route(rest_server, EVHTTP_REQ_POST, "/api/v1/test"));
ASSERT_FALSE(found_route(rest_server, EVHTTP_REQ_POST, "/api/v1/notfound"));
restd_server_register_hook_on_path(rest_server, "GET", "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, kget_method, "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, "GET", "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, kget_method, "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, EVHTTP_REQ_GET, "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, EVHTTP_REQ_GET, "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, "PUT", "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, "PUT", "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_PUT, "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, EVHTTP_REQ_PUT, "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, kdelete_method, "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, kdelete_method, "/api/v1/test"));
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_DELETE, "/api/v1/test", my_success_http_handler, NULL);
ASSERT_TRUE(found_route(rest_server, EVHTTP_REQ_DELETE, "/api/v1/test"));
restd_server_free(rest_server);
}
@@ -336,13 +337,13 @@ TEST("Rest - create access route with param free\t")
rest_server = restd_server_new();
ASSERT_NOT_NULL(rest_server);
restd_server_register_hook_on_path(rest_server, kget_method, "/api/v1/klong/:id", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, kget_method, "/api/v1/donkey", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, kget_method, "/api/v1/test/:id", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/klong/:id", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/donkey", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/test/:id", my_success_http_handler, NULL);
ASSERT_FALSE(found_special_route(rest_server, kget_method, "/api/v1/notfound/77", &id));
ASSERT_FALSE(found_special_route(rest_server, EVHTTP_REQ_GET, "/api/v1/notfound/77", &id));
ASSERT_TRUE(found_special_route(rest_server, kget_method, "/api/v1/test/77", &id));
ASSERT_TRUE(found_special_route(rest_server, EVHTTP_REQ_GET, "/api/v1/test/77", &id));
ASSERT_EQUAL_INT(id, 77);
restd_server_free(rest_server);
@@ -361,7 +362,7 @@ TEST("Rest - create start free\t")
restd_server_set_option(rest_server, "server.port", kserver_port);
restd_server_set_option(rest_server, "server.thread", "1");
restd_server_register_hook_on_path(rest_server, kget_method, "/api/v1/test/:id", my_success_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/test/:id", my_success_http_handler, NULL);
ret = restd_server_start(rest_server);
ASSERT_EQUAL_INT(ret, 0);
@@ -370,7 +371,7 @@ TEST("Rest - create start free\t")
}
/*--------------------------------------------------------------------------*/
#if 0
TEST("Rest - create start access http hook free\t")
{
int ret;
@@ -382,8 +383,8 @@ TEST("Rest - create start access http hook free\t")
restd_server_set_option(rest_server, "server.port", kserver_port);
restd_server_set_option(rest_server, "server.thread", "1");
restd_server_register_hook(rest_server, restd_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, "GET", kapi_test_get, my_success_http_handler, NULL);
// restd_server_register_hook(rest_server, restd_http_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, kapi_test_get, my_success_http_handler, NULL);
ret = restd_server_start(rest_server);
ASSERT_EQUAL_INT(ret, 0);
@@ -409,11 +410,11 @@ TEST("Rest - create start access rest hook free\t")
restd_server_set_option(rest_server, "server.port", kserver_port);
restd_server_set_option(rest_server, "server.thread", "1");
restd_server_register_call_hooks_handler(rest_server, restd_rest_handler);
//restd_server_register_call_hooks_handler(rest_server, restd_rest_handler);
restd_server_register_hook_on_path(rest_server, kget_method, kapi_test_get, my_success_rest_get_handler, NULL);
restd_server_register_hook_on_path(rest_server, kput_method, kapi_test_get, my_success_rest_put_handler, NULL);
restd_server_register_hook_on_path(rest_server, kdelete_method, kapi_test_get, my_success_rest_delete_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, kapi_test_get, my_success_rest_get_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_PUT, kapi_test_get, my_success_rest_put_handler, NULL);
restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_DELETE, kapi_test_get, my_success_rest_delete_handler, NULL);
ret = restd_server_start(rest_server);
ASSERT_EQUAL_INT(ret, 0);
@@ -423,17 +424,17 @@ TEST("Rest - create start access rest hook free\t")
PRINTLN("\n - GET");
ret = exec_request(kget_method, "http://localhost:"kserver_port kapi_test_get, 200, ksuccess_get_body);
ASSERT_EQUAL_INT(ret, 0);
PRINTLN("\n - DELETE");
ret = exec_request(kdelete_method, "http://localhost:"kserver_port kapi_test_get, 200, ksuccess_delete_body);
ASSERT_EQUAL_INT(ret, 0);
#if 0
PRINTLN("\n - PUT");
ret = exec_request(kput_method, "http://localhost:"kserver_port kapi_test_get, 200, ksuccess_put_body);
ASSERT_EQUAL_INT(ret, 0);
#endif
// TODO POST
restd_server_free(rest_server);
}
#endif