libcoap  4.1.2
uri.c
Go to the documentation of this file.
1 /* uri.c -- helper functions for URI treatment
2  *
3  * Copyright (C) 2010--2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_config.h"
10 
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14 
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18 
19 #include "mem.h"
20 #include "debug.h"
21 #include "pdu.h"
22 #include "option.h"
23 #include "uri.h"
24 
36 static inline unsigned char *
37 strnchr(unsigned char *s, size_t len, unsigned char c) {
38  while (len && *s++ != c)
39  --len;
40 
41  return len ? s : NULL;
42 }
43 
44 #define ISEQUAL_CI(a,b) \
45  ((a) == (b) || (islower(b) && ((a) == ((b) - 0x20))))
46 
47 int
48 coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri) {
49  const unsigned char *p, *q;
50  int secure = 0, res = 0;
51 
52  if (!str_var || !uri)
53  return -1;
54 
55  memset(uri, 0, sizeof(coap_uri_t));
56  uri->port = COAP_DEFAULT_PORT;
57 
58  /* search for scheme */
59  p = str_var;
60  if (*p == '/') {
61  q = p;
62  goto path;
63  }
64 
65  q = (unsigned char *)COAP_DEFAULT_SCHEME;
66  while (len && *q && ISEQUAL_CI(*p, *q)) {
67  ++p; ++q; --len;
68  }
69 
70  /* If q does not point to the string end marker '\0', the schema
71  * identifier is wrong. */
72  if (*q) {
73  res = -1;
74  goto error;
75  }
76 
77  /* There might be an additional 's', indicating the secure version: */
78  if (len && (secure = *p == 's')) {
79  ++p; --len;
80  }
81 
82  q = (unsigned char *)"://";
83  while (len && *q && *p == *q) {
84  ++p; ++q; --len;
85  }
86 
87  if (*q) {
88  res = -2;
89  goto error;
90  }
91 
92  /* p points to beginning of Uri-Host */
93  q = p;
94  if (len && *p == '[') { /* IPv6 address reference */
95  ++p;
96 
97  while (len && *q != ']') {
98  ++q; --len;
99  }
100 
101  if (!len || *q != ']' || p == q) {
102  res = -3;
103  goto error;
104  }
105 
106  COAP_SET_STR(&uri->host, q - p, (unsigned char *)p);
107  ++q; --len;
108  } else { /* IPv4 address or FQDN */
109  while (len && *q != ':' && *q != '/' && *q != '?') {
110  ++q;
111  --len;
112  }
113 
114  if (p == q) {
115  res = -3;
116  goto error;
117  }
118 
119  COAP_SET_STR(&uri->host, q - p, (unsigned char *)p);
120  }
121 
122  /* check for Uri-Port */
123  if (len && *q == ':') {
124  p = ++q;
125  --len;
126 
127  while (len && isdigit(*q)) {
128  ++q;
129  --len;
130  }
131 
132  if (p < q) { /* explicit port number given */
133  int uri_port = 0;
134 
135  while (p < q)
136  uri_port = uri_port * 10 + (*p++ - '0');
137 
138  /* check if port number is in allowed range */
139  if (uri_port > 65535) {
140  res = -4;
141  goto error;
142  }
143 
144  uri->port = uri_port;
145  }
146  }
147 
148  path: /* at this point, p must point to an absolute path */
149 
150  if (!len)
151  goto end;
152 
153  if (*q == '/') {
154  p = ++q;
155  --len;
156 
157  while (len && *q != '?') {
158  ++q;
159  --len;
160  }
161 
162  if (p < q) {
163  COAP_SET_STR(&uri->path, q - p, (unsigned char *)p);
164  p = q;
165  }
166  }
167 
168  /* Uri_Query */
169  if (len && *p == '?') {
170  ++p;
171  --len;
172  COAP_SET_STR(&uri->query, len, (unsigned char *)p);
173  len = 0;
174  }
175 
176  end:
177  return len ? -1 : 0;
178 
179  error:
180  return res;
181 }
182 
190 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
191 
204 static void
205 decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
206 
207  while (length--) {
208 
209  if (*seg == '%') {
210  *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
211 
212  seg += 2; length -= 2;
213  } else {
214  *buf = *seg;
215  }
216 
217  ++buf; ++seg;
218  }
219 }
220 
226 static int
227 check_segment(const unsigned char *s, size_t length) {
228 
229  size_t n = 0;
230 
231  while (length) {
232  if (*s == '%') {
233  if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
234  return -1;
235 
236  s += 2;
237  length -= 2;
238  }
239 
240  ++s; ++n; --length;
241  }
242 
243  return n;
244 }
245 
265 static int
266 make_decoded_option(const unsigned char *s, size_t length,
267  unsigned char *buf, size_t buflen) {
268  int res;
269  size_t written;
270 
271  if (!buflen) {
272  debug("make_decoded_option(): buflen is 0!\n");
273  return -1;
274  }
275 
276  res = check_segment(s, length);
277  if (res < 0)
278  return -1;
279 
280  /* write option header using delta 0 and length res */
281  written = coap_opt_setheader(buf, buflen, 0, res);
282 
283  assert(written <= buflen);
284 
285  if (!written) /* encoding error */
286  return -1;
287 
288  buf += written; /* advance past option type/length */
289  buflen -= written;
290 
291  if (buflen < (size_t)res) {
292  debug("buffer too small for option\n");
293  return -1;
294  }
295 
296  decode_segment(s, length, buf);
297 
298  return written + res;
299 }
300 
301 
302 #ifndef min
303 #define min(a,b) ((a) < (b) ? (a) : (b))
304 #endif
305 
306 typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
307 
311 static inline int
312 dots(unsigned char *s, size_t len) {
313  return *s == '.' && (len == 1 || (*(s+1) == '.' && len == 2));
314 }
315 
327 static size_t
328 coap_split_path_impl(const unsigned char *s, size_t length,
329  segment_handler_t h, void *data) {
330 
331  const unsigned char *p, *q;
332 
333  p = q = s;
334  while (length > 0 && !strnchr((unsigned char *)"?#", 2, *q)) {
335  if (*q == '/') { /* start new segment */
336 
337  if (!dots((unsigned char *)p, q - p)) {
338  h((unsigned char *)p, q - p, data);
339  }
340 
341  p = q + 1;
342  }
343 
344  q++;
345  length--;
346  }
347 
348  /* write last segment */
349  if (!dots((unsigned char *)p, q - p)) {
350  h((unsigned char *)p, q - p, data);
351  }
352 
353  return q - s;
354 }
355 
356 struct cnt_str {
358  int n;
359 };
360 
361 static void
362 write_option(unsigned char *s, size_t len, void *data) {
363  struct cnt_str *state = (struct cnt_str *)data;
364  int res;
365  assert(state);
366 
367  res = make_decoded_option(s, len, state->buf.s, state->buf.length);
368  if (res > 0) {
369  state->buf.s += res;
370  state->buf.length -= res;
371  state->n++;
372  }
373 }
374 
375 int
376 coap_split_path(const unsigned char *s, size_t length,
377  unsigned char *buf, size_t *buflen) {
378  struct cnt_str tmp = { { *buflen, buf }, 0 };
379 
380  coap_split_path_impl(s, length, write_option, &tmp);
381 
382  *buflen = *buflen - tmp.buf.length;
383 
384  return tmp.n;
385 }
386 
387 int
388 coap_split_query(const unsigned char *s, size_t length,
389  unsigned char *buf, size_t *buflen) {
390  struct cnt_str tmp = { { *buflen, buf }, 0 };
391  const unsigned char *p;
392 
393  p = s;
394  while (length > 0 && *s != '#') {
395  if (*s == '&') { /* start new query element */
396  write_option((unsigned char *)p, s - p, &tmp);
397  p = s + 1;
398  }
399 
400  s++;
401  length--;
402  }
403 
404  /* write last query element */
405  write_option((unsigned char *)p, s - p, &tmp);
406 
407  *buflen = *buflen - tmp.buf.length;
408  return tmp.n;
409 }
410 
411 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
412 
413 coap_uri_t *
414 coap_new_uri(const unsigned char *uri, unsigned int length) {
415  unsigned char *result;
416 
417  result = coap_malloc(length + 1 + sizeof(coap_uri_t));
418 
419  if (!result)
420  return NULL;
421 
422  memcpy(URI_DATA(result), uri, length);
423  URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
424 
425  if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
426  coap_free(result);
427  return NULL;
428  }
429  return (coap_uri_t *)result;
430 }
431 
432 coap_uri_t *
434  coap_uri_t *result;
435 
436  if ( !uri )
437  return NULL;
438 
439  result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
440  uri->path.length + sizeof(coap_uri_t) + 1);
441 
442  if ( !result )
443  return NULL;
444 
445  memset( result, 0, sizeof(coap_uri_t) );
446 
447  result->port = uri->port;
448 
449  if ( uri->host.length ) {
450  result->host.s = URI_DATA(result);
451  result->host.length = uri->host.length;
452 
453  memcpy(result->host.s, uri->host.s, uri->host.length);
454  }
455 
456  if ( uri->path.length ) {
457  result->path.s = URI_DATA(result) + uri->host.length;
458  result->path.length = uri->path.length;
459 
460  memcpy(result->path.s, uri->path.s, uri->path.length);
461  }
462 
463  if ( uri->query.length ) {
464  result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
465  result->query.length = uri->query.length;
466 
467  memcpy(result->query.s, uri->query.s, uri->query.length);
468  }
469 
470  return result;
471 }
472 
473 /* hash URI path segments */
474 
475 /* The function signature of coap_hash() is different from
476  * segment_handler_t hence we use this wrapper as safe typecast. */
477 static inline void
478 hash_segment(unsigned char *s, size_t len, void *data) {
479  coap_hash(s, len, data);
480 }
481 
482 int
483 coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
484  if (!path)
485  return 0;
486 
487  memset(key, 0, sizeof(coap_key_t));
488 
489  coap_split_path_impl(path, len, hash_segment, key);
490 
491  return 1;
492 }
void(* segment_handler_t)(unsigned char *, size_t, void *)
Definition: uri.c:306
Representation of parsed URI.
Definition: uri.h:20
str query
The query part if present.
Definition: uri.h:25
static void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf)
Decodes percent-encoded characters while copying the string seg of size length to buf...
Definition: uri.c:205
unsigned char coap_key_t[4]
Definition: hashkey.h:20
#define URI_DATA(uriobj)
Definition: uri.c:411
static void write_option(unsigned char *s, size_t len, void *data)
Definition: uri.c:362
static int check_segment(const unsigned char *s, size_t length)
Runs through the given path (or query) segment and checks if percent-encodings are correct...
Definition: uri.c:227
static void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:70
str host
host part of the URI
Definition: uri.h:21
str path
Beginning of the first path segment.
Definition: uri.h:23
Definition: uri.c:356
size_t length
Definition: str.h:16
Helpers for handling options in CoAP PDUs.
int coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition: uri.c:48
unsigned short port
The port in host byte order.
Definition: uri.h:22
#define COAP_SET_STR(st, l, v)
Definition: str.h:20
str buf
Definition: uri.c:357
#define debug(...)
Definition: debug.h:66
static unsigned char * strnchr(unsigned char *s, size_t len, unsigned char c)
A length-safe version of strchr().
Definition: uri.c:37
#define ISEQUAL_CI(a, b)
Definition: uri.c:44
static void hash_segment(unsigned char *s, size_t len, void *data)
Definition: uri.c:478
#define assert(...)
Definition: mem.c:17
coap_uri_t * coap_new_uri(const unsigned char *uri, unsigned int length)
Creates a new coap_uri_t object from the specified URI.
Definition: uri.c:414
static size_t coap_split_path_impl(const unsigned char *s, size_t length, segment_handler_t h, void *data)
Splits the given string into segments.
Definition: uri.c:328
int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
Splits the given URI path into segments.
Definition: uri.c:376
#define coap_hash(String, Length, Result)
Definition: hashkey.h:34
#define COAP_DEFAULT_SCHEME
Definition: pdu.h:31
#define COAP_DEFAULT_PORT
Definition: pdu.h:24
Pre-defined constants that reflect defaults for CoAP.
static int dots(unsigned char *s, size_t len)
Checks if path segment s consists of one or two dots.
Definition: uri.c:312
int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key)
Calculates a hash over the given path and stores the result in key.
Definition: uri.c:483
Definition: str.h:15
coap_uri_t * coap_clone_uri(const coap_uri_t *uri)
Clones the specified coap_uri_t object.
Definition: uri.c:433
int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
Splits the given URI query into segments.
Definition: uri.c:388
static void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:77
size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
Encodes the given delta and length values into opt.
Definition: option.c:329
int n
Definition: uri.c:358
unsigned char * s
Definition: str.h:17
static int make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen)
Writes a coap option from given string s to buf.
Definition: uri.c:266
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition: uri.c:190