restful_utils.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <stdbool.h>
  8. #include <stdio.h>
  9. #include "bi-inc/shared_utils.h"
  10. /* Serialization of request and response message
  11. *
  12. * Choices:
  13. * We considered a few options:
  14. * 1. coap
  15. * 2. flatbuffer
  16. * 3. cbor
  17. * 4. attr-containers of our own
  18. * 5. customized serialization for request/response
  19. *
  20. * Now we choose the #5 mainly because we need to quickly get the URL for dispatching
  21. * and sometimes we want to change the URL in the original packet. the request format:
  22. * 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)
  23. * dynamic part: url (bytes in url_len), payload
  24. *
  25. * response format:
  26. * fixed part: (1 byte), code (1 byte), fmt(2 byte), mid (4 bytes), sender_id(4 bytes), payload_len(4bytes)
  27. * dynamic part: payload
  28. */
  29. #define REQUES_PACKET_VER 1
  30. #define REQUEST_PACKET_FIX_PART_LEN 18
  31. #define REQUEST_PACKET_URL_OFFSET REQUEST_PACKET_FIX_PART_LEN
  32. #define REQUEST_PACKET_URL_LEN *((uint16*)( (char*) buffer + 12))) //!!! to ensure little endian
  33. #define REQUEST_PACKET_PAYLOAD_LEN *((uint32*)( (char*) buffer + 14))) //!!! to ensure little endian
  34. #define REQUEST_PACKET_URL(buffer) ((char*) buffer + REQUEST_PACKET_URL_OFFSET)
  35. #define REQUEST_PACKET_PAYLOAD(buffer) ((char*) buffer + REQUEST_PACKET_URL_OFFSET + REQUEST_PACKET_URL_LEN(buffer))
  36. #define RESPONSE_PACKET_FIX_PART_LEN 16
  37. char * pack_request(request_t *request, int * size)
  38. {
  39. int url_len = strlen(request->url) + 1;
  40. int len = REQUEST_PACKET_FIX_PART_LEN + url_len + request->payload_len;
  41. char * packet = (char*) WA_MALLOC(len);
  42. if (packet == NULL)
  43. return NULL;
  44. // TODO: ensure little endian for words and dwords
  45. *packet = REQUES_PACKET_VER;
  46. *((uint8*) (packet + 1)) = request->action;
  47. *((uint16*) (packet + 2)) = htons(request->fmt);
  48. *((uint32*) (packet + 4)) = htonl(request->mid);
  49. *((uint32*) (packet + 8)) = htonl(request->sender);
  50. *((uint16*) (packet + 12)) = htons(url_len);
  51. *((uint32*) (packet + 14)) = htonl(request->payload_len);
  52. strcpy(packet + REQUEST_PACKET_URL_OFFSET, request->url);
  53. memcpy(packet + REQUEST_PACKET_URL_OFFSET + url_len, request->payload,
  54. request->payload_len);
  55. *size = len;
  56. return packet;
  57. }
  58. void free_req_resp_packet(char * packet)
  59. {
  60. WA_FREE(packet);
  61. }
  62. request_t * unpack_request(char * packet, int size, request_t * request)
  63. {
  64. if (*packet != REQUES_PACKET_VER) {
  65. return NULL;
  66. }
  67. if (size < REQUEST_PACKET_FIX_PART_LEN) {
  68. return NULL;
  69. }
  70. uint16 url_len = ntohs(*((uint16*) (packet + 12)));
  71. uint32 payload_len = ntohl(*((uint32*) (packet + 14)));
  72. if (size != ( REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) {
  73. return NULL;
  74. }
  75. if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) {
  76. return NULL;
  77. }
  78. request->action = *((uint8*) (packet + 1));
  79. request->fmt = ntohs(*((uint16*) (packet + 2)));
  80. request->mid = ntohl(*((uint32*) (packet + 4)));
  81. request->sender = ntohl(*((uint32*) (packet + 8)));
  82. request->payload_len = payload_len;
  83. request->url = REQUEST_PACKET_URL(packet);
  84. if (payload_len > 0)
  85. request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len;
  86. else
  87. request->payload = NULL;
  88. return request;
  89. }
  90. char * pack_response(response_t *response, int * size)
  91. {
  92. int len = RESPONSE_PACKET_FIX_PART_LEN + response->payload_len;
  93. char * packet = (char*) WA_MALLOC(len);
  94. if (packet == NULL)
  95. return NULL;
  96. // TODO: ensure little endian for words and dwords
  97. *packet = REQUES_PACKET_VER;
  98. *((uint8*) (packet + 1)) = response->status;
  99. *((uint16*) (packet + 2)) = htons(response->fmt);
  100. *((uint32*) (packet + 4)) = htonl(response->mid);
  101. *((uint32*) (packet + 8)) = htonl(response->reciever);
  102. *((uint32*) (packet + 12)) = htonl(response->payload_len);
  103. memcpy(packet + RESPONSE_PACKET_FIX_PART_LEN, response->payload,
  104. response->payload_len);
  105. *size = len;
  106. return packet;
  107. }
  108. response_t * unpack_response(char * packet, int size, response_t * response)
  109. {
  110. if (*packet != REQUES_PACKET_VER)
  111. return NULL;
  112. if (size < RESPONSE_PACKET_FIX_PART_LEN)
  113. return NULL;
  114. uint32 payload_len = ntohl(*((uint32*) (packet + 12)));
  115. if (size != ( RESPONSE_PACKET_FIX_PART_LEN + payload_len))
  116. return NULL;
  117. response->status = *((uint8*) (packet + 1));
  118. response->fmt = ntohs(*((uint16*) (packet + 2)));
  119. response->mid = ntohl(*((uint32*) (packet + 4)));
  120. response->reciever = ntohl(*((uint32*) (packet + 8)));
  121. response->payload_len = payload_len;
  122. if (payload_len > 0)
  123. response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN;
  124. else
  125. response->payload = NULL;
  126. return response;
  127. }
  128. request_t *clone_request(request_t *request)
  129. {
  130. /* deep clone */
  131. request_t *req = (request_t *) WA_MALLOC(sizeof(request_t));
  132. if (req == NULL)
  133. return NULL;
  134. memset(req, 0, sizeof(*req));
  135. req->action = request->action;
  136. req->fmt = request->fmt;
  137. req->url = wa_strdup(request->url);
  138. req->sender = request->sender;
  139. req->mid = request->mid;
  140. if (req->url == NULL)
  141. goto fail;
  142. req->payload_len = request->payload_len;
  143. if (request->payload_len) {
  144. req->payload = (char *) WA_MALLOC(request->payload_len);
  145. if (!req->payload)
  146. goto fail;
  147. memcpy(req->payload, request->payload, request->payload_len);
  148. } else {
  149. // when payload_len is 0, the payload may be used for carrying some handle or integer
  150. req->payload = request->payload;
  151. }
  152. return req;
  153. fail:
  154. request_cleaner(req);
  155. return NULL;
  156. }
  157. void request_cleaner(request_t *request)
  158. {
  159. if (request->url != NULL)
  160. WA_FREE(request->url);
  161. if (request->payload != NULL && request->payload_len > 0)
  162. WA_FREE(request->payload);
  163. WA_FREE(request);
  164. }
  165. void response_cleaner(response_t * response)
  166. {
  167. if (response->payload != NULL && response->payload_len > 0)
  168. WA_FREE(response->payload);
  169. WA_FREE(response);
  170. }
  171. response_t * clone_response(response_t * response)
  172. {
  173. response_t *clone = (response_t *) WA_MALLOC(sizeof(response_t));
  174. if (clone == NULL)
  175. return NULL;
  176. memset(clone, 0, sizeof(*clone));
  177. clone->fmt = response->fmt;
  178. clone->mid = response->mid;
  179. clone->status = response->status;
  180. clone->reciever = response->reciever;
  181. clone->payload_len = response->payload_len;
  182. if (clone->payload_len) {
  183. clone->payload = (char *) WA_MALLOC(response->payload_len);
  184. if (!clone->payload)
  185. goto fail;
  186. memcpy(clone->payload, response->payload, response->payload_len);
  187. } else {
  188. // when payload_len is 0, the payload may be used for carrying some handle or integer
  189. clone->payload = response->payload;
  190. }
  191. return clone;
  192. fail:
  193. response_cleaner(clone);
  194. return NULL;
  195. }
  196. response_t * set_response(response_t * response, int status, int fmt,
  197. const char *payload, int payload_len)
  198. {
  199. response->payload = (void *)payload;
  200. response->payload_len = payload_len;
  201. response->status = status;
  202. response->fmt = fmt;
  203. return response;
  204. }
  205. response_t * make_response_for_request(request_t * request,
  206. response_t * response)
  207. {
  208. response->mid = request->mid;
  209. response->reciever = request->sender;
  210. return response;
  211. }
  212. request_t * init_request(request_t * request, char *url, int action, int fmt,
  213. void *payload, int payload_len)
  214. {
  215. static unsigned int mid = 0;
  216. request->url = url;
  217. request->action = action;
  218. request->fmt = fmt;
  219. request->payload = payload;
  220. request->payload_len = payload_len;
  221. request->mid = ++mid;
  222. return request;
  223. }
  224. /*
  225. check if the "url" is starting with "leading_str"
  226. return: 0 - not match; >0 - the offset of matched url, include any "/" at the end
  227. notes:
  228. 1. it ensures the leading_str "/abc" can pass "/abc/cde" and "/abc/, but fail "/ab" and "/abcd".
  229. leading_str "/abc/" can pass "/abc"
  230. 2. it omit the '/' at the first char
  231. 3. it ensure the leading_str "/abc" can pass "/abc?cde
  232. */
  233. int check_url_start(const char* url, int url_len, const char * leading_str)
  234. {
  235. int offset = 0;
  236. if (*leading_str == '/')
  237. leading_str++;
  238. if (url_len > 0 && *url == '/') {
  239. url_len--;
  240. url++;
  241. offset++;
  242. }
  243. int len = strlen(leading_str);
  244. if (len == 0)
  245. return 0;
  246. // ensure leading_str not end with "/"
  247. if (leading_str[len - 1] == '/') {
  248. len--;
  249. if (len == 0)
  250. return 0;
  251. }
  252. // equal length
  253. if (url_len == len) {
  254. if (memcmp(url, leading_str, url_len) == 0) {
  255. return (offset + len);
  256. } else {
  257. return 0;
  258. }
  259. }
  260. if (url_len < len)
  261. return 0;
  262. else if (memcmp(url, leading_str, len) != 0)
  263. return 0;
  264. else if (url[len] != '/' && url[len] != '?')
  265. return 0;
  266. else
  267. return (offset + len + 1);
  268. }
  269. // * @pattern:
  270. // * sample 1: /abcd, match /abcd only
  271. // * sample 2: /abcd/ match match "/abcd" and "/abcd/*"
  272. // * sample 3: /abcd*, match any url started with "/abcd"
  273. // * sample 4: /abcd/*, exclude "/abcd"
  274. bool match_url(char * pattern, char * matched)
  275. {
  276. if (*pattern == '/')
  277. pattern++;
  278. if (*matched == '/')
  279. matched++;
  280. int matched_len = strlen(matched);
  281. if (matched_len == 0)
  282. return false;
  283. if (matched[matched_len - 1] == '/') {
  284. matched_len--;
  285. if (matched_len == 0)
  286. return false;
  287. }
  288. int len = strlen(pattern);
  289. if (len == 0)
  290. return false;
  291. if (pattern[len - 1] == '/') {
  292. len--;
  293. if (strncmp(pattern, matched, len) != 0)
  294. return false;
  295. if (len == matched_len)
  296. return true;
  297. if (matched_len > len && matched[len] == '/')
  298. return true;
  299. return false;
  300. } else if (pattern[len - 1] == '*') {
  301. if (pattern[len - 2] == '/') {
  302. if (strncmp(pattern, matched, len - 1) == 0)
  303. return true;
  304. else
  305. return false;
  306. } else {
  307. return (strncmp(pattern, matched, len - 1) == 0);
  308. }
  309. } else {
  310. return (strcmp(pattern, matched) == 0);
  311. }
  312. }
  313. /*
  314. * get the value of the key from following format buffer:
  315. * key1=value1;key2=value2;key3=value3
  316. */
  317. char * find_key_value(char * buffer, int buffer_len, char * key, char * value,
  318. int value_len, char delimiter)
  319. {
  320. char * p = buffer;
  321. int remaining = buffer_len;
  322. int key_len = strlen(key);
  323. while (*p != 0 && remaining > 0) {
  324. while (*p == ' ' || *p == delimiter) {
  325. p++;
  326. remaining--;
  327. }
  328. if (remaining <= key_len)
  329. return NULL;
  330. // find the key
  331. if (0 == strncmp(p, key, key_len) && p[key_len] == '=') {
  332. p += (key_len + 1);
  333. remaining -= (key_len + 1);
  334. char * v = value;
  335. memset(value, 0, value_len);
  336. value_len--; // ensure last char is 0
  337. while (*p != delimiter && remaining > 0 && value_len > 0) {
  338. *v++ = *p++;
  339. remaining--;
  340. value_len--;
  341. }
  342. return value;
  343. }
  344. // goto next key
  345. while (*p != delimiter && remaining > 0) {
  346. p++;
  347. remaining--;
  348. }
  349. }
  350. return NULL;
  351. }