uri.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /* uri.c -- helper functions for URI treatment
  2. */
  3. #include "c_stdio.h"
  4. #include "c_stdlib.h"
  5. #include "c_string.h"
  6. #include "c_ctype.h"
  7. #include "coap.h"
  8. #include "uri.h"
  9. #ifndef assert
  10. // #warning "assertions are disabled"
  11. # define assert(x) do { \
  12. if(!x) NODE_ERR("uri.c assert!\n"); \
  13. } while (0)
  14. #endif
  15. /**
  16. * A length-safe version of strchr(). This function returns a pointer
  17. * to the first occurrence of @p c in @p s, or @c NULL if not found.
  18. *
  19. * @param s The string to search for @p c.
  20. * @param len The length of @p s.
  21. * @param c The character to search.
  22. *
  23. * @return A pointer to the first occurence of @p c, or @c NULL
  24. * if not found.
  25. */
  26. static inline unsigned char *
  27. strnchr(unsigned char *s, size_t len, unsigned char c) {
  28. while (len && *s++ != c)
  29. --len;
  30. return len ? s : NULL;
  31. }
  32. int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
  33. unsigned char *p, *q;
  34. int secure = 0, res = 0;
  35. if (!str_var || !uri)
  36. return -1;
  37. c_memset(uri, 0, sizeof(coap_uri_t));
  38. uri->port = COAP_DEFAULT_PORT;
  39. /* search for scheme */
  40. p = str_var;
  41. if (*p == '/') {
  42. q = p;
  43. goto path;
  44. }
  45. q = (unsigned char *)COAP_DEFAULT_SCHEME;
  46. while (len && *q && tolower(*p) == *q) {
  47. ++p; ++q; --len;
  48. }
  49. /* If q does not point to the string end marker '\0', the schema
  50. * identifier is wrong. */
  51. if (*q) {
  52. res = -1;
  53. goto error;
  54. }
  55. /* There might be an additional 's', indicating the secure version: */
  56. if (len && (secure = tolower(*p) == 's')) {
  57. ++p; --len;
  58. }
  59. q = (unsigned char *)"://";
  60. while (len && *q && tolower(*p) == *q) {
  61. ++p; ++q; --len;
  62. }
  63. if (*q) {
  64. res = -2;
  65. goto error;
  66. }
  67. /* p points to beginning of Uri-Host */
  68. q = p;
  69. if (len && *p == '[') { /* IPv6 address reference */
  70. ++p;
  71. while (len && *q != ']') {
  72. ++q; --len;
  73. }
  74. if (!len || *q != ']' || p == q) {
  75. res = -3;
  76. goto error;
  77. }
  78. COAP_SET_STR(&uri->host, q - p, p);
  79. ++q; --len;
  80. } else { /* IPv4 address or FQDN */
  81. while (len && *q != ':' && *q != '/' && *q != '?') {
  82. *q = tolower(*q);
  83. ++q;
  84. --len;
  85. }
  86. if (p == q) {
  87. res = -3;
  88. goto error;
  89. }
  90. COAP_SET_STR(&uri->host, q - p, p);
  91. }
  92. /* check for Uri-Port */
  93. if (len && *q == ':') {
  94. p = ++q;
  95. --len;
  96. while (len && isdigit(*q)) {
  97. ++q;
  98. --len;
  99. }
  100. if (p < q) { /* explicit port number given */
  101. int uri_port = 0;
  102. while (p < q)
  103. uri_port = uri_port * 10 + (*p++ - '0');
  104. uri->port = uri_port;
  105. }
  106. }
  107. path: /* at this point, p must point to an absolute path */
  108. if (!len)
  109. goto end;
  110. if (*q == '/') {
  111. p = ++q;
  112. --len;
  113. while (len && *q != '?') {
  114. ++q;
  115. --len;
  116. }
  117. if (p < q) {
  118. COAP_SET_STR(&uri->path, q - p, p);
  119. p = q;
  120. }
  121. }
  122. /* Uri_Query */
  123. if (len && *p == '?') {
  124. ++p;
  125. --len;
  126. COAP_SET_STR(&uri->query, len, p);
  127. len = 0;
  128. }
  129. end:
  130. return len ? -1 : 0;
  131. error:
  132. return res;
  133. }
  134. /**
  135. * Calculates decimal value from hexadecimal ASCII character given in
  136. * @p c. The caller must ensure that @p c actually represents a valid
  137. * heaxdecimal character, e.g. with isxdigit(3).
  138. *
  139. * @hideinitializer
  140. */
  141. #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
  142. /**
  143. * Decodes percent-encoded characters while copying the string @p seg
  144. * of size @p length to @p buf. The caller of this function must
  145. * ensure that the percent-encodings are correct (i.e. the character
  146. * '%' is always followed by two hex digits. and that @p buf provides
  147. * sufficient space to hold the result. This function is supposed to
  148. * be called by make_decoded_option() only.
  149. *
  150. * @param seg The segment to decode and copy.
  151. * @param length Length of @p seg.
  152. * @param buf The result buffer.
  153. */
  154. void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
  155. while (length--) {
  156. if (*seg == '%') {
  157. *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
  158. seg += 2; length -= 2;
  159. } else {
  160. *buf = *seg;
  161. }
  162. ++buf; ++seg;
  163. }
  164. }
  165. /**
  166. * Runs through the given path (or query) segment and checks if
  167. * percent-encodings are correct. This function returns @c -1 on error
  168. * or the length of @p s when decoded.
  169. */
  170. int check_segment(const unsigned char *s, size_t length) {
  171. size_t n = 0;
  172. while (length) {
  173. if (*s == '%') {
  174. if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
  175. return -1;
  176. s += 2;
  177. length -= 2;
  178. }
  179. ++s; ++n; --length;
  180. }
  181. return n;
  182. }
  183. /**
  184. * Writes a coap option from given string @p s to @p buf. @p s should
  185. * point to a (percent-encoded) path or query segment of a coap_uri_t
  186. * object. The created option will have type @c 0, and the length
  187. * parameter will be set according to the size of the decoded string.
  188. * On success, this function returns the option's size, or a value
  189. * less than zero on error. This function must be called from
  190. * coap_split_path_impl() only.
  191. *
  192. * @param s The string to decode.
  193. * @param length The size of the percent-encoded string @p s.
  194. * @param buf The buffer to store the new coap option.
  195. * @param buflen The maximum size of @p buf.
  196. *
  197. * @return The option's size, or @c -1 on error.
  198. *
  199. * @bug This function does not split segments that are bigger than 270
  200. * bytes.
  201. */
  202. int make_decoded_option(const unsigned char *s, size_t length,
  203. unsigned char *buf, size_t buflen) {
  204. int res;
  205. size_t written;
  206. if (!buflen) {
  207. NODE_DBG("make_decoded_option(): buflen is 0!\n");
  208. return -1;
  209. }
  210. res = check_segment(s, length);
  211. if (res < 0)
  212. return -1;
  213. /* write option header using delta 0 and length res */
  214. // written = coap_opt_setheader(buf, buflen, 0, res);
  215. written = coap_buildOptionHeader(0, res, buf, buflen);
  216. assert(written <= buflen);
  217. if (!written) /* encoding error */
  218. return -1;
  219. buf += written; /* advance past option type/length */
  220. buflen -= written;
  221. if (buflen < (size_t)res) {
  222. NODE_DBG("buffer too small for option\n");
  223. return -1;
  224. }
  225. decode_segment(s, length, buf);
  226. return written + res;
  227. }
  228. #ifndef min
  229. #define min(a,b) ((a) < (b) ? (a) : (b))
  230. #endif
  231. typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
  232. /**
  233. * Splits the given string into segments. You should call one of the
  234. * macros coap_split_path() or coap_split_query() instead.
  235. *
  236. * @param parse_iter The iterator used for tokenizing.
  237. * @param h A handler that is called with every token.
  238. * @param data Opaque data that is passed to @p h when called.
  239. *
  240. * @return The number of characters that have been parsed from @p s.
  241. */
  242. size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter,
  243. segment_handler_t h, void *data) {
  244. unsigned char *seg;
  245. size_t length;
  246. assert(parse_iter);
  247. assert(h);
  248. length = parse_iter->n;
  249. while ( (seg = coap_parse_next(parse_iter)) ) {
  250. /* any valid path segment is handled here: */
  251. h(seg, parse_iter->segment_length, data);
  252. }
  253. return length - (parse_iter->n - parse_iter->segment_length);
  254. }
  255. struct pkt_scr {
  256. coap_packet_t *pkt;
  257. coap_rw_buffer_t *scratch;
  258. int n;
  259. };
  260. void write_option(unsigned char *s, size_t len, void *data) {
  261. struct pkt_scr *state = (struct pkt_scr *)data;
  262. int res;
  263. assert(state);
  264. /* skip empty segments and those that consist of only one or two dots */
  265. if (memcmp(s, "..", min(len,2)) == 0)
  266. return;
  267. res = check_segment(s, len);
  268. if (res < 0){
  269. NODE_DBG("not a valid segment\n");
  270. return;
  271. }
  272. if (state->scratch->len < (size_t)res) {
  273. NODE_DBG("buffer too small for option\n");
  274. return;
  275. }
  276. decode_segment(s, len, state->scratch->p);
  277. if (res > 0) {
  278. state->pkt->opts[state->pkt->numopts].buf.p = state->scratch->p;
  279. state->pkt->opts[state->pkt->numopts].buf.len = res;
  280. state->scratch->p += res;
  281. state->scratch->len -= res;
  282. state->pkt->numopts++;
  283. state->n++;
  284. }
  285. }
  286. int coap_split_path(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const unsigned char *s, size_t length) {
  287. struct pkt_scr tmp = { pkt, scratch, 0 };
  288. coap_parse_iterator_t pi;
  289. coap_parse_iterator_init((unsigned char *)s, length,
  290. '/', (unsigned char *)"?#", 2, &pi);
  291. coap_split_path_impl(&pi, write_option, &tmp);
  292. int i;
  293. for(i=0;i<tmp.n;i++){
  294. pkt->opts[pkt->numopts - i - 1].num = COAP_OPTION_URI_PATH;
  295. }
  296. return tmp.n;
  297. }
  298. int coap_split_query(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const unsigned char *s, size_t length) {
  299. struct pkt_scr tmp = { pkt, scratch, 0 };
  300. coap_parse_iterator_t pi;
  301. coap_parse_iterator_init((unsigned char *)s, length,
  302. '&', (unsigned char *)"#", 1, &pi);
  303. coap_split_path_impl(&pi, write_option, &tmp);
  304. int i;
  305. for(i=0;i<tmp.n;i++){
  306. pkt->opts[pkt->numopts - i - 1].num = COAP_OPTION_URI_QUERY;
  307. }
  308. return tmp.n;
  309. }
  310. #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
  311. coap_uri_t * coap_new_uri(const unsigned char *uri, unsigned int length) {
  312. unsigned char *result;
  313. result = (unsigned char *)c_malloc(length + 1 + sizeof(coap_uri_t));
  314. if (!result)
  315. return NULL;
  316. c_memcpy(URI_DATA(result), uri, length);
  317. URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
  318. if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
  319. c_free(result);
  320. return NULL;
  321. }
  322. return (coap_uri_t *)result;
  323. }
  324. /* iterator functions */
  325. coap_parse_iterator_t * coap_parse_iterator_init(unsigned char *s, size_t n,
  326. unsigned char separator,
  327. unsigned char *delim, size_t dlen,
  328. coap_parse_iterator_t *pi) {
  329. assert(pi);
  330. assert(separator);
  331. pi->separator = separator;
  332. pi->delim = delim;
  333. pi->dlen = dlen;
  334. pi->pos = s;
  335. pi->n = n;
  336. pi->segment_length = 0;
  337. return pi;
  338. }
  339. unsigned char * coap_parse_next(coap_parse_iterator_t *pi) {
  340. unsigned char *p;
  341. if (!pi)
  342. return NULL;
  343. /* proceed to the next segment */
  344. pi->n -= pi->segment_length;
  345. pi->pos += pi->segment_length;
  346. pi->segment_length = 0;
  347. /* last segment? */
  348. if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos)) {
  349. pi->pos = NULL;
  350. return NULL;
  351. }
  352. /* skip following separator (the first segment might not have one) */
  353. if (*pi->pos == pi->separator) {
  354. ++pi->pos;
  355. --pi->n;
  356. }
  357. p = pi->pos;
  358. while (pi->segment_length < pi->n && *p != pi->separator &&
  359. !strnchr(pi->delim, pi->dlen, *p)) {
  360. ++p;
  361. ++pi->segment_length;
  362. }
  363. if (!pi->n) {
  364. pi->pos = NULL;
  365. pi->segment_length = 0;
  366. }
  367. return pi->pos;
  368. }