class EL_URI
Client examples: JSON_PARSING_TEST_SET ; M3U_PLAYLIST_READER ; RBOX_DATABASE ; RBOX_IGNORED_ENTRY ; RBOX_IRADIO_ENTRY ; RBOX_IRADIO_FIELDS ; RBOX_PLAYLIST ; RBOX_SONG ; RBOX_TEST_DATABASE ; SMIL_PRESENTATION ; URI_TEST_SET
Uniform Resource Identifier as defined by RFC 3986
The following are two example URIs and their component parts:
foo://example.com:8042/over/there?name=ferret#nose \_/ \______________/\_________/ \_________/ \__/ | | | | | scheme authority path query fragment | _____________________|__ / \ / \ urn:example:animal:ferret:nose
note
description: "Uniform Resource Identifier as defined by [https://tools.ietf.org/html/rfc3986 RFC 3986]"
notes: "[
The following are two example URIs and their component parts:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
]"
author: "Finnian Reilly"
copyright: "Copyright (c) 2001-2022 Finnian Reilly"
contact: "finnian at eiffel hyphen loop dot com"
license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
date: "2024-11-08 9:11:25 GMT (Friday 8th November 2024)"
revision: "49"
class
EL_URI
inherit
STRING
rename
make as make_with_size,
substring as uri_substring,
String_searcher as String_8_searcher
export
{NONE} all
{ANY} hash_code, to_string_8, is_empty, starts_with, has_substring, last_index_of, count
{STRING_HANDLER} append, wipe_out, share, prune_all_trailing
redefine
to_string_32
end
EL_URI_IMPLEMENTATION
export
{STRING_HANDLER} Colon_slash_x2
undefine
String_8_searcher
end
create
make_empty, make, make_from_general, make_with_size
convert
make ({STRING_8, IMMUTABLE_STRING_8})
feature {NONE} -- Initialization
make (uri: READABLE_STRING_8)
require
valid_uri: uri.substring_index (Colon_slash_x2, 1) > 1
do
if cursor_8 (uri).all_ascii then
make_from_string (uri)
else
make_from_unencoded (uri)
end
end
make_from_general (str: READABLE_STRING_GENERAL)
do
if str.is_valid_as_string_8 then
make (str.as_string_8)
else
make_from_unencoded (str)
end
end
make_from_unencoded (unencoded: READABLE_STRING_GENERAL)
do
if attached new_encoded_parts (unencoded) as encoded then
make_with_size (parts_count (encoded))
append_parts (encoded)
end
end
feature -- Access
authority: STRING
local
start_index, end_index: INTEGER
do
start_index := authority_start_index
end_index := authority_end_index (start_index)
if end_index > 0 then
Result := substring (start_index, end_index, True)
else
Result := substring (1, 0, True)
end
end
fragment: STRING
local
index: INTEGER
do
index := index_of ('#', 1)
if index > 0 then
Result := substring (index + 1, count, True)
else
Result := substring (1, 0, True)
end
end
joined (a_path: EL_PATH): like Current
do
Result := twin
Result.join (a_path)
end
parent: like Current
do
Result := twin
Result.remove_step
end
path: STRING
do
Result := internal_path (True)
end
query: STRING
local
start_index, end_index: INTEGER
do
start_index := query_start_index
if start_index > 0 then
end_index := query_end_index (start_index)
end
if end_index > 0 then
Result := substring (start_index, end_index, True)
else
Result := substring (1, 0, True)
end
end
query_table: EL_URI_QUERY_ZSTRING_HASH_TABLE
do
create Result.make_url (query)
end
scheme: STRING
do
Result := substring (1, scheme_end_index, True)
end
feature -- Conversion
to_dir_uri_path: EL_DIR_URI_PATH
do
Result := to_uri_path.decoded
end
to_file_uri_path: EL_FILE_URI_PATH
do
Result := to_uri_path.decoded
end
to_string: ZSTRING
-- decoded string
do
Result := to_uri_path.decoded
if query_start_index > 0 then
Result.append_character ('?')
Result.append (decoded_query)
end
end
to_string_32: STRING_32
-- decoded unicode string
do
if query_start_index > 0 then
if attached String_32_pool.sufficient_item (count - occurrences ('%%') * 2) as borrowed then
if attached borrowed.empty as decoded then
to_uri_path.decode_to (decoded)
decoded.append_character ('?')
decoded_query.append_to_string_32 (decoded)
Result := decoded.twin
end
borrowed.return
end
else
Result := to_uri_path.decoded_32 (True)
end
end
feature -- Basic operations
append_to (general: STRING_GENERAL)
do
general.append (to_uri_path.decoded_32 (False))
end
decoded_query: ZSTRING
local
pair_split: EL_URI_QUERY_PAIRS_SPLIT
do
create pair_split.make (query, is_url)
if attached String_pool.borrowed_item as borrowed then
if attached borrowed.empty as str then
pair_split.append_as_unencoded (str)
Result := str.twin
end
borrowed.return
end
end
feature -- Element change
append_general (unencoded: READABLE_STRING_GENERAL)
-- append `unencoded' string
do
if attached new_encoded_parts (unencoded) as encoded then
grow (parts_count (encoded))
append_parts (encoded)
end
end
append_query_from_table (value_table: HASH_TABLE [READABLE_STRING_GENERAL, READABLE_STRING_GENERAL])
-- append `value_table' to `query' part of URI
do
replace_query_from_table (value_table, True)
end
join (a_path: EL_PATH)
require
valid_path: not is_empty implies not a_path.is_absolute
do
if attached Uri_path.emptied as encoded then
if count > 0 and then item (count) /= Separator then
encoded.append_character (Separator)
end
a_path.append_to_uri (encoded)
insert_string (encoded, path_end_index (1) + 1)
end
end
remove_step
-- remove the last path step, query and fragment
local
index: INTEGER
do
index := last_separator_index
if index > 0 then
keep_head (last_separator_index - 1)
trim
end
end
set_authority (a_authority: READABLE_STRING_GENERAL)
local
start_index: INTEGER
do
start_index := authority_start_index
replace_substring (a_authority.to_string_8, start_index, authority_end_index (start_index))
end
set_encoded_query (encoded: READABLE_STRING_8)
local
start_index: INTEGER
do
start_index := query_start_index
if start_index > 0 then
replace_substring (encoded, start_index, query_end_index (start_index))
else
start_index := fragment_start_index
if start_index > 0 then
insert_character ('?', start_index - 1)
insert_string (encoded, start_index)
else
append_character ('?')
append (encoded)
end
end
end
set_fragment (str: READABLE_STRING_GENERAL)
local
start_index: INTEGER
do
start_index := fragment_start_index
if start_index > 0 then
replace_substring (once_encoded (Uri_fragment, str), start_index, count)
else
append_character ('#')
append (once_encoded (Uri_fragment, str))
end
end
set_path (str: READABLE_STRING_GENERAL)
local
start_index, end_index: INTEGER
do
start_index := path_start_index
if start_index > 0 then
end_index := path_end_index (start_index)
if end_index > 0 then
replace_substring (once_encoded (Uri_path, str), start_index, end_index)
end
end
end
set_query (str: READABLE_STRING_GENERAL)
do
set_encoded_query (once_encoded (Uri_query, str))
end
set_query_from_table (value_table: HASH_TABLE [READABLE_STRING_GENERAL, READABLE_STRING_GENERAL])
do
replace_query_from_table (value_table, false)
end
set_scheme (a_scheme: READABLE_STRING_GENERAL)
do
replace_substring (a_scheme.to_string_8, 1, scheme_end_index)
end
feature -- Status query
has_parent: BOOLEAN
do
Result := last_separator_index.to_boolean
end
has_scheme (a_scheme: READABLE_STRING_8): BOOLEAN
local
end_index: INTEGER
do
end_index := scheme_end_index
if a_scheme.count = end_index then
Result := same_characters (a_scheme, 1, end_index, 1)
end
end
is_file: BOOLEAN
do
Result := has_scheme (Protocol.file)
end
is_http: BOOLEAN
do
Result := has_scheme (Protocol.http)
end
is_https: BOOLEAN
do
Result := has_scheme (Protocol.https)
end
is_url: BOOLEAN
do
Result := False
end
feature -- Contract Support
is_unencoded (str: READABLE_STRING_8): BOOLEAN
do
Result := cursor_8 (str).all_ascii
end
feature {NONE} -- Implementation
append_parts (parts: like new_encoded_parts)
local
i: INTEGER
do
from i := 0 until i = 3 loop
append (parts [i])
i := i + 1
end
end
current_string: STRING
do
Result := Current
end
parts_count (parts: like new_encoded_parts): INTEGER
local
i: INTEGER
do
from i := 0 until i = 3 loop
Result := Result + parts [i].count
i := i + 1
end
end
replace_query_from_table (
value_table: HASH_TABLE [READABLE_STRING_GENERAL, READABLE_STRING_GENERAL]; appending: BOOLEAN
)
do
if attached Uri_query as l_query then
l_query.wipe_out
if appending and then query_start_index.to_boolean then
l_query.append_raw_8 (query)
end
across value_table as table loop
if l_query.count > 0 then
l_query.append_character ('&')
end
l_query.append_general (table.key)
l_query.append_character ('=')
l_query.append_general (table.item)
end
set_encoded_query (l_query)
end
end
end