summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c493
1 files changed, 493 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c
new file mode 100644
index 000000000..03e86a699
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "bi-inc/shared_utils.h"
+
+/* Serialization of request and response message
+ *
+ * Choices:
+ * We considered a few options:
+ * 1. coap
+ * 2. flatbuffer
+ * 3. cbor
+ * 4. attr-containers of our own
+ * 5. customized serialization for request/response
+ *
+ * Now we choose the #5 mainly because we need to quickly get the URL for
+ * dispatching and sometimes we want to change the URL in the original packet.
+ * the request format: fixed part: version: (1 byte), code (1 byte), fmt(2
+ * byte), mid (4 bytes), sender_id(4 bytes), url_len(2 bytes),
+ * payload_len(4bytes) dynamic part: url (bytes in url_len), payload
+ *
+ * response format:
+ * fixed part: (1 byte), code (1 byte), fmt(2 byte), mid (4 bytes), sender_id(4
+ * bytes), payload_len(4bytes) dynamic part: payload
+ */
+#define REQUES_PACKET_VER 1
+#define REQUEST_PACKET_FIX_PART_LEN 18
+#define REQUEST_PACKET_URL_OFFSET REQUEST_PACKET_FIX_PART_LEN
+#define REQUEST_PACKET_URL_LEN \
+ *((uint16 *)((char *)buffer + 12)) /* to ensure little endian */
+#define REQUEST_PACKET_PAYLOAD_LEN \
+ *((uint32 *)((char *)buffer + 14)) /* to ensure little endian */
+#define REQUEST_PACKET_URL(buffer) ((char *)buffer + REQUEST_PACKET_URL_OFFSET)
+#define REQUEST_PACKET_PAYLOAD(buffer) \
+ ((char *)buffer + REQUEST_PACKET_URL_OFFSET \
+ + REQUEST_PACKET_URL_LEN(buffer))
+
+#define RESPONSE_PACKET_FIX_PART_LEN 16
+
+char *
+pack_request(request_t *request, int *size)
+{
+ int url_len = strlen(request->url) + 1;
+ int len = REQUEST_PACKET_FIX_PART_LEN + url_len + request->payload_len;
+ uint16 u16;
+ uint32 u32;
+ char *packet;
+
+ if ((packet = (char *)WA_MALLOC(len)) == NULL)
+ return NULL;
+
+ /* TODO: ensure little endian for words and dwords */
+ *packet = REQUES_PACKET_VER;
+ *((uint8 *)(packet + 1)) = request->action;
+
+ u16 = htons(request->fmt);
+ memcpy(packet + 2, &u16, 2);
+
+ u32 = htonl(request->mid);
+ memcpy(packet + 4, &u32, 4);
+
+ u32 = htonl(request->sender);
+ memcpy(packet + 8, &u32, 4);
+
+ u16 = htons(url_len);
+ memcpy(packet + 12, &u16, 2);
+
+ u32 = htonl(request->payload_len);
+ memcpy(packet + 14, &u32, 4);
+
+ strcpy(packet + REQUEST_PACKET_URL_OFFSET, request->url);
+ memcpy(packet + REQUEST_PACKET_URL_OFFSET + url_len, request->payload,
+ request->payload_len);
+
+ *size = len;
+ return packet;
+}
+
+void
+free_req_resp_packet(char *packet)
+{
+ WA_FREE(packet);
+}
+
+request_t *
+unpack_request(char *packet, int size, request_t *request)
+{
+ uint16 url_len, u16;
+ uint32 payload_len, u32;
+
+ if (*packet != REQUES_PACKET_VER) {
+ return NULL;
+ }
+ if (size < REQUEST_PACKET_FIX_PART_LEN) {
+ return NULL;
+ }
+
+ memcpy(&u16, packet + 12, 2);
+ url_len = ntohs(u16);
+
+ memcpy(&u32, packet + 14, 4);
+ payload_len = ntohl(u32);
+
+ if (size != (REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) {
+ return NULL;
+ }
+
+ if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) {
+ return NULL;
+ }
+
+ request->action = *((uint8 *)(packet + 1));
+
+ memcpy(&u16, packet + 2, 2);
+ request->fmt = ntohs(u16);
+
+ memcpy(&u32, packet + 4, 4);
+ request->mid = ntohl(u32);
+
+ memcpy(&u32, packet + 8, 4);
+ request->sender = ntohl(u32);
+
+ request->payload_len = payload_len;
+ request->url = REQUEST_PACKET_URL(packet);
+
+ if (payload_len > 0)
+ request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len;
+ else
+ request->payload = NULL;
+
+ return request;
+}
+
+char *
+pack_response(response_t *response, int *size)
+{
+ int len = RESPONSE_PACKET_FIX_PART_LEN + response->payload_len;
+ uint16 u16;
+ uint32 u32;
+ char *packet;
+
+ if ((packet = (char *)WA_MALLOC(len)) == NULL)
+ return NULL;
+
+ /* TODO: ensure little endian for words and dwords */
+ *packet = REQUES_PACKET_VER;
+ *((uint8 *)(packet + 1)) = response->status;
+
+ u16 = htons(response->fmt);
+ memcpy(packet + 2, &u16, 2);
+
+ u32 = htonl(response->mid);
+ memcpy(packet + 4, &u32, 4);
+
+ u32 = htonl(response->reciever);
+ memcpy(packet + 8, &u32, 4);
+
+ u32 = htonl(response->payload_len);
+ memcpy(packet + 12, &u32, 4);
+
+ memcpy(packet + RESPONSE_PACKET_FIX_PART_LEN, response->payload,
+ response->payload_len);
+
+ *size = len;
+ return packet;
+}
+
+response_t *
+unpack_response(char *packet, int size, response_t *response)
+{
+ uint16 u16;
+ uint32 payload_len, u32;
+
+ if (*packet != REQUES_PACKET_VER)
+ return NULL;
+
+ if (size < RESPONSE_PACKET_FIX_PART_LEN)
+ return NULL;
+
+ memcpy(&u32, packet + 12, 4);
+ payload_len = ntohl(u32);
+ if (size != (RESPONSE_PACKET_FIX_PART_LEN + payload_len))
+ return NULL;
+
+ response->status = *((uint8 *)(packet + 1));
+
+ memcpy(&u16, packet + 2, 2);
+ response->fmt = ntohs(u16);
+
+ memcpy(&u32, packet + 4, 4);
+ response->mid = ntohl(u32);
+
+ memcpy(&u32, packet + 8, 4);
+ response->reciever = ntohl(u32);
+
+ response->payload_len = payload_len;
+ if (payload_len > 0)
+ response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN;
+ else
+ response->payload = NULL;
+
+ return response;
+}
+
+request_t *
+clone_request(request_t *request)
+{
+ /* deep clone */
+ request_t *req = (request_t *)WA_MALLOC(sizeof(request_t));
+ if (req == NULL)
+ return NULL;
+
+ memset(req, 0, sizeof(*req));
+ req->action = request->action;
+ req->fmt = request->fmt;
+ req->url = wa_strdup(request->url);
+ req->sender = request->sender;
+ req->mid = request->mid;
+
+ if (req->url == NULL)
+ goto fail;
+
+ req->payload_len = request->payload_len;
+
+ if (request->payload_len) {
+ req->payload = (char *)WA_MALLOC(request->payload_len);
+ if (!req->payload)
+ goto fail;
+ memcpy(req->payload, request->payload, request->payload_len);
+ }
+ else {
+ /* when payload_len is 0, the payload may be used for
+ carrying some handle or integer */
+ req->payload = request->payload;
+ }
+
+ return req;
+
+fail:
+ request_cleaner(req);
+ return NULL;
+}
+
+void
+request_cleaner(request_t *request)
+{
+ if (request->url != NULL)
+ WA_FREE(request->url);
+ if (request->payload != NULL && request->payload_len > 0)
+ WA_FREE(request->payload);
+
+ WA_FREE(request);
+}
+
+void
+response_cleaner(response_t *response)
+{
+ if (response->payload != NULL && response->payload_len > 0)
+ WA_FREE(response->payload);
+
+ WA_FREE(response);
+}
+
+response_t *
+clone_response(response_t *response)
+{
+ response_t *clone = (response_t *)WA_MALLOC(sizeof(response_t));
+
+ if (clone == NULL)
+ return NULL;
+
+ memset(clone, 0, sizeof(*clone));
+ clone->fmt = response->fmt;
+ clone->mid = response->mid;
+ clone->status = response->status;
+ clone->reciever = response->reciever;
+ clone->payload_len = response->payload_len;
+ if (clone->payload_len) {
+ clone->payload = (char *)WA_MALLOC(response->payload_len);
+ if (!clone->payload)
+ goto fail;
+ memcpy(clone->payload, response->payload, response->payload_len);
+ }
+ else {
+ /* when payload_len is 0, the payload may be used for
+ carrying some handle or integer */
+ clone->payload = response->payload;
+ }
+ return clone;
+
+fail:
+ response_cleaner(clone);
+ return NULL;
+}
+
+response_t *
+set_response(response_t *response, int status, int fmt, const char *payload,
+ int payload_len)
+{
+ response->payload = (void *)payload;
+ response->payload_len = payload_len;
+ response->status = status;
+ response->fmt = fmt;
+ return response;
+}
+
+response_t *
+make_response_for_request(request_t *request, response_t *response)
+{
+ response->mid = request->mid;
+ response->reciever = request->sender;
+
+ return response;
+}
+
+static unsigned int mid = 0;
+
+request_t *
+init_request(request_t *request, char *url, int action, int fmt, void *payload,
+ int payload_len)
+{
+ request->url = url;
+ request->action = action;
+ request->fmt = fmt;
+ request->payload = payload;
+ request->payload_len = payload_len;
+ request->mid = ++mid;
+
+ return request;
+}
+
+/*
+ check if the "url" is starting with "leading_str"
+ return: 0 - not match; >0 - the offset of matched url, include any "/" at the
+ end notes:
+ 1. it ensures the leading_str "/abc" can pass "/abc/cde" and "/abc/, but fail
+ "/ab" and "/abcd". leading_str "/abc/" can pass "/abc"
+ 2. it omit the '/' at the first char
+ 3. it ensure the leading_str "/abc" can pass "/abc?cde
+ */
+
+int
+check_url_start(const char *url, int url_len, const char *leading_str)
+{
+ int offset = 0;
+ if (*leading_str == '/')
+ leading_str++;
+ if (url_len > 0 && *url == '/') {
+ url_len--;
+ url++;
+ offset++;
+ }
+
+ int len = strlen(leading_str);
+ if (len == 0)
+ return 0;
+
+ /* ensure leading_str not end with "/" */
+ if (leading_str[len - 1] == '/') {
+ len--;
+ if (len == 0)
+ return 0;
+ }
+
+ /* equal length */
+ if (url_len == len) {
+ if (memcmp(url, leading_str, url_len) == 0) {
+ return (offset + len);
+ }
+ else {
+ return 0;
+ }
+ }
+
+ if (url_len < len)
+ return 0;
+ else if (memcmp(url, leading_str, len) != 0)
+ return 0;
+ else if (url[len] != '/' && url[len] != '?')
+ return 0;
+ else
+ return (offset + len + 1);
+}
+
+// * @pattern:
+// * sample 1: /abcd, match /abcd only
+// * sample 2: /abcd/ match match "/abcd" and "/abcd/*"
+// * sample 3: /abcd*, match any url started with "/abcd"
+// * sample 4: /abcd/*, exclude "/abcd"
+
+bool
+match_url(char *pattern, char *matched)
+{
+ if (*pattern == '/')
+ pattern++;
+ if (*matched == '/')
+ matched++;
+
+ int matched_len = strlen(matched);
+ if (matched_len == 0)
+ return false;
+
+ if (matched[matched_len - 1] == '/') {
+ matched_len--;
+ if (matched_len == 0)
+ return false;
+ }
+
+ int len = strlen(pattern);
+ if (len == 0)
+ return false;
+
+ if (pattern[len - 1] == '/') {
+ len--;
+ if (strncmp(pattern, matched, len) != 0)
+ return false;
+
+ if (len == matched_len)
+ return true;
+
+ if (matched_len > len && matched[len] == '/')
+ return true;
+
+ return false;
+ }
+ else if (pattern[len - 1] == '*') {
+ if (pattern[len - 2] == '/') {
+ if (strncmp(pattern, matched, len - 1) == 0)
+ return true;
+ else
+ return false;
+ }
+ else {
+ return (strncmp(pattern, matched, len - 1) == 0);
+ }
+ }
+ else {
+ return (strcmp(pattern, matched) == 0);
+ }
+}
+
+/*
+ * get the value of the key from following format buffer:
+ * key1=value1;key2=value2;key3=value3
+ */
+char *
+find_key_value(char *buffer, int buffer_len, char *key, char *value,
+ int value_len, char delimiter)
+{
+ char *p = buffer;
+ int remaining = buffer_len;
+ int key_len = strlen(key);
+
+ while (*p != 0 && remaining > 0) {
+ while (*p == ' ' || *p == delimiter) {
+ p++;
+ remaining--;
+ }
+
+ if (remaining <= key_len)
+ return NULL;
+
+ /* find the key */
+ if (0 == strncmp(p, key, key_len) && p[key_len] == '=') {
+ p += (key_len + 1);
+ remaining -= (key_len + 1);
+ char *v = value;
+ memset(value, 0, value_len);
+ value_len--; /* ensure last char is 0 */
+ while (*p != delimiter && remaining > 0 && value_len > 0) {
+ *v++ = *p++;
+ remaining--;
+ value_len--;
+ }
+ return value;
+ }
+
+ /* goto next key */
+ while (*p != delimiter && remaining > 0) {
+ p++;
+ remaining--;
+ }
+ }
+
+ return NULL;
+}