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