restful_utils.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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 "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: request_cleaner(req);
  159. return NULL;
  160. }
  161. void request_cleaner(request_t *request)
  162. {
  163. if (request->url != NULL)
  164. wa_free(request->url);
  165. if (request->payload != NULL && request->payload_len > 0)
  166. wa_free(request->payload);
  167. wa_free(request);
  168. }
  169. void response_cleaner(response_t * response)
  170. {
  171. if (response->payload != NULL && response->payload_len > 0)
  172. wa_free(response->payload);
  173. wa_free(response);
  174. }
  175. response_t * clone_response(response_t * response)
  176. {
  177. response_t *clone = (response_t *) wa_malloc(sizeof(response_t));
  178. if (clone == NULL)
  179. return NULL;
  180. memset(clone, 0, sizeof(*clone));
  181. clone->fmt = response->fmt;
  182. clone->mid = response->mid;
  183. clone->status = response->status;
  184. clone->reciever = response->reciever;
  185. clone->payload_len = response->payload_len;
  186. if (clone->payload_len) {
  187. clone->payload = (char *) wa_malloc(response->payload_len);
  188. if (!clone->payload)
  189. goto fail;
  190. memcpy(clone->payload, response->payload, response->payload_len);
  191. } else {
  192. // when payload_len is 0, the payload may be used for carrying some handle or integer
  193. clone->payload = response->payload;
  194. }
  195. return clone;
  196. fail: response_cleaner(clone);
  197. return NULL;
  198. }
  199. response_t * set_response(response_t * response, int status, int fmt,
  200. const char *payload, int payload_len)
  201. {
  202. response->payload = (void *)payload;
  203. response->payload_len = payload_len;
  204. response->status = status;
  205. response->fmt = fmt;
  206. return response;
  207. }
  208. response_t * make_response_for_request(request_t * request,
  209. response_t * response)
  210. {
  211. response->mid = request->mid;
  212. response->reciever = request->sender;
  213. return response;
  214. }
  215. request_t * init_request(request_t * request, char *url, int action, int fmt,
  216. void *payload, int payload_len)
  217. {
  218. static unsigned int mid = 0;
  219. request->url = url;
  220. request->action = action;
  221. request->fmt = fmt;
  222. request->payload = payload;
  223. request->payload_len = payload_len;
  224. request->mid = ++mid;
  225. return request;
  226. }
  227. /*
  228. check if the "url" is starting with "leading_str"
  229. return: 0 - not match; >0 - the offset of matched url, include any "/" at the end
  230. notes:
  231. 1. it ensures the leading_str "/abc" can pass "/abc/cde" and "/abc/, but fail "/ab" and "/abcd".
  232. leading_str "/abc/" can pass "/abc"
  233. 2. it omit the '/' at the first char
  234. 3. it ensure the leading_str "/abc" can pass "/abc?cde
  235. */
  236. int check_url_start(const char* url, int url_len, const char * leading_str)
  237. {
  238. int offset = 0;
  239. if (*leading_str == '/')
  240. leading_str++;
  241. if (url_len > 0 && *url == '/') {
  242. url_len--;
  243. url++;
  244. offset++;
  245. }
  246. int len = strlen(leading_str);
  247. if (len == 0)
  248. return 0;
  249. // ensure leading_str not end with "/"
  250. if (leading_str[len - 1] == '/') {
  251. len--;
  252. if (len == 0)
  253. return 0;
  254. }
  255. // equal length
  256. if (url_len == len) {
  257. if (memcmp(url, leading_str, url_len) == 0) {
  258. return (offset + len);
  259. } else {
  260. return 0;
  261. }
  262. }
  263. if (url_len < len)
  264. return 0;
  265. else if (memcmp(url, leading_str, len) != 0)
  266. return 0;
  267. else if (url[len] != '/' && url[len] != '?')
  268. return 0;
  269. else
  270. return (offset + len + 1);
  271. }
  272. // * @pattern:
  273. // * sample 1: /abcd, match /abcd only
  274. // * sample 2: /abcd/ match match "/abcd" and "/abcd/*"
  275. // * sample 3: /abcd*, match any url started with "/abcd"
  276. // * sample 4: /abcd/*, exclude "/abcd"
  277. bool match_url(char * pattern, char * matched)
  278. {
  279. if (*pattern == '/')
  280. pattern++;
  281. if (*matched == '/')
  282. matched++;
  283. int matched_len = strlen(matched);
  284. if (matched_len == 0)
  285. return false;
  286. if (matched[matched_len - 1] == '/') {
  287. matched_len--;
  288. if (matched_len == 0)
  289. return false;
  290. }
  291. int len = strlen(pattern);
  292. if (len == 0)
  293. return false;
  294. if (pattern[len - 1] == '/') {
  295. len--;
  296. if (strncmp(pattern, matched, len) != 0)
  297. return false;
  298. if (len == matched_len)
  299. return true;
  300. if (matched_len > len && matched[len] == '/')
  301. return true;
  302. return false;
  303. } else if (pattern[len - 1] == '*') {
  304. if (pattern[len - 2] == '/') {
  305. if (strncmp(pattern, matched, len - 1) == 0)
  306. return true;
  307. else
  308. return false;
  309. } else {
  310. return (strncmp(pattern, matched, len - 1) == 0);
  311. }
  312. } else {
  313. return (strcmp(pattern, matched) == 0);
  314. }
  315. }
  316. /*
  317. * get the value of the key from following format buffer:
  318. * key1=value1;key2=value2;key3=value3
  319. */
  320. char * find_key_value(char * buffer, int buffer_len, char * key, char * value,
  321. int value_len, char delimiter)
  322. {
  323. char * p = buffer;
  324. int remaining = buffer_len;
  325. int key_len = strlen(key);
  326. while (*p != 0 && remaining > 0) {
  327. while (*p == ' ' || *p == delimiter) {
  328. p++;
  329. remaining--;
  330. }
  331. if (remaining <= key_len)
  332. return NULL;
  333. // find the key
  334. if (0 == strncmp(p, key, key_len) && p[key_len] == '=') {
  335. p += (key_len + 1);
  336. remaining -= (key_len + 1);
  337. char * v = value;
  338. memset(value, 0, value_len);
  339. value_len--; // ensure last char is 0
  340. while (*p != delimiter && remaining > 0 && value_len > 0) {
  341. *v++ = *p++;
  342. remaining--;
  343. value_len--;
  344. }
  345. return value;
  346. }
  347. // goto next key
  348. while (*p != delimiter && remaining > 0) {
  349. p++;
  350. remaining--;
  351. }
  352. }
  353. return NULL;
  354. }