restful_utils.c 12 KB

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