UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
uri.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 * Copyright (c) 2012 France Telecom All rights reserved.
6 * Copyright (C) 2021 GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
7 * Redistribution only with this Copyright remark. Last modified: 2025-05-16
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * - Neither name of Intel Corporation nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 ******************************************************************************/
39#include <upnp.hpp>
40#include <uri.hpp>
41
42#include <UPnPsdk/port_sock.hpp>
43#include <umock/netdb.hpp>
44
46#include <cassert>
47#include <cstdio> // Needed if OpenSSL isn't compiled in.
49
51
52using compa::pathType::ABS_PATH;
53using compa::pathType::OPAQUE_PART;
54using compa::pathType::REL_PATH;
55using compa::uriType::Absolute;
56using compa::uriType::Relative;
57
58namespace {
74 const unsigned char in) {
75 if (strchr(";/?:@&=+$,{}", in)) {
76 return 1;
77 } else {
78 return 0;
79 }
80}
81
92 const unsigned char in) {
93 if (strchr("-_.!~*'()", in)) {
94 return 1;
95 } else {
96 return 0;
97 }
98}
99
110 const unsigned char in) {
111 if (isalnum(in) || is_mark(in)) {
112 return 1;
113 } else {
114 return 0;
115 }
116}
117
128 const unsigned char* in) {
129 if (in == nullptr)
130 return 0;
131 if (in[0] == '%' && isxdigit(in[1]) && isxdigit(in[2])) {
132 return 1;
133 } else {
134 return 0;
135 }
136}
137
148 const char* in,
150 size_t max,
152 token* out) {
153 size_t i{};
154
155 while (i < max &&
156 (is_unreserved((unsigned char)in[i]) ||
157 is_reserved((unsigned char)in[i]) ||
158 ((i + (size_t)2 < max) &&
159 is_escaped(reinterpret_cast<const unsigned char*>(&in[i]))))) {
160 i++;
161 }
162
163 out->size = i;
164 out->buff = in;
165 return i;
166}
167
177 const token* in,
179 const char* in_base,
181 token* out,
183 char* out_base) {
184 out->size = in->size;
185 out->buff = out_base + (in->buff - in_base);
186}
187
198 const char* in,
201 unsigned short int defaultPort,
203 hostport_type* out) {
204 char workbuf[256];
205 char* c;
206 struct sockaddr_in* sai4 = (struct sockaddr_in*)&out->IPaddress;
207 struct sockaddr_in6* sai6 = (struct sockaddr_in6*)&out->IPaddress;
208 char* srvname = NULL;
209 char* srvport = NULL;
210 char* last_dot = NULL;
211 unsigned short int port;
212 int af = AF_UNSPEC;
213 size_t hostport_size;
214 int has_port = 0;
215 int ret;
216
217 memset(out, 0, sizeof(hostport_type));
218 memset(workbuf, 0, sizeof(workbuf));
219 /* Work on a copy of the input string. */
220 strncpy(workbuf, in, sizeof(workbuf) - 1);
221 c = workbuf;
222 if (*c == '[') {
223 /* IPv6 addresses are enclosed in square brackets. */
224 srvname = ++c;
225 while (*c != '\0' && *c != ']')
226 c++;
227 if (*c == '\0')
228 /* did not find closing bracket. */
229 return UPNP_E_INVALID_URL;
230 /* NULL terminate the srvname and then increment c. */
231 *c++ = '\0'; /* overwrite the ']' */
232 if (*c == ':') {
233 has_port = 1;
234 c++;
235 }
236 af = AF_INET6;
237 } else {
238 /* IPv4 address -OR- host name. */
239 srvname = c;
240 while (*c != ':' && *c != '/' &&
241 (isalnum(*c) || *c == '.' || *c == '-')) {
242 if (*c == '.')
243 last_dot = c;
244 c++;
245 }
246 has_port = (*c == ':') ? 1 : 0;
247 /* NULL terminate the srvname */
248 *c = '\0';
249 if (has_port == 1)
250 c++;
251 if (last_dot != NULL && isdigit(*(last_dot + 1)))
252 /* Must be an IPv4 address. */
253 af = AF_INET;
254 else {
255 /* Must be a host name. */
256 struct addrinfo hints, *res, *res0;
257
258 memset(&hints, 0, sizeof(hints));
259 hints.ai_family = AF_UNSPEC;
260 hints.ai_socktype = SOCK_STREAM;
261
262 ret = umock::netdb_h.getaddrinfo(srvname, NULL, &hints, &res0);
263 if (ret == 0) {
264 for (res = res0; res; res = res->ai_next) {
265 switch (res->ai_family) {
266 case AF_INET:
267 case AF_INET6:
268 /* Found a valid IPv4 or IPv6
269 * address. */
270 memcpy(&out->IPaddress, res->ai_addr, res->ai_addrlen);
271 goto found;
272 }
273 }
274 found:
275 umock::netdb_h.freeaddrinfo(res0);
276 if (res == NULL)
277 /* Didn't find an AF_INET or AF_INET6
278 * address. */
279 return UPNP_E_INVALID_URL;
280 } else
281 /* getaddrinfo failed. */
282 return UPNP_E_INVALID_URL;
283 }
284 }
285 /* Check if a port is specified. */
286 if (has_port == 1) {
287 /* Port is specified. */
288 srvport = c;
289 while (*c != '\0' && isdigit(*c))
290 c++;
291 port = (unsigned short int)atoi(srvport);
292 if (port == 0)
293 /* Bad port number. */
294 return UPNP_E_INVALID_URL;
295 } else
296 /* Port was not specified, use default port. */
297 port = defaultPort;
298 /* The length of the host and port string can be calculated by */
299 /* subtracting pointers. */
300 hostport_size = (size_t)c - (size_t)workbuf;
301 /* Fill in the 'out' information. */
302 switch (af) {
303 case AF_INET:
304 sai4->sin_family = (sa_family_t)af;
305 sai4->sin_port = htons(port);
306 ret = inet_pton(AF_INET, srvname, &sai4->sin_addr);
307 break;
308 case AF_INET6:
309 sai6->sin6_family = (sa_family_t)af;
310 sai6->sin6_port = htons(port);
311 sai6->sin6_scope_id = gIF_INDEX;
312 ret = inet_pton(AF_INET6, srvname, &sai6->sin6_addr);
313 break;
314 default:
315 /* IP address was set by the hostname (getaddrinfo). */
316 /* Override port: */
317 if (out->IPaddress.ss_family == (sa_family_t)AF_INET)
318 sai4->sin_port = htons(port);
319 else
320 sai6->sin6_port = htons(port);
321 ret = 1;
322 }
323 /* Check if address was converted successfully. */
324 if (ret <= 0)
325 return UPNP_E_INVALID_URL;
326 out->text.size = hostport_size;
327 out->text.buff = in;
328
329 return (int)hostport_size;
330}
331
349//
352 const char* in,
354 size_t max,
356 token* out) {
357 size_t i = (size_t)0;
358
359 out->size = (size_t)0;
360 out->buff = NULL;
361
362 if ((max == (size_t)0) || (!isalpha(in[0])))
363 return (size_t)0;
364
365 i++;
366 while ((i < max) && (in[i] != ':')) {
367 if (!(isalnum(in[i]) || (in[i] == '+') || (in[i] == '-') ||
368 (in[i] == '.')))
369 return (size_t)0;
370 i++;
371 }
372 if (i < max) {
373 out->size = i;
374 out->buff = &in[0];
375 return i;
376 }
377
378 return (size_t)0;
379}
380
382inline int is_end_path(char c) {
383 switch (c) {
384 case '?':
385 case '#':
386 case '\0':
387 return 1;
388 }
389 return 0;
390}
391
393} // anonymous namespace
394
395
396int replace_escaped(char* in, size_t index, size_t* max) {
397 int tempInt = 0;
398 char tempChar = 0;
399 size_t i = (size_t)0;
400 size_t j = (size_t)0;
401
402 if (in[index] == '%' && isxdigit(in[index + (size_t)1]) &&
403 isxdigit(in[index + (size_t)2])) {
404 /* Note the "%2x", makes sure that we convert a maximum of two
405 * characters. */
406#ifdef _WIN32
407 if (sscanf_s(&in[index + (size_t)1],
408#else
409 if (sscanf(&in[index + (size_t)1],
410#endif
411 "%2x", (unsigned int*)&tempInt) != 1) {
412 return 0;
413 }
414 tempChar = (char)tempInt;
415 for (i = index + (size_t)3, j = index; j < *max; i++, j++) {
416 in[j] = tempChar;
417 if (i < *max) {
418 tempChar = in[i];
419 } else {
420 tempChar = 0;
421 }
422 }
423 *max -= (size_t)2;
424 return 1;
425 } else {
426 return 0;
427 }
428}
429
430
432 size_t len = strlen(in->URLs) + (size_t)1;
433 size_t i = (size_t)0;
434
435 out->URLs = NULL;
436 out->parsedURLs = NULL;
437 out->size = (size_t)0;
438
439 // clang-format off
440// #ifdef UPNPLIB_PUPNP_BUG
441 // Ingo - Error old code: this isn't fixed due to compatibility.
442 out->URLs = (char*)malloc(len);
443 out->parsedURLs = (uri_type*)malloc(sizeof(uri_type) * in->size);
444
445 if (!out->URLs || !out->parsedURLs)
446 return UPNP_E_OUTOF_MEMORY;
447// #else
448// out->URLs = (char*)malloc(len);
449// if (!out->URLs)
450// return UPNP_E_OUTOF_MEMORY;
451// out->parsedURLs = (uri_type*)malloc(sizeof(uri_type) * in->size);
452// if (!out->parsedURLs) {
453// free(out->URLs);
454// return UPNP_E_OUTOF_MEMORY;
455// }
456// #endif
457 // clang-format on
458 memcpy(out->URLs, in->URLs, len);
459 for (i = (size_t)0; i < in->size; i++) {
460 /*copy the parsed uri */
461 out->parsedURLs[i].type = in->parsedURLs[i].type;
462 copy_token(&in->parsedURLs[i].scheme, in->URLs,
463 &out->parsedURLs[i].scheme, out->URLs);
464 out->parsedURLs[i].path_type = in->parsedURLs[i].path_type;
465 copy_token(&in->parsedURLs[i].pathquery, in->URLs,
466 &out->parsedURLs[i].pathquery, out->URLs);
467 copy_token(&in->parsedURLs[i].fragment, in->URLs,
468 &out->parsedURLs[i].fragment, out->URLs);
470 &out->parsedURLs[i].hostport.text, out->URLs);
471 memcpy(&out->parsedURLs[i].hostport.IPaddress,
473 sizeof(struct sockaddr_storage));
474 }
475 out->size = in->size;
476
477 return HTTP_SUCCESS;
478}
479
481 if (list->URLs) {
482 free(list->URLs);
483 }
484 if (list->parsedURLs) {
485 free(list->parsedURLs);
486 }
487 list->size = (size_t)0;
488}
489
490/* This should use upnpdebug. Failing that, disable by default */
491#if defined(DEBUG_URI) || defined(DOXYGEN_RUN)
493 print_token(&in->scheme);
496 print_token(&in->fragment);
497}
498
500 size_t i = 0;
501
502 fprintf(stderr, "Token Size : %" PRIzu "\n\'", in->size);
503 for (i = 0; i < in->size; i++)
504 putchar(in->buff[i]);
505 putchar('\'');
506 putchar('\n');
507}
508#endif /* DEBUG */
509
510int token_string_casecmp(token* in1, const char* in2) {
511 size_t in2_length = strlen(in2);
512 if (in1->size != in2_length)
513 return 1;
514 else
515 return strncasecmp(in1->buff, in2, in1->size);
516}
517
518int token_cmp(token* in1, token* in2) {
519 if (in1->size != in2->size)
520 return 1;
521 else
522 return memcmp(in1->buff, in2->buff, in1->size);
523}
524
525
526int remove_escaped_chars(char* in, size_t* size) {
528 size_t i = (size_t)0;
529
530 for (i = (size_t)0; i < *size; i++) {
531 replace_escaped(in, i, size);
532 }
533
534 return UPNP_E_SUCCESS;
535}
536
537
538int remove_dots(char* buf, size_t size) {
539 char* in = buf;
540 char* out = buf;
541 char* max = buf + size;
542
543 while (!is_end_path(in[0])) {
544 assert(buf <= out);
545 assert(out <= in);
546 assert(in < max);
547
548 /* case 2.A: */
549 if (strncmp(in, "./", 2) == 0) {
550 in += 2;
551 } else if (strncmp(in, "../", 3) == 0) {
552 in += 3;
553 /* case 2.B: */
554 } else if (strncmp(in, "/./", 3) == 0) {
555 in += 2;
556 } else if (strncmp(in, "/.", 2) == 0 && is_end_path(in[2])) {
557 in += 1;
558 in[0] = '/';
559 /* case 2.C: */
560 } else if (strncmp(in, "/../", 4) == 0 ||
561 (strncmp(in, "/..", 3) == 0 && is_end_path(in[3]))) {
562 /* Make the next character in the input buffer a '/': */
563 if (is_end_path(in[3])) { /* terminating "/.." case */
564 in += 2;
565 in[0] = '/';
566 } else { /* "/../" prefix case */
567 in += 3;
568 }
569 /* Trim the last component from the output buffer, or
570 * empty it. */
571 while (buf < out)
572 if (*--out == '/')
573 break;
574#ifdef DEBUG
575 if (out < in)
576 out[0] = '\0';
577#endif
578 /* case 2.D: */
579 } else if (strncmp(in, ".", 1) == 0 && is_end_path(in[1])) {
580 in += 1;
581 } else if (strncmp(in, "..", 2) == 0 && is_end_path(in[2])) {
582 in += 2;
583 /* case 2.E */
584 } else {
585 /* move initial '/' character (if any) */
586 if (in[0] == '/')
587 *out++ = *in++;
588 /* move first segment up to, but not including, the next
589 * '/' character */
590 while (in < max && in[0] != '/' && !is_end_path(in[0]))
591 *out++ = *in++;
592#ifdef DEBUG
593 if (out < in)
594 out[0] = '\0';
595#endif
596 }
597 }
598 while (in < max)
599 *out++ = *in++;
600 if (out < max)
601 out[0] = '\0';
602 return UPNP_E_SUCCESS;
603}
604
605char* resolve_rel_url(char* base_url, char* rel_url) {
606 uri_type base;
607 uri_type rel;
608 int rv;
609 size_t len_rel;
610 size_t len_base;
611 size_t len;
612 char* out;
613 char* out_finger;
614 char* path;
615 size_t i;
616 size_t prefix;
617
618 if (!base_url) {
619 if (!rel_url)
620 return NULL;
621 return strdup(rel_url);
622 }
623
624 // BUG! Following segfaults if rel_url is NULL
625 len_rel = strlen(rel_url);
626 if (parse_uri(rel_url, len_rel, &rel) != HTTP_SUCCESS)
627 return NULL;
628 if (rel.type == Absolute)
629 return strdup(rel_url);
630
631 len_base = strlen(base_url);
632 if ((parse_uri(base_url, len_base, &base) != HTTP_SUCCESS) ||
633 (base.type != Absolute))
634 return NULL;
635 if (len_rel == (size_t)0)
636 return strdup(base_url);
637
638 len = len_base + len_rel + (size_t)2;
639 out = (char*)malloc(len);
640 if (out == NULL)
641 return NULL;
642 memset(out, 0, len);
643 out_finger = out;
644
645 /* scheme */
646 rv = snprintf(out_finger, len, "%.*s:", (int)base.scheme.size,
647 base.scheme.buff);
648 if (rv < 0 || rv >= (int)len)
649 goto error;
650 out_finger += rv;
651 len -= (size_t)rv;
652
653 /* authority */
654 if (rel.hostport.text.size > (size_t)0) {
655 rv = snprintf(out_finger, len, "%s", rel_url);
656 if (rv < 0 || rv >= (int)len)
657 goto error;
658 return out;
659 }
660 if (base.hostport.text.size > (size_t)0) {
661 rv = snprintf(out_finger, len, "//%.*s", (int)base.hostport.text.size,
662 base.hostport.text.buff);
663 if (rv < 0 || rv >= (int)len)
664 goto error;
665 out_finger += rv;
666 len -= (size_t)rv;
667 }
668
669 /* path */
670 path = out_finger;
671 if (rel.path_type == ABS_PATH) {
672 rv = snprintf(out_finger, len, "%s", rel_url);
673 } else if (base.pathquery.size == (size_t)0) {
674 rv = snprintf(out_finger, len, "/%s", rel_url);
675 } else {
676 if (rel.pathquery.size == (size_t)0) {
677 rv = snprintf(out_finger, len, "%.*s", (int)base.pathquery.size,
678 base.pathquery.buff);
679 } else {
680 if (len < base.pathquery.size)
681 goto error;
682 i = 0;
683 prefix = 1;
684 while (i < base.pathquery.size) {
685 out_finger[i] = base.pathquery.buff[i];
686 switch (base.pathquery.buff[i++]) {
687 case '/':
688 prefix = i;
689 /* fall-through */
690 default:
691 continue;
692 case '?': /* query */
693 if (rel.pathquery.buff[0] == '?')
694 prefix = --i;
695 }
696 break;
697 }
698 out_finger += prefix;
699 len -= prefix;
700 rv = snprintf(out_finger, len, "%.*s", (int)rel.pathquery.size,
701 rel.pathquery.buff);
702 }
703 if (rv < 0 || rv >= (int)len)
704 goto error;
705 out_finger += rv;
706 len -= (size_t)rv;
707
708 /* fragment */
709 if (rel.fragment.size > (size_t)0)
710 rv = snprintf(out_finger, len, "#%.*s", (int)rel.fragment.size,
711 rel.fragment.buff);
712 else if (base.fragment.size > (size_t)0)
713 rv = snprintf(out_finger, len, "#%.*s", (int)base.fragment.size,
714 base.fragment.buff);
715 else
716 rv = 0;
717 }
718 if (rv < 0 || rv >= (int)len)
719 goto error;
720 out_finger += rv;
721 len -= (size_t)rv;
722
723 if (remove_dots(path, (size_t)(out_finger - path)) != UPNP_E_SUCCESS)
724 goto error;
725
726 return out;
727
728error:
729 free(out);
730 return NULL;
731}
732
733int parse_uri(const char* in, size_t max, uri_type* out) {
734 int begin_path = 0;
735 size_t begin_hostport = (size_t)0;
736 size_t begin_fragment = (size_t)0;
737 unsigned short int defaultPort = 80;
738
739 begin_hostport = parse_scheme(in, max, &out->scheme);
740 if (begin_hostport) {
741 out->type = Absolute;
742 out->path_type = OPAQUE_PART;
743 begin_hostport++; // skip ':' scheme delimiter
744 } else {
745 out->type = Relative;
746 out->path_type = REL_PATH;
747 }
748 if (begin_hostport + (size_t)1 < max && in[begin_hostport] == '/' &&
749 in[begin_hostport + (size_t)1] == '/') {
750 begin_hostport += (size_t)2;
751 if (token_string_casecmp(&out->scheme, "https") == 0) {
752 defaultPort = 443;
753 }
754 begin_path =
755 parse_hostport(&in[begin_hostport], defaultPort, &out->hostport);
756 if (begin_path >= 0) {
757 begin_path += (int)begin_hostport;
758 } else
759 return begin_path; // error code from parse_hostport()
760 } else {
761 memset(&out->hostport, 0, sizeof(out->hostport));
762 begin_path = (int)begin_hostport;
763 }
764 begin_fragment =
765 parse_uric(&in[begin_path], max - (size_t)begin_path, &out->pathquery) +
766 (size_t)begin_path;
767 if (out->pathquery.size && out->pathquery.buff[0] == '/') {
768 out->path_type = ABS_PATH;
769 }
770 if (begin_fragment < max && in[begin_fragment] == '#') {
771 begin_fragment++;
772 parse_uric(&in[begin_fragment], max - begin_fragment, &out->fragment);
773 } else {
774 out->fragment.buff = NULL;
775 out->fragment.size = (size_t)0;
776 }
777
778 return HTTP_SUCCESS;
779}
token fragment
Member variable.
Definition uri.hpp:99
token scheme
Member variable.
Definition uri.hpp:96
char * URLs
Dynamic memory for all urls, delimited by <>
Definition uri.hpp:110
hostport_type hostport
Member variable.
Definition uri.hpp:100
uri_type * parsedURLs
parsed URLs
Definition uri.hpp:111
size_t size
Size of the buffer.
Definition uri.hpp:78
size_t size
size
Definition uri.hpp:109
compa::uriType type
Member variable.
Definition uri.hpp:95
const char * buff
Buffer.
Definition uri.hpp:77
token pathquery
Member variable.
Definition uri.hpp:98
sockaddr_storage IPaddress
Network socket address.
Definition uri.hpp:86
constexpr int HTTP_SUCCESS
Yet another success code.
Definition uri.hpp:70
compa::pathType path_type
Member variable.
Definition uri.hpp:97
token text
Pointing to the full host:port string representation.
Definition uri.hpp:85
Represents a list of URLs as in the "callback" header of SUBSCRIBE message in GENA.
Definition uri.hpp:108
Represents a URI used in parse_uri and elsewhere.
Definition uri.hpp:92
Buffer used in parsinghttp messages, urls, etc. Generally this simply holds a pointer into a larger a...
Definition uri.hpp:76
Represents a host port, e.g. "127.127.0.1:80".
Definition uri.hpp:84
#define UPNP_E_SUCCESS
The operation completed successfully.
Definition messages.hpp:27
#define UPNP_E_OUTOF_MEMORY
Not enough resources are currently available to complete the operation.
Definition messages.hpp:57
#define UPNP_E_INVALID_URL
An URL passed into the function is invalid.
Definition messages.hpp:83
int is_mark(const unsigned char in)
Check for a MARK character.
Definition uri.cpp:90
int is_end_path(char c)
Check if end of a path.
Definition uri.cpp:382
int is_escaped(const unsigned char *in)
Check that a char[3] sequence is ESCAPED.
Definition uri.cpp:126
int is_reserved(const unsigned char in)
Check for a RESERVED character.
Definition uri.cpp:72
size_t parse_uric(const char *in, size_t max, token *out)
Parses a string of uric characters starting at in[0].
Definition uri.cpp:146
size_t parse_scheme(const char *in, size_t max, token *out)
parses a uri scheme starting at in[0].
Definition uri.cpp:350
int is_unreserved(const unsigned char in)
Check for an UNRESERVED character.
Definition uri.cpp:108
int parse_hostport(const char *in, unsigned short int defaultPort, hostport_type *out)
Parses a string with host and port and fills a hostport structure.
Definition uri.cpp:196
void copy_token(const token *in, const char *in_base, token *out, char *out_base)
Copy the offset and size from a token to another token.
Definition uri.cpp:175
Specifications to be portable with sockets between different platforms.
UPnPsdk_EXTERN unsigned gIF_INDEX
Contains network interface index of the link local address gIF_IPV6 that is used as its scope_id.
Definition uri.cpp:50
char * resolve_rel_url(char *base_url, char *rel_url)
Resolves a relative url with a base url.
Definition uri.cpp:605
int remove_dots(char *buf, size_t size)
Removes ".", and ".." from a path.
Definition uri.cpp:538
int copy_URL_list(URL_list *in, URL_list *out)
Copies one URL_list into another.
Definition uri.cpp:431
int replace_escaped(char *in, size_t index, size_t *max)
Replaces one single escaped character within a string with its unescaped version.
Definition uri.cpp:396
int token_cmp(token *in1, token *in2)
Compares two tokens.
Definition uri.cpp:518
int token_string_casecmp(token *in1, const char *in2)
Compares buffer in the token object with the buffer in in2 case insensitive.
Definition uri.cpp:510
int remove_escaped_chars(char *in, size_t *size)
Removes http escaped characters such as: "%20" and replaces them with their character representation.
Definition uri.cpp:526
void print_uri(uri_type *in)
Function useful in debugging for printing a parsed uri.
Definition uri.cpp:492
void print_token(token *in)
Function useful in debugging for printing a token.
Definition uri.cpp:499
int parse_uri(const char *in, size_t max, uri_type *out)
Parses a uri as defined in RFC 2396 (explaining URIs).
Definition uri.cpp:733
void free_URL_list(URL_list *list)
Frees the memory associated with a URL_list.
Definition uri.cpp:480
#define UPnPsdk_EXTERN
Prefix for a portable 'extern' declaration.