Better support for unicode path and values.
Added WSF_REQUEST.percent_encoded_path_info: READABLE_STRING_8
to keep url encoded path info, as it is useful for specific component
The router is now using WSF_REQUEST.percent_encoded_path_info
since URI_TEMPLATE are handling URI (and not IRI)
this fixes an issue with unicode path parameters.
This should not break existing code, and this fixes various unicode related issues related
to PATH parameter and path info
but also any component using file names.
(required EiffelStudio >= 7.2)
This commit is contained in:
@@ -15,31 +15,53 @@ inherit
|
||||
|
||||
WSF_SELF_DOCUMENTED_HANDLER
|
||||
|
||||
SHARED_HTML_ENCODER
|
||||
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoder as url_encoder
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make_with_path,
|
||||
make_hidden_with_path,
|
||||
make,
|
||||
make_hidden
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (d: like document_root)
|
||||
require
|
||||
valid_d: (d /= Void and then not d.is_empty) implies not d.ends_with (operating_environment.directory_separator.out)
|
||||
local
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
make_with_path (d: like document_root)
|
||||
do
|
||||
if d.is_empty then
|
||||
create e
|
||||
document_root := e.current_working_directory
|
||||
document_root := execution_environment.current_working_path
|
||||
else
|
||||
document_root := d
|
||||
end
|
||||
ensure
|
||||
not document_root.is_empty and then not document_root.ends_with (operating_environment.directory_separator.out)
|
||||
not document_root.is_empty
|
||||
end
|
||||
|
||||
make_hidden (d: like document_root)
|
||||
require
|
||||
valid_d: (d /= Void and then not d.is_empty) implies not d.ends_with (operating_environment.directory_separator.out)
|
||||
make_hidden_with_path (d: like document_root)
|
||||
do
|
||||
make_with_path (d)
|
||||
is_hidden := True
|
||||
ensure
|
||||
hidden: is_hidden
|
||||
end
|
||||
|
||||
make (d: READABLE_STRING_GENERAL)
|
||||
do
|
||||
make_with_path (create {PATH}.make_from_string (d))
|
||||
end
|
||||
|
||||
make_hidden (d: READABLE_STRING_GENERAL)
|
||||
do
|
||||
make (d)
|
||||
is_hidden := True
|
||||
@@ -60,9 +82,10 @@ feature -- Documentation
|
||||
Result.add_description ("File service")
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
feature -- Access
|
||||
|
||||
document_root: PATH
|
||||
|
||||
document_root: STRING
|
||||
max_age: INTEGER
|
||||
|
||||
index_disabled: BOOLEAN
|
||||
@@ -118,10 +141,10 @@ feature -- Execution
|
||||
|
||||
execute (a_start_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
p: STRING
|
||||
p: STRING_32
|
||||
do
|
||||
p := req.path_info
|
||||
if p.starts_with (a_start_path) then
|
||||
create p.make_from_string (req.path_info)
|
||||
if p.starts_with_general (a_start_path) then
|
||||
p.remove_head (a_start_path.count)
|
||||
else
|
||||
check starts_with_base: False end
|
||||
@@ -131,16 +154,16 @@ feature -- Execution
|
||||
|
||||
execute_starts_with (a_start_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
execute (a_start_path,req, res)
|
||||
execute (a_start_path, req, res)
|
||||
end
|
||||
|
||||
process_uri (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
process_uri (uri: READABLE_STRING_32; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
f: RAW_FILE
|
||||
fn: READABLE_STRING_8
|
||||
fn: like resource_filename
|
||||
do
|
||||
fn := resource_filename (uri)
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
if f.exists then
|
||||
if f.is_readable then
|
||||
if f.is_directory then
|
||||
@@ -160,14 +183,15 @@ feature -- Execution
|
||||
end
|
||||
end
|
||||
|
||||
process_index (a_uri: READABLE_STRING_8; dn: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
process_index (a_uri: READABLE_STRING_8; dn: PATH; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
uri, s: STRING_8
|
||||
d: DIRECTORY
|
||||
l_files: LIST [STRING_8]
|
||||
l_files: LIST [PATH]
|
||||
do
|
||||
create d.make_open_read (dn)
|
||||
create d.make_with_path (dn)
|
||||
d.open_read
|
||||
if attached directory_index_file (d) as f then
|
||||
process_file (f, req, res)
|
||||
else
|
||||
@@ -187,12 +211,16 @@ feature -- Execution
|
||||
s.replace_substring_all ("$URI", uri)
|
||||
|
||||
from
|
||||
l_files := d.linear_representation
|
||||
l_files := d.entries
|
||||
l_files.start
|
||||
until
|
||||
l_files.after
|
||||
loop
|
||||
s.append ("<li><a href=%"" + uri + l_files.item_for_iteration + "%">" + l_files.item_for_iteration + "</a></li>%N")
|
||||
s.append ("<li><a href=%"" + uri)
|
||||
url_encoder.append_percent_encoded_string_to (l_files.item.name, s)
|
||||
s.append ("%">")
|
||||
s.append (html_encoder.encoded_string (l_files.item.name))
|
||||
s.append ("</a></li>%N")
|
||||
l_files.forth
|
||||
end
|
||||
s.append ("[
|
||||
@@ -217,12 +245,12 @@ feature -- Execution
|
||||
|
||||
process_file (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
ext: READABLE_STRING_8
|
||||
ext: READABLE_STRING_32
|
||||
ct: detachable READABLE_STRING_8
|
||||
fres: WSF_FILE_RESPONSE
|
||||
dt: DATE_TIME
|
||||
do
|
||||
ext := extension (f.name)
|
||||
ext := extension (f.path.name)
|
||||
ct := extension_mime_mapping.mime_type (ext)
|
||||
if ct = Void then
|
||||
ct := {HTTP_MIME_TYPES}.application_force_download
|
||||
@@ -235,7 +263,7 @@ feature -- Execution
|
||||
then
|
||||
process_not_modified (f_date, req, res)
|
||||
else
|
||||
create fres.make_with_content_type (ct, f.name)
|
||||
create fres.make_with_content_type (ct, f.path.name)
|
||||
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
|
||||
-- cache control
|
||||
@@ -341,7 +369,7 @@ feature {NONE} -- Implementation
|
||||
directory_index_file (d: DIRECTORY): detachable FILE
|
||||
local
|
||||
f: detachable RAW_FILE
|
||||
fn: FILE_NAME
|
||||
fn: PATH
|
||||
do
|
||||
if attached directory_index as default_index then
|
||||
across
|
||||
@@ -350,12 +378,11 @@ feature {NONE} -- Implementation
|
||||
Result /= Void
|
||||
loop
|
||||
if d.has_entry (c.item) then
|
||||
create fn.make_from_string (d.name)
|
||||
fn.set_file_name (c.item)
|
||||
fn := d.path.extended (c.item)
|
||||
if f = Void then
|
||||
create f.make (fn.string)
|
||||
create f.make_with_path (fn)
|
||||
else
|
||||
f.make (fn.string)
|
||||
f.make_with_path (fn)
|
||||
end
|
||||
if f.exists and then f.is_readable then
|
||||
Result := f
|
||||
@@ -365,28 +392,34 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
resource_filename (uri: READABLE_STRING_8): READABLE_STRING_8
|
||||
do
|
||||
Result := real_filename (document_root + operating_environment.directory_separator.out + real_filename (uri))
|
||||
end
|
||||
|
||||
dirname (uri: READABLE_STRING_8): READABLE_STRING_8
|
||||
resource_filename (uri: READABLE_STRING_32): PATH
|
||||
local
|
||||
p: INTEGER
|
||||
s: like uri_path_to_filename
|
||||
do
|
||||
p := uri.last_index_of ('/', uri.count)
|
||||
if p > 0 then
|
||||
Result := uri.substring (1, p - 1)
|
||||
else
|
||||
create {STRING_8} Result.make_empty
|
||||
Result := document_root
|
||||
s := uri_path_to_filename (uri)
|
||||
if not s.is_empty then
|
||||
Result := Result.extended (s)
|
||||
end
|
||||
end
|
||||
|
||||
filename (uri: READABLE_STRING_8): READABLE_STRING_8
|
||||
dirname (uri: READABLE_STRING_32): READABLE_STRING_32
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := uri.last_index_of ('/', uri.count)
|
||||
p := uri.last_index_of ({CHARACTER_32} '/', uri.count)
|
||||
if p > 0 then
|
||||
Result := uri.substring (1, p - 1)
|
||||
else
|
||||
create {STRING_32} Result.make_empty
|
||||
end
|
||||
end
|
||||
|
||||
filename (uri: READABLE_STRING_32): READABLE_STRING_32
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := uri.last_index_of ({CHARACTER_32} '/', uri.count)
|
||||
if p > 0 then
|
||||
Result := uri.substring (p + 1, uri.count)
|
||||
else
|
||||
@@ -394,58 +427,52 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
extension (uri: READABLE_STRING_8): READABLE_STRING_8
|
||||
extension (uri: READABLE_STRING_32): READABLE_STRING_32
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := uri.last_index_of ('.', uri.count)
|
||||
p := uri.last_index_of ({CHARACTER_32} '.', uri.count)
|
||||
if p > 0 then
|
||||
Result := uri.substring (p + 1, uri.count)
|
||||
else
|
||||
create {STRING_8} Result.make_empty
|
||||
create {STRING_32} Result.make_empty
|
||||
end
|
||||
end
|
||||
|
||||
real_filename (fn: STRING): STRING
|
||||
uri_path_to_filename (fn: READABLE_STRING_32): STRING_32
|
||||
-- Real filename from url-path `fn'
|
||||
--| Find a better design for this piece of code
|
||||
--| Eventually in a spec/$ISE_PLATFORM/ specific cluster
|
||||
local
|
||||
n: INTEGER
|
||||
do
|
||||
if fn.is_empty then
|
||||
Result := fn
|
||||
else
|
||||
n := fn.count
|
||||
create Result.make_from_string (fn)
|
||||
if n > 0 and then Result.item (Result.count) = {CHARACTER_32} '/' then
|
||||
Result.remove_tail (1)
|
||||
n := n - 1
|
||||
end
|
||||
if n > 0 and then Result.item (1) = {CHARACTER_32} '/' then
|
||||
Result.remove_head (1)
|
||||
n := n - 1
|
||||
end
|
||||
|
||||
if n > 0 then
|
||||
if {PLATFORM}.is_windows then
|
||||
create Result.make_from_string (fn)
|
||||
Result.replace_substring_all ("/", "\")
|
||||
if Result [Result.count] = '\' then
|
||||
Result.remove_tail (1)
|
||||
end
|
||||
else
|
||||
Result := fn
|
||||
if Result [Result.count] = '/' then
|
||||
Result.remove_tail (1)
|
||||
end
|
||||
Result.replace_substring_all ({STRING_32} "/", {STRING_32} "\")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
node_exists (p: READABLE_STRING_8): BOOLEAN
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (p)
|
||||
Result := f.exists
|
||||
end
|
||||
|
||||
extension_mime_mapping: HTTP_FILE_EXTENSION_MIME_MAPPING
|
||||
local
|
||||
f: RAW_FILE
|
||||
once
|
||||
create f.make ("mime.types")
|
||||
create f.make_with_name ("mime.types")
|
||||
if f.exists and then f.is_readable then
|
||||
create Result.make_from_file (f.name)
|
||||
create Result.make_from_file (f.path.name)
|
||||
else
|
||||
create Result.make_default
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user