diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2017-05-06 16:36:16 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2017-05-06 16:36:16 +0200 |
commit | 19bd8afa6b63dccadc2006292154f1633e2a29c9 (patch) | |
tree | 1677f5a2b3caccce45a75fc6ca5857a7d820686c | |
parent | 4b2800f8f3ee34d9779dfdcd40d7e68b569380e6 (diff) | |
download | monitoring-plugins-19bd8af.tar.gz |
some rework:
- added old style 'redir' function and options along to a new
libcurl internal 'follow' parameter 'curl'
- moved picohttpparser to it's own subdirectory
- added uriparser to be used instead of the home-grown parser in
'redir'
33 files changed, 8661 insertions, 39 deletions
@@ -202,7 +202,18 @@ NP-VERSION-FILE | |||
202 | /plugins/negate | 202 | /plugins/negate |
203 | /plugins/stamp-h* | 203 | /plugins/stamp-h* |
204 | /plugins/urlize | 204 | /plugins/urlize |
205 | /plugins/libpicohttpparser.a | 205 | |
206 | # /plugins/picohttpparser | ||
207 | /plugins/picohttpparser/Makefile | ||
208 | /plugins/picohttpparser/Makefile.in | ||
209 | /plugins/picohttpparser/.deps | ||
210 | /plugins/picohttpparser/libpicohttpparser.a | ||
211 | |||
212 | # /plugins/uriparser | ||
213 | /plugins/uriparser/Makefile | ||
214 | /plugins/uriparser/Makefile.in | ||
215 | /plugins/uriparser/.deps | ||
216 | /plugins/uriparser/liburiparser.a | ||
206 | 217 | ||
207 | # /plugins/t/ | 218 | # /plugins/t/ |
208 | /plugins/t/*.tmp | 219 | /plugins/t/*.tmp |
diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS index 50c714c3..06e84e25 100644 --- a/ACKNOWLEDGEMENTS +++ b/ACKNOWLEDGEMENTS | |||
@@ -31,3 +31,16 @@ Gnulib team | |||
31 | Copyright (C) 2001, 2003, 2004, 2006 Free Software Foundation, Inc | 31 | Copyright (C) 2001, 2003, 2004, 2006 Free Software Foundation, Inc |
32 | http://www.gnu.org/software/gnulib/ | 32 | http://www.gnu.org/software/gnulib/ |
33 | Use of lib files that originally were used from coreutils | 33 | Use of lib files that originally were used from coreutils |
34 | |||
35 | Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, | ||
36 | Shigeo Mitsunari | ||
37 | picohttpparser | ||
38 | https://github.com/h2o/picohttpparser | ||
39 | Use of the library for HTTP header parsing in check_curl. | ||
40 | |||
41 | Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
42 | Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
43 | All rights reserved. | ||
44 | uriparser - RFC 3986 URI parsing library | ||
45 | http://uriparser.sourceforge.net/ | ||
46 | Use of the library for URL parsing in check_curl. | ||
diff --git a/configure.ac b/configure.ac index 04ec5bde..c56163c1 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -385,19 +385,31 @@ if test "$ac_cv_header_wtsapi32_h" = "yes"; then | |||
385 | AC_SUBST(WTSAPI32LIBS) | 385 | AC_SUBST(WTSAPI32LIBS) |
386 | fi | 386 | fi |
387 | 387 | ||
388 | dnl Check for cURL library | 388 | AC_ARG_ENABLE(check-curl, |
389 | LIBCURL_CHECK_CONFIG(yes, 7.15.2, [ | 389 | AC_HELP_STRING([--enable-check-curl], |
390 | EXTRAS="$EXTRAS check_curl\$(EXEEXT)" | 390 | [Enables compilation of check_curl (default: no)]), |
391 | LIBCURLINCLUDE="$LIBCURL_CPPFLAGS" | 391 | [enable_check_curl=$enableval], |
392 | LIBCURLLIBS="$LIBCURL" | 392 | [enable_check_curl=no]) |
393 | LIBCURLCFLAGS="$LIBCURL_CPPFLAGS" | 393 | if test "$enable_check_curl" = "yes" ; then |
394 | AC_SUBST(LIBCURLINCLUDE) | 394 | dnl Check for cURL library |
395 | AC_SUBST(LIBCURLLIBS) | 395 | LIBCURL_CHECK_CONFIG(yes, 7.15.2, [ |
396 | AC_SUBST(LIBCURLCFLAGS) | 396 | EXTRAS="$EXTRAS check_curl\$(EXEEXT)" |
397 | ], [ | 397 | LIBCURLINCLUDE="$LIBCURL_CPPFLAGS" |
398 | AC_MSG_WARN([Skipping curl plugin]) | 398 | LIBCURLLIBS="$LIBCURL" |
399 | AC_MSG_WARN([install libcurl libs to compile this plugin (see REQUIREMENTS).]) | 399 | LIBCURLCFLAGS="$LIBCURL_CPPFLAGS" |
400 | ]) | 400 | AC_SUBST(LIBCURLINCLUDE) |
401 | AC_SUBST(LIBCURLLIBS) | ||
402 | AC_SUBST(LIBCURLCFLAGS) | ||
403 | AC_SUBST(PICOHTTPPARSER_DIR, picohttpparser) | ||
404 | AC_SUBST(URIPARSER_DIR, uriparser) | ||
405 | ], [ | ||
406 | AC_MSG_WARN([Skipping curl plugin]) | ||
407 | AC_MSG_WARN([install libcurl libs to compile this plugin (see REQUIREMENTS).]) | ||
408 | ]) | ||
409 | fi | ||
410 | AM_CONDITIONAL([WITH_CHECK_CURL], [test "$enable_check_curl" = "yes"]) | ||
411 | AM_COND_IF([WITH_CHECK_CURL], | ||
412 | [AC_CONFIG_FILES([plugins/picohttpparser/Makefile plugins/uriparser/Makefile])]) | ||
401 | 413 | ||
402 | dnl Fallback to who(1) if the system doesn't provide an utmpx(5) interface | 414 | dnl Fallback to who(1) if the system doesn't provide an utmpx(5) interface |
403 | if test "$ac_cv_header_utmpx_h" = "no" -a "$ac_cv_header_wtsapi32_h" = "no" | 415 | if test "$ac_cv_header_utmpx_h" = "no" -a "$ac_cv_header_wtsapi32_h" = "no" |
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index ff745c39..34a7da8b 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am | |||
@@ -40,17 +40,17 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ | |||
40 | check_nagios check_by_ssh check_dns check_nt check_ide_smart \ | 40 | check_nagios check_by_ssh check_dns check_nt check_ide_smart \ |
41 | check_procs check_mysql_query check_apt check_dbi check_curl | 41 | check_procs check_mysql_query check_apt check_dbi check_curl |
42 | 42 | ||
43 | SUBDIRS = @PICOHTTPPARSER_DIR@ @URIPARSER_DIR@ | ||
44 | |||
43 | EXTRA_DIST = t tests | 45 | EXTRA_DIST = t tests |
44 | 46 | ||
45 | PLUGINHDRS = common.h | 47 | PLUGINHDRS = common.h |
46 | 48 | ||
47 | noinst_LIBRARIES = libnpcommon.a libpicohttpparser.a | 49 | noinst_LIBRARIES = libnpcommon.a |
48 | 50 | ||
49 | libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ | 51 | libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ |
50 | popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h | 52 | popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h |
51 | 53 | ||
52 | libpicohttpparser_a_SOURCES = picohttpparser.c | ||
53 | |||
54 | BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a | 54 | BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a |
55 | NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) | 55 | NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) |
56 | NETLIBS = $(NETOBJS) $(SOCKETLIBS) | 56 | NETLIBS = $(NETOBJS) $(SOCKETLIBS) |
@@ -71,9 +71,9 @@ test-debug: | |||
71 | 71 | ||
72 | check_apt_LDADD = $(BASEOBJS) | 72 | check_apt_LDADD = $(BASEOBJS) |
73 | check_cluster_LDADD = $(BASEOBJS) | 73 | check_cluster_LDADD = $(BASEOBJS) |
74 | check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) | 74 | check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) -Ipicohttpparser -Iuriparser |
75 | check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLINCLUDE) | 75 | check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLINCLUDE) -Ipicohttpparser -Iuriparser |
76 | check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) libpicohttpparser.a | 76 | check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) picohttpparser/libpicohttpparser.a uriparser/liburiparser.a |
77 | check_dbi_LDADD = $(NETLIBS) $(DBILIBS) | 77 | check_dbi_LDADD = $(NETLIBS) $(DBILIBS) |
78 | check_dig_LDADD = $(NETLIBS) | 78 | check_dig_LDADD = $(NETLIBS) |
79 | check_disk_LDADD = $(BASEOBJS) | 79 | check_disk_LDADD = $(BASEOBJS) |
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 5f6905f9..72db27ad 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
@@ -51,17 +51,35 @@ const char *email = "devel@monitoring-plugins.org"; | |||
51 | 51 | ||
52 | #include "picohttpparser.h" | 52 | #include "picohttpparser.h" |
53 | 53 | ||
54 | #include "uriparser/Uri.h" | ||
55 | |||
56 | #include <arpa/inet.h> | ||
57 | |||
54 | #define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) | 58 | #define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) |
55 | 59 | ||
56 | #define DEFAULT_BUFFER_SIZE 2048 | 60 | #define DEFAULT_BUFFER_SIZE 2048 |
57 | #define DEFAULT_SERVER_URL "/" | 61 | #define DEFAULT_SERVER_URL "/" |
58 | #define HTTP_EXPECT "HTTP/1." | 62 | #define HTTP_EXPECT "HTTP/1." |
63 | #define DEFAULT_MAX_REDIRS 15 | ||
64 | #define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN | ||
59 | enum { | 65 | enum { |
66 | MAX_IPV4_HOSTLENGTH = 255, | ||
60 | HTTP_PORT = 80, | 67 | HTTP_PORT = 80, |
61 | HTTPS_PORT = 443, | 68 | HTTPS_PORT = 443, |
62 | MAX_PORT = 65535 | 69 | MAX_PORT = 65535 |
63 | }; | 70 | }; |
64 | 71 | ||
72 | enum { | ||
73 | STICKY_NONE = 0, | ||
74 | STICKY_HOST = 1, | ||
75 | STICKY_PORT = 2 | ||
76 | }; | ||
77 | |||
78 | enum { | ||
79 | FOLLOW_HTTP_CURL = 0, | ||
80 | FOLLOW_LIBCURL = 1 | ||
81 | }; | ||
82 | |||
65 | /* for buffers for header and body */ | 83 | /* for buffers for header and body */ |
66 | typedef struct { | 84 | typedef struct { |
67 | char *buf; | 85 | char *buf; |
@@ -128,6 +146,8 @@ int verbose = 0; | |||
128 | int show_extended_perfdata = FALSE; | 146 | int show_extended_perfdata = FALSE; |
129 | int min_page_len = 0; | 147 | int min_page_len = 0; |
130 | int max_page_len = 0; | 148 | int max_page_len = 0; |
149 | int redir_depth = 0; | ||
150 | int max_depth = DEFAULT_MAX_REDIRS; | ||
131 | char *http_method = NULL; | 151 | char *http_method = NULL; |
132 | char *http_post_data = NULL; | 152 | char *http_post_data = NULL; |
133 | char *http_content_type = NULL; | 153 | char *http_content_type = NULL; |
@@ -155,8 +175,12 @@ char string_expect[MAX_INPUT_BUFFER] = ""; | |||
155 | char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; | 175 | char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; |
156 | int server_expect_yn = 0; | 176 | int server_expect_yn = 0; |
157 | char user_auth[MAX_INPUT_BUFFER] = ""; | 177 | char user_auth[MAX_INPUT_BUFFER] = ""; |
178 | char **http_opt_headers; | ||
179 | int http_opt_headers_count = 0; | ||
158 | int display_html = FALSE; | 180 | int display_html = FALSE; |
159 | int onredirect = STATE_OK; | 181 | int onredirect = STATE_OK; |
182 | int followmethod = FOLLOW_HTTP_CURL; | ||
183 | int followsticky = STICKY_NONE; | ||
160 | int use_ssl = FALSE; | 184 | int use_ssl = FALSE; |
161 | int use_sni = TRUE; | 185 | int use_sni = TRUE; |
162 | int check_cert = FALSE; | 186 | int check_cert = FALSE; |
@@ -181,6 +205,7 @@ curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; | |||
181 | int process_arguments (int, char**); | 205 | int process_arguments (int, char**); |
182 | void handle_curl_option_return_code (CURLcode res, const char* option); | 206 | void handle_curl_option_return_code (CURLcode res, const char* option); |
183 | int check_http (void); | 207 | int check_http (void); |
208 | void redir (curlhelp_write_curlbuf*); | ||
184 | void print_help (void); | 209 | void print_help (void); |
185 | void print_usage (void); | 210 | void print_usage (void); |
186 | void print_curl_version (void); | 211 | void print_curl_version (void); |
@@ -295,6 +320,8 @@ check_http (void) | |||
295 | { | 320 | { |
296 | int result = STATE_OK; | 321 | int result = STATE_OK; |
297 | int page_len = 0; | 322 | int page_len = 0; |
323 | int i; | ||
324 | char *force_host_header = NULL; | ||
298 | 325 | ||
299 | /* initialize curl */ | 326 | /* initialize curl */ |
300 | if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) | 327 | if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) |
@@ -371,6 +398,28 @@ check_http (void) | |||
371 | snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); | 398 | snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); |
372 | header_list = curl_slist_append (header_list, http_header); | 399 | header_list = curl_slist_append (header_list, http_header); |
373 | 400 | ||
401 | /* check if Host header is explicitly set in options */ | ||
402 | if (http_opt_headers_count) { | ||
403 | for (i = 0; i < http_opt_headers_count ; i++) { | ||
404 | if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { | ||
405 | force_host_header = http_opt_headers[i]; | ||
406 | } | ||
407 | } | ||
408 | } | ||
409 | |||
410 | /* attach additional headers supplied by the user */ | ||
411 | /* optionally send any other header tag */ | ||
412 | if (http_opt_headers_count) { | ||
413 | for (i = 0; i < http_opt_headers_count ; i++) { | ||
414 | if (force_host_header != http_opt_headers[i]) { | ||
415 | header_list = curl_slist_append (header_list, http_opt_headers[i]); | ||
416 | } | ||
417 | } | ||
418 | /* This cannot be free'd here because a redirection will then try to access this and segfault */ | ||
419 | /* Covered in a testcase in tests/check_http.t */ | ||
420 | /* free(http_opt_headers); */ | ||
421 | } | ||
422 | |||
374 | /* set HTTP headers */ | 423 | /* set HTTP headers */ |
375 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER"); | 424 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER"); |
376 | 425 | ||
@@ -481,13 +530,29 @@ check_http (void) | |||
481 | 530 | ||
482 | /* handle redirections */ | 531 | /* handle redirections */ |
483 | if (onredirect == STATE_DEPENDENT) { | 532 | if (onredirect == STATE_DEPENDENT) { |
484 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); | 533 | if( followmethod == FOLLOW_LIBCURL ) { |
485 | /* TODO: handle the following aspects of redirection | 534 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); |
486 | CURLOPT_POSTREDIR: method switch | 535 | |
487 | CURLINFO_REDIRECT_URL: custom redirect option | 536 | /* default -1 is infinite, not good, could lead to zombie plugins! |
488 | CURLOPT_REDIRECT_PROTOCOLS | 537 | Setting it to one bigger than maximal limit to handle errors nicely below |
489 | CURLINFO_REDIRECT_COUNT | 538 | */ |
490 | */ | 539 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS"); |
540 | |||
541 | /* for now allow only http and https (we are a http(s) check plugin in the end) */ | ||
542 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) | ||
543 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS"); | ||
544 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) */ | ||
545 | |||
546 | /* TODO: handle the following aspects of redirection, make them | ||
547 | * command line options too later: | ||
548 | CURLOPT_POSTREDIR: method switch | ||
549 | CURLINFO_REDIRECT_URL: custom redirect option | ||
550 | CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols | ||
551 | CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size? | ||
552 | */ | ||
553 | } else { | ||
554 | // old style redirection is handled below | ||
555 | } | ||
491 | } | 556 | } |
492 | 557 | ||
493 | /* no-body */ | 558 | /* no-body */ |
@@ -533,8 +598,8 @@ check_http (void) | |||
533 | printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data); | 598 | printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data); |
534 | 599 | ||
535 | /* free header and server IP resolve lists, we don't need it anymore */ | 600 | /* free header and server IP resolve lists, we don't need it anymore */ |
536 | curl_slist_free_all (header_list); | 601 | curl_slist_free_all (header_list); header_list = NULL; |
537 | curl_slist_free_all (server_ips); | 602 | curl_slist_free_all (server_ips); server_ips = NULL; |
538 | 603 | ||
539 | /* Curl errors, result in critical Nagios state */ | 604 | /* Curl errors, result in critical Nagios state */ |
540 | if (res != CURLE_OK) { | 605 | if (res != CURLE_OK) { |
@@ -691,18 +756,39 @@ GOT_FIRST_CERT: | |||
691 | /* check redirected page if specified */ | 756 | /* check redirected page if specified */ |
692 | } else if (code >= 300) { | 757 | } else if (code >= 300) { |
693 | if (onredirect == STATE_DEPENDENT) { | 758 | if (onredirect == STATE_DEPENDENT) { |
694 | code = status_line.http_code; | 759 | if( followmethod == FOLLOW_LIBCURL ) { |
760 | code = status_line.http_code; | ||
761 | } else { | ||
762 | /* old check_http style redirection, if we come | ||
763 | * back here, we are in the same status as with | ||
764 | * the libcurl method | ||
765 | */ | ||
766 | redir (&header_buf); | ||
767 | } | ||
768 | } else { | ||
769 | /* this is a specific code in the command line to | ||
770 | * be returned when a redirection is encoutered | ||
771 | */ | ||
695 | } | 772 | } |
696 | result = max_state_alt (onredirect, result); | 773 | result = max_state_alt (onredirect, result); |
697 | /* TODO: make sure the last status line has been | ||
698 | parsed into the status_line structure | ||
699 | */ | ||
700 | /* all other codes are considered ok */ | 774 | /* all other codes are considered ok */ |
701 | } else { | 775 | } else { |
702 | result = STATE_OK; | 776 | result = STATE_OK; |
703 | } | 777 | } |
704 | } | 778 | } |
705 | 779 | ||
780 | /* libcurl redirection internally, handle error states here */ | ||
781 | if( followmethod == FOLLOW_LIBCURL ) { | ||
782 | handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT"); | ||
783 | if (verbose >= 2) | ||
784 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); | ||
785 | if (redir_depth > max_depth) { | ||
786 | snprintf (msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", | ||
787 | max_depth); | ||
788 | die (STATE_WARNING, "HTTP WARNING - %s", msg); | ||
789 | } | ||
790 | } | ||
791 | |||
706 | /* check status codes, set exit status accordingly */ | 792 | /* check status codes, set exit status accordingly */ |
707 | if( status_line.http_code != code ) { | 793 | if( status_line.http_code != code ) { |
708 | die (STATE_CRITICAL, _("HTTP CRITICAL HTTP/%d.%d %d %s - different HTTP codes (cUrl has %ld)\n"), | 794 | die (STATE_CRITICAL, _("HTTP CRITICAL HTTP/%d.%d %d %s - different HTTP codes (cUrl has %ld)\n"), |
@@ -813,6 +899,188 @@ GOT_FIRST_CERT: | |||
813 | return result; | 899 | return result; |
814 | } | 900 | } |
815 | 901 | ||
902 | int | ||
903 | uri_strcmp (const UriTextRangeA range, const char* s) | ||
904 | { | ||
905 | if (!range.first) return -1; | ||
906 | if (range.afterLast - range.first < strlen (s)) return -1; | ||
907 | return strncmp (s, range.first, min( range.afterLast - range.first, strlen (s))); | ||
908 | } | ||
909 | |||
910 | char* | ||
911 | uri_string (const UriTextRangeA range, char* buf, size_t buflen) | ||
912 | { | ||
913 | if (!range.first) return "(null)"; | ||
914 | strncpy (buf, range.first, max (buflen, range.afterLast - range.first)); | ||
915 | buf[max (buflen, range.afterLast - range.first)] = '\0'; | ||
916 | buf[range.afterLast - range.first] = '\0'; | ||
917 | return buf; | ||
918 | } | ||
919 | |||
920 | void | ||
921 | redir (curlhelp_write_curlbuf* header_buf) | ||
922 | { | ||
923 | char *location = NULL; | ||
924 | curlhelp_statusline status_line; | ||
925 | struct phr_header headers[255]; | ||
926 | size_t nof_headers = 255; | ||
927 | size_t msglen; | ||
928 | char buf[DEFAULT_BUFFER_SIZE]; | ||
929 | char ipstr[INET_ADDR_MAX_SIZE]; | ||
930 | int new_port; | ||
931 | char *new_host; | ||
932 | char *new_url; | ||
933 | |||
934 | int res = phr_parse_response (header_buf->buf, header_buf->buflen, | ||
935 | &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen, | ||
936 | headers, &nof_headers, 0); | ||
937 | |||
938 | location = get_header_value (headers, nof_headers, "location"); | ||
939 | |||
940 | if (verbose >= 2) | ||
941 | printf(_("* Seen redirect location %s\n"), location); | ||
942 | |||
943 | if (++redir_depth > max_depth) | ||
944 | die (STATE_WARNING, | ||
945 | _("HTTP WARNING - maximum redirection depth %d exceeded - %s\n"), | ||
946 | max_depth, location, (display_html ? "</A>" : "")); | ||
947 | |||
948 | UriParserStateA state; | ||
949 | UriUriA uri; | ||
950 | state.uri = &uri; | ||
951 | if (uriParseUriA (&state, location) != URI_SUCCESS) { | ||
952 | if (state.errorCode == URI_ERROR_SYNTAX) { | ||
953 | die (STATE_UNKNOWN, | ||
954 | _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), | ||
955 | location, (display_html ? "</A>" : "")); | ||
956 | } else if (state.errorCode == URI_ERROR_MALLOC) { | ||
957 | die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); | ||
958 | } | ||
959 | } | ||
960 | |||
961 | if (verbose >= 2) { | ||
962 | printf (_("** scheme: %s\n"), | ||
963 | uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE)); | ||
964 | printf (_("** host: %s\n"), | ||
965 | uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); | ||
966 | printf (_("** port: %s\n"), | ||
967 | uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); | ||
968 | if (uri.hostData.ip4) { | ||
969 | inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr)); | ||
970 | printf (_("** IPv4: %s\n"), ipstr); | ||
971 | } | ||
972 | if (uri.hostData.ip6) { | ||
973 | inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr)); | ||
974 | printf (_("** IPv6: %s\n"), ipstr); | ||
975 | } | ||
976 | if (uri.pathHead) { | ||
977 | printf (_("** path: ")); | ||
978 | const UriPathSegmentA* p = uri.pathHead; | ||
979 | for (; p; p = p->next) { | ||
980 | printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE)); | ||
981 | } | ||
982 | puts (""); | ||
983 | } | ||
984 | if (uri.query.first) { | ||
985 | printf (_("** query: %s\n"), | ||
986 | uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE)); | ||
987 | } | ||
988 | if (uri.fragment.first) { | ||
989 | printf (_("** fragment: %s\n"), | ||
990 | uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE)); | ||
991 | } | ||
992 | } | ||
993 | |||
994 | use_ssl = !uri_strcmp (uri.scheme, "https"); | ||
995 | |||
996 | /* we do a sloppy test here only, because uriparser would have failed | ||
997 | * above, if the port would be invalid, we just check for MAX_PORT | ||
998 | */ | ||
999 | if (uri.portText.first) { | ||
1000 | new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); | ||
1001 | } else { | ||
1002 | new_port = HTTP_PORT; | ||
1003 | if (use_ssl) | ||
1004 | new_port = HTTPS_PORT; | ||
1005 | } | ||
1006 | if (new_port > MAX_PORT) | ||
1007 | die (STATE_UNKNOWN, | ||
1008 | _("HTTP UNKNOWN - Redirection to port above %d - %s\n"), | ||
1009 | MAX_PORT, location, display_html ? "</A>" : ""); | ||
1010 | |||
1011 | /* by RFC 7231 relative URLs in Location should be taken relative to | ||
1012 | * the original URL, so wy try to form a new absolute URL here | ||
1013 | */ | ||
1014 | if (!uri.scheme.first && !uri.hostText.first) { | ||
1015 | /* TODO: implement */ | ||
1016 | die (STATE_UNKNOWN, _("HTTP UNKNOWN - non-absolute location, not implemented yet!\n")); | ||
1017 | new_host = strdup (host_name ? host_name : server_address); | ||
1018 | } else { | ||
1019 | new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); | ||
1020 | } | ||
1021 | |||
1022 | new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE); | ||
1023 | if (uri.pathHead) { | ||
1024 | const UriPathSegmentA* p = uri.pathHead; | ||
1025 | for (; p; p = p->next) { | ||
1026 | strncat (new_url, "/", DEFAULT_BUFFER_SIZE); | ||
1027 | strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE); | ||
1028 | } | ||
1029 | } | ||
1030 | |||
1031 | if (server_port==new_port && | ||
1032 | !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && | ||
1033 | (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && | ||
1034 | !strcmp(server_url, new_url)) | ||
1035 | die (STATE_WARNING, | ||
1036 | _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"), | ||
1037 | use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); | ||
1038 | |||
1039 | /* set new values for redirected request */ | ||
1040 | |||
1041 | free (host_name); | ||
1042 | host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH); | ||
1043 | free(new_host); | ||
1044 | |||
1045 | server_port = (unsigned short)new_port; | ||
1046 | |||
1047 | /* reset virtual port */ | ||
1048 | virtual_port = server_port; | ||
1049 | |||
1050 | if (!(followsticky & STICKY_HOST)) { | ||
1051 | free (server_address); | ||
1052 | server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH); | ||
1053 | } | ||
1054 | if (!(followsticky & STICKY_PORT)) { | ||
1055 | server_port = new_port; | ||
1056 | } | ||
1057 | |||
1058 | free (server_url); | ||
1059 | server_url = new_url; | ||
1060 | |||
1061 | uriFreeUriMembersA (&uri); | ||
1062 | |||
1063 | if (verbose) | ||
1064 | printf (_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", | ||
1065 | host_name ? host_name : server_address, server_port, server_url); | ||
1066 | |||
1067 | /* TODO: the hash component MUST be taken from the original URL and | ||
1068 | * attached to the URL in Location | ||
1069 | */ | ||
1070 | |||
1071 | check_http (); | ||
1072 | } | ||
1073 | |||
1074 | #if 0 | ||
1075 | |||
1076 | int main(int argc, char *argv[]) { | ||
1077 | |||
1078 | for (; i < argc; i++) { | ||
1079 | |||
1080 | } | ||
1081 | printf("\n"); | ||
1082 | #endif | ||
1083 | |||
816 | /* check whether a file exists */ | 1084 | /* check whether a file exists */ |
817 | void | 1085 | void |
818 | test_file (char *path) | 1086 | test_file (char *path) |
@@ -974,7 +1242,11 @@ process_arguments (int argc, char **argv) | |||
974 | snprintf (user_agent, DEFAULT_BUFFER_SIZE, optarg); | 1242 | snprintf (user_agent, DEFAULT_BUFFER_SIZE, optarg); |
975 | break; | 1243 | break; |
976 | case 'k': /* Additional headers */ | 1244 | case 'k': /* Additional headers */ |
977 | header_list = curl_slist_append(header_list, optarg); | 1245 | if (http_opt_headers_count == 0) |
1246 | http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); | ||
1247 | else | ||
1248 | http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); | ||
1249 | http_opt_headers[http_opt_headers_count - 1] = optarg; | ||
978 | break; | 1250 | break; |
979 | case 'L': /* show html link */ | 1251 | case 'L': /* show html link */ |
980 | display_html = TRUE; | 1252 | display_html = TRUE; |
@@ -1121,6 +1393,14 @@ process_arguments (int argc, char **argv) | |||
1121 | onredirect = STATE_UNKNOWN; | 1393 | onredirect = STATE_UNKNOWN; |
1122 | else if (!strcmp (optarg, "follow")) | 1394 | else if (!strcmp (optarg, "follow")) |
1123 | onredirect = STATE_DEPENDENT; | 1395 | onredirect = STATE_DEPENDENT; |
1396 | else if (!strcmp (optarg, "stickyport")) | ||
1397 | onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT; | ||
1398 | else if (!strcmp (optarg, "sticky")) | ||
1399 | onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; | ||
1400 | else if (!strcmp (optarg, "follow")) | ||
1401 | onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; | ||
1402 | else if (!strcmp (optarg, "curl")) | ||
1403 | onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; | ||
1124 | else usage2 (_("Invalid onredirect option"), optarg); | 1404 | else usage2 (_("Invalid onredirect option"), optarg); |
1125 | if (verbose >= 2) | 1405 | if (verbose >= 2) |
1126 | printf(_("* Following redirects set to %s\n"), state_text(onredirect)); | 1406 | printf(_("* Following redirects set to %s\n"), state_text(onredirect)); |
@@ -1264,7 +1544,6 @@ print_help (void) | |||
1264 | print_revision (progname, NP_VERSION); | 1544 | print_revision (progname, NP_VERSION); |
1265 | 1545 | ||
1266 | printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); | 1546 | printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); |
1267 | printf ("Copyright (c) 2017 Andreas Baumann <mail@andreasbaumann.cc>\n"); | ||
1268 | printf (COPYRIGHT, copyright, email); | 1547 | printf (COPYRIGHT, copyright, email); |
1269 | 1548 | ||
1270 | printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); | 1549 | printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); |
@@ -1365,8 +1644,11 @@ print_help (void) | |||
1365 | printf (" %s\n", _("Print additional performance data")); | 1644 | printf (" %s\n", _("Print additional performance data")); |
1366 | printf (" %s\n", "-L, --link"); | 1645 | printf (" %s\n", "-L, --link"); |
1367 | printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); | 1646 | printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); |
1368 | printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>"); | 1647 | printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>"); |
1369 | printf (" %s\n", _("How to handle redirected pages.")); | 1648 | printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); |
1649 | printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); | ||
1650 | printf (" %s\n", _("follow uses the old redirection algorithm of check_http.")); | ||
1651 | printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl.")); | ||
1370 | printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); | 1652 | printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); |
1371 | printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); | 1653 | printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); |
1372 | 1654 | ||
@@ -1436,7 +1718,7 @@ print_usage (void) | |||
1436 | printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); | 1718 | printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); |
1437 | printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>]\n"); | 1719 | printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>]\n"); |
1438 | printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); | 1720 | printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); |
1439 | printf (" [-f <ok|warning|critcal|follow>]\n"); | 1721 | printf (" [-f <ok|warning|critcal|follow|sticky|stickyport|curl>]\n"); |
1440 | printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); | 1722 | printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); |
1441 | printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); | 1723 | printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); |
1442 | printf (" [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]]\n"); | 1724 | printf (" [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]]\n"); |
@@ -1739,7 +2021,7 @@ get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_wri | |||
1739 | content_length_s += strspn (content_length_s, " \t"); | 2021 | content_length_s += strspn (content_length_s, " \t"); |
1740 | content_length = atoi (content_length_s); | 2022 | content_length = atoi (content_length_s); |
1741 | if (content_length != body_buf->buflen) { | 2023 | if (content_length != body_buf->buflen) { |
1742 | /* TODO: should we warn if the actual and the reported body length doen't match? */ | 2024 | /* TODO: should we warn if the actual and the reported body length don't match? */ |
1743 | } | 2025 | } |
1744 | 2026 | ||
1745 | if (content_length_s) free (content_length_s); | 2027 | if (content_length_s) free (content_length_s); |
diff --git a/plugins/picohttpparser/Makefile.am b/plugins/picohttpparser/Makefile.am new file mode 100644 index 00000000..5a610278 --- /dev/null +++ b/plugins/picohttpparser/Makefile.am | |||
@@ -0,0 +1,3 @@ | |||
1 | noinst_LIBRARIES = libpicohttpparser.a | ||
2 | |||
3 | libpicohttpparser_a_SOURCES = picohttpparser.c | ||
diff --git a/plugins/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c index 6a2d872d..6a2d872d 100644 --- a/plugins/picohttpparser.c +++ b/plugins/picohttpparser/picohttpparser.c | |||
diff --git a/plugins/picohttpparser.h b/plugins/picohttpparser/picohttpparser.h index a8fad71d..a8fad71d 100644 --- a/plugins/picohttpparser.h +++ b/plugins/picohttpparser/picohttpparser.h | |||
diff --git a/plugins/uriparser/Makefile.am b/plugins/uriparser/Makefile.am new file mode 100644 index 00000000..592e694c --- /dev/null +++ b/plugins/uriparser/Makefile.am | |||
@@ -0,0 +1,9 @@ | |||
1 | noinst_LIBRARIES = liburiparser.a | ||
2 | |||
3 | liburiparser_a_SOURCES = UriCommon.c UriCompare.c \ | ||
4 | UriEscape.c UriFile.c UriIp4.c \ | ||
5 | UriIp4Base.c UriNormalize.c \ | ||
6 | UriNormalizeBase.c UriParse.c \ | ||
7 | UriParseBase.c UriQuery.c \ | ||
8 | UriRecompose.c UriResolve.c \ | ||
9 | UriShorten.c | ||
diff --git a/plugins/uriparser/Uri.h b/plugins/uriparser/Uri.h new file mode 100644 index 00000000..4a185808 --- /dev/null +++ b/plugins/uriparser/Uri.h | |||
@@ -0,0 +1,777 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file Uri.h | ||
42 | * Holds the RFC 3986 %URI parser interface. | ||
43 | * NOTE: This header includes itself twice. | ||
44 | */ | ||
45 | |||
46 | #if (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI)) \ | ||
47 | || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE)) \ | ||
48 | || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
49 | /* What encodings are enabled? */ | ||
50 | #include "UriDefsConfig.h" | ||
51 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
52 | /* Include SELF twice */ | ||
53 | # ifdef URI_ENABLE_ANSI | ||
54 | # define URI_PASS_ANSI 1 | ||
55 | # include "Uri.h" | ||
56 | # undef URI_PASS_ANSI | ||
57 | # endif | ||
58 | # ifdef URI_ENABLE_UNICODE | ||
59 | # define URI_PASS_UNICODE 1 | ||
60 | # include "Uri.h" | ||
61 | # undef URI_PASS_UNICODE | ||
62 | # endif | ||
63 | /* Only one pass for each encoding */ | ||
64 | #elif (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI) \ | ||
65 | && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ | ||
66 | && !defined(URI_H_UNICODE) && defined(URI_ENABLE_UNICODE)) | ||
67 | # ifdef URI_PASS_ANSI | ||
68 | # define URI_H_ANSI 1 | ||
69 | # include "UriDefsAnsi.h" | ||
70 | # else | ||
71 | # define URI_H_UNICODE 1 | ||
72 | # include "UriDefsUnicode.h" | ||
73 | # endif | ||
74 | |||
75 | |||
76 | |||
77 | #ifdef __cplusplus | ||
78 | extern "C" { | ||
79 | #endif | ||
80 | |||
81 | |||
82 | |||
83 | #ifndef URI_DOXYGEN | ||
84 | # include "UriBase.h" | ||
85 | #endif | ||
86 | |||
87 | |||
88 | |||
89 | /** | ||
90 | * Specifies a range of characters within a string. | ||
91 | * The range includes all characters from <c>first</c> | ||
92 | * to one before <c>afterLast</c>. So if both are | ||
93 | * non-NULL the difference is the length of the text range. | ||
94 | * | ||
95 | * @see UriUriA | ||
96 | * @see UriPathSegmentA | ||
97 | * @see UriHostDataA | ||
98 | * @since 0.3.0 | ||
99 | */ | ||
100 | typedef struct URI_TYPE(TextRangeStruct) { | ||
101 | const URI_CHAR * first; /**< Pointer to first character */ | ||
102 | const URI_CHAR * afterLast; /**< Pointer to character after the last one still in */ | ||
103 | } URI_TYPE(TextRange); /**< @copydoc UriTextRangeStructA */ | ||
104 | |||
105 | |||
106 | |||
107 | /** | ||
108 | * Represents a path segment within a %URI path. | ||
109 | * More precisely it is a node in a linked | ||
110 | * list of path segments. | ||
111 | * | ||
112 | * @see UriUriA | ||
113 | * @since 0.3.0 | ||
114 | */ | ||
115 | typedef struct URI_TYPE(PathSegmentStruct) { | ||
116 | URI_TYPE(TextRange) text; /**< Path segment name */ | ||
117 | struct URI_TYPE(PathSegmentStruct) * next; /**< Pointer to the next path segment in the list, can be NULL if last already */ | ||
118 | |||
119 | void * reserved; /**< Reserved to the parser */ | ||
120 | } URI_TYPE(PathSegment); /**< @copydoc UriPathSegmentStructA */ | ||
121 | |||
122 | |||
123 | |||
124 | /** | ||
125 | * Holds structured host information. | ||
126 | * This is either a IPv4, IPv6, plain | ||
127 | * text for IPvFuture or all zero for | ||
128 | * a registered name. | ||
129 | * | ||
130 | * @see UriUriA | ||
131 | * @since 0.3.0 | ||
132 | */ | ||
133 | typedef struct URI_TYPE(HostDataStruct) { | ||
134 | UriIp4 * ip4; /**< IPv4 address */ | ||
135 | UriIp6 * ip6; /**< IPv6 address */ | ||
136 | URI_TYPE(TextRange) ipFuture; /**< IPvFuture address */ | ||
137 | } URI_TYPE(HostData); /**< @copydoc UriHostDataStructA */ | ||
138 | |||
139 | |||
140 | |||
141 | /** | ||
142 | * Represents an RFC 3986 %URI. | ||
143 | * Missing components can be {NULL, NULL} ranges. | ||
144 | * | ||
145 | * @see uriParseUriA | ||
146 | * @see uriFreeUriMembersA | ||
147 | * @see UriParserStateA | ||
148 | * @since 0.3.0 | ||
149 | */ | ||
150 | typedef struct URI_TYPE(UriStruct) { | ||
151 | URI_TYPE(TextRange) scheme; /**< Scheme (e.g. "http") */ | ||
152 | URI_TYPE(TextRange) userInfo; /**< User info (e.g. "user:pass") */ | ||
153 | URI_TYPE(TextRange) hostText; /**< Host text (set for all hosts, excluding square brackets) */ | ||
154 | URI_TYPE(HostData) hostData; /**< Structured host type specific data */ | ||
155 | URI_TYPE(TextRange) portText; /**< Port (e.g. "80") */ | ||
156 | URI_TYPE(PathSegment) * pathHead; /**< Head of a linked list of path segments */ | ||
157 | URI_TYPE(PathSegment) * pathTail; /**< Tail of the list behind pathHead */ | ||
158 | URI_TYPE(TextRange) query; /**< Query without leading "?" */ | ||
159 | URI_TYPE(TextRange) fragment; /**< Query without leading "#" */ | ||
160 | UriBool absolutePath; /**< Absolute path flag, distincting "a" and "/a" */ | ||
161 | UriBool owner; /**< Memory owner flag */ | ||
162 | |||
163 | void * reserved; /**< Reserved to the parser */ | ||
164 | } URI_TYPE(Uri); /**< @copydoc UriUriStructA */ | ||
165 | |||
166 | |||
167 | |||
168 | /** | ||
169 | * Represents a state of the %URI parser. | ||
170 | * Missing components can be NULL to reflect | ||
171 | * a components absence. | ||
172 | * | ||
173 | * @see uriFreeUriMembersA | ||
174 | * @since 0.3.0 | ||
175 | */ | ||
176 | typedef struct URI_TYPE(ParserStateStruct) { | ||
177 | URI_TYPE(Uri) * uri; /**< Plug in the %URI structure to be filled while parsing here */ | ||
178 | int errorCode; /**< Code identifying the occured error */ | ||
179 | const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */ | ||
180 | |||
181 | void * reserved; /**< Reserved to the parser */ | ||
182 | } URI_TYPE(ParserState); /**< @copydoc UriParserStateStructA */ | ||
183 | |||
184 | |||
185 | |||
186 | /** | ||
187 | * Represents a query element. | ||
188 | * More precisely it is a node in a linked | ||
189 | * list of query elements. | ||
190 | * | ||
191 | * @since 0.7.0 | ||
192 | */ | ||
193 | typedef struct URI_TYPE(QueryListStruct) { | ||
194 | const URI_CHAR * key; /**< Key of the query element */ | ||
195 | const URI_CHAR * value; /**< Value of the query element, can be NULL */ | ||
196 | |||
197 | struct URI_TYPE(QueryListStruct) * next; /**< Pointer to the next key/value pair in the list, can be NULL if last already */ | ||
198 | } URI_TYPE(QueryList); /**< @copydoc UriQueryListStructA */ | ||
199 | |||
200 | |||
201 | |||
202 | /** | ||
203 | * Parses a RFC 3986 URI. | ||
204 | * | ||
205 | * @param state <b>INOUT</b>: Parser state with set output %URI, must not be NULL | ||
206 | * @param first <b>IN</b>: Pointer to the first character to parse, must not be NULL | ||
207 | * @param afterLast <b>IN</b>: Pointer to the character after the last to parse, must not be NULL | ||
208 | * @return 0 on success, error code otherwise | ||
209 | * | ||
210 | * @see uriParseUriA | ||
211 | * @see uriToStringA | ||
212 | * @since 0.3.0 | ||
213 | */ | ||
214 | int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, | ||
215 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
216 | |||
217 | |||
218 | |||
219 | /** | ||
220 | * Parses a RFC 3986 %URI. | ||
221 | * | ||
222 | * @param state <b>INOUT</b>: Parser state with set output %URI, must not be NULL | ||
223 | * @param text <b>IN</b>: Text to parse, must not be NULL | ||
224 | * @return 0 on success, error code otherwise | ||
225 | * | ||
226 | * @see uriParseUriExA | ||
227 | * @see uriToStringA | ||
228 | * @since 0.3.0 | ||
229 | */ | ||
230 | int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, | ||
231 | const URI_CHAR * text); | ||
232 | |||
233 | |||
234 | |||
235 | /** | ||
236 | * Frees all memory associated with the members | ||
237 | * of the %URI structure. Note that the structure | ||
238 | * itself is not freed, only its members. | ||
239 | * | ||
240 | * @param uri <b>INOUT</b>: %URI structure whose members should be freed | ||
241 | * | ||
242 | * @since 0.3.0 | ||
243 | */ | ||
244 | void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri); | ||
245 | |||
246 | |||
247 | |||
248 | /** | ||
249 | * Percent-encodes all unreserved characters from the input string and | ||
250 | * writes the encoded version to the output string. | ||
251 | * Be sure to allocate <b>3 times</b> the space of the input buffer for | ||
252 | * the output buffer for <c>normalizeBreaks == URI_FALSE</c> and <b>6 times</b> | ||
253 | * the space for <c>normalizeBreaks == URI_TRUE</c> | ||
254 | * (since e.g. "\x0d" becomes "%0D%0A" in that case) | ||
255 | * | ||
256 | * @param inFirst <b>IN</b>: Pointer to first character of the input text | ||
257 | * @param inAfterLast <b>IN</b>: Pointer after the last character of the input text | ||
258 | * @param out <b>OUT</b>: Encoded text destination | ||
259 | * @param spaceToPlus <b>IN</b>: Wether to convert ' ' to '+' or not | ||
260 | * @param normalizeBreaks <b>IN</b>: Wether to convert CR and LF to CR-LF or not. | ||
261 | * @return Position of terminator in output string | ||
262 | * | ||
263 | * @see uriEscapeA | ||
264 | * @see uriUnescapeInPlaceExA | ||
265 | * @since 0.5.2 | ||
266 | */ | ||
267 | URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, | ||
268 | const URI_CHAR * inAfterLast, URI_CHAR * out, | ||
269 | UriBool spaceToPlus, UriBool normalizeBreaks); | ||
270 | |||
271 | |||
272 | |||
273 | /** | ||
274 | * Percent-encodes all unreserved characters from the input string and | ||
275 | * writes the encoded version to the output string. | ||
276 | * Be sure to allocate <b>3 times</b> the space of the input buffer for | ||
277 | * the output buffer for <c>normalizeBreaks == URI_FALSE</c> and <b>6 times</b> | ||
278 | * the space for <c>normalizeBreaks == URI_TRUE</c> | ||
279 | * (since e.g. "\x0d" becomes "%0D%0A" in that case) | ||
280 | * | ||
281 | * @param in <b>IN</b>: Text source | ||
282 | * @param out <b>OUT</b>: Encoded text destination | ||
283 | * @param spaceToPlus <b>IN</b>: Wether to convert ' ' to '+' or not | ||
284 | * @param normalizeBreaks <b>IN</b>: Wether to convert CR and LF to CR-LF or not. | ||
285 | * @return Position of terminator in output string | ||
286 | * | ||
287 | * @see uriEscapeExA | ||
288 | * @see uriUnescapeInPlaceA | ||
289 | * @since 0.5.0 | ||
290 | */ | ||
291 | URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, | ||
292 | UriBool spaceToPlus, UriBool normalizeBreaks); | ||
293 | |||
294 | |||
295 | |||
296 | /** | ||
297 | * Unescapes percent-encoded groups in a given string. | ||
298 | * E.g. "%20" will become " ". Unescaping is done in place. | ||
299 | * The return value will be point to the new position | ||
300 | * of the terminating zero. Use this value to get the new | ||
301 | * length of the string. NULL is only returned if <c>inout</c> | ||
302 | * is NULL. | ||
303 | * | ||
304 | * @param inout <b>INOUT</b>: Text to unescape/decode | ||
305 | * @param plusToSpace <b>IN</b>: Whether to convert '+' to ' ' or not | ||
306 | * @param breakConversion <b>IN</b>: Line break conversion mode | ||
307 | * @return Pointer to new position of the terminating zero | ||
308 | * | ||
309 | * @see uriUnescapeInPlaceA | ||
310 | * @see uriEscapeExA | ||
311 | * @since 0.5.0 | ||
312 | */ | ||
313 | const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, | ||
314 | UriBool plusToSpace, UriBreakConversion breakConversion); | ||
315 | |||
316 | |||
317 | |||
318 | /** | ||
319 | * Unescapes percent-encoded groups in a given string. | ||
320 | * E.g. "%20" will become " ". Unescaping is done in place. | ||
321 | * The return value will be point to the new position | ||
322 | * of the terminating zero. Use this value to get the new | ||
323 | * length of the string. NULL is only returned if <c>inout</c> | ||
324 | * is NULL. | ||
325 | * | ||
326 | * NOTE: '+' is not decoded to ' ' and line breaks are not converted. | ||
327 | * Use the more advanced UnescapeInPlaceEx for that features instead. | ||
328 | * | ||
329 | * @param inout <b>INOUT</b>: Text to unescape/decode | ||
330 | * @return Pointer to new position of the terminating zero | ||
331 | * | ||
332 | * @see uriUnescapeInPlaceExA | ||
333 | * @see uriEscapeA | ||
334 | * @since 0.3.0 | ||
335 | */ | ||
336 | const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout); | ||
337 | |||
338 | |||
339 | |||
340 | /** | ||
341 | * Performs reference resolution as described in | ||
342 | * <a href="http://tools.ietf.org/html/rfc3986#section-5.2.2">section 5.2.2 of RFC 3986</a>. | ||
343 | * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later. | ||
344 | * | ||
345 | * @param absoluteDest <b>OUT</b>: Result %URI | ||
346 | * @param relativeSource <b>IN</b>: Reference to resolve | ||
347 | * @param absoluteBase <b>IN</b>: Base %URI to apply | ||
348 | * @return Error code or 0 on success | ||
349 | * | ||
350 | * @see uriRemoveBaseUriA, uriAddBaseUriExA | ||
351 | * @since 0.4.0 | ||
352 | */ | ||
353 | int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absoluteDest, | ||
354 | const URI_TYPE(Uri) * relativeSource, | ||
355 | const URI_TYPE(Uri) * absoluteBase); | ||
356 | |||
357 | |||
358 | |||
359 | /** | ||
360 | * Performs reference resolution as described in | ||
361 | * <a href="http://tools.ietf.org/html/rfc3986#section-5.2.2">section 5.2.2 of RFC 3986</a>. | ||
362 | * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later. | ||
363 | * | ||
364 | * @param absoluteDest <b>OUT</b>: Result %URI | ||
365 | * @param relativeSource <b>IN</b>: Reference to resolve | ||
366 | * @param absoluteBase <b>IN</b>: Base %URI to apply | ||
367 | * @param options <b>IN</b>: Configuration to apply | ||
368 | * @return Error code or 0 on success | ||
369 | * | ||
370 | * @see uriRemoveBaseUriA, uriAddBaseUriA | ||
371 | * @since 0.8.1 | ||
372 | */ | ||
373 | int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absoluteDest, | ||
374 | const URI_TYPE(Uri) * relativeSource, | ||
375 | const URI_TYPE(Uri) * absoluteBase, | ||
376 | UriResolutionOptions options); | ||
377 | |||
378 | |||
379 | |||
380 | /** | ||
381 | * Tries to make a relative %URI (a reference) from an | ||
382 | * absolute %URI and a given base %URI. This can only work if | ||
383 | * the absolute %URI shares scheme and authority with | ||
384 | * the base %URI. If it does not the result will still be | ||
385 | * an absolute URI (with scheme part if necessary). | ||
386 | * NOTE: On success you have to call uriFreeUriMembersA on | ||
387 | * \p dest manually later. | ||
388 | * | ||
389 | * @param dest <b>OUT</b>: Result %URI | ||
390 | * @param absoluteSource <b>IN</b>: Absolute %URI to make relative | ||
391 | * @param absoluteBase <b>IN</b>: Base %URI | ||
392 | * @param domainRootMode <b>IN</b>: Create %URI with path relative to domain root | ||
393 | * @return Error code or 0 on success | ||
394 | * | ||
395 | * @see uriAddBaseUriA, uriAddBaseUriExA | ||
396 | * @since 0.5.2 | ||
397 | */ | ||
398 | int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, | ||
399 | const URI_TYPE(Uri) * absoluteSource, | ||
400 | const URI_TYPE(Uri) * absoluteBase, | ||
401 | UriBool domainRootMode); | ||
402 | |||
403 | |||
404 | |||
405 | /** | ||
406 | * Checks two URIs for equivalence. Comparison is done | ||
407 | * the naive way, without prior normalization. | ||
408 | * NOTE: Two <c>NULL</c> URIs are equal as well. | ||
409 | * | ||
410 | * @param a <b>IN</b>: First %URI | ||
411 | * @param b <b>IN</b>: Second %URI | ||
412 | * @return <c>URI_TRUE</c> when equal, <c>URI_FAlSE</c> else | ||
413 | * | ||
414 | * @since 0.4.0 | ||
415 | */ | ||
416 | UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b); | ||
417 | |||
418 | |||
419 | |||
420 | /** | ||
421 | * Calculates the number of characters needed to store the | ||
422 | * string representation of the given %URI excluding the | ||
423 | * terminator. | ||
424 | * | ||
425 | * @param uri <b>IN</b>: %URI to measure | ||
426 | * @param charsRequired <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator | ||
427 | * @return Error code or 0 on success | ||
428 | * | ||
429 | * @see uriToStringA | ||
430 | * @since 0.5.0 | ||
431 | */ | ||
432 | int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, | ||
433 | int * charsRequired); | ||
434 | |||
435 | |||
436 | |||
437 | /** | ||
438 | * Converts a %URI structure back to text as described in | ||
439 | * <a href="http://tools.ietf.org/html/rfc3986#section-5.3">section 5.3 of RFC 3986</a>. | ||
440 | * | ||
441 | * @param dest <b>OUT</b>: Output destination | ||
442 | * @param uri <b>IN</b>: %URI to convert | ||
443 | * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator | ||
444 | * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than maxChars even if the %URI is too long! | ||
445 | * @return Error code or 0 on success | ||
446 | * | ||
447 | * @see uriToStringCharsRequiredA | ||
448 | * @since 0.4.0 | ||
449 | */ | ||
450 | int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten); | ||
451 | |||
452 | |||
453 | |||
454 | /** | ||
455 | * Determines the components of a %URI that are not normalized. | ||
456 | * | ||
457 | * @param uri <b>IN</b>: %URI to check | ||
458 | * @return Normalization job mask | ||
459 | * | ||
460 | * @see uriNormalizeSyntaxA | ||
461 | * @since 0.5.0 | ||
462 | */ | ||
463 | unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri); | ||
464 | |||
465 | |||
466 | |||
467 | /** | ||
468 | * Normalizes a %URI using a normalization mask. | ||
469 | * The normalization mask decides what components are normalized. | ||
470 | * | ||
471 | * NOTE: If necessary the %URI becomes owner of all memory | ||
472 | * behind the text pointed to. Text is duplicated in that case. | ||
473 | * | ||
474 | * @param uri <b>INOUT</b>: %URI to normalize | ||
475 | * @param mask <b>IN</b>: Normalization mask | ||
476 | * @return Error code or 0 on success | ||
477 | * | ||
478 | * @see uriNormalizeSyntaxA | ||
479 | * @see uriNormalizeSyntaxMaskRequiredA | ||
480 | * @since 0.5.0 | ||
481 | */ | ||
482 | int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask); | ||
483 | |||
484 | |||
485 | |||
486 | /** | ||
487 | * Normalizes all components of a %URI. | ||
488 | * | ||
489 | * NOTE: If necessary the %URI becomes owner of all memory | ||
490 | * behind the text pointed to. Text is duplicated in that case. | ||
491 | * | ||
492 | * @param uri <b>INOUT</b>: %URI to normalize | ||
493 | * @return Error code or 0 on success | ||
494 | * | ||
495 | * @see uriNormalizeSyntaxExA | ||
496 | * @see uriNormalizeSyntaxMaskRequiredA | ||
497 | * @since 0.5.0 | ||
498 | */ | ||
499 | int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri); | ||
500 | |||
501 | |||
502 | |||
503 | /** | ||
504 | * Converts a Unix filename to a %URI string. | ||
505 | * The destination buffer must be large enough to hold 7 + 3 * len(filename) + 1 | ||
506 | * characters in case of an absolute filename or 3 * len(filename) + 1 in case | ||
507 | * of a relative filename. | ||
508 | * | ||
509 | * EXAMPLE | ||
510 | * Input: "/bin/bash" | ||
511 | * Output: "file:///bin/bash" | ||
512 | * | ||
513 | * @param filename <b>IN</b>: Unix filename to convert | ||
514 | * @param uriString <b>OUT</b>: Destination to write %URI string to | ||
515 | * @return Error code or 0 on success | ||
516 | * | ||
517 | * @see uriUriStringToUnixFilenameA | ||
518 | * @see uriWindowsFilenameToUriStringA | ||
519 | * @since 0.5.2 | ||
520 | */ | ||
521 | int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, | ||
522 | URI_CHAR * uriString); | ||
523 | |||
524 | |||
525 | |||
526 | /** | ||
527 | * Converts a Windows filename to a %URI string. | ||
528 | * The destination buffer must be large enough to hold 8 + 3 * len(filename) + 1 | ||
529 | * characters in case of an absolute filename or 3 * len(filename) + 1 in case | ||
530 | * of a relative filename. | ||
531 | * | ||
532 | * EXAMPLE | ||
533 | * Input: "E:\\Documents and Settings" | ||
534 | * Output: "file:///E:/Documents%20and%20Settings" | ||
535 | * | ||
536 | * @param filename <b>IN</b>: Windows filename to convert | ||
537 | * @param uriString <b>OUT</b>: Destination to write %URI string to | ||
538 | * @return Error code or 0 on success | ||
539 | * | ||
540 | * @see uriUriStringToWindowsFilenameA | ||
541 | * @see uriUnixFilenameToUriStringA | ||
542 | * @since 0.5.2 | ||
543 | */ | ||
544 | int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, | ||
545 | URI_CHAR * uriString); | ||
546 | |||
547 | |||
548 | |||
549 | /** | ||
550 | * Extracts a Unix filename from a %URI string. | ||
551 | * The destination buffer must be large enough to hold len(uriString) + 1 - 7 | ||
552 | * characters in case of an absolute %URI or len(uriString) + 1 in case | ||
553 | * of a relative %URI. | ||
554 | * | ||
555 | * @param uriString <b>IN</b>: %URI string to convert | ||
556 | * @param filename <b>OUT</b>: Destination to write filename to | ||
557 | * @return Error code or 0 on success | ||
558 | * | ||
559 | * @see uriUnixFilenameToUriStringA | ||
560 | * @see uriUriStringToWindowsFilenameA | ||
561 | * @since 0.5.2 | ||
562 | */ | ||
563 | int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, | ||
564 | URI_CHAR * filename); | ||
565 | |||
566 | |||
567 | |||
568 | /** | ||
569 | * Extracts a Windows filename from a %URI string. | ||
570 | * The destination buffer must be large enough to hold len(uriString) + 1 - 8 | ||
571 | * characters in case of an absolute %URI or len(uriString) + 1 in case | ||
572 | * of a relative %URI. | ||
573 | * | ||
574 | * @param uriString <b>IN</b>: %URI string to convert | ||
575 | * @param filename <b>OUT</b>: Destination to write filename to | ||
576 | * @return Error code or 0 on success | ||
577 | * | ||
578 | * @see uriWindowsFilenameToUriStringA | ||
579 | * @see uriUriStringToUnixFilenameA | ||
580 | * @since 0.5.2 | ||
581 | */ | ||
582 | int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, | ||
583 | URI_CHAR * filename); | ||
584 | |||
585 | |||
586 | |||
587 | /** | ||
588 | * Calculates the number of characters needed to store the | ||
589 | * string representation of the given query list excluding the | ||
590 | * terminator. It is assumed that line breaks are will be | ||
591 | * normalized to "%0D%0A". | ||
592 | * | ||
593 | * @param queryList <b>IN</b>: Query list to measure | ||
594 | * @param charsRequired <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator | ||
595 | * @return Error code or 0 on success | ||
596 | * | ||
597 | * @see uriComposeQueryCharsRequiredExA | ||
598 | * @see uriComposeQueryA | ||
599 | * @since 0.7.0 | ||
600 | */ | ||
601 | int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, | ||
602 | int * charsRequired); | ||
603 | |||
604 | |||
605 | |||
606 | /** | ||
607 | * Calculates the number of characters needed to store the | ||
608 | * string representation of the given query list excluding the | ||
609 | * terminator. | ||
610 | * | ||
611 | * @param queryList <b>IN</b>: Query list to measure | ||
612 | * @param charsRequired <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator | ||
613 | * @param spaceToPlus <b>IN</b>: Wether to convert ' ' to '+' or not | ||
614 | * @param normalizeBreaks <b>IN</b>: Wether to convert CR and LF to CR-LF or not. | ||
615 | * @return Error code or 0 on success | ||
616 | * | ||
617 | * @see uriComposeQueryCharsRequiredA | ||
618 | * @see uriComposeQueryExA | ||
619 | * @since 0.7.0 | ||
620 | */ | ||
621 | int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList, | ||
622 | int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks); | ||
623 | |||
624 | |||
625 | |||
626 | /** | ||
627 | * Converts a query list structure back to a query string. | ||
628 | * The composed string does not start with '?', | ||
629 | * on the way ' ' is converted to '+' and line breaks are | ||
630 | * normalized to "%0D%0A". | ||
631 | * | ||
632 | * @param dest <b>OUT</b>: Output destination | ||
633 | * @param queryList <b>IN</b>: Query list to convert | ||
634 | * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator | ||
635 | * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than maxChars even if the query list is too long! | ||
636 | * @return Error code or 0 on success | ||
637 | * | ||
638 | * @see uriComposeQueryExA | ||
639 | * @see uriComposeQueryMallocA | ||
640 | * @see uriComposeQueryCharsRequiredA | ||
641 | * @see uriDissectQueryMallocA | ||
642 | * @since 0.7.0 | ||
643 | */ | ||
644 | int URI_FUNC(ComposeQuery)(URI_CHAR * dest, | ||
645 | const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten); | ||
646 | |||
647 | |||
648 | |||
649 | /** | ||
650 | * Converts a query list structure back to a query string. | ||
651 | * The composed string does not start with '?'. | ||
652 | * | ||
653 | * @param dest <b>OUT</b>: Output destination | ||
654 | * @param queryList <b>IN</b>: Query list to convert | ||
655 | * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator | ||
656 | * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than maxChars even if the query list is too long! | ||
657 | * @param spaceToPlus <b>IN</b>: Wether to convert ' ' to '+' or not | ||
658 | * @param normalizeBreaks <b>IN</b>: Wether to convert CR and LF to CR-LF or not. | ||
659 | * @return Error code or 0 on success | ||
660 | * | ||
661 | * @see uriComposeQueryA | ||
662 | * @see uriComposeQueryMallocExA | ||
663 | * @see uriComposeQueryCharsRequiredExA | ||
664 | * @see uriDissectQueryMallocExA | ||
665 | * @since 0.7.0 | ||
666 | */ | ||
667 | int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, | ||
668 | const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, | ||
669 | UriBool spaceToPlus, UriBool normalizeBreaks); | ||
670 | |||
671 | |||
672 | |||
673 | /** | ||
674 | * Converts a query list structure back to a query string. | ||
675 | * Memory for this string is allocated internally. | ||
676 | * The composed string does not start with '?', | ||
677 | * on the way ' ' is converted to '+' and line breaks are | ||
678 | * normalized to "%0D%0A". | ||
679 | * | ||
680 | * @param dest <b>OUT</b>: Output destination | ||
681 | * @param queryList <b>IN</b>: Query list to convert | ||
682 | * @return Error code or 0 on success | ||
683 | * | ||
684 | * @see uriComposeQueryMallocExA | ||
685 | * @see uriComposeQueryA | ||
686 | * @see uriDissectQueryMallocA | ||
687 | * @since 0.7.0 | ||
688 | */ | ||
689 | int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, | ||
690 | const URI_TYPE(QueryList) * queryList); | ||
691 | |||
692 | |||
693 | |||
694 | /** | ||
695 | * Converts a query list structure back to a query string. | ||
696 | * Memory for this string is allocated internally. | ||
697 | * The composed string does not start with '?'. | ||
698 | * | ||
699 | * @param dest <b>OUT</b>: Output destination | ||
700 | * @param queryList <b>IN</b>: Query list to convert | ||
701 | * @param spaceToPlus <b>IN</b>: Wether to convert ' ' to '+' or not | ||
702 | * @param normalizeBreaks <b>IN</b>: Wether to convert CR and LF to CR-LF or not. | ||
703 | * @return Error code or 0 on success | ||
704 | * | ||
705 | * @see uriComposeQueryMallocA | ||
706 | * @see uriComposeQueryExA | ||
707 | * @see uriDissectQueryMallocExA | ||
708 | * @since 0.7.0 | ||
709 | */ | ||
710 | int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, | ||
711 | const URI_TYPE(QueryList) * queryList, | ||
712 | UriBool spaceToPlus, UriBool normalizeBreaks); | ||
713 | |||
714 | |||
715 | |||
716 | /** | ||
717 | * Constructs a query list from the raw query string of a given URI. | ||
718 | * On the way '+' is converted back to ' ', line breaks are not modified. | ||
719 | * | ||
720 | * @param dest <b>OUT</b>: Output destination | ||
721 | * @param itemCount <b>OUT</b>: Number of items found, can be NULL | ||
722 | * @param first <b>IN</b>: Pointer to first character <b>after</b> '?' | ||
723 | * @param afterLast <b>IN</b>: Pointer to character after the last one still in | ||
724 | * @return Error code or 0 on success | ||
725 | * | ||
726 | * @see uriDissectQueryMallocExA | ||
727 | * @see uriComposeQueryA | ||
728 | * @see uriFreeQueryListA | ||
729 | * @since 0.7.0 | ||
730 | */ | ||
731 | int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount, | ||
732 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
733 | |||
734 | |||
735 | |||
736 | /** | ||
737 | * Constructs a query list from the raw query string of a given URI. | ||
738 | * | ||
739 | * @param dest <b>OUT</b>: Output destination | ||
740 | * @param itemCount <b>OUT</b>: Number of items found, can be NULL | ||
741 | * @param first <b>IN</b>: Pointer to first character <b>after</b> '?' | ||
742 | * @param afterLast <b>IN</b>: Pointer to character after the last one still in | ||
743 | * @param plusToSpace <b>IN</b>: Whether to convert '+' to ' ' or not | ||
744 | * @param breakConversion <b>IN</b>: Line break conversion mode | ||
745 | * @return Error code or 0 on success | ||
746 | * | ||
747 | * @see uriDissectQueryMallocA | ||
748 | * @see uriComposeQueryExA | ||
749 | * @see uriFreeQueryListA | ||
750 | * @since 0.7.0 | ||
751 | */ | ||
752 | int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount, | ||
753 | const URI_CHAR * first, const URI_CHAR * afterLast, | ||
754 | UriBool plusToSpace, UriBreakConversion breakConversion); | ||
755 | |||
756 | |||
757 | |||
758 | /** | ||
759 | * Frees all memory associated with the given query list. | ||
760 | * The structure itself is freed as well. | ||
761 | * | ||
762 | * @param queryList <b>INOUT</b>: Query list to free | ||
763 | * | ||
764 | * @since 0.7.0 | ||
765 | */ | ||
766 | void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList); | ||
767 | |||
768 | |||
769 | |||
770 | #ifdef __cplusplus | ||
771 | } | ||
772 | #endif | ||
773 | |||
774 | |||
775 | |||
776 | #endif | ||
777 | #endif | ||
diff --git a/plugins/uriparser/UriBase.h b/plugins/uriparser/UriBase.h new file mode 100644 index 00000000..bc63b059 --- /dev/null +++ b/plugins/uriparser/UriBase.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriBase.h | ||
42 | * Holds definitions independent of the encoding pass. | ||
43 | */ | ||
44 | |||
45 | #ifndef URI_BASE_H | ||
46 | #define URI_BASE_H 1 | ||
47 | |||
48 | |||
49 | |||
50 | /* Version helper macro */ | ||
51 | #define URI_ANSI_TO_UNICODE(x) L##x | ||
52 | |||
53 | |||
54 | |||
55 | /* Version */ | ||
56 | #define URI_VER_MAJOR 0 | ||
57 | #define URI_VER_MINOR 8 | ||
58 | #define URI_VER_RELEASE 4 | ||
59 | #define URI_VER_SUFFIX_ANSI "" | ||
60 | #define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI) | ||
61 | |||
62 | |||
63 | |||
64 | /* More version helper macros */ | ||
65 | #define URI_INT_TO_ANSI_HELPER(x) #x | ||
66 | #define URI_INT_TO_ANSI(x) URI_INT_TO_ANSI_HELPER(x) | ||
67 | |||
68 | #define URI_INT_TO_UNICODE_HELPER(x) URI_ANSI_TO_UNICODE(#x) | ||
69 | #define URI_INT_TO_UNICODE(x) URI_INT_TO_UNICODE_HELPER(x) | ||
70 | |||
71 | #define URI_VER_ANSI_HELPER(ma, mi, r, s) \ | ||
72 | URI_INT_TO_ANSI(ma) "." \ | ||
73 | URI_INT_TO_ANSI(mi) "." \ | ||
74 | URI_INT_TO_ANSI(r) \ | ||
75 | s | ||
76 | |||
77 | #define URI_VER_UNICODE_HELPER(ma, mi, r, s) \ | ||
78 | URI_INT_TO_UNICODE(ma) L"." \ | ||
79 | URI_INT_TO_UNICODE(mi) L"." \ | ||
80 | URI_INT_TO_UNICODE(r) \ | ||
81 | s | ||
82 | |||
83 | |||
84 | |||
85 | /* Full version strings */ | ||
86 | #define URI_VER_ANSI URI_VER_ANSI_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_ANSI) | ||
87 | #define URI_VER_UNICODE URI_VER_UNICODE_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_UNICODE) | ||
88 | |||
89 | |||
90 | |||
91 | /* Unused parameter macro */ | ||
92 | #ifdef __GNUC__ | ||
93 | # define URI_UNUSED(x) unused_##x __attribute__((unused)) | ||
94 | #else | ||
95 | # define URI_UNUSED(x) x | ||
96 | #endif | ||
97 | |||
98 | |||
99 | |||
100 | typedef int UriBool; /**< Boolean type */ | ||
101 | |||
102 | #define URI_TRUE 1 | ||
103 | #define URI_FALSE 0 | ||
104 | |||
105 | |||
106 | |||
107 | /* Shared errors */ | ||
108 | #define URI_SUCCESS 0 | ||
109 | #define URI_ERROR_SYNTAX 1 /* Parsed text violates expected format */ | ||
110 | #define URI_ERROR_NULL 2 /* One of the params passed was NULL | ||
111 | although it mustn't be */ | ||
112 | #define URI_ERROR_MALLOC 3 /* Requested memory could not be allocated */ | ||
113 | #define URI_ERROR_OUTPUT_TOO_LARGE 4 /* Some output is to large for the receiving buffer */ | ||
114 | #define URI_ERROR_NOT_IMPLEMENTED 8 /* The called function is not implemented yet */ | ||
115 | #define URI_ERROR_RANGE_INVALID 9 /* The parameters passed contained invalid ranges */ | ||
116 | |||
117 | |||
118 | /* Errors specific to ToString */ | ||
119 | #define URI_ERROR_TOSTRING_TOO_LONG URI_ERROR_OUTPUT_TOO_LARGE /* Deprecated, test for URI_ERROR_OUTPUT_TOO_LARGE instead */ | ||
120 | |||
121 | /* Errors specific to AddBaseUri */ | ||
122 | #define URI_ERROR_ADDBASE_REL_BASE 5 /* Given base is not absolute */ | ||
123 | |||
124 | /* Errors specific to RemoveBaseUri */ | ||
125 | #define URI_ERROR_REMOVEBASE_REL_BASE 6 /* Given base is not absolute */ | ||
126 | #define URI_ERROR_REMOVEBASE_REL_SOURCE 7 /* Given base is not absolute */ | ||
127 | |||
128 | |||
129 | |||
130 | #ifndef URI_DOXYGEN | ||
131 | # include <stdio.h> /* For NULL, snprintf */ | ||
132 | # include <ctype.h> /* For wchar_t */ | ||
133 | # include <string.h> /* For strlen, memset, memcpy */ | ||
134 | # include <stdlib.h> /* For malloc */ | ||
135 | #endif /* URI_DOXYGEN */ | ||
136 | |||
137 | |||
138 | |||
139 | /** | ||
140 | * Holds an IPv4 address. | ||
141 | */ | ||
142 | typedef struct UriIp4Struct { | ||
143 | unsigned char data[4]; /**< Each octet in one byte */ | ||
144 | } UriIp4; /**< @copydoc UriIp4Struct */ | ||
145 | |||
146 | |||
147 | |||
148 | /** | ||
149 | * Holds an IPv6 address. | ||
150 | */ | ||
151 | typedef struct UriIp6Struct { | ||
152 | unsigned char data[16]; /**< Each quad in two bytes */ | ||
153 | } UriIp6; /**< @copydoc UriIp6Struct */ | ||
154 | |||
155 | |||
156 | |||
157 | /** | ||
158 | * Specifies a line break conversion mode. | ||
159 | */ | ||
160 | typedef enum UriBreakConversionEnum { | ||
161 | URI_BR_TO_LF, /**< Convert to Unix line breaks ("\\x0a") */ | ||
162 | URI_BR_TO_CRLF, /**< Convert to Windows line breaks ("\\x0d\\x0a") */ | ||
163 | URI_BR_TO_CR, /**< Convert to Macintosh line breaks ("\\x0d") */ | ||
164 | URI_BR_TO_UNIX = URI_BR_TO_LF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_LF */ | ||
165 | URI_BR_TO_WINDOWS = URI_BR_TO_CRLF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CRLF */ | ||
166 | URI_BR_TO_MAC = URI_BR_TO_CR, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CR */ | ||
167 | URI_BR_DONT_TOUCH /**< Copy line breaks unmodified */ | ||
168 | } UriBreakConversion; /**< @copydoc UriBreakConversionEnum */ | ||
169 | |||
170 | |||
171 | |||
172 | /** | ||
173 | * Specifies which component of a %URI has to be normalized. | ||
174 | */ | ||
175 | typedef enum UriNormalizationMaskEnum { | ||
176 | URI_NORMALIZED = 0, /**< Do not normalize anything */ | ||
177 | URI_NORMALIZE_SCHEME = 1 << 0, /**< Normalize scheme (fix uppercase letters) */ | ||
178 | URI_NORMALIZE_USER_INFO = 1 << 1, /**< Normalize user info (fix uppercase percent-encodings) */ | ||
179 | URI_NORMALIZE_HOST = 1 << 2, /**< Normalize host (fix uppercase letters) */ | ||
180 | URI_NORMALIZE_PATH = 1 << 3, /**< Normalize path (fix uppercase percent-encodings and redundant dot segments) */ | ||
181 | URI_NORMALIZE_QUERY = 1 << 4, /**< Normalize query (fix uppercase percent-encodings) */ | ||
182 | URI_NORMALIZE_FRAGMENT = 1 << 5 /**< Normalize fragment (fix uppercase percent-encodings) */ | ||
183 | } UriNormalizationMask; /**< @copydoc UriNormalizationMaskEnum */ | ||
184 | |||
185 | |||
186 | |||
187 | /** | ||
188 | * Specifies how to resolve %URI references. | ||
189 | */ | ||
190 | typedef enum UriResolutionOptionsEnum { | ||
191 | URI_RESOLVE_STRICTLY = 0, /**< Full RFC conformance */ | ||
192 | URI_RESOLVE_IDENTICAL_SCHEME_COMPAT = 1 << 0 /**< Treat %URI to resolve with identical scheme as having no scheme */ | ||
193 | } UriResolutionOptions; /**< @copydoc UriResolutionOptionsEnum */ | ||
194 | |||
195 | |||
196 | |||
197 | #endif /* URI_BASE_H */ | ||
diff --git a/plugins/uriparser/UriCommon.c b/plugins/uriparser/UriCommon.c new file mode 100644 index 00000000..37d6b39d --- /dev/null +++ b/plugins/uriparser/UriCommon.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriCommon.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriCommon.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include "UriCommon.h" | ||
67 | #endif | ||
68 | |||
69 | |||
70 | |||
71 | /*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X"); | ||
72 | /*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT("."); | ||
73 | /*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT(".."); | ||
74 | |||
75 | |||
76 | |||
77 | void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) { | ||
78 | memset(uri, 0, sizeof(URI_TYPE(Uri))); | ||
79 | } | ||
80 | |||
81 | |||
82 | |||
83 | /* Compares two text ranges for equal text content */ | ||
84 | int URI_FUNC(CompareRange)( | ||
85 | const URI_TYPE(TextRange) * a, | ||
86 | const URI_TYPE(TextRange) * b) { | ||
87 | int diff; | ||
88 | |||
89 | /* NOTE: Both NULL means equal! */ | ||
90 | if ((a == NULL) || (b == NULL)) { | ||
91 | return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1); | ||
92 | } | ||
93 | |||
94 | /* NOTE: Both NULL means equal! */ | ||
95 | if ((a->first == NULL) || (b->first == NULL)) { | ||
96 | return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1); | ||
97 | } | ||
98 | |||
99 | diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first)); | ||
100 | if (diff > 0) { | ||
101 | return 1; | ||
102 | } else if (diff < 0) { | ||
103 | return -1; | ||
104 | } | ||
105 | |||
106 | diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first)); | ||
107 | |||
108 | if (diff > 0) { | ||
109 | return 1; | ||
110 | } else if (diff < 0) { | ||
111 | return -1; | ||
112 | } | ||
113 | |||
114 | return diff; | ||
115 | } | ||
116 | |||
117 | |||
118 | |||
119 | /* Properly removes "." and ".." path segments */ | ||
120 | UriBool URI_FUNC(RemoveDotSegments)(URI_TYPE(Uri) * uri, | ||
121 | UriBool relative) { | ||
122 | if (uri == NULL) { | ||
123 | return URI_TRUE; | ||
124 | } | ||
125 | return URI_FUNC(RemoveDotSegmentsEx)(uri, relative, uri->owner); | ||
126 | } | ||
127 | |||
128 | |||
129 | |||
130 | UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, | ||
131 | UriBool relative, UriBool pathOwned) { | ||
132 | URI_TYPE(PathSegment) * walker; | ||
133 | if ((uri == NULL) || (uri->pathHead == NULL)) { | ||
134 | return URI_TRUE; | ||
135 | } | ||
136 | |||
137 | walker = uri->pathHead; | ||
138 | walker->reserved = NULL; /* Prev pointer */ | ||
139 | do { | ||
140 | UriBool removeSegment = URI_FALSE; | ||
141 | int len = (int)(walker->text.afterLast - walker->text.first); | ||
142 | switch (len) { | ||
143 | case 1: | ||
144 | if ((walker->text.first)[0] == _UT('.')) { | ||
145 | /* "." segment -> remove if not essential */ | ||
146 | URI_TYPE(PathSegment) * const prev = walker->reserved; | ||
147 | URI_TYPE(PathSegment) * const nextBackup = walker->next; | ||
148 | |||
149 | /* Is this dot segment essential? */ | ||
150 | removeSegment = URI_TRUE; | ||
151 | if (relative && (walker == uri->pathHead) && (walker->next != NULL)) { | ||
152 | const URI_CHAR * ch = walker->next->text.first; | ||
153 | for (; ch < walker->next->text.afterLast; ch++) { | ||
154 | if (*ch == _UT(':')) { | ||
155 | removeSegment = URI_FALSE; | ||
156 | break; | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | if (removeSegment) { | ||
162 | /* Last segment? */ | ||
163 | if (walker->next != NULL) { | ||
164 | /* Not last segment */ | ||
165 | walker->next->reserved = prev; | ||
166 | |||
167 | if (prev == NULL) { | ||
168 | /* First but not last segment */ | ||
169 | uri->pathHead = walker->next; | ||
170 | } else { | ||
171 | /* Middle segment */ | ||
172 | prev->next = walker->next; | ||
173 | } | ||
174 | |||
175 | if (pathOwned && (walker->text.first != walker->text.afterLast)) { | ||
176 | free((URI_CHAR *)walker->text.first); | ||
177 | } | ||
178 | free(walker); | ||
179 | } else { | ||
180 | /* Last segment */ | ||
181 | if (pathOwned && (walker->text.first != walker->text.afterLast)) { | ||
182 | free((URI_CHAR *)walker->text.first); | ||
183 | } | ||
184 | |||
185 | if (prev == NULL) { | ||
186 | /* Last and first */ | ||
187 | if (URI_FUNC(IsHostSet)(uri)) { | ||
188 | /* Replace "." with empty segment to represent trailing slash */ | ||
189 | walker->text.first = URI_FUNC(SafeToPointTo); | ||
190 | walker->text.afterLast = URI_FUNC(SafeToPointTo); | ||
191 | } else { | ||
192 | free(walker); | ||
193 | |||
194 | uri->pathHead = NULL; | ||
195 | uri->pathTail = NULL; | ||
196 | } | ||
197 | } else { | ||
198 | /* Last but not first, replace "." with empty segment to represent trailing slash */ | ||
199 | walker->text.first = URI_FUNC(SafeToPointTo); | ||
200 | walker->text.afterLast = URI_FUNC(SafeToPointTo); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | walker = nextBackup; | ||
205 | } | ||
206 | } | ||
207 | break; | ||
208 | |||
209 | case 2: | ||
210 | if (((walker->text.first)[0] == _UT('.')) | ||
211 | && ((walker->text.first)[1] == _UT('.'))) { | ||
212 | /* Path ".." -> remove this and the previous segment */ | ||
213 | URI_TYPE(PathSegment) * const prev = walker->reserved; | ||
214 | URI_TYPE(PathSegment) * prevPrev; | ||
215 | URI_TYPE(PathSegment) * const nextBackup = walker->next; | ||
216 | |||
217 | removeSegment = URI_TRUE; | ||
218 | if (relative) { | ||
219 | if (prev == NULL) { | ||
220 | removeSegment = URI_FALSE; | ||
221 | } else if ((prev != NULL) | ||
222 | && ((prev->text.afterLast - prev->text.first) == 2) | ||
223 | && ((prev->text.first)[0] == _UT('.')) | ||
224 | && ((prev->text.first)[1] == _UT('.'))) { | ||
225 | removeSegment = URI_FALSE; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | if (removeSegment) { | ||
230 | if (prev != NULL) { | ||
231 | /* Not first segment */ | ||
232 | prevPrev = prev->reserved; | ||
233 | if (prevPrev != NULL) { | ||
234 | /* Not even prev is the first one */ | ||
235 | prevPrev->next = walker->next; | ||
236 | if (walker->next != NULL) { | ||
237 | walker->next->reserved = prevPrev; | ||
238 | } else { | ||
239 | /* Last segment -> insert "" segment to represent trailing slash, update tail */ | ||
240 | URI_TYPE(PathSegment) * const segment = malloc(1 * sizeof(URI_TYPE(PathSegment))); | ||
241 | if (segment == NULL) { | ||
242 | if (pathOwned && (walker->text.first != walker->text.afterLast)) { | ||
243 | free((URI_CHAR *)walker->text.first); | ||
244 | } | ||
245 | free(walker); | ||
246 | |||
247 | if (pathOwned && (prev->text.first != prev->text.afterLast)) { | ||
248 | free((URI_CHAR *)prev->text.first); | ||
249 | } | ||
250 | free(prev); | ||
251 | |||
252 | return URI_FALSE; /* Raises malloc error */ | ||
253 | } | ||
254 | memset(segment, 0, sizeof(URI_TYPE(PathSegment))); | ||
255 | segment->text.first = URI_FUNC(SafeToPointTo); | ||
256 | segment->text.afterLast = URI_FUNC(SafeToPointTo); | ||
257 | prevPrev->next = segment; | ||
258 | uri->pathTail = segment; | ||
259 | } | ||
260 | |||
261 | if (pathOwned && (walker->text.first != walker->text.afterLast)) { | ||
262 | free((URI_CHAR *)walker->text.first); | ||
263 | } | ||
264 | free(walker); | ||
265 | |||
266 | if (pathOwned && (prev->text.first != prev->text.afterLast)) { | ||
267 | free((URI_CHAR *)prev->text.first); | ||
268 | } | ||
269 | free(prev); | ||
270 | |||
271 | walker = nextBackup; | ||
272 | } else { | ||
273 | /* Prev is the first segment */ | ||
274 | if (walker->next != NULL) { | ||
275 | uri->pathHead = walker->next; | ||
276 | walker->next->reserved = NULL; | ||
277 | |||
278 | if (pathOwned && (walker->text.first != walker->text.afterLast)) { | ||
279 | free((URI_CHAR *)walker->text.first); | ||
280 | } | ||
281 | free(walker); | ||
282 | } else { | ||
283 | /* Re-use segment for "" path segment to represent trailing slash, update tail */ | ||
284 | URI_TYPE(PathSegment) * const segment = walker; | ||
285 | if (pathOwned && (segment->text.first != segment->text.afterLast)) { | ||
286 | free((URI_CHAR *)segment->text.first); | ||
287 | } | ||
288 | segment->text.first = URI_FUNC(SafeToPointTo); | ||
289 | segment->text.afterLast = URI_FUNC(SafeToPointTo); | ||
290 | uri->pathHead = segment; | ||
291 | uri->pathTail = segment; | ||
292 | } | ||
293 | |||
294 | if (pathOwned && (prev->text.first != prev->text.afterLast)) { | ||
295 | free((URI_CHAR *)prev->text.first); | ||
296 | } | ||
297 | free(prev); | ||
298 | |||
299 | walker = nextBackup; | ||
300 | } | ||
301 | } else { | ||
302 | URI_TYPE(PathSegment) * const anotherNextBackup = walker->next; | ||
303 | /* First segment -> update head pointer */ | ||
304 | uri->pathHead = walker->next; | ||
305 | if (walker->next != NULL) { | ||
306 | walker->next->reserved = NULL; | ||
307 | } else { | ||
308 | /* Last segment -> update tail */ | ||
309 | uri->pathTail = NULL; | ||
310 | } | ||
311 | |||
312 | if (pathOwned && (walker->text.first != walker->text.afterLast)) { | ||
313 | free((URI_CHAR *)walker->text.first); | ||
314 | } | ||
315 | free(walker); | ||
316 | |||
317 | walker = anotherNextBackup; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | break; | ||
322 | |||
323 | } | ||
324 | |||
325 | if (!removeSegment) { | ||
326 | if (walker->next != NULL) { | ||
327 | walker->next->reserved = walker; | ||
328 | } else { | ||
329 | /* Last segment -> update tail */ | ||
330 | uri->pathTail = walker; | ||
331 | } | ||
332 | walker = walker->next; | ||
333 | } | ||
334 | } while (walker != NULL); | ||
335 | |||
336 | return URI_TRUE; | ||
337 | } | ||
338 | |||
339 | |||
340 | |||
341 | /* Properly removes "." and ".." path segments */ | ||
342 | UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri) { | ||
343 | const UriBool ABSOLUTE = URI_FALSE; | ||
344 | return URI_FUNC(RemoveDotSegments)(uri, ABSOLUTE); | ||
345 | } | ||
346 | |||
347 | |||
348 | |||
349 | unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) { | ||
350 | switch (hexdig) { | ||
351 | case _UT('0'): | ||
352 | case _UT('1'): | ||
353 | case _UT('2'): | ||
354 | case _UT('3'): | ||
355 | case _UT('4'): | ||
356 | case _UT('5'): | ||
357 | case _UT('6'): | ||
358 | case _UT('7'): | ||
359 | case _UT('8'): | ||
360 | case _UT('9'): | ||
361 | return (unsigned char)(9 + hexdig - _UT('9')); | ||
362 | |||
363 | case _UT('a'): | ||
364 | case _UT('b'): | ||
365 | case _UT('c'): | ||
366 | case _UT('d'): | ||
367 | case _UT('e'): | ||
368 | case _UT('f'): | ||
369 | return (unsigned char)(15 + hexdig - _UT('f')); | ||
370 | |||
371 | case _UT('A'): | ||
372 | case _UT('B'): | ||
373 | case _UT('C'): | ||
374 | case _UT('D'): | ||
375 | case _UT('E'): | ||
376 | case _UT('F'): | ||
377 | return (unsigned char)(15 + hexdig - _UT('F')); | ||
378 | |||
379 | default: | ||
380 | return 0; | ||
381 | } | ||
382 | } | ||
383 | |||
384 | |||
385 | |||
386 | URI_CHAR URI_FUNC(HexToLetter)(unsigned int value) { | ||
387 | /* Uppercase recommended in section 2.1. of RFC 3986 * | ||
388 | * http://tools.ietf.org/html/rfc3986#section-2.1 */ | ||
389 | return URI_FUNC(HexToLetterEx)(value, URI_TRUE); | ||
390 | } | ||
391 | |||
392 | |||
393 | |||
394 | URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) { | ||
395 | switch (value) { | ||
396 | case 0: return _UT('0'); | ||
397 | case 1: return _UT('1'); | ||
398 | case 2: return _UT('2'); | ||
399 | case 3: return _UT('3'); | ||
400 | case 4: return _UT('4'); | ||
401 | case 5: return _UT('5'); | ||
402 | case 6: return _UT('6'); | ||
403 | case 7: return _UT('7'); | ||
404 | case 8: return _UT('8'); | ||
405 | case 9: return _UT('9'); | ||
406 | |||
407 | case 10: return (uppercase == URI_TRUE) ? _UT('A') : _UT('a'); | ||
408 | case 11: return (uppercase == URI_TRUE) ? _UT('B') : _UT('b'); | ||
409 | case 12: return (uppercase == URI_TRUE) ? _UT('C') : _UT('c'); | ||
410 | case 13: return (uppercase == URI_TRUE) ? _UT('D') : _UT('d'); | ||
411 | case 14: return (uppercase == URI_TRUE) ? _UT('E') : _UT('e'); | ||
412 | default: return (uppercase == URI_TRUE) ? _UT('F') : _UT('f'); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | |||
417 | |||
418 | /* Checks if a URI has the host component set. */ | ||
419 | UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri) { | ||
420 | return (uri != NULL) | ||
421 | && ((uri->hostText.first != NULL) | ||
422 | || (uri->hostData.ip4 != NULL) | ||
423 | || (uri->hostData.ip6 != NULL) | ||
424 | || (uri->hostData.ipFuture.first != NULL) | ||
425 | ); | ||
426 | } | ||
427 | |||
428 | |||
429 | |||
430 | /* Copies the path segment list from one URI to another. */ | ||
431 | UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, | ||
432 | const URI_TYPE(Uri) * source) { | ||
433 | if (source->pathHead == NULL) { | ||
434 | /* No path component */ | ||
435 | dest->pathHead = NULL; | ||
436 | dest->pathTail = NULL; | ||
437 | } else { | ||
438 | /* Copy list but not the text contained */ | ||
439 | URI_TYPE(PathSegment) * sourceWalker = source->pathHead; | ||
440 | URI_TYPE(PathSegment) * destPrev = NULL; | ||
441 | do { | ||
442 | URI_TYPE(PathSegment) * cur = malloc(sizeof(URI_TYPE(PathSegment))); | ||
443 | if (cur == NULL) { | ||
444 | /* Fix broken list */ | ||
445 | if (destPrev != NULL) { | ||
446 | destPrev->next = NULL; | ||
447 | } | ||
448 | return URI_FALSE; /* Raises malloc error */ | ||
449 | } | ||
450 | |||
451 | /* From this functions usage we know that * | ||
452 | * the dest URI cannot be uri->owner */ | ||
453 | cur->text = sourceWalker->text; | ||
454 | if (destPrev == NULL) { | ||
455 | /* First segment ever */ | ||
456 | dest->pathHead = cur; | ||
457 | } else { | ||
458 | destPrev->next = cur; | ||
459 | } | ||
460 | destPrev = cur; | ||
461 | sourceWalker = sourceWalker->next; | ||
462 | } while (sourceWalker != NULL); | ||
463 | dest->pathTail = destPrev; | ||
464 | dest->pathTail->next = NULL; | ||
465 | } | ||
466 | |||
467 | dest->absolutePath = source->absolutePath; | ||
468 | return URI_TRUE; | ||
469 | } | ||
470 | |||
471 | |||
472 | |||
473 | /* Copies the authority part of an URI over to another. */ | ||
474 | UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, | ||
475 | const URI_TYPE(Uri) * source) { | ||
476 | /* From this functions usage we know that * | ||
477 | * the dest URI cannot be uri->owner */ | ||
478 | |||
479 | /* Copy userInfo */ | ||
480 | dest->userInfo = source->userInfo; | ||
481 | |||
482 | /* Copy hostText */ | ||
483 | dest->hostText = source->hostText; | ||
484 | |||
485 | /* Copy hostData */ | ||
486 | if (source->hostData.ip4 != NULL) { | ||
487 | dest->hostData.ip4 = malloc(sizeof(UriIp4)); | ||
488 | if (dest->hostData.ip4 == NULL) { | ||
489 | return URI_FALSE; /* Raises malloc error */ | ||
490 | } | ||
491 | *(dest->hostData.ip4) = *(source->hostData.ip4); | ||
492 | dest->hostData.ip6 = NULL; | ||
493 | dest->hostData.ipFuture.first = NULL; | ||
494 | dest->hostData.ipFuture.afterLast = NULL; | ||
495 | } else if (source->hostData.ip6 != NULL) { | ||
496 | dest->hostData.ip4 = NULL; | ||
497 | dest->hostData.ip6 = malloc(sizeof(UriIp6)); | ||
498 | if (dest->hostData.ip6 == NULL) { | ||
499 | return URI_FALSE; /* Raises malloc error */ | ||
500 | } | ||
501 | *(dest->hostData.ip6) = *(source->hostData.ip6); | ||
502 | dest->hostData.ipFuture.first = NULL; | ||
503 | dest->hostData.ipFuture.afterLast = NULL; | ||
504 | } else { | ||
505 | dest->hostData.ip4 = NULL; | ||
506 | dest->hostData.ip6 = NULL; | ||
507 | dest->hostData.ipFuture = source->hostData.ipFuture; | ||
508 | } | ||
509 | |||
510 | /* Copy portText */ | ||
511 | dest->portText = source->portText; | ||
512 | |||
513 | return URI_TRUE; | ||
514 | } | ||
515 | |||
516 | |||
517 | |||
518 | UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri) { | ||
519 | URI_TYPE(PathSegment) * segment; | ||
520 | |||
521 | if ( /* Case 1: absolute path, empty first segment */ | ||
522 | (uri->absolutePath | ||
523 | && (uri->pathHead != NULL) | ||
524 | && (uri->pathHead->text.afterLast == uri->pathHead->text.first)) | ||
525 | |||
526 | /* Case 2: relative path, empty first and second segment */ | ||
527 | || (!uri->absolutePath | ||
528 | && (uri->pathHead != NULL) | ||
529 | && (uri->pathHead->next != NULL) | ||
530 | && (uri->pathHead->text.afterLast == uri->pathHead->text.first) | ||
531 | && (uri->pathHead->next->text.afterLast == uri->pathHead->next->text.first))) { | ||
532 | /* NOOP */ | ||
533 | } else { | ||
534 | return URI_TRUE; | ||
535 | } | ||
536 | |||
537 | segment = malloc(1 * sizeof(URI_TYPE(PathSegment))); | ||
538 | if (segment == NULL) { | ||
539 | return URI_FALSE; /* Raises malloc error */ | ||
540 | } | ||
541 | |||
542 | /* Insert "." segment in front */ | ||
543 | segment->next = uri->pathHead; | ||
544 | segment->text.first = URI_FUNC(ConstPwd); | ||
545 | segment->text.afterLast = URI_FUNC(ConstPwd) + 1; | ||
546 | uri->pathHead = segment; | ||
547 | return URI_TRUE; | ||
548 | } | ||
549 | |||
550 | |||
551 | |||
552 | void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri) { | ||
553 | /* Fix path if only one empty segment */ | ||
554 | if (!uri->absolutePath | ||
555 | && !URI_FUNC(IsHostSet)(uri) | ||
556 | && (uri->pathHead != NULL) | ||
557 | && (uri->pathHead->next == NULL) | ||
558 | && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) { | ||
559 | free(uri->pathHead); | ||
560 | uri->pathHead = NULL; | ||
561 | uri->pathTail = NULL; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | |||
566 | |||
567 | #endif | ||
diff --git a/plugins/uriparser/UriCommon.h b/plugins/uriparser/UriCommon.h new file mode 100644 index 00000000..f6bc2ccf --- /dev/null +++ b/plugins/uriparser/UriCommon.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #if (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI)) \ | ||
41 | || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE)) \ | ||
42 | || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* What encodings are enabled? */ | ||
44 | #include <uriparser/UriDefsConfig.h> | ||
45 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
46 | /* Include SELF twice */ | ||
47 | # ifdef URI_ENABLE_ANSI | ||
48 | # define URI_PASS_ANSI 1 | ||
49 | # include "UriCommon.h" | ||
50 | # undef URI_PASS_ANSI | ||
51 | # endif | ||
52 | # ifdef URI_ENABLE_UNICODE | ||
53 | # define URI_PASS_UNICODE 1 | ||
54 | # include "UriCommon.h" | ||
55 | # undef URI_PASS_UNICODE | ||
56 | # endif | ||
57 | /* Only one pass for each encoding */ | ||
58 | #elif (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI) \ | ||
59 | && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ | ||
60 | && !defined(URI_COMMON_H_UNICODE) && defined(URI_ENABLE_UNICODE)) | ||
61 | # ifdef URI_PASS_ANSI | ||
62 | # define URI_COMMON_H_ANSI 1 | ||
63 | # include <uriparser/UriDefsAnsi.h> | ||
64 | # else | ||
65 | # define URI_COMMON_H_UNICODE 1 | ||
66 | # include <uriparser/UriDefsUnicode.h> | ||
67 | # endif | ||
68 | |||
69 | |||
70 | |||
71 | /* Used to point to from empty path segments. | ||
72 | * X.first and X.afterLast must be the same non-NULL value then. */ | ||
73 | extern const URI_CHAR * const URI_FUNC(SafeToPointTo); | ||
74 | extern const URI_CHAR * const URI_FUNC(ConstPwd); | ||
75 | extern const URI_CHAR * const URI_FUNC(ConstParent); | ||
76 | |||
77 | |||
78 | |||
79 | void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri); | ||
80 | |||
81 | int URI_FUNC(CompareRange)( | ||
82 | const URI_TYPE(TextRange) * a, | ||
83 | const URI_TYPE(TextRange) * b); | ||
84 | |||
85 | UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri); | ||
86 | UriBool URI_FUNC(RemoveDotSegments)(URI_TYPE(Uri) * uri, UriBool relative); | ||
87 | UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, | ||
88 | UriBool relative, UriBool pathOwned); | ||
89 | |||
90 | unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig); | ||
91 | URI_CHAR URI_FUNC(HexToLetter)(unsigned int value); | ||
92 | URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase); | ||
93 | |||
94 | UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri); | ||
95 | |||
96 | UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source); | ||
97 | UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source); | ||
98 | |||
99 | UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri); | ||
100 | void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri); | ||
101 | |||
102 | |||
103 | #endif | ||
104 | #endif | ||
diff --git a/plugins/uriparser/UriCompare.c b/plugins/uriparser/UriCompare.c new file mode 100644 index 00000000..6896f64e --- /dev/null +++ b/plugins/uriparser/UriCompare.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriCompare.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriCompare.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include <uriparser/UriIp4.h> | ||
67 | # include "UriCommon.h" | ||
68 | #endif | ||
69 | |||
70 | |||
71 | |||
72 | UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, | ||
73 | const URI_TYPE(Uri) * b) { | ||
74 | /* NOTE: Both NULL means equal! */ | ||
75 | if ((a == NULL) || (b == NULL)) { | ||
76 | return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE; | ||
77 | } | ||
78 | |||
79 | /* scheme */ | ||
80 | if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) { | ||
81 | return URI_FALSE; | ||
82 | } | ||
83 | |||
84 | /* absolutePath */ | ||
85 | if ((a->scheme.first == NULL)&& (a->absolutePath != b->absolutePath)) { | ||
86 | return URI_FALSE; | ||
87 | } | ||
88 | |||
89 | /* userInfo */ | ||
90 | if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) { | ||
91 | return URI_FALSE; | ||
92 | } | ||
93 | |||
94 | /* Host */ | ||
95 | if (((a->hostData.ip4 == NULL) != (b->hostData.ip4 == NULL)) | ||
96 | || ((a->hostData.ip6 == NULL) != (b->hostData.ip6 == NULL)) | ||
97 | || ((a->hostData.ipFuture.first == NULL) | ||
98 | != (b->hostData.ipFuture.first == NULL))) { | ||
99 | return URI_FALSE; | ||
100 | } | ||
101 | |||
102 | if (a->hostData.ip4 != NULL) { | ||
103 | if (memcmp(a->hostData.ip4->data, b->hostData.ip4->data, 4)) { | ||
104 | return URI_FALSE; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | if (a->hostData.ip6 != NULL) { | ||
109 | if (memcmp(a->hostData.ip6->data, b->hostData.ip6->data, 16)) { | ||
110 | return URI_FALSE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (a->hostData.ipFuture.first != NULL) { | ||
115 | if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) { | ||
116 | return URI_FALSE; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | if ((a->hostData.ip4 == NULL) | ||
121 | && (a->hostData.ip6 == NULL) | ||
122 | && (a->hostData.ipFuture.first == NULL)) { | ||
123 | if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) { | ||
124 | return URI_FALSE; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /* portText */ | ||
129 | if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) { | ||
130 | return URI_FALSE; | ||
131 | } | ||
132 | |||
133 | /* Path */ | ||
134 | if ((a->pathHead == NULL) != (b->pathHead == NULL)) { | ||
135 | return URI_FALSE; | ||
136 | } | ||
137 | |||
138 | if (a->pathHead != NULL) { | ||
139 | URI_TYPE(PathSegment) * walkA = a->pathHead; | ||
140 | URI_TYPE(PathSegment) * walkB = b->pathHead; | ||
141 | do { | ||
142 | if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) { | ||
143 | return URI_FALSE; | ||
144 | } | ||
145 | if ((walkA->next == NULL) != (walkB->next == NULL)) { | ||
146 | return URI_FALSE; | ||
147 | } | ||
148 | walkA = walkA->next; | ||
149 | walkB = walkB->next; | ||
150 | } while (walkA != NULL); | ||
151 | } | ||
152 | |||
153 | /* query */ | ||
154 | if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) { | ||
155 | return URI_FALSE; | ||
156 | } | ||
157 | |||
158 | /* fragment */ | ||
159 | if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) { | ||
160 | return URI_FALSE; | ||
161 | } | ||
162 | |||
163 | return URI_TRUE; /* Equal*/ | ||
164 | } | ||
165 | |||
166 | |||
167 | |||
168 | #endif | ||
diff --git a/plugins/uriparser/UriDefsAnsi.h b/plugins/uriparser/UriDefsAnsi.h new file mode 100644 index 00000000..deaefaa5 --- /dev/null +++ b/plugins/uriparser/UriDefsAnsi.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriDefsAnsi.h | ||
42 | * Holds definitions for the ANSI pass. | ||
43 | * NOTE: This header is included N times, not once. | ||
44 | */ | ||
45 | |||
46 | /* Allow multi inclusion */ | ||
47 | #include "UriDefsConfig.h" | ||
48 | |||
49 | |||
50 | |||
51 | #undef URI_CHAR | ||
52 | #define URI_CHAR char | ||
53 | |||
54 | #undef _UT | ||
55 | #define _UT(x) x | ||
56 | |||
57 | |||
58 | |||
59 | #undef URI_FUNC | ||
60 | #define URI_FUNC(x) uri##x##A | ||
61 | |||
62 | #undef URI_TYPE | ||
63 | #define URI_TYPE(x) Uri##x##A | ||
64 | |||
65 | |||
66 | |||
67 | #undef URI_STRLEN | ||
68 | #define URI_STRLEN strlen | ||
69 | #undef URI_STRCPY | ||
70 | #define URI_STRCPY strcpy | ||
71 | #undef URI_STRCMP | ||
72 | #define URI_STRCMP strcmp | ||
73 | #undef URI_STRNCMP | ||
74 | #define URI_STRNCMP strncmp | ||
75 | |||
76 | /* TODO Remove on next source-compatibility break */ | ||
77 | #undef URI_SNPRINTF | ||
78 | #if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32)) | ||
79 | # define URI_SNPRINTF _snprintf | ||
80 | #else | ||
81 | # define URI_SNPRINTF snprintf | ||
82 | #endif | ||
diff --git a/plugins/uriparser/UriDefsConfig.h b/plugins/uriparser/UriDefsConfig.h new file mode 100644 index 00000000..d87ccb63 --- /dev/null +++ b/plugins/uriparser/UriDefsConfig.h | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriDefsConfig.h | ||
42 | * Adjusts the internal configuration after processing external definitions. | ||
43 | */ | ||
44 | |||
45 | #ifndef URI_DEFS_CONFIG_H | ||
46 | #define URI_DEFS_CONFIG_H 1 | ||
47 | |||
48 | |||
49 | |||
50 | /* Deny external overriding */ | ||
51 | #undef URI_ENABLE_ANSI /* Internal for !URI_NO_ANSI */ | ||
52 | #undef URI_ENABLE_UNICODE /* Internal for !URI_NO_UNICODE */ | ||
53 | |||
54 | |||
55 | |||
56 | /* Encoding */ | ||
57 | #ifdef URI_NO_ANSI | ||
58 | # ifdef URI_NO_UNICODE | ||
59 | /* No encoding at all */ | ||
60 | # error URI_NO_ANSI and URI_NO_UNICODE cannot go together. | ||
61 | # else | ||
62 | /* Unicode only */ | ||
63 | # define URI_ENABLE_UNICODE 1 | ||
64 | # endif | ||
65 | #else | ||
66 | # ifdef URI_NO_UNICODE | ||
67 | /* ANSI only */ | ||
68 | # define URI_ENABLE_ANSI 1 | ||
69 | # else | ||
70 | /* Both ANSI and Unicode */ | ||
71 | # define URI_ENABLE_ANSI 1 | ||
72 | # define URI_ENABLE_UNICODE 1 | ||
73 | # endif | ||
74 | #endif | ||
75 | |||
76 | |||
77 | |||
78 | /* Function inlining, not ANSI/ISO C! */ | ||
79 | #if (defined(URI_DOXYGEN) || defined(URI_SIZEDOWN)) | ||
80 | # define URI_INLINE | ||
81 | #elif defined(__INTEL_COMPILER) | ||
82 | /* Intel C/C++ */ | ||
83 | /* http://predef.sourceforge.net/precomp.html#sec20 */ | ||
84 | /* http://www.intel.com/support/performancetools/c/windows/sb/CS-007751.htm#2 */ | ||
85 | # define URI_INLINE __force_inline | ||
86 | #elif defined(_MSC_VER) | ||
87 | /* Microsoft Visual C++ */ | ||
88 | /* http://predef.sourceforge.net/precomp.html#sec32 */ | ||
89 | /* http://msdn2.microsoft.com/en-us/library/ms882281.aspx */ | ||
90 | # define URI_INLINE __forceinline | ||
91 | #elif (__STDC_VERSION__ >= 199901L) | ||
92 | /* C99, "inline" is a keyword */ | ||
93 | # define URI_INLINE inline | ||
94 | #else | ||
95 | /* No inlining */ | ||
96 | # define URI_INLINE | ||
97 | #endif | ||
98 | |||
99 | |||
100 | |||
101 | #endif /* URI_DEFS_CONFIG_H */ | ||
diff --git a/plugins/uriparser/UriDefsUnicode.h b/plugins/uriparser/UriDefsUnicode.h new file mode 100644 index 00000000..fa4befcd --- /dev/null +++ b/plugins/uriparser/UriDefsUnicode.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriDefsUnicode.h | ||
42 | * Holds definitions for the Unicode pass. | ||
43 | * NOTE: This header is included N times, not once. | ||
44 | */ | ||
45 | |||
46 | /* Allow multi inclusion */ | ||
47 | #include "UriDefsConfig.h" | ||
48 | |||
49 | |||
50 | |||
51 | #undef URI_CHAR | ||
52 | #define URI_CHAR wchar_t | ||
53 | |||
54 | #undef _UT | ||
55 | #define _UT(x) L##x | ||
56 | |||
57 | |||
58 | |||
59 | #undef URI_FUNC | ||
60 | #define URI_FUNC(x) uri##x##W | ||
61 | |||
62 | #undef URI_TYPE | ||
63 | #define URI_TYPE(x) Uri##x##W | ||
64 | |||
65 | |||
66 | |||
67 | #undef URI_STRLEN | ||
68 | #define URI_STRLEN wcslen | ||
69 | #undef URI_STRCPY | ||
70 | #define URI_STRCPY wcscpy | ||
71 | #undef URI_STRCMP | ||
72 | #define URI_STRCMP wcscmp | ||
73 | #undef URI_STRNCMP | ||
74 | #define URI_STRNCMP wcsncmp | ||
75 | |||
76 | /* TODO Remove on next source-compatibility break */ | ||
77 | #undef URI_SNPRINTF | ||
78 | #if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32)) | ||
79 | # define URI_SNPRINTF _snwprintf | ||
80 | #else | ||
81 | # define URI_SNPRINTF swprintf | ||
82 | #endif | ||
diff --git a/plugins/uriparser/UriEscape.c b/plugins/uriparser/UriEscape.c new file mode 100644 index 00000000..79ee3a68 --- /dev/null +++ b/plugins/uriparser/UriEscape.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriEscape.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriEscape.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include "UriCommon.h" | ||
67 | #endif | ||
68 | |||
69 | |||
70 | |||
71 | URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, | ||
72 | UriBool spaceToPlus, UriBool normalizeBreaks) { | ||
73 | return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks); | ||
74 | } | ||
75 | |||
76 | |||
77 | |||
78 | URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, | ||
79 | const URI_CHAR * inAfterLast, URI_CHAR * out, | ||
80 | UriBool spaceToPlus, UriBool normalizeBreaks) { | ||
81 | const URI_CHAR * read = inFirst; | ||
82 | URI_CHAR * write = out; | ||
83 | UriBool prevWasCr = URI_FALSE; | ||
84 | if ((out == NULL) || (inFirst == out)) { | ||
85 | return NULL; | ||
86 | } else if (inFirst == NULL) { | ||
87 | if (out != NULL) { | ||
88 | out[0] = _UT('\0'); | ||
89 | } | ||
90 | return out; | ||
91 | } | ||
92 | |||
93 | for (;;) { | ||
94 | if ((inAfterLast != NULL) && (read >= inAfterLast)) { | ||
95 | write[0] = _UT('\0'); | ||
96 | return write; | ||
97 | } | ||
98 | |||
99 | switch (read[0]) { | ||
100 | case _UT('\0'): | ||
101 | write[0] = _UT('\0'); | ||
102 | return write; | ||
103 | |||
104 | case _UT(' '): | ||
105 | if (spaceToPlus) { | ||
106 | write[0] = _UT('+'); | ||
107 | write++; | ||
108 | } else { | ||
109 | write[0] = _UT('%'); | ||
110 | write[1] = _UT('2'); | ||
111 | write[2] = _UT('0'); | ||
112 | write += 3; | ||
113 | } | ||
114 | prevWasCr = URI_FALSE; | ||
115 | break; | ||
116 | |||
117 | case _UT('a'): /* ALPHA */ | ||
118 | case _UT('A'): | ||
119 | case _UT('b'): | ||
120 | case _UT('B'): | ||
121 | case _UT('c'): | ||
122 | case _UT('C'): | ||
123 | case _UT('d'): | ||
124 | case _UT('D'): | ||
125 | case _UT('e'): | ||
126 | case _UT('E'): | ||
127 | case _UT('f'): | ||
128 | case _UT('F'): | ||
129 | case _UT('g'): | ||
130 | case _UT('G'): | ||
131 | case _UT('h'): | ||
132 | case _UT('H'): | ||
133 | case _UT('i'): | ||
134 | case _UT('I'): | ||
135 | case _UT('j'): | ||
136 | case _UT('J'): | ||
137 | case _UT('k'): | ||
138 | case _UT('K'): | ||
139 | case _UT('l'): | ||
140 | case _UT('L'): | ||
141 | case _UT('m'): | ||
142 | case _UT('M'): | ||
143 | case _UT('n'): | ||
144 | case _UT('N'): | ||
145 | case _UT('o'): | ||
146 | case _UT('O'): | ||
147 | case _UT('p'): | ||
148 | case _UT('P'): | ||
149 | case _UT('q'): | ||
150 | case _UT('Q'): | ||
151 | case _UT('r'): | ||
152 | case _UT('R'): | ||
153 | case _UT('s'): | ||
154 | case _UT('S'): | ||
155 | case _UT('t'): | ||
156 | case _UT('T'): | ||
157 | case _UT('u'): | ||
158 | case _UT('U'): | ||
159 | case _UT('v'): | ||
160 | case _UT('V'): | ||
161 | case _UT('w'): | ||
162 | case _UT('W'): | ||
163 | case _UT('x'): | ||
164 | case _UT('X'): | ||
165 | case _UT('y'): | ||
166 | case _UT('Y'): | ||
167 | case _UT('z'): | ||
168 | case _UT('Z'): | ||
169 | case _UT('0'): /* DIGIT */ | ||
170 | case _UT('1'): | ||
171 | case _UT('2'): | ||
172 | case _UT('3'): | ||
173 | case _UT('4'): | ||
174 | case _UT('5'): | ||
175 | case _UT('6'): | ||
176 | case _UT('7'): | ||
177 | case _UT('8'): | ||
178 | case _UT('9'): | ||
179 | case _UT('-'): /* "-" / "." / "_" / "~" */ | ||
180 | case _UT('.'): | ||
181 | case _UT('_'): | ||
182 | case _UT('~'): | ||
183 | /* Copy unmodified */ | ||
184 | write[0] = read[0]; | ||
185 | write++; | ||
186 | |||
187 | prevWasCr = URI_FALSE; | ||
188 | break; | ||
189 | |||
190 | case _UT('\x0a'): | ||
191 | if (normalizeBreaks) { | ||
192 | if (!prevWasCr) { | ||
193 | write[0] = _UT('%'); | ||
194 | write[1] = _UT('0'); | ||
195 | write[2] = _UT('D'); | ||
196 | write[3] = _UT('%'); | ||
197 | write[4] = _UT('0'); | ||
198 | write[5] = _UT('A'); | ||
199 | write += 6; | ||
200 | } | ||
201 | } else { | ||
202 | write[0] = _UT('%'); | ||
203 | write[1] = _UT('0'); | ||
204 | write[2] = _UT('A'); | ||
205 | write += 3; | ||
206 | } | ||
207 | prevWasCr = URI_FALSE; | ||
208 | break; | ||
209 | |||
210 | case _UT('\x0d'): | ||
211 | if (normalizeBreaks) { | ||
212 | write[0] = _UT('%'); | ||
213 | write[1] = _UT('0'); | ||
214 | write[2] = _UT('D'); | ||
215 | write[3] = _UT('%'); | ||
216 | write[4] = _UT('0'); | ||
217 | write[5] = _UT('A'); | ||
218 | write += 6; | ||
219 | } else { | ||
220 | write[0] = _UT('%'); | ||
221 | write[1] = _UT('0'); | ||
222 | write[2] = _UT('D'); | ||
223 | write += 3; | ||
224 | } | ||
225 | prevWasCr = URI_TRUE; | ||
226 | break; | ||
227 | |||
228 | default: | ||
229 | /* Percent encode */ | ||
230 | { | ||
231 | const unsigned char code = (unsigned char)read[0]; | ||
232 | write[0] = _UT('%'); | ||
233 | write[1] = URI_FUNC(HexToLetter)(code >> 4); | ||
234 | write[2] = URI_FUNC(HexToLetter)(code & 0x0f); | ||
235 | write += 3; | ||
236 | } | ||
237 | prevWasCr = URI_FALSE; | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | read++; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | |||
246 | |||
247 | const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout) { | ||
248 | return URI_FUNC(UnescapeInPlaceEx)(inout, URI_FALSE, URI_BR_DONT_TOUCH); | ||
249 | } | ||
250 | |||
251 | |||
252 | |||
253 | const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, | ||
254 | UriBool plusToSpace, UriBreakConversion breakConversion) { | ||
255 | URI_CHAR * read = inout; | ||
256 | URI_CHAR * write = inout; | ||
257 | UriBool prevWasCr = URI_FALSE; | ||
258 | |||
259 | if (inout == NULL) { | ||
260 | return NULL; | ||
261 | } | ||
262 | |||
263 | for (;;) { | ||
264 | switch (read[0]) { | ||
265 | case _UT('\0'): | ||
266 | if (read > write) { | ||
267 | write[0] = _UT('\0'); | ||
268 | } | ||
269 | return write; | ||
270 | |||
271 | case _UT('%'): | ||
272 | switch (read[1]) { | ||
273 | case _UT('0'): | ||
274 | case _UT('1'): | ||
275 | case _UT('2'): | ||
276 | case _UT('3'): | ||
277 | case _UT('4'): | ||
278 | case _UT('5'): | ||
279 | case _UT('6'): | ||
280 | case _UT('7'): | ||
281 | case _UT('8'): | ||
282 | case _UT('9'): | ||
283 | case _UT('a'): | ||
284 | case _UT('b'): | ||
285 | case _UT('c'): | ||
286 | case _UT('d'): | ||
287 | case _UT('e'): | ||
288 | case _UT('f'): | ||
289 | case _UT('A'): | ||
290 | case _UT('B'): | ||
291 | case _UT('C'): | ||
292 | case _UT('D'): | ||
293 | case _UT('E'): | ||
294 | case _UT('F'): | ||
295 | switch (read[2]) { | ||
296 | case _UT('0'): | ||
297 | case _UT('1'): | ||
298 | case _UT('2'): | ||
299 | case _UT('3'): | ||
300 | case _UT('4'): | ||
301 | case _UT('5'): | ||
302 | case _UT('6'): | ||
303 | case _UT('7'): | ||
304 | case _UT('8'): | ||
305 | case _UT('9'): | ||
306 | case _UT('a'): | ||
307 | case _UT('b'): | ||
308 | case _UT('c'): | ||
309 | case _UT('d'): | ||
310 | case _UT('e'): | ||
311 | case _UT('f'): | ||
312 | case _UT('A'): | ||
313 | case _UT('B'): | ||
314 | case _UT('C'): | ||
315 | case _UT('D'): | ||
316 | case _UT('E'): | ||
317 | case _UT('F'): | ||
318 | { | ||
319 | /* Percent group found */ | ||
320 | const unsigned char left = URI_FUNC(HexdigToInt)(read[1]); | ||
321 | const unsigned char right = URI_FUNC(HexdigToInt)(read[2]); | ||
322 | const int code = 16 * left + right; | ||
323 | switch (code) { | ||
324 | case 10: | ||
325 | switch (breakConversion) { | ||
326 | case URI_BR_TO_LF: | ||
327 | if (!prevWasCr) { | ||
328 | write[0] = (URI_CHAR)10; | ||
329 | write++; | ||
330 | } | ||
331 | break; | ||
332 | |||
333 | case URI_BR_TO_CRLF: | ||
334 | if (!prevWasCr) { | ||
335 | write[0] = (URI_CHAR)13; | ||
336 | write[1] = (URI_CHAR)10; | ||
337 | write += 2; | ||
338 | } | ||
339 | break; | ||
340 | |||
341 | case URI_BR_TO_CR: | ||
342 | if (!prevWasCr) { | ||
343 | write[0] = (URI_CHAR)13; | ||
344 | write++; | ||
345 | } | ||
346 | break; | ||
347 | |||
348 | case URI_BR_DONT_TOUCH: | ||
349 | default: | ||
350 | write[0] = (URI_CHAR)10; | ||
351 | write++; | ||
352 | |||
353 | } | ||
354 | prevWasCr = URI_FALSE; | ||
355 | break; | ||
356 | |||
357 | case 13: | ||
358 | switch (breakConversion) { | ||
359 | case URI_BR_TO_LF: | ||
360 | write[0] = (URI_CHAR)10; | ||
361 | write++; | ||
362 | break; | ||
363 | |||
364 | case URI_BR_TO_CRLF: | ||
365 | write[0] = (URI_CHAR)13; | ||
366 | write[1] = (URI_CHAR)10; | ||
367 | write += 2; | ||
368 | break; | ||
369 | |||
370 | case URI_BR_TO_CR: | ||
371 | write[0] = (URI_CHAR)13; | ||
372 | write++; | ||
373 | break; | ||
374 | |||
375 | case URI_BR_DONT_TOUCH: | ||
376 | default: | ||
377 | write[0] = (URI_CHAR)13; | ||
378 | write++; | ||
379 | |||
380 | } | ||
381 | prevWasCr = URI_TRUE; | ||
382 | break; | ||
383 | |||
384 | default: | ||
385 | write[0] = (URI_CHAR)(code); | ||
386 | write++; | ||
387 | |||
388 | prevWasCr = URI_FALSE; | ||
389 | |||
390 | } | ||
391 | read += 3; | ||
392 | } | ||
393 | break; | ||
394 | |||
395 | default: | ||
396 | /* Copy two chars unmodified and */ | ||
397 | /* look at this char again */ | ||
398 | if (read > write) { | ||
399 | write[0] = read[0]; | ||
400 | write[1] = read[1]; | ||
401 | } | ||
402 | read += 2; | ||
403 | write += 2; | ||
404 | |||
405 | prevWasCr = URI_FALSE; | ||
406 | } | ||
407 | break; | ||
408 | |||
409 | default: | ||
410 | /* Copy one char unmodified and */ | ||
411 | /* look at this char again */ | ||
412 | if (read > write) { | ||
413 | write[0] = read[0]; | ||
414 | } | ||
415 | read++; | ||
416 | write++; | ||
417 | |||
418 | prevWasCr = URI_FALSE; | ||
419 | } | ||
420 | break; | ||
421 | |||
422 | case _UT('+'): | ||
423 | if (plusToSpace) { | ||
424 | /* Convert '+' to ' ' */ | ||
425 | write[0] = _UT(' '); | ||
426 | } else { | ||
427 | /* Copy one char unmodified */ | ||
428 | if (read > write) { | ||
429 | write[0] = read[0]; | ||
430 | } | ||
431 | } | ||
432 | read++; | ||
433 | write++; | ||
434 | |||
435 | prevWasCr = URI_FALSE; | ||
436 | break; | ||
437 | |||
438 | default: | ||
439 | /* Copy one char unmodified */ | ||
440 | if (read > write) { | ||
441 | write[0] = read[0]; | ||
442 | } | ||
443 | read++; | ||
444 | write++; | ||
445 | |||
446 | prevWasCr = URI_FALSE; | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | |||
451 | |||
452 | |||
453 | #endif | ||
diff --git a/plugins/uriparser/UriFile.c b/plugins/uriparser/UriFile.c new file mode 100644 index 00000000..9cf788fc --- /dev/null +++ b/plugins/uriparser/UriFile.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriFile.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriFile.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | #endif | ||
67 | |||
68 | |||
69 | |||
70 | static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename, | ||
71 | URI_CHAR * uriString, UriBool fromUnix) { | ||
72 | const URI_CHAR * input = filename; | ||
73 | const URI_CHAR * lastSep = input - 1; | ||
74 | UriBool firstSegment = URI_TRUE; | ||
75 | URI_CHAR * output = uriString; | ||
76 | UriBool absolute; | ||
77 | UriBool is_windows_network; | ||
78 | |||
79 | if ((filename == NULL) || (uriString == NULL)) { | ||
80 | return URI_ERROR_NULL; | ||
81 | } | ||
82 | |||
83 | is_windows_network = (filename[0] == _UT('\\')) && (filename[1] == _UT('\\')); | ||
84 | absolute = fromUnix | ||
85 | ? (filename[0] == _UT('/')) | ||
86 | : ((filename[0] != _UT('\0')) && (filename[1] == _UT(':')) | ||
87 | || is_windows_network); | ||
88 | |||
89 | if (absolute) { | ||
90 | const URI_CHAR * const prefix = fromUnix | ||
91 | ? _UT("file://") | ||
92 | : is_windows_network | ||
93 | ? _UT("file:") | ||
94 | : _UT("file:///"); | ||
95 | const int prefixLen = URI_STRLEN(prefix); | ||
96 | |||
97 | /* Copy prefix */ | ||
98 | memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR)); | ||
99 | output += prefixLen; | ||
100 | } | ||
101 | |||
102 | /* Copy and escape on the fly */ | ||
103 | for (;;) { | ||
104 | if ((input[0] == _UT('\0')) | ||
105 | || (fromUnix && input[0] == _UT('/')) | ||
106 | || (!fromUnix && input[0] == _UT('\\'))) { | ||
107 | /* Copy text after last seperator */ | ||
108 | if (lastSep + 1 < input) { | ||
109 | if (!fromUnix && absolute && (firstSegment == URI_TRUE)) { | ||
110 | /* Quick hack to not convert "C:" to "C%3A" */ | ||
111 | const int charsToCopy = (int)(input - (lastSep + 1)); | ||
112 | memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR)); | ||
113 | output += charsToCopy; | ||
114 | } else { | ||
115 | output = URI_FUNC(EscapeEx)(lastSep + 1, input, output, | ||
116 | URI_FALSE, URI_FALSE); | ||
117 | } | ||
118 | } | ||
119 | firstSegment = URI_FALSE; | ||
120 | } | ||
121 | |||
122 | if (input[0] == _UT('\0')) { | ||
123 | output[0] = _UT('\0'); | ||
124 | break; | ||
125 | } else if (fromUnix && (input[0] == _UT('/'))) { | ||
126 | /* Copy separators unmodified */ | ||
127 | output[0] = _UT('/'); | ||
128 | output++; | ||
129 | lastSep = input; | ||
130 | } else if (!fromUnix && (input[0] == _UT('\\'))) { | ||
131 | /* Convert backslashes to forward slashes */ | ||
132 | output[0] = _UT('/'); | ||
133 | output++; | ||
134 | lastSep = input; | ||
135 | } | ||
136 | input++; | ||
137 | } | ||
138 | |||
139 | return URI_SUCCESS; | ||
140 | } | ||
141 | |||
142 | |||
143 | |||
144 | static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString, | ||
145 | URI_CHAR * filename, UriBool toUnix) { | ||
146 | if ((uriString == NULL) || (filename == NULL)) { | ||
147 | return URI_ERROR_NULL; | ||
148 | } | ||
149 | |||
150 | { | ||
151 | const UriBool file_two_slashes = | ||
152 | URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0; | ||
153 | const UriBool file_three_slashes = file_two_slashes | ||
154 | && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0); | ||
155 | |||
156 | const size_t charsToSkip = file_two_slashes | ||
157 | ? file_three_slashes | ||
158 | ? toUnix | ||
159 | /* file:///bin/bash */ | ||
160 | ? URI_STRLEN(_UT("file://")) | ||
161 | /* file:///E:/Documents%20and%20Settings */ | ||
162 | : URI_STRLEN(_UT("file:///")) | ||
163 | /* file://Server01/Letter.txt */ | ||
164 | : URI_STRLEN(_UT("file://")) | ||
165 | : 0; | ||
166 | const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1; | ||
167 | |||
168 | const UriBool is_windows_network_with_authority = | ||
169 | (toUnix == URI_FALSE) | ||
170 | && file_two_slashes | ||
171 | && ! file_three_slashes; | ||
172 | |||
173 | URI_CHAR * const unescape_target = is_windows_network_with_authority | ||
174 | ? (filename + 2) | ||
175 | : filename; | ||
176 | |||
177 | if (is_windows_network_with_authority) { | ||
178 | filename[0] = '\\'; | ||
179 | filename[1] = '\\'; | ||
180 | } | ||
181 | |||
182 | memcpy(unescape_target, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR)); | ||
183 | URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH); | ||
184 | } | ||
185 | |||
186 | /* Convert forward slashes to backslashes */ | ||
187 | if (!toUnix) { | ||
188 | URI_CHAR * walker = filename; | ||
189 | while (walker[0] != _UT('\0')) { | ||
190 | if (walker[0] == _UT('/')) { | ||
191 | walker[0] = _UT('\\'); | ||
192 | } | ||
193 | walker++; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | return URI_SUCCESS; | ||
198 | } | ||
199 | |||
200 | |||
201 | |||
202 | int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) { | ||
203 | return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE); | ||
204 | } | ||
205 | |||
206 | |||
207 | |||
208 | int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) { | ||
209 | return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE); | ||
210 | } | ||
211 | |||
212 | |||
213 | |||
214 | int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, URI_CHAR * filename) { | ||
215 | return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE); | ||
216 | } | ||
217 | |||
218 | |||
219 | |||
220 | int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, URI_CHAR * filename) { | ||
221 | return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE); | ||
222 | } | ||
223 | |||
224 | |||
225 | |||
226 | #endif | ||
diff --git a/plugins/uriparser/UriIp4.c b/plugins/uriparser/UriIp4.c new file mode 100644 index 00000000..c00910bb --- /dev/null +++ b/plugins/uriparser/UriIp4.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriIp4.c | ||
42 | * Holds the IPv4 parser implementation. | ||
43 | * NOTE: This source file includes itself twice. | ||
44 | */ | ||
45 | |||
46 | /* What encodings are enabled? */ | ||
47 | #include <uriparser/UriDefsConfig.h> | ||
48 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
49 | /* Include SELF twice */ | ||
50 | # ifdef URI_ENABLE_ANSI | ||
51 | # define URI_PASS_ANSI 1 | ||
52 | # include "UriIp4.c" | ||
53 | # undef URI_PASS_ANSI | ||
54 | # endif | ||
55 | # ifdef URI_ENABLE_UNICODE | ||
56 | # define URI_PASS_UNICODE 1 | ||
57 | # include "UriIp4.c" | ||
58 | # undef URI_PASS_UNICODE | ||
59 | # endif | ||
60 | #else | ||
61 | # ifdef URI_PASS_ANSI | ||
62 | # include <uriparser/UriDefsAnsi.h> | ||
63 | # else | ||
64 | # include <uriparser/UriDefsUnicode.h> | ||
65 | # endif | ||
66 | |||
67 | |||
68 | |||
69 | #ifndef URI_DOXYGEN | ||
70 | # include <uriparser/UriIp4.h> | ||
71 | # include "UriIp4Base.h" | ||
72 | # include <uriparser/UriBase.h> | ||
73 | #endif | ||
74 | |||
75 | |||
76 | |||
77 | /* Prototypes */ | ||
78 | static const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser, | ||
79 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
80 | static const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser, | ||
81 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
82 | static const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser, | ||
83 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
84 | static const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser, | ||
85 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
86 | static const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser, | ||
87 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
88 | |||
89 | |||
90 | |||
91 | /* | ||
92 | * [ipFourAddress]->[decOctet]<.>[decOctet]<.>[decOctet]<.>[decOctet] | ||
93 | */ | ||
94 | int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, | ||
95 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
96 | const URI_CHAR * after; | ||
97 | UriIp4Parser parser; | ||
98 | |||
99 | /* Essential checks */ | ||
100 | if ((octetOutput == NULL) || (first == NULL) | ||
101 | || (afterLast <= first)) { | ||
102 | return URI_ERROR_SYNTAX; | ||
103 | } | ||
104 | |||
105 | /* Reset parser */ | ||
106 | parser.stackCount = 0; | ||
107 | |||
108 | /* Octet #1 */ | ||
109 | after = URI_FUNC(ParseDecOctet)(&parser, first, afterLast); | ||
110 | if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { | ||
111 | return URI_ERROR_SYNTAX; | ||
112 | } | ||
113 | uriStackToOctet(&parser, octetOutput); | ||
114 | |||
115 | /* Octet #2 */ | ||
116 | after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); | ||
117 | if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { | ||
118 | return URI_ERROR_SYNTAX; | ||
119 | } | ||
120 | uriStackToOctet(&parser, octetOutput + 1); | ||
121 | |||
122 | /* Octet #3 */ | ||
123 | after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); | ||
124 | if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { | ||
125 | return URI_ERROR_SYNTAX; | ||
126 | } | ||
127 | uriStackToOctet(&parser, octetOutput + 2); | ||
128 | |||
129 | /* Octet #4 */ | ||
130 | after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); | ||
131 | if (after != afterLast) { | ||
132 | return URI_ERROR_SYNTAX; | ||
133 | } | ||
134 | uriStackToOctet(&parser, octetOutput + 3); | ||
135 | |||
136 | return URI_SUCCESS; | ||
137 | } | ||
138 | |||
139 | |||
140 | |||
141 | /* | ||
142 | * [decOctet]-><0> | ||
143 | * [decOctet]-><1>[decOctetOne] | ||
144 | * [decOctet]-><2>[decOctetTwo] | ||
145 | * [decOctet]-><3>[decOctetThree] | ||
146 | * [decOctet]-><4>[decOctetThree] | ||
147 | * [decOctet]-><5>[decOctetThree] | ||
148 | * [decOctet]-><6>[decOctetThree] | ||
149 | * [decOctet]-><7>[decOctetThree] | ||
150 | * [decOctet]-><8>[decOctetThree] | ||
151 | * [decOctet]-><9>[decOctetThree] | ||
152 | */ | ||
153 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser, | ||
154 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
155 | if (first >= afterLast) { | ||
156 | return NULL; | ||
157 | } | ||
158 | |||
159 | switch (*first) { | ||
160 | case _UT('0'): | ||
161 | uriPushToStack(parser, 0); | ||
162 | return first + 1; | ||
163 | |||
164 | case _UT('1'): | ||
165 | uriPushToStack(parser, 1); | ||
166 | return (const URI_CHAR *)URI_FUNC(ParseDecOctetOne)(parser, first + 1, afterLast); | ||
167 | |||
168 | case _UT('2'): | ||
169 | uriPushToStack(parser, 2); | ||
170 | return (const URI_CHAR *)URI_FUNC(ParseDecOctetTwo)(parser, first + 1, afterLast); | ||
171 | |||
172 | case _UT('3'): | ||
173 | case _UT('4'): | ||
174 | case _UT('5'): | ||
175 | case _UT('6'): | ||
176 | case _UT('7'): | ||
177 | case _UT('8'): | ||
178 | case _UT('9'): | ||
179 | uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); | ||
180 | return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast); | ||
181 | |||
182 | default: | ||
183 | return NULL; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | |||
188 | |||
189 | /* | ||
190 | * [decOctetOne]-><NULL> | ||
191 | * [decOctetOne]->[DIGIT][decOctetThree] | ||
192 | */ | ||
193 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser, | ||
194 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
195 | if (first >= afterLast) { | ||
196 | return afterLast; | ||
197 | } | ||
198 | |||
199 | switch (*first) { | ||
200 | case _UT('0'): | ||
201 | case _UT('1'): | ||
202 | case _UT('2'): | ||
203 | case _UT('3'): | ||
204 | case _UT('4'): | ||
205 | case _UT('5'): | ||
206 | case _UT('6'): | ||
207 | case _UT('7'): | ||
208 | case _UT('8'): | ||
209 | case _UT('9'): | ||
210 | uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); | ||
211 | return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast); | ||
212 | |||
213 | default: | ||
214 | return first; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | |||
220 | /* | ||
221 | * [decOctetTwo]-><NULL> | ||
222 | * [decOctetTwo]-><0>[decOctetThree] | ||
223 | * [decOctetTwo]-><1>[decOctetThree] | ||
224 | * [decOctetTwo]-><2>[decOctetThree] | ||
225 | * [decOctetTwo]-><3>[decOctetThree] | ||
226 | * [decOctetTwo]-><4>[decOctetThree] | ||
227 | * [decOctetTwo]-><5>[decOctetFour] | ||
228 | * [decOctetTwo]-><6> | ||
229 | * [decOctetTwo]-><7> | ||
230 | * [decOctetTwo]-><8> | ||
231 | * [decOctetTwo]-><9> | ||
232 | */ | ||
233 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser, | ||
234 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
235 | if (first >= afterLast) { | ||
236 | return afterLast; | ||
237 | } | ||
238 | |||
239 | switch (*first) { | ||
240 | case _UT('0'): | ||
241 | case _UT('1'): | ||
242 | case _UT('2'): | ||
243 | case _UT('3'): | ||
244 | case _UT('4'): | ||
245 | uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); | ||
246 | return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast); | ||
247 | |||
248 | case _UT('5'): | ||
249 | uriPushToStack(parser, 5); | ||
250 | return (const URI_CHAR *)URI_FUNC(ParseDecOctetFour)(parser, first + 1, afterLast); | ||
251 | |||
252 | case _UT('6'): | ||
253 | case _UT('7'): | ||
254 | case _UT('8'): | ||
255 | case _UT('9'): | ||
256 | uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); | ||
257 | return first + 1; | ||
258 | |||
259 | default: | ||
260 | return first; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | |||
265 | |||
266 | /* | ||
267 | * [decOctetThree]-><NULL> | ||
268 | * [decOctetThree]->[DIGIT] | ||
269 | */ | ||
270 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser, | ||
271 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
272 | if (first >= afterLast) { | ||
273 | return afterLast; | ||
274 | } | ||
275 | |||
276 | switch (*first) { | ||
277 | case _UT('0'): | ||
278 | case _UT('1'): | ||
279 | case _UT('2'): | ||
280 | case _UT('3'): | ||
281 | case _UT('4'): | ||
282 | case _UT('5'): | ||
283 | case _UT('6'): | ||
284 | case _UT('7'): | ||
285 | case _UT('8'): | ||
286 | case _UT('9'): | ||
287 | uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); | ||
288 | return first + 1; | ||
289 | |||
290 | default: | ||
291 | return first; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | |||
296 | |||
297 | /* | ||
298 | * [decOctetFour]-><NULL> | ||
299 | * [decOctetFour]-><0> | ||
300 | * [decOctetFour]-><1> | ||
301 | * [decOctetFour]-><2> | ||
302 | * [decOctetFour]-><3> | ||
303 | * [decOctetFour]-><4> | ||
304 | * [decOctetFour]-><5> | ||
305 | */ | ||
306 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser, | ||
307 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
308 | if (first >= afterLast) { | ||
309 | return afterLast; | ||
310 | } | ||
311 | |||
312 | switch (*first) { | ||
313 | case _UT('0'): | ||
314 | case _UT('1'): | ||
315 | case _UT('2'): | ||
316 | case _UT('3'): | ||
317 | case _UT('4'): | ||
318 | case _UT('5'): | ||
319 | uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); | ||
320 | return first + 1; | ||
321 | |||
322 | default: | ||
323 | return first; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | |||
328 | |||
329 | #endif | ||
diff --git a/plugins/uriparser/UriIp4.h b/plugins/uriparser/UriIp4.h new file mode 100644 index 00000000..885a35ca --- /dev/null +++ b/plugins/uriparser/UriIp4.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriIp4.h | ||
42 | * Holds the IPv4 parser interface. | ||
43 | * NOTE: This header includes itself twice. | ||
44 | */ | ||
45 | |||
46 | #if (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI)) \ | ||
47 | || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE)) \ | ||
48 | || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
49 | /* What encodings are enabled? */ | ||
50 | #include "UriDefsConfig.h" | ||
51 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
52 | /* Include SELF twice */ | ||
53 | # ifdef URI_ENABLE_ANSI | ||
54 | # define URI_PASS_ANSI 1 | ||
55 | # include "UriIp4.h" | ||
56 | # undef URI_PASS_ANSI | ||
57 | # endif | ||
58 | # ifdef URI_ENABLE_UNICODE | ||
59 | # define URI_PASS_UNICODE 1 | ||
60 | # include "UriIp4.h" | ||
61 | # undef URI_PASS_UNICODE | ||
62 | # endif | ||
63 | /* Only one pass for each encoding */ | ||
64 | #elif (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI) \ | ||
65 | && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ | ||
66 | && !defined(URI_IP4_TWICE_H_UNICODE) && defined(URI_ENABLE_UNICODE)) | ||
67 | # ifdef URI_PASS_ANSI | ||
68 | # define URI_IP4_TWICE_H_ANSI 1 | ||
69 | # include "UriDefsAnsi.h" | ||
70 | # else | ||
71 | # define URI_IP4_TWICE_H_UNICODE 1 | ||
72 | # include "UriDefsUnicode.h" | ||
73 | # include <wchar.h> | ||
74 | # endif | ||
75 | |||
76 | |||
77 | |||
78 | /** | ||
79 | * Converts a IPv4 text representation into four bytes. | ||
80 | * | ||
81 | * @param octetOutput Output destination | ||
82 | * @param first First character of IPv4 text to parse | ||
83 | * @param afterLast Position to stop parsing at | ||
84 | * @return Error code or 0 on success | ||
85 | */ | ||
86 | int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, | ||
87 | const URI_CHAR * first, const URI_CHAR * afterLast); | ||
88 | |||
89 | |||
90 | |||
91 | #endif | ||
92 | #endif | ||
diff --git a/plugins/uriparser/UriIp4Base.c b/plugins/uriparser/UriIp4Base.c new file mode 100644 index 00000000..5cd298fa --- /dev/null +++ b/plugins/uriparser/UriIp4Base.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriIp4Base.c | ||
42 | * Holds code independent of the encoding pass. | ||
43 | */ | ||
44 | |||
45 | #ifndef URI_DOXYGEN | ||
46 | # include "UriIp4Base.h" | ||
47 | #endif | ||
48 | |||
49 | |||
50 | |||
51 | void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet) { | ||
52 | switch (parser->stackCount) { | ||
53 | case 1: | ||
54 | *octet = parser->stackOne; | ||
55 | break; | ||
56 | |||
57 | case 2: | ||
58 | *octet = parser->stackOne * 10 | ||
59 | + parser->stackTwo; | ||
60 | break; | ||
61 | |||
62 | case 3: | ||
63 | *octet = parser->stackOne * 100 | ||
64 | + parser->stackTwo * 10 | ||
65 | + parser->stackThree; | ||
66 | break; | ||
67 | |||
68 | default: | ||
69 | ; | ||
70 | } | ||
71 | parser->stackCount = 0; | ||
72 | } | ||
73 | |||
74 | |||
75 | |||
76 | void uriPushToStack(UriIp4Parser * parser, unsigned char digit) { | ||
77 | switch (parser->stackCount) { | ||
78 | case 0: | ||
79 | parser->stackOne = digit; | ||
80 | parser->stackCount = 1; | ||
81 | break; | ||
82 | |||
83 | case 1: | ||
84 | parser->stackTwo = digit; | ||
85 | parser->stackCount = 2; | ||
86 | break; | ||
87 | |||
88 | case 2: | ||
89 | parser->stackThree = digit; | ||
90 | parser->stackCount = 3; | ||
91 | break; | ||
92 | |||
93 | default: | ||
94 | ; | ||
95 | } | ||
96 | } | ||
diff --git a/plugins/uriparser/UriIp4Base.h b/plugins/uriparser/UriIp4Base.h new file mode 100644 index 00000000..23b838e2 --- /dev/null +++ b/plugins/uriparser/UriIp4Base.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #ifndef URI_IP4_BASE_H | ||
41 | #define URI_IP4_BASE_H 1 | ||
42 | |||
43 | |||
44 | |||
45 | typedef struct UriIp4ParserStruct { | ||
46 | unsigned char stackCount; | ||
47 | unsigned char stackOne; | ||
48 | unsigned char stackTwo; | ||
49 | unsigned char stackThree; | ||
50 | } UriIp4Parser; | ||
51 | |||
52 | |||
53 | |||
54 | void uriPushToStack(UriIp4Parser * parser, unsigned char digit); | ||
55 | void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet); | ||
56 | |||
57 | |||
58 | |||
59 | #endif /* URI_IP4_BASE_H */ | ||
diff --git a/plugins/uriparser/UriNormalize.c b/plugins/uriparser/UriNormalize.c new file mode 100644 index 00000000..49db9fff --- /dev/null +++ b/plugins/uriparser/UriNormalize.c | |||
@@ -0,0 +1,728 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriNormalize.c | ||
42 | * Holds the RFC 3986 %URI normalization implementation. | ||
43 | * NOTE: This source file includes itself twice. | ||
44 | */ | ||
45 | |||
46 | /* What encodings are enabled? */ | ||
47 | #include <uriparser/UriDefsConfig.h> | ||
48 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
49 | /* Include SELF twice */ | ||
50 | # ifdef URI_ENABLE_ANSI | ||
51 | # define URI_PASS_ANSI 1 | ||
52 | # include "UriNormalize.c" | ||
53 | # undef URI_PASS_ANSI | ||
54 | # endif | ||
55 | # ifdef URI_ENABLE_UNICODE | ||
56 | # define URI_PASS_UNICODE 1 | ||
57 | # include "UriNormalize.c" | ||
58 | # undef URI_PASS_UNICODE | ||
59 | # endif | ||
60 | #else | ||
61 | # ifdef URI_PASS_ANSI | ||
62 | # include <uriparser/UriDefsAnsi.h> | ||
63 | # else | ||
64 | # include <uriparser/UriDefsUnicode.h> | ||
65 | # include <wchar.h> | ||
66 | # endif | ||
67 | |||
68 | |||
69 | |||
70 | #ifndef URI_DOXYGEN | ||
71 | # include <uriparser/Uri.h> | ||
72 | # include "UriNormalizeBase.h" | ||
73 | # include "UriCommon.h" | ||
74 | #endif | ||
75 | |||
76 | |||
77 | |||
78 | static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask, | ||
79 | unsigned int * outMask); | ||
80 | |||
81 | static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask, | ||
82 | unsigned int maskTest, URI_TYPE(TextRange) * range); | ||
83 | static UriBool URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri, | ||
84 | unsigned int * doneMask); | ||
85 | |||
86 | static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first, | ||
87 | const URI_CHAR ** afterLast); | ||
88 | static UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first, | ||
89 | const URI_CHAR ** afterLast); | ||
90 | static void URI_FUNC(FixPercentEncodingEngine)( | ||
91 | const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, | ||
92 | const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast); | ||
93 | |||
94 | static UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first, | ||
95 | const URI_CHAR * afterLast); | ||
96 | static UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first, | ||
97 | const URI_CHAR * afterLast); | ||
98 | |||
99 | static void URI_FUNC(LowercaseInplace)(const URI_CHAR * first, | ||
100 | const URI_CHAR * afterLast); | ||
101 | static UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first, | ||
102 | const URI_CHAR ** afterLast); | ||
103 | |||
104 | static void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, | ||
105 | unsigned int revertMask); | ||
106 | |||
107 | |||
108 | |||
109 | static URI_INLINE void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, | ||
110 | unsigned int revertMask) { | ||
111 | if (revertMask & URI_NORMALIZE_SCHEME) { | ||
112 | free((URI_CHAR *)uri->scheme.first); | ||
113 | uri->scheme.first = NULL; | ||
114 | uri->scheme.afterLast = NULL; | ||
115 | } | ||
116 | |||
117 | if (revertMask & URI_NORMALIZE_USER_INFO) { | ||
118 | free((URI_CHAR *)uri->userInfo.first); | ||
119 | uri->userInfo.first = NULL; | ||
120 | uri->userInfo.afterLast = NULL; | ||
121 | } | ||
122 | |||
123 | if (revertMask & URI_NORMALIZE_HOST) { | ||
124 | if (uri->hostData.ipFuture.first != NULL) { | ||
125 | /* IPvFuture */ | ||
126 | free((URI_CHAR *)uri->hostData.ipFuture.first); | ||
127 | uri->hostData.ipFuture.first = NULL; | ||
128 | uri->hostData.ipFuture.afterLast = NULL; | ||
129 | uri->hostText.first = NULL; | ||
130 | uri->hostText.afterLast = NULL; | ||
131 | } else if ((uri->hostText.first != NULL) | ||
132 | && (uri->hostData.ip4 == NULL) | ||
133 | && (uri->hostData.ip6 == NULL)) { | ||
134 | /* Regname */ | ||
135 | free((URI_CHAR *)uri->hostText.first); | ||
136 | uri->hostText.first = NULL; | ||
137 | uri->hostText.afterLast = NULL; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /* NOTE: Port cannot happen! */ | ||
142 | |||
143 | if (revertMask & URI_NORMALIZE_PATH) { | ||
144 | URI_TYPE(PathSegment) * walker = uri->pathHead; | ||
145 | while (walker != NULL) { | ||
146 | URI_TYPE(PathSegment) * const next = walker->next; | ||
147 | if (walker->text.afterLast > walker->text.first) { | ||
148 | free((URI_CHAR *)walker->text.first); | ||
149 | } | ||
150 | free(walker); | ||
151 | walker = next; | ||
152 | } | ||
153 | uri->pathHead = NULL; | ||
154 | uri->pathTail = NULL; | ||
155 | } | ||
156 | |||
157 | if (revertMask & URI_NORMALIZE_QUERY) { | ||
158 | free((URI_CHAR *)uri->query.first); | ||
159 | uri->query.first = NULL; | ||
160 | uri->query.afterLast = NULL; | ||
161 | } | ||
162 | |||
163 | if (revertMask & URI_NORMALIZE_FRAGMENT) { | ||
164 | free((URI_CHAR *)uri->fragment.first); | ||
165 | uri->fragment.first = NULL; | ||
166 | uri->fragment.afterLast = NULL; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | |||
171 | |||
172 | static URI_INLINE UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first, | ||
173 | const URI_CHAR * afterLast) { | ||
174 | if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { | ||
175 | const URI_CHAR * i = first; | ||
176 | for (; i < afterLast; i++) { | ||
177 | /* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */ | ||
178 | if ((*i >= _UT('A')) && (*i <= _UT('Z'))) { | ||
179 | return URI_TRUE; | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | return URI_FALSE; | ||
184 | } | ||
185 | |||
186 | |||
187 | |||
188 | static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first, | ||
189 | const URI_CHAR * afterLast) { | ||
190 | if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { | ||
191 | const URI_CHAR * i = first; | ||
192 | for (; i + 2 < afterLast; i++) { | ||
193 | if (i[0] == _UT('%')) { | ||
194 | /* 6.2.2.1 Case Normalization: * | ||
195 | * lowercase percent-encodings */ | ||
196 | if (((i[1] >= _UT('a')) && (i[1] <= _UT('f'))) | ||
197 | || ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) { | ||
198 | return URI_TRUE; | ||
199 | } else { | ||
200 | /* 6.2.2.2 Percent-Encoding Normalization: * | ||
201 | * percent-encoded unreserved characters */ | ||
202 | const unsigned char left = URI_FUNC(HexdigToInt)(i[1]); | ||
203 | const unsigned char right = URI_FUNC(HexdigToInt)(i[2]); | ||
204 | const int code = 16 * left + right; | ||
205 | if (uriIsUnreserved(code)) { | ||
206 | return URI_TRUE; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | return URI_FALSE; | ||
213 | } | ||
214 | |||
215 | |||
216 | |||
217 | static URI_INLINE void URI_FUNC(LowercaseInplace)(const URI_CHAR * first, | ||
218 | const URI_CHAR * afterLast) { | ||
219 | if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { | ||
220 | URI_CHAR * i = (URI_CHAR *)first; | ||
221 | const int lowerUpperDiff = (_UT('a') - _UT('A')); | ||
222 | for (; i < afterLast; i++) { | ||
223 | if ((*i >= _UT('A')) && (*i <=_UT('Z'))) { | ||
224 | *i = (URI_CHAR)(*i + lowerUpperDiff); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | |||
231 | |||
232 | static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first, | ||
233 | const URI_CHAR ** afterLast) { | ||
234 | int lenInChars; | ||
235 | const int lowerUpperDiff = (_UT('a') - _UT('A')); | ||
236 | URI_CHAR * buffer; | ||
237 | int i = 0; | ||
238 | |||
239 | if ((first == NULL) || (afterLast == NULL) || (*first == NULL) | ||
240 | || (*afterLast == NULL)) { | ||
241 | return URI_FALSE; | ||
242 | } | ||
243 | |||
244 | lenInChars = (int)(*afterLast - *first); | ||
245 | if (lenInChars == 0) { | ||
246 | return URI_TRUE; | ||
247 | } else if (lenInChars < 0) { | ||
248 | return URI_FALSE; | ||
249 | } | ||
250 | |||
251 | buffer = malloc(lenInChars * sizeof(URI_CHAR)); | ||
252 | if (buffer == NULL) { | ||
253 | return URI_FALSE; | ||
254 | } | ||
255 | |||
256 | for (; i < lenInChars; i++) { | ||
257 | if (((*first)[i] >= _UT('A')) && ((*first)[i] <=_UT('Z'))) { | ||
258 | buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff); | ||
259 | } else { | ||
260 | buffer[i] = (*first)[i]; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | *first = buffer; | ||
265 | *afterLast = buffer + lenInChars; | ||
266 | return URI_TRUE; | ||
267 | } | ||
268 | |||
269 | |||
270 | |||
271 | /* NOTE: Implementation must stay inplace-compatible */ | ||
272 | static URI_INLINE void URI_FUNC(FixPercentEncodingEngine)( | ||
273 | const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, | ||
274 | const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast) { | ||
275 | URI_CHAR * write = (URI_CHAR *)outFirst; | ||
276 | const int lenInChars = (int)(inAfterLast - inFirst); | ||
277 | int i = 0; | ||
278 | |||
279 | /* All but last two */ | ||
280 | for (; i + 2 < lenInChars; i++) { | ||
281 | if (inFirst[i] != _UT('%')) { | ||
282 | write[0] = inFirst[i]; | ||
283 | write++; | ||
284 | } else { | ||
285 | /* 6.2.2.2 Percent-Encoding Normalization: * | ||
286 | * percent-encoded unreserved characters */ | ||
287 | const URI_CHAR one = inFirst[i + 1]; | ||
288 | const URI_CHAR two = inFirst[i + 2]; | ||
289 | const unsigned char left = URI_FUNC(HexdigToInt)(one); | ||
290 | const unsigned char right = URI_FUNC(HexdigToInt)(two); | ||
291 | const int code = 16 * left + right; | ||
292 | if (uriIsUnreserved(code)) { | ||
293 | write[0] = (URI_CHAR)(code); | ||
294 | write++; | ||
295 | } else { | ||
296 | /* 6.2.2.1 Case Normalization: * | ||
297 | * lowercase percent-encodings */ | ||
298 | write[0] = _UT('%'); | ||
299 | write[1] = URI_FUNC(HexToLetter)(left); | ||
300 | write[2] = URI_FUNC(HexToLetter)(right); | ||
301 | write += 3; | ||
302 | } | ||
303 | |||
304 | i += 2; /* For the two chars of the percent group we just ate */ | ||
305 | } | ||
306 | } | ||
307 | |||
308 | /* Last two */ | ||
309 | for (; i < lenInChars; i++) { | ||
310 | write[0] = inFirst[i]; | ||
311 | write++; | ||
312 | } | ||
313 | |||
314 | *outAfterLast = write; | ||
315 | } | ||
316 | |||
317 | |||
318 | |||
319 | static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first, | ||
320 | const URI_CHAR ** afterLast) { | ||
321 | /* Death checks */ | ||
322 | if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) { | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | /* Fix inplace */ | ||
327 | URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast); | ||
328 | } | ||
329 | |||
330 | |||
331 | |||
332 | static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first, | ||
333 | const URI_CHAR ** afterLast) { | ||
334 | int lenInChars; | ||
335 | URI_CHAR * buffer; | ||
336 | |||
337 | /* Death checks */ | ||
338 | if ((first == NULL) || (afterLast == NULL) | ||
339 | || (*first == NULL) || (*afterLast == NULL)) { | ||
340 | return URI_FALSE; | ||
341 | } | ||
342 | |||
343 | /* Old text length */ | ||
344 | lenInChars = (int)(*afterLast - *first); | ||
345 | if (lenInChars == 0) { | ||
346 | return URI_TRUE; | ||
347 | } else if (lenInChars < 0) { | ||
348 | return URI_FALSE; | ||
349 | } | ||
350 | |||
351 | /* New buffer */ | ||
352 | buffer = malloc(lenInChars * sizeof(URI_CHAR)); | ||
353 | if (buffer == NULL) { | ||
354 | return URI_FALSE; | ||
355 | } | ||
356 | |||
357 | /* Fix on copy */ | ||
358 | URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast); | ||
359 | *first = buffer; | ||
360 | return URI_TRUE; | ||
361 | } | ||
362 | |||
363 | |||
364 | |||
365 | static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask, | ||
366 | unsigned int maskTest, URI_TYPE(TextRange) * range) { | ||
367 | if (((*doneMask & maskTest) == 0) | ||
368 | && (range->first != NULL) | ||
369 | && (range->afterLast != NULL) | ||
370 | && (range->afterLast > range->first)) { | ||
371 | const int lenInChars = (int)(range->afterLast - range->first); | ||
372 | const int lenInBytes = lenInChars * sizeof(URI_CHAR); | ||
373 | URI_CHAR * dup = malloc(lenInBytes); | ||
374 | if (dup == NULL) { | ||
375 | return URI_FALSE; /* Raises malloc error */ | ||
376 | } | ||
377 | memcpy(dup, range->first, lenInBytes); | ||
378 | range->first = dup; | ||
379 | range->afterLast = dup + lenInChars; | ||
380 | *doneMask |= maskTest; | ||
381 | } | ||
382 | return URI_TRUE; | ||
383 | } | ||
384 | |||
385 | |||
386 | |||
387 | static URI_INLINE UriBool URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri, | ||
388 | unsigned int * doneMask) { | ||
389 | URI_TYPE(PathSegment) * walker = uri->pathHead; | ||
390 | if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_SCHEME, | ||
391 | &(uri->scheme)) | ||
392 | || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_USER_INFO, | ||
393 | &(uri->userInfo)) | ||
394 | || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_QUERY, | ||
395 | &(uri->query)) | ||
396 | || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_FRAGMENT, | ||
397 | &(uri->fragment))) { | ||
398 | return URI_FALSE; /* Raises malloc error */ | ||
399 | } | ||
400 | |||
401 | /* Host */ | ||
402 | if ((*doneMask & URI_NORMALIZE_HOST) == 0) { | ||
403 | if ((uri->hostData.ip4 == NULL) | ||
404 | && (uri->hostData.ip6 == NULL)) { | ||
405 | if (uri->hostData.ipFuture.first != NULL) { | ||
406 | /* IPvFuture */ | ||
407 | if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST, | ||
408 | &(uri->hostData.ipFuture))) { | ||
409 | return URI_FALSE; /* Raises malloc error */ | ||
410 | } | ||
411 | uri->hostText.first = uri->hostData.ipFuture.first; | ||
412 | uri->hostText.afterLast = uri->hostData.ipFuture.afterLast; | ||
413 | } else if (uri->hostText.first != NULL) { | ||
414 | /* Regname */ | ||
415 | if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST, | ||
416 | &(uri->hostText))) { | ||
417 | return URI_FALSE; /* Raises malloc error */ | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* Path */ | ||
424 | if ((*doneMask & URI_NORMALIZE_PATH) == 0) { | ||
425 | while (walker != NULL) { | ||
426 | if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(walker->text))) { | ||
427 | /* Free allocations done so far and kill path */ | ||
428 | |||
429 | /* Kill path to one before walker (if any) */ | ||
430 | URI_TYPE(PathSegment) * ranger = uri->pathHead; | ||
431 | while (ranger != walker) { | ||
432 | URI_TYPE(PathSegment) * const next = ranger->next; | ||
433 | if ((ranger->text.first != NULL) | ||
434 | && (ranger->text.afterLast != NULL) | ||
435 | && (ranger->text.afterLast > ranger->text.first)) { | ||
436 | free((URI_CHAR *)ranger->text.first); | ||
437 | free(ranger); | ||
438 | } | ||
439 | ranger = next; | ||
440 | } | ||
441 | |||
442 | /* Kill path from walker */ | ||
443 | while (walker != NULL) { | ||
444 | URI_TYPE(PathSegment) * const next = walker->next; | ||
445 | free(walker); | ||
446 | walker = next; | ||
447 | } | ||
448 | |||
449 | uri->pathHead = NULL; | ||
450 | uri->pathTail = NULL; | ||
451 | return URI_FALSE; /* Raises malloc error */ | ||
452 | } | ||
453 | walker = walker->next; | ||
454 | } | ||
455 | *doneMask |= URI_NORMALIZE_PATH; | ||
456 | } | ||
457 | |||
458 | /* Port text, must come last so we don't have to undo that one if it fails. * | ||
459 | * Otherwise we would need and extra enum flag for it although the port * | ||
460 | * cannot go unnormalized... */ | ||
461 | if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(uri->portText))) { | ||
462 | return URI_FALSE; /* Raises malloc error */ | ||
463 | } | ||
464 | |||
465 | return URI_TRUE; | ||
466 | } | ||
467 | |||
468 | |||
469 | |||
470 | unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri) { | ||
471 | unsigned int res; | ||
472 | #if defined(__GNUC__) && ((__GNUC__ > 4) \ | ||
473 | || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2))) | ||
474 | /* Slower code that fixes a warning, not sure if this is a smart idea */ | ||
475 | URI_TYPE(Uri) writeableClone; | ||
476 | memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri))); | ||
477 | URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, &res); | ||
478 | #else | ||
479 | URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, &res); | ||
480 | #endif | ||
481 | return res; | ||
482 | } | ||
483 | |||
484 | |||
485 | |||
486 | int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask) { | ||
487 | return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL); | ||
488 | } | ||
489 | |||
490 | |||
491 | |||
492 | int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri) { | ||
493 | return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1); | ||
494 | } | ||
495 | |||
496 | |||
497 | |||
498 | static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask, unsigned int * outMask) { | ||
499 | unsigned int doneMask = URI_NORMALIZED; | ||
500 | if (uri == NULL) { | ||
501 | if (outMask != NULL) { | ||
502 | *outMask = URI_NORMALIZED; | ||
503 | return URI_SUCCESS; | ||
504 | } else { | ||
505 | return URI_ERROR_NULL; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | if (outMask != NULL) { | ||
510 | /* Reset mask */ | ||
511 | *outMask = URI_NORMALIZED; | ||
512 | } else if (inMask == URI_NORMALIZED) { | ||
513 | /* Nothing to do */ | ||
514 | return URI_SUCCESS; | ||
515 | } | ||
516 | |||
517 | /* Scheme, host */ | ||
518 | if (outMask != NULL) { | ||
519 | const UriBool normalizeScheme = URI_FUNC(ContainsUppercaseLetters)( | ||
520 | uri->scheme.first, uri->scheme.afterLast); | ||
521 | const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)( | ||
522 | uri->hostText.first, uri->hostText.afterLast); | ||
523 | if (normalizeScheme) { | ||
524 | *outMask |= URI_NORMALIZE_SCHEME; | ||
525 | } | ||
526 | |||
527 | if (normalizeHostCase) { | ||
528 | *outMask |= URI_NORMALIZE_HOST; | ||
529 | } else { | ||
530 | const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)( | ||
531 | uri->hostText.first, uri->hostText.afterLast); | ||
532 | if (normalizeHostPrecent) { | ||
533 | *outMask |= URI_NORMALIZE_HOST; | ||
534 | } | ||
535 | } | ||
536 | } else { | ||
537 | /* Scheme */ | ||
538 | if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) { | ||
539 | if (uri->owner) { | ||
540 | URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast); | ||
541 | } else { | ||
542 | if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first), &(uri->scheme.afterLast))) { | ||
543 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
544 | return URI_ERROR_MALLOC; | ||
545 | } | ||
546 | doneMask |= URI_NORMALIZE_SCHEME; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /* Host */ | ||
551 | if (inMask & URI_NORMALIZE_HOST) { | ||
552 | if (uri->hostData.ipFuture.first != NULL) { | ||
553 | /* IPvFuture */ | ||
554 | if (uri->owner) { | ||
555 | URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first, | ||
556 | uri->hostData.ipFuture.afterLast); | ||
557 | } else { | ||
558 | if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first), | ||
559 | &(uri->hostData.ipFuture.afterLast))) { | ||
560 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
561 | return URI_ERROR_MALLOC; | ||
562 | } | ||
563 | doneMask |= URI_NORMALIZE_HOST; | ||
564 | } | ||
565 | uri->hostText.first = uri->hostData.ipFuture.first; | ||
566 | uri->hostText.afterLast = uri->hostData.ipFuture.afterLast; | ||
567 | } else if ((uri->hostText.first != NULL) | ||
568 | && (uri->hostData.ip4 == NULL) | ||
569 | && (uri->hostData.ip6 == NULL)) { | ||
570 | /* Regname */ | ||
571 | if (uri->owner) { | ||
572 | URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first, | ||
573 | &(uri->hostText.afterLast)); | ||
574 | } else { | ||
575 | if (!URI_FUNC(FixPercentEncodingMalloc)( | ||
576 | &(uri->hostText.first), | ||
577 | &(uri->hostText.afterLast))) { | ||
578 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
579 | return URI_ERROR_MALLOC; | ||
580 | } | ||
581 | doneMask |= URI_NORMALIZE_HOST; | ||
582 | } | ||
583 | |||
584 | URI_FUNC(LowercaseInplace)(uri->hostText.first, | ||
585 | uri->hostText.afterLast); | ||
586 | } | ||
587 | } | ||
588 | } | ||
589 | |||
590 | /* User info */ | ||
591 | if (outMask != NULL) { | ||
592 | const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)( | ||
593 | uri->userInfo.first, uri->userInfo.afterLast); | ||
594 | if (normalizeUserInfo) { | ||
595 | *outMask |= URI_NORMALIZE_USER_INFO; | ||
596 | } | ||
597 | } else { | ||
598 | if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) { | ||
599 | if (uri->owner) { | ||
600 | URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first, &(uri->userInfo.afterLast)); | ||
601 | } else { | ||
602 | if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->userInfo.first), | ||
603 | &(uri->userInfo.afterLast))) { | ||
604 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
605 | return URI_ERROR_MALLOC; | ||
606 | } | ||
607 | doneMask |= URI_NORMALIZE_USER_INFO; | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | /* Path */ | ||
613 | if (outMask != NULL) { | ||
614 | const URI_TYPE(PathSegment) * walker = uri->pathHead; | ||
615 | while (walker != NULL) { | ||
616 | const URI_CHAR * const first = walker->text.first; | ||
617 | const URI_CHAR * const afterLast = walker->text.afterLast; | ||
618 | if ((first != NULL) | ||
619 | && (afterLast != NULL) | ||
620 | && (afterLast > first) | ||
621 | && ( | ||
622 | (((afterLast - first) == 1) | ||
623 | && (first[0] == _UT('.'))) | ||
624 | || | ||
625 | (((afterLast - first) == 2) | ||
626 | && (first[0] == _UT('.')) | ||
627 | && (first[1] == _UT('.'))) | ||
628 | || | ||
629 | URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast) | ||
630 | )) { | ||
631 | *outMask |= URI_NORMALIZE_PATH; | ||
632 | break; | ||
633 | } | ||
634 | walker = walker->next; | ||
635 | } | ||
636 | } else if (inMask & URI_NORMALIZE_PATH) { | ||
637 | URI_TYPE(PathSegment) * walker; | ||
638 | const UriBool relative = ((uri->scheme.first == NULL) | ||
639 | && !uri->absolutePath) ? URI_TRUE : URI_FALSE; | ||
640 | |||
641 | /* Fix percent-encoding for each segment */ | ||
642 | walker = uri->pathHead; | ||
643 | if (uri->owner) { | ||
644 | while (walker != NULL) { | ||
645 | URI_FUNC(FixPercentEncodingInplace)(walker->text.first, &(walker->text.afterLast)); | ||
646 | walker = walker->next; | ||
647 | } | ||
648 | } else { | ||
649 | while (walker != NULL) { | ||
650 | if (!URI_FUNC(FixPercentEncodingMalloc)(&(walker->text.first), | ||
651 | &(walker->text.afterLast))) { | ||
652 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
653 | return URI_ERROR_MALLOC; | ||
654 | } | ||
655 | walker = walker->next; | ||
656 | } | ||
657 | doneMask |= URI_NORMALIZE_PATH; | ||
658 | } | ||
659 | |||
660 | /* 6.2.2.3 Path Segment Normalization */ | ||
661 | if (!URI_FUNC(RemoveDotSegmentsEx)(uri, relative, | ||
662 | (uri->owner == URI_TRUE) | ||
663 | || ((doneMask & URI_NORMALIZE_PATH) != 0) | ||
664 | )) { | ||
665 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
666 | return URI_ERROR_MALLOC; | ||
667 | } | ||
668 | URI_FUNC(FixEmptyTrailSegment)(uri); | ||
669 | } | ||
670 | |||
671 | /* Query, fragment */ | ||
672 | if (outMask != NULL) { | ||
673 | const UriBool normalizeQuery = URI_FUNC(ContainsUglyPercentEncoding)( | ||
674 | uri->query.first, uri->query.afterLast); | ||
675 | const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)( | ||
676 | uri->fragment.first, uri->fragment.afterLast); | ||
677 | if (normalizeQuery) { | ||
678 | *outMask |= URI_NORMALIZE_QUERY; | ||
679 | } | ||
680 | |||
681 | if (normalizeFragment) { | ||
682 | *outMask |= URI_NORMALIZE_FRAGMENT; | ||
683 | } | ||
684 | } else { | ||
685 | /* Query */ | ||
686 | if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) { | ||
687 | if (uri->owner) { | ||
688 | URI_FUNC(FixPercentEncodingInplace)(uri->query.first, &(uri->query.afterLast)); | ||
689 | } else { | ||
690 | if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->query.first), | ||
691 | &(uri->query.afterLast))) { | ||
692 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
693 | return URI_ERROR_MALLOC; | ||
694 | } | ||
695 | doneMask |= URI_NORMALIZE_QUERY; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | /* Fragment */ | ||
700 | if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) { | ||
701 | if (uri->owner) { | ||
702 | URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first, &(uri->fragment.afterLast)); | ||
703 | } else { | ||
704 | if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->fragment.first), | ||
705 | &(uri->fragment.afterLast))) { | ||
706 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
707 | return URI_ERROR_MALLOC; | ||
708 | } | ||
709 | doneMask |= URI_NORMALIZE_FRAGMENT; | ||
710 | } | ||
711 | } | ||
712 | } | ||
713 | |||
714 | /* Dup all not duped yet */ | ||
715 | if ((outMask == NULL) && !uri->owner) { | ||
716 | if (!URI_FUNC(MakeOwner)(uri, &doneMask)) { | ||
717 | URI_FUNC(PreventLeakage)(uri, doneMask); | ||
718 | return URI_ERROR_MALLOC; | ||
719 | } | ||
720 | uri->owner = URI_TRUE; | ||
721 | } | ||
722 | |||
723 | return URI_SUCCESS; | ||
724 | } | ||
725 | |||
726 | |||
727 | |||
728 | #endif | ||
diff --git a/plugins/uriparser/UriNormalizeBase.c b/plugins/uriparser/UriNormalizeBase.c new file mode 100644 index 00000000..bac58886 --- /dev/null +++ b/plugins/uriparser/UriNormalizeBase.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #ifndef URI_DOXYGEN | ||
41 | # include "UriNormalizeBase.h" | ||
42 | #endif | ||
43 | |||
44 | |||
45 | |||
46 | UriBool uriIsUnreserved(int code) { | ||
47 | switch (code) { | ||
48 | case L'a': /* ALPHA */ | ||
49 | case L'A': | ||
50 | case L'b': | ||
51 | case L'B': | ||
52 | case L'c': | ||
53 | case L'C': | ||
54 | case L'd': | ||
55 | case L'D': | ||
56 | case L'e': | ||
57 | case L'E': | ||
58 | case L'f': | ||
59 | case L'F': | ||
60 | case L'g': | ||
61 | case L'G': | ||
62 | case L'h': | ||
63 | case L'H': | ||
64 | case L'i': | ||
65 | case L'I': | ||
66 | case L'j': | ||
67 | case L'J': | ||
68 | case L'k': | ||
69 | case L'K': | ||
70 | case L'l': | ||
71 | case L'L': | ||
72 | case L'm': | ||
73 | case L'M': | ||
74 | case L'n': | ||
75 | case L'N': | ||
76 | case L'o': | ||
77 | case L'O': | ||
78 | case L'p': | ||
79 | case L'P': | ||
80 | case L'q': | ||
81 | case L'Q': | ||
82 | case L'r': | ||
83 | case L'R': | ||
84 | case L's': | ||
85 | case L'S': | ||
86 | case L't': | ||
87 | case L'T': | ||
88 | case L'u': | ||
89 | case L'U': | ||
90 | case L'v': | ||
91 | case L'V': | ||
92 | case L'w': | ||
93 | case L'W': | ||
94 | case L'x': | ||
95 | case L'X': | ||
96 | case L'y': | ||
97 | case L'Y': | ||
98 | case L'z': | ||
99 | case L'Z': | ||
100 | case L'0': /* DIGIT */ | ||
101 | case L'1': | ||
102 | case L'2': | ||
103 | case L'3': | ||
104 | case L'4': | ||
105 | case L'5': | ||
106 | case L'6': | ||
107 | case L'7': | ||
108 | case L'8': | ||
109 | case L'9': | ||
110 | case L'-': /* "-" / "." / "_" / "~" */ | ||
111 | case L'.': | ||
112 | case L'_': | ||
113 | case L'~': | ||
114 | return URI_TRUE; | ||
115 | |||
116 | default: | ||
117 | return URI_FALSE; | ||
118 | } | ||
119 | } | ||
diff --git a/plugins/uriparser/UriNormalizeBase.h b/plugins/uriparser/UriNormalizeBase.h new file mode 100644 index 00000000..9f3abd55 --- /dev/null +++ b/plugins/uriparser/UriNormalizeBase.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #ifndef URI_NORMALIZE_BASE_H | ||
41 | #define URI_NORMALIZE_BASE_H 1 | ||
42 | |||
43 | |||
44 | |||
45 | #include <uriparser/UriBase.h> | ||
46 | |||
47 | |||
48 | |||
49 | UriBool uriIsUnreserved(int code); | ||
50 | |||
51 | |||
52 | |||
53 | #endif /* URI_NORMALIZE_BASE_H */ | ||
diff --git a/plugins/uriparser/UriParse.c b/plugins/uriparser/UriParse.c new file mode 100644 index 00000000..e3cdc68d --- /dev/null +++ b/plugins/uriparser/UriParse.c | |||
@@ -0,0 +1,2241 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * @file UriParse.c | ||
42 | * Holds the RFC 3986 %URI parsing implementation. | ||
43 | * NOTE: This source file includes itself twice. | ||
44 | */ | ||
45 | |||
46 | /* What encodings are enabled? */ | ||
47 | #include <uriparser/UriDefsConfig.h> | ||
48 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
49 | /* Include SELF twice */ | ||
50 | # ifdef URI_ENABLE_ANSI | ||
51 | # define URI_PASS_ANSI 1 | ||
52 | # include "UriParse.c" | ||
53 | # undef URI_PASS_ANSI | ||
54 | # endif | ||
55 | # ifdef URI_ENABLE_UNICODE | ||
56 | # define URI_PASS_UNICODE 1 | ||
57 | # include "UriParse.c" | ||
58 | # undef URI_PASS_UNICODE | ||
59 | # endif | ||
60 | #else | ||
61 | # ifdef URI_PASS_ANSI | ||
62 | # include <uriparser/UriDefsAnsi.h> | ||
63 | # else | ||
64 | # include <uriparser/UriDefsUnicode.h> | ||
65 | # include <wchar.h> | ||
66 | # endif | ||
67 | |||
68 | |||
69 | |||
70 | #ifndef URI_DOXYGEN | ||
71 | # include <uriparser/Uri.h> | ||
72 | # include <uriparser/UriIp4.h> | ||
73 | # include "UriCommon.h" | ||
74 | # include "UriParseBase.h" | ||
75 | #endif | ||
76 | |||
77 | |||
78 | |||
79 | #define URI_SET_DIGIT \ | ||
80 | _UT('0'): \ | ||
81 | case _UT('1'): \ | ||
82 | case _UT('2'): \ | ||
83 | case _UT('3'): \ | ||
84 | case _UT('4'): \ | ||
85 | case _UT('5'): \ | ||
86 | case _UT('6'): \ | ||
87 | case _UT('7'): \ | ||
88 | case _UT('8'): \ | ||
89 | case _UT('9') | ||
90 | |||
91 | #define URI_SET_HEX_LETTER_UPPER \ | ||
92 | _UT('A'): \ | ||
93 | case _UT('B'): \ | ||
94 | case _UT('C'): \ | ||
95 | case _UT('D'): \ | ||
96 | case _UT('E'): \ | ||
97 | case _UT('F') | ||
98 | |||
99 | #define URI_SET_HEX_LETTER_LOWER \ | ||
100 | _UT('a'): \ | ||
101 | case _UT('b'): \ | ||
102 | case _UT('c'): \ | ||
103 | case _UT('d'): \ | ||
104 | case _UT('e'): \ | ||
105 | case _UT('f') | ||
106 | |||
107 | #define URI_SET_HEXDIG \ | ||
108 | URI_SET_DIGIT: \ | ||
109 | case URI_SET_HEX_LETTER_UPPER: \ | ||
110 | case URI_SET_HEX_LETTER_LOWER | ||
111 | |||
112 | #define URI_SET_ALPHA \ | ||
113 | URI_SET_HEX_LETTER_UPPER: \ | ||
114 | case URI_SET_HEX_LETTER_LOWER: \ | ||
115 | case _UT('g'): \ | ||
116 | case _UT('G'): \ | ||
117 | case _UT('h'): \ | ||
118 | case _UT('H'): \ | ||
119 | case _UT('i'): \ | ||
120 | case _UT('I'): \ | ||
121 | case _UT('j'): \ | ||
122 | case _UT('J'): \ | ||
123 | case _UT('k'): \ | ||
124 | case _UT('K'): \ | ||
125 | case _UT('l'): \ | ||
126 | case _UT('L'): \ | ||
127 | case _UT('m'): \ | ||
128 | case _UT('M'): \ | ||
129 | case _UT('n'): \ | ||
130 | case _UT('N'): \ | ||
131 | case _UT('o'): \ | ||
132 | case _UT('O'): \ | ||
133 | case _UT('p'): \ | ||
134 | case _UT('P'): \ | ||
135 | case _UT('q'): \ | ||
136 | case _UT('Q'): \ | ||
137 | case _UT('r'): \ | ||
138 | case _UT('R'): \ | ||
139 | case _UT('s'): \ | ||
140 | case _UT('S'): \ | ||
141 | case _UT('t'): \ | ||
142 | case _UT('T'): \ | ||
143 | case _UT('u'): \ | ||
144 | case _UT('U'): \ | ||
145 | case _UT('v'): \ | ||
146 | case _UT('V'): \ | ||
147 | case _UT('w'): \ | ||
148 | case _UT('W'): \ | ||
149 | case _UT('x'): \ | ||
150 | case _UT('X'): \ | ||
151 | case _UT('y'): \ | ||
152 | case _UT('Y'): \ | ||
153 | case _UT('z'): \ | ||
154 | case _UT('Z') | ||
155 | |||
156 | |||
157 | |||
158 | static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
159 | static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
160 | static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
161 | static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
162 | static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
163 | static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
164 | static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
165 | static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
166 | static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
167 | static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
168 | static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
169 | static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
170 | static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
171 | static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
172 | static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
173 | static const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
174 | static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
175 | static const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
176 | static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
177 | static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
178 | static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
179 | static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
180 | static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
181 | static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
182 | static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
183 | static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
184 | static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
185 | static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
186 | static const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
187 | static const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
188 | static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
189 | |||
190 | static UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first); | ||
191 | static UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first); | ||
192 | static UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first); | ||
193 | static UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first); | ||
194 | static void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state); | ||
195 | |||
196 | static void URI_FUNC(ResetParserState)(URI_TYPE(ParserState) * state); | ||
197 | |||
198 | static UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); | ||
199 | |||
200 | static void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, const URI_CHAR * errorPos); | ||
201 | static void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state); | ||
202 | |||
203 | |||
204 | |||
205 | static URI_INLINE void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, | ||
206 | const URI_CHAR * errorPos) { | ||
207 | URI_FUNC(FreeUriMembers)(state->uri); | ||
208 | state->errorPos = errorPos; | ||
209 | state->errorCode = URI_ERROR_SYNTAX; | ||
210 | } | ||
211 | |||
212 | |||
213 | |||
214 | static URI_INLINE void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state) { | ||
215 | URI_FUNC(FreeUriMembers)(state->uri); | ||
216 | state->errorPos = NULL; | ||
217 | state->errorCode = URI_ERROR_MALLOC; | ||
218 | } | ||
219 | |||
220 | |||
221 | |||
222 | /* | ||
223 | * [authority]-><[>[ipLit2][authorityTwo] | ||
224 | * [authority]->[ownHostUserInfoNz] | ||
225 | * [authority]-><NULL> | ||
226 | */ | ||
227 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
228 | if (first >= afterLast) { | ||
229 | /* "" regname host */ | ||
230 | state->uri->hostText.first = URI_FUNC(SafeToPointTo); | ||
231 | state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo); | ||
232 | return afterLast; | ||
233 | } | ||
234 | |||
235 | switch (*first) { | ||
236 | case _UT('['): | ||
237 | { | ||
238 | const URI_CHAR * const afterIpLit2 | ||
239 | = URI_FUNC(ParseIpLit2)(state, first + 1, afterLast); | ||
240 | if (afterIpLit2 == NULL) { | ||
241 | return NULL; | ||
242 | } | ||
243 | state->uri->hostText.first = first + 1; /* HOST BEGIN */ | ||
244 | return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast); | ||
245 | } | ||
246 | |||
247 | case _UT('!'): | ||
248 | case _UT('$'): | ||
249 | case _UT('%'): | ||
250 | case _UT('&'): | ||
251 | case _UT('('): | ||
252 | case _UT(')'): | ||
253 | case _UT('-'): | ||
254 | case _UT('*'): | ||
255 | case _UT(','): | ||
256 | case _UT('.'): | ||
257 | case _UT(':'): | ||
258 | case _UT(';'): | ||
259 | case _UT('@'): | ||
260 | case _UT('\''): | ||
261 | case _UT('_'): | ||
262 | case _UT('~'): | ||
263 | case _UT('+'): | ||
264 | case _UT('='): | ||
265 | case URI_SET_DIGIT: | ||
266 | case URI_SET_ALPHA: | ||
267 | state->uri->userInfo.first = first; /* USERINFO BEGIN */ | ||
268 | return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast); | ||
269 | |||
270 | default: | ||
271 | /* "" regname host */ | ||
272 | state->uri->hostText.first = URI_FUNC(SafeToPointTo); | ||
273 | state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo); | ||
274 | return first; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | |||
279 | |||
280 | /* | ||
281 | * [authorityTwo]-><:>[port] | ||
282 | * [authorityTwo]-><NULL> | ||
283 | */ | ||
284 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
285 | if (first >= afterLast) { | ||
286 | return afterLast; | ||
287 | } | ||
288 | |||
289 | switch (*first) { | ||
290 | case _UT(':'): | ||
291 | { | ||
292 | const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(state, first + 1, afterLast); | ||
293 | if (afterPort == NULL) { | ||
294 | return NULL; | ||
295 | } | ||
296 | state->uri->portText.first = first + 1; /* PORT BEGIN */ | ||
297 | state->uri->portText.afterLast = afterPort; /* PORT END */ | ||
298 | return afterPort; | ||
299 | } | ||
300 | |||
301 | default: | ||
302 | return first; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | |||
307 | |||
308 | /* | ||
309 | * [hexZero]->[HEXDIG][hexZero] | ||
310 | * [hexZero]-><NULL> | ||
311 | */ | ||
312 | static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
313 | if (first >= afterLast) { | ||
314 | return afterLast; | ||
315 | } | ||
316 | |||
317 | switch (*first) { | ||
318 | case URI_SET_HEXDIG: | ||
319 | return URI_FUNC(ParseHexZero)(state, first + 1, afterLast); | ||
320 | |||
321 | default: | ||
322 | return first; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | |||
327 | |||
328 | /* | ||
329 | * [hierPart]->[pathRootless] | ||
330 | * [hierPart]-></>[partHelperTwo] | ||
331 | * [hierPart]-><NULL> | ||
332 | */ | ||
333 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
334 | if (first >= afterLast) { | ||
335 | return afterLast; | ||
336 | } | ||
337 | |||
338 | switch (*first) { | ||
339 | case _UT('!'): | ||
340 | case _UT('$'): | ||
341 | case _UT('%'): | ||
342 | case _UT('&'): | ||
343 | case _UT('('): | ||
344 | case _UT(')'): | ||
345 | case _UT('-'): | ||
346 | case _UT('*'): | ||
347 | case _UT(','): | ||
348 | case _UT('.'): | ||
349 | case _UT(':'): | ||
350 | case _UT(';'): | ||
351 | case _UT('@'): | ||
352 | case _UT('\''): | ||
353 | case _UT('_'): | ||
354 | case _UT('~'): | ||
355 | case _UT('+'): | ||
356 | case _UT('='): | ||
357 | case URI_SET_DIGIT: | ||
358 | case URI_SET_ALPHA: | ||
359 | return URI_FUNC(ParsePathRootless)(state, first, afterLast); | ||
360 | |||
361 | case _UT('/'): | ||
362 | return URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast); | ||
363 | |||
364 | default: | ||
365 | return first; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | |||
370 | |||
371 | /* | ||
372 | * [ipFutLoop]->[subDelims][ipFutStopGo] | ||
373 | * [ipFutLoop]->[unreserved][ipFutStopGo] | ||
374 | * [ipFutLoop]-><:>[ipFutStopGo] | ||
375 | */ | ||
376 | static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
377 | if (first >= afterLast) { | ||
378 | URI_FUNC(StopSyntax)(state, first); | ||
379 | return NULL; | ||
380 | } | ||
381 | |||
382 | switch (*first) { | ||
383 | case _UT('!'): | ||
384 | case _UT('$'): | ||
385 | case _UT('&'): | ||
386 | case _UT('('): | ||
387 | case _UT(')'): | ||
388 | case _UT('-'): | ||
389 | case _UT('*'): | ||
390 | case _UT(','): | ||
391 | case _UT('.'): | ||
392 | case _UT(':'): | ||
393 | case _UT(';'): | ||
394 | case _UT('\''): | ||
395 | case _UT('_'): | ||
396 | case _UT('~'): | ||
397 | case _UT('+'): | ||
398 | case _UT('='): | ||
399 | case URI_SET_DIGIT: | ||
400 | case URI_SET_ALPHA: | ||
401 | return URI_FUNC(ParseIpFutStopGo)(state, first + 1, afterLast); | ||
402 | |||
403 | default: | ||
404 | URI_FUNC(StopSyntax)(state, first); | ||
405 | return NULL; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | |||
410 | |||
411 | /* | ||
412 | * [ipFutStopGo]->[ipFutLoop] | ||
413 | * [ipFutStopGo]-><NULL> | ||
414 | */ | ||
415 | static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
416 | if (first >= afterLast) { | ||
417 | return afterLast; | ||
418 | } | ||
419 | |||
420 | switch (*first) { | ||
421 | case _UT('!'): | ||
422 | case _UT('$'): | ||
423 | case _UT('&'): | ||
424 | case _UT('('): | ||
425 | case _UT(')'): | ||
426 | case _UT('-'): | ||
427 | case _UT('*'): | ||
428 | case _UT(','): | ||
429 | case _UT('.'): | ||
430 | case _UT(':'): | ||
431 | case _UT(';'): | ||
432 | case _UT('\''): | ||
433 | case _UT('_'): | ||
434 | case _UT('~'): | ||
435 | case _UT('+'): | ||
436 | case _UT('='): | ||
437 | case URI_SET_DIGIT: | ||
438 | case URI_SET_ALPHA: | ||
439 | return URI_FUNC(ParseIpFutLoop)(state, first, afterLast); | ||
440 | |||
441 | default: | ||
442 | return first; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | |||
448 | /* | ||
449 | * [ipFuture]-><v>[HEXDIG][hexZero]<.>[ipFutLoop] | ||
450 | */ | ||
451 | static const URI_CHAR * URI_FUNC(ParseIpFuture)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
452 | if (first >= afterLast) { | ||
453 | URI_FUNC(StopSyntax)(state, first); | ||
454 | return NULL; | ||
455 | } | ||
456 | |||
457 | /* | ||
458 | First character has already been | ||
459 | checked before entering this rule. | ||
460 | |||
461 | switch (*first) { | ||
462 | case _UT('v'): | ||
463 | */ | ||
464 | if (first + 1 >= afterLast) { | ||
465 | URI_FUNC(StopSyntax)(state, first + 1); | ||
466 | return NULL; | ||
467 | } | ||
468 | |||
469 | switch (first[1]) { | ||
470 | case URI_SET_HEXDIG: | ||
471 | { | ||
472 | const URI_CHAR * afterIpFutLoop; | ||
473 | const URI_CHAR * const afterHexZero | ||
474 | = URI_FUNC(ParseHexZero)(state, first + 2, afterLast); | ||
475 | if (afterHexZero == NULL) { | ||
476 | return NULL; | ||
477 | } | ||
478 | if ((afterHexZero >= afterLast) | ||
479 | || (*afterHexZero != _UT('.'))) { | ||
480 | URI_FUNC(StopSyntax)(state, afterHexZero); | ||
481 | return NULL; | ||
482 | } | ||
483 | state->uri->hostText.first = first; /* HOST BEGIN */ | ||
484 | state->uri->hostData.ipFuture.first = first; /* IPFUTURE BEGIN */ | ||
485 | afterIpFutLoop = URI_FUNC(ParseIpFutLoop)(state, afterHexZero + 1, afterLast); | ||
486 | if (afterIpFutLoop == NULL) { | ||
487 | return NULL; | ||
488 | } | ||
489 | state->uri->hostText.afterLast = afterIpFutLoop; /* HOST END */ | ||
490 | state->uri->hostData.ipFuture.afterLast = afterIpFutLoop; /* IPFUTURE END */ | ||
491 | return afterIpFutLoop; | ||
492 | } | ||
493 | |||
494 | default: | ||
495 | URI_FUNC(StopSyntax)(state, first + 1); | ||
496 | return NULL; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | default: | ||
501 | URI_FUNC(StopSyntax)(state, first); | ||
502 | return NULL; | ||
503 | } | ||
504 | */ | ||
505 | } | ||
506 | |||
507 | |||
508 | |||
509 | /* | ||
510 | * [ipLit2]->[ipFuture]<]> | ||
511 | * [ipLit2]->[IPv6address2] | ||
512 | */ | ||
513 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
514 | if (first >= afterLast) { | ||
515 | URI_FUNC(StopSyntax)(state, first); | ||
516 | return NULL; | ||
517 | } | ||
518 | |||
519 | switch (*first) { | ||
520 | case _UT('v'): | ||
521 | { | ||
522 | const URI_CHAR * const afterIpFuture | ||
523 | = URI_FUNC(ParseIpFuture)(state, first, afterLast); | ||
524 | if (afterIpFuture == NULL) { | ||
525 | return NULL; | ||
526 | } | ||
527 | if ((afterIpFuture >= afterLast) | ||
528 | || (*afterIpFuture != _UT(']'))) { | ||
529 | URI_FUNC(StopSyntax)(state, first); | ||
530 | return NULL; | ||
531 | } | ||
532 | return afterIpFuture + 1; | ||
533 | } | ||
534 | |||
535 | case _UT(':'): | ||
536 | case _UT(']'): | ||
537 | case URI_SET_HEXDIG: | ||
538 | state->uri->hostData.ip6 = malloc(1 * sizeof(UriIp6)); /* Freed when stopping on parse error */ | ||
539 | if (state->uri->hostData.ip6 == NULL) { | ||
540 | URI_FUNC(StopMalloc)(state); | ||
541 | return NULL; | ||
542 | } | ||
543 | return URI_FUNC(ParseIPv6address2)(state, first, afterLast); | ||
544 | |||
545 | default: | ||
546 | URI_FUNC(StopSyntax)(state, first); | ||
547 | return NULL; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | |||
552 | |||
553 | /* | ||
554 | * [IPv6address2]->..<]> | ||
555 | */ | ||
556 | static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
557 | int zipperEver = 0; | ||
558 | int quadsDone = 0; | ||
559 | int digitCount = 0; | ||
560 | unsigned char digitHistory[4]; | ||
561 | int ip4OctetsDone = 0; | ||
562 | |||
563 | unsigned char quadsAfterZipper[14]; | ||
564 | int quadsAfterZipperCount = 0; | ||
565 | |||
566 | |||
567 | for (;;) { | ||
568 | if (first >= afterLast) { | ||
569 | URI_FUNC(StopSyntax)(state, first); | ||
570 | return NULL; | ||
571 | } | ||
572 | |||
573 | /* Inside IPv4 part? */ | ||
574 | if (ip4OctetsDone > 0) { | ||
575 | /* Eat rest of IPv4 address */ | ||
576 | for (;;) { | ||
577 | switch (*first) { | ||
578 | case URI_SET_DIGIT: | ||
579 | if (digitCount == 4) { | ||
580 | URI_FUNC(StopSyntax)(state, first); | ||
581 | return NULL; | ||
582 | } | ||
583 | digitHistory[digitCount++] = (unsigned char)(9 + *first - _UT('9')); | ||
584 | break; | ||
585 | |||
586 | case _UT('.'): | ||
587 | if ((ip4OctetsDone == 4) /* NOTE! */ | ||
588 | || (digitCount == 0) | ||
589 | || (digitCount == 4)) { | ||
590 | /* Invalid digit or octet count */ | ||
591 | URI_FUNC(StopSyntax)(state, first); | ||
592 | return NULL; | ||
593 | } else if ((digitCount > 1) | ||
594 | && (digitHistory[0] == 0)) { | ||
595 | /* Leading zero */ | ||
596 | URI_FUNC(StopSyntax)(state, first - digitCount); | ||
597 | return NULL; | ||
598 | } else if ((digitCount > 2) | ||
599 | && (digitHistory[1] == 0)) { | ||
600 | /* Leading zero */ | ||
601 | URI_FUNC(StopSyntax)(state, first - digitCount + 1); | ||
602 | return NULL; | ||
603 | } else if ((digitCount == 3) | ||
604 | && (100 * digitHistory[0] | ||
605 | + 10 * digitHistory[1] | ||
606 | + digitHistory[2] > 255)) { | ||
607 | /* Octet value too large */ | ||
608 | if (digitHistory[0] > 2) { | ||
609 | URI_FUNC(StopSyntax)(state, first - 3); | ||
610 | } else if (digitHistory[1] > 5) { | ||
611 | URI_FUNC(StopSyntax)(state, first - 2); | ||
612 | } else { | ||
613 | URI_FUNC(StopSyntax)(state, first - 1); | ||
614 | } | ||
615 | return NULL; | ||
616 | } | ||
617 | |||
618 | /* Copy IPv4 octet */ | ||
619 | state->uri->hostData.ip6->data[16 - 4 + ip4OctetsDone] = uriGetOctetValue(digitHistory, digitCount); | ||
620 | digitCount = 0; | ||
621 | ip4OctetsDone++; | ||
622 | break; | ||
623 | |||
624 | case _UT(']'): | ||
625 | if ((ip4OctetsDone != 3) /* NOTE! */ | ||
626 | || (digitCount == 0) | ||
627 | || (digitCount == 4)) { | ||
628 | /* Invalid digit or octet count */ | ||
629 | URI_FUNC(StopSyntax)(state, first); | ||
630 | return NULL; | ||
631 | } else if ((digitCount > 1) | ||
632 | && (digitHistory[0] == 0)) { | ||
633 | /* Leading zero */ | ||
634 | URI_FUNC(StopSyntax)(state, first - digitCount); | ||
635 | return NULL; | ||
636 | } else if ((digitCount > 2) | ||
637 | && (digitHistory[1] == 0)) { | ||
638 | /* Leading zero */ | ||
639 | URI_FUNC(StopSyntax)(state, first - digitCount + 1); | ||
640 | return NULL; | ||
641 | } else if ((digitCount == 3) | ||
642 | && (100 * digitHistory[0] | ||
643 | + 10 * digitHistory[1] | ||
644 | + digitHistory[2] > 255)) { | ||
645 | /* Octet value too large */ | ||
646 | if (digitHistory[0] > 2) { | ||
647 | URI_FUNC(StopSyntax)(state, first - 3); | ||
648 | } else if (digitHistory[1] > 5) { | ||
649 | URI_FUNC(StopSyntax)(state, first - 2); | ||
650 | } else { | ||
651 | URI_FUNC(StopSyntax)(state, first - 1); | ||
652 | } | ||
653 | return NULL; | ||
654 | } | ||
655 | |||
656 | state->uri->hostText.afterLast = first; /* HOST END */ | ||
657 | |||
658 | /* Copy missing quads right before IPv4 */ | ||
659 | memcpy(state->uri->hostData.ip6->data + 16 - 4 - 2 * quadsAfterZipperCount, | ||
660 | quadsAfterZipper, 2 * quadsAfterZipperCount); | ||
661 | |||
662 | /* Copy last IPv4 octet */ | ||
663 | state->uri->hostData.ip6->data[16 - 4 + 3] = uriGetOctetValue(digitHistory, digitCount); | ||
664 | |||
665 | return first + 1; | ||
666 | |||
667 | default: | ||
668 | URI_FUNC(StopSyntax)(state, first); | ||
669 | return NULL; | ||
670 | } | ||
671 | first++; | ||
672 | } | ||
673 | } else { | ||
674 | /* Eat while no dot in sight */ | ||
675 | int letterAmong = 0; | ||
676 | int walking = 1; | ||
677 | do { | ||
678 | switch (*first) { | ||
679 | case URI_SET_HEX_LETTER_LOWER: | ||
680 | letterAmong = 1; | ||
681 | if (digitCount == 4) { | ||
682 | URI_FUNC(StopSyntax)(state, first); | ||
683 | return NULL; | ||
684 | } | ||
685 | digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('f')); | ||
686 | digitCount++; | ||
687 | break; | ||
688 | |||
689 | case URI_SET_HEX_LETTER_UPPER: | ||
690 | letterAmong = 1; | ||
691 | if (digitCount == 4) { | ||
692 | URI_FUNC(StopSyntax)(state, first); | ||
693 | return NULL; | ||
694 | } | ||
695 | digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('F')); | ||
696 | digitCount++; | ||
697 | break; | ||
698 | |||
699 | case URI_SET_DIGIT: | ||
700 | if (digitCount == 4) { | ||
701 | URI_FUNC(StopSyntax)(state, first); | ||
702 | return NULL; | ||
703 | } | ||
704 | digitHistory[digitCount] = (unsigned char)(9 + *first - _UT('9')); | ||
705 | digitCount++; | ||
706 | break; | ||
707 | |||
708 | case _UT(':'): | ||
709 | { | ||
710 | int setZipper = 0; | ||
711 | |||
712 | if (digitCount > 0) { | ||
713 | if (zipperEver) { | ||
714 | uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount); | ||
715 | quadsAfterZipperCount++; | ||
716 | } else { | ||
717 | uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone); | ||
718 | } | ||
719 | quadsDone++; | ||
720 | digitCount = 0; | ||
721 | } | ||
722 | letterAmong = 0; | ||
723 | |||
724 | /* Too many quads? */ | ||
725 | if (quadsDone >= 8 - zipperEver) { | ||
726 | URI_FUNC(StopSyntax)(state, first); | ||
727 | return NULL; | ||
728 | } | ||
729 | |||
730 | /* "::"? */ | ||
731 | if (first + 1 >= afterLast) { | ||
732 | URI_FUNC(StopSyntax)(state, first + 1); | ||
733 | return NULL; | ||
734 | } | ||
735 | if (first[1] == _UT(':')) { | ||
736 | const int resetOffset = 2 * (quadsDone + (digitCount > 0)); | ||
737 | |||
738 | first++; | ||
739 | if (zipperEver) { | ||
740 | URI_FUNC(StopSyntax)(state, first); | ||
741 | return NULL; /* "::.+::" */ | ||
742 | } | ||
743 | |||
744 | /* Zero everything after zipper */ | ||
745 | memset(state->uri->hostData.ip6->data + resetOffset, 0, 16 - resetOffset); | ||
746 | setZipper = 1; | ||
747 | |||
748 | /* ":::+"? */ | ||
749 | if (first + 1 >= afterLast) { | ||
750 | URI_FUNC(StopSyntax)(state, first + 1); | ||
751 | return NULL; /* No ']' yet */ | ||
752 | } | ||
753 | if (first[1] == _UT(':')) { | ||
754 | URI_FUNC(StopSyntax)(state, first + 1); | ||
755 | return NULL; /* ":::+ "*/ | ||
756 | } | ||
757 | } | ||
758 | |||
759 | if (setZipper) { | ||
760 | zipperEver = 1; | ||
761 | } | ||
762 | } | ||
763 | break; | ||
764 | |||
765 | case _UT('.'): | ||
766 | if ((quadsDone > 6) /* NOTE */ | ||
767 | || (!zipperEver && (quadsDone < 6)) | ||
768 | || letterAmong | ||
769 | || (digitCount == 0) | ||
770 | || (digitCount == 4)) { | ||
771 | /* Invalid octet before */ | ||
772 | URI_FUNC(StopSyntax)(state, first); | ||
773 | return NULL; | ||
774 | } else if ((digitCount > 1) | ||
775 | && (digitHistory[0] == 0)) { | ||
776 | /* Leading zero */ | ||
777 | URI_FUNC(StopSyntax)(state, first - digitCount); | ||
778 | return NULL; | ||
779 | } else if ((digitCount > 2) | ||
780 | && (digitHistory[1] == 0)) { | ||
781 | /* Leading zero */ | ||
782 | URI_FUNC(StopSyntax)(state, first - digitCount + 1); | ||
783 | return NULL; | ||
784 | } else if ((digitCount == 3) | ||
785 | && (100 * digitHistory[0] | ||
786 | + 10 * digitHistory[1] | ||
787 | + digitHistory[2] > 255)) { | ||
788 | /* Octet value too large */ | ||
789 | if (digitHistory[0] > 2) { | ||
790 | URI_FUNC(StopSyntax)(state, first - 3); | ||
791 | } else if (digitHistory[1] > 5) { | ||
792 | URI_FUNC(StopSyntax)(state, first - 2); | ||
793 | } else { | ||
794 | URI_FUNC(StopSyntax)(state, first - 1); | ||
795 | } | ||
796 | return NULL; | ||
797 | } | ||
798 | |||
799 | /* Copy first IPv4 octet */ | ||
800 | state->uri->hostData.ip6->data[16 - 4] = uriGetOctetValue(digitHistory, digitCount); | ||
801 | digitCount = 0; | ||
802 | |||
803 | /* Switch over to IPv4 loop */ | ||
804 | ip4OctetsDone = 1; | ||
805 | walking = 0; | ||
806 | break; | ||
807 | |||
808 | case _UT(']'): | ||
809 | /* Too little quads? */ | ||
810 | if (!zipperEver && !((quadsDone == 7) && (digitCount > 0))) { | ||
811 | URI_FUNC(StopSyntax)(state, first); | ||
812 | return NULL; | ||
813 | } | ||
814 | |||
815 | if (digitCount > 0) { | ||
816 | if (zipperEver) { | ||
817 | uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount); | ||
818 | quadsAfterZipperCount++; | ||
819 | } else { | ||
820 | uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone); | ||
821 | } | ||
822 | /* | ||
823 | quadsDone++; | ||
824 | digitCount = 0; | ||
825 | */ | ||
826 | } | ||
827 | |||
828 | /* Copy missing quads to the end */ | ||
829 | memcpy(state->uri->hostData.ip6->data + 16 - 2 * quadsAfterZipperCount, | ||
830 | quadsAfterZipper, 2 * quadsAfterZipperCount); | ||
831 | |||
832 | state->uri->hostText.afterLast = first; /* HOST END */ | ||
833 | return first + 1; /* Fine */ | ||
834 | |||
835 | default: | ||
836 | URI_FUNC(StopSyntax)(state, first); | ||
837 | return NULL; | ||
838 | } | ||
839 | first++; | ||
840 | |||
841 | if (first >= afterLast) { | ||
842 | URI_FUNC(StopSyntax)(state, first); | ||
843 | return NULL; /* No ']' yet */ | ||
844 | } | ||
845 | } while (walking); | ||
846 | } | ||
847 | } | ||
848 | } | ||
849 | |||
850 | |||
851 | |||
852 | /* | ||
853 | * [mustBeSegmentNzNc]->[pctEncoded][mustBeSegmentNzNc] | ||
854 | * [mustBeSegmentNzNc]->[subDelims][mustBeSegmentNzNc] | ||
855 | * [mustBeSegmentNzNc]->[unreserved][mustBeSegmentNzNc] | ||
856 | * [mustBeSegmentNzNc]->[uriTail] // can take <NULL> | ||
857 | * [mustBeSegmentNzNc]-></>[segment][zeroMoreSlashSegs][uriTail] | ||
858 | * [mustBeSegmentNzNc]-><@>[mustBeSegmentNzNc] | ||
859 | */ | ||
860 | static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
861 | if (first >= afterLast) { | ||
862 | if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */ | ||
863 | URI_FUNC(StopMalloc)(state); | ||
864 | return NULL; | ||
865 | } | ||
866 | state->uri->scheme.first = NULL; /* Not a scheme, reset */ | ||
867 | return afterLast; | ||
868 | } | ||
869 | |||
870 | switch (*first) { | ||
871 | case _UT('%'): | ||
872 | { | ||
873 | const URI_CHAR * const afterPctEncoded | ||
874 | = URI_FUNC(ParsePctEncoded)(state, first, afterLast); | ||
875 | if (afterPctEncoded == NULL) { | ||
876 | return NULL; | ||
877 | } | ||
878 | return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast); | ||
879 | } | ||
880 | |||
881 | case _UT('@'): | ||
882 | case _UT('!'): | ||
883 | case _UT('$'): | ||
884 | case _UT('&'): | ||
885 | case _UT('('): | ||
886 | case _UT(')'): | ||
887 | case _UT('*'): | ||
888 | case _UT(','): | ||
889 | case _UT(';'): | ||
890 | case _UT('\''): | ||
891 | case _UT('+'): | ||
892 | case _UT('='): | ||
893 | case _UT('-'): | ||
894 | case _UT('.'): | ||
895 | case _UT('_'): | ||
896 | case _UT('~'): | ||
897 | case URI_SET_DIGIT: | ||
898 | case URI_SET_ALPHA: | ||
899 | return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast); | ||
900 | |||
901 | case _UT('/'): | ||
902 | { | ||
903 | const URI_CHAR * afterZeroMoreSlashSegs; | ||
904 | const URI_CHAR * afterSegment; | ||
905 | if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */ | ||
906 | URI_FUNC(StopMalloc)(state); | ||
907 | return NULL; | ||
908 | } | ||
909 | state->uri->scheme.first = NULL; /* Not a scheme, reset */ | ||
910 | afterSegment = URI_FUNC(ParseSegment)(state, first + 1, afterLast); | ||
911 | if (afterSegment == NULL) { | ||
912 | return NULL; | ||
913 | } | ||
914 | if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */ | ||
915 | URI_FUNC(StopMalloc)(state); | ||
916 | return NULL; | ||
917 | } | ||
918 | afterZeroMoreSlashSegs | ||
919 | = URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast); | ||
920 | if (afterZeroMoreSlashSegs == NULL) { | ||
921 | return NULL; | ||
922 | } | ||
923 | return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast); | ||
924 | } | ||
925 | |||
926 | default: | ||
927 | if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */ | ||
928 | URI_FUNC(StopMalloc)(state); | ||
929 | return NULL; | ||
930 | } | ||
931 | state->uri->scheme.first = NULL; /* Not a scheme, reset */ | ||
932 | return URI_FUNC(ParseUriTail)(state, first, afterLast); | ||
933 | } | ||
934 | } | ||
935 | |||
936 | |||
937 | |||
938 | /* | ||
939 | * [ownHost]-><[>[ipLit2][authorityTwo] | ||
940 | * [ownHost]->[ownHost2] // can take <NULL> | ||
941 | */ | ||
942 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
943 | if (first >= afterLast) { | ||
944 | return afterLast; | ||
945 | } | ||
946 | |||
947 | switch (*first) { | ||
948 | case _UT('['): | ||
949 | { | ||
950 | const URI_CHAR * const afterIpLit2 | ||
951 | = URI_FUNC(ParseIpLit2)(state, first + 1, afterLast); | ||
952 | if (afterIpLit2 == NULL) { | ||
953 | return NULL; | ||
954 | } | ||
955 | state->uri->hostText.first = first + 1; /* HOST BEGIN */ | ||
956 | return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast); | ||
957 | } | ||
958 | |||
959 | default: | ||
960 | return URI_FUNC(ParseOwnHost2)(state, first, afterLast); | ||
961 | } | ||
962 | } | ||
963 | |||
964 | |||
965 | |||
966 | static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first) { | ||
967 | state->uri->hostText.afterLast = first; /* HOST END */ | ||
968 | |||
969 | /* Valid IPv4 or just a regname? */ | ||
970 | state->uri->hostData.ip4 = malloc(1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ | ||
971 | if (state->uri->hostData.ip4 == NULL) { | ||
972 | return URI_FALSE; /* Raises malloc error */ | ||
973 | } | ||
974 | if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, | ||
975 | state->uri->hostText.first, state->uri->hostText.afterLast)) { | ||
976 | /* Not IPv4 */ | ||
977 | free(state->uri->hostData.ip4); | ||
978 | state->uri->hostData.ip4 = NULL; | ||
979 | } | ||
980 | return URI_TRUE; /* Success */ | ||
981 | } | ||
982 | |||
983 | |||
984 | |||
985 | /* | ||
986 | * [ownHost2]->[authorityTwo] // can take <NULL> | ||
987 | * [ownHost2]->[pctSubUnres][ownHost2] | ||
988 | */ | ||
989 | static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
990 | if (first >= afterLast) { | ||
991 | if (!URI_FUNC(OnExitOwnHost2)(state, first)) { | ||
992 | URI_FUNC(StopMalloc)(state); | ||
993 | return NULL; | ||
994 | } | ||
995 | return afterLast; | ||
996 | } | ||
997 | |||
998 | switch (*first) { | ||
999 | case _UT('!'): | ||
1000 | case _UT('$'): | ||
1001 | case _UT('%'): | ||
1002 | case _UT('&'): | ||
1003 | case _UT('('): | ||
1004 | case _UT(')'): | ||
1005 | case _UT('-'): | ||
1006 | case _UT('*'): | ||
1007 | case _UT(','): | ||
1008 | case _UT('.'): | ||
1009 | case _UT(';'): | ||
1010 | case _UT('\''): | ||
1011 | case _UT('_'): | ||
1012 | case _UT('~'): | ||
1013 | case _UT('+'): | ||
1014 | case _UT('='): | ||
1015 | case URI_SET_DIGIT: | ||
1016 | case URI_SET_ALPHA: | ||
1017 | { | ||
1018 | const URI_CHAR * const afterPctSubUnres | ||
1019 | = URI_FUNC(ParsePctSubUnres)(state, first, afterLast); | ||
1020 | if (afterPctSubUnres == NULL) { | ||
1021 | return NULL; | ||
1022 | } | ||
1023 | return URI_FUNC(ParseOwnHost2)(state, afterPctSubUnres, afterLast); | ||
1024 | } | ||
1025 | |||
1026 | default: | ||
1027 | if (!URI_FUNC(OnExitOwnHost2)(state, first)) { | ||
1028 | URI_FUNC(StopMalloc)(state); | ||
1029 | return NULL; | ||
1030 | } | ||
1031 | return URI_FUNC(ParseAuthorityTwo)(state, first, afterLast); | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | |||
1037 | static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first) { | ||
1038 | state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */ | ||
1039 | state->uri->userInfo.first = NULL; /* Not a userInfo, reset */ | ||
1040 | state->uri->hostText.afterLast = first; /* HOST END */ | ||
1041 | |||
1042 | /* Valid IPv4 or just a regname? */ | ||
1043 | state->uri->hostData.ip4 = malloc(1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ | ||
1044 | if (state->uri->hostData.ip4 == NULL) { | ||
1045 | return URI_FALSE; /* Raises malloc error */ | ||
1046 | } | ||
1047 | if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, | ||
1048 | state->uri->hostText.first, state->uri->hostText.afterLast)) { | ||
1049 | /* Not IPv4 */ | ||
1050 | free(state->uri->hostData.ip4); | ||
1051 | state->uri->hostData.ip4 = NULL; | ||
1052 | } | ||
1053 | return URI_TRUE; /* Success */ | ||
1054 | } | ||
1055 | |||
1056 | |||
1057 | |||
1058 | /* | ||
1059 | * [ownHostUserInfo]->[ownHostUserInfoNz] | ||
1060 | * [ownHostUserInfo]-><NULL> | ||
1061 | */ | ||
1062 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1063 | if (first >= afterLast) { | ||
1064 | if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) { | ||
1065 | URI_FUNC(StopMalloc)(state); | ||
1066 | return NULL; | ||
1067 | } | ||
1068 | return afterLast; | ||
1069 | } | ||
1070 | |||
1071 | switch (*first) { | ||
1072 | case _UT('!'): | ||
1073 | case _UT('$'): | ||
1074 | case _UT('%'): | ||
1075 | case _UT('&'): | ||
1076 | case _UT('('): | ||
1077 | case _UT(')'): | ||
1078 | case _UT('-'): | ||
1079 | case _UT('*'): | ||
1080 | case _UT(','): | ||
1081 | case _UT('.'): | ||
1082 | case _UT(':'): | ||
1083 | case _UT(';'): | ||
1084 | case _UT('@'): | ||
1085 | case _UT('\''): | ||
1086 | case _UT('_'): | ||
1087 | case _UT('~'): | ||
1088 | case _UT('+'): | ||
1089 | case _UT('='): | ||
1090 | case URI_SET_DIGIT: | ||
1091 | case URI_SET_ALPHA: | ||
1092 | return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast); | ||
1093 | |||
1094 | default: | ||
1095 | if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) { | ||
1096 | URI_FUNC(StopMalloc)(state); | ||
1097 | return NULL; | ||
1098 | } | ||
1099 | return first; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | |||
1105 | /* | ||
1106 | * [ownHostUserInfoNz]->[pctSubUnres][ownHostUserInfo] | ||
1107 | * [ownHostUserInfoNz]-><:>[ownPortUserInfo] | ||
1108 | * [ownHostUserInfoNz]-><@>[ownHost] | ||
1109 | */ | ||
1110 | static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1111 | if (first >= afterLast) { | ||
1112 | URI_FUNC(StopSyntax)(state, first); | ||
1113 | return NULL; | ||
1114 | } | ||
1115 | |||
1116 | switch (*first) { | ||
1117 | case _UT('!'): | ||
1118 | case _UT('$'): | ||
1119 | case _UT('%'): | ||
1120 | case _UT('&'): | ||
1121 | case _UT('('): | ||
1122 | case _UT(')'): | ||
1123 | case _UT('-'): | ||
1124 | case _UT('*'): | ||
1125 | case _UT(','): | ||
1126 | case _UT('.'): | ||
1127 | case _UT(';'): | ||
1128 | case _UT('\''): | ||
1129 | case _UT('_'): | ||
1130 | case _UT('~'): | ||
1131 | case _UT('+'): | ||
1132 | case _UT('='): | ||
1133 | case URI_SET_DIGIT: | ||
1134 | case URI_SET_ALPHA: | ||
1135 | { | ||
1136 | const URI_CHAR * const afterPctSubUnres | ||
1137 | = URI_FUNC(ParsePctSubUnres)(state, first, afterLast); | ||
1138 | if (afterPctSubUnres == NULL) { | ||
1139 | return NULL; | ||
1140 | } | ||
1141 | return URI_FUNC(ParseOwnHostUserInfo)(state, afterPctSubUnres, afterLast); | ||
1142 | } | ||
1143 | |||
1144 | case _UT(':'): | ||
1145 | state->uri->hostText.afterLast = first; /* HOST END */ | ||
1146 | state->uri->portText.first = first + 1; /* PORT BEGIN */ | ||
1147 | return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast); | ||
1148 | |||
1149 | case _UT('@'): | ||
1150 | state->uri->userInfo.afterLast = first; /* USERINFO END */ | ||
1151 | state->uri->hostText.first = first + 1; /* HOST BEGIN */ | ||
1152 | return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast); | ||
1153 | |||
1154 | default: | ||
1155 | URI_FUNC(StopSyntax)(state, first); | ||
1156 | return NULL; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | |||
1161 | |||
1162 | static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first) { | ||
1163 | state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */ | ||
1164 | state->uri->userInfo.first = NULL; /* Not a userInfo, reset */ | ||
1165 | state->uri->portText.afterLast = first; /* PORT END */ | ||
1166 | |||
1167 | /* Valid IPv4 or just a regname? */ | ||
1168 | state->uri->hostData.ip4 = malloc(1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ | ||
1169 | if (state->uri->hostData.ip4 == NULL) { | ||
1170 | return URI_FALSE; /* Raises malloc error */ | ||
1171 | } | ||
1172 | if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, | ||
1173 | state->uri->hostText.first, state->uri->hostText.afterLast)) { | ||
1174 | /* Not IPv4 */ | ||
1175 | free(state->uri->hostData.ip4); | ||
1176 | state->uri->hostData.ip4 = NULL; | ||
1177 | } | ||
1178 | return URI_TRUE; /* Success */ | ||
1179 | } | ||
1180 | |||
1181 | |||
1182 | |||
1183 | /* | ||
1184 | * [ownPortUserInfo]->[ALPHA][ownUserInfo] | ||
1185 | * [ownPortUserInfo]->[DIGIT][ownPortUserInfo] | ||
1186 | * [ownPortUserInfo]-><.>[ownUserInfo] | ||
1187 | * [ownPortUserInfo]-><_>[ownUserInfo] | ||
1188 | * [ownPortUserInfo]-><~>[ownUserInfo] | ||
1189 | * [ownPortUserInfo]-><->[ownUserInfo] | ||
1190 | * [ownPortUserInfo]->[subDelims][ownUserInfo] | ||
1191 | * [ownPortUserInfo]->[pctEncoded][ownUserInfo] | ||
1192 | * [ownPortUserInfo]-><:>[ownUserInfo] | ||
1193 | * [ownPortUserInfo]-><@>[ownHost] | ||
1194 | * [ownPortUserInfo]-><NULL> | ||
1195 | */ | ||
1196 | static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1197 | if (first >= afterLast) { | ||
1198 | if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first)) { | ||
1199 | URI_FUNC(StopMalloc)(state); | ||
1200 | return NULL; | ||
1201 | } | ||
1202 | return afterLast; | ||
1203 | } | ||
1204 | |||
1205 | switch (*first) { | ||
1206 | /* begin sub-delims */ | ||
1207 | case _UT('!'): | ||
1208 | case _UT('$'): | ||
1209 | case _UT('&'): | ||
1210 | case _UT('\''): | ||
1211 | case _UT('('): | ||
1212 | case _UT(')'): | ||
1213 | case _UT('*'): | ||
1214 | case _UT('+'): | ||
1215 | case _UT(','): | ||
1216 | case _UT(';'): | ||
1217 | case _UT('='): | ||
1218 | /* end sub-delims */ | ||
1219 | /* begin unreserved (except alpha and digit) */ | ||
1220 | case _UT('-'): | ||
1221 | case _UT('.'): | ||
1222 | case _UT('_'): | ||
1223 | case _UT('~'): | ||
1224 | /* end unreserved (except alpha and digit) */ | ||
1225 | case _UT(':'): | ||
1226 | case URI_SET_ALPHA: | ||
1227 | state->uri->hostText.afterLast = NULL; /* Not a host, reset */ | ||
1228 | state->uri->portText.first = NULL; /* Not a port, reset */ | ||
1229 | return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast); | ||
1230 | |||
1231 | case URI_SET_DIGIT: | ||
1232 | return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast); | ||
1233 | |||
1234 | case _UT('%'): | ||
1235 | state->uri->portText.first = NULL; /* Not a port, reset */ | ||
1236 | { | ||
1237 | const URI_CHAR * const afterPct | ||
1238 | = URI_FUNC(ParsePctEncoded)(state, first, afterLast); | ||
1239 | if (afterPct == NULL) { | ||
1240 | return NULL; | ||
1241 | } | ||
1242 | return URI_FUNC(ParseOwnUserInfo)(state, afterPct, afterLast); | ||
1243 | } | ||
1244 | |||
1245 | case _UT('@'): | ||
1246 | state->uri->hostText.afterLast = NULL; /* Not a host, reset */ | ||
1247 | state->uri->portText.first = NULL; /* Not a port, reset */ | ||
1248 | state->uri->userInfo.afterLast = first; /* USERINFO END */ | ||
1249 | state->uri->hostText.first = first + 1; /* HOST BEGIN */ | ||
1250 | return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast); | ||
1251 | |||
1252 | default: | ||
1253 | if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first)) { | ||
1254 | URI_FUNC(StopMalloc)(state); | ||
1255 | return NULL; | ||
1256 | } | ||
1257 | return first; | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | |||
1262 | |||
1263 | /* | ||
1264 | * [ownUserInfo]->[pctSubUnres][ownUserInfo] | ||
1265 | * [ownUserInfo]-><:>[ownUserInfo] | ||
1266 | * [ownUserInfo]-><@>[ownHost] | ||
1267 | */ | ||
1268 | static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1269 | if (first >= afterLast) { | ||
1270 | URI_FUNC(StopSyntax)(state, first); | ||
1271 | return NULL; | ||
1272 | } | ||
1273 | |||
1274 | switch (*first) { | ||
1275 | case _UT('!'): | ||
1276 | case _UT('$'): | ||
1277 | case _UT('%'): | ||
1278 | case _UT('&'): | ||
1279 | case _UT('('): | ||
1280 | case _UT(')'): | ||
1281 | case _UT('-'): | ||
1282 | case _UT('*'): | ||
1283 | case _UT(','): | ||
1284 | case _UT('.'): | ||
1285 | case _UT(';'): | ||
1286 | case _UT('\''): | ||
1287 | case _UT('_'): | ||
1288 | case _UT('~'): | ||
1289 | case _UT('+'): | ||
1290 | case _UT('='): | ||
1291 | case URI_SET_DIGIT: | ||
1292 | case URI_SET_ALPHA: | ||
1293 | { | ||
1294 | const URI_CHAR * const afterPctSubUnres | ||
1295 | = URI_FUNC(ParsePctSubUnres)(state, first, afterLast); | ||
1296 | if (afterPctSubUnres == NULL) { | ||
1297 | return NULL; | ||
1298 | } | ||
1299 | return URI_FUNC(ParseOwnUserInfo)(state, afterPctSubUnres, afterLast); | ||
1300 | } | ||
1301 | |||
1302 | case _UT(':'): | ||
1303 | return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast); | ||
1304 | |||
1305 | case _UT('@'): | ||
1306 | /* SURE */ | ||
1307 | state->uri->userInfo.afterLast = first; /* USERINFO END */ | ||
1308 | state->uri->hostText.first = first + 1; /* HOST BEGIN */ | ||
1309 | return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast); | ||
1310 | |||
1311 | default: | ||
1312 | URI_FUNC(StopSyntax)(state, first); | ||
1313 | return NULL; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | |||
1318 | |||
1319 | static URI_INLINE void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state) { | ||
1320 | state->uri->absolutePath = URI_TRUE; | ||
1321 | } | ||
1322 | |||
1323 | |||
1324 | |||
1325 | /* | ||
1326 | * [partHelperTwo]->[pathAbsNoLeadSlash] // can take <NULL> | ||
1327 | * [partHelperTwo]-></>[authority][pathAbsEmpty] | ||
1328 | */ | ||
1329 | static URI_INLINE const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1330 | if (first >= afterLast) { | ||
1331 | URI_FUNC(OnExitPartHelperTwo)(state); | ||
1332 | return afterLast; | ||
1333 | } | ||
1334 | |||
1335 | switch (*first) { | ||
1336 | case _UT('/'): | ||
1337 | { | ||
1338 | const URI_CHAR * const afterAuthority | ||
1339 | = URI_FUNC(ParseAuthority)(state, first + 1, afterLast); | ||
1340 | const URI_CHAR * afterPathAbsEmpty; | ||
1341 | if (afterAuthority == NULL) { | ||
1342 | return NULL; | ||
1343 | } | ||
1344 | afterPathAbsEmpty = URI_FUNC(ParsePathAbsEmpty)(state, afterAuthority, afterLast); | ||
1345 | |||
1346 | URI_FUNC(FixEmptyTrailSegment)(state->uri); | ||
1347 | |||
1348 | return afterPathAbsEmpty; | ||
1349 | } | ||
1350 | |||
1351 | default: | ||
1352 | URI_FUNC(OnExitPartHelperTwo)(state); | ||
1353 | return URI_FUNC(ParsePathAbsNoLeadSlash)(state, first, afterLast); | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | |||
1359 | /* | ||
1360 | * [pathAbsEmpty]-></>[segment][pathAbsEmpty] | ||
1361 | * [pathAbsEmpty]-><NULL> | ||
1362 | */ | ||
1363 | static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1364 | if (first >= afterLast) { | ||
1365 | return afterLast; | ||
1366 | } | ||
1367 | |||
1368 | switch (*first) { | ||
1369 | case _UT('/'): | ||
1370 | { | ||
1371 | const URI_CHAR * const afterSegment | ||
1372 | = URI_FUNC(ParseSegment)(state, first + 1, afterLast); | ||
1373 | if (afterSegment == NULL) { | ||
1374 | return NULL; | ||
1375 | } | ||
1376 | if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */ | ||
1377 | URI_FUNC(StopMalloc)(state); | ||
1378 | return NULL; | ||
1379 | } | ||
1380 | return URI_FUNC(ParsePathAbsEmpty)(state, afterSegment, afterLast); | ||
1381 | } | ||
1382 | |||
1383 | default: | ||
1384 | return first; | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | |||
1389 | |||
1390 | /* | ||
1391 | * [pathAbsNoLeadSlash]->[segmentNz][zeroMoreSlashSegs] | ||
1392 | * [pathAbsNoLeadSlash]-><NULL> | ||
1393 | */ | ||
1394 | static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1395 | if (first >= afterLast) { | ||
1396 | return afterLast; | ||
1397 | } | ||
1398 | |||
1399 | switch (*first) { | ||
1400 | case _UT('!'): | ||
1401 | case _UT('$'): | ||
1402 | case _UT('%'): | ||
1403 | case _UT('&'): | ||
1404 | case _UT('('): | ||
1405 | case _UT(')'): | ||
1406 | case _UT('-'): | ||
1407 | case _UT('*'): | ||
1408 | case _UT(','): | ||
1409 | case _UT('.'): | ||
1410 | case _UT(':'): | ||
1411 | case _UT(';'): | ||
1412 | case _UT('@'): | ||
1413 | case _UT('\''): | ||
1414 | case _UT('_'): | ||
1415 | case _UT('~'): | ||
1416 | case _UT('+'): | ||
1417 | case _UT('='): | ||
1418 | case URI_SET_DIGIT: | ||
1419 | case URI_SET_ALPHA: | ||
1420 | { | ||
1421 | const URI_CHAR * const afterSegmentNz | ||
1422 | = URI_FUNC(ParseSegmentNz)(state, first, afterLast); | ||
1423 | if (afterSegmentNz == NULL) { | ||
1424 | return NULL; | ||
1425 | } | ||
1426 | if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz)) { /* SEGMENT BOTH */ | ||
1427 | URI_FUNC(StopMalloc)(state); | ||
1428 | return NULL; | ||
1429 | } | ||
1430 | return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast); | ||
1431 | } | ||
1432 | |||
1433 | default: | ||
1434 | return first; | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | |||
1439 | |||
1440 | /* | ||
1441 | * [pathRootless]->[segmentNz][zeroMoreSlashSegs] | ||
1442 | */ | ||
1443 | static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1444 | const URI_CHAR * const afterSegmentNz | ||
1445 | = URI_FUNC(ParseSegmentNz)(state, first, afterLast); | ||
1446 | if (afterSegmentNz == NULL) { | ||
1447 | return NULL; | ||
1448 | } else { | ||
1449 | if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz)) { /* SEGMENT BOTH */ | ||
1450 | URI_FUNC(StopMalloc)(state); | ||
1451 | return NULL; | ||
1452 | } | ||
1453 | } | ||
1454 | return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast); | ||
1455 | } | ||
1456 | |||
1457 | |||
1458 | |||
1459 | /* | ||
1460 | * [pchar]->[pctEncoded] | ||
1461 | * [pchar]->[subDelims] | ||
1462 | * [pchar]->[unreserved] | ||
1463 | * [pchar]-><:> | ||
1464 | * [pchar]-><@> | ||
1465 | */ | ||
1466 | static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1467 | if (first >= afterLast) { | ||
1468 | URI_FUNC(StopSyntax)(state, first); | ||
1469 | return NULL; | ||
1470 | } | ||
1471 | |||
1472 | switch (*first) { | ||
1473 | case _UT('%'): | ||
1474 | return URI_FUNC(ParsePctEncoded)(state, first, afterLast); | ||
1475 | |||
1476 | case _UT(':'): | ||
1477 | case _UT('@'): | ||
1478 | case _UT('!'): | ||
1479 | case _UT('$'): | ||
1480 | case _UT('&'): | ||
1481 | case _UT('('): | ||
1482 | case _UT(')'): | ||
1483 | case _UT('*'): | ||
1484 | case _UT(','): | ||
1485 | case _UT(';'): | ||
1486 | case _UT('\''): | ||
1487 | case _UT('+'): | ||
1488 | case _UT('='): | ||
1489 | case _UT('-'): | ||
1490 | case _UT('.'): | ||
1491 | case _UT('_'): | ||
1492 | case _UT('~'): | ||
1493 | case URI_SET_DIGIT: | ||
1494 | case URI_SET_ALPHA: | ||
1495 | return first + 1; | ||
1496 | |||
1497 | default: | ||
1498 | URI_FUNC(StopSyntax)(state, first); | ||
1499 | return NULL; | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | |||
1504 | |||
1505 | /* | ||
1506 | * [pctEncoded]-><%>[HEXDIG][HEXDIG] | ||
1507 | */ | ||
1508 | static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1509 | if (first >= afterLast) { | ||
1510 | URI_FUNC(StopSyntax)(state, first); | ||
1511 | return NULL; | ||
1512 | } | ||
1513 | |||
1514 | /* | ||
1515 | First character has already been | ||
1516 | checked before entering this rule. | ||
1517 | |||
1518 | switch (*first) { | ||
1519 | case _UT('%'): | ||
1520 | */ | ||
1521 | if (first + 1 >= afterLast) { | ||
1522 | URI_FUNC(StopSyntax)(state, first + 1); | ||
1523 | return NULL; | ||
1524 | } | ||
1525 | |||
1526 | switch (first[1]) { | ||
1527 | case URI_SET_HEXDIG: | ||
1528 | if (first + 2 >= afterLast) { | ||
1529 | URI_FUNC(StopSyntax)(state, first + 2); | ||
1530 | return NULL; | ||
1531 | } | ||
1532 | |||
1533 | switch (first[2]) { | ||
1534 | case URI_SET_HEXDIG: | ||
1535 | return first + 3; | ||
1536 | |||
1537 | default: | ||
1538 | URI_FUNC(StopSyntax)(state, first + 2); | ||
1539 | return NULL; | ||
1540 | } | ||
1541 | |||
1542 | default: | ||
1543 | URI_FUNC(StopSyntax)(state, first + 1); | ||
1544 | return NULL; | ||
1545 | } | ||
1546 | |||
1547 | /* | ||
1548 | default: | ||
1549 | URI_FUNC(StopSyntax)(state, first); | ||
1550 | return NULL; | ||
1551 | } | ||
1552 | */ | ||
1553 | } | ||
1554 | |||
1555 | |||
1556 | |||
1557 | /* | ||
1558 | * [pctSubUnres]->[pctEncoded] | ||
1559 | * [pctSubUnres]->[subDelims] | ||
1560 | * [pctSubUnres]->[unreserved] | ||
1561 | */ | ||
1562 | static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1563 | if (first >= afterLast) { | ||
1564 | URI_FUNC(StopSyntax)(state, first); | ||
1565 | return NULL; | ||
1566 | } | ||
1567 | |||
1568 | switch (*first) { | ||
1569 | case _UT('%'): | ||
1570 | return URI_FUNC(ParsePctEncoded)(state, first, afterLast); | ||
1571 | |||
1572 | case _UT('!'): | ||
1573 | case _UT('$'): | ||
1574 | case _UT('&'): | ||
1575 | case _UT('('): | ||
1576 | case _UT(')'): | ||
1577 | case _UT('*'): | ||
1578 | case _UT(','): | ||
1579 | case _UT(';'): | ||
1580 | case _UT('\''): | ||
1581 | case _UT('+'): | ||
1582 | case _UT('='): | ||
1583 | case _UT('-'): | ||
1584 | case _UT('.'): | ||
1585 | case _UT('_'): | ||
1586 | case _UT('~'): | ||
1587 | case URI_SET_DIGIT: | ||
1588 | case URI_SET_ALPHA: | ||
1589 | return first + 1; | ||
1590 | |||
1591 | default: | ||
1592 | URI_FUNC(StopSyntax)(state, first); | ||
1593 | return NULL; | ||
1594 | } | ||
1595 | } | ||
1596 | |||
1597 | |||
1598 | |||
1599 | /* | ||
1600 | * [port]->[DIGIT][port] | ||
1601 | * [port]-><NULL> | ||
1602 | */ | ||
1603 | static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1604 | if (first >= afterLast) { | ||
1605 | return afterLast; | ||
1606 | } | ||
1607 | |||
1608 | switch (*first) { | ||
1609 | case URI_SET_DIGIT: | ||
1610 | return URI_FUNC(ParsePort)(state, first + 1, afterLast); | ||
1611 | |||
1612 | default: | ||
1613 | return first; | ||
1614 | } | ||
1615 | } | ||
1616 | |||
1617 | |||
1618 | |||
1619 | /* | ||
1620 | * [queryFrag]->[pchar][queryFrag] | ||
1621 | * [queryFrag]-></>[queryFrag] | ||
1622 | * [queryFrag]-><?>[queryFrag] | ||
1623 | * [queryFrag]-><NULL> | ||
1624 | */ | ||
1625 | static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1626 | if (first >= afterLast) { | ||
1627 | return afterLast; | ||
1628 | } | ||
1629 | |||
1630 | switch (*first) { | ||
1631 | case _UT('!'): | ||
1632 | case _UT('$'): | ||
1633 | case _UT('%'): | ||
1634 | case _UT('&'): | ||
1635 | case _UT('('): | ||
1636 | case _UT(')'): | ||
1637 | case _UT('-'): | ||
1638 | case _UT('*'): | ||
1639 | case _UT(','): | ||
1640 | case _UT('.'): | ||
1641 | case _UT(':'): | ||
1642 | case _UT(';'): | ||
1643 | case _UT('@'): | ||
1644 | case _UT('\''): | ||
1645 | case _UT('_'): | ||
1646 | case _UT('~'): | ||
1647 | case _UT('+'): | ||
1648 | case _UT('='): | ||
1649 | case URI_SET_DIGIT: | ||
1650 | case URI_SET_ALPHA: | ||
1651 | { | ||
1652 | const URI_CHAR * const afterPchar | ||
1653 | = URI_FUNC(ParsePchar)(state, first, afterLast); | ||
1654 | if (afterPchar == NULL) { | ||
1655 | return NULL; | ||
1656 | } | ||
1657 | return URI_FUNC(ParseQueryFrag)(state, afterPchar, afterLast); | ||
1658 | } | ||
1659 | |||
1660 | case _UT('/'): | ||
1661 | case _UT('?'): | ||
1662 | return URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast); | ||
1663 | |||
1664 | default: | ||
1665 | return first; | ||
1666 | } | ||
1667 | } | ||
1668 | |||
1669 | |||
1670 | |||
1671 | /* | ||
1672 | * [segment]->[pchar][segment] | ||
1673 | * [segment]-><NULL> | ||
1674 | */ | ||
1675 | static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1676 | if (first >= afterLast) { | ||
1677 | return afterLast; | ||
1678 | } | ||
1679 | |||
1680 | switch (*first) { | ||
1681 | case _UT('!'): | ||
1682 | case _UT('$'): | ||
1683 | case _UT('%'): | ||
1684 | case _UT('&'): | ||
1685 | case _UT('('): | ||
1686 | case _UT(')'): | ||
1687 | case _UT('-'): | ||
1688 | case _UT('*'): | ||
1689 | case _UT(','): | ||
1690 | case _UT('.'): | ||
1691 | case _UT(':'): | ||
1692 | case _UT(';'): | ||
1693 | case _UT('@'): | ||
1694 | case _UT('\''): | ||
1695 | case _UT('_'): | ||
1696 | case _UT('~'): | ||
1697 | case _UT('+'): | ||
1698 | case _UT('='): | ||
1699 | case URI_SET_DIGIT: | ||
1700 | case URI_SET_ALPHA: | ||
1701 | { | ||
1702 | const URI_CHAR * const afterPchar | ||
1703 | = URI_FUNC(ParsePchar)(state, first, afterLast); | ||
1704 | if (afterPchar == NULL) { | ||
1705 | return NULL; | ||
1706 | } | ||
1707 | return URI_FUNC(ParseSegment)(state, afterPchar, afterLast); | ||
1708 | } | ||
1709 | |||
1710 | default: | ||
1711 | return first; | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | |||
1716 | |||
1717 | /* | ||
1718 | * [segmentNz]->[pchar][segment] | ||
1719 | */ | ||
1720 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1721 | const URI_CHAR * const afterPchar | ||
1722 | = URI_FUNC(ParsePchar)(state, first, afterLast); | ||
1723 | if (afterPchar == NULL) { | ||
1724 | return NULL; | ||
1725 | } | ||
1726 | return URI_FUNC(ParseSegment)(state, afterPchar, afterLast); | ||
1727 | } | ||
1728 | |||
1729 | |||
1730 | |||
1731 | static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first) { | ||
1732 | if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */ | ||
1733 | return URI_FALSE; /* Raises malloc error*/ | ||
1734 | } | ||
1735 | state->uri->scheme.first = NULL; /* Not a scheme, reset */ | ||
1736 | return URI_TRUE; /* Success */ | ||
1737 | } | ||
1738 | |||
1739 | |||
1740 | |||
1741 | /* | ||
1742 | * [segmentNzNcOrScheme2]->[ALPHA][segmentNzNcOrScheme2] | ||
1743 | * [segmentNzNcOrScheme2]->[DIGIT][segmentNzNcOrScheme2] | ||
1744 | * [segmentNzNcOrScheme2]->[pctEncoded][mustBeSegmentNzNc] | ||
1745 | * [segmentNzNcOrScheme2]->[uriTail] // can take <NULL> | ||
1746 | * [segmentNzNcOrScheme2]-><!>[mustBeSegmentNzNc] | ||
1747 | * [segmentNzNcOrScheme2]-><$>[mustBeSegmentNzNc] | ||
1748 | * [segmentNzNcOrScheme2]-><&>[mustBeSegmentNzNc] | ||
1749 | * [segmentNzNcOrScheme2]-><(>[mustBeSegmentNzNc] | ||
1750 | * [segmentNzNcOrScheme2]-><)>[mustBeSegmentNzNc] | ||
1751 | * [segmentNzNcOrScheme2]-><*>[mustBeSegmentNzNc] | ||
1752 | * [segmentNzNcOrScheme2]-><,>[mustBeSegmentNzNc] | ||
1753 | * [segmentNzNcOrScheme2]-><.>[segmentNzNcOrScheme2] | ||
1754 | * [segmentNzNcOrScheme2]-></>[segment][zeroMoreSlashSegs][uriTail] | ||
1755 | * [segmentNzNcOrScheme2]-><:>[hierPart][uriTail] | ||
1756 | * [segmentNzNcOrScheme2]-><;>[mustBeSegmentNzNc] | ||
1757 | * [segmentNzNcOrScheme2]-><@>[mustBeSegmentNzNc] | ||
1758 | * [segmentNzNcOrScheme2]-><_>[mustBeSegmentNzNc] | ||
1759 | * [segmentNzNcOrScheme2]-><~>[mustBeSegmentNzNc] | ||
1760 | * [segmentNzNcOrScheme2]-><+>[segmentNzNcOrScheme2] | ||
1761 | * [segmentNzNcOrScheme2]-><=>[mustBeSegmentNzNc] | ||
1762 | * [segmentNzNcOrScheme2]-><'>[mustBeSegmentNzNc] | ||
1763 | * [segmentNzNcOrScheme2]-><->[segmentNzNcOrScheme2] | ||
1764 | */ | ||
1765 | static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1766 | if (first >= afterLast) { | ||
1767 | if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first)) { | ||
1768 | URI_FUNC(StopMalloc)(state); | ||
1769 | return NULL; | ||
1770 | } | ||
1771 | return afterLast; | ||
1772 | } | ||
1773 | |||
1774 | switch (*first) { | ||
1775 | case _UT('.'): | ||
1776 | case _UT('+'): | ||
1777 | case _UT('-'): | ||
1778 | case URI_SET_ALPHA: | ||
1779 | case URI_SET_DIGIT: | ||
1780 | return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast); | ||
1781 | |||
1782 | case _UT('%'): | ||
1783 | { | ||
1784 | const URI_CHAR * const afterPctEncoded | ||
1785 | = URI_FUNC(ParsePctEncoded)(state, first, afterLast); | ||
1786 | if (afterPctEncoded == NULL) { | ||
1787 | return NULL; | ||
1788 | } | ||
1789 | return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast); | ||
1790 | } | ||
1791 | |||
1792 | case _UT('!'): | ||
1793 | case _UT('$'): | ||
1794 | case _UT('&'): | ||
1795 | case _UT('('): | ||
1796 | case _UT(')'): | ||
1797 | case _UT('*'): | ||
1798 | case _UT(','): | ||
1799 | case _UT(';'): | ||
1800 | case _UT('@'): | ||
1801 | case _UT('_'): | ||
1802 | case _UT('~'): | ||
1803 | case _UT('='): | ||
1804 | case _UT('\''): | ||
1805 | return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast); | ||
1806 | |||
1807 | case _UT('/'): | ||
1808 | { | ||
1809 | const URI_CHAR * afterZeroMoreSlashSegs; | ||
1810 | const URI_CHAR * const afterSegment | ||
1811 | = URI_FUNC(ParseSegment)(state, first + 1, afterLast); | ||
1812 | if (afterSegment == NULL) { | ||
1813 | return NULL; | ||
1814 | } | ||
1815 | if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */ | ||
1816 | URI_FUNC(StopMalloc)(state); | ||
1817 | return NULL; | ||
1818 | } | ||
1819 | state->uri->scheme.first = NULL; /* Not a scheme, reset */ | ||
1820 | if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */ | ||
1821 | URI_FUNC(StopMalloc)(state); | ||
1822 | return NULL; | ||
1823 | } | ||
1824 | afterZeroMoreSlashSegs | ||
1825 | = URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast); | ||
1826 | if (afterZeroMoreSlashSegs == NULL) { | ||
1827 | return NULL; | ||
1828 | } | ||
1829 | return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast); | ||
1830 | } | ||
1831 | |||
1832 | case _UT(':'): | ||
1833 | { | ||
1834 | const URI_CHAR * const afterHierPart | ||
1835 | = URI_FUNC(ParseHierPart)(state, first + 1, afterLast); | ||
1836 | state->uri->scheme.afterLast = first; /* SCHEME END */ | ||
1837 | if (afterHierPart == NULL) { | ||
1838 | return NULL; | ||
1839 | } | ||
1840 | return URI_FUNC(ParseUriTail)(state, afterHierPart, afterLast); | ||
1841 | } | ||
1842 | |||
1843 | default: | ||
1844 | if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first)) { | ||
1845 | URI_FUNC(StopMalloc)(state); | ||
1846 | return NULL; | ||
1847 | } | ||
1848 | return URI_FUNC(ParseUriTail)(state, first, afterLast); | ||
1849 | } | ||
1850 | } | ||
1851 | |||
1852 | |||
1853 | |||
1854 | /* | ||
1855 | * [uriReference]->[ALPHA][segmentNzNcOrScheme2] | ||
1856 | * [uriReference]->[DIGIT][mustBeSegmentNzNc] | ||
1857 | * [uriReference]->[pctEncoded][mustBeSegmentNzNc] | ||
1858 | * [uriReference]->[subDelims][mustBeSegmentNzNc] | ||
1859 | * [uriReference]->[uriTail] // can take <NULL> | ||
1860 | * [uriReference]-><.>[mustBeSegmentNzNc] | ||
1861 | * [uriReference]-></>[partHelperTwo][uriTail] | ||
1862 | * [uriReference]-><@>[mustBeSegmentNzNc] | ||
1863 | * [uriReference]-><_>[mustBeSegmentNzNc] | ||
1864 | * [uriReference]-><~>[mustBeSegmentNzNc] | ||
1865 | * [uriReference]-><->[mustBeSegmentNzNc] | ||
1866 | */ | ||
1867 | static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1868 | if (first >= afterLast) { | ||
1869 | return afterLast; | ||
1870 | } | ||
1871 | |||
1872 | switch (*first) { | ||
1873 | case URI_SET_ALPHA: | ||
1874 | state->uri->scheme.first = first; /* SCHEME BEGIN */ | ||
1875 | return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast); | ||
1876 | |||
1877 | case URI_SET_DIGIT: | ||
1878 | case _UT('!'): | ||
1879 | case _UT('$'): | ||
1880 | case _UT('&'): | ||
1881 | case _UT('('): | ||
1882 | case _UT(')'): | ||
1883 | case _UT('*'): | ||
1884 | case _UT(','): | ||
1885 | case _UT(';'): | ||
1886 | case _UT('\''): | ||
1887 | case _UT('+'): | ||
1888 | case _UT('='): | ||
1889 | case _UT('.'): | ||
1890 | case _UT('_'): | ||
1891 | case _UT('~'): | ||
1892 | case _UT('-'): | ||
1893 | case _UT('@'): | ||
1894 | state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */ | ||
1895 | return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast); | ||
1896 | |||
1897 | case _UT('%'): | ||
1898 | { | ||
1899 | const URI_CHAR * const afterPctEncoded | ||
1900 | = URI_FUNC(ParsePctEncoded)(state, first, afterLast); | ||
1901 | if (afterPctEncoded == NULL) { | ||
1902 | return NULL; | ||
1903 | } | ||
1904 | state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */ | ||
1905 | return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast); | ||
1906 | } | ||
1907 | |||
1908 | case _UT('/'): | ||
1909 | { | ||
1910 | const URI_CHAR * const afterPartHelperTwo | ||
1911 | = URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast); | ||
1912 | if (afterPartHelperTwo == NULL) { | ||
1913 | return NULL; | ||
1914 | } | ||
1915 | return URI_FUNC(ParseUriTail)(state, afterPartHelperTwo, afterLast); | ||
1916 | } | ||
1917 | |||
1918 | default: | ||
1919 | return URI_FUNC(ParseUriTail)(state, first, afterLast); | ||
1920 | } | ||
1921 | } | ||
1922 | |||
1923 | |||
1924 | |||
1925 | /* | ||
1926 | * [uriTail]-><#>[queryFrag] | ||
1927 | * [uriTail]-><?>[queryFrag][uriTailTwo] | ||
1928 | * [uriTail]-><NULL> | ||
1929 | */ | ||
1930 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1931 | if (first >= afterLast) { | ||
1932 | return afterLast; | ||
1933 | } | ||
1934 | |||
1935 | switch (*first) { | ||
1936 | case _UT('#'): | ||
1937 | { | ||
1938 | const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast); | ||
1939 | if (afterQueryFrag == NULL) { | ||
1940 | return NULL; | ||
1941 | } | ||
1942 | state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */ | ||
1943 | state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */ | ||
1944 | return afterQueryFrag; | ||
1945 | } | ||
1946 | |||
1947 | case _UT('?'): | ||
1948 | { | ||
1949 | const URI_CHAR * const afterQueryFrag | ||
1950 | = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast); | ||
1951 | if (afterQueryFrag == NULL) { | ||
1952 | return NULL; | ||
1953 | } | ||
1954 | state->uri->query.first = first + 1; /* QUERY BEGIN */ | ||
1955 | state->uri->query.afterLast = afterQueryFrag; /* QUERY END */ | ||
1956 | return URI_FUNC(ParseUriTailTwo)(state, afterQueryFrag, afterLast); | ||
1957 | } | ||
1958 | |||
1959 | default: | ||
1960 | return first; | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | |||
1965 | |||
1966 | /* | ||
1967 | * [uriTailTwo]-><#>[queryFrag] | ||
1968 | * [uriTailTwo]-><NULL> | ||
1969 | */ | ||
1970 | static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1971 | if (first >= afterLast) { | ||
1972 | return afterLast; | ||
1973 | } | ||
1974 | |||
1975 | switch (*first) { | ||
1976 | case _UT('#'): | ||
1977 | { | ||
1978 | const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast); | ||
1979 | if (afterQueryFrag == NULL) { | ||
1980 | return NULL; | ||
1981 | } | ||
1982 | state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */ | ||
1983 | state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */ | ||
1984 | return afterQueryFrag; | ||
1985 | } | ||
1986 | |||
1987 | default: | ||
1988 | return first; | ||
1989 | } | ||
1990 | } | ||
1991 | |||
1992 | |||
1993 | |||
1994 | /* | ||
1995 | * [zeroMoreSlashSegs]-></>[segment][zeroMoreSlashSegs] | ||
1996 | * [zeroMoreSlashSegs]-><NULL> | ||
1997 | */ | ||
1998 | static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
1999 | if (first >= afterLast) { | ||
2000 | return afterLast; | ||
2001 | } | ||
2002 | |||
2003 | switch (*first) { | ||
2004 | case _UT('/'): | ||
2005 | { | ||
2006 | const URI_CHAR * const afterSegment | ||
2007 | = URI_FUNC(ParseSegment)(state, first + 1, afterLast); | ||
2008 | if (afterSegment == NULL) { | ||
2009 | return NULL; | ||
2010 | } | ||
2011 | if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */ | ||
2012 | URI_FUNC(StopMalloc)(state); | ||
2013 | return NULL; | ||
2014 | } | ||
2015 | return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast); | ||
2016 | } | ||
2017 | |||
2018 | default: | ||
2019 | return first; | ||
2020 | } | ||
2021 | } | ||
2022 | |||
2023 | |||
2024 | |||
2025 | static URI_INLINE void URI_FUNC(ResetParserState)(URI_TYPE(ParserState) * state) { | ||
2026 | URI_TYPE(Uri) * const uriBackup = state->uri; | ||
2027 | memset(state, 0, sizeof(URI_TYPE(ParserState))); | ||
2028 | state->uri = uriBackup; | ||
2029 | } | ||
2030 | |||
2031 | |||
2032 | |||
2033 | static URI_INLINE UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
2034 | URI_TYPE(PathSegment) * segment = malloc(1 * sizeof(URI_TYPE(PathSegment))); | ||
2035 | if (segment == NULL) { | ||
2036 | return URI_FALSE; /* Raises malloc error */ | ||
2037 | } | ||
2038 | memset(segment, 0, sizeof(URI_TYPE(PathSegment))); | ||
2039 | if (first == afterLast) { | ||
2040 | segment->text.first = URI_FUNC(SafeToPointTo); | ||
2041 | segment->text.afterLast = URI_FUNC(SafeToPointTo); | ||
2042 | } else { | ||
2043 | segment->text.first = first; | ||
2044 | segment->text.afterLast = afterLast; | ||
2045 | } | ||
2046 | |||
2047 | /* First segment ever? */ | ||
2048 | if (state->uri->pathHead == NULL) { | ||
2049 | /* First segment ever, set head and tail */ | ||
2050 | state->uri->pathHead = segment; | ||
2051 | state->uri->pathTail = segment; | ||
2052 | } else { | ||
2053 | /* Append, update tail */ | ||
2054 | state->uri->pathTail->next = segment; | ||
2055 | state->uri->pathTail = segment; | ||
2056 | } | ||
2057 | |||
2058 | return URI_TRUE; /* Success */ | ||
2059 | } | ||
2060 | |||
2061 | |||
2062 | |||
2063 | int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
2064 | const URI_CHAR * afterUriReference; | ||
2065 | URI_TYPE(Uri) * uri; | ||
2066 | |||
2067 | /* Check params */ | ||
2068 | if ((state == NULL) || (first == NULL) || (afterLast == NULL)) { | ||
2069 | return URI_ERROR_NULL; | ||
2070 | } | ||
2071 | uri = state->uri; | ||
2072 | |||
2073 | /* Init parser */ | ||
2074 | URI_FUNC(ResetParserState)(state); | ||
2075 | URI_FUNC(ResetUri)(uri); | ||
2076 | |||
2077 | /* Parse */ | ||
2078 | afterUriReference = URI_FUNC(ParseUriReference)(state, first, afterLast); | ||
2079 | if (afterUriReference == NULL) { | ||
2080 | return state->errorCode; | ||
2081 | } | ||
2082 | if (afterUriReference != afterLast) { | ||
2083 | URI_FUNC(StopSyntax)(state, afterUriReference); | ||
2084 | return state->errorCode; | ||
2085 | } | ||
2086 | return URI_SUCCESS; | ||
2087 | } | ||
2088 | |||
2089 | |||
2090 | |||
2091 | int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, const URI_CHAR * text) { | ||
2092 | if ((state == NULL) || (text == NULL)) { | ||
2093 | return URI_ERROR_NULL; | ||
2094 | } | ||
2095 | return URI_FUNC(ParseUriEx)(state, text, text + URI_STRLEN(text)); | ||
2096 | } | ||
2097 | |||
2098 | |||
2099 | |||
2100 | void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri) { | ||
2101 | if (uri == NULL) { | ||
2102 | return; | ||
2103 | } | ||
2104 | |||
2105 | if (uri->owner) { | ||
2106 | /* Scheme */ | ||
2107 | if (uri->scheme.first != NULL) { | ||
2108 | if (uri->scheme.first != uri->scheme.afterLast) { | ||
2109 | free((URI_CHAR *)uri->scheme.first); | ||
2110 | } | ||
2111 | uri->scheme.first = NULL; | ||
2112 | uri->scheme.afterLast = NULL; | ||
2113 | } | ||
2114 | |||
2115 | /* User info */ | ||
2116 | if (uri->userInfo.first != NULL) { | ||
2117 | if (uri->userInfo.first != uri->userInfo.afterLast) { | ||
2118 | free((URI_CHAR *)uri->userInfo.first); | ||
2119 | } | ||
2120 | uri->userInfo.first = NULL; | ||
2121 | uri->userInfo.afterLast = NULL; | ||
2122 | } | ||
2123 | |||
2124 | /* Host data - IPvFuture */ | ||
2125 | if (uri->hostData.ipFuture.first != NULL) { | ||
2126 | if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) { | ||
2127 | free((URI_CHAR *)uri->hostData.ipFuture.first); | ||
2128 | } | ||
2129 | uri->hostData.ipFuture.first = NULL; | ||
2130 | uri->hostData.ipFuture.afterLast = NULL; | ||
2131 | uri->hostText.first = NULL; | ||
2132 | uri->hostText.afterLast = NULL; | ||
2133 | } | ||
2134 | |||
2135 | /* Host text (if regname, after IPvFuture!) */ | ||
2136 | if ((uri->hostText.first != NULL) | ||
2137 | && (uri->hostData.ip4 == NULL) | ||
2138 | && (uri->hostData.ip6 == NULL)) { | ||
2139 | /* Real regname */ | ||
2140 | if (uri->hostText.first != uri->hostText.afterLast) { | ||
2141 | free((URI_CHAR *)uri->hostText.first); | ||
2142 | } | ||
2143 | uri->hostText.first = NULL; | ||
2144 | uri->hostText.afterLast = NULL; | ||
2145 | } | ||
2146 | } | ||
2147 | |||
2148 | /* Host data - IPv4 */ | ||
2149 | if (uri->hostData.ip4 != NULL) { | ||
2150 | free(uri->hostData.ip4); | ||
2151 | uri->hostData.ip4 = NULL; | ||
2152 | } | ||
2153 | |||
2154 | /* Host data - IPv6 */ | ||
2155 | if (uri->hostData.ip6 != NULL) { | ||
2156 | free(uri->hostData.ip6); | ||
2157 | uri->hostData.ip6 = NULL; | ||
2158 | } | ||
2159 | |||
2160 | /* Port text */ | ||
2161 | if (uri->owner && (uri->portText.first != NULL)) { | ||
2162 | if (uri->portText.first != uri->portText.afterLast) { | ||
2163 | free((URI_CHAR *)uri->portText.first); | ||
2164 | } | ||
2165 | uri->portText.first = NULL; | ||
2166 | uri->portText.afterLast = NULL; | ||
2167 | } | ||
2168 | |||
2169 | /* Path */ | ||
2170 | if (uri->pathHead != NULL) { | ||
2171 | URI_TYPE(PathSegment) * segWalk = uri->pathHead; | ||
2172 | while (segWalk != NULL) { | ||
2173 | URI_TYPE(PathSegment) * const next = segWalk->next; | ||
2174 | if (uri->owner && (segWalk->text.first != NULL) | ||
2175 | && (segWalk->text.first < segWalk->text.afterLast)) { | ||
2176 | free((URI_CHAR *)segWalk->text.first); | ||
2177 | } | ||
2178 | free(segWalk); | ||
2179 | segWalk = next; | ||
2180 | } | ||
2181 | uri->pathHead = NULL; | ||
2182 | uri->pathTail = NULL; | ||
2183 | } | ||
2184 | |||
2185 | if (uri->owner) { | ||
2186 | /* Query */ | ||
2187 | if (uri->query.first != NULL) { | ||
2188 | if (uri->query.first != uri->query.afterLast) { | ||
2189 | free((URI_CHAR *)uri->query.first); | ||
2190 | } | ||
2191 | uri->query.first = NULL; | ||
2192 | uri->query.afterLast = NULL; | ||
2193 | } | ||
2194 | |||
2195 | /* Fragment */ | ||
2196 | if (uri->fragment.first != NULL) { | ||
2197 | if (uri->fragment.first != uri->fragment.afterLast) { | ||
2198 | free((URI_CHAR *)uri->fragment.first); | ||
2199 | } | ||
2200 | uri->fragment.first = NULL; | ||
2201 | uri->fragment.afterLast = NULL; | ||
2202 | } | ||
2203 | } | ||
2204 | } | ||
2205 | |||
2206 | |||
2207 | |||
2208 | UriBool URI_FUNC(_TESTING_ONLY_ParseIpSix)(const URI_CHAR * text) { | ||
2209 | URI_TYPE(Uri) uri; | ||
2210 | URI_TYPE(ParserState) parser; | ||
2211 | const URI_CHAR * const afterIpSix = text + URI_STRLEN(text); | ||
2212 | const URI_CHAR * res; | ||
2213 | |||
2214 | URI_FUNC(ResetParserState)(&parser); | ||
2215 | URI_FUNC(ResetUri)(&uri); | ||
2216 | parser.uri = &uri; | ||
2217 | parser.uri->hostData.ip6 = malloc(1 * sizeof(UriIp6)); | ||
2218 | res = URI_FUNC(ParseIPv6address2)(&parser, text, afterIpSix); | ||
2219 | URI_FUNC(FreeUriMembers)(&uri); | ||
2220 | return res == afterIpSix ? URI_TRUE : URI_FALSE; | ||
2221 | } | ||
2222 | |||
2223 | |||
2224 | |||
2225 | UriBool URI_FUNC(_TESTING_ONLY_ParseIpFour)(const URI_CHAR * text) { | ||
2226 | unsigned char octets[4]; | ||
2227 | int res = URI_FUNC(ParseIpFourAddress)(octets, text, text + URI_STRLEN(text)); | ||
2228 | return (res == URI_SUCCESS) ? URI_TRUE : URI_FALSE; | ||
2229 | } | ||
2230 | |||
2231 | |||
2232 | |||
2233 | #undef URI_SET_DIGIT | ||
2234 | #undef URI_SET_HEX_LETTER_UPPER | ||
2235 | #undef URI_SET_HEX_LETTER_LOWER | ||
2236 | #undef URI_SET_HEXDIG | ||
2237 | #undef URI_SET_ALPHA | ||
2238 | |||
2239 | |||
2240 | |||
2241 | #endif | ||
diff --git a/plugins/uriparser/UriParseBase.c b/plugins/uriparser/UriParseBase.c new file mode 100644 index 00000000..75e47613 --- /dev/null +++ b/plugins/uriparser/UriParseBase.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #ifndef URI_DOXYGEN | ||
41 | # include "UriParseBase.h" | ||
42 | #endif | ||
43 | |||
44 | |||
45 | |||
46 | void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, unsigned char * output) { | ||
47 | switch (digitCount) { | ||
48 | case 1: | ||
49 | /* 0x___? -> \x00 \x0? */ | ||
50 | output[0] = 0; | ||
51 | output[1] = hexDigits[0]; | ||
52 | break; | ||
53 | |||
54 | case 2: | ||
55 | /* 0x__?? -> \0xx \x?? */ | ||
56 | output[0] = 0; | ||
57 | output[1] = 16 * hexDigits[0] + hexDigits[1]; | ||
58 | break; | ||
59 | |||
60 | case 3: | ||
61 | /* 0x_??? -> \0x? \x?? */ | ||
62 | output[0] = hexDigits[0]; | ||
63 | output[1] = 16 * hexDigits[1] + hexDigits[2]; | ||
64 | break; | ||
65 | |||
66 | case 4: | ||
67 | /* 0x???? -> \0?? \x?? */ | ||
68 | output[0] = 16 * hexDigits[0] + hexDigits[1]; | ||
69 | output[1] = 16 * hexDigits[2] + hexDigits[3]; | ||
70 | break; | ||
71 | |||
72 | } | ||
73 | } | ||
74 | |||
75 | |||
76 | |||
77 | unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount) { | ||
78 | switch (digitCount) { | ||
79 | case 1: | ||
80 | return digits[0]; | ||
81 | |||
82 | case 2: | ||
83 | return 10 * digits[0] + digits[1]; | ||
84 | |||
85 | case 3: | ||
86 | default: | ||
87 | return 100 * digits[0] + 10 * digits[1] + digits[2]; | ||
88 | |||
89 | } | ||
90 | } | ||
diff --git a/plugins/uriparser/UriParseBase.h b/plugins/uriparser/UriParseBase.h new file mode 100644 index 00000000..dea5c81c --- /dev/null +++ b/plugins/uriparser/UriParseBase.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #ifndef URI_PARSE_BASE_H | ||
41 | #define URI_PARSE_BASE_H 1 | ||
42 | |||
43 | |||
44 | |||
45 | #include <uriparser/UriBase.h> | ||
46 | |||
47 | |||
48 | |||
49 | void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, | ||
50 | unsigned char * output); | ||
51 | unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount); | ||
52 | |||
53 | |||
54 | |||
55 | #endif /* URI_PARSE_BASE_H */ | ||
diff --git a/plugins/uriparser/UriQuery.c b/plugins/uriparser/UriQuery.c new file mode 100644 index 00000000..7adb0736 --- /dev/null +++ b/plugins/uriparser/UriQuery.c | |||
@@ -0,0 +1,460 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriQuery.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriQuery.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include "UriCommon.h" | ||
67 | #endif | ||
68 | |||
69 | |||
70 | |||
71 | static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, | ||
72 | const URI_TYPE(QueryList) * queryList, | ||
73 | int maxChars, int * charsWritten, int * charsRequired, | ||
74 | UriBool spaceToPlus, UriBool normalizeBreaks); | ||
75 | |||
76 | static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, | ||
77 | int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, | ||
78 | const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, | ||
79 | UriBool plusToSpace, UriBreakConversion breakConversion); | ||
80 | |||
81 | |||
82 | |||
83 | int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, | ||
84 | int * charsRequired) { | ||
85 | const UriBool spaceToPlus = URI_TRUE; | ||
86 | const UriBool normalizeBreaks = URI_TRUE; | ||
87 | |||
88 | return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired, | ||
89 | spaceToPlus, normalizeBreaks); | ||
90 | } | ||
91 | |||
92 | |||
93 | |||
94 | int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList, | ||
95 | int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) { | ||
96 | if ((queryList == NULL) || (charsRequired == NULL)) { | ||
97 | return URI_ERROR_NULL; | ||
98 | } | ||
99 | |||
100 | return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL, | ||
101 | charsRequired, spaceToPlus, normalizeBreaks); | ||
102 | } | ||
103 | |||
104 | |||
105 | |||
106 | int URI_FUNC(ComposeQuery)(URI_CHAR * dest, | ||
107 | const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) { | ||
108 | const UriBool spaceToPlus = URI_TRUE; | ||
109 | const UriBool normalizeBreaks = URI_TRUE; | ||
110 | |||
111 | return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten, | ||
112 | spaceToPlus, normalizeBreaks); | ||
113 | } | ||
114 | |||
115 | |||
116 | |||
117 | int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, | ||
118 | const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, | ||
119 | UriBool spaceToPlus, UriBool normalizeBreaks) { | ||
120 | if ((dest == NULL) || (queryList == NULL)) { | ||
121 | return URI_ERROR_NULL; | ||
122 | } | ||
123 | |||
124 | if (maxChars < 1) { | ||
125 | return URI_ERROR_OUTPUT_TOO_LARGE; | ||
126 | } | ||
127 | |||
128 | return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars, | ||
129 | charsWritten, NULL, spaceToPlus, normalizeBreaks); | ||
130 | } | ||
131 | |||
132 | |||
133 | |||
134 | int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, | ||
135 | const URI_TYPE(QueryList) * queryList) { | ||
136 | const UriBool spaceToPlus = URI_TRUE; | ||
137 | const UriBool normalizeBreaks = URI_TRUE; | ||
138 | |||
139 | return URI_FUNC(ComposeQueryMallocEx)(dest, queryList, | ||
140 | spaceToPlus, normalizeBreaks); | ||
141 | } | ||
142 | |||
143 | |||
144 | |||
145 | int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, | ||
146 | const URI_TYPE(QueryList) * queryList, | ||
147 | UriBool spaceToPlus, UriBool normalizeBreaks) { | ||
148 | int charsRequired; | ||
149 | int res; | ||
150 | URI_CHAR * queryString; | ||
151 | |||
152 | if (dest == NULL) { | ||
153 | return URI_ERROR_NULL; | ||
154 | } | ||
155 | |||
156 | /* Calculate space */ | ||
157 | res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired, | ||
158 | spaceToPlus, normalizeBreaks); | ||
159 | if (res != URI_SUCCESS) { | ||
160 | return res; | ||
161 | } | ||
162 | charsRequired++; | ||
163 | |||
164 | /* Allocate space */ | ||
165 | queryString = malloc(charsRequired * sizeof(URI_CHAR)); | ||
166 | if (queryString == NULL) { | ||
167 | return URI_ERROR_MALLOC; | ||
168 | } | ||
169 | |||
170 | /* Put query in */ | ||
171 | res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired, | ||
172 | NULL, spaceToPlus, normalizeBreaks); | ||
173 | if (res != URI_SUCCESS) { | ||
174 | free(queryString); | ||
175 | return res; | ||
176 | } | ||
177 | |||
178 | *dest = queryString; | ||
179 | return URI_SUCCESS; | ||
180 | } | ||
181 | |||
182 | |||
183 | |||
184 | int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, | ||
185 | const URI_TYPE(QueryList) * queryList, | ||
186 | int maxChars, int * charsWritten, int * charsRequired, | ||
187 | UriBool spaceToPlus, UriBool normalizeBreaks) { | ||
188 | UriBool firstItem = URI_TRUE; | ||
189 | int ampersandLen = 0; | ||
190 | URI_CHAR * write = dest; | ||
191 | |||
192 | /* Subtract terminator */ | ||
193 | if (dest == NULL) { | ||
194 | *charsRequired = 0; | ||
195 | } else { | ||
196 | maxChars--; | ||
197 | } | ||
198 | |||
199 | while (queryList != NULL) { | ||
200 | const URI_CHAR * const key = queryList->key; | ||
201 | const URI_CHAR * const value = queryList->value; | ||
202 | const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3); | ||
203 | const int keyLen = (key == NULL) ? 0 : (int)URI_STRLEN(key); | ||
204 | const int keyRequiredChars = worstCase * keyLen; | ||
205 | const int valueLen = (value == NULL) ? 0 : (int)URI_STRLEN(value); | ||
206 | const int valueRequiredChars = worstCase * valueLen; | ||
207 | |||
208 | if (dest == NULL) { | ||
209 | if (firstItem == URI_TRUE) { | ||
210 | ampersandLen = 1; | ||
211 | firstItem = URI_FALSE; | ||
212 | } | ||
213 | |||
214 | (*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL) | ||
215 | ? 0 | ||
216 | : 1 + valueRequiredChars); | ||
217 | } else { | ||
218 | URI_CHAR * afterKey; | ||
219 | |||
220 | if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) { | ||
221 | return URI_ERROR_OUTPUT_TOO_LARGE; | ||
222 | } | ||
223 | |||
224 | /* Copy key */ | ||
225 | if (firstItem == URI_TRUE) { | ||
226 | firstItem = URI_FALSE; | ||
227 | } else { | ||
228 | write[0] = _UT('&'); | ||
229 | write++; | ||
230 | } | ||
231 | afterKey = URI_FUNC(EscapeEx)(key, key + keyLen, | ||
232 | write, spaceToPlus, normalizeBreaks); | ||
233 | write += (afterKey - write); | ||
234 | |||
235 | if (value != NULL) { | ||
236 | URI_CHAR * afterValue; | ||
237 | |||
238 | if ((write - dest) + 1 + valueRequiredChars > maxChars) { | ||
239 | return URI_ERROR_OUTPUT_TOO_LARGE; | ||
240 | } | ||
241 | |||
242 | /* Copy value */ | ||
243 | write[0] = _UT('='); | ||
244 | write++; | ||
245 | afterValue = URI_FUNC(EscapeEx)(value, value + valueLen, | ||
246 | write, spaceToPlus, normalizeBreaks); | ||
247 | write += (afterValue - write); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | queryList = queryList->next; | ||
252 | } | ||
253 | |||
254 | if (dest != NULL) { | ||
255 | write[0] = _UT('\0'); | ||
256 | if (charsWritten != NULL) { | ||
257 | *charsWritten = (int)(write - dest) + 1; /* .. for terminator */ | ||
258 | } | ||
259 | } | ||
260 | |||
261 | return URI_SUCCESS; | ||
262 | } | ||
263 | |||
264 | |||
265 | |||
266 | UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, | ||
267 | int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, | ||
268 | const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, | ||
269 | UriBool plusToSpace, UriBreakConversion breakConversion) { | ||
270 | const int keyLen = (int)(keyAfter - keyFirst); | ||
271 | const int valueLen = (int)(valueAfter - valueFirst); | ||
272 | URI_CHAR * key; | ||
273 | URI_CHAR * value; | ||
274 | |||
275 | if ((prevNext == NULL) || (itemCount == NULL) | ||
276 | || (keyFirst == NULL) || (keyAfter == NULL) | ||
277 | || (keyFirst > keyAfter) || (valueFirst > valueAfter) | ||
278 | || ((keyFirst == keyAfter) | ||
279 | && (valueFirst == NULL) && (valueAfter == NULL))) { | ||
280 | return URI_TRUE; | ||
281 | } | ||
282 | |||
283 | /* Append new empty item */ | ||
284 | *prevNext = malloc(1 * sizeof(URI_TYPE(QueryList))); | ||
285 | if (*prevNext == NULL) { | ||
286 | return URI_FALSE; /* Raises malloc error */ | ||
287 | } | ||
288 | (*prevNext)->next = NULL; | ||
289 | |||
290 | |||
291 | /* Fill key */ | ||
292 | key = malloc((keyLen + 1) * sizeof(URI_CHAR)); | ||
293 | if (key == NULL) { | ||
294 | free(*prevNext); | ||
295 | *prevNext = NULL; | ||
296 | return URI_FALSE; /* Raises malloc error */ | ||
297 | } | ||
298 | |||
299 | key[keyLen] = _UT('\0'); | ||
300 | if (keyLen > 0) { | ||
301 | /* Copy 1:1 */ | ||
302 | memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR)); | ||
303 | |||
304 | /* Unescape */ | ||
305 | URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion); | ||
306 | } | ||
307 | (*prevNext)->key = key; | ||
308 | |||
309 | |||
310 | /* Fill value */ | ||
311 | if (valueFirst != NULL) { | ||
312 | value = malloc((valueLen + 1) * sizeof(URI_CHAR)); | ||
313 | if (value == NULL) { | ||
314 | free(key); | ||
315 | free(*prevNext); | ||
316 | *prevNext = NULL; | ||
317 | return URI_FALSE; /* Raises malloc error */ | ||
318 | } | ||
319 | |||
320 | value[valueLen] = _UT('\0'); | ||
321 | if (valueLen > 0) { | ||
322 | /* Copy 1:1 */ | ||
323 | memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR)); | ||
324 | |||
325 | /* Unescape */ | ||
326 | URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion); | ||
327 | } | ||
328 | (*prevNext)->value = value; | ||
329 | } else { | ||
330 | value = NULL; | ||
331 | } | ||
332 | (*prevNext)->value = value; | ||
333 | |||
334 | (*itemCount)++; | ||
335 | return URI_TRUE; | ||
336 | } | ||
337 | |||
338 | |||
339 | |||
340 | void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) { | ||
341 | while (queryList != NULL) { | ||
342 | URI_TYPE(QueryList) * nextBackup = queryList->next; | ||
343 | free((URI_CHAR *)queryList->key); /* const cast */ | ||
344 | free((URI_CHAR *)queryList->value); /* const cast */ | ||
345 | free(queryList); | ||
346 | queryList = nextBackup; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | |||
351 | |||
352 | int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount, | ||
353 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
354 | const UriBool plusToSpace = URI_TRUE; | ||
355 | const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; | ||
356 | |||
357 | return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast, | ||
358 | plusToSpace, breakConversion); | ||
359 | } | ||
360 | |||
361 | |||
362 | |||
363 | int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount, | ||
364 | const URI_CHAR * first, const URI_CHAR * afterLast, | ||
365 | UriBool plusToSpace, UriBreakConversion breakConversion) { | ||
366 | const URI_CHAR * walk = first; | ||
367 | const URI_CHAR * keyFirst = first; | ||
368 | const URI_CHAR * keyAfter = NULL; | ||
369 | const URI_CHAR * valueFirst = NULL; | ||
370 | const URI_CHAR * valueAfter = NULL; | ||
371 | URI_TYPE(QueryList) ** prevNext = dest; | ||
372 | int nullCounter; | ||
373 | int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount; | ||
374 | |||
375 | if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) { | ||
376 | return URI_ERROR_NULL; | ||
377 | } | ||
378 | |||
379 | if (first > afterLast) { | ||
380 | return URI_ERROR_RANGE_INVALID; | ||
381 | } | ||
382 | |||
383 | *dest = NULL; | ||
384 | *itemsAppended = 0; | ||
385 | |||
386 | /* Parse query string */ | ||
387 | for (; walk < afterLast; walk++) { | ||
388 | switch (*walk) { | ||
389 | case _UT('&'): | ||
390 | if (valueFirst != NULL) { | ||
391 | valueAfter = walk; | ||
392 | } else { | ||
393 | keyAfter = walk; | ||
394 | } | ||
395 | |||
396 | if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, | ||
397 | keyFirst, keyAfter, valueFirst, valueAfter, | ||
398 | plusToSpace, breakConversion) | ||
399 | == URI_FALSE) { | ||
400 | /* Free list we built */ | ||
401 | *itemsAppended = 0; | ||
402 | URI_FUNC(FreeQueryList)(*dest); | ||
403 | return URI_ERROR_MALLOC; | ||
404 | } | ||
405 | |||
406 | /* Make future items children of the current */ | ||
407 | if ((prevNext != NULL) && (*prevNext != NULL)) { | ||
408 | prevNext = &((*prevNext)->next); | ||
409 | } | ||
410 | |||
411 | if (walk + 1 < afterLast) { | ||
412 | keyFirst = walk + 1; | ||
413 | } else { | ||
414 | keyFirst = NULL; | ||
415 | } | ||
416 | keyAfter = NULL; | ||
417 | valueFirst = NULL; | ||
418 | valueAfter = NULL; | ||
419 | break; | ||
420 | |||
421 | case _UT('='): | ||
422 | /* NOTE: WE treat the first '=' as a separator, */ | ||
423 | /* all following go into the value part */ | ||
424 | if (keyAfter == NULL) { | ||
425 | keyAfter = walk; | ||
426 | if (walk + 1 <= afterLast) { | ||
427 | valueFirst = walk + 1; | ||
428 | valueAfter = walk + 1; | ||
429 | } | ||
430 | } | ||
431 | break; | ||
432 | |||
433 | default: | ||
434 | break; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | if (valueFirst != NULL) { | ||
439 | /* Must be key/value pair */ | ||
440 | valueAfter = walk; | ||
441 | } else { | ||
442 | /* Must be key only */ | ||
443 | keyAfter = walk; | ||
444 | } | ||
445 | |||
446 | if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, | ||
447 | valueFirst, valueAfter, plusToSpace, breakConversion) | ||
448 | == URI_FALSE) { | ||
449 | /* Free list we built */ | ||
450 | *itemsAppended = 0; | ||
451 | URI_FUNC(FreeQueryList)(*dest); | ||
452 | return URI_ERROR_MALLOC; | ||
453 | } | ||
454 | |||
455 | return URI_SUCCESS; | ||
456 | } | ||
457 | |||
458 | |||
459 | |||
460 | #endif | ||
diff --git a/plugins/uriparser/UriRecompose.c b/plugins/uriparser/UriRecompose.c new file mode 100644 index 00000000..09daee07 --- /dev/null +++ b/plugins/uriparser/UriRecompose.c | |||
@@ -0,0 +1,577 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriRecompose.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriRecompose.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include "UriCommon.h" | ||
67 | #endif | ||
68 | |||
69 | |||
70 | |||
71 | static int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, | ||
72 | int maxChars, int * charsWritten, int * charsRequired); | ||
73 | |||
74 | |||
75 | |||
76 | int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, | ||
77 | int * charsRequired) { | ||
78 | const int MAX_CHARS = ((unsigned int)-1) >> 1; | ||
79 | return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired); | ||
80 | } | ||
81 | |||
82 | |||
83 | |||
84 | int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, | ||
85 | int maxChars, int * charsWritten) { | ||
86 | return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL); | ||
87 | } | ||
88 | |||
89 | |||
90 | |||
91 | static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, | ||
92 | const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten, | ||
93 | int * charsRequired) { | ||
94 | int written = 0; | ||
95 | if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) { | ||
96 | if (charsWritten != NULL) { | ||
97 | *charsWritten = 0; | ||
98 | } | ||
99 | return URI_ERROR_NULL; | ||
100 | } | ||
101 | |||
102 | if (maxChars < 1) { | ||
103 | if (charsWritten != NULL) { | ||
104 | *charsWritten = 0; | ||
105 | } | ||
106 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
107 | } | ||
108 | maxChars--; /* So we don't have to substract 1 for '\0' all the time */ | ||
109 | |||
110 | /* [01/19] result = "" */ | ||
111 | if (dest != NULL) { | ||
112 | dest[0] = _UT('\0'); | ||
113 | } else { | ||
114 | (*charsRequired) = 0; | ||
115 | } | ||
116 | /* [02/19] if defined(scheme) then */ | ||
117 | if (uri->scheme.first != NULL) { | ||
118 | /* [03/19] append scheme to result; */ | ||
119 | const int charsToWrite | ||
120 | = (int)(uri->scheme.afterLast - uri->scheme.first); | ||
121 | if (dest != NULL) { | ||
122 | if (written + charsToWrite <= maxChars) { | ||
123 | memcpy(dest + written, uri->scheme.first, | ||
124 | charsToWrite * sizeof(URI_CHAR)); | ||
125 | written += charsToWrite; | ||
126 | } else { | ||
127 | dest[0] = _UT('\0'); | ||
128 | if (charsWritten != NULL) { | ||
129 | *charsWritten = 0; | ||
130 | } | ||
131 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
132 | } | ||
133 | } else { | ||
134 | (*charsRequired) += charsToWrite; | ||
135 | } | ||
136 | /* [04/19] append ":" to result; */ | ||
137 | if (dest != NULL) { | ||
138 | if (written + 1 <= maxChars) { | ||
139 | memcpy(dest + written, _UT(":"), | ||
140 | 1 * sizeof(URI_CHAR)); | ||
141 | written += 1; | ||
142 | } else { | ||
143 | dest[0] = _UT('\0'); | ||
144 | if (charsWritten != NULL) { | ||
145 | *charsWritten = 0; | ||
146 | } | ||
147 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
148 | } | ||
149 | } else { | ||
150 | (*charsRequired) += 1; | ||
151 | } | ||
152 | /* [05/19] endif; */ | ||
153 | } | ||
154 | /* [06/19] if defined(authority) then */ | ||
155 | if (URI_FUNC(IsHostSet)(uri)) { | ||
156 | /* [07/19] append "//" to result; */ | ||
157 | if (dest != NULL) { | ||
158 | if (written + 2 <= maxChars) { | ||
159 | memcpy(dest + written, _UT("//"), | ||
160 | 2 * sizeof(URI_CHAR)); | ||
161 | written += 2; | ||
162 | } else { | ||
163 | dest[0] = _UT('\0'); | ||
164 | if (charsWritten != NULL) { | ||
165 | *charsWritten = 0; | ||
166 | } | ||
167 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
168 | } | ||
169 | } else { | ||
170 | (*charsRequired) += 2; | ||
171 | } | ||
172 | /* [08/19] append authority to result; */ | ||
173 | /* UserInfo */ | ||
174 | if (uri->userInfo.first != NULL) { | ||
175 | const int charsToWrite = (int)(uri->userInfo.afterLast - uri->userInfo.first); | ||
176 | if (dest != NULL) { | ||
177 | if (written + charsToWrite <= maxChars) { | ||
178 | memcpy(dest + written, uri->userInfo.first, | ||
179 | charsToWrite * sizeof(URI_CHAR)); | ||
180 | written += charsToWrite; | ||
181 | } else { | ||
182 | dest[0] = _UT('\0'); | ||
183 | if (charsWritten != NULL) { | ||
184 | *charsWritten = 0; | ||
185 | } | ||
186 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
187 | } | ||
188 | |||
189 | if (written + 1 <= maxChars) { | ||
190 | memcpy(dest + written, _UT("@"), | ||
191 | 1 * sizeof(URI_CHAR)); | ||
192 | written += 1; | ||
193 | } else { | ||
194 | dest[0] = _UT('\0'); | ||
195 | if (charsWritten != NULL) { | ||
196 | *charsWritten = 0; | ||
197 | } | ||
198 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
199 | } | ||
200 | } else { | ||
201 | (*charsRequired) += charsToWrite + 1; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* Host */ | ||
206 | if (uri->hostData.ip4 != NULL) { | ||
207 | /* IPv4 */ | ||
208 | int i = 0; | ||
209 | for (; i < 4; i++) { | ||
210 | const unsigned char value = uri->hostData.ip4->data[i]; | ||
211 | const int charsToWrite = (value > 99) ? 3 : ((value > 9) ? 2 : 1); | ||
212 | if (dest != NULL) { | ||
213 | if (written + charsToWrite <= maxChars) { | ||
214 | URI_CHAR text[4]; | ||
215 | if (value > 99) { | ||
216 | text[0] = _UT('0') + (value / 100); | ||
217 | text[1] = _UT('0') + ((value % 100) / 10); | ||
218 | text[2] = _UT('0') + (value % 10); | ||
219 | } else if (value > 9) { | ||
220 | text[0] = _UT('0') + (value / 10); | ||
221 | text[1] = _UT('0') + (value % 10); | ||
222 | } else { | ||
223 | text[0] = _UT('0') + value; | ||
224 | } | ||
225 | text[charsToWrite] = _UT('\0'); | ||
226 | memcpy(dest + written, text, charsToWrite * sizeof(URI_CHAR)); | ||
227 | written += charsToWrite; | ||
228 | } else { | ||
229 | dest[0] = _UT('\0'); | ||
230 | if (charsWritten != NULL) { | ||
231 | *charsWritten = 0; | ||
232 | } | ||
233 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
234 | } | ||
235 | if (i < 3) { | ||
236 | if (written + 1 <= maxChars) { | ||
237 | memcpy(dest + written, _UT("."), | ||
238 | 1 * sizeof(URI_CHAR)); | ||
239 | written += 1; | ||
240 | } else { | ||
241 | dest[0] = _UT('\0'); | ||
242 | if (charsWritten != NULL) { | ||
243 | *charsWritten = 0; | ||
244 | } | ||
245 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
246 | } | ||
247 | } | ||
248 | } else { | ||
249 | (*charsRequired) += charsToWrite + 1; | ||
250 | } | ||
251 | } | ||
252 | } else if (uri->hostData.ip6 != NULL) { | ||
253 | /* IPv6 */ | ||
254 | int i = 0; | ||
255 | if (dest != NULL) { | ||
256 | if (written + 1 <= maxChars) { | ||
257 | memcpy(dest + written, _UT("["), | ||
258 | 1 * sizeof(URI_CHAR)); | ||
259 | written += 1; | ||
260 | } else { | ||
261 | dest[0] = _UT('\0'); | ||
262 | if (charsWritten != NULL) { | ||
263 | *charsWritten = 0; | ||
264 | } | ||
265 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
266 | } | ||
267 | } else { | ||
268 | (*charsRequired) += 1; | ||
269 | } | ||
270 | |||
271 | for (; i < 16; i++) { | ||
272 | const unsigned char value = uri->hostData.ip6->data[i]; | ||
273 | if (dest != NULL) { | ||
274 | if (written + 2 <= maxChars) { | ||
275 | URI_CHAR text[3]; | ||
276 | text[0] = URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE); | ||
277 | text[1] = URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE); | ||
278 | text[2] = _UT('\0'); | ||
279 | memcpy(dest + written, text, 2 * sizeof(URI_CHAR)); | ||
280 | written += 2; | ||
281 | } else { | ||
282 | dest[0] = _UT('\0'); | ||
283 | if (charsWritten != NULL) { | ||
284 | *charsWritten = 0; | ||
285 | } | ||
286 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
287 | } | ||
288 | } else { | ||
289 | (*charsRequired) += 2; | ||
290 | } | ||
291 | if (((i & 1) == 1) && (i < 15)) { | ||
292 | if (dest != NULL) { | ||
293 | if (written + 1 <= maxChars) { | ||
294 | memcpy(dest + written, _UT(":"), | ||
295 | 1 * sizeof(URI_CHAR)); | ||
296 | written += 1; | ||
297 | } else { | ||
298 | dest[0] = _UT('\0'); | ||
299 | if (charsWritten != NULL) { | ||
300 | *charsWritten = 0; | ||
301 | } | ||
302 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
303 | } | ||
304 | } else { | ||
305 | (*charsRequired) += 1; | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | |||
310 | if (dest != NULL) { | ||
311 | if (written + 1 <= maxChars) { | ||
312 | memcpy(dest + written, _UT("]"), | ||
313 | 1 * sizeof(URI_CHAR)); | ||
314 | written += 1; | ||
315 | } else { | ||
316 | dest[0] = _UT('\0'); | ||
317 | if (charsWritten != NULL) { | ||
318 | *charsWritten = 0; | ||
319 | } | ||
320 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
321 | } | ||
322 | } else { | ||
323 | (*charsRequired) += 1; | ||
324 | } | ||
325 | } else if (uri->hostData.ipFuture.first != NULL) { | ||
326 | /* IPvFuture */ | ||
327 | const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast | ||
328 | - uri->hostData.ipFuture.first); | ||
329 | if (dest != NULL) { | ||
330 | if (written + 1 <= maxChars) { | ||
331 | memcpy(dest + written, _UT("["), | ||
332 | 1 * sizeof(URI_CHAR)); | ||
333 | written += 1; | ||
334 | } else { | ||
335 | dest[0] = _UT('\0'); | ||
336 | if (charsWritten != NULL) { | ||
337 | *charsWritten = 0; | ||
338 | } | ||
339 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
340 | } | ||
341 | |||
342 | if (written + charsToWrite <= maxChars) { | ||
343 | memcpy(dest + written, uri->hostData.ipFuture.first, charsToWrite * sizeof(URI_CHAR)); | ||
344 | written += charsToWrite; | ||
345 | } else { | ||
346 | dest[0] = _UT('\0'); | ||
347 | if (charsWritten != NULL) { | ||
348 | *charsWritten = 0; | ||
349 | } | ||
350 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
351 | } | ||
352 | |||
353 | if (written + 1 <= maxChars) { | ||
354 | memcpy(dest + written, _UT("]"), | ||
355 | 1 * sizeof(URI_CHAR)); | ||
356 | written += 1; | ||
357 | } else { | ||
358 | dest[0] = _UT('\0'); | ||
359 | if (charsWritten != NULL) { | ||
360 | *charsWritten = 0; | ||
361 | } | ||
362 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
363 | } | ||
364 | } else { | ||
365 | (*charsRequired) += 1 + charsToWrite + 1; | ||
366 | } | ||
367 | } else if (uri->hostText.first != NULL) { | ||
368 | /* Regname */ | ||
369 | const int charsToWrite = (int)(uri->hostText.afterLast - uri->hostText.first); | ||
370 | if (dest != NULL) { | ||
371 | if (written + charsToWrite <= maxChars) { | ||
372 | memcpy(dest + written, uri->hostText.first, | ||
373 | charsToWrite * sizeof(URI_CHAR)); | ||
374 | written += charsToWrite; | ||
375 | } else { | ||
376 | dest[0] = _UT('\0'); | ||
377 | if (charsWritten != NULL) { | ||
378 | *charsWritten = 0; | ||
379 | } | ||
380 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
381 | } | ||
382 | } else { | ||
383 | (*charsRequired) += charsToWrite; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | /* Port */ | ||
388 | if (uri->portText.first != NULL) { | ||
389 | const int charsToWrite = (int)(uri->portText.afterLast - uri->portText.first); | ||
390 | if (dest != NULL) { | ||
391 | /* Leading ':' */ | ||
392 | if (written + 1 <= maxChars) { | ||
393 | memcpy(dest + written, _UT(":"), | ||
394 | 1 * sizeof(URI_CHAR)); | ||
395 | written += 1; | ||
396 | } else { | ||
397 | dest[0] = _UT('\0'); | ||
398 | if (charsWritten != NULL) { | ||
399 | *charsWritten = 0; | ||
400 | } | ||
401 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
402 | } | ||
403 | |||
404 | /* Port number */ | ||
405 | if (written + charsToWrite <= maxChars) { | ||
406 | memcpy(dest + written, uri->portText.first, | ||
407 | charsToWrite * sizeof(URI_CHAR)); | ||
408 | written += charsToWrite; | ||
409 | } else { | ||
410 | dest[0] = _UT('\0'); | ||
411 | if (charsWritten != NULL) { | ||
412 | *charsWritten = 0; | ||
413 | } | ||
414 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
415 | } | ||
416 | } else { | ||
417 | (*charsRequired) += 1 + charsToWrite; | ||
418 | } | ||
419 | } | ||
420 | /* [09/19] endif; */ | ||
421 | } | ||
422 | /* [10/19] append path to result; */ | ||
423 | /* Slash needed here? */ | ||
424 | if (uri->absolutePath || ((uri->pathHead != NULL) | ||
425 | && URI_FUNC(IsHostSet)(uri))) { | ||
426 | if (dest != NULL) { | ||
427 | if (written + 1 <= maxChars) { | ||
428 | memcpy(dest + written, _UT("/"), | ||
429 | 1 * sizeof(URI_CHAR)); | ||
430 | written += 1; | ||
431 | } else { | ||
432 | dest[0] = _UT('\0'); | ||
433 | if (charsWritten != NULL) { | ||
434 | *charsWritten = 0; | ||
435 | } | ||
436 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
437 | } | ||
438 | } else { | ||
439 | (*charsRequired) += 1; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | if (uri->pathHead != NULL) { | ||
444 | URI_TYPE(PathSegment) * walker = uri->pathHead; | ||
445 | do { | ||
446 | const int charsToWrite = (int)(walker->text.afterLast - walker->text.first); | ||
447 | if (dest != NULL) { | ||
448 | if (written + charsToWrite <= maxChars) { | ||
449 | memcpy(dest + written, walker->text.first, | ||
450 | charsToWrite * sizeof(URI_CHAR)); | ||
451 | written += charsToWrite; | ||
452 | } else { | ||
453 | dest[0] = _UT('\0'); | ||
454 | if (charsWritten != NULL) { | ||
455 | *charsWritten = 0; | ||
456 | } | ||
457 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
458 | } | ||
459 | } else { | ||
460 | (*charsRequired) += charsToWrite; | ||
461 | } | ||
462 | |||
463 | /* Not last segment -> append slash */ | ||
464 | if (walker->next != NULL) { | ||
465 | if (dest != NULL) { | ||
466 | if (written + 1 <= maxChars) { | ||
467 | memcpy(dest + written, _UT("/"), | ||
468 | 1 * sizeof(URI_CHAR)); | ||
469 | written += 1; | ||
470 | } else { | ||
471 | dest[0] = _UT('\0'); | ||
472 | if (charsWritten != NULL) { | ||
473 | *charsWritten = 0; | ||
474 | } | ||
475 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
476 | } | ||
477 | } else { | ||
478 | (*charsRequired) += 1; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | walker = walker->next; | ||
483 | } while (walker != NULL); | ||
484 | } | ||
485 | /* [11/19] if defined(query) then */ | ||
486 | if (uri->query.first != NULL) { | ||
487 | /* [12/19] append "?" to result; */ | ||
488 | if (dest != NULL) { | ||
489 | if (written + 1 <= maxChars) { | ||
490 | memcpy(dest + written, _UT("?"), | ||
491 | 1 * sizeof(URI_CHAR)); | ||
492 | written += 1; | ||
493 | } else { | ||
494 | dest[0] = _UT('\0'); | ||
495 | if (charsWritten != NULL) { | ||
496 | *charsWritten = 0; | ||
497 | } | ||
498 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
499 | } | ||
500 | } else { | ||
501 | (*charsRequired) += 1; | ||
502 | } | ||
503 | /* [13/19] append query to result; */ | ||
504 | { | ||
505 | const int charsToWrite | ||
506 | = (int)(uri->query.afterLast - uri->query.first); | ||
507 | if (dest != NULL) { | ||
508 | if (written + charsToWrite <= maxChars) { | ||
509 | memcpy(dest + written, uri->query.first, | ||
510 | charsToWrite * sizeof(URI_CHAR)); | ||
511 | written += charsToWrite; | ||
512 | } else { | ||
513 | dest[0] = _UT('\0'); | ||
514 | if (charsWritten != NULL) { | ||
515 | *charsWritten = 0; | ||
516 | } | ||
517 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
518 | } | ||
519 | } else { | ||
520 | (*charsRequired) += charsToWrite; | ||
521 | } | ||
522 | } | ||
523 | /* [14/19] endif; */ | ||
524 | } | ||
525 | /* [15/19] if defined(fragment) then */ | ||
526 | if (uri->fragment.first != NULL) { | ||
527 | /* [16/19] append "#" to result; */ | ||
528 | if (dest != NULL) { | ||
529 | if (written + 1 <= maxChars) { | ||
530 | memcpy(dest + written, _UT("#"), | ||
531 | 1 * sizeof(URI_CHAR)); | ||
532 | written += 1; | ||
533 | } else { | ||
534 | dest[0] = _UT('\0'); | ||
535 | if (charsWritten != NULL) { | ||
536 | *charsWritten = 0; | ||
537 | } | ||
538 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
539 | } | ||
540 | } else { | ||
541 | (*charsRequired) += 1; | ||
542 | } | ||
543 | /* [17/19] append fragment to result; */ | ||
544 | { | ||
545 | const int charsToWrite | ||
546 | = (int)(uri->fragment.afterLast - uri->fragment.first); | ||
547 | if (dest != NULL) { | ||
548 | if (written + charsToWrite <= maxChars) { | ||
549 | memcpy(dest + written, uri->fragment.first, | ||
550 | charsToWrite * sizeof(URI_CHAR)); | ||
551 | written += charsToWrite; | ||
552 | } else { | ||
553 | dest[0] = _UT('\0'); | ||
554 | if (charsWritten != NULL) { | ||
555 | *charsWritten = 0; | ||
556 | } | ||
557 | return URI_ERROR_TOSTRING_TOO_LONG; | ||
558 | } | ||
559 | } else { | ||
560 | (*charsRequired) += charsToWrite; | ||
561 | } | ||
562 | } | ||
563 | /* [18/19] endif; */ | ||
564 | } | ||
565 | /* [19/19] return result; */ | ||
566 | if (dest != NULL) { | ||
567 | dest[written++] = _UT('\0'); | ||
568 | if (charsWritten != NULL) { | ||
569 | *charsWritten = written; | ||
570 | } | ||
571 | } | ||
572 | return URI_SUCCESS; | ||
573 | } | ||
574 | |||
575 | |||
576 | |||
577 | #endif | ||
diff --git a/plugins/uriparser/UriResolve.c b/plugins/uriparser/UriResolve.c new file mode 100644 index 00000000..3660b6b2 --- /dev/null +++ b/plugins/uriparser/UriResolve.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriResolve.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriResolve.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include "UriCommon.h" | ||
67 | #endif | ||
68 | |||
69 | |||
70 | |||
71 | /* Appends a relative URI to an absolute. The last path segment of | ||
72 | * the absolute URI is replaced. */ | ||
73 | static URI_INLINE UriBool URI_FUNC(MergePath)(URI_TYPE(Uri) * absWork, | ||
74 | const URI_TYPE(Uri) * relAppend) { | ||
75 | URI_TYPE(PathSegment) * sourceWalker; | ||
76 | URI_TYPE(PathSegment) * destPrev; | ||
77 | if (relAppend->pathHead == NULL) { | ||
78 | return URI_TRUE; | ||
79 | } | ||
80 | |||
81 | /* Replace last segment ("" if trailing slash) with first of append chain */ | ||
82 | if (absWork->pathHead == NULL) { | ||
83 | URI_TYPE(PathSegment) * const dup = malloc(sizeof(URI_TYPE(PathSegment))); | ||
84 | if (dup == NULL) { | ||
85 | return URI_FALSE; /* Raises malloc error */ | ||
86 | } | ||
87 | dup->next = NULL; | ||
88 | absWork->pathHead = dup; | ||
89 | absWork->pathTail = dup; | ||
90 | } | ||
91 | absWork->pathTail->text.first = relAppend->pathHead->text.first; | ||
92 | absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast; | ||
93 | |||
94 | /* Append all the others */ | ||
95 | sourceWalker = relAppend->pathHead->next; | ||
96 | if (sourceWalker == NULL) { | ||
97 | return URI_TRUE; | ||
98 | } | ||
99 | destPrev = absWork->pathTail; | ||
100 | |||
101 | for (;;) { | ||
102 | URI_TYPE(PathSegment) * const dup = malloc(sizeof(URI_TYPE(PathSegment))); | ||
103 | if (dup == NULL) { | ||
104 | destPrev->next = NULL; | ||
105 | absWork->pathTail = destPrev; | ||
106 | return URI_FALSE; /* Raises malloc error */ | ||
107 | } | ||
108 | dup->text = sourceWalker->text; | ||
109 | destPrev->next = dup; | ||
110 | |||
111 | if (sourceWalker->next == NULL) { | ||
112 | absWork->pathTail = dup; | ||
113 | absWork->pathTail->next = NULL; | ||
114 | break; | ||
115 | } | ||
116 | destPrev = dup; | ||
117 | sourceWalker = sourceWalker->next; | ||
118 | } | ||
119 | |||
120 | return URI_TRUE; | ||
121 | } | ||
122 | |||
123 | |||
124 | static int URI_FUNC(ResolveAbsolutePathFlag)(URI_TYPE(Uri) * absWork) { | ||
125 | if (absWork == NULL) { | ||
126 | return URI_ERROR_NULL; | ||
127 | } | ||
128 | |||
129 | if (URI_FUNC(IsHostSet)(absWork) && absWork->absolutePath) { | ||
130 | /* Empty segment needed, instead? */ | ||
131 | if (absWork->pathHead == NULL) { | ||
132 | URI_TYPE(PathSegment) * const segment = malloc(sizeof(URI_TYPE(PathSegment))); | ||
133 | if (segment == NULL) { | ||
134 | return URI_ERROR_MALLOC; | ||
135 | } | ||
136 | segment->text.first = URI_FUNC(SafeToPointTo); | ||
137 | segment->text.afterLast = URI_FUNC(SafeToPointTo); | ||
138 | segment->next = NULL; | ||
139 | |||
140 | absWork->pathHead = segment; | ||
141 | absWork->pathTail = segment; | ||
142 | } | ||
143 | |||
144 | absWork->absolutePath = URI_FALSE; | ||
145 | } | ||
146 | |||
147 | return URI_SUCCESS; | ||
148 | } | ||
149 | |||
150 | |||
151 | static int URI_FUNC(AddBaseUriImpl)(URI_TYPE(Uri) * absDest, | ||
152 | const URI_TYPE(Uri) * relSource, | ||
153 | const URI_TYPE(Uri) * absBase, | ||
154 | UriResolutionOptions options) { | ||
155 | if (absDest == NULL) { | ||
156 | return URI_ERROR_NULL; | ||
157 | } | ||
158 | URI_FUNC(ResetUri)(absDest); | ||
159 | |||
160 | if ((relSource == NULL) || (absBase == NULL)) { | ||
161 | return URI_ERROR_NULL; | ||
162 | } | ||
163 | |||
164 | /* absBase absolute? */ | ||
165 | if (absBase->scheme.first == NULL) { | ||
166 | return URI_ERROR_ADDBASE_REL_BASE; | ||
167 | } | ||
168 | |||
169 | /* [00/32] -- A non-strict parser may ignore a scheme in the reference */ | ||
170 | /* [00/32] -- if it is identical to the base URI's scheme. */ | ||
171 | /* [00/32] if ((not strict) and (R.scheme == Base.scheme)) then */ | ||
172 | UriBool relSourceHasScheme = (relSource->scheme.first != NULL) ? URI_TRUE : URI_FALSE; | ||
173 | if ((options & URI_RESOLVE_IDENTICAL_SCHEME_COMPAT) | ||
174 | && (absBase->scheme.first != NULL) | ||
175 | && (relSource->scheme.first != NULL) | ||
176 | && (0 == URI_FUNC(CompareRange)(&(absBase->scheme), &(relSource->scheme)))) { | ||
177 | /* [00/32] undefine(R.scheme); */ | ||
178 | relSourceHasScheme = URI_FALSE; | ||
179 | /* [00/32] endif; */ | ||
180 | } | ||
181 | |||
182 | /* [01/32] if defined(R.scheme) then */ | ||
183 | if (relSourceHasScheme) { | ||
184 | /* [02/32] T.scheme = R.scheme; */ | ||
185 | absDest->scheme = relSource->scheme; | ||
186 | /* [03/32] T.authority = R.authority; */ | ||
187 | if (!URI_FUNC(CopyAuthority)(absDest, relSource)) { | ||
188 | return URI_ERROR_MALLOC; | ||
189 | } | ||
190 | /* [04/32] T.path = remove_dot_segments(R.path); */ | ||
191 | if (!URI_FUNC(CopyPath)(absDest, relSource)) { | ||
192 | return URI_ERROR_MALLOC; | ||
193 | } | ||
194 | if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) { | ||
195 | return URI_ERROR_MALLOC; | ||
196 | } | ||
197 | /* [05/32] T.query = R.query; */ | ||
198 | absDest->query = relSource->query; | ||
199 | /* [06/32] else */ | ||
200 | } else { | ||
201 | /* [07/32] if defined(R.authority) then */ | ||
202 | if (URI_FUNC(IsHostSet)(relSource)) { | ||
203 | /* [08/32] T.authority = R.authority; */ | ||
204 | if (!URI_FUNC(CopyAuthority)(absDest, relSource)) { | ||
205 | return URI_ERROR_MALLOC; | ||
206 | } | ||
207 | /* [09/32] T.path = remove_dot_segments(R.path); */ | ||
208 | if (!URI_FUNC(CopyPath)(absDest, relSource)) { | ||
209 | return URI_ERROR_MALLOC; | ||
210 | } | ||
211 | if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) { | ||
212 | return URI_ERROR_MALLOC; | ||
213 | } | ||
214 | /* [10/32] T.query = R.query; */ | ||
215 | absDest->query = relSource->query; | ||
216 | /* [11/32] else */ | ||
217 | } else { | ||
218 | /* [28/32] T.authority = Base.authority; */ | ||
219 | if (!URI_FUNC(CopyAuthority)(absDest, absBase)) { | ||
220 | return URI_ERROR_MALLOC; | ||
221 | } | ||
222 | /* [12/32] if (R.path == "") then */ | ||
223 | if (relSource->pathHead == NULL && !relSource->absolutePath) { | ||
224 | /* [13/32] T.path = Base.path; */ | ||
225 | if (!URI_FUNC(CopyPath)(absDest, absBase)) { | ||
226 | return URI_ERROR_MALLOC; | ||
227 | } | ||
228 | /* [14/32] if defined(R.query) then */ | ||
229 | if (relSource->query.first != NULL) { | ||
230 | /* [15/32] T.query = R.query; */ | ||
231 | absDest->query = relSource->query; | ||
232 | /* [16/32] else */ | ||
233 | } else { | ||
234 | /* [17/32] T.query = Base.query; */ | ||
235 | absDest->query = absBase->query; | ||
236 | /* [18/32] endif; */ | ||
237 | } | ||
238 | /* [19/32] else */ | ||
239 | } else { | ||
240 | /* [20/32] if (R.path starts-with "/") then */ | ||
241 | if (relSource->absolutePath) { | ||
242 | int res; | ||
243 | /* [21/32] T.path = remove_dot_segments(R.path); */ | ||
244 | if (!URI_FUNC(CopyPath)(absDest, relSource)) { | ||
245 | return URI_ERROR_MALLOC; | ||
246 | } | ||
247 | res = URI_FUNC(ResolveAbsolutePathFlag)(absDest); | ||
248 | if (res != URI_SUCCESS) { | ||
249 | return res; | ||
250 | } | ||
251 | if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) { | ||
252 | return URI_ERROR_MALLOC; | ||
253 | } | ||
254 | /* [22/32] else */ | ||
255 | } else { | ||
256 | /* [23/32] T.path = merge(Base.path, R.path); */ | ||
257 | if (!URI_FUNC(CopyPath)(absDest, absBase)) { | ||
258 | return URI_ERROR_MALLOC; | ||
259 | } | ||
260 | if (!URI_FUNC(MergePath)(absDest, relSource)) { | ||
261 | return URI_ERROR_MALLOC; | ||
262 | } | ||
263 | /* [24/32] T.path = remove_dot_segments(T.path); */ | ||
264 | if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) { | ||
265 | return URI_ERROR_MALLOC; | ||
266 | } | ||
267 | |||
268 | if (!URI_FUNC(FixAmbiguity)(absDest)) { | ||
269 | return URI_ERROR_MALLOC; | ||
270 | } | ||
271 | /* [25/32] endif; */ | ||
272 | } | ||
273 | /* [26/32] T.query = R.query; */ | ||
274 | absDest->query = relSource->query; | ||
275 | /* [27/32] endif; */ | ||
276 | } | ||
277 | URI_FUNC(FixEmptyTrailSegment)(absDest); | ||
278 | /* [29/32] endif; */ | ||
279 | } | ||
280 | /* [30/32] T.scheme = Base.scheme; */ | ||
281 | absDest->scheme = absBase->scheme; | ||
282 | /* [31/32] endif; */ | ||
283 | } | ||
284 | /* [32/32] T.fragment = R.fragment; */ | ||
285 | absDest->fragment = relSource->fragment; | ||
286 | |||
287 | return URI_SUCCESS; | ||
288 | |||
289 | } | ||
290 | |||
291 | |||
292 | |||
293 | int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest, | ||
294 | const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase) { | ||
295 | const int res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, URI_RESOLVE_STRICTLY); | ||
296 | if ((res != URI_SUCCESS) && (absDest != NULL)) { | ||
297 | URI_FUNC(FreeUriMembers)(absDest); | ||
298 | } | ||
299 | return res; | ||
300 | } | ||
301 | |||
302 | |||
303 | |||
304 | int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absDest, | ||
305 | const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase, | ||
306 | UriResolutionOptions options) { | ||
307 | const int res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, options); | ||
308 | if ((res != URI_SUCCESS) && (absDest != NULL)) { | ||
309 | URI_FUNC(FreeUriMembers)(absDest); | ||
310 | } | ||
311 | return res; | ||
312 | } | ||
313 | |||
314 | |||
315 | |||
316 | #endif | ||
diff --git a/plugins/uriparser/UriShorten.c b/plugins/uriparser/UriShorten.c new file mode 100644 index 00000000..c839ae53 --- /dev/null +++ b/plugins/uriparser/UriShorten.c | |||
@@ -0,0 +1,320 @@ | |||
1 | /* | ||
2 | * uriparser - RFC 3986 URI parsing library | ||
3 | * | ||
4 | * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | ||
5 | * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above | ||
13 | * copyright notice, this list of conditions and the following | ||
14 | * disclaimer. | ||
15 | * | ||
16 | * * Redistributions in binary form must reproduce the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the <ORGANIZATION> nor the names of its | ||
22 | * contributors may be used to endorse or promote products | ||
23 | * derived from this software without specific prior written | ||
24 | * permission. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
30 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
32 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
37 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | /* What encodings are enabled? */ | ||
41 | #include <uriparser/UriDefsConfig.h> | ||
42 | #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | ||
43 | /* Include SELF twice */ | ||
44 | # ifdef URI_ENABLE_ANSI | ||
45 | # define URI_PASS_ANSI 1 | ||
46 | # include "UriShorten.c" | ||
47 | # undef URI_PASS_ANSI | ||
48 | # endif | ||
49 | # ifdef URI_ENABLE_UNICODE | ||
50 | # define URI_PASS_UNICODE 1 | ||
51 | # include "UriShorten.c" | ||
52 | # undef URI_PASS_UNICODE | ||
53 | # endif | ||
54 | #else | ||
55 | # ifdef URI_PASS_ANSI | ||
56 | # include <uriparser/UriDefsAnsi.h> | ||
57 | # else | ||
58 | # include <uriparser/UriDefsUnicode.h> | ||
59 | # include <wchar.h> | ||
60 | # endif | ||
61 | |||
62 | |||
63 | |||
64 | #ifndef URI_DOXYGEN | ||
65 | # include <uriparser/Uri.h> | ||
66 | # include "UriCommon.h" | ||
67 | #endif | ||
68 | |||
69 | |||
70 | |||
71 | static URI_INLINE UriBool URI_FUNC(AppendSegment)(URI_TYPE(Uri) * uri, | ||
72 | const URI_CHAR * first, const URI_CHAR * afterLast) { | ||
73 | /* Create segment */ | ||
74 | URI_TYPE(PathSegment) * segment = malloc(1 * sizeof(URI_TYPE(PathSegment))); | ||
75 | if (segment == NULL) { | ||
76 | return URI_FALSE; /* Raises malloc error */ | ||
77 | } | ||
78 | segment->next = NULL; | ||
79 | segment->text.first = first; | ||
80 | segment->text.afterLast = afterLast; | ||
81 | |||
82 | /* Put into chain */ | ||
83 | if (uri->pathTail == NULL) { | ||
84 | uri->pathHead = segment; | ||
85 | } else { | ||
86 | uri->pathTail->next = segment; | ||
87 | } | ||
88 | uri->pathTail = segment; | ||
89 | |||
90 | return URI_TRUE; | ||
91 | } | ||
92 | |||
93 | |||
94 | |||
95 | static URI_INLINE UriBool URI_FUNC(EqualsAuthority)(const URI_TYPE(Uri) * first, | ||
96 | const URI_TYPE(Uri) * second) { | ||
97 | /* IPv4 */ | ||
98 | if (first->hostData.ip4 != NULL) { | ||
99 | return ((second->hostData.ip4 != NULL) | ||
100 | && !memcmp(first->hostData.ip4->data, | ||
101 | second->hostData.ip4->data, 4)) ? URI_TRUE : URI_FALSE; | ||
102 | } | ||
103 | |||
104 | /* IPv6 */ | ||
105 | if (first->hostData.ip6 != NULL) { | ||
106 | return ((second->hostData.ip6 != NULL) | ||
107 | && !memcmp(first->hostData.ip6->data, | ||
108 | second->hostData.ip6->data, 16)) ? URI_TRUE : URI_FALSE; | ||
109 | } | ||
110 | |||
111 | /* IPvFuture */ | ||
112 | if (first->hostData.ipFuture.first != NULL) { | ||
113 | return ((second->hostData.ipFuture.first != NULL) | ||
114 | && !URI_STRNCMP(first->hostData.ipFuture.first, | ||
115 | second->hostData.ipFuture.first, | ||
116 | first->hostData.ipFuture.afterLast | ||
117 | - first->hostData.ipFuture.first)) | ||
118 | ? URI_TRUE : URI_FALSE; | ||
119 | } | ||
120 | |||
121 | if (first->hostText.first != NULL) { | ||
122 | return ((second->hostText.first != NULL) | ||
123 | && !URI_STRNCMP(first->hostText.first, | ||
124 | second->hostText.first, | ||
125 | first->hostText.afterLast | ||
126 | - first->hostText.first)) ? URI_TRUE : URI_FALSE; | ||
127 | } | ||
128 | |||
129 | return (second->hostText.first == NULL); | ||
130 | } | ||
131 | |||
132 | |||
133 | |||
134 | int URI_FUNC(RemoveBaseUriImpl)(URI_TYPE(Uri) * dest, | ||
135 | const URI_TYPE(Uri) * absSource, | ||
136 | const URI_TYPE(Uri) * absBase, | ||
137 | UriBool domainRootMode) { | ||
138 | if (dest == NULL) { | ||
139 | return URI_ERROR_NULL; | ||
140 | } | ||
141 | URI_FUNC(ResetUri)(dest); | ||
142 | |||
143 | if ((absSource == NULL) || (absBase == NULL)) { | ||
144 | return URI_ERROR_NULL; | ||
145 | } | ||
146 | |||
147 | /* absBase absolute? */ | ||
148 | if (absBase->scheme.first == NULL) { | ||
149 | return URI_ERROR_REMOVEBASE_REL_BASE; | ||
150 | } | ||
151 | |||
152 | /* absSource absolute? */ | ||
153 | if (absSource->scheme.first == NULL) { | ||
154 | return URI_ERROR_REMOVEBASE_REL_SOURCE; | ||
155 | } | ||
156 | |||
157 | /* [01/50] if (A.scheme != Base.scheme) then */ | ||
158 | if (URI_STRNCMP(absSource->scheme.first, absBase->scheme.first, | ||
159 | absSource->scheme.afterLast - absSource->scheme.first)) { | ||
160 | /* [02/50] T.scheme = A.scheme; */ | ||
161 | dest->scheme = absSource->scheme; | ||
162 | /* [03/50] T.authority = A.authority; */ | ||
163 | if (!URI_FUNC(CopyAuthority)(dest, absSource)) { | ||
164 | return URI_ERROR_MALLOC; | ||
165 | } | ||
166 | /* [04/50] T.path = A.path; */ | ||
167 | if (!URI_FUNC(CopyPath)(dest, absSource)) { | ||
168 | return URI_ERROR_MALLOC; | ||
169 | } | ||
170 | /* [05/50] else */ | ||
171 | } else { | ||
172 | /* [06/50] undef(T.scheme); */ | ||
173 | /* NOOP */ | ||
174 | /* [07/50] if (A.authority != Base.authority) then */ | ||
175 | if (!URI_FUNC(EqualsAuthority)(absSource, absBase)) { | ||
176 | /* [08/50] T.authority = A.authority; */ | ||
177 | if (!URI_FUNC(CopyAuthority)(dest, absSource)) { | ||
178 | return URI_ERROR_MALLOC; | ||
179 | } | ||
180 | /* [09/50] T.path = A.path; */ | ||
181 | if (!URI_FUNC(CopyPath)(dest, absSource)) { | ||
182 | return URI_ERROR_MALLOC; | ||
183 | } | ||
184 | /* [10/50] else */ | ||
185 | } else { | ||
186 | /* [11/50] if domainRootMode then */ | ||
187 | if (domainRootMode == URI_TRUE) { | ||
188 | /* [12/50] undef(T.authority); */ | ||
189 | /* NOOP */ | ||
190 | /* [13/50] if (first(A.path) == "") then */ | ||
191 | /* GROUPED */ | ||
192 | /* [14/50] T.path = "/." + A.path; */ | ||
193 | /* GROUPED */ | ||
194 | /* [15/50] else */ | ||
195 | /* GROUPED */ | ||
196 | /* [16/50] T.path = A.path; */ | ||
197 | /* GROUPED */ | ||
198 | /* [17/50] endif; */ | ||
199 | if (!URI_FUNC(CopyPath)(dest, absSource)) { | ||
200 | return URI_ERROR_MALLOC; | ||
201 | } | ||
202 | dest->absolutePath = URI_TRUE; | ||
203 | |||
204 | if (!URI_FUNC(FixAmbiguity)(dest)) { | ||
205 | return URI_ERROR_MALLOC; | ||
206 | } | ||
207 | /* [18/50] else */ | ||
208 | } else { | ||
209 | const URI_TYPE(PathSegment) * sourceSeg = absSource->pathHead; | ||
210 | const URI_TYPE(PathSegment) * baseSeg = absBase->pathHead; | ||
211 | /* [19/50] bool pathNaked = true; */ | ||
212 | UriBool pathNaked = URI_TRUE; | ||
213 | /* [20/50] undef(last(Base.path)); */ | ||
214 | /* NOOP */ | ||
215 | /* [21/50] T.path = ""; */ | ||
216 | dest->absolutePath = URI_FALSE; | ||
217 | /* [22/50] while (first(A.path) == first(Base.path)) do */ | ||
218 | while ((sourceSeg != NULL) && (baseSeg != NULL) | ||
219 | && !URI_STRNCMP(sourceSeg->text.first, baseSeg->text.first, | ||
220 | sourceSeg->text.afterLast - sourceSeg->text.first) | ||
221 | && !((sourceSeg->text.first == sourceSeg->text.afterLast) | ||
222 | && ((sourceSeg->next == NULL) != (baseSeg->next == NULL)))) { | ||
223 | /* [23/50] A.path++; */ | ||
224 | sourceSeg = sourceSeg->next; | ||
225 | /* [24/50] Base.path++; */ | ||
226 | baseSeg = baseSeg->next; | ||
227 | /* [25/50] endwhile; */ | ||
228 | } | ||
229 | /* [26/50] while defined(first(Base.path)) do */ | ||
230 | while ((baseSeg != NULL) && (baseSeg->next != NULL)) { | ||
231 | /* [27/50] Base.path++; */ | ||
232 | baseSeg = baseSeg->next; | ||
233 | /* [28/50] T.path += "../"; */ | ||
234 | if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstParent), | ||
235 | URI_FUNC(ConstParent) + 2)) { | ||
236 | return URI_ERROR_MALLOC; | ||
237 | } | ||
238 | /* [29/50] pathNaked = false; */ | ||
239 | pathNaked = URI_FALSE; | ||
240 | /* [30/50] endwhile; */ | ||
241 | } | ||
242 | /* [31/50] while defined(first(A.path)) do */ | ||
243 | while (sourceSeg != NULL) { | ||
244 | /* [32/50] if pathNaked then */ | ||
245 | if (pathNaked == URI_TRUE) { | ||
246 | /* [33/50] if (first(A.path) contains ":") then */ | ||
247 | UriBool containsColon = URI_FALSE; | ||
248 | const URI_CHAR * ch = sourceSeg->text.first; | ||
249 | for (; ch < sourceSeg->text.afterLast; ch++) { | ||
250 | if (*ch == _UT(':')) { | ||
251 | containsColon = URI_TRUE; | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if (containsColon) { | ||
257 | /* [34/50] T.path += "./"; */ | ||
258 | if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd), | ||
259 | URI_FUNC(ConstPwd) + 1)) { | ||
260 | return URI_ERROR_MALLOC; | ||
261 | } | ||
262 | /* [35/50] elseif (first(A.path) == "") then */ | ||
263 | } else if (sourceSeg->text.first == sourceSeg->text.afterLast) { | ||
264 | /* [36/50] T.path += "/."; */ | ||
265 | if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd), | ||
266 | URI_FUNC(ConstPwd) + 1)) { | ||
267 | return URI_ERROR_MALLOC; | ||
268 | } | ||
269 | /* [37/50] endif; */ | ||
270 | } | ||
271 | /* [38/50] endif; */ | ||
272 | } | ||
273 | /* [39/50] T.path += first(A.path); */ | ||
274 | if (!URI_FUNC(AppendSegment)(dest, sourceSeg->text.first, | ||
275 | sourceSeg->text.afterLast)) { | ||
276 | return URI_ERROR_MALLOC; | ||
277 | } | ||
278 | /* [40/50] pathNaked = false; */ | ||
279 | pathNaked = URI_FALSE; | ||
280 | /* [41/50] A.path++; */ | ||
281 | sourceSeg = sourceSeg->next; | ||
282 | /* [42/50] if defined(first(A.path)) then */ | ||
283 | /* NOOP */ | ||
284 | /* [43/50] T.path += + "/"; */ | ||
285 | /* NOOP */ | ||
286 | /* [44/50] endif; */ | ||
287 | /* NOOP */ | ||
288 | /* [45/50] endwhile; */ | ||
289 | } | ||
290 | /* [46/50] endif; */ | ||
291 | } | ||
292 | /* [47/50] endif; */ | ||
293 | } | ||
294 | /* [48/50] endif; */ | ||
295 | } | ||
296 | /* [49/50] T.query = A.query; */ | ||
297 | dest->query = absSource->query; | ||
298 | /* [50/50] T.fragment = A.fragment; */ | ||
299 | dest->fragment = absSource->fragment; | ||
300 | |||
301 | return URI_SUCCESS; | ||
302 | } | ||
303 | |||
304 | |||
305 | |||
306 | int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, | ||
307 | const URI_TYPE(Uri) * absSource, | ||
308 | const URI_TYPE(Uri) * absBase, | ||
309 | UriBool domainRootMode) { | ||
310 | const int res = URI_FUNC(RemoveBaseUriImpl)(dest, absSource, | ||
311 | absBase, domainRootMode); | ||
312 | if ((res != URI_SUCCESS) && (dest != NULL)) { | ||
313 | URI_FUNC(FreeUriMembers)(dest); | ||
314 | } | ||
315 | return res; | ||
316 | } | ||
317 | |||
318 | |||
319 | |||
320 | #endif | ||