diff options
-rw-r--r-- | !NetSurf/Resources/CSS,f79 | 4 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | frontends/amiga/os3support.h | 1 | ||||
-rw-r--r-- | frontends/riscos/gui.c | 6 | ||||
-rw-r--r-- | render/box_textarea.c | 13 | ||||
-rw-r--r-- | test/Makefile | 13 | ||||
-rw-r--r-- | utils/Makefile | 1 | ||||
-rw-r--r-- | utils/nsurl/Makefile | 7 | ||||
-rw-r--r-- | utils/nsurl/nsurl.c | 850 | ||||
-rw-r--r-- | utils/nsurl/parse.c (renamed from utils/nsurl.c) | 1053 | ||||
-rw-r--r-- | utils/nsurl/private.h | 215 |
11 files changed, 1165 insertions, 1012 deletions
diff --git a/!NetSurf/Resources/CSS,f79 b/!NetSurf/Resources/CSS,f79 index 44268d6a7..2aee83b7c 100644 --- a/!NetSurf/Resources/CSS,f79 +++ b/!NetSurf/Resources/CSS,f79 @@ -115,7 +115,7 @@ input, button { background-color: #fff; color: #000; text-align: left; font-family: sans-serif; width: auto; height: auto; overflow: hidden; border: 1px solid #444; padding: 2px 3px; line-height: 1.33; margin: 1px; } -input[readonly] { background-color: #ddd; color: #333; } +input[disabled] { background-color: #ddd; color: #333; } input[type=button], input[type=reset], input[type=submit], button { background-color: #d9d9d9; color: #000; text-align: center; border: 2px outset #d9d9d9; padding: 1px 0.5em; } @@ -137,7 +137,7 @@ select:after { content: "\25bc"; border-left: 2px ridge #d9d9d9; } textarea { background-color: #fff; color: #000; text-align: left; font-family: monospace; width: auto; height: auto; overflow: scroll; margin: 1px; border: 1px solid #333; padding: 1px 3px; } -textarea[readonly] { background-color: #ddd; color: #333; } +textarea[disabled] { background-color: #ddd; color: #333; } fieldset { display: block; border: thin solid #888; margin: 1.12em 0; } @@ -621,12 +621,22 @@ include utils/Makefile # http utility sources include utils/http/Makefile +# nsurl utility sources +include utils/nsurl/Makefile + # Desktop sources include desktop/Makefile # S_COMMON are sources common to all builds -S_COMMON := $(S_CONTENT) $(S_FETCHERS) $(S_RENDER) $(S_UTILS) $(S_HTTP) \ - $(S_DESKTOP) $(S_JAVASCRIPT_BINDING) +S_COMMON := \ + $(S_CONTENT) \ + $(S_FETCHERS) \ + $(S_RENDER) \ + $(S_UTILS) \ + $(S_HTTP) \ + $(S_NSURL) \ + $(S_DESKTOP) \ + $(S_JAVASCRIPT_BINDING) # ---------------------------------------------------------------------------- diff --git a/frontends/amiga/os3support.h b/frontends/amiga/os3support.h index 856439bd8..aa3027d36 100644 --- a/frontends/amiga/os3support.h +++ b/frontends/amiga/os3support.h @@ -116,6 +116,7 @@ #define BGBACKFILL JAM1 #define OFF_OPEN 0 #define AFF_OTAG 0 +#define ML_SEPARATOR NM_BARLABEL /* Renamed structures */ #define AnchorPathOld AnchorPath diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c index 27b81d92e..540a8be54 100644 --- a/frontends/riscos/gui.c +++ b/frontends/riscos/gui.c @@ -1179,6 +1179,9 @@ static nserror gui_init(int argc, char** argv) /* Initialise save complete functionality */ save_complete_init(); + /* Initialise the font subsystem */ + nsfont_init(); + /* Load in visited URLs, Cookies, and hostlist */ urldb_load(nsoption_charp(url_path)); urldb_load_cookies(nsoption_charp(cookie_file)); @@ -1212,9 +1215,6 @@ static nserror gui_init(int argc, char** argv) ro_message_register_route(message_WINDOW_INFO, ro_msg_window_info); - /* Initialise the font subsystem */ - nsfont_init(); - /* Initialise global information */ ro_gui_get_screen_properties(); ro_gui_wimp_get_desktop_font(); diff --git a/render/box_textarea.c b/render/box_textarea.c index 44f5c0b16..1586d71c4 100644 --- a/render/box_textarea.c +++ b/render/box_textarea.c @@ -239,6 +239,7 @@ bool box_textarea_create_textarea(html_content *html, textarea_flags ta_flags; plot_font_style_t fstyle; bool read_only = false; + bool disabled = false; struct form_control *gadget = box->gadget; const char *text; @@ -257,6 +258,11 @@ bool box_textarea_create_textarea(html_content *html, if (err != DOM_NO_ERR) return false; + err = dom_html_text_area_element_get_disabled( + textarea, &disabled); + if (err != DOM_NO_ERR) + return false; + /* Get the textarea's initial content */ err = dom_html_text_area_element_get_value(textarea, &dom_text); if (err != DOM_NO_ERR) @@ -270,6 +276,11 @@ bool box_textarea_create_textarea(html_content *html, if (err != DOM_NO_ERR) return false; + err = dom_html_input_element_get_disabled( + input, &disabled); + if (err != DOM_NO_ERR) + return false; + if (gadget->type == GADGET_PASSWORD) ta_flags = TEXTAREA_PASSWORD; else @@ -289,7 +300,7 @@ bool box_textarea_create_textarea(html_content *html, text = ""; } - if (read_only) + if (read_only || disabled) ta_flags |= TEXTAREA_READONLY; gadget->data.text.data.gadget = gadget; diff --git a/test/Makefile b/test/Makefile index d5e9d0033..1f884dcc9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -13,12 +13,15 @@ TESTS := \ time #llcache # nsurl sources -nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \ +nsurl_SRCS := utils/corestrings.c utils/nsurl/nsurl.c \ + utils/nsurl/parse.c \ + utils/idna.c utils/punycode.c \ test/log.c test/nsurl.c # url database test sources urldbtest_SRCS := content/urldb.c \ - utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \ + utils/idna.c utils/bloom.c utils/nsoption.c \ + utils/nsurl/nsurl.c utils/nsurl/parse.c \ utils/corestrings.c utils/punycode.c \ utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \ test/log.c test/urldbtest.c @@ -30,7 +33,8 @@ llcache_SRCS := content/fetch.c content/fetchers/curl.c \ content/urldb.c \ image/image_cache.c \ utils/base64.c utils/corestrings.c utils/hashtable.c \ - utils/nsurl.c utils/messages.c utils/url.c utils/useragent.c \ + utils/nsurl/nsurl.c utils/nsurl/parse.c \ + utils/messages.c utils/url.c utils/useragent.c \ utils/utils.c \ test/log.c test/llcache.c @@ -51,7 +55,8 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c # utility test sources utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \ - utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \ + utils/corestrings.c utils/nsurl/nsurl.c \ + utils/nsurl/parse.c utils/idna.c utils/punycode.c \ test/log.c test/utils.c # time test sources diff --git a/utils/Makefile b/utils/Makefile index 62b7e05e7..2f59501c2 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -12,7 +12,6 @@ S_UTILS := \ log.c \ messages.c \ nsoption.c \ - nsurl.c \ punycode.c \ talloc.c \ time.c \ diff --git a/utils/nsurl/Makefile b/utils/nsurl/Makefile new file mode 100644 index 000000000..71304b292 --- /dev/null +++ b/utils/nsurl/Makefile @@ -0,0 +1,7 @@ +# nsurl utils sources + +S_NSURL := \ + nsurl.c \ + parse.c + +S_NSURL := $(addprefix utils/nsurl/,$(S_NSURL))
\ No newline at end of file diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c new file mode 100644 index 000000000..7166a2707 --- /dev/null +++ b/utils/nsurl/nsurl.c @@ -0,0 +1,850 @@ +/* + * Copyright 2011 Michael Drake <tlsa@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * NetSurf URL handling implementation. + * + * This is the common implementation of all URL handling within the + * browser. This implementation is based upon RFC3986 although this has + * been superceeded by https://url.spec.whatwg.org/ which is based on + * actual contemporary implementations. + * + * Care must be taken with character encodings within this module as + * the specifications work with specific ascii ranges and must not be + * affected by locale. Hence the c library character type functions + * are not used. + */ + +#include <assert.h> +#include <libwapcaplet/libwapcaplet.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "utils/ascii.h" +#include "utils/corestrings.h" +#include "utils/errors.h" +#include "utils/idna.h" +#include "utils/log.h" +#include "utils/nsurl/private.h" +#include "utils/nsurl.h" +#include "utils/utils.h" + + +/** + * Compare two component values. + * + * Sets match to false if the components are not the same. + * Does nothing if the components are the same, so ensure match is + * preset to true. + */ +#define nsurl__component_compare(c1, c2, match) \ + if (c1 && c2 && lwc_error_ok == \ + lwc_string_isequal(c1, c2, match)) { \ + /* do nothing */ \ + } else if (c1 || c2) { \ + *match = false; \ + } + + + +/****************************************************************************** + * NetSurf URL Public API * + ******************************************************************************/ + +/* exported interface, documented in nsurl.h */ +nsurl *nsurl_ref(nsurl *url) +{ + assert(url != NULL); + + url->count++; + + return url; +} + + +/* exported interface, documented in nsurl.h */ +void nsurl_unref(nsurl *url) +{ + assert(url != NULL); + assert(url->count > 0); + + if (--url->count > 0) + return; + +#ifdef NSURL_DEBUG + nsurl__dump(url); +#endif + + /* Release lwc strings */ + nsurl__components_destroy(&url->components); + + /* Free the NetSurf URL */ + free(url); +} + + +/* exported interface, documented in nsurl.h */ +bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts) +{ + bool match = true; + + assert(url1 != NULL); + assert(url2 != NULL); + + /* Compare URL components */ + + /* Path, host and query first, since they're most likely to differ */ + + if (parts & NSURL_PATH) { + nsurl__component_compare(url1->components.path, + url2->components.path, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_HOST) { + nsurl__component_compare(url1->components.host, + url2->components.host, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_QUERY) { + nsurl__component_compare(url1->components.query, + url2->components.query, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_SCHEME) { + nsurl__component_compare(url1->components.scheme, + url2->components.scheme, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_USERNAME) { + nsurl__component_compare(url1->components.username, + url2->components.username, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_PASSWORD) { + nsurl__component_compare(url1->components.password, + url2->components.password, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_PORT) { + nsurl__component_compare(url1->components.port, + url2->components.port, &match); + + if (match == false) + return false; + } + + if (parts & NSURL_FRAGMENT) { + nsurl__component_compare(url1->components.fragment, + url2->components.fragment, &match); + + if (match == false) + return false; + } + + return true; +} + + +/* exported interface, documented in nsurl.h */ +nserror nsurl_get(const nsurl *url, nsurl_component parts, + char **url_s, size_t *url_l) +{ + assert(url != NULL); + + return nsurl__components_to_string(&(url->components), parts, 0, + url_s, url_l); +} + + +/* exported interface, documented in nsurl.h */ +lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part) +{ + assert(url != NULL); + + switch (part) { + case NSURL_SCHEME: + return (url->components.scheme != NULL) ? + lwc_string_ref(url->components.scheme) : NULL; + + case NSURL_USERNAME: + return (url->components.username != NULL) ? + lwc_string_ref(url->components.username) : NULL; + + case NSURL_PASSWORD: + return (url->components.password != NULL) ? + lwc_string_ref(url->components.password) : NULL; + + case NSURL_HOST: + return (url->components.host != NULL) ? + lwc_string_ref(url->components.host) : NULL; + + case NSURL_PORT: + return (url->components.port != NULL) ? + lwc_string_ref(url->components.port) : NULL; + + case NSURL_PATH: + return (url->components.path != NULL) ? + lwc_string_ref(url->components.path) : NULL; + + case NSURL_QUERY: + return (url->components.query != NULL) ? + lwc_string_ref(url->components.query) : NULL; + + case NSURL_FRAGMENT: + return (url->components.fragment != NULL) ? + lwc_string_ref(url->components.fragment) : NULL; + + default: + LOG("Unsupported value passed to part param."); + assert(0); + } + + return NULL; +} + + +/* exported interface, documented in nsurl.h */ +bool nsurl_has_component(const nsurl *url, nsurl_component part) +{ + assert(url != NULL); + + switch (part) { + case NSURL_SCHEME: + if (url->components.scheme != NULL) + return true; + else + return false; + + case NSURL_CREDENTIALS: + /* Only username required for credentials section */ + /* Fall through */ + case NSURL_USERNAME: + if (url->components.username != NULL) + return true; + else + return false; + + case NSURL_PASSWORD: + if (url->components.password != NULL) + return true; + else + return false; + + case NSURL_HOST: + if (url->components.host != NULL) + return true; + else + return false; + + case NSURL_PORT: + if (url->components.port != NULL) + return true; + else + return false; + + case NSURL_PATH: + if (url->components.path != NULL) + return true; + else + return false; + + case NSURL_QUERY: + if (url->components.query != NULL) + return true; + else + return false; + + case NSURL_FRAGMENT: + if (url->components.fragment != NULL) + return true; + else + return false; + + default: + LOG("Unsupported value passed to part param."); + assert(0); + } + + return false; +} + + +/* exported interface, documented in nsurl.h */ +const char *nsurl_access(const nsurl *url) +{ + assert(url != NULL); + + return url->string; +} + + +/* exported interface, documented in nsurl.h */ +nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l) +{ + nserror err; + lwc_string *host; + char *idna_host = NULL; + size_t idna_host_len; + char *scheme = NULL; + size_t scheme_len; + char *path = NULL; + size_t path_len; + + assert(url != NULL); + + if (url->components.host == NULL) { + return nsurl_get(url, NSURL_WITH_FRAGMENT, url_s, url_l); + } + + host = url->components.host; + err = idna_decode(lwc_string_data(host), lwc_string_length(host), + &idna_host, &idna_host_len); + if (err != NSERROR_OK) { + goto cleanup; + } + + err = nsurl_get(url, + NSURL_SCHEME | NSURL_CREDENTIALS, + &scheme, &scheme_len); + if (err != NSERROR_OK) { + goto cleanup; + } + + err = nsurl_get(url, + NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT, + &path, &path_len); + if (err != NSERROR_OK) { + goto cleanup; + } + + *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */ + *url_s = malloc(*url_l); + + if (*url_s == NULL) { + err = NSERROR_NOMEM; + goto cleanup; + } + + snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path); + + err = NSERROR_OK; + +cleanup: + free(idna_host); + free(scheme); + free(path); + + return err; +} + + +/* exported interface, documented in nsurl.h */ +const char *nsurl_access_leaf(const nsurl *url) +{ + size_t path_len; + const char *path; + const char *leaf; + + assert(url != NULL); + + if (url->components.path == NULL) + return ""; + + path = lwc_string_data(url->components.path); + path_len = lwc_string_length(url->components.path); + + if (path_len == 0) + return ""; + + if (path_len == 1 && *path == '/') + return "/"; + + leaf = path + path_len; + + do { + leaf--; + } while ((leaf != path) && (*leaf != '/')); + + if (*leaf == '/') + leaf++; + + return leaf; +} + + +/* exported interface, documented in nsurl.h */ +size_t nsurl_length(const nsurl *url) +{ + assert(url != NULL); + + return url->length; +} + + +/* exported interface, documented in nsurl.h */ +uint32_t nsurl_hash(const nsurl *url) +{ + assert(url != NULL); + + return url->hash; +} + + +/* exported interface, documented in nsurl.h */ +nserror nsurl_defragment(const nsurl *url, nsurl **no_frag) +{ + size_t length; + char *pos; + + assert(url != NULL); + + /* check for source url having no fragment already */ + if (url->components.fragment == NULL) { + *no_frag = (nsurl *)url; + + (*no_frag)->count++; + + return NSERROR_OK; + } + + /* Find the change in length from url to new_url */ + length = url->length; + if (url->components.fragment != NULL) { + length -= 1 + lwc_string_length(url->components.fragment); + } + + /* Create NetSurf URL object */ + *no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */ + if (*no_frag == NULL) { + return NSERROR_NOMEM; + } + + /* Copy components */ + (*no_frag)->components.scheme = + nsurl__component_copy(url->components.scheme); + (*no_frag)->components.username = + nsurl__component_copy(url->components.username); + (*no_frag)->components.password = + nsurl__component_copy(url->components.password); + (*no_frag)->components.host = + nsurl__component_copy(url->components.host); + (*no_frag)->components.port = + nsurl__component_copy(url->components.port); + (*no_frag)->components.path = + nsurl__component_copy(url->components.path); + (*no_frag)->components.query = + nsurl__component_copy(url->components.query); + (*no_frag)->components.fragment = NULL; + + (*no_frag)->components.scheme_type = url->components.scheme_type; + + (*no_frag)->length = length; + + /* Fill out the url string */ + pos = (*no_frag)->string; + memcpy(pos, url->string, length); + pos += length; + *pos = '\0'; + + /* Get the nsurl's hash */ + nsurl__calc_hash(*no_frag); + + /* Give the URL a reference */ + (*no_frag)->count = 1; + + return NSERROR_OK; +} + + +/* exported interface, documented in nsurl.h */ +nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url) +{ + int frag_len; + int base_len; + char *pos; + size_t len; + + assert(url != NULL); + assert(frag != NULL); + + /* Find the change in length from url to new_url */ + base_len = url->length; + if (url->components.fragment != NULL) { + base_len -= 1 + lwc_string_length(url->components.fragment); + } + frag_len = lwc_string_length(frag); + + /* Set new_url's length */ + len = base_len + 1 /* # */ + frag_len; + + /* Create NetSurf URL object */ + *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ + if (*new_url == NULL) { + return NSERROR_NOMEM; + } + + (*new_url)->length = len; + + /* Set string */ + pos = (*new_url)->string; + memcpy(pos, url->string, base_len); + pos += base_len; + *pos = '#'; + memcpy(++pos, lwc_string_data(frag), frag_len); + pos += frag_len; + *pos = '\0'; + + /* Copy components */ + (*new_url)->components.scheme = + nsurl__component_copy(url->components.scheme); + (*new_url)->components.username = + nsurl__component_copy(url->components.username); + (*new_url)->components.password = + nsurl__component_copy(url->components.password); + (*new_url)->components.host = + nsurl__component_copy(url->components.host); + (*new_url)->components.port = + nsurl__component_copy(url->components.port); + (*new_url)->components.path = + nsurl__component_copy(url->components.path); + (*new_url)->components.query = + nsurl__component_copy(url->components.query); + (*new_url)->components.fragment = + lwc_string_ref(frag); + + (*new_url)->components.scheme_type = url->components.scheme_type; + + /* Get the nsurl's hash */ + nsurl__calc_hash(*new_url); + + /* Give the URL a reference */ + (*new_url)->count = 1; + + return NSERROR_OK; +} + + +/* exported interface, documented in nsurl.h */ +nserror nsurl_replace_query(const nsurl *url, const char *query, + nsurl **new_url) +{ + int query_len; /* Length of new query string, including '?' */ + int frag_len = 0; /* Length of fragment, including '#' */ + int base_len; /* Length of URL up to start of query */ + char *pos; + size_t len; + lwc_string *lwc_query; + + assert(url != NULL); + assert(query != NULL); + assert(query[0] == '?'); + + /* Get the length of the new query */ + query_len = strlen(query); + + /* Find the change in length from url to new_url */ + base_len = url->length; + if (url->components.query != NULL) { + base_len -= lwc_string_length(url->components.query); + } + if (url->components.fragment != NULL) { + frag_len = 1 + lwc_string_length(url->components.fragment); + base_len -= frag_len; + } + + /* Set new_url's length */ + len = base_len + query_len + frag_len; + + /* Create NetSurf URL object */ + *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ + if (*new_url == NULL) { + return NSERROR_NOMEM; + } + + if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) { + free(*new_url); + return NSERROR_NOMEM; + } + + (*new_url)->length = len; + + /* Set string */ + pos = (*new_url)->string; + memcpy(pos, url->string, base_len); + pos += base_len; + memcpy(pos, query, query_len); + pos += query_len; + if (url->components.fragment != NULL) { + const char *frag = lwc_string_data(url->components.fragment); + *pos = '#'; + memcpy(++pos, frag, frag_len - 1); + pos += frag_len - 1; + } + *pos = '\0'; + + /* Copy components */ + (*new_url)->components.scheme = + nsurl__component_copy(url->components.scheme); + (*new_url)->components.username = + nsurl__component_copy(url->components.username); + (*new_url)->components.password = + nsurl__component_copy(url->components.password); + (*new_url)->components.host = + nsurl__component_copy(url->components.host); + (*new_url)->components.port = + nsurl__component_copy(url->components.port); + (*new_url)->components.path = + nsurl__component_copy(url->components.path); + (*new_url)->components.query = lwc_query; + (*new_url)->components.fragment = + nsurl__component_copy(url->components.fragment); + + (*new_url)->components.scheme_type = url->components.scheme_type; + + /* Get the nsurl's hash */ + nsurl__calc_hash(*new_url); + + /* Give the URL a reference */ + (*new_url)->count = 1; + + return NSERROR_OK; +} + + +/* exported interface documented in utils/nsurl.h */ +nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions) +{ + const char *data; + size_t len; + size_t pos; + bool match; + char *name; + + assert(url != NULL); + + *result = 0; + + /* extract the last component of the path, if possible */ + if ((url->components.path != NULL) && + (lwc_string_length(url->components.path) != 0) && + (lwc_string_isequal(url->components.path, + corestring_lwc_slash_, &match) == lwc_error_ok) && + (match == false)) { + bool first = true; + bool keep_looking; + + /* Get hold of the string data we're examining */ + data = lwc_string_data(url->components.path); + len = lwc_string_length(url->components.path); + pos = len; + + do { + keep_looking = false; + pos--; + + /* Find last '/' with stuff after it */ + while (pos != 0) { + if (data[pos] == '/' && pos < len - 1) { + break; + } + pos--; + } + + if (pos == 0) { + break; + } + + if (first) { + if (strncasecmp("/default.", data + pos, + SLEN("/default.")) == 0) { + keep_looking = true; + + } else if (strncasecmp("/index.", + data + pos, + 6) == 0) { + keep_looking = true; + + } + first = false; + } + + } while (keep_looking); + + if (data[pos] == '/') + pos++; + + if (strncasecmp("default.", data + pos, 8) != 0 && + strncasecmp("index.", data + pos, 6) != 0) { + size_t end = pos; + while (data[end] != '\0' && data[end] != '/') { + end++; + } + if (end - pos != 0) { + name = malloc(end - pos + 1); + if (name == NULL) { + return NSERROR_NOMEM; + } + memcpy(name, data + pos, end - pos); + name[end - pos] = '\0'; + if (remove_extensions) { + /* strip any extenstion */ + char *dot = strchr(name, '.'); + if (dot && dot != name) { + *dot = '\0'; + } + } + *result = name; + return NSERROR_OK; + } + } + } + + if (url->components.host != NULL) { + name = strdup(lwc_string_data(url->components.host)); + + for (pos = 0; name[pos] != '\0'; pos++) { + if (name[pos] == '.') { + name[pos] = '_'; + } + } + + *result = name; + return NSERROR_OK; + } + + return NSERROR_NOT_FOUND; +} + + +/* exported interface, documented in nsurl.h */ +nserror nsurl_parent(const nsurl *url, nsurl **new_url) +{ + lwc_string *lwc_path; + size_t old_path_len, new_path_len; + size_t len; + const char* path = NULL; + char *pos; + + assert(url != NULL); + + old_path_len = (url->components.path == NULL) ? 0 : + lwc_string_length(url->components.path); + + /* Find new path length */ + if (old_path_len == 0) { + new_path_len = old_path_len; + } else { + path = lwc_string_data(url->components.path); + + new_path_len = old_path_len; + if (old_path_len > 1) { + /* Skip over any trailing / */ + if (path[new_path_len - 1] == '/') + new_path_len--; + + /* Work back to next / */ + while (new_path_len > 0 && + path[new_path_len - 1] != '/') + new_path_len--; + } + } + + /* Find the length of new_url */ + len = url->length; + if (url->components.query != NULL) { + len -= lwc_string_length(url->components.query); + } + if (url->components.fragment != NULL) { + len -= 1; /* # */ + len -= lwc_string_length(url->components.fragment); + } + len -= old_path_len - new_path_len; + + /* Create NetSurf URL object */ + *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ + if (*new_url == NULL) { + return NSERROR_NOMEM; + } + + /* Make new path */ + if (old_path_len == 0) { + lwc_path = NULL; + } else if (old_path_len == new_path_len) { + lwc_path = lwc_string_ref(url->components.path); + } else { + if (lwc_intern_string(path, old_path_len - new_path_len, + &lwc_path) != lwc_error_ok) { + free(*new_url); + return NSERROR_NOMEM; + } + } + + (*new_url)->length = len; + + /* Set string */ + pos = (*new_url)->string; + memcpy(pos, url->string, len); + pos += len; + *pos = '\0'; + + /* Copy components */ + (*new_url)->components.scheme = + nsurl__component_copy(url->components.scheme); + (*new_url)->components.username = + nsurl__component_copy(url->components.username); + (*new_url)->components.password = + nsurl__component_copy(url->components.password); + (*new_url)->components.host = + nsurl__component_copy(url->components.host); + (*new_url)->components.port = + nsurl__component_copy(url->components.port); + (*new_url)->components.path = lwc_path; + (*new_url)->components.query = NULL; + (*new_url)->components.fragment = NULL; + + (*new_url)->components.scheme_type = url->components.scheme_type; + + /* Get the nsurl's hash */ + nsurl__calc_hash(*new_url); + + /* Give the URL a reference */ + (*new_url)->count = 1; + + return NSERROR_OK; +} + diff --git a/utils/nsurl.c b/utils/nsurl/parse.c index c5c614c55..89a10d244 100644 --- a/utils/nsurl.c +++ b/utils/nsurl/parse.c @@ -43,61 +43,9 @@ #include "utils/idna.h" #include "utils/log.h" #include "utils/nsurl.h" +#include "utils/nsurl/private.h" #include "utils/utils.h" -/* Define to enable NSURL debugging */ -#undef NSURL_DEBUG - -/** - * nsurl scheme type - */ -enum scheme_type { - NSURL_SCHEME_OTHER, - NSURL_SCHEME_HTTP, - NSURL_SCHEME_HTTPS, - NSURL_SCHEME_FTP, - NSURL_SCHEME_MAILTO -}; - -/** - * nsurl components - * - * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment] - * - * Note: - * "path" string includes preceding '/', if needed for the scheme - * "query" string always includes preceding '?' - * - * The other spanned punctuation is to be inserted when building URLs from - * components. - */ -struct nsurl_components { - lwc_string *scheme; - lwc_string *username; - lwc_string *password; - lwc_string *host; - lwc_string *port; - lwc_string *path; - lwc_string *query; - lwc_string *fragment; - - enum scheme_type scheme_type; -}; - - -/** - * NetSurf URL object - */ -struct nsurl { - struct nsurl_components components; - - int count; /* Number of references to NetSurf URL object */ - uint32_t hash; /* Hash value for nsurl identification */ - - size_t length; /* Length of string */ - char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */ -}; - /** Marker set, indicating positions of sections within a URL string */ struct url_markers { @@ -115,41 +63,7 @@ struct url_markers { size_t end; /** end of URL */ - enum scheme_type scheme_type; -}; - - -/** Marker set, indicating positions of sections within a URL string */ -struct nsurl_component_lengths { - size_t scheme; - size_t username; - size_t password; - size_t host; - size_t port; - size_t path; - size_t query; - size_t fragment; -}; - - -/** Flags indicating which parts of a URL string are required for a nsurl */ -enum nsurl_string_flags { - NSURL_F_SCHEME = (1 << 0), - NSURL_F_SCHEME_PUNCTUATION = (1 << 1), - NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2), - NSURL_F_USERNAME = (1 << 3), - NSURL_F_PASSWORD = (1 << 4), - NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5), - NSURL_F_HOST = (1 << 6), - NSURL_F_PORT = (1 << 7), - NSURL_F_AUTHORITY = (NSURL_F_USERNAME | - NSURL_F_PASSWORD | - NSURL_F_HOST | - NSURL_F_PORT), - NSURL_F_PATH = (1 << 8), - NSURL_F_QUERY = (1 << 9), - NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10), - NSURL_F_FRAGMENT = (1 << 11) + enum nsurl_scheme_type scheme_type; }; @@ -164,16 +78,6 @@ enum url_sections { }; -#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c) - -#define nsurl__component_compare(c1, c2, match) \ - if (c1 && c2 && lwc_error_ok == \ - lwc_string_isequal(c1, c2, match)) { \ - /* do nothing */ \ - } else if (c1 || c2) { \ - *match = false; \ - } - /** * Return a hex digit for the given numerical value. * @@ -1187,14 +1091,14 @@ static void nsurl__get_string_data(const struct nsurl_components *url, /** - * Get nsurl string info; total length, component lengths, & components present + * Copy url string into provided buffer * * \param url NetSurf URL components * \param url_s Updated to contain the string * \param l Individual component lengths * \param flags String flags */ -static void nsurl_get_string(const struct nsurl_components *url, char *url_s, +static void nsurl__get_string(const struct nsurl_components *url, char *url_s, struct nsurl_component_lengths *l, enum nsurl_string_flags flags) { @@ -1264,12 +1168,49 @@ static void nsurl_get_string(const struct nsurl_components *url, char *url_s, } +/* exported interface, documented in nsurl.h */ +nserror nsurl__components_to_string( + const struct nsurl_components *components, + nsurl_component parts, size_t pre_padding, + char **url_s_out, size_t *url_l_out) +{ + struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 }; + enum nsurl_string_flags str_flags = 0; + size_t url_l; + char *url_s; + + assert(components != NULL); + + /* Get the string length and find which parts of url need copied */ + nsurl__get_string_data(components, parts, &url_l, + &str_len, &str_flags); + + if (url_l == 0) { + return NSERROR_BAD_URL; + } + + /* Allocate memory for url string */ + url_s = malloc(pre_padding + url_l + 1); /* adding 1 for '\0' */ + if (url_s == NULL) { + return NSERROR_NOMEM; + } + + /* Copy the required parts into the url string */ + nsurl__get_string(components, url_s + pre_padding, &str_len, str_flags); + + *url_s_out = url_s; + *url_l_out = url_l; + + return NSERROR_OK; +} + + /** * Calculate hash value * * \param url NetSurf URL object to set hash value for */ -static void nsurl_calc_hash(nsurl *url) +void nsurl__calc_hash(nsurl *url) { uint32_t hash = 0; @@ -1298,73 +1239,6 @@ static void nsurl_calc_hash(nsurl *url) } -/** - * Destroy components - * - * \param c url components - */ -static void nsurl_destroy_components(struct nsurl_components *c) -{ - if (c->scheme) - lwc_string_unref(c->scheme); - - if (c->username) - lwc_string_unref(c->username); - - if (c->password) - lwc_string_unref(c->password); - - if (c->host) - lwc_string_unref(c->host); - - if (c->port) - lwc_string_unref(c->port); - - if (c->path) - lwc_string_unref(c->path); - - if (c->query) - lwc_string_unref(c->query); - - if (c->fragment) - lwc_string_unref(c->fragment); -} - - -#ifdef NSURL_DEBUG -/** - * Dump a NetSurf URL's internal components - * - * \param url The NetSurf URL to dump components of - */ -static void nsurl__dump(const nsurl *url) -{ - if (url->components.scheme) - LOG(" Scheme: %s", lwc_string_data(url->components.scheme)); - - if (url->components.username) - LOG("Username: %s", lwc_string_data(url->components.username)); - - if (url->components.password) - LOG("Password: %s", lwc_string_data(url->components.password)); - - if (url->components.host) - LOG(" Host: %s", lwc_string_data(url->components.host)); - - if (url->components.port) - LOG(" Port: %s", lwc_string_data(url->components.port)); - - if (url->components.path) - LOG(" Path: %s", lwc_string_data(url->components.path)); - - if (url->components.query) - LOG(" Query: %s", lwc_string_data(url->components.query)); - - if (url->components.fragment) - LOG("Fragment: %s", lwc_string_data(url->components.fragment)); -} -#endif - /****************************************************************************** * NetSurf URL Public API * ******************************************************************************/ @@ -1376,8 +1250,6 @@ nserror nsurl_create(const char * const url_s, nsurl **url) struct nsurl_components c; size_t length; char *buff; - struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 }; - enum nsurl_string_flags str_flags = 0; nserror e = NSERROR_OK; bool match; @@ -1409,7 +1281,7 @@ nserror nsurl_create(const char * const url_s, nsurl **url) free(buff); if (e != NSERROR_OK) { - nsurl_destroy_components(&c); + nsurl__components_destroy(&c); return NSERROR_NOMEM; } @@ -1420,30 +1292,22 @@ nserror nsurl_create(const char * const url_s, nsurl **url) &match) == lwc_error_ok && match == true)) { /* http, https must have host */ if (c.host == NULL) { - nsurl_destroy_components(&c); + nsurl__components_destroy(&c); return NSERROR_BAD_URL; } } - /* Get the string length and find which parts of url are present */ - nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length, - &str_len, &str_flags); - - /* Create NetSurf URL object */ - *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */ - if (*url == NULL) { - nsurl_destroy_components(&c); - return NSERROR_NOMEM; + e = nsurl__components_to_string(&c, NSURL_WITH_FRAGMENT, + sizeof(nsurl), (char **)url, &length); + if (e != NSERROR_OK) { + return e; } (*url)->components = c; (*url)->length = length; - /* Fill out the url string */ - nsurl_get_string(&c, (*url)->string, &str_len, str_flags); - /* Get the nsurl's hash */ - nsurl_calc_hash(*url); + nsurl__calc_hash(*url); /* Give the URL a reference */ (*url)->count = 1; @@ -1453,382 +1317,6 @@ nserror nsurl_create(const char * const url_s, nsurl **url) /* exported interface, documented in nsurl.h */ -nsurl *nsurl_ref(nsurl *url) -{ - assert(url != NULL); - - url->count++; - - return url; -} - - -/* exported interface, documented in nsurl.h */ -void nsurl_unref(nsurl *url) -{ - assert(url != NULL); - assert(url->count > 0); - - if (--url->count > 0) - return; - -#ifdef NSURL_DEBUG - nsurl__dump(url); -#endif - - /* Release lwc strings */ - nsurl_destroy_components(&url->components); - - /* Free the NetSurf URL */ - free(url); -} - - -/* exported interface, documented in nsurl.h */ -bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts) -{ - bool match = true; - - assert(url1 != NULL); - assert(url2 != NULL); - - /* Compare URL components */ - - /* Path, host and query first, since they're most likely to differ */ - - if (parts & NSURL_PATH) { - nsurl__component_compare(url1->components.path, - url2->components.path, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_HOST) { - nsurl__component_compare(url1->components.host, - url2->components.host, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_QUERY) { - nsurl__component_compare(url1->components.query, - url2->components.query, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_SCHEME) { - nsurl__component_compare(url1->components.scheme, - url2->components.scheme, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_USERNAME) { - nsurl__component_compare(url1->components.username, - url2->components.username, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_PASSWORD) { - nsurl__component_compare(url1->components.password, - url2->components.password, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_PORT) { - nsurl__component_compare(url1->components.port, - url2->components.port, &match); - - if (match == false) - return false; - } - - if (parts & NSURL_FRAGMENT) { - nsurl__component_compare(url1->components.fragment, - url2->components.fragment, &match); - - if (match == false) - return false; - } - - return true; -} - - -/* exported interface, documented in nsurl.h */ -nserror nsurl_get(const nsurl *url, nsurl_component parts, - char **url_s, size_t *url_l) -{ - struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 }; - enum nsurl_string_flags str_flags = 0; - - assert(url != NULL); - - /* Get the string length and find which parts of url need copied */ - nsurl__get_string_data(&(url->components), parts, url_l, - &str_len, &str_flags); - - if (*url_l == 0) { - return NSERROR_BAD_URL; - } - - /* Allocate memory for url string */ - *url_s = malloc(*url_l + 1); /* adding 1 for '\0' */ - if (*url_s == NULL) { - return NSERROR_NOMEM; - } - - /* Copy the required parts into the url string */ - nsurl_get_string(&(url->components), *url_s, &str_len, str_flags); - - return NSERROR_OK; -} - - -/* exported interface, documented in nsurl.h */ -lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part) -{ - assert(url != NULL); - - switch (part) { - case NSURL_SCHEME: - return (url->components.scheme != NULL) ? - lwc_string_ref(url->components.scheme) : NULL; - - case NSURL_USERNAME: - return (url->components.username != NULL) ? - lwc_string_ref(url->components.username) : NULL; - - case NSURL_PASSWORD: - return (url->components.password != NULL) ? - lwc_string_ref(url->components.password) : NULL; - - case NSURL_HOST: - return (url->components.host != NULL) ? - lwc_string_ref(url->components.host) : NULL; - - case NSURL_PORT: - return (url->components.port != NULL) ? - lwc_string_ref(url->components.port) : NULL; - - case NSURL_PATH: - return (url->components.path != NULL) ? - lwc_string_ref(url->components.path) : NULL; - - case NSURL_QUERY: - return (url->components.query != NULL) ? - lwc_string_ref(url->components.query) : NULL; - - case NSURL_FRAGMENT: - return (url->components.fragment != NULL) ? - lwc_string_ref(url->components.fragment) : NULL; - - default: - LOG("Unsupported value passed to part param."); - assert(0); - } - - return NULL; -} - - -/* exported interface, documented in nsurl.h */ -bool nsurl_has_component(const nsurl *url, nsurl_component part) -{ - assert(url != NULL); - - switch (part) { - case NSURL_SCHEME: - if (url->components.scheme != NULL) - return true; - else - return false; - - case NSURL_CREDENTIALS: - /* Only username required for credentials section */ - /* Fall through */ - case NSURL_USERNAME: - if (url->components.username != NULL) - return true; - else - return false; - - case NSURL_PASSWORD: - if (url->components.password != NULL) - return true; - else - return false; - - case NSURL_HOST: - if (url->components.host != NULL) - return true; - else - return false; - - case NSURL_PORT: - if (url->components.port != NULL) - return true; - else - return false; - - case NSURL_PATH: - if (url->components.path != NULL) - return true; - else - return false; - - case NSURL_QUERY: - if (url->components.query != NULL) - return true; - else - return false; - - case NSURL_FRAGMENT: - if (url->components.fragment != NULL) - return true; - else - return false; - - default: - LOG("Unsupported value passed to part param."); - assert(0); - } - - return false; -} - - -/* exported interface, documented in nsurl.h */ -const char *nsurl_access(const nsurl *url) -{ - assert(url != NULL); - - return url->string; -} - - -/* exported interface, documented in nsurl.h */ -nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l) -{ - nserror err; - lwc_string *host; - char *idna_host = NULL; - size_t idna_host_len; - char *scheme = NULL; - size_t scheme_len; - char *path = NULL; - size_t path_len; - - assert(url != NULL); - - if (url->components.host == NULL) { - return nsurl_get(url, NSURL_WITH_FRAGMENT, url_s, url_l); - } - - host = url->components.host; - err = idna_decode(lwc_string_data(host), lwc_string_length(host), - &idna_host, &idna_host_len); - if (err != NSERROR_OK) { - goto cleanup; - } - - err = nsurl_get(url, - NSURL_SCHEME | NSURL_CREDENTIALS, - &scheme, &scheme_len); - if (err != NSERROR_OK) { - goto cleanup; - } - - err = nsurl_get(url, - NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT, - &path, &path_len); - if (err != NSERROR_OK) { - goto cleanup; - } - - *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */ - *url_s = malloc(*url_l); - - if (*url_s == NULL) { - err = NSERROR_NOMEM; - goto cleanup; - } - - snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path); - - err = NSERROR_OK; - -cleanup: - free(idna_host); - free(scheme); - free(path); - - return err; -} - - -/* exported interface, documented in nsurl.h */ -const char *nsurl_access_leaf(const nsurl *url) -{ - size_t path_len; - const char *path; - const char *leaf; - - assert(url != NULL); - - if (url->components.path == NULL) - return ""; - - path = lwc_string_data(url->components.path); - path_len = lwc_string_length(url->components.path); - - if (path_len == 0) - return ""; - - if (path_len == 1 && *path == '/') - return "/"; - - leaf = path + path_len; - - do { - leaf--; - } while ((leaf != path) && (*leaf != '/')); - - if (*leaf == '/') - leaf++; - - return leaf; -} - - -/* exported interface, documented in nsurl.h */ -size_t nsurl_length(const nsurl *url) -{ - assert(url != NULL); - - return url->length; -} - - -/* exported interface, documented in nsurl.h */ -uint32_t nsurl_hash(const nsurl *url) -{ - assert(url != NULL); - - return url->hash; -} - - -/* exported interface, documented in nsurl.h */ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined) { struct url_markers m; @@ -1837,8 +1325,6 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined) char *buff; char *buff_pos; char *buff_start; - struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 }; - enum nsurl_string_flags str_flags = 0; nserror error = 0; enum { NSURL_F_REL = 0, @@ -2049,24 +1535,17 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined) return error; } - /* Get the string length and find which parts of url are present */ - nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length, - &str_len, &str_flags); - - /* Create NetSurf URL object */ - *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */ - if (*joined == NULL) { - return NSERROR_NOMEM; + error = nsurl__components_to_string(&c, NSURL_WITH_FRAGMENT, + sizeof(nsurl), (char **)joined, &length); + if (error != NSERROR_OK) { + return error; } (*joined)->components = c; (*joined)->length = length; - /* Fill out the url string */ - nsurl_get_string(&c, (*joined)->string, &str_len, str_flags); - /* Get the nsurl's hash */ - nsurl_calc_hash(*joined); + nsurl__calc_hash(*joined); /* Give the URL a reference */ (*joined)->count = 1; @@ -2074,427 +1553,3 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined) return NSERROR_OK; } - -/* exported interface, documented in nsurl.h */ -nserror nsurl_defragment(const nsurl *url, nsurl **no_frag) -{ - size_t length; - char *pos; - - assert(url != NULL); - - /* check for source url having no fragment already */ - if (url->components.fragment == NULL) { - *no_frag = (nsurl *)url; - - (*no_frag)->count++; - - return NSERROR_OK; - } - - /* Find the change in length from url to new_url */ - length = url->length; - if (url->components.fragment != NULL) { - length -= 1 + lwc_string_length(url->components.fragment); - } - - /* Create NetSurf URL object */ - *no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */ - if (*no_frag == NULL) { - return NSERROR_NOMEM; - } - - /* Copy components */ - (*no_frag)->components.scheme = - nsurl__component_copy(url->components.scheme); - (*no_frag)->components.username = - nsurl__component_copy(url->components.username); - (*no_frag)->components.password = - nsurl__component_copy(url->components.password); - (*no_frag)->components.host = - nsurl__component_copy(url->components.host); - (*no_frag)->components.port = - nsurl__component_copy(url->components.port); - (*no_frag)->components.path = - nsurl__component_copy(url->components.path); - (*no_frag)->components.query = - nsurl__component_copy(url->components.query); - (*no_frag)->components.fragment = NULL; - - (*no_frag)->components.scheme_type = url->components.scheme_type; - - (*no_frag)->length = length; - - /* Fill out the url string */ - pos = (*no_frag)->string; - memcpy(pos, url->string, length); - pos += length; - *pos = '\0'; - - /* Get the nsurl's hash */ - nsurl_calc_hash(*no_frag); - - /* Give the URL a reference */ - (*no_frag)->count = 1; - - return NSERROR_OK; -} - - -/* exported interface, documented in nsurl.h */ -nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url) -{ - int frag_len; - int base_len; - char *pos; - size_t len; - - assert(url != NULL); - assert(frag != NULL); - - /* Find the change in length from url to new_url */ - base_len = url->length; - if (url->components.fragment != NULL) { - base_len -= 1 + lwc_string_length(url->components.fragment); - } - frag_len = lwc_string_length(frag); - - /* Set new_url's length */ - len = base_len + 1 /* # */ + frag_len; - - /* Create NetSurf URL object */ - *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ - if (*new_url == NULL) { - return NSERROR_NOMEM; - } - - (*new_url)->length = len; - - /* Set string */ - pos = (*new_url)->string; - memcpy(pos, url->string, base_len); - pos += base_len; - *pos = '#'; - memcpy(++pos, lwc_string_data(frag), frag_len); - pos += frag_len; - *pos = '\0'; - - /* Copy components */ - (*new_url)->components.scheme = - nsurl__component_copy(url->components.scheme); - (*new_url)->components.username = - nsurl__component_copy(url->components.username); - (*new_url)->components.password = - nsurl__component_copy(url->components.password); - (*new_url)->components.host = - nsurl__component_copy(url->components.host); - (*new_url)->components.port = - nsurl__component_copy(url->components.port); - (*new_url)->components.path = - nsurl__component_copy(url->components.path); - (*new_url)->components.query = - nsurl__component_copy(url->components.query); - (*new_url)->components.fragment = - lwc_string_ref(frag); - - (*new_url)->components.scheme_type = url->components.scheme_type; - - /* Get the nsurl's hash */ - nsurl_calc_hash(*new_url); - - /* Give the URL a reference */ - (*new_url)->count = 1; - - return NSERROR_OK; -} - - -/* exported interface, documented in nsurl.h */ -nserror nsurl_replace_query(const nsurl *url, const char *query, - nsurl **new_url) -{ - int query_len; /* Length of new query string, including '?' */ - int frag_len = 0; /* Length of fragment, including '#' */ - int base_len; /* Length of URL up to start of query */ - char *pos; - size_t len; - lwc_string *lwc_query; - - assert(url != NULL); - assert(query != NULL); - assert(query[0] == '?'); - - /* Get the length of the new query */ - query_len = strlen(query); - - /* Find the change in length from url to new_url */ - base_len = url->length; - if (url->components.query != NULL) { - base_len -= lwc_string_length(url->components.query); - } - if (url->components.fragment != NULL) { - frag_len = 1 + lwc_string_length(url->components.fragment); - base_len -= frag_len; - } - - /* Set new_url's length */ - len = base_len + query_len + frag_len; - - /* Create NetSurf URL object */ - *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ - if (*new_url == NULL) { - return NSERROR_NOMEM; - } - - if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) { - free(*new_url); - return NSERROR_NOMEM; - } - - (*new_url)->length = len; - - /* Set string */ - pos = (*new_url)->string; - memcpy(pos, url->string, base_len); - pos += base_len; - memcpy(pos, query, query_len); - pos += query_len; - if (url->components.fragment != NULL) { - const char *frag = lwc_string_data(url->components.fragment); - *pos = '#'; - memcpy(++pos, frag, frag_len - 1); - pos += frag_len - 1; - } - *pos = '\0'; - - /* Copy components */ - (*new_url)->components.scheme = - nsurl__component_copy(url->components.scheme); - (*new_url)->components.username = - nsurl__component_copy(url->components.username); - (*new_url)->components.password = - nsurl__component_copy(url->components.password); - (*new_url)->components.host = - nsurl__component_copy(url->components.host); - (*new_url)->components.port = - nsurl__component_copy(url->components.port); - (*new_url)->components.path = - nsurl__component_copy(url->components.path); - (*new_url)->components.query = lwc_query; - (*new_url)->components.fragment = - nsurl__component_copy(url->components.fragment); - - (*new_url)->components.scheme_type = url->components.scheme_type; - - /* Get the nsurl's hash */ - nsurl_calc_hash(*new_url); - - /* Give the URL a reference */ - (*new_url)->count = 1; - - return NSERROR_OK; -} - - -/* exported interface documented in utils/nsurl.h */ -nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions) -{ - const char *data; - size_t len; - size_t pos; - bool match; - char *name; - - assert(url != NULL); - - *result = 0; - - /* extract the last component of the path, if possible */ - if ((url->components.path != NULL) && - (lwc_string_length(url->components.path) != 0) && - (lwc_string_isequal(url->components.path, - corestring_lwc_slash_, &match) == lwc_error_ok) && - (match == false)) { - bool first = true; - bool keep_looking; - - /* Get hold of the string data we're examining */ - data = lwc_string_data(url->components.path); - len = lwc_string_length(url->components.path); - pos = len; - - do { - keep_looking = false; - pos--; - - /* Find last '/' with stuff after it */ - while (pos != 0) { - if (data[pos] == '/' && pos < len - 1) { - break; - } - pos--; - } - - if (pos == 0) { - break; - } - - if (first) { - if (strncasecmp("/default.", data + pos, - SLEN("/default.")) == 0) { - keep_looking = true; - - } else if (strncasecmp("/index.", - data + pos, - 6) == 0) { - keep_looking = true; - - } - first = false; - } - - } while (keep_looking); - - if (data[pos] == '/') - pos++; - - if (strncasecmp("default.", data + pos, 8) != 0 && - strncasecmp("index.", data + pos, 6) != 0) { - size_t end = pos; - while (data[end] != '\0' && data[end] != '/') { - end++; - } - if (end - pos != 0) { - name = malloc(end - pos + 1); - if (name == NULL) { - return NSERROR_NOMEM; - } - memcpy(name, data + pos, end - pos); - name[end - pos] = '\0'; - if (remove_extensions) { - /* strip any extenstion */ - char *dot = strchr(name, '.'); - if (dot && dot != name) { - *dot = '\0'; - } - } - *result = name; - return NSERROR_OK; - } - } - } - - if (url->components.host != NULL) { - name = strdup(lwc_string_data(url->components.host)); - - for (pos = 0; name[pos] != '\0'; pos++) { - if (name[pos] == '.') { - name[pos] = '_'; - } - } - - *result = name; - return NSERROR_OK; - } - - return NSERROR_NOT_FOUND; -} - - -/* exported interface, documented in nsurl.h */ -nserror nsurl_parent(const nsurl *url, nsurl **new_url) -{ - lwc_string *lwc_path; - size_t old_path_len, new_path_len; - size_t len; - const char* path = NULL; - char *pos; - - assert(url != NULL); - - old_path_len = (url->components.path == NULL) ? 0 : - lwc_string_length(url->components.path); - - /* Find new path length */ - if (old_path_len == 0) { - new_path_len = old_path_len; - } else { - path = lwc_string_data(url->components.path); - - new_path_len = old_path_len; - if (old_path_len > 1) { - /* Skip over any trailing / */ - if (path[new_path_len - 1] == '/') - new_path_len--; - - /* Work back to next / */ - while (new_path_len > 0 && - path[new_path_len - 1] != '/') - new_path_len--; - } - } - - /* Find the length of new_url */ - len = url->length; - if (url->components.query != NULL) { - len -= lwc_string_length(url->components.query); - } - if (url->components.fragment != NULL) { - len -= 1; /* # */ - len -= lwc_string_length(url->components.fragment); - } - len -= old_path_len - new_path_len; - - /* Create NetSurf URL object */ - *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ - if (*new_url == NULL) { - return NSERROR_NOMEM; - } - - /* Make new path */ - if (old_path_len == 0) { - lwc_path = NULL; - } else if (old_path_len == new_path_len) { - lwc_path = lwc_string_ref(url->components.path); - } else { - if (lwc_intern_string(path, old_path_len - new_path_len, - &lwc_path) != lwc_error_ok) { - free(*new_url); - return NSERROR_NOMEM; - } - } - - (*new_url)->length = len; - - /* Set string */ - pos = (*new_url)->string; - memcpy(pos, url->string, len); - pos += len; - *pos = '\0'; - - /* Copy components */ - (*new_url)->components.scheme = - nsurl__component_copy(url->components.scheme); - (*new_url)->components.username = - nsurl__component_copy(url->components.username); - (*new_url)->components.password = - nsurl__component_copy(url->components.password); - (*new_url)->components.host = - nsurl__component_copy(url->components.host); - (*new_url)->components.port = - nsurl__component_copy(url->components.port); - (*new_url)->components.path = lwc_path; - (*new_url)->components.query = NULL; - (*new_url)->components.fragment = NULL; - - (*new_url)->components.scheme_type = url->components.scheme_type; - - /* Get the nsurl's hash */ - nsurl_calc_hash(*new_url); - - /* Give the URL a reference */ - (*new_url)->count = 1; - - return NSERROR_OK; -} - diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h new file mode 100644 index 000000000..e78f83042 --- /dev/null +++ b/utils/nsurl/private.h @@ -0,0 +1,215 @@ +/* + * Copyright 2011-2017 Michael Drake <tlsa@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NETSURF_UTILS_NSURL_PRIVATE_H_ +#define NETSURF_UTILS_NSURL_PRIVATE_H_ + +#include <libwapcaplet/libwapcaplet.h> + +#include "utils/nsurl.h" +#include "utils/utils.h" + + +/* Define to enable NSURL debugging */ +#undef NSURL_DEBUG + + +/** A type for URL schemes */ +enum nsurl_scheme_type { + NSURL_SCHEME_OTHER, + NSURL_SCHEME_HTTP, + NSURL_SCHEME_HTTPS, + NSURL_SCHEME_FTP, + NSURL_SCHEME_MAILTO +}; + + +/** + * nsurl components + * + * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment] + * + * Note: + * "path" string includes preceding '/', if needed for the scheme + * "query" string always includes preceding '?' + * + * The other spanned punctuation is to be inserted when building URLs from + * components. + */ +struct nsurl_components { + lwc_string *scheme; + lwc_string *username; + lwc_string *password; + lwc_string *host; + lwc_string *port; + lwc_string *path; + lwc_string *query; + lwc_string *fragment; + + enum nsurl_scheme_type scheme_type; +}; + + +/** + * NetSurf URL object + */ +struct nsurl { + struct nsurl_components components; + + int count; /* Number of references to NetSurf URL object */ + uint32_t hash; /* Hash value for nsurl identification */ + + size_t length; /* Length of string */ + char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */ +}; + + +/** Marker set, indicating positions of sections within a URL string */ +struct nsurl_component_lengths { + size_t scheme; + size_t username; + size_t password; + size_t host; + size_t port; + size_t path; + size_t query; + size_t fragment; +}; + + +/** Flags indicating which parts of a URL string are required for a nsurl */ +enum nsurl_string_flags { + NSURL_F_SCHEME = (1 << 0), + NSURL_F_SCHEME_PUNCTUATION = (1 << 1), + NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2), + NSURL_F_USERNAME = (1 << 3), + NSURL_F_PASSWORD = (1 << 4), + NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5), + NSURL_F_HOST = (1 << 6), + NSURL_F_PORT = (1 << 7), + NSURL_F_AUTHORITY = (NSURL_F_USERNAME | + NSURL_F_PASSWORD | + NSURL_F_HOST | + NSURL_F_PORT), + NSURL_F_PATH = (1 << 8), + NSURL_F_QUERY = (1 << 9), + NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10), + NSURL_F_FRAGMENT = (1 << 11) +}; + +/** + * NULL-safe lwc_string_ref + */ +#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c) + + +/** + * Convert a set of nsurl components to a single string + * + * \param[in] components The URL components to stitch together. + * \param[in] parts The set of parts wanted in the string. + * \param[in] pre_padding Amount in bytes to pad the start of the string by. + * \param[out] url_s_out Returns allocated URL string. + * \param[out] url_l_out Returns byte length of string, excluding pre_padding. + * \return NSERROR_OK on success, appropriate error otherwise. + */ +nserror nsurl__components_to_string( + const struct nsurl_components *components, + nsurl_component parts, size_t pre_padding, + char **url_s_out, size_t *url_l_out); + +/** + * Calculate hash value + * + * \param url NetSurf URL object to set hash value for + */ +void nsurl__calc_hash(nsurl *url); + + + + +/** + * Destroy components + * + * \param c url components + */ +static inline void nsurl__components_destroy(struct nsurl_components *c) +{ + if (c->scheme) + lwc_string_unref(c->scheme); + + if (c->username) + lwc_string_unref(c->username); + + if (c->password) + lwc_string_unref(c->password); + + if (c->host) + lwc_string_unref(c->host); + + if (c->port) + lwc_string_unref(c->port); + + if (c->path) + lwc_string_unref(c->path); + + if (c->query) + lwc_string_unref(c->query); + + if (c->fragment) + lwc_string_unref(c->fragment); +} + + + +#ifdef NSURL_DEBUG +/** + * Dump a NetSurf URL's internal components + * + * \param url The NetSurf URL to dump components of + */ +static inline void nsurl__dump(const nsurl *url) +{ + if (url->components.scheme) + LOG(" Scheme: %s", lwc_string_data(url->components.scheme)); + + if (url->components.username) + LOG("Username: %s", lwc_string_data(url->components.username)); + + if (url->components.password) + LOG("Password: %s", lwc_string_data(url->components.password)); + + if (url->components.host) + LOG(" Host: %s", lwc_string_data(url->components.host)); + + if (url->components.port) + LOG(" Port: %s", lwc_string_data(url->components.port)); + + if (url->components.path) + LOG(" Path: %s", lwc_string_data(url->components.path)); + + if (url->components.query) + LOG(" Query: %s", lwc_string_data(url->components.query)); + + if (url->components.fragment) + LOG("Fragment: %s", lwc_string_data(url->components.fragment)); +} +#endif + + +#endif |