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:
@@ -10,6 +10,10 @@ class
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoder as url_encoder
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
@@ -75,7 +79,8 @@ feature -- Access
|
||||
|
||||
url_encoded_string (s: READABLE_STRING_32): STRING_8
|
||||
do
|
||||
Result := (create {UTF8_URL_ENCODER}).encoded_string (s)
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_encoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
html_decoded_string (v: READABLE_STRING_32): READABLE_STRING_32
|
||||
|
||||
@@ -33,8 +33,7 @@ feature {NONE} -- Initialization
|
||||
-- Create with no mapping
|
||||
-- but one can use `map' to add new mapping
|
||||
do
|
||||
create mapping.make (n)
|
||||
mapping.compare_objects
|
||||
create mapping.make_caseless (n)
|
||||
end
|
||||
|
||||
make_default
|
||||
@@ -43,9 +42,8 @@ feature {NONE} -- Initialization
|
||||
local
|
||||
m: like mapping
|
||||
do
|
||||
create m.make (40)
|
||||
create m.make_caseless (40)
|
||||
mapping := m
|
||||
m.compare_objects
|
||||
m.force (text_css, "css")
|
||||
m.force (text_html, "html")
|
||||
m.force (text_xml, "xml")
|
||||
@@ -74,13 +72,13 @@ feature {NONE} -- Initialization
|
||||
m.force (text_plain, "txt")
|
||||
end
|
||||
|
||||
make_from_file (fn: READABLE_STRING_8)
|
||||
make_from_file (fn: READABLE_STRING_GENERAL)
|
||||
-- Create with mime.types file
|
||||
-- One can use `map' to add new mapping
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_name (fn)
|
||||
if f.exists and then f.is_readable then
|
||||
make_empty (50)
|
||||
f.open_read
|
||||
@@ -128,7 +126,7 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature -- Access
|
||||
|
||||
mime_type (ext: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||
mime_type (ext: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
|
||||
-- Mime type for extension `ext'
|
||||
do
|
||||
Result := mapping.item (ext.as_lower)
|
||||
@@ -136,7 +134,7 @@ feature -- Access
|
||||
|
||||
feature -- Element change
|
||||
|
||||
map (e: READABLE_STRING_8; t: READABLE_STRING_8)
|
||||
map (e: READABLE_STRING_GENERAL; t: READABLE_STRING_8)
|
||||
-- Add mapping extension `e' to mime type `t'
|
||||
do
|
||||
mapping.force (t, e.as_lower)
|
||||
@@ -220,13 +218,13 @@ feature {NONE} -- Implementation
|
||||
|
||||
feature {NONE} -- Extension MIME mapping
|
||||
|
||||
mapping: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
mapping: STRING_TABLE [READABLE_STRING_8]
|
||||
|
||||
invariant
|
||||
mapping_keys_are_lowercase: across mapping as c all c.key.same_string (c.key.as_lower) end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -137,7 +137,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
|
||||
debug
|
||||
l_description.append ("<h2>Meta Information</h2><ul>")
|
||||
l_description.append ("<li>PATH_INFO=" + request.path_info + "</li>")
|
||||
l_description.append ("<li>PATH_INFO=" + request.percent_encoded_path_info + "</li>")
|
||||
l_description.append ("<li>QUERY_STRING=" + request.query_string + "</li>")
|
||||
l_description.append ("<li>REQUEST_URI=" + request.request_uri + "</li>")
|
||||
l_description.append ("<li>SCRIPT_NAME=" + request.script_name + "</li>")
|
||||
|
||||
@@ -20,7 +20,7 @@ feature -- Execution
|
||||
a_start_path_attached: a_start_path /= Void
|
||||
req_attached: req /= Void
|
||||
res_attached: res /= Void
|
||||
path_start_with_a_start_path: req.path_info.starts_with (a_start_path)
|
||||
path_start_with_a_start_path: req.percent_encoded_path_info.starts_with (a_start_path)
|
||||
deferred
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ feature {WSF_ROUTER} -- Mapping
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -83,7 +83,7 @@ feature {NONE} -- Execution
|
||||
a_start_path_attached: a_start_path /= Void
|
||||
req_attached: req /= Void
|
||||
res_attached: res /= Void
|
||||
path_start_with_a_start_path: req.path_info.starts_with (a_start_path)
|
||||
path_start_with_a_start_path: req.percent_encoded_path_info.starts_with (a_start_path)
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ feature -- Status
|
||||
-- <Precursor>
|
||||
local
|
||||
tpl: URI_TEMPLATE
|
||||
p: READABLE_STRING_32
|
||||
p: READABLE_STRING_8
|
||||
do
|
||||
p := path_from_request (req)
|
||||
tpl := based_uri_template (template, a_router)
|
||||
@@ -72,7 +72,7 @@ feature -- Status
|
||||
-- <Precursor>
|
||||
local
|
||||
tpl: URI_TEMPLATE
|
||||
p: READABLE_STRING_32
|
||||
p: READABLE_STRING_8
|
||||
new_src: detachable WSF_REQUEST_PATH_PARAMETERS_PROVIDER
|
||||
do
|
||||
p := path_from_request (req)
|
||||
|
||||
@@ -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
|
||||
@@ -62,7 +84,8 @@ feature -- Documentation
|
||||
|
||||
feature -- Access
|
||||
|
||||
document_root: STRING
|
||||
document_root: PATH
|
||||
|
||||
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
|
||||
@@ -134,13 +157,13 @@ feature -- Execution
|
||||
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
|
||||
resource_filename (uri: READABLE_STRING_32): PATH
|
||||
local
|
||||
s: like uri_path_to_filename
|
||||
do
|
||||
Result := real_filename (document_root + operating_environment.directory_separator.out + real_filename (uri))
|
||||
Result := document_root
|
||||
s := uri_path_to_filename (uri)
|
||||
if not s.is_empty then
|
||||
Result := Result.extended (s)
|
||||
end
|
||||
end
|
||||
|
||||
dirname (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_8} Result.make_empty
|
||||
create {STRING_32} Result.make_empty
|
||||
end
|
||||
end
|
||||
|
||||
filename (uri: READABLE_STRING_8): READABLE_STRING_8
|
||||
filename (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
|
||||
@@ -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
|
||||
if {PLATFORM}.is_windows then
|
||||
n := fn.count
|
||||
create Result.make_from_string (fn)
|
||||
Result.replace_substring_all ("/", "\")
|
||||
if Result [Result.count] = '\' then
|
||||
if n > 0 and then Result.item (Result.count) = {CHARACTER_32} '/' then
|
||||
Result.remove_tail (1)
|
||||
n := n - 1
|
||||
end
|
||||
else
|
||||
Result := fn
|
||||
if Result [Result.count] = '/' then
|
||||
Result.remove_tail (1)
|
||||
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
|
||||
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
|
||||
|
||||
@@ -77,12 +77,12 @@ feature -- Status
|
||||
|
||||
feature -- Helper
|
||||
|
||||
path_from_request (req: WSF_REQUEST): READABLE_STRING_32
|
||||
path_from_request (req: WSF_REQUEST): READABLE_STRING_8
|
||||
-- Path used by `Current' to check that mapping matches request `req'
|
||||
require
|
||||
req_attached: req /= Void
|
||||
do
|
||||
Result := req.path_info
|
||||
Result := req.percent_encoded_path_info
|
||||
ensure
|
||||
path_from_request_attached: Result /= Void
|
||||
end
|
||||
|
||||
@@ -10,6 +10,11 @@ class
|
||||
inherit
|
||||
WSF_SESSION
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make,
|
||||
make_new
|
||||
@@ -128,15 +133,6 @@ feature {NONE} -- Storage
|
||||
data.compare_objects
|
||||
end
|
||||
|
||||
sessions_folder_name: READABLE_STRING_8
|
||||
local
|
||||
dn: DIRECTORY_NAME
|
||||
once
|
||||
create dn.make_from_string ((create {EXECUTION_ENVIRONMENT}).current_working_directory)
|
||||
dn.extend ("_sessions_")
|
||||
Result := dn.string
|
||||
end
|
||||
|
||||
load
|
||||
do
|
||||
if manager.session_exists (uuid) then
|
||||
@@ -181,7 +177,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2012, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -21,12 +21,12 @@ feature {NONE} -- Initialization
|
||||
make_with_folder ("_WSF_SESSIONS_")
|
||||
end
|
||||
|
||||
make_with_folder (a_folder: like sessions_folder_name)
|
||||
make_with_folder (a_folder: READABLE_STRING_GENERAL)
|
||||
do
|
||||
sessions_folder_name := a_folder
|
||||
create sessions_folder_name.make_from_string (a_folder)
|
||||
end
|
||||
|
||||
sessions_folder_name: STRING_8
|
||||
sessions_folder_name: PATH
|
||||
|
||||
feature -- Access
|
||||
|
||||
@@ -34,7 +34,7 @@ feature -- Access
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name (a_session_uuid))
|
||||
create f.make_with_path (file_name (a_session_uuid))
|
||||
Result := f.exists and then f.is_readable
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ feature -- Access
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name (a_session_uuid))
|
||||
create f.make_with_path (file_name (a_session_uuid))
|
||||
if f.exists and then f.is_readable then
|
||||
f.open_read
|
||||
if attached data_from_file (f) as d then
|
||||
@@ -68,7 +68,7 @@ feature -- Persistence
|
||||
delete_session (a_session)
|
||||
else
|
||||
ensure_session_folder_exists
|
||||
create f.make (file_name (a_session.uuid))
|
||||
create f.make_with_path (file_name (a_session.uuid))
|
||||
if not f.exists or else f.is_writable then
|
||||
f.create_read_write
|
||||
a_session.data.set_expiration (a_session.expiration)
|
||||
@@ -91,7 +91,7 @@ feature -- Persistence
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
create f.make (file_name (a_session.uuid))
|
||||
create f.make_with_path (file_name (a_session.uuid))
|
||||
if f.exists then
|
||||
f.delete
|
||||
end
|
||||
@@ -131,7 +131,7 @@ feature {NONE} -- Implementation
|
||||
local
|
||||
d: DIRECTORY
|
||||
once
|
||||
create d.make (sessions_folder_name)
|
||||
create d.make_with_path (sessions_folder_name)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
@@ -143,18 +143,13 @@ feature {NONE} -- Implementation
|
||||
local
|
||||
d: DIRECTORY
|
||||
do
|
||||
create d.make (sessions_folder_name)
|
||||
create d.make_with_path (sessions_folder_name)
|
||||
Result := d.exists and then d.is_writable
|
||||
end
|
||||
|
||||
file_name (a_uuid: like {WSF_SESSION}.uuid): READABLE_STRING_8
|
||||
local
|
||||
fn: FILE_NAME
|
||||
file_name (a_uuid: like {WSF_SESSION}.uuid): PATH
|
||||
do
|
||||
create fn.make_from_string (sessions_folder_name)
|
||||
fn.set_file_name (a_uuid.out)
|
||||
fn.add_extension ("session")
|
||||
Result := fn.string
|
||||
Result := sessions_folder_name.extended (a_uuid.out).appended_with_extension ("session")
|
||||
end
|
||||
|
||||
note
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
note
|
||||
description: "Objects to access the shared once WSF_PERCENT_ENCODER ..."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
percent_encoder: WSF_PERCENT_ENCODER
|
||||
-- Shared Percent encoding engine.
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
|
||||
end
|
||||
523
library/server/wsf/src/implementation/wsf_percent_encoder.e
Normal file
523
library/server/wsf/src/implementation/wsf_percent_encoder.e
Normal file
@@ -0,0 +1,523 @@
|
||||
note
|
||||
description: "[
|
||||
Component to handle percent encoding
|
||||
]"
|
||||
date: "$Date: 2013-05-21 01:15:17 +0200 (mar., 21 mai 2013) $"
|
||||
revision: "$Revision: 92557 $"
|
||||
EIS: "name=Percent-encoding", "protocol=URI", "src=http://en.wikipedia.org/wiki/Percent-encoding"
|
||||
|
||||
class
|
||||
WSF_PERCENT_ENCODER
|
||||
|
||||
feature -- Percent encoding
|
||||
|
||||
percent_encoded_string (v: READABLE_STRING_GENERAL): STRING_8
|
||||
-- Return `a_string' percent-encoded
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_encoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append `a_string' as percent-encoded value to `a_result'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i,n: INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := s.code (i)
|
||||
if
|
||||
--| unreserved ALPHA / DIGIT
|
||||
(48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
or (65 <= c and c <= 90) -- ALPHA: A .. Z
|
||||
or (97 <= c and c <= 122) -- ALPHA: a .. z
|
||||
then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
inspect c
|
||||
when
|
||||
45, 46, 95, 126 -- unreserved characters: -._~
|
||||
then
|
||||
a_result.append_code (c)
|
||||
when
|
||||
58, 64, -- reserved =+ gen-delims: :@
|
||||
33, 36, 38, 39, 40, 41, 42, -- reserved =+ sub-delims: !$&'()*
|
||||
43, 44, 59, 61, -- reserved = sub-delims: +,;=
|
||||
37 -- percent encoding: %
|
||||
then
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Percent encoding: character
|
||||
|
||||
append_percent_encoded_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append character code `a_code' as percent-encoded content into `a_result'
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
elseif a_code > 0x7F then
|
||||
-- Extended ASCII
|
||||
-- This requires percent-encoding on UTF-8 converted character.
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- ASCII
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: character encoding
|
||||
|
||||
append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append extended ascii character code `a_code' as percent-encoded content into `a_result'
|
||||
-- Note: it does not UTF-8 convert this extended ASCII.
|
||||
require
|
||||
is_extended_ascii: a_code <= 0xFF
|
||||
local
|
||||
c: INTEGER
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- Extended ASCII
|
||||
c := a_code.to_integer_32
|
||||
a_result.append_code (37) -- 37 '%%'
|
||||
a_result.append_code (hex_digit [c |>> 4])
|
||||
a_result.append_code (hex_digit [c & 0xF])
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
append_percent_encoded_unicode_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append Unicode character code `a_code' as UTF-8 and percent-encoded content into `a_result'
|
||||
-- Note: it does include UTF-8 conversion of extended ASCII and Unicode.
|
||||
do
|
||||
if a_code <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
elseif a_code <= 0x7FF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 6) | 0xC0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
elseif a_code <= 0xFFFF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 12) | 0xE0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
else
|
||||
-- c <= 1FFFFF - there are no higher code points
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 18) | 0xF0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 12) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature -- Percent decoding
|
||||
|
||||
percent_decoded_string (v: READABLE_STRING_GENERAL): STRING_32
|
||||
-- Return the percent decoded string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_decoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_decoded_string_to (v: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append to `a_result' a string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
local
|
||||
i,n: INTEGER
|
||||
c: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
a_result_is_string_32: BOOLEAN
|
||||
do
|
||||
a_result_is_string_32 := attached {STRING_32} a_result
|
||||
from
|
||||
i := 1
|
||||
create pr.put (i)
|
||||
n := v.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := v.code (i)
|
||||
inspect c
|
||||
when 43 then -- 43 '+'
|
||||
-- Some implementation are replacing spaces with "+" instead of "%20"
|
||||
a_result.append_code (32) -- 32 ' '
|
||||
when 37 then -- 37 '%%'
|
||||
-- An escaped character ?
|
||||
if i = n then -- Error?
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
-- Convert UTF-8 to UTF-32
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_unicode_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
else
|
||||
-- Keep UTF-8
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
end
|
||||
end
|
||||
else
|
||||
if c <= 0x7F then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: decoding
|
||||
|
||||
next_percent_decoded_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Character decoded from string `v' starting from index `a_position.item'
|
||||
-- note: it also updates `a_position.item' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i, n: INTEGER
|
||||
not_a_digit: BOOLEAN
|
||||
ascii_pos: NATURAL_32
|
||||
ival: NATURAL_32
|
||||
pos: INTEGER
|
||||
c_is_digit: BOOLEAN
|
||||
do
|
||||
--| pos is index in stream of escape character ('%')
|
||||
pos := a_position.item
|
||||
c := v.code (pos + 1)
|
||||
if c = 85 or c = 117 then -- 117 'u' 85 'U'
|
||||
-- NOTE: this is not a standard, but it can occur, so use this for decoding only
|
||||
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||
-- has the form: %u<n> where <n> is the UCS value
|
||||
-- of the character (two byte integer, one to 4 chars
|
||||
-- after escape sequence).
|
||||
-- See: http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations
|
||||
-- UTF-8 result can be 1 to 4 characters.
|
||||
from
|
||||
i := pos + 2
|
||||
n := v.count
|
||||
until
|
||||
(i > n) or not_a_digit
|
||||
loop
|
||||
c := v.code (i)
|
||||
c_is_digit := (48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
if
|
||||
c_is_digit
|
||||
or (97 <= c and c <= 102) -- ALPHA: a..f
|
||||
or (65 <= c and c <= 70) -- ALPHA: A..F
|
||||
then
|
||||
ival := ival * 16
|
||||
if c_is_digit then
|
||||
ival := ival + (c - 48) -- 48 '0'
|
||||
else
|
||||
if c > 70 then -- a..f
|
||||
ival := ival + (c - 97) + 10 -- 97 'a'
|
||||
else -- A..F
|
||||
ival := ival + (c - 65) + 10 -- 65 'A'
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
else
|
||||
not_a_digit := True
|
||||
i := i - 1
|
||||
end
|
||||
end
|
||||
a_position.replace (i)
|
||||
Result := ival
|
||||
else
|
||||
-- ASCII char?
|
||||
ascii_pos := hexadecimal_string_to_natural_32 (v.substring (pos + 1, pos + 2))
|
||||
Result := ascii_pos
|
||||
a_position.replace (pos + 2)
|
||||
end
|
||||
end
|
||||
|
||||
next_percent_decoded_unicode_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Next decoded character from `v' at position `a_position.item'
|
||||
-- note: it also updates `a_position' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
n, j: INTEGER
|
||||
c: NATURAL_32
|
||||
c1, c2, c3, c4: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
do
|
||||
create pr.put (a_position.item)
|
||||
c1 := next_percent_decoded_character_code (v, pr)
|
||||
|
||||
j := pr.item
|
||||
n := v.count
|
||||
|
||||
Result := c1
|
||||
a_position.replace (j)
|
||||
|
||||
if c1 <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
Result := c1
|
||||
elseif c1 <= 0xDF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
Result := (
|
||||
((c1 & 0x1F) |<< 6) |
|
||||
( c2 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xEF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
Result := (
|
||||
((c1 & 0xF) |<< 12) |
|
||||
((c2 & 0x3F) |<< 6) |
|
||||
( c3 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xF7 then
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c4 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
a_position.replace (j)
|
||||
|
||||
Result := (
|
||||
((c1 & 0x7) |<< 18 ) |
|
||||
((c2 & 0x3F) |<< 12) |
|
||||
((c3 & 0x3F) |<< 6) |
|
||||
( c4 & 0x3F )
|
||||
)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
Result := c1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- RFC and characters
|
||||
|
||||
is_hexa_decimal_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is hexadecimal character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F') -- HEXA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_or_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA or DIGIT character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z')
|
||||
end
|
||||
|
||||
is_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is DIGIT character ?
|
||||
do
|
||||
Result := ('0' <= c and c <= '9')
|
||||
end
|
||||
|
||||
is_unreserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
do
|
||||
if
|
||||
('a' <= c and c <= 'z') -- ALPHA
|
||||
or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
inspect c
|
||||
when '-', '_', '.', '~' then -- unreserved
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_reserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- reserved = gen-delims / sub-delims
|
||||
do
|
||||
Result := is_gen_delims_character (c) or is_sub_delims_character (c)
|
||||
end
|
||||
|
||||
is_gen_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
do
|
||||
inspect c
|
||||
when ':' , '/', '?' , '#' , '[' , ']' , '@' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
is_sub_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
-- / "*" / "+" / "," / ";" / "="
|
||||
do
|
||||
inspect c
|
||||
when '!' , '$' , '&' , '%'' , '(' , ')' , '*' , '+' , ',' , ';' , '=' then -- sub-delims
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
hex_digit: SPECIAL [NATURAL_32]
|
||||
-- Hexadecimal digits.
|
||||
once
|
||||
create Result.make_filled (0, 16)
|
||||
Result [0] := {NATURAL_32} 48 -- 48 '0'
|
||||
Result [1] := {NATURAL_32} 49 -- 49 '1'
|
||||
Result [2] := {NATURAL_32} 50 -- 50 '2'
|
||||
Result [3] := {NATURAL_32} 51 -- 51 '3'
|
||||
Result [4] := {NATURAL_32} 52 -- 52 '4'
|
||||
Result [5] := {NATURAL_32} 53 -- 53 '5'
|
||||
Result [6] := {NATURAL_32} 54 -- 54 '6'
|
||||
Result [7] := {NATURAL_32} 55 -- 55 '7'
|
||||
Result [8] := {NATURAL_32} 56 -- 56 '8'
|
||||
Result [9] := {NATURAL_32} 57 -- 57 '9'
|
||||
Result [10] := {NATURAL_32} 65 -- 65 'A'
|
||||
Result [11] := {NATURAL_32} 66 -- 66 'B'
|
||||
Result [12] := {NATURAL_32} 67 -- 67 'C'
|
||||
Result [13] := {NATURAL_32} 68 -- 68 'D'
|
||||
Result [14] := {NATURAL_32} 69 -- 69 'E'
|
||||
Result [15] := {NATURAL_32} 70 -- 70 'F'
|
||||
end
|
||||
|
||||
is_hexa_decimal (a_string: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Is `a_string' a valid hexadecimal sequence?
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_string, {NUMERIC_INFORMATION}.type_natural_32)
|
||||
Result := l_convertor.is_integral_integer
|
||||
end
|
||||
|
||||
hexadecimal_string_to_natural_32 (a_hex_string: READABLE_STRING_GENERAL): NATURAL_32
|
||||
-- Convert hexadecimal value `a_hex_string' to its corresponding NATURAL_32 value.
|
||||
require
|
||||
is_hexa: is_hexa_decimal (a_hex_string)
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_hex_string, {NUMERIC_INFORMATION}.type_no_limitation)
|
||||
Result := l_convertor.parsed_natural_32
|
||||
end
|
||||
|
||||
ctoi_convertor: HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
|
||||
-- Converter used to convert string to integer or natural.
|
||||
once
|
||||
create Result.make
|
||||
Result.set_leading_separators_acceptable (False)
|
||||
Result.set_trailing_separators_acceptable (False)
|
||||
ensure
|
||||
ctoi_convertor_not_void: Result /= Void
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -62,7 +62,7 @@ feature -- Access
|
||||
url_encoded_name: READABLE_STRING_8
|
||||
-- URL encoded string of `name'.
|
||||
do
|
||||
Result := url_encoder.encoded_string (name)
|
||||
Result := url_encoded_string (name)
|
||||
end
|
||||
|
||||
values: LIST [WSF_STRING]
|
||||
|
||||
@@ -50,20 +50,6 @@ feature -- Access
|
||||
url_encoded_value: READABLE_STRING_8
|
||||
-- URL encoded string of `value'.
|
||||
|
||||
frozen string: like value
|
||||
obsolete
|
||||
"Use value [2012-May-31]"
|
||||
do
|
||||
Result := value
|
||||
end
|
||||
|
||||
frozen url_encoded_string: like url_encoded_value
|
||||
obsolete
|
||||
"Use url_encoded_value [2012-May-31]"
|
||||
do
|
||||
Result := url_encoded_value
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
integer_value: INTEGER
|
||||
@@ -137,7 +123,7 @@ feature -- Visitor
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -36,17 +36,17 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: STRING_32
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := Precursor
|
||||
if
|
||||
exists and then
|
||||
attached tmp_name as n
|
||||
attached tmp_path as p
|
||||
then
|
||||
Result.append_character (' ')
|
||||
Result.append_character ('%"')
|
||||
Result.append (n)
|
||||
Result.append (p.name)
|
||||
Result.append_character ('%"')
|
||||
end
|
||||
Result.append (" filename=%"")
|
||||
@@ -108,9 +108,16 @@ feature -- Access: Uploaded File
|
||||
size: INTEGER
|
||||
-- Size of uploaded file
|
||||
|
||||
tmp_name: detachable STRING
|
||||
tmp_path: detachable PATH
|
||||
-- Filename of tmp file
|
||||
|
||||
tmp_name: detachable READABLE_STRING_GENERAL
|
||||
do
|
||||
if attached tmp_path as p then
|
||||
Result := p.name
|
||||
end
|
||||
end
|
||||
|
||||
tmp_basename: detachable STRING
|
||||
-- Basename of tmp file
|
||||
|
||||
@@ -237,7 +244,7 @@ feature -- Implementation
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
move_to (a_destination: STRING): BOOLEAN
|
||||
move_to (a_destination: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Move current uploaded file to `a_destination'
|
||||
--| Violates CQS principle.
|
||||
require
|
||||
@@ -246,10 +253,10 @@ feature -- Basic operation
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
if attached tmp_name as n then
|
||||
create f.make (n)
|
||||
if attached tmp_path as p then
|
||||
create f.make_with_path (p)
|
||||
if f.exists then
|
||||
f.change_name (a_destination)
|
||||
f.rename_file (a_destination)
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
@@ -274,8 +281,8 @@ feature -- Status
|
||||
local
|
||||
f: PLAIN_TEXT_FILE
|
||||
do
|
||||
if attached tmp_name as n then
|
||||
create f.make (n)
|
||||
if attached tmp_path as p then
|
||||
create f.make_with_path (p)
|
||||
Result := f.exists
|
||||
end
|
||||
end
|
||||
@@ -288,10 +295,19 @@ feature -- Element change
|
||||
error := e
|
||||
end
|
||||
|
||||
set_tmp_path (p: like tmp_path)
|
||||
do
|
||||
tmp_path := p
|
||||
end
|
||||
|
||||
set_tmp_name (n: like tmp_name)
|
||||
-- Set `tmp_name' to `n'
|
||||
do
|
||||
tmp_name := n
|
||||
if n /= Void then
|
||||
set_tmp_path (create {PATH}.make_from_string (n))
|
||||
else
|
||||
set_tmp_path (Void)
|
||||
end
|
||||
end
|
||||
|
||||
set_tmp_basename (n: like tmp_basename)
|
||||
|
||||
@@ -9,6 +9,13 @@ deferred class
|
||||
inherit
|
||||
DEBUG_OUTPUT
|
||||
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoder as url_encoder
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: READABLE_STRING_32
|
||||
@@ -91,23 +98,26 @@ feature -- Helper
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: STRING_32
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
create Result.make_from_string (url_encoder.encoded_string (name) + "=" + url_encoder.encoded_string (string_representation))
|
||||
create Result.make_from_string (name + {STRING_32} "=" + string_representation)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
url_decoded_string (s: READABLE_STRING_8): READABLE_STRING_32
|
||||
url_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
-- Decoded url-encoded string `s'
|
||||
do
|
||||
Result := url_encoder.decoded_string (s)
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_encoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create {UTF8_URL_ENCODER} Result --| Chrome is UTF-8 encoding the non ascii in query
|
||||
url_decoded_string (s: READABLE_STRING_GENERAL): STRING_32
|
||||
-- Decoded url-encoded string `s'
|
||||
do
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_decoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
feature -- Visitor
|
||||
@@ -117,7 +127,7 @@ feature -- Visitor
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -10,6 +10,8 @@ class
|
||||
inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
SHARED_UTF8_URL_ENCODER
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_content_type,
|
||||
@@ -17,26 +19,26 @@ create
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_file_name: READABLE_STRING_8)
|
||||
make (a_file_name: READABLE_STRING_GENERAL)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_file_name
|
||||
base_name := basename (a_file_name)
|
||||
create file_path.make_from_string (a_file_name)
|
||||
base_name := basename (file_path)
|
||||
get_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_filename: READABLE_STRING_8)
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_filename
|
||||
base_name := basename (a_filename)
|
||||
create file_path.make_from_string (a_filename)
|
||||
base_name := basename (file_path)
|
||||
content_type := a_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_html (a_filename: READABLE_STRING_8)
|
||||
make_html (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type ({HTTP_MIME_TYPES}.text_html, a_filename)
|
||||
@@ -45,15 +47,14 @@ feature {NONE} -- Initialization
|
||||
initialize
|
||||
local
|
||||
h: like header
|
||||
d: HTTP_DATE
|
||||
do
|
||||
create h.make
|
||||
header := h
|
||||
h.put_content_type (content_type)
|
||||
h.put_transfer_encoding_binary
|
||||
h.put_content_length (filesize (file_name))
|
||||
h.put_content_length (filesize (file_path))
|
||||
h.put_content_disposition ("attachment", "filename=%""+ base_name +"%"")
|
||||
if attached filedate (file_name) as dt then
|
||||
if attached filedate (file_path) as dt then
|
||||
h.put_last_modified (dt)
|
||||
end
|
||||
end
|
||||
@@ -89,7 +90,14 @@ feature -- Access
|
||||
|
||||
status_code: INTEGER assign set_status_code
|
||||
|
||||
file_path: PATH
|
||||
|
||||
file_name: READABLE_STRING_8
|
||||
obsolete
|
||||
"Use `file_path.name' for unicode support [2013-may]"
|
||||
do
|
||||
Result := file_path.utf_8_name
|
||||
end
|
||||
|
||||
base_name: READABLE_STRING_8
|
||||
|
||||
@@ -125,73 +133,57 @@ feature {WSF_RESPONSE} -- Output
|
||||
res.set_status_code (status_code)
|
||||
res.put_header_text (header.string)
|
||||
if not answer_head_request_method then
|
||||
send_file_content_to (file_name, res)
|
||||
send_file_content_to (file_path, res)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: file system helper
|
||||
|
||||
filesize (fn: STRING): INTEGER
|
||||
filesize (fn: PATH): INTEGER
|
||||
-- Size of the file `fn'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
if f.exists then
|
||||
Result := f.count
|
||||
end
|
||||
end
|
||||
|
||||
filedate (fn: STRING): detachable DATE_TIME
|
||||
filedate (fn: PATH): detachable DATE_TIME
|
||||
-- Size of the file `fn'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
d: HTTP_DATE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
if f.exists then
|
||||
create d.make_from_timestamp (f.date)
|
||||
Result := d.date_time
|
||||
end
|
||||
end
|
||||
|
||||
file_extension (fn: STRING): STRING
|
||||
file_extension (fn: PATH): STRING_32
|
||||
-- Extension of file `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := fn.last_index_of ('.', fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (p + 1, fn.count)
|
||||
if attached fn.extension as ext then
|
||||
Result := ext
|
||||
else
|
||||
create Result.make_empty
|
||||
end
|
||||
end
|
||||
|
||||
basename (fn: STRING): STRING
|
||||
basename (fn: PATH): STRING
|
||||
-- Basename of `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
s: READABLE_STRING_32
|
||||
do
|
||||
p := fn.last_index_of ((create {OPERATING_ENVIRONMENT}).Directory_separator, fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (p + 1, fn.count)
|
||||
if attached fn.entry as p then
|
||||
s := p.name
|
||||
else
|
||||
Result := fn
|
||||
end
|
||||
end
|
||||
|
||||
dirname (fn: STRING): STRING
|
||||
-- Dirname of `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := fn.last_index_of ((create {OPERATING_ENVIRONMENT}).Directory_separator, fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (1, p - 1)
|
||||
else
|
||||
create Result.make_empty
|
||||
s := fn.name
|
||||
end
|
||||
Result := url_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
feature -- Content-type related
|
||||
@@ -203,7 +195,7 @@ feature -- Content-type related
|
||||
m: detachable READABLE_STRING_8
|
||||
do
|
||||
create m_map.make_default
|
||||
m := m_map.mime_type (file_extension (file_name).as_lower)
|
||||
m := m_map.mime_type (file_extension (file_path).as_lower)
|
||||
if m = Void then
|
||||
m := {HTTP_MIME_TYPES}.application_force_download
|
||||
end
|
||||
@@ -212,15 +204,15 @@ feature -- Content-type related
|
||||
|
||||
feature -- Implementation: output
|
||||
|
||||
send_file_content_to (fn: READABLE_STRING_8; res: WSF_RESPONSE)
|
||||
send_file_content_to (fn: PATH; res: WSF_RESPONSE)
|
||||
-- Send the content of file `fn'
|
||||
require
|
||||
string_not_empty: not fn.is_empty
|
||||
is_readable: (create {RAW_FILE}.make (fn)).is_readable
|
||||
is_readable: (create {RAW_FILE}.make_with_path (fn)).is_readable
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
check f.exists and then f.is_readable end
|
||||
|
||||
f.open_read
|
||||
|
||||
@@ -11,30 +11,49 @@ inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
create
|
||||
make_with_path,
|
||||
make_with_content_type_and_path,
|
||||
make_html_with_path,
|
||||
make,
|
||||
make_with_content_type,
|
||||
make_html
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_file_name: READABLE_STRING_8)
|
||||
make_with_path (a_path: PATH)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_file_name
|
||||
file_path := a_path
|
||||
get_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_filename: READABLE_STRING_8)
|
||||
-- Initialize `Current'.
|
||||
make_with_content_type_and_path (a_content_type: READABLE_STRING_8; a_path: PATH)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_filename
|
||||
file_path := a_path
|
||||
content_type := a_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_html (a_filename: READABLE_STRING_8)
|
||||
make_html_with_path (a_path: PATH)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type_and_path ({HTTP_MIME_TYPES}.text_html, a_path)
|
||||
end
|
||||
|
||||
make (a_file_name: READABLE_STRING_GENERAL)
|
||||
do
|
||||
make_with_path (create {PATH}.make_from_string (a_file_name))
|
||||
end
|
||||
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_file_name: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type_and_path (a_content_type, create {PATH}.make_from_string (a_file_name))
|
||||
end
|
||||
|
||||
make_html (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type ({HTTP_MIME_TYPES}.text_html, a_filename)
|
||||
@@ -118,13 +137,21 @@ feature -- Access
|
||||
content_type: READABLE_STRING_8
|
||||
-- Content-Type of the response
|
||||
|
||||
file_path: path
|
||||
-- File path
|
||||
|
||||
file_name: READABLE_STRING_8
|
||||
obsolete
|
||||
"Use `file_path.name' for unicode support [2013-may]"
|
||||
do
|
||||
Result := file_path.utf_8_name
|
||||
end
|
||||
|
||||
file_exists: BOOLEAN
|
||||
-- File exists?
|
||||
|
||||
file_size: INTEGER
|
||||
-- Size of file named `file_name'
|
||||
-- Size of file `file_path'
|
||||
|
||||
head, bottom: detachable READABLE_STRING_8
|
||||
-- Eventual head and bottom part
|
||||
@@ -184,7 +211,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
res.put_string (s)
|
||||
end
|
||||
if not answer_head_request_method then
|
||||
send_file_content_to (file_name, res)
|
||||
send_file_content_to (file_path, res)
|
||||
end
|
||||
s := bottom
|
||||
if s /= Void then
|
||||
@@ -200,40 +227,37 @@ feature {NONE} -- Implementation: file system helper
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name)
|
||||
create f.make_with_path (file_path)
|
||||
file_exists := f.exists
|
||||
end
|
||||
|
||||
get_file_size
|
||||
-- Get `file_size' from file named `file_name'
|
||||
-- Get `file_size' from file named `file_path'
|
||||
require
|
||||
file_exists: file_exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name)
|
||||
create f.make_with_path (file_path)
|
||||
file_size := f.count
|
||||
end
|
||||
|
||||
file_last_modified: detachable DATE_TIME
|
||||
-- Get `file_size' from file named `file_name'
|
||||
-- Get `file_size' from file named `file_path'
|
||||
require
|
||||
file_exists: file_exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name)
|
||||
create f.make_with_path (file_path)
|
||||
create Result.make_from_epoch (f.change_date)
|
||||
end
|
||||
|
||||
file_extension (fn: STRING): STRING
|
||||
file_extension (fn: PATH): STRING_32
|
||||
-- Extension of file `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := fn.last_index_of ('.', fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (p + 1, fn.count)
|
||||
if attached fn.extension as ext then
|
||||
Result := ext
|
||||
else
|
||||
create Result.make_empty
|
||||
end
|
||||
@@ -242,13 +266,13 @@ feature {NONE} -- Implementation: file system helper
|
||||
feature -- Content-type related
|
||||
|
||||
get_content_type
|
||||
-- Content type associated with `file_name'
|
||||
-- Content type associated with `file_path'
|
||||
local
|
||||
m_map: HTTP_FILE_EXTENSION_MIME_MAPPING
|
||||
m: detachable READABLE_STRING_8
|
||||
do
|
||||
create m_map.make_default
|
||||
m := m_map.mime_type (file_extension (file_name).as_lower)
|
||||
m := m_map.mime_type (file_extension (file_path).as_lower)
|
||||
if m = Void then
|
||||
m := {HTTP_MIME_TYPES}.application_force_download
|
||||
end
|
||||
@@ -257,16 +281,16 @@ feature -- Content-type related
|
||||
|
||||
feature {NONE} -- Implementation: output
|
||||
|
||||
send_file_content_to (fn: READABLE_STRING_8; res: WSF_RESPONSE)
|
||||
send_file_content_to (fn: PATH; res: WSF_RESPONSE)
|
||||
-- Send the content of file `fn'
|
||||
require
|
||||
string_not_empty: not fn.is_empty
|
||||
is_readable: (create {RAW_FILE}.make (fn)).is_readable
|
||||
is_readable: (create {RAW_FILE}.make_with_path (fn)).is_readable
|
||||
file_exists: file_exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
check f.is_readable end
|
||||
|
||||
f.open_read
|
||||
|
||||
@@ -15,7 +15,7 @@ class
|
||||
WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
|
||||
inherit
|
||||
ANY
|
||||
TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
@@ -23,7 +23,8 @@ inherit
|
||||
create
|
||||
default_create,
|
||||
make,
|
||||
make_from_array
|
||||
make_from_array,
|
||||
make_from_iterable
|
||||
|
||||
convert
|
||||
make_from_array ({ARRAY [TUPLE [name: READABLE_STRING_GENERAL; value: detachable ANY]]})
|
||||
@@ -44,6 +45,19 @@ feature {NONE} -- Initialization
|
||||
make_from_array (a_options: ARRAY [TUPLE [name: READABLE_STRING_GENERAL; value: detachable ANY]])
|
||||
do
|
||||
make
|
||||
append_array_of_options (a_options)
|
||||
end
|
||||
|
||||
make_from_iterable (a_options: TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL])
|
||||
do
|
||||
make
|
||||
append_options (a_options)
|
||||
end
|
||||
|
||||
feature -- Merging
|
||||
|
||||
append_array_of_options (a_options: ARRAY [TUPLE [name: READABLE_STRING_GENERAL; value: detachable ANY]])
|
||||
do
|
||||
across
|
||||
a_options as opt
|
||||
loop
|
||||
@@ -53,6 +67,15 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
end
|
||||
|
||||
append_options (a_options: TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL])
|
||||
do
|
||||
across
|
||||
a_options as o
|
||||
loop
|
||||
set_option (o.key, o.item)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
option (a_name: READABLE_STRING_GENERAL): detachable ANY
|
||||
@@ -60,6 +83,14 @@ feature -- Access
|
||||
Result := options.item (a_name)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_cursor: TABLE_ITERATION_CURSOR [detachable ANY, READABLE_STRING_GENERAL]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := options.new_cursor
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_option (a_name: READABLE_STRING_GENERAL; a_value: detachable ANY)
|
||||
@@ -75,13 +106,13 @@ feature -- Element change
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
options: HASH_TABLE [detachable ANY, READABLE_STRING_GENERAL]
|
||||
options: STRING_TABLE [detachable ANY]
|
||||
-- Custom options which might be support (or not) by the default service
|
||||
|
||||
invariant
|
||||
options_attached: options /= Void
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -11,28 +11,40 @@ inherit
|
||||
WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
|
||||
create
|
||||
make_from_file
|
||||
make_from_file,
|
||||
make_from_file_and_defaults
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_from_file (a_filename: READABLE_STRING_32)
|
||||
make_from_file (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make
|
||||
import (a_filename)
|
||||
end
|
||||
|
||||
make_from_file_and_defaults (a_filename: READABLE_STRING_GENERAL; dft: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make
|
||||
|
||||
if dft /= Void then
|
||||
append_options (dft)
|
||||
end
|
||||
|
||||
import (a_filename)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
import (a_filename: READABLE_STRING_32)
|
||||
import (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Import ini file content
|
||||
local
|
||||
f: PLAIN_TEXT_FILE
|
||||
l,v: STRING_8
|
||||
p: INTEGER
|
||||
do
|
||||
--FIXME: handle unicode filename here.
|
||||
create f.make (a_filename)
|
||||
create f.make_with_name (a_filename)
|
||||
if f.exists and f.is_readable then
|
||||
f.open_read
|
||||
from
|
||||
@@ -60,7 +72,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -26,6 +26,18 @@ class
|
||||
inherit
|
||||
DEBUG_OUTPUT
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoder as url_encoder
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create {WSF_TO_WGI_SERVICE}
|
||||
make_from_wgi
|
||||
|
||||
@@ -40,26 +52,25 @@ feature {NONE} -- Initialization
|
||||
do
|
||||
wgi_request := r
|
||||
|
||||
create string_equality_tester
|
||||
if attached r.meta_variables as l_vars then
|
||||
create tb.make_with_key_tester (l_vars.count, string_equality_tester)
|
||||
create tb.make_equal (l_vars.count)
|
||||
across
|
||||
l_vars as c
|
||||
loop
|
||||
tb.force (new_string_value (c.key, c.item), c.key)
|
||||
if attached {READABLE_STRING_8} c.key as s8 then
|
||||
tb.force (new_string_value (s8, c.item), c.key)
|
||||
else
|
||||
tb.force (new_string_value (url_encoded_string (c.key), c.item), c.key)
|
||||
end
|
||||
end
|
||||
else
|
||||
create tb.make_with_key_tester (0, string_equality_tester)
|
||||
create tb.make_equal (0)
|
||||
end
|
||||
meta_variables_table := tb
|
||||
meta_variables := tb
|
||||
create error_handler.make
|
||||
create uploaded_files_table.make_with_key_tester (0, string_equality_tester)
|
||||
create uploaded_files_table.make_equal (0)
|
||||
set_raw_input_data_recorded (False)
|
||||
create {IMMUTABLE_STRING_32} empty_string.make_empty
|
||||
|
||||
create execution_variables_table.make_with_key_tester (0, string_equality_tester)
|
||||
execution_variables_table.compare_objects
|
||||
create execution_variables_table.make_equal (0)
|
||||
|
||||
initialize
|
||||
analyze
|
||||
@@ -96,12 +107,13 @@ feature {NONE} -- Initialization
|
||||
request_method := req.request_method
|
||||
|
||||
--| PATH_INFO
|
||||
path_info := raw_url_encoder.decoded_string (req.path_info)
|
||||
percent_encoded_path_info := req.path_info
|
||||
path_info := url_decoded_string (req.path_info)
|
||||
|
||||
--| PATH_TRANSLATED
|
||||
s8 := req.path_translated
|
||||
if s8 /= Void then
|
||||
path_translated := raw_url_encoder.decoded_string (s8)
|
||||
path_translated := url_decoded_string (s8)
|
||||
end
|
||||
|
||||
--| Here one can set its own environment entries if needed
|
||||
@@ -111,6 +123,7 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
|
||||
wgi_request: WGI_REQUEST
|
||||
-- Associated WGI request
|
||||
|
||||
feature -- Destroy
|
||||
|
||||
@@ -125,6 +138,26 @@ feature -- Destroy
|
||||
loop
|
||||
delete_uploaded_file (c.item)
|
||||
end
|
||||
|
||||
content_length_value := 0
|
||||
content_type := Void
|
||||
execution_variables_table.wipe_out
|
||||
internal_cookies_table := Void
|
||||
internal_form_data_parameters_table := Void
|
||||
internal_query_parameters_table := Void
|
||||
internal_server_url := Void
|
||||
internal_url_base := Void
|
||||
form_parameters_table.wipe_out
|
||||
mime_handlers := Void
|
||||
path_info := empty_string_32
|
||||
path_parameters_source := Void
|
||||
path_parameters_table := Void
|
||||
path_translated := Void
|
||||
raw_input_data := Void
|
||||
raw_input_data_recorded := False
|
||||
request_method := empty_string_8
|
||||
set_uploaded_file_path (Void)
|
||||
-- wgi_request
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
@@ -353,12 +386,12 @@ feature {WSF_REQUEST_EXPORTER} -- Override value
|
||||
|
||||
feature {NONE} -- Access: global variable
|
||||
|
||||
items_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
items_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Table containing all the various variables
|
||||
-- Warning: this is computed each time, if you change the content of other containers
|
||||
-- this won't update this Result's content, unless you query it again
|
||||
do
|
||||
create Result.make_with_key_tester (20, string_equality_tester)
|
||||
create Result.make_equal (20)
|
||||
|
||||
if attached path_parameters as l_path_parameters then
|
||||
across
|
||||
@@ -558,7 +591,7 @@ feature -- Execution variables
|
||||
|
||||
feature {NONE} -- Execution variables: implementation
|
||||
|
||||
execution_variables_table: HASH_TABLE_EX [detachable ANY, READABLE_STRING_GENERAL]
|
||||
execution_variables_table: STRING_TABLE [detachable ANY]
|
||||
|
||||
feature -- Access: CGI Meta variables
|
||||
|
||||
@@ -582,6 +615,9 @@ feature -- Access: CGI Meta variables
|
||||
|
||||
meta_variables: ITERABLE [WSF_STRING]
|
||||
-- CGI meta variables values
|
||||
do
|
||||
Result := meta_variables_table
|
||||
end
|
||||
|
||||
meta_string_variable_or_default (a_name: READABLE_STRING_GENERAL; a_default: READABLE_STRING_32; use_default_when_empty: BOOLEAN): READABLE_STRING_32
|
||||
-- Value for meta parameter `a_name'
|
||||
@@ -617,7 +653,7 @@ feature -- Access: CGI Meta variables
|
||||
|
||||
feature {NONE} -- Access: CGI meta parameters
|
||||
|
||||
meta_variables_table: HASH_TABLE_EX [WSF_STRING, READABLE_STRING_GENERAL]
|
||||
meta_variables_table: STRING_TABLE [WSF_STRING]
|
||||
-- CGI Environment parameters
|
||||
|
||||
feature -- Access: CGI meta parameters - 1.1
|
||||
@@ -739,6 +775,11 @@ feature -- Access: CGI meta parameters - 1.1
|
||||
Result := wgi_request.gateway_interface
|
||||
end
|
||||
|
||||
percent_encoded_path_info: READABLE_STRING_8
|
||||
-- Non decoded PATH_INFO value from CGI.
|
||||
-- See `path_info' for the related percent decoded value.
|
||||
--| This value should be used by component dealing only with ASCII path
|
||||
|
||||
path_info: READABLE_STRING_32
|
||||
-- The PATH_INFO metavariable specifies a path to be interpreted
|
||||
-- by the CGI script. It identifies the resource or sub-resource
|
||||
@@ -767,6 +808,8 @@ feature -- Access: CGI meta parameters - 1.1
|
||||
-- The PATH_INFO value is case-sensitive, and the server MUST
|
||||
-- preserve the case of the PATH_INFO element of the URI when
|
||||
-- making it available to scripts.
|
||||
--
|
||||
-- See `percent_encoded_path_info' to get the original non decoded path info.
|
||||
|
||||
path_translated: detachable READABLE_STRING_32
|
||||
-- PATH_TRANSLATED is derived by taking any path-info component
|
||||
@@ -1150,7 +1193,7 @@ feature -- Cookies
|
||||
|
||||
feature {NONE} -- Cookies
|
||||
|
||||
cookies_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
cookies_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Expanded cookies variable
|
||||
local
|
||||
i,j,p,n: INTEGER
|
||||
@@ -1161,8 +1204,7 @@ feature {NONE} -- Cookies
|
||||
if l_cookies = Void then
|
||||
if attached {WSF_STRING} meta_variable ({WSF_META_NAMES}.http_cookie) as val then
|
||||
s := val.value
|
||||
create l_cookies.make_with_key_tester (5, string_equality_tester)
|
||||
l_cookies.compare_objects
|
||||
create l_cookies.make_equal (5)
|
||||
from
|
||||
n := s.count
|
||||
p := 1
|
||||
@@ -1190,8 +1232,7 @@ feature {NONE} -- Cookies
|
||||
end
|
||||
end
|
||||
else
|
||||
create l_cookies.make_with_key_tester (0, string_equality_tester)
|
||||
l_cookies.compare_objects
|
||||
create l_cookies.make_equal (0)
|
||||
end
|
||||
internal_cookies_table := l_cookies
|
||||
end
|
||||
@@ -1217,7 +1258,7 @@ feature -- Path parameters
|
||||
|
||||
feature {NONE} -- Query parameters: implementation
|
||||
|
||||
path_parameters_table: detachable HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
path_parameters_table: detachable STRING_TABLE [WSF_VALUE]
|
||||
-- Parameters computed from `path_parameters_source'
|
||||
--| most often coming from the associated route from WSF_ROUTER
|
||||
|
||||
@@ -1240,8 +1281,7 @@ feature {WSF_REQUEST_PATH_PARAMETERS_SOURCE} -- Path parameters: Element change
|
||||
if l_count = 0 then
|
||||
l_table := Void
|
||||
else
|
||||
create l_table.make_with_key_tester (l_count, string_equality_tester)
|
||||
l_table.compare_objects
|
||||
create l_table.make_equal (l_count)
|
||||
if attached src.path_parameters as tb then
|
||||
across
|
||||
tb as c
|
||||
@@ -1278,7 +1318,7 @@ feature -- Query parameters
|
||||
|
||||
feature {NONE} -- Query parameters: implementation
|
||||
|
||||
query_parameters_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
query_parameters_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Parameters extracted from QUERY_STRING
|
||||
local
|
||||
vars: like internal_query_parameters_table
|
||||
@@ -1303,13 +1343,12 @@ feature {NONE} -- Query parameters: implementation
|
||||
end
|
||||
end
|
||||
vars := urlencoded_parameters (s)
|
||||
vars.compare_objects
|
||||
internal_query_parameters_table := vars
|
||||
end
|
||||
Result := vars
|
||||
end
|
||||
|
||||
urlencoded_parameters (a_content: detachable READABLE_STRING_8): HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
urlencoded_parameters (a_content: detachable READABLE_STRING_8): STRING_TABLE [WSF_VALUE]
|
||||
-- Import `a_content'
|
||||
local
|
||||
n, p, i, j: INTEGER
|
||||
@@ -1317,13 +1356,13 @@ feature {NONE} -- Query parameters: implementation
|
||||
l_name, l_value: READABLE_STRING_8
|
||||
do
|
||||
if a_content = Void then
|
||||
create Result.make_with_key_tester (0, string_equality_tester)
|
||||
create Result.make_equal (0)
|
||||
else
|
||||
n := a_content.count
|
||||
if n = 0 then
|
||||
create Result.make_with_key_tester (0, string_equality_tester)
|
||||
create Result.make_equal (0)
|
||||
else
|
||||
create Result.make_with_key_tester (3, string_equality_tester) --| 3 = arbitrary value
|
||||
create Result.make_equal (3) --| 3 = arbitrary value
|
||||
from
|
||||
p := 1
|
||||
until
|
||||
@@ -1348,6 +1387,8 @@ feature {NONE} -- Query parameters: implementation
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_with_object_comparison: Result.object_comparison
|
||||
end
|
||||
|
||||
feature -- Form fields and related
|
||||
@@ -1452,7 +1493,7 @@ feature {NONE} -- Implementation: MIME handler
|
||||
|
||||
feature {NONE} -- Form fields and related
|
||||
|
||||
uploaded_files_table: HASH_TABLE_EX [WSF_UPLOADED_FILE, READABLE_STRING_GENERAL]
|
||||
uploaded_files_table: STRING_TABLE [WSF_UPLOADED_FILE]
|
||||
|
||||
get_form_parameters
|
||||
-- Variables sent by POST, ... request
|
||||
@@ -1464,14 +1505,12 @@ feature {NONE} -- Form fields and related
|
||||
vars := internal_form_data_parameters_table
|
||||
if vars = Void then
|
||||
if not is_chunked_input and content_length_value = 0 then
|
||||
create vars.make_with_key_tester (0, string_equality_tester)
|
||||
vars.compare_objects
|
||||
create vars.make_equal (0)
|
||||
else
|
||||
if raw_input_data_recorded then
|
||||
create l_raw_data_cell.put (Void)
|
||||
end
|
||||
create vars.make_with_key_tester (5, string_equality_tester)
|
||||
vars.compare_objects
|
||||
create vars.make_equal (5)
|
||||
|
||||
l_type := content_type
|
||||
if l_type /= Void and then attached mime_handler (l_type) as hdl then
|
||||
@@ -1488,7 +1527,7 @@ feature {NONE} -- Form fields and related
|
||||
internal_form_data_parameters_table /= Void
|
||||
end
|
||||
|
||||
form_parameters_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
form_parameters_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Variables sent by POST request
|
||||
local
|
||||
vars: like internal_form_data_parameters_table
|
||||
@@ -1497,14 +1536,14 @@ feature {NONE} -- Form fields and related
|
||||
vars := internal_form_data_parameters_table
|
||||
if vars = Void then
|
||||
check form_parameters_already_retrieved: False end
|
||||
create vars.make_with_key_tester (0, string_equality_tester)
|
||||
create vars.make_equal (0)
|
||||
end
|
||||
Result := vars
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: smart parameter identification
|
||||
|
||||
add_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL])
|
||||
add_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: STRING_TABLE [WSF_VALUE])
|
||||
-- Add urlencoded parameter `a_name'=`a_value' to `a_table'
|
||||
-- following smart computation such as handling the "..[..]" as table
|
||||
local
|
||||
@@ -1548,7 +1587,7 @@ feature {NONE} -- Implementation: smart parameter identification
|
||||
if p > 0 then
|
||||
q := r.index_of ({CHARACTER_8} ']', p + 1)
|
||||
if q > p then
|
||||
k32 := url_encoder.decoded_string (k)
|
||||
k32 := url_decoded_string (k)
|
||||
if attached {WSF_TABLE} ptb.value (k32) as l_tb_value then
|
||||
tb := l_tb_value
|
||||
else
|
||||
@@ -1610,7 +1649,7 @@ feature -- Uploaded File Handling
|
||||
until
|
||||
l_files.after or Result
|
||||
loop
|
||||
if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string_general (a_filename) then
|
||||
if attached l_files.item_for_iteration.tmp_path as l_tmp_path and then a_filename.same_string (l_tmp_path.name) then
|
||||
Result := True
|
||||
end
|
||||
l_files.forth
|
||||
@@ -1686,7 +1725,7 @@ feature -- URL Utility
|
||||
elseif spos > 0 then
|
||||
i := spos
|
||||
end
|
||||
spos := l_rq_uri.substring_index (path_info, i)
|
||||
spos := l_rq_uri.substring_index (percent_encoded_path_info, i)
|
||||
if spos > 0 then
|
||||
l_base_url := l_rq_uri.substring (1, spos - 1)
|
||||
else
|
||||
@@ -1736,18 +1775,18 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
f: RAW_FILE
|
||||
do
|
||||
if uploaded_files_table.has_item (uf) then
|
||||
if attached uf.tmp_name as fn then
|
||||
create f.make (fn)
|
||||
if attached uf.tmp_path as fn then
|
||||
create f.make_with_path (fn)
|
||||
if f.exists and then f.is_writable then
|
||||
f.delete
|
||||
else
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete file %""+ fn +"%"")
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", {STRING_32} "Can not delete file %""+ fn.name + {STRING_32} "%"")
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete uploaded file %""+ uf.name +"%" Tmp File not found")
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", {STRING_32} "Can not delete uploaded file %""+ uf.name + {STRING_32} "%" Tmp File not found")
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "Not an uploaded file", "This file %""+ uf.name +"%" is not an uploaded file.")
|
||||
error_handler.add_custom_error (0, "Not an uploaded file", {STRING_32} "This file %""+ uf.name + {STRING_32} "%" is not an uploaded file.")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1757,8 +1796,8 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
bn: STRING
|
||||
l_safe_name: STRING
|
||||
f: RAW_FILE
|
||||
dn: STRING
|
||||
fn: FILE_NAME
|
||||
dn: PATH
|
||||
fn: PATH
|
||||
d: DIRECTORY
|
||||
n: INTEGER
|
||||
rescued: BOOLEAN
|
||||
@@ -1768,30 +1807,28 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
dn := p
|
||||
else
|
||||
-- FIXME: should it be configured somewhere?
|
||||
dn := (create {EXECUTION_ENVIRONMENT}).current_working_directory
|
||||
dn := execution_environment.current_working_path
|
||||
end
|
||||
create d.make (dn)
|
||||
create d.make_with_path (dn)
|
||||
if d.exists and then d.is_writable then
|
||||
l_safe_name := a_up_file.safe_filename
|
||||
from
|
||||
create fn.make_from_string (dn)
|
||||
bn := "EWF_tmp-" + l_safe_name
|
||||
fn.set_file_name (bn)
|
||||
create f.make (fn.string)
|
||||
bn := "tmp-" + l_safe_name
|
||||
fn := dn.extended (bn)
|
||||
create f.make_with_path (fn)
|
||||
n := 0
|
||||
until
|
||||
not f.exists
|
||||
or else n > 1_000
|
||||
loop
|
||||
n := n + 1
|
||||
fn.make_from_string (dn)
|
||||
bn := "EWF_tmp-" + n.out + "-" + l_safe_name
|
||||
fn.set_file_name (bn)
|
||||
f.make (fn.string)
|
||||
bn := "tmp-" + n.out + "-" + l_safe_name
|
||||
fn := dn.extended (bn)
|
||||
f.make_with_path (fn)
|
||||
end
|
||||
|
||||
if not f.exists or else f.is_writable then
|
||||
a_up_file.set_tmp_name (f.name)
|
||||
a_up_file.set_tmp_path (f.path)
|
||||
a_up_file.set_tmp_basename (bn)
|
||||
f.open_write
|
||||
f.put_string (a_content)
|
||||
@@ -1800,7 +1837,7 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
a_up_file.set_error (-1)
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "Directory not writable", "Can not create file in directory %""+ dn +"%"")
|
||||
error_handler.add_custom_error (0, "Directory not writable", {STRING_32} "Can not create file in directory %""+ dn.name + {STRING_32} "%"")
|
||||
end
|
||||
uploaded_files_table.force (a_up_file, a_up_file.name)
|
||||
else
|
||||
@@ -1813,13 +1850,13 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
|
||||
feature {WSF_REQUEST_EXPORTER} -- Settings
|
||||
|
||||
uploaded_file_path: detachable READABLE_STRING_8
|
||||
uploaded_file_path: detachable PATH
|
||||
-- Optional folder path used to store uploaded files
|
||||
|
||||
set_uploaded_file_path (p: like uploaded_file_path)
|
||||
-- Set `uploaded_file_path' to `p'.
|
||||
require
|
||||
path_exists: p /= Void implies (create {DIRECTORY}.make (p)).exists
|
||||
path_exists: p /= Void implies (create {DIRECTORY}.make_with_path (p)).exists
|
||||
do
|
||||
uploaded_file_path := p
|
||||
end
|
||||
@@ -1874,8 +1911,6 @@ feature {NONE} -- Implementation
|
||||
|
||||
feature {NONE} -- Implementation: utilities
|
||||
|
||||
string_equality_tester: STRING_EQUALITY_TESTER
|
||||
|
||||
single_slash_starting_string (s: READABLE_STRING_32): STRING_32
|
||||
-- Return the string `s' (or twin) with one and only one starting slash
|
||||
local
|
||||
@@ -1927,17 +1962,27 @@ feature {NONE} -- Implementation: utilities
|
||||
create Result.make (a_name, a_value)
|
||||
end
|
||||
|
||||
empty_string: READABLE_STRING_32
|
||||
empty_string_32: IMMUTABLE_STRING_32
|
||||
-- Reusable empty string
|
||||
|
||||
raw_url_encoder: URL_ENCODER
|
||||
once
|
||||
create {URL_ENCODER} Result
|
||||
create Result.make_empty
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
empty_string_8: IMMUTABLE_STRING_8
|
||||
once
|
||||
create {UTF8_URL_ENCODER} Result
|
||||
create Result.make_empty
|
||||
end
|
||||
|
||||
url_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
do
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_encoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
url_decoded_string (s: READABLE_STRING_GENERAL): STRING_32
|
||||
do
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_decoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
date_time_utilities: HTTP_DATE_TIME_UTILITIES
|
||||
@@ -1947,7 +1992,8 @@ feature {NONE} -- Implementation: utilities
|
||||
end
|
||||
|
||||
invariant
|
||||
empty_string_unchanged: empty_string.is_empty
|
||||
empty_string_32_unchanged: empty_string_32.is_empty
|
||||
empty_string_8_unchanged: empty_string_8.is_empty
|
||||
wgi_request.content_type /= Void implies content_type /= Void
|
||||
|
||||
note
|
||||
|
||||
@@ -11,22 +11,10 @@
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="encoding" location="$ISE_LIBRARY\library\encoding\encoding-safe.ecf"/>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/tests$</exclude>
|
||||
<exclude>/spec$</exclude>
|
||||
</file_rule>
|
||||
<cluster name="src_before_70" location="$|spec\before_70\" recursive="true">
|
||||
<condition>
|
||||
<version type="compiler" max="7.0.8.7585"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="src_70" location="$|spec\70\" recursive="true">
|
||||
<condition>
|
||||
<version type="compiler" min="7.0.8.7586"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -11,22 +11,10 @@
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="encoding" location="$ISE_LIBRARY\library\encoding\encoding.ecf"/>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/tests$</exclude>
|
||||
<exclude>/spec$</exclude>
|
||||
</file_rule>
|
||||
<cluster name="src_before_70" location="$\spec\before_70" recursive="true">
|
||||
<condition>
|
||||
<version type="compiler" max="7.0.8.7585"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="src_70" location="$\spec\70" recursive="true">
|
||||
<condition>
|
||||
<version type="compiler" min="7.0.8.7586"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
description: "Objects to access the shared once UTF8_URL_ENCODER ..."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
UTF8_ENCODER_HELPER
|
||||
class
|
||||
SHARED_UTF8_URL_ENCODER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
feature -- Encoder
|
||||
|
||||
UNICODE_CONVERSION
|
||||
export
|
||||
{NONE} all
|
||||
{ANY} is_valid_utf8
|
||||
undefine
|
||||
is_little_endian
|
||||
url_encoder: UTF8_URL_ENCODER
|
||||
-- Shared UTF8 URL encoder.
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
@@ -29,4 +24,5 @@ note
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
|
||||
end
|
||||
@@ -1,73 +0,0 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
UTF8_ENCODER_HELPER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
UNICODE_CONVERSION
|
||||
export
|
||||
{NONE} all
|
||||
undefine
|
||||
is_little_endian
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_valid_utf8 (a_string: STRING): BOOLEAN
|
||||
-- Is `a_string' valid UTF-8 string?
|
||||
require
|
||||
a_string_not_void: a_string /= Void
|
||||
local
|
||||
l_nat8: NATURAL_8
|
||||
l_code: NATURAL_32
|
||||
i, nb: INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
nb := a_string.count
|
||||
Result := True
|
||||
until
|
||||
i > nb or not Result
|
||||
loop
|
||||
l_nat8 := a_string.code (i).to_natural_8
|
||||
if l_nat8 <= 127 then
|
||||
-- Form 0xxxxxxx.
|
||||
elseif (l_nat8 & 0xE0) = 0xC0 then
|
||||
-- Form 110xxxxx 10xxxxxx.
|
||||
l_code := (l_nat8 & 0x1F).to_natural_32 |<< 6
|
||||
i := i + 1
|
||||
elseif (l_nat8 & 0xF0) = 0xE0 then
|
||||
-- Form 1110xxxx 10xxxxxx 10xxxxxx.
|
||||
i := i + 2
|
||||
elseif (l_nat8 & 0xF8) = 0xF0 then
|
||||
-- Form 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx.
|
||||
i := i + 3
|
||||
elseif (l_nat8 & 0xFC) = 0xF8 then
|
||||
-- Starts with 111110xx
|
||||
Result := False
|
||||
else
|
||||
-- Starts with 1111110x
|
||||
Result := False
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -15,8 +15,6 @@ class
|
||||
inherit
|
||||
ENCODER [READABLE_STRING_32, READABLE_STRING_8]
|
||||
|
||||
UTF8_ENCODER_HELPER
|
||||
|
||||
PLATFORM
|
||||
export
|
||||
{NONE} all
|
||||
@@ -37,9 +35,13 @@ feature -- Encoder
|
||||
|
||||
encoded_string (s: READABLE_STRING_32): STRING_8
|
||||
-- UTF8-encoded value of `s'.
|
||||
do
|
||||
Result := general_encoded_string (s)
|
||||
end
|
||||
|
||||
general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
do
|
||||
Result := utf32_to_utf8 (s)
|
||||
has_error := not last_conversion_successful
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
@@ -48,11 +50,34 @@ feature -- Decoder
|
||||
-- The UTF8-encoded equivalent of the given string
|
||||
do
|
||||
Result := utf8_to_utf32 (v)
|
||||
has_error := not last_conversion_successful
|
||||
has_error := not is_valid_utf8 (v)
|
||||
end
|
||||
|
||||
feature {NONE} -- UTF implementation
|
||||
|
||||
utf32_to_utf8 (s: READABLE_STRING_GENERAL): STRING_8
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
Result := utf.utf_32_string_to_utf_8_string_8 (s)
|
||||
end
|
||||
|
||||
utf8_to_utf32 (s: READABLE_STRING_8): STRING_32
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
Result := utf.utf_8_string_8_to_string_32 (s)
|
||||
end
|
||||
|
||||
is_valid_utf8 (s: READABLE_STRING_8): BOOLEAN
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
Result := utf.is_valid_utf_8_string_8 (s)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
copyright: "2011-2013, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -15,23 +15,24 @@ class
|
||||
inherit
|
||||
URL_ENCODER
|
||||
redefine
|
||||
default_create,
|
||||
name,
|
||||
general_encoded_string,
|
||||
encoded_string, partial_encoded_string,
|
||||
decoded_string
|
||||
select
|
||||
encoded_string,
|
||||
decoded_string,
|
||||
has_error
|
||||
end
|
||||
|
||||
UTF8_ENCODER_HELPER
|
||||
UTF8_ENCODER
|
||||
rename
|
||||
general_encoded_string as utf8_general_encoded_string,
|
||||
encoded_string as utf8_encoded_string,
|
||||
decoded_string as utf8_decoded_string,
|
||||
has_error as utf8_has_error
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
default_create
|
||||
do
|
||||
Precursor {UTF8_ENCODER_HELPER}
|
||||
name
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
@@ -46,27 +47,22 @@ feature -- Encoder
|
||||
encoded_string (s: READABLE_STRING_32): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
do
|
||||
Result := utf32_to_utf8 (s)
|
||||
Result := Precursor (Result)
|
||||
Result := general_encoded_string (s)
|
||||
end
|
||||
|
||||
general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
do
|
||||
if attached {READABLE_STRING_32} s as s32 then
|
||||
Result := utf32_to_utf8 (s32)
|
||||
else
|
||||
Result := s.as_string_8
|
||||
end
|
||||
Result := Precursor (Result)
|
||||
Result := utf8_general_encoded_string (s)
|
||||
Result := Precursor {URL_ENCODER} (Result)
|
||||
has_error := has_error or utf8_has_error
|
||||
end
|
||||
|
||||
partial_encoded_string (s: READABLE_STRING_GENERAL; a_ignore: ARRAY [CHARACTER]): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
do
|
||||
Result := Precursor (s, a_ignore)
|
||||
if not has_error then
|
||||
Result := utf32_to_utf8 (Result)
|
||||
end
|
||||
Result := utf8_general_encoded_string (s)
|
||||
Result := Precursor {URL_ENCODER} (Result, a_ignore)
|
||||
has_error := has_error or utf8_has_error
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
@@ -74,17 +70,15 @@ feature -- Decoder
|
||||
decoded_string (v: READABLE_STRING_8): STRING_32
|
||||
-- The URL-encoded equivalent of the given string
|
||||
do
|
||||
Result := Precursor (v)
|
||||
Result := Precursor {URL_ENCODER} (v)
|
||||
if not has_error then
|
||||
if is_valid_utf8 (Result) then
|
||||
Result := utf8_to_utf32 (Result)
|
||||
has_error := not last_conversion_successful
|
||||
end
|
||||
Result := utf8_decoded_string (Result)
|
||||
has_error := utf8_has_error
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
copyright: "2011-2013, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
BIN
tools/bin/ecf_updater.exe
Normal file
BIN
tools/bin/ecf_updater.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user