restful_utils.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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 *
  38. pack_request(request_t *request, int *size)
  39. {
  40. int url_len = strlen(request->url) + 1;
  41. int len = REQUEST_PACKET_FIX_PART_LEN + url_len + request->payload_len;
  42. uint16 u16;
  43. uint32 u32;
  44. char *packet;
  45. if ((packet = (char*) WA_MALLOC(len)) == NULL)
  46. return NULL;
  47. /* TODO: ensure little endian for words and dwords */
  48. *packet = REQUES_PACKET_VER;
  49. *((uint8*) (packet + 1)) = request->action;
  50. u16 = htons(request->fmt);
  51. memcpy(packet + 2, &u16, 2);
  52. u32 = htonl(request->mid);
  53. memcpy(packet + 4, &u32, 4);
  54. u32 = htonl(request->sender);
  55. memcpy(packet + 8, &u32, 4);
  56. u16 = htons(url_len);
  57. memcpy(packet + 12, &u16, 2);
  58. u32 = htonl(request->payload_len);
  59. memcpy(packet + 14, &u32, 4);
  60. strcpy(packet + REQUEST_PACKET_URL_OFFSET, request->url);
  61. memcpy(packet + REQUEST_PACKET_URL_OFFSET + url_len, request->payload,
  62. request->payload_len);
  63. *size = len;
  64. return packet;
  65. }
  66. void
  67. free_req_resp_packet(char *packet)
  68. {
  69. WA_FREE(packet);
  70. }
  71. request_t *
  72. unpack_request(char *packet, int size, request_t *request)
  73. {
  74. uint16 url_len, u16;
  75. uint32 payload_len, u32;
  76. if (*packet != REQUES_PACKET_VER) {
  77. return NULL;
  78. }
  79. if (size < REQUEST_PACKET_FIX_PART_LEN) {
  80. return NULL;
  81. }
  82. memcpy(&u16, packet + 12, 2);
  83. url_len = ntohs(u16);
  84. memcpy(&u32, packet + 14, 4);
  85. payload_len = ntohl(u32);
  86. if (size != (REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) {
  87. return NULL;
  88. }
  89. if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) {
  90. return NULL;
  91. }
  92. request->action = *((uint8*) (packet + 1));
  93. memcpy(&u16, packet + 2, 2);
  94. request->fmt = ntohs(u16);
  95. memcpy(&u32, packet + 4, 4);
  96. request->mid = ntohl(u32);
  97. memcpy(&u32, packet + 8, 4);
  98. request->sender = ntohl(u32);
  99. request->payload_len = payload_len;
  100. request->url = REQUEST_PACKET_URL(packet);
  101. if (payload_len > 0)
  102. request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len;
  103. else
  104. request->payload = NULL;
  105. return request;
  106. }
  107. char *
  108. pack_response(response_t *response, int *size)
  109. {
  110. int len = RESPONSE_PACKET_FIX_PART_LEN + response->payload_len;
  111. uint16 u16;
  112. uint32 u32;
  113. char *packet;
  114. if ((packet = (char*) WA_MALLOC(len)) == NULL)
  115. return NULL;
  116. /* TODO: ensure little endian for words and dwords */
  117. *packet = REQUES_PACKET_VER;
  118. *((uint8*) (packet + 1)) = response->status;
  119. u16 = htons(response->fmt);
  120. memcpy(packet + 2, &u16, 2);
  121. u32 = htonl(response->mid);
  122. memcpy(packet + 4, &u32, 4);
  123. u32 = htonl(response->reciever);
  124. memcpy(packet + 8, &u32, 4);
  125. u32 = htonl(response->payload_len);
  126. memcpy(packet + 12, &u32, 4);
  127. memcpy(packet + RESPONSE_PACKET_FIX_PART_LEN, response->payload,
  128. response->payload_len);
  129. *size = len;
  130. return packet;
  131. }
  132. response_t *
  133. unpack_response(char *packet, int size, response_t *response)
  134. {
  135. uint16 u16;
  136. uint32 payload_len, u32;
  137. if (*packet != REQUES_PACKET_VER)
  138. return NULL;
  139. if (size < RESPONSE_PACKET_FIX_PART_LEN)
  140. return NULL;
  141. memcpy(&u32, packet + 12, 4);
  142. payload_len = ntohl(u32);
  143. if (size != (RESPONSE_PACKET_FIX_PART_LEN + payload_len))
  144. return NULL;
  145. response->status = *((uint8*) (packet + 1));
  146. memcpy(&u16, packet + 2, 2);
  147. response->fmt = ntohs(u16);
  148. memcpy(&u32, packet + 4, 4);
  149. response->mid = ntohl(u32);
  150. memcpy(&u32, packet + 8, 4);
  151. response->reciever = ntohl(u32);
  152. response->payload_len = payload_len;
  153. if (payload_len > 0)
  154. response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN;
  155. else
  156. response->payload = NULL;
  157. return response;
  158. }
  159. request_t *
  160. clone_request(request_t *request)
  161. {
  162. /* deep clone */
  163. request_t *req = (request_t *) WA_MALLOC(sizeof(request_t));
  164. if (req == NULL)
  165. return NULL;
  166. memset(req, 0, sizeof(*req));
  167. req->action = request->action;
  168. req->fmt = request->fmt;
  169. req->url = wa_strdup(request->url);
  170. req->sender = request->sender;
  171. req->mid = request->mid;
  172. if (req->url == NULL)
  173. goto fail;
  174. req->payload_len = request->payload_len;
  175. if (request->payload_len) {
  176. req->payload = (char *)WA_MALLOC(request->payload_len);
  177. if (!req->payload)
  178. goto fail;
  179. memcpy(req->payload, request->payload, request->payload_len);
  180. }
  181. else {
  182. /* when payload_len is 0, the payload may be used for
  183. carrying some handle or integer */
  184. req->payload = request->payload;
  185. }
  186. return req;
  187. fail:
  188. request_cleaner(req);
  189. return NULL;
  190. }
  191. void
  192. request_cleaner(request_t *request)
  193. {
  194. if (request->url != NULL)
  195. WA_FREE(request->url);
  196. if (request->payload != NULL && request->payload_len > 0)
  197. WA_FREE(request->payload);
  198. WA_FREE(request);
  199. }
  200. void
  201. response_cleaner(response_t *response)
  202. {
  203. if (response->payload != NULL && response->payload_len > 0)
  204. WA_FREE(response->payload);
  205. WA_FREE(response);
  206. }
  207. response_t *
  208. clone_response(response_t *response)
  209. {
  210. response_t *clone = (response_t *)WA_MALLOC(sizeof(response_t));
  211. if (clone == NULL)
  212. return NULL;
  213. memset(clone, 0, sizeof(*clone));
  214. clone->fmt = response->fmt;
  215. clone->mid = response->mid;
  216. clone->status = response->status;
  217. clone->reciever = response->reciever;
  218. clone->payload_len = response->payload_len;
  219. if (clone->payload_len) {
  220. clone->payload = (char *) WA_MALLOC(response->payload_len);
  221. if (!clone->payload)
  222. goto fail;
  223. memcpy(clone->payload, response->payload, response->payload_len);
  224. }
  225. else {
  226. /* when payload_len is 0, the payload may be used for
  227. carrying some handle or integer */
  228. clone->payload = response->payload;
  229. }
  230. return clone;
  231. fail:
  232. response_cleaner(clone);
  233. return NULL;
  234. }
  235. response_t *
  236. set_response(response_t *response, int status, int fmt,
  237. const char *payload, int payload_len)
  238. {
  239. response->payload = (void *)payload;
  240. response->payload_len = payload_len;
  241. response->status = status;
  242. response->fmt = fmt;
  243. return response;
  244. }
  245. response_t *
  246. make_response_for_request(request_t *request,
  247. response_t *response)
  248. {
  249. response->mid = request->mid;
  250. response->reciever = request->sender;
  251. return response;
  252. }
  253. static unsigned int mid = 0;
  254. request_t *
  255. init_request(request_t *request, char *url, int action, int fmt,
  256. void *payload, int payload_len)
  257. {
  258. request->url = url;
  259. request->action = action;
  260. request->fmt = fmt;
  261. request->payload = payload;
  262. request->payload_len = payload_len;
  263. request->mid = ++mid;
  264. return request;
  265. }
  266. /*
  267. check if the "url" is starting with "leading_str"
  268. return: 0 - not match; >0 - the offset of matched url, include any "/" at the end
  269. notes:
  270. 1. it ensures the leading_str "/abc" can pass "/abc/cde" and "/abc/, but fail "/ab" and "/abcd".
  271. leading_str "/abc/" can pass "/abc"
  272. 2. it omit the '/' at the first char
  273. 3. it ensure the leading_str "/abc" can pass "/abc?cde
  274. */
  275. int
  276. check_url_start(const char *url, int url_len, const char *leading_str)
  277. {
  278. int offset = 0;
  279. if (*leading_str == '/')
  280. leading_str++;
  281. if (url_len > 0 && *url == '/') {
  282. url_len--;
  283. url++;
  284. offset++;
  285. }
  286. int len = strlen(leading_str);
  287. if (len == 0)
  288. return 0;
  289. /* ensure leading_str not end with "/" */
  290. if (leading_str[len - 1] == '/') {
  291. len--;
  292. if (len == 0)
  293. return 0;
  294. }
  295. /* equal length */
  296. if (url_len == len) {
  297. if (memcmp(url, leading_str, url_len) == 0) {
  298. return (offset + len);
  299. }
  300. else {
  301. return 0;
  302. }
  303. }
  304. if (url_len < len)
  305. return 0;
  306. else if (memcmp(url, leading_str, len) != 0)
  307. return 0;
  308. else if (url[len] != '/' && url[len] != '?')
  309. return 0;
  310. else
  311. return (offset + len + 1);
  312. }
  313. // * @pattern:
  314. // * sample 1: /abcd, match /abcd only
  315. // * sample 2: /abcd/ match match "/abcd" and "/abcd/*"
  316. // * sample 3: /abcd*, match any url started with "/abcd"
  317. // * sample 4: /abcd/*, exclude "/abcd"
  318. bool
  319. match_url(char *pattern, char *matched)
  320. {
  321. if (*pattern == '/')
  322. pattern++;
  323. if (*matched == '/')
  324. matched++;
  325. int matched_len = strlen(matched);
  326. if (matched_len == 0)
  327. return false;
  328. if (matched[matched_len - 1] == '/') {
  329. matched_len--;
  330. if (matched_len == 0)
  331. return false;
  332. }
  333. int len = strlen(pattern);
  334. if (len == 0)
  335. return false;
  336. if (pattern[len - 1] == '/') {
  337. len--;
  338. if (strncmp(pattern, matched, len) != 0)
  339. return false;
  340. if (len == matched_len)
  341. return true;
  342. if (matched_len > len && matched[len] == '/')
  343. return true;
  344. return false;
  345. }
  346. else if (pattern[len - 1] == '*') {
  347. if (pattern[len - 2] == '/') {
  348. if (strncmp(pattern, matched, len - 1) == 0)
  349. return true;
  350. else
  351. return false;
  352. }
  353. else {
  354. return (strncmp(pattern, matched, len - 1) == 0);
  355. }
  356. }
  357. else {
  358. return (strcmp(pattern, matched) == 0);
  359. }
  360. }
  361. /*
  362. * get the value of the key from following format buffer:
  363. * key1=value1;key2=value2;key3=value3
  364. */
  365. char *
  366. find_key_value(char *buffer, int buffer_len, char *key, char *value,
  367. int value_len, char delimiter)
  368. {
  369. char *p = buffer;
  370. int remaining = buffer_len;
  371. int key_len = strlen(key);
  372. while (*p != 0 && remaining > 0) {
  373. while (*p == ' ' || *p == delimiter) {
  374. p++;
  375. remaining--;
  376. }
  377. if (remaining <= key_len)
  378. return NULL;
  379. /* find the key */
  380. if (0 == strncmp(p, key, key_len) && p[key_len] == '=') {
  381. p += (key_len + 1);
  382. remaining -= (key_len + 1);
  383. char * v = value;
  384. memset(value, 0, value_len);
  385. value_len--; /* ensure last char is 0 */
  386. while (*p != delimiter && remaining > 0 && value_len > 0) {
  387. *v++ = *p++;
  388. remaining--;
  389. value_len--;
  390. }
  391. return value;
  392. }
  393. /* goto next key */
  394. while (*p != delimiter && remaining > 0) {
  395. p++;
  396. remaining--;
  397. }
  398. }
  399. return NULL;
  400. }