This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
wasm-micro-runtime/core/app-framework/app-native-shared/restful_utils.c
Wenyong Huang db695fada4
Implement XIP feature and enable ARC target support (#694)
Implement XIP (Execution In Place) feature for AOT mode to enable running the AOT code inside AOT file directly, without memory mapping the executable memory for AOT code and applying relocations for text section. Developer can use wamrc with "--enable-indirect-mode --disable-llvm-intrinsics" flags to generate the AOT file and run iwasm with "--xip" flag. Known issues: there might still be some relocations in the text section which access the ".rodata" like sections.

And also enable ARC target support for both interpreter mode and AOT mode.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
2021-08-12 17:44:39 +08:00

491 lines
12 KiB
C

/*
* 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;
}