restful_utils.c 12 KB

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