libcoap  4.1.1
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
uri.c
Go to the documentation of this file.
1 /* uri.c -- helper functions for URI treatment
2  *
3  * Copyright (C) 2010--2012 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 "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  uri->port = uri_port;
137  }
138  }
139 
140  path: /* at this point, p must point to an absolute path */
141 
142  if (!len)
143  goto end;
144 
145  if (*q == '/') {
146  p = ++q;
147  --len;
148 
149  while (len && *q != '?') {
150  ++q;
151  --len;
152  }
153 
154  if (p < q) {
155  COAP_SET_STR(&uri->path, q - p, p);
156  p = q;
157  }
158  }
159 
160  /* Uri_Query */
161  if (len && *p == '?') {
162  ++p;
163  --len;
164  COAP_SET_STR(&uri->query, len, p);
165  len = 0;
166  }
167 
168  end:
169  return len ? -1 : 0;
170 
171  error:
172  return res;
173 }
174 
182 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
183 
196 void
197 decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
198 
199  while (length--) {
200 
201  if (*seg == '%') {
202  *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
203 
204  seg += 2; length -= 2;
205  } else {
206  *buf = *seg;
207  }
208 
209  ++buf; ++seg;
210  }
211 }
212 
218 int
219 check_segment(const unsigned char *s, size_t length) {
220 
221  size_t n = 0;
222 
223  while (length) {
224  if (*s == '%') {
225  if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
226  return -1;
227 
228  s += 2;
229  length -= 2;
230  }
231 
232  ++s; ++n; --length;
233  }
234 
235  return n;
236 }
237 
257 int
258 make_decoded_option(const unsigned char *s, size_t length,
259  unsigned char *buf, size_t buflen) {
260  int res;
261  size_t written;
262 
263  if (!buflen) {
264  debug("make_decoded_option(): buflen is 0!\n");
265  return -1;
266  }
267 
268  res = check_segment(s, length);
269  if (res < 0)
270  return -1;
271 
272  /* write option header using delta 0 and length res */
273  written = coap_opt_setheader(buf, buflen, 0, res);
274 
275  assert(written <= buflen);
276 
277  if (!written) /* encoding error */
278  return -1;
279 
280  buf += written; /* advance past option type/length */
281  buflen -= written;
282 
283  if (buflen < (size_t)res) {
284  debug("buffer too small for option\n");
285  return -1;
286  }
287 
288  decode_segment(s, length, buf);
289 
290  return written + res;
291 }
292 
293 
294 #ifndef min
295 #define min(a,b) ((a) < (b) ? (a) : (b))
296 #endif
297 
298 typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
299 
310 size_t
312  segment_handler_t h, void *data) {
313  unsigned char *seg;
314  size_t length;
315 
316  assert(parse_iter);
317  assert(h);
318 
319  length = parse_iter->n;
320 
321  while ( (seg = coap_parse_next(parse_iter)) ) {
322 
323  /* any valid path segment is handled here: */
324  h(seg, parse_iter->segment_length, data);
325  }
326 
327  return length - (parse_iter->n - parse_iter->segment_length);
328 }
329 
330 struct cnt_str {
332  int n;
333 };
334 
335 void
336 write_option(unsigned char *s, size_t len, void *data) {
337  struct cnt_str *state = (struct cnt_str *)data;
338  int res;
339  assert(state);
340 
341  /* skip empty segments and those that consist of only one or two dots */
342  if (memcmp(s, "..", min(len,2)) == 0)
343  return;
344 
345  res = make_decoded_option(s, len, state->buf.s, state->buf.length);
346  if (res > 0) {
347  state->buf.s += res;
348  state->buf.length -= res;
349  state->n++;
350  }
351 }
352 
353 int
354 coap_split_path(const unsigned char *s, size_t length,
355  unsigned char *buf, size_t *buflen) {
356  struct cnt_str tmp = { { *buflen, buf }, 0 };
358 
359  coap_parse_iterator_init((unsigned char *)s, length,
360  '/', (unsigned char *)"?#", 2, &pi);
362 
363  *buflen = *buflen - tmp.buf.length;
364  return tmp.n;
365 }
366 
367 int
368 coap_split_query(const unsigned char *s, size_t length,
369  unsigned char *buf, size_t *buflen) {
370  struct cnt_str tmp = { { *buflen, buf }, 0 };
372 
373  coap_parse_iterator_init((unsigned char *)s, length,
374  '&', (unsigned char *)"#", 1, &pi);
375 
377 
378  *buflen = tmp.buf.length;
379  return tmp.n;
380 }
381 
382 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
383 
384 coap_uri_t *
385 coap_new_uri(const unsigned char *uri, unsigned int length) {
386  unsigned char *result;
387 
388  result = coap_malloc(length + 1 + sizeof(coap_uri_t));
389 
390  if (!result)
391  return NULL;
392 
393  memcpy(URI_DATA(result), uri, length);
394  URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
395 
396  if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
397  free(result);
398  return NULL;
399  }
400  return (coap_uri_t *)result;
401 }
402 
403 coap_uri_t *
405  coap_uri_t *result;
406 
407  if ( !uri )
408  return NULL;
409 
410  result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
411  uri->path.length + sizeof(coap_uri_t) + 1);
412 
413  if ( !result )
414  return NULL;
415 
416  memset( result, 0, sizeof(coap_uri_t) );
417 
418  result->port = uri->port;
419 
420  if ( uri->host.length ) {
421  result->host.s = URI_DATA(result);
422  result->host.length = uri->host.length;
423 
424  memcpy(result->host.s, uri->host.s, uri->host.length);
425  }
426 
427  if ( uri->path.length ) {
428  result->path.s = URI_DATA(result) + uri->host.length;
429  result->path.length = uri->path.length;
430 
431  memcpy(result->path.s, uri->path.s, uri->path.length);
432  }
433 
434  if ( uri->query.length ) {
435  result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
436  result->query.length = uri->query.length;
437 
438  memcpy(result->query.s, uri->query.s, uri->query.length);
439  }
440 
441  return result;
442 }
443 
444 /* hash URI path segments */
445 
446 /* The function signature of coap_hash() is different from
447  * segment_handler_t hence we use this wrapper as safe typecast. */
448 static inline void
449 hash_segment(unsigned char *s, size_t len, void *data) {
450  coap_hash(s, len, data);
451 }
452 
453 int
454 coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
456 
457  if (!path)
458  return 0;
459 
460  memset(key, 0, sizeof(coap_key_t));
461 
462  coap_parse_iterator_init((unsigned char *)path, len,
463  '/', (unsigned char *)"?#", 2, &pi);
465 
466  return 1;
467 }
468 
469 /* iterator functions */
470 
472 coap_parse_iterator_init(unsigned char *s, size_t n,
473  unsigned char separator,
474  unsigned char *delim, size_t dlen,
475  coap_parse_iterator_t *pi) {
476  assert(pi);
477  assert(separator);
478 
479  pi->separator = separator;
480  pi->delim = delim;
481  pi->dlen = dlen;
482  pi->pos = s;
483  pi->n = n;
484  pi->segment_length = 0;
485 
486  return pi;
487 }
488 
489 unsigned char *
491  unsigned char *p;
492 
493  if (!pi)
494  return NULL;
495 
496  /* proceed to the next segment */
497  pi->n -= pi->segment_length;
498  pi->pos += pi->segment_length;
499  pi->segment_length = 0;
500 
501  /* last segment? */
502  if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos)) {
503  pi->pos = NULL;
504  return NULL;
505  }
506 
507  /* skip following separator (the first segment might not have one) */
508  if (*pi->pos == pi->separator) {
509  ++pi->pos;
510  --pi->n;
511  }
512 
513  p = pi->pos;
514 
515  while (pi->segment_length < pi->n && *p != pi->separator &&
516  !strnchr(pi->delim, pi->dlen, *p)) {
517  ++p;
518  ++pi->segment_length;
519  }
520 
521  if (!pi->n) {
522  pi->pos = NULL;
523  pi->segment_length = 0;
524  }
525 
526  return pi->pos;
527 }
528 
Representation of parsed URI.
Definition: uri.h:18
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:23
unsigned char coap_key_t[4]
Definition: hashkey.h:19
#define URI_DATA(uriobj)
Definition: uri.c:382
void(* segment_handler_t)(unsigned char *, size_t, void *)
Definition: uri.c:298
#define min(a, b)
Definition: uri.c:295
str host
host part of the URI
Definition: uri.h:19
size_t segment_length
length of current segment
Definition: uri.h:84
size_t dlen
length of separator
Definition: uri.h:82
str path
Beginning of the first path segment.
Definition: uri.h:21
Definition: uri.c:330
#define coap_malloc(size)
Definition: mem.h:15
size_t length
Definition: str.h:15
static coap_uri_t uri
Definition: client.c:36
helpers for handling options in CoAP PDUs
unsigned short port
The port in host byte order.
Definition: uri.h:20
Iterator to for tokenizing a URI path or query.
Definition: uri.h:78
unsigned char * coap_parse_next(coap_parse_iterator_t *pi)
Updates the iterator pi to point to the next token.
Definition: uri.c:490
#define COAP_SET_STR(st, l, v)
Definition: str.h:19
void write_option(unsigned char *s, size_t len, void *data)
Definition: uri.c:336
str buf
Definition: uri.c:331
#define debug(...)
Definition: debug.h:55
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:449
size_t n
number of remaining characters in buffer
Definition: uri.h:79
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:385
unsigned char separator
segment separators
Definition: uri.h:80
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:354
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:258
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:197
#define coap_hash(String, Length, Result)
Definition: hashkey.h:34
#define COAP_DEFAULT_SCHEME
Definition: pdu.h:31
coap_parse_iterator_t * coap_parse_iterator_init(unsigned char *s, size_t n, unsigned char separator, unsigned char *delim, size_t dlen, coap_parse_iterator_t *pi)
Initializes the given iterator pi.
Definition: uri.c:472
#define COAP_DEFAULT_PORT
Definition: pdu.h:24
unsigned char * delim
delimiters where to split the string
Definition: uri.h:81
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:454
Definition: str.h:14
coap_uri_t * coap_clone_uri(const coap_uri_t *uri)
Clones the specified coap_uri_t object.
Definition: uri.c:404
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:368
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:327
int n
Definition: uri.c:332
size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter, segment_handler_t h, void *data)
Splits the given string into segments.
Definition: uri.c:311
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:219
unsigned char * s
Definition: str.h:16
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition: uri.c:182
unsigned char * pos
current position in buffer
Definition: uri.h:83