mirror of
https://github.com/polhenarejos/pico-keys-sdk
synced 2026-05-28 17:11:23 +02:00
Add more support for rest emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
@@ -1,8 +1,5 @@
|
|||||||
#include "rest_server.h"
|
#include "rest_server.h"
|
||||||
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -11,20 +8,44 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define REST_PORT 80
|
#define REST_PORT 80
|
||||||
#define REST_MAX_CONNS 4
|
#define REST_MAX_CONNS 4
|
||||||
#define REST_MAX_REQUEST_SIZE 8192
|
#define REST_MAX_REQUEST_SIZE 1024
|
||||||
#define REST_MAX_METHOD_SIZE 8
|
#define REST_MAX_METHOD_SIZE 8
|
||||||
#define REST_MAX_PATH_SIZE 192
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool in_use;
|
bool in_use;
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
int sock;
|
||||||
|
#else
|
||||||
struct tcp_pcb *pcb;
|
struct tcp_pcb *pcb;
|
||||||
|
#endif
|
||||||
char request[REST_MAX_REQUEST_SIZE + 1];
|
char request[REST_MAX_REQUEST_SIZE + 1];
|
||||||
size_t request_len;
|
size_t request_len;
|
||||||
} rest_conn_t;
|
} rest_conn_t;
|
||||||
|
|
||||||
|
#ifndef ENABLE_EMULATION
|
||||||
static struct tcp_pcb *listener_pcb = NULL;
|
static struct tcp_pcb *listener_pcb = NULL;
|
||||||
|
#else
|
||||||
|
static int listener_sock = -1;
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
static pthread_t rest_thread;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
static rest_conn_t conns[REST_MAX_CONNS];
|
static rest_conn_t conns[REST_MAX_CONNS];
|
||||||
|
|
||||||
__attribute__((weak)) const rest_route_t *rest_get_routes(size_t *count) {
|
__attribute__((weak)) const rest_route_t *rest_get_routes(size_t *count) {
|
||||||
@@ -34,13 +55,23 @@ __attribute__((weak)) const rest_route_t *rest_get_routes(size_t *count) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rest_conn_t *alloc_conn(struct tcp_pcb *pcb) {
|
static rest_conn_t *alloc_conn(
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
int sock
|
||||||
|
#else
|
||||||
|
struct tcp_pcb *pcb
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < REST_MAX_CONNS; i++) {
|
for (i = 0; i < REST_MAX_CONNS; i++) {
|
||||||
if (!conns[i].in_use) {
|
if (!conns[i].in_use) {
|
||||||
memset(&conns[i], 0, sizeof(conns[i]));
|
memset(&conns[i], 0, sizeof(conns[i]));
|
||||||
conns[i].in_use = true;
|
conns[i].in_use = true;
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
conns[i].sock = sock;
|
||||||
|
#else
|
||||||
conns[i].pcb = pcb;
|
conns[i].pcb = pcb;
|
||||||
|
#endif
|
||||||
return &conns[i];
|
return &conns[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,6 +86,17 @@ static void clear_conn(rest_conn_t *conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void close_conn(rest_conn_t *conn) {
|
static void close_conn(rest_conn_t *conn) {
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
if (conn == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (conn->sock >= 0) {
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
(void)close(conn->sock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
clear_conn(conn);
|
||||||
|
#else
|
||||||
err_t err;
|
err_t err;
|
||||||
if (conn == NULL || conn->pcb == NULL) {
|
if (conn == NULL || conn->pcb == NULL) {
|
||||||
clear_conn(conn);
|
clear_conn(conn);
|
||||||
@@ -70,13 +112,25 @@ static void close_conn(rest_conn_t *conn) {
|
|||||||
tcp_abort(conn->pcb);
|
tcp_abort(conn->pcb);
|
||||||
}
|
}
|
||||||
clear_conn(conn);
|
clear_conn(conn);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_response(rest_conn_t *conn, int status_code, const char *status_text, const char *content_type, const char *body, size_t body_len) {
|
static void send_response(rest_conn_t *conn, int status_code, const char *status_text, const char *content_type, const char *body, size_t body_len) {
|
||||||
char headers[256];
|
char headers[256];
|
||||||
int header_len;
|
int header_len;
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
size_t sent_total = 0;
|
||||||
|
#else
|
||||||
err_t err;
|
err_t err;
|
||||||
if (conn == NULL || conn->pcb == NULL) {
|
#endif
|
||||||
|
if (
|
||||||
|
conn == NULL
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
|| conn->sock < 0
|
||||||
|
#else
|
||||||
|
|| conn->pcb == NULL
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
header_len = snprintf(headers, sizeof(headers),
|
header_len = snprintf(headers, sizeof(headers),
|
||||||
@@ -90,6 +144,33 @@ static void send_response(rest_conn_t *conn, int status_code, const char *status
|
|||||||
close_conn(conn);
|
close_conn(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
while (sent_total < (size_t)header_len) {
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
ssize_t n = send(conn->sock, headers + sent_total, (size_t)header_len - sent_total, 0);
|
||||||
|
#else
|
||||||
|
int n = -1;
|
||||||
|
#endif
|
||||||
|
if (n <= 0) {
|
||||||
|
close_conn(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sent_total += (size_t)n;
|
||||||
|
}
|
||||||
|
sent_total = 0;
|
||||||
|
while (sent_total < body_len) {
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
ssize_t n = send(conn->sock, body + sent_total, body_len - sent_total, 0);
|
||||||
|
#else
|
||||||
|
int n = -1;
|
||||||
|
#endif
|
||||||
|
if (n <= 0) {
|
||||||
|
close_conn(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sent_total += (size_t)n;
|
||||||
|
}
|
||||||
|
#else
|
||||||
err = tcp_write(conn->pcb, headers, (uint16_t)header_len, TCP_WRITE_FLAG_COPY);
|
err = tcp_write(conn->pcb, headers, (uint16_t)header_len, TCP_WRITE_FLAG_COPY);
|
||||||
if (err == ERR_OK && body_len > 0) {
|
if (err == ERR_OK && body_len > 0) {
|
||||||
err = tcp_write(conn->pcb, body, (uint16_t)body_len, TCP_WRITE_FLAG_COPY);
|
err = tcp_write(conn->pcb, body, (uint16_t)body_len, TCP_WRITE_FLAG_COPY);
|
||||||
@@ -97,6 +178,7 @@ static void send_response(rest_conn_t *conn, int status_code, const char *status
|
|||||||
if (err == ERR_OK) {
|
if (err == ERR_OK) {
|
||||||
(void)tcp_output(conn->pcb);
|
(void)tcp_output(conn->pcb);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
close_conn(conn);
|
close_conn(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +207,7 @@ static const char *status_text_from_code(uint16_t code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_request(rest_conn_t *conn, rest_http_method_t *method, char *path, size_t path_size, rest_request_t *request) {
|
static int parse_request(rest_conn_t *conn, rest_request_t *request) {
|
||||||
char *header_end, *line_end, *cursor;
|
char *header_end, *line_end, *cursor;
|
||||||
size_t headers_size;
|
size_t headers_size;
|
||||||
unsigned long content_length = 0;
|
unsigned long content_length = 0;
|
||||||
@@ -142,20 +224,20 @@ static int parse_request(rest_conn_t *conn, rest_http_method_t *method, char *pa
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*line_end = '\0';
|
*line_end = '\0';
|
||||||
if (sscanf(conn->request, "%7s %191s", method_str, path) != 2) {
|
if (sscanf(conn->request, "%7s %191s", method_str, request->path) != 2) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strcmp(method_str, "GET") == 0) {
|
if (strcmp(method_str, "GET") == 0) {
|
||||||
*method = REST_HTTP_GET;
|
request->method = REST_HTTP_GET;
|
||||||
}
|
}
|
||||||
else if (strcmp(method_str, "POST") == 0) {
|
else if (strcmp(method_str, "POST") == 0) {
|
||||||
*method = REST_HTTP_POST;
|
request->method = REST_HTTP_POST;
|
||||||
}
|
}
|
||||||
else if (strcmp(method_str, "PUT") == 0) {
|
else if (strcmp(method_str, "PUT") == 0) {
|
||||||
*method = REST_HTTP_PUT;
|
request->method = REST_HTTP_PUT;
|
||||||
}
|
}
|
||||||
else if (strcmp(method_str, "DELETE") == 0) {
|
else if (strcmp(method_str, "DELETE") == 0) {
|
||||||
*method = REST_HTTP_DELETE;
|
request->method = REST_HTTP_DELETE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -210,51 +292,73 @@ static int parse_request(rest_conn_t *conn, rest_http_method_t *method, char *pa
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_json(const char *content_type) {
|
||||||
|
if (content_type == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return strncasecmp(content_type, "application/json", 16) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_request(rest_conn_t *conn) {
|
static void handle_request(rest_conn_t *conn) {
|
||||||
rest_http_method_t method;
|
rest_request_t request = {0};
|
||||||
char path[REST_MAX_PATH_SIZE] = {0};
|
rest_response_t response = {0};
|
||||||
rest_request_t request;
|
|
||||||
rest_response_t response;
|
|
||||||
const rest_route_t *routes;
|
const rest_route_t *routes;
|
||||||
size_t route_count = 0, i;
|
size_t route_count = 0, i;
|
||||||
bool path_exists_for_other_method = false;
|
bool path_exists_for_other_method = false;
|
||||||
int parsed;
|
int parsed;
|
||||||
|
|
||||||
parsed = parse_request(conn, &method, path, sizeof(path), &request);
|
parsed = parse_request(conn, &request);
|
||||||
if (parsed <= 0) {
|
if (parsed <= 0) {
|
||||||
if (parsed < 0) {
|
if (parsed < 0) {
|
||||||
send_json(conn, 400, "Bad Request", "{\"error\":\"bad_request\"}");
|
send_json(conn, 400, "Bad Request", "{\"error\":\"bad_request\"}");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
request.method = method;
|
if (request.method == REST_HTTP_POST || request.method == REST_HTTP_PUT) {
|
||||||
request.path = path;
|
if (!is_json(request.content_type)) {
|
||||||
|
send_json(conn, 415, "Unsupported Media Type", "{\"error\":\"content_type_must_be_application_json\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
routes = rest_get_routes(&route_count);
|
routes = rest_get_routes(&route_count);
|
||||||
for (i = 0; i < route_count; i++) {
|
for (i = 0; i < route_count; i++) {
|
||||||
if (routes[i].path == NULL || routes[i].handler == NULL) {
|
if (routes[i].path == NULL || routes[i].handler == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(routes[i].path, path) != 0) {
|
if (strcmp(routes[i].path, request.path) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (routes[i].method != method) {
|
if (routes[i].method != request.method) {
|
||||||
path_exists_for_other_method = true;
|
path_exists_for_other_method = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
response.status_code = 200;
|
response.status_code = 200;
|
||||||
response.content_type = "application/json";
|
response.content_type = "application/json";
|
||||||
response.body = "{\"ok\":true}";
|
response.body = "{\"ok\":true}";
|
||||||
response.body_len = strlen(response.body);
|
response.json = cJSON_CreateObject();
|
||||||
|
|
||||||
if (routes[i].handler(&request, &response) != 0) {
|
if (routes[i].handler(&request, &response) != 0) {
|
||||||
send_json(conn, 500, "Internal Server Error", "{\"error\":\"internal_error\"}");
|
send_json(conn, 500, "Internal Server Error", "{\"error\":\"internal_error\"}");
|
||||||
|
cJSON_Delete(response.json);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response.content_type == NULL || response.body == NULL) {
|
if (response.content_type == NULL || response.body == NULL) {
|
||||||
send_json(conn, 500, "Internal Server Error", "{\"error\":\"invalid_response\"}");
|
send_json(conn, 500, "Internal Server Error", "{\"error\":\"invalid_response\"}");
|
||||||
|
cJSON_Delete(response.json);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
response.body = cJSON_PrintUnformatted(response.json);
|
||||||
|
cJSON_Delete(response.json);
|
||||||
|
if (response.body == NULL) {
|
||||||
|
send_json(conn, 500, "Internal Server Error", "{\"error\":\"internal_error\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.status_code = (response.status_code == 0) ? 200 : response.status_code;
|
||||||
|
response.body_len = (response.body_len == 0) ? strlen(response.body) : response.body_len;
|
||||||
send_response(conn, response.status_code, status_text_from_code(response.status_code), response.content_type, response.body, response.body_len);
|
send_response(conn, response.status_code, status_text_from_code(response.status_code), response.content_type, response.body, response.body_len);
|
||||||
|
if (response.body) {
|
||||||
|
free(response.body);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,6 +369,7 @@ static void handle_request(rest_conn_t *conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ENABLE_EMULATION
|
||||||
static err_t rest_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
|
static err_t rest_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
|
||||||
rest_conn_t *conn = (rest_conn_t *)arg;
|
rest_conn_t *conn = (rest_conn_t *)arg;
|
||||||
|
|
||||||
@@ -355,3 +460,105 @@ err_t rest_server_init(void) {
|
|||||||
tcp_accept(listener_pcb, rest_accept);
|
tcp_accept(listener_pcb, rest_accept);
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static int emulation_rest_port(void) {
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
const char *port_env = getenv("PICO_REST_PORT");
|
||||||
|
long v;
|
||||||
|
if (port_env == NULL || *port_env == '\0') {
|
||||||
|
return REST_PORT;
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
v = strtol(port_env, NULL, 10);
|
||||||
|
if (errno != 0 || v < 1 || v > 65535) {
|
||||||
|
return REST_PORT;
|
||||||
|
}
|
||||||
|
return (int)v;
|
||||||
|
#else
|
||||||
|
return REST_PORT;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
static void *rest_emulation_thread(void *arg) {
|
||||||
|
struct sockaddr_in peer;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
socklen_t peer_len = sizeof(peer);
|
||||||
|
int accepted = accept(listener_sock, (struct sockaddr *)&peer, &peer_len);
|
||||||
|
rest_conn_t *conn;
|
||||||
|
if (accepted < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
conn = alloc_conn(accepted);
|
||||||
|
if (conn == NULL) {
|
||||||
|
(void)close(accepted);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while (conn->in_use) {
|
||||||
|
ssize_t n = recv(conn->sock, conn->request + conn->request_len, REST_MAX_REQUEST_SIZE - conn->request_len, 0);
|
||||||
|
if (n <= 0) {
|
||||||
|
close_conn(conn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
conn->request_len += (size_t)n;
|
||||||
|
if (conn->request_len > REST_MAX_REQUEST_SIZE) {
|
||||||
|
send_json(conn, 413, "Payload Too Large", "{\"error\":\"payload_too_large\"}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_request(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err_t rest_server_init(void) {
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int one = 1;
|
||||||
|
int port = emulation_rest_port();
|
||||||
|
|
||||||
|
if (listener_sock >= 0) {
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
listener_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (listener_sock < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (setsockopt(listener_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) {
|
||||||
|
(void)close(listener_sock);
|
||||||
|
listener_sock = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons((uint16_t)port);
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
if (bind(listener_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
||||||
|
(void)close(listener_sock);
|
||||||
|
listener_sock = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (listen(listener_sock, REST_MAX_CONNS) != 0) {
|
||||||
|
(void)close(listener_sock);
|
||||||
|
listener_sock = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pthread_create(&rest_thread, NULL, rest_emulation_thread, NULL) != 0) {
|
||||||
|
(void)close(listener_sock);
|
||||||
|
listener_sock = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
(void)pthread_detach(rest_thread);
|
||||||
|
return ERR_OK;
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int lwip_itf_init(void) {
|
||||||
|
return rest_server_init();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,9 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program 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
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef PICO_KEYS_REST_SERVER_H
|
#ifndef PICO_KEYS_REST_SERVER_H
|
||||||
#define PICO_KEYS_REST_SERVER_H
|
#define PICO_KEYS_REST_SERVER_H
|
||||||
|
|
||||||
|
#ifdef ENABLE_EMULATION
|
||||||
|
typedef int err_t;
|
||||||
|
#define ERR_OK 0
|
||||||
|
#else
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
#endif
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "cJSON.h"
|
||||||
|
|
||||||
|
#define REST_MAX_PATH_SIZE 192
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
REST_HTTP_GET = 0,
|
REST_HTTP_GET = 0,
|
||||||
@@ -14,7 +40,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
rest_http_method_t method;
|
rest_http_method_t method;
|
||||||
const char *path;
|
char path[REST_MAX_PATH_SIZE];
|
||||||
const char *body;
|
const char *body;
|
||||||
size_t body_len;
|
size_t body_len;
|
||||||
const char *content_type;
|
const char *content_type;
|
||||||
@@ -23,8 +49,9 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t status_code;
|
uint16_t status_code;
|
||||||
const char *content_type;
|
const char *content_type;
|
||||||
const char *body;
|
char *body; // heap !
|
||||||
size_t body_len;
|
size_t body_len;
|
||||||
|
cJSON *json;
|
||||||
} rest_response_t;
|
} rest_response_t;
|
||||||
|
|
||||||
typedef int (*rest_route_handler_t)(const rest_request_t *request, rest_response_t *response);
|
typedef int (*rest_route_handler_t)(const rest_request_t *request, rest_response_t *response);
|
||||||
@@ -38,5 +65,6 @@ typedef struct {
|
|||||||
const rest_route_t *rest_get_routes(size_t *count);
|
const rest_route_t *rest_get_routes(size_t *count);
|
||||||
|
|
||||||
err_t rest_server_init(void);
|
err_t rest_server_init(void);
|
||||||
|
int lwip_itf_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user