Merge branch 'master' of https://github.com/EiffelWebFramework/EWF
Conflicts: draft/application/cms/cms.ecf draft/application/cms/example/src/web_cms.e draft/application/cms/src/cms_configuration.e draft/application/cms/src/cms_default_setup.e draft/application/cms/src/cms_service.e draft/application/cms/src/cms_setup.e draft/application/cms/src/handler/cms_file_system_handler.e draft/application/cms/src/kernel/content/format/filters/cms_html_filter.e draft/application/cms/src/modules/debug/debug_module.e draft/application/cms/src/notification/cms_email.e draft/application/cms/src/notification/cms_storage_mailer.e draft/application/cms/src/storage/cms_sed_storage.e draft/application/cms/src/storage/cms_storage.e library/runtime/process/notification_email/notification_external_mailer.e tools/bin/ecf_updater.exe
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
<library name="wsf" location="..\..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_html" location="..\..\..\library\server\wsf_html\wsf_html-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_session" location="..\..\..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/>
|
||||
<library name="notification_email" location="..\..\..\library\runtime\process\notification_email\notification_email-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
31
draft/application/cms/cms.ecf
Normal file
31
draft/application/cms/cms.ecf
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="cms" library_target="cms" uuid="0D24AE3C-61DA-4E81-8DCF-90C2E65FB669">
|
||||
<target name="cms">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<setting name="exception_trace" value="true"/>
|
||||
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="encoder" location="..\..\..\library\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<library name="wsf_html" location="..\..\..\library\server\wsf_html\wsf_html.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\library\network\protocol\http\http.ecf" readonly="false"/>
|
||||
<library name="openid" location="..\..\..\library\security\openid\consumer\openid.ecf" />
|
||||
<library name="process" location="$ISE_LIBRARY\library\process\process.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid.ecf"/>
|
||||
<library name="uri_template" location="..\..\..\library\text\parser\uri_template\uri_template.ecf"/>
|
||||
<library name="wsf" location="..\..\..\library\server\wsf\wsf.ecf" readonly="false"/>
|
||||
<library name="wsf_session" location="..\..\..\library\server\wsf\wsf_session.ecf" readonly="false"/>
|
||||
<library name="notification_email" location="..\..\..\library\runtime\process\notification_email\notification_email.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true">
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
135
draft/application/cms/example/src/web_cms.e
Normal file
135
draft/application/cms/example/src/web_cms.e
Normal file
@@ -0,0 +1,135 @@
|
||||
note
|
||||
description: "[
|
||||
This class implements the Demo of WEB CMS service
|
||||
|
||||
]"
|
||||
|
||||
class
|
||||
WEB_CMS
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
local
|
||||
args: ARGUMENTS_32
|
||||
cfg: detachable READABLE_STRING_32
|
||||
i,n: INTEGER
|
||||
do
|
||||
--| Arguments
|
||||
create args
|
||||
from
|
||||
i := 1
|
||||
n := args.argument_count
|
||||
until
|
||||
i > n or cfg /= Void
|
||||
loop
|
||||
if attached args.argument (i) as s then
|
||||
if s.same_string_general ("--config") or s.same_string_general ("-c") then
|
||||
if i < n then
|
||||
cfg := args.argument (i + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
if cfg = Void then
|
||||
if file_exists ("cms.ini") then
|
||||
cfg := {STRING_32} "cms.ini"
|
||||
end
|
||||
end
|
||||
|
||||
--| EWF settings
|
||||
service_options := create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("ewf.ini")
|
||||
Precursor
|
||||
|
||||
--| CMS initialization
|
||||
launch_cms (cms_setup (cfg))
|
||||
end
|
||||
|
||||
cms_setup (a_cfg_fn: detachable READABLE_STRING_GENERAL): CMS_CUSTOM_SETUP
|
||||
do
|
||||
if a_cfg_fn /= Void then
|
||||
create Result.make_from_file (a_cfg_fn)
|
||||
else
|
||||
create Result -- Default
|
||||
end
|
||||
setup_modules (Result)
|
||||
setup_storage (Result)
|
||||
end
|
||||
|
||||
launch_cms (a_setup: CMS_SETUP)
|
||||
local
|
||||
cms: CMS_SERVICE
|
||||
do
|
||||
create cms.make (a_setup)
|
||||
on_launched (cms)
|
||||
cms_service := cms
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
cms_service: CMS_SERVICE
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
cms_service.execute (req, res)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
setup_modules (a_setup: CMS_SETUP)
|
||||
local
|
||||
m: CMS_MODULE
|
||||
do
|
||||
create {DEMO_MODULE} m.make
|
||||
m.enable
|
||||
a_setup.add_module (m)
|
||||
|
||||
create {SHUTDOWN_MODULE} m.make
|
||||
m.enable
|
||||
a_setup.add_module (m)
|
||||
|
||||
create {DEBUG_MODULE} m.make
|
||||
m.enable
|
||||
a_setup.add_module (m)
|
||||
|
||||
create {OPENID_MODULE} m.make
|
||||
m.enable
|
||||
a_setup.add_module (m)
|
||||
end
|
||||
|
||||
setup_storage (a_setup: CMS_SETUP)
|
||||
do
|
||||
|
||||
end
|
||||
|
||||
feature -- Event
|
||||
|
||||
on_launched (cms: CMS_SERVICE)
|
||||
local
|
||||
e: CMS_EMAIL
|
||||
do
|
||||
create e.make (cms.site_email, cms.site_email, "[" + cms.site_name + "] launched...", "The site [" + cms.site_name + "] was launched at " + (create {DATE_TIME}.make_now_utc).out + " UTC.")
|
||||
cms.mailer.safe_process_email (e)
|
||||
end
|
||||
|
||||
feature -- Helper
|
||||
|
||||
file_exists (fn: READABLE_STRING_GENERAL): BOOLEAN
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make_with_name (fn)
|
||||
Result := f.exists and then f.is_readable
|
||||
end
|
||||
|
||||
end
|
||||
311
draft/application/cms/src/cms_configuration.e
Normal file
311
draft/application/cms/src/cms_configuration.e
Normal file
@@ -0,0 +1,311 @@
|
||||
note
|
||||
description: "Summary description for {CMS_CONFIGURATION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_CONFIGURATION
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make,
|
||||
make_from_file
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
create options.make_equal (10)
|
||||
analyze
|
||||
end
|
||||
|
||||
make_from_file (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
local
|
||||
p: PATH
|
||||
do
|
||||
make
|
||||
create p.make_from_string (a_filename)
|
||||
configuration_location := p
|
||||
import_from_path (p)
|
||||
analyze
|
||||
end
|
||||
|
||||
analyze
|
||||
do
|
||||
get_root_location
|
||||
get_var_location
|
||||
get_themes_location
|
||||
get_files_location
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
configuration_location: detachable PATH
|
||||
|
||||
option (a_name: READABLE_STRING_GENERAL): detachable ANY
|
||||
do
|
||||
Result := options.item (a_name)
|
||||
end
|
||||
|
||||
options: STRING_TABLE [STRING_32]
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
append_to_string (s: STRING)
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
s.append ("Options:%N")
|
||||
across
|
||||
options as c
|
||||
loop
|
||||
s.append (c.key.to_string_8)
|
||||
s.append_character ('=')
|
||||
utf.string_32_into_utf_8_string_8 (c.item, s)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
|
||||
s.append ("Specific:%N")
|
||||
s.append ("root_location=" + root_location.utf_8_name + "%N")
|
||||
s.append ("var_location=" + var_location.utf_8_name + "%N")
|
||||
s.append ("files_location=" + files_location.utf_8_name + "%N")
|
||||
s.append ("themes_location=" + themes_location.utf_8_name + "%N")
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_option (a_name: READABLE_STRING_GENERAL; a_value: STRING_32)
|
||||
do
|
||||
options.force (a_value, a_name.as_string_8)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
var_location: PATH
|
||||
|
||||
root_location: PATH
|
||||
|
||||
files_location: PATH
|
||||
|
||||
themes_location: PATH
|
||||
|
||||
theme_name (dft: detachable like theme_name): READABLE_STRING_8
|
||||
do
|
||||
if attached options.item ("theme") as s then
|
||||
Result := s
|
||||
elseif dft /= Void then
|
||||
Result := dft
|
||||
else
|
||||
Result := "default"
|
||||
end
|
||||
end
|
||||
|
||||
site_id: READABLE_STRING_8
|
||||
do
|
||||
if attached options.item ("site.id") as s then
|
||||
Result := s
|
||||
else
|
||||
Result := "_EWF_CMS_NO_ID_"
|
||||
end
|
||||
end
|
||||
|
||||
site_name (dft: like site_name): READABLE_STRING_8
|
||||
do
|
||||
if attached options.item ("site.name") as s then
|
||||
Result := s
|
||||
else
|
||||
Result := dft
|
||||
end
|
||||
end
|
||||
|
||||
site_url (dft: like site_url): READABLE_STRING_8
|
||||
do
|
||||
if attached options.item ("site.url") as s then
|
||||
Result := s
|
||||
else
|
||||
Result := dft
|
||||
end
|
||||
if Result /= Void then
|
||||
if Result.is_empty then
|
||||
-- ok
|
||||
elseif not Result.ends_with ("/") then
|
||||
Result := Result + "/"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
site_script_url (dft: like site_script_url): detachable READABLE_STRING_8
|
||||
do
|
||||
if attached options.item ("site.script_url") as s then
|
||||
Result := s
|
||||
else
|
||||
Result := dft
|
||||
end
|
||||
if Result /= Void then
|
||||
if Result.is_empty then
|
||||
elseif not Result.ends_with ("/") then
|
||||
Result := Result + "/"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
site_email (dft: like site_email): READABLE_STRING_8
|
||||
do
|
||||
if attached options.item ("site.email") as s then
|
||||
Result := s
|
||||
else
|
||||
Result := dft
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
get_var_location
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
if attached options.item ("var-dir") as s then
|
||||
create var_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
|
||||
else
|
||||
var_location := execution_environment.current_working_path
|
||||
end
|
||||
end
|
||||
|
||||
get_root_location
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
if attached options.item ("root-dir") as s then
|
||||
create root_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
|
||||
else
|
||||
root_location := execution_environment.current_working_path
|
||||
end
|
||||
end
|
||||
|
||||
get_files_location
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
if attached options.item ("files-dir") as s then
|
||||
create files_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
|
||||
else
|
||||
create files_location.make_from_string ("files")
|
||||
end
|
||||
end
|
||||
|
||||
get_themes_location
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
if attached options.item ("themes-dir") as s then
|
||||
create themes_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
|
||||
else
|
||||
themes_location := root_location.extended ("themes")
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
import_from_file (fn: READABLE_STRING_GENERAL)
|
||||
do
|
||||
import_from_path (create {PATH}.make_from_string (fn))
|
||||
end
|
||||
|
||||
import_from_path (a_filename: PATH)
|
||||
-- Import ini file content
|
||||
local
|
||||
f: PLAIN_TEXT_FILE
|
||||
l,v: STRING_8
|
||||
p: INTEGER
|
||||
do
|
||||
create f.make_with_path (a_filename)
|
||||
if f.exists and f.is_readable then
|
||||
f.open_read
|
||||
from
|
||||
f.read_line
|
||||
until
|
||||
f.exhausted
|
||||
loop
|
||||
l := f.last_string
|
||||
l.left_adjust
|
||||
if not l.is_empty then
|
||||
if l[1] = '#' then
|
||||
-- commented line
|
||||
else
|
||||
p := l.index_of ('=', 1)
|
||||
if p > 1 then
|
||||
v := l.substring (p + 1, l.count)
|
||||
l.keep_head (p - 1)
|
||||
v.left_adjust
|
||||
v.right_adjust
|
||||
l.right_adjust
|
||||
|
||||
if l.is_case_insensitive_equal ("@include") then
|
||||
import_from_file (resolved_string (v))
|
||||
else
|
||||
set_option (l.as_lower, resolved_string (v))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
f.read_line
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Environment
|
||||
|
||||
resolved_string (s: READABLE_STRING_8): STRING_32
|
||||
-- Resolved `s' using `options' or else environment variables.
|
||||
local
|
||||
i,n,b,e: INTEGER
|
||||
k: detachable READABLE_STRING_8
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
create Result.make (s.count)
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
if i + 1 < n and then s[i] = '$' and then s[i+1] = '{' then
|
||||
b := i + 2
|
||||
e := s.index_of ('}', b) - 1
|
||||
if e > 0 then
|
||||
k := s.substring (b, e)
|
||||
if attached option (k) as v then
|
||||
if attached {READABLE_STRING_32} v as s32 then
|
||||
Result.append (s32)
|
||||
else
|
||||
Result.append (v.out)
|
||||
end
|
||||
i := e + 1
|
||||
elseif attached execution_environment.item (k) as v then
|
||||
Result.append (v)
|
||||
i := e + 1
|
||||
else
|
||||
Result.extend (s[i])
|
||||
end
|
||||
else
|
||||
Result.extend (s[i])
|
||||
end
|
||||
else
|
||||
Result.extend (s[i])
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
132
draft/application/cms/src/cms_default_setup.e
Normal file
132
draft/application/cms/src/cms_default_setup.e
Normal file
@@ -0,0 +1,132 @@
|
||||
note
|
||||
description: "Summary description for {CMS_DEFAULT_SETUP}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_DEFAULT_SETUP
|
||||
|
||||
inherit
|
||||
CMS_SETUP
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
|
||||
create
|
||||
default_create,
|
||||
make,
|
||||
make_from_file
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_cfg: CMS_CONFIGURATION)
|
||||
do
|
||||
configuration := a_cfg
|
||||
default_create
|
||||
end
|
||||
|
||||
make_from_file (fn: READABLE_STRING_GENERAL)
|
||||
local
|
||||
cfg: CMS_CONFIGURATION
|
||||
do
|
||||
create cfg.make_from_file (fn)
|
||||
make (cfg)
|
||||
end
|
||||
|
||||
default_create
|
||||
do
|
||||
Precursor
|
||||
build_modules
|
||||
build_storage
|
||||
build_session_manager
|
||||
build_auth_engine
|
||||
build_mailer
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
modules: ARRAYED_LIST [CMS_MODULE]
|
||||
|
||||
storage: CMS_STORAGE
|
||||
-- CMS persistent layer
|
||||
|
||||
session_manager: WSF_SESSION_MANAGER
|
||||
-- CMS Session manager
|
||||
|
||||
auth_engine: CMS_AUTH_ENGINE
|
||||
-- CMS Authentication engine
|
||||
|
||||
mailer: NOTIFICATION_MAILER
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
build_modules
|
||||
local
|
||||
m: CMS_MODULE
|
||||
do
|
||||
create modules.make (3)
|
||||
|
||||
-- Core
|
||||
create {USER_MODULE} m.make
|
||||
m.enable
|
||||
modules.extend (m)
|
||||
|
||||
create {ADMIN_MODULE} m.make
|
||||
m.enable
|
||||
modules.extend (m)
|
||||
|
||||
create {NODE_MODULE} m.make
|
||||
m.enable
|
||||
modules.extend (m)
|
||||
end
|
||||
|
||||
build_storage
|
||||
local
|
||||
dn: PATH
|
||||
do
|
||||
if attached configuration as cfg and then attached cfg.var_location as l_site_var_dir then
|
||||
dn := l_site_var_dir
|
||||
else
|
||||
create dn.make_current
|
||||
end
|
||||
create {CMS_SED_STORAGE} storage.make (dn.extended ("_storage_").name)
|
||||
end
|
||||
|
||||
build_session_manager
|
||||
local
|
||||
dn: PATH
|
||||
do
|
||||
if attached configuration as cfg and then attached cfg.var_location as l_site_var_dir then
|
||||
dn := l_site_var_dir
|
||||
else
|
||||
create dn.make_empty
|
||||
end
|
||||
dn := dn.extended ("_storage_").extended ("_sessions_")
|
||||
create {WSF_FS_SESSION_MANAGER} session_manager.make_with_folder (dn.name)
|
||||
end
|
||||
|
||||
build_auth_engine
|
||||
do
|
||||
create {CMS_STORAGE_AUTH_ENGINE} auth_engine.make (storage)
|
||||
end
|
||||
|
||||
build_mailer
|
||||
local
|
||||
ch_mailer: NOTIFICATION_CHAIN_MAILER
|
||||
st_mailer: CMS_STORAGE_MAILER
|
||||
do
|
||||
create st_mailer.make (storage)
|
||||
create ch_mailer.make (st_mailer)
|
||||
ch_mailer.set_next (create {NOTIFICATION_SENDMAIL_MAILER})
|
||||
mailer := ch_mailer
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
add_module (m: CMS_MODULE)
|
||||
do
|
||||
modules.force (m)
|
||||
end
|
||||
|
||||
end
|
||||
442
draft/application/cms/src/cms_service.e
Normal file
442
draft/application/cms/src/cms_service.e
Normal file
@@ -0,0 +1,442 @@
|
||||
note
|
||||
description: "[
|
||||
This class implements the CMS service
|
||||
|
||||
It could be used to implement the main EWF service, or
|
||||
even for a specific handler.
|
||||
]"
|
||||
|
||||
class
|
||||
CMS_SERVICE
|
||||
|
||||
inherit
|
||||
WSF_SERVICE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_setup: CMS_SETUP)
|
||||
local
|
||||
cfg: detachable CMS_CONFIGURATION
|
||||
do
|
||||
cfg := a_setup.configuration
|
||||
if cfg = Void then
|
||||
create cfg.make
|
||||
end
|
||||
|
||||
configuration := cfg
|
||||
base_url := a_setup.base_url
|
||||
|
||||
site_id := cfg.site_id
|
||||
site_url := cfg.site_url ("")
|
||||
site_name := cfg.site_name ("EWF::CMS")
|
||||
site_email := cfg.site_email ("webmaster")
|
||||
site_dir := cfg.root_location
|
||||
site_var_dir := cfg.var_location
|
||||
files_location := cfg.files_location
|
||||
themes_location := cfg.themes_location
|
||||
theme_name := cfg.theme_name ("default")
|
||||
|
||||
set_script_url (cfg.site_script_url (Void)) -- Temporary value
|
||||
|
||||
compute_theme_resource_location
|
||||
|
||||
create content_types.make (3)
|
||||
|
||||
modules := a_setup.modules
|
||||
storage := a_setup.storage
|
||||
session_manager := a_setup.session_manager
|
||||
auth_engine := a_setup.auth_engine
|
||||
mailer := a_setup.mailer
|
||||
|
||||
initialize_storage
|
||||
initialize_auth_engine
|
||||
initialize_session_manager
|
||||
initialize_mailer
|
||||
initialize_router
|
||||
initialize_modules
|
||||
end
|
||||
|
||||
initialize_session_manager
|
||||
-- local
|
||||
-- dn: DIRECTORY_NAME
|
||||
do
|
||||
-- create dn.make_from_string (site_var_dir)
|
||||
-- dn.extend ("_storage_")
|
||||
-- dn.extend ("_sessions_")
|
||||
-- create {WSF_FS_SESSION_MANAGER} session_manager.make_with_folder (dn.string)
|
||||
end
|
||||
|
||||
initialize_storage
|
||||
do
|
||||
if not storage.has_user then
|
||||
initialize_users
|
||||
end
|
||||
end
|
||||
|
||||
initialize_users
|
||||
require
|
||||
has_no_user: not storage.has_user
|
||||
local
|
||||
u: CMS_USER
|
||||
ur: CMS_USER_ROLE
|
||||
do
|
||||
create u.make_new ("admin")
|
||||
u.set_password ("istrator")
|
||||
storage.save_user (u)
|
||||
|
||||
create ur.make_with_id (1, "anonymous")
|
||||
storage.save_user_role (ur)
|
||||
create ur.make_with_id (2, "authenticated")
|
||||
ur.add_permission ("create page")
|
||||
ur.add_permission ("edit page")
|
||||
storage.save_user_role (ur)
|
||||
end
|
||||
|
||||
initialize_mailer
|
||||
local
|
||||
-- ch_mailer: CMS_CHAIN_MAILER
|
||||
-- st_mailer: CMS_STORAGE_MAILER
|
||||
do
|
||||
-- create st_mailer.make (storage)
|
||||
-- create ch_mailer.make (st_mailer)
|
||||
-- ch_mailer.set_next (create {CMS_SENDMAIL_MAILER})
|
||||
-- mailer := ch_mailer
|
||||
end
|
||||
|
||||
initialize_router
|
||||
local
|
||||
-- h: CMS_HANDLER
|
||||
file_hdl: CMS_FILE_SYSTEM_HANDLER
|
||||
do
|
||||
create router.make (10)
|
||||
router.set_base_url (base_url)
|
||||
|
||||
router.map (create {WSF_URI_MAPPING}.make ("/", create {CMS_HANDLER}.make (agent handle_home)))
|
||||
router.map (create {WSF_URI_MAPPING}.make ("/favicon.ico", create {CMS_HANDLER}.make (agent handle_favicon)))
|
||||
|
||||
create file_hdl.make_with_path (files_location)
|
||||
file_hdl.disable_index
|
||||
file_hdl.set_max_age (8*60*60)
|
||||
router.map (create {WSF_STARTS_WITH_MAPPING}.make ("/files/", file_hdl))
|
||||
|
||||
create file_hdl.make_with_path (theme_resource_location)
|
||||
file_hdl.set_max_age (8*60*60)
|
||||
router.map (create {WSF_STARTS_WITH_MAPPING}.make ("/theme/", file_hdl))
|
||||
end
|
||||
|
||||
initialize_modules
|
||||
do
|
||||
across
|
||||
modules as m
|
||||
loop
|
||||
if m.item.is_enabled then
|
||||
m.item.register (Current)
|
||||
if attached {CMS_HOOK_AUTO_REGISTER} m.item as h_auto then
|
||||
h_auto.hook_auto_register (Current)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
initialize_auth_engine
|
||||
do
|
||||
-- create {CMS_STORAGE_AUTH_ENGINE} auth_engine.make (storage)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
configuration: CMS_CONFIGURATION
|
||||
|
||||
auth_engine: CMS_AUTH_ENGINE
|
||||
|
||||
modules: LIST [CMS_MODULE]
|
||||
|
||||
feature -- Hook: menu_alter
|
||||
|
||||
add_menu_alter_hook (h: like menu_alter_hooks.item)
|
||||
local
|
||||
lst: like menu_alter_hooks
|
||||
do
|
||||
lst := menu_alter_hooks
|
||||
if lst = Void then
|
||||
create lst.make (1)
|
||||
menu_alter_hooks := lst
|
||||
end
|
||||
if not lst.has (h) then
|
||||
lst.force (h)
|
||||
end
|
||||
end
|
||||
|
||||
menu_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_MENU_ALTER]
|
||||
|
||||
call_menu_alter_hooks (m: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION)
|
||||
do
|
||||
if attached menu_alter_hooks as lst then
|
||||
across
|
||||
lst as c
|
||||
loop
|
||||
c.item.menu_alter (m, a_execution)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Hook: form_alter
|
||||
|
||||
add_form_alter_hook (h: like form_alter_hooks.item)
|
||||
local
|
||||
lst: like form_alter_hooks
|
||||
do
|
||||
lst := form_alter_hooks
|
||||
if lst = Void then
|
||||
create lst.make (1)
|
||||
form_alter_hooks := lst
|
||||
end
|
||||
if not lst.has (h) then
|
||||
lst.force (h)
|
||||
end
|
||||
end
|
||||
|
||||
form_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_FORM_ALTER]
|
||||
|
||||
call_form_alter_hooks (f: CMS_FORM; a_form_data: detachable WSF_FORM_DATA; a_execution: CMS_EXECUTION)
|
||||
do
|
||||
if attached form_alter_hooks as lst then
|
||||
across
|
||||
lst as c
|
||||
loop
|
||||
c.item.form_alter (f, a_form_data, a_execution)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Hook: block
|
||||
|
||||
add_block_hook (h: like block_hooks.item)
|
||||
local
|
||||
lst: like block_hooks
|
||||
do
|
||||
lst := block_hooks
|
||||
if lst = Void then
|
||||
create lst.make (1)
|
||||
block_hooks := lst
|
||||
end
|
||||
if not lst.has (h) then
|
||||
lst.force (h)
|
||||
end
|
||||
end
|
||||
|
||||
block_hooks: detachable ARRAYED_LIST [CMS_HOOK_BLOCK]
|
||||
|
||||
hook_block_view (a_execution: CMS_EXECUTION)
|
||||
do
|
||||
if attached block_hooks as lst then
|
||||
across
|
||||
lst as c
|
||||
loop
|
||||
across
|
||||
c.item.block_list as blst
|
||||
loop
|
||||
c.item.get_block_view (blst.item, a_execution)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Router
|
||||
|
||||
site_id: READABLE_STRING_8
|
||||
|
||||
site_name: READABLE_STRING_32
|
||||
|
||||
site_email: READABLE_STRING_8
|
||||
|
||||
site_url: READABLE_STRING_8
|
||||
|
||||
site_dir: PATH
|
||||
|
||||
site_var_dir: PATH
|
||||
|
||||
files_location: PATH
|
||||
|
||||
themes_location: PATH
|
||||
|
||||
compute_theme_resource_location
|
||||
do
|
||||
theme_resource_location := themes_location.extended (theme_name).extended ("res")
|
||||
end
|
||||
|
||||
theme_resource_location: PATH
|
||||
|
||||
theme_name: READABLE_STRING_32
|
||||
|
||||
router: WSF_ROUTER
|
||||
|
||||
map_uri_template (tpl: STRING; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]])
|
||||
do
|
||||
router.map (create {WSF_URI_TEMPLATE_MAPPING}.make_from_template (tpl, create {CMS_HANDLER}.make (proc)))
|
||||
end
|
||||
|
||||
map_uri (a_uri: STRING; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]])
|
||||
do
|
||||
router.map (create {WSF_URI_MAPPING}.make (a_uri, create {CMS_HANDLER}.make (proc)))
|
||||
end
|
||||
|
||||
feature -- URL related
|
||||
|
||||
front_path: STRING
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
Result := l_base_url + "/"
|
||||
else
|
||||
Result := "/"
|
||||
end
|
||||
end
|
||||
|
||||
urls_set: BOOLEAN
|
||||
|
||||
initialize_urls (req: WSF_REQUEST)
|
||||
local
|
||||
u: like base_url
|
||||
do
|
||||
if not urls_set then
|
||||
u := base_url
|
||||
if u = Void then
|
||||
u := ""
|
||||
end
|
||||
urls_set := True
|
||||
if site_url.is_empty then
|
||||
site_url := req.absolute_script_url (u)
|
||||
end
|
||||
set_script_url (req.script_url (u))
|
||||
end
|
||||
end
|
||||
|
||||
base_url: detachable READABLE_STRING_8
|
||||
-- Base url (related to the script path).
|
||||
|
||||
script_url: detachable READABLE_STRING_8
|
||||
|
||||
set_script_url (a_url: like script_url)
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if a_url = Void then
|
||||
script_url := Void
|
||||
elseif not a_url.is_empty then
|
||||
if a_url.ends_with ("/") then
|
||||
create s.make_from_string (a_url)
|
||||
else
|
||||
create s.make (a_url.count + 1)
|
||||
s.append (a_url)
|
||||
s.append_character ('/')
|
||||
end
|
||||
script_url := s
|
||||
end
|
||||
ensure
|
||||
attached script_url as l_url implies l_url.ends_with ("/")
|
||||
end
|
||||
|
||||
feature -- Report
|
||||
|
||||
is_front_page (req: WSF_REQUEST): BOOLEAN
|
||||
do
|
||||
Result := req.path_info.same_string (front_path)
|
||||
end
|
||||
|
||||
feature {CMS_EXECUTION, CMS_MODULE} -- Security report
|
||||
|
||||
user_has_permission (u: detachable CMS_USER; s: detachable READABLE_STRING_8): BOOLEAN
|
||||
-- Anonymous or user `u' has permission for `s' ?
|
||||
--| `s' could be "create page",
|
||||
do
|
||||
Result := storage.user_has_permission (u, s)
|
||||
end
|
||||
|
||||
feature -- Storage
|
||||
|
||||
session_controller (req: WSF_REQUEST): CMS_SESSION_CONTROLER
|
||||
-- New session controller for request `req'
|
||||
do
|
||||
create Result.make (req, session_manager, site_id)
|
||||
end
|
||||
|
||||
session_manager: WSF_SESSION_MANAGER
|
||||
-- CMS Session manager
|
||||
|
||||
storage: CMS_STORAGE
|
||||
|
||||
feature -- Logging
|
||||
|
||||
log (a_category: READABLE_STRING_8; a_message: READABLE_STRING_8; a_level: INTEGER; a_link: detachable CMS_LINK)
|
||||
local
|
||||
l_log: CMS_LOG
|
||||
do
|
||||
create l_log.make (a_category, a_message, a_level, Void)
|
||||
if a_link /= Void then
|
||||
l_log.set_link (a_link)
|
||||
end
|
||||
storage.save_log (l_log)
|
||||
end
|
||||
|
||||
feature -- Content type
|
||||
|
||||
content_types: ARRAYED_LIST [CMS_CONTENT_TYPE]
|
||||
-- Available content types
|
||||
|
||||
add_content_type (a_type: CMS_CONTENT_TYPE)
|
||||
do
|
||||
content_types.force (a_type)
|
||||
end
|
||||
|
||||
content_type (a_name: READABLE_STRING_8): detachable CMS_CONTENT_TYPE
|
||||
do
|
||||
across
|
||||
content_types as t
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
if t.item.name.same_string (a_name) then
|
||||
Result := t.item
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Notification
|
||||
|
||||
mailer: NOTIFICATION_MAILER
|
||||
|
||||
feature -- Core Execution
|
||||
|
||||
handle_favicon (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
fres: WSF_FILE_RESPONSE
|
||||
do
|
||||
create fres.make_with_path (theme_resource_location.extended ("favicon.ico"))
|
||||
fres.set_expires_in_seconds (7 * 24 * 60 * 60) -- 7 jours
|
||||
res.send (fres)
|
||||
end
|
||||
|
||||
handle_home (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
(create {HOME_CMS_EXECUTION}.make (req, res, Current)).execute
|
||||
end
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Default request handler if no other are relevant
|
||||
local
|
||||
e: CMS_EXECUTION
|
||||
sess: WSF_ROUTER_SESSION
|
||||
do
|
||||
initialize_urls (req)
|
||||
create sess
|
||||
router.dispatch (req, res, sess)
|
||||
if not sess.dispatched then
|
||||
create {NOT_FOUND_CMS_EXECUTION} e.make (req, res, Current)
|
||||
e.execute
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
55
draft/application/cms/src/cms_setup.e
Normal file
55
draft/application/cms/src/cms_setup.e
Normal file
@@ -0,0 +1,55 @@
|
||||
note
|
||||
description: "Summary description for {CMS_SETUP}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_SETUP
|
||||
|
||||
feature -- Access
|
||||
|
||||
configuration: detachable CMS_CONFIGURATION
|
||||
|
||||
base_url: detachable READABLE_STRING_8
|
||||
|
||||
modules: LIST [CMS_MODULE]
|
||||
deferred
|
||||
end
|
||||
|
||||
storage: CMS_STORAGE
|
||||
-- CMS persistent layer
|
||||
deferred
|
||||
end
|
||||
|
||||
session_manager: WSF_SESSION_MANAGER
|
||||
-- CMS Session manager
|
||||
deferred
|
||||
end
|
||||
|
||||
auth_engine: CMS_AUTH_ENGINE
|
||||
-- CMS Authentication engine
|
||||
deferred
|
||||
end
|
||||
|
||||
mailer: NOTIFICATION_MAILER
|
||||
-- CMS email engine
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_base_url (a_base_url: like base_url)
|
||||
do
|
||||
if a_base_url /= Void and then not a_base_url.is_empty then
|
||||
base_url := a_base_url
|
||||
else
|
||||
base_url := Void
|
||||
end
|
||||
end
|
||||
|
||||
add_module (m: CMS_MODULE)
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
17
draft/application/cms/src/handler/cms_file_system_handler.e
Normal file
17
draft/application/cms/src/handler/cms_file_system_handler.e
Normal file
@@ -0,0 +1,17 @@
|
||||
note
|
||||
description: "Summary description for {CMS_FILE_SYSTEM_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_FILE_SYSTEM_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_FILE_SYSTEM_HANDLER
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_path
|
||||
|
||||
end
|
||||
@@ -0,0 +1,128 @@
|
||||
note
|
||||
description: "Summary description for {CMS_HTML_FILTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_HTML_FILTER
|
||||
|
||||
inherit
|
||||
CMS_FILTER
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
default_create
|
||||
do
|
||||
Precursor
|
||||
allowed_html_tags := <<"a", "em", "strong", "cite", "blockquote", "code", "ul", "ol", "li", "dl">>
|
||||
description := "Allowed HTML tags: "
|
||||
across
|
||||
allowed_html_tags as c
|
||||
loop
|
||||
description.append ("<" + c.item + "> ")
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING_8 = "html_filter"
|
||||
|
||||
title: STRING_8 = "HTML filter"
|
||||
|
||||
description: STRING_8
|
||||
|
||||
allowed_html_tags: ITERABLE [READABLE_STRING_8]
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
filter (a_text: STRING_8)
|
||||
local
|
||||
l_new: STRING_8
|
||||
i: INTEGER
|
||||
n: INTEGER
|
||||
in_tag: BOOLEAN
|
||||
p1, p2: INTEGER
|
||||
do
|
||||
create l_new.make (a_text.count)
|
||||
from
|
||||
p1 := 1
|
||||
i := a_text.index_of ('<', 1)
|
||||
if i > 0 then
|
||||
l_new.append (a_text.substring (1, i - 1))
|
||||
end
|
||||
n := a_text.count
|
||||
until
|
||||
i = 0 or i > n
|
||||
loop
|
||||
if a_text[i] = '<' then
|
||||
in_tag := True
|
||||
p1 := i
|
||||
p2 := a_text.index_of ('>', i + 1)
|
||||
if p2 = 0 then
|
||||
-- next '<'
|
||||
i := a_text.index_of ('<', i + 1)
|
||||
if i > 0 then
|
||||
l_new.append (a_text.substring (p1, i - 1))
|
||||
end
|
||||
else
|
||||
if is_authorized (a_text.substring (p1, p2)) then
|
||||
l_new.append (a_text.substring (p1, p2))
|
||||
i := a_text.index_of ('<', p2 + 1)
|
||||
else
|
||||
i := a_text.index_of ('<', p2 + 1)
|
||||
end
|
||||
if i = 0 then
|
||||
p1 := p2 + 1
|
||||
else
|
||||
l_new.append (a_text.substring (p2 + 1, i - 1))
|
||||
end
|
||||
end
|
||||
else
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
l_new.append (a_text.substring (p1, n))
|
||||
a_text.wipe_out
|
||||
a_text.append (l_new)
|
||||
end
|
||||
|
||||
is_authorized (s: READABLE_STRING_8): BOOLEAN
|
||||
-- Is `s' authorized?
|
||||
--| `s' has either "<....>" or "<..../>" or "</.....>"
|
||||
local
|
||||
l_tagname: detachable STRING
|
||||
i,n,p1: INTEGER
|
||||
do
|
||||
-- create l_tagname.make_empty
|
||||
from
|
||||
i := 2 -- skip first '<'
|
||||
n := s.count
|
||||
until
|
||||
i > n or l_tagname /= Void
|
||||
loop
|
||||
if p1 > 0 then
|
||||
if s[i].is_space or s[i] = '/' or s[i] = '>' then
|
||||
l_tagname := s.substring (p1, i - 1)
|
||||
end
|
||||
else
|
||||
if s[i].is_space or s[i] = '/' then
|
||||
else
|
||||
p1 := i
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
if l_tagname /= Void then
|
||||
l_tagname.to_lower
|
||||
Result := across allowed_html_tags as c some c.item.same_string (l_tagname) end
|
||||
else
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
128
draft/application/cms/src/modules/debug/debug_module.e
Normal file
128
draft/application/cms/src/modules/debug/debug_module.e
Normal file
@@ -0,0 +1,128 @@
|
||||
note
|
||||
description: "Summary description for {DEBUG_MODULE}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DEBUG_MODULE
|
||||
|
||||
inherit
|
||||
CMS_MODULE
|
||||
|
||||
-- CMS_HOOK_BLOCK
|
||||
|
||||
CMS_HOOK_AUTO_REGISTER
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
name := "debug"
|
||||
version := "1.0"
|
||||
description := "Debug"
|
||||
package := "cms"
|
||||
end
|
||||
|
||||
feature {CMS_SERVICE} -- Registration
|
||||
|
||||
service: detachable CMS_SERVICE
|
||||
|
||||
register (a_service: CMS_SERVICE)
|
||||
do
|
||||
service := a_service
|
||||
a_service.map_uri_template ("/debug/", agent handle_debug (a_service, ?, ?))
|
||||
end
|
||||
|
||||
feature -- Hooks
|
||||
|
||||
-- block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
-- do
|
||||
-- Result := <<"debug-info">>
|
||||
-- end
|
||||
|
||||
-- get_block_view (a_block_id: detachable READABLE_STRING_8; a_execution: CMS_EXECUTION)
|
||||
-- local
|
||||
-- b: CMS_CONTENT_BLOCK
|
||||
-- do
|
||||
-- create b.make ("debug-info", "Debug", "... ", a_execution.formats.plain_text)
|
||||
-- a_execution.add_block (b, Void)
|
||||
-- end
|
||||
|
||||
feature -- Handler
|
||||
|
||||
handle_debug (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
e: CMS_EXECUTION
|
||||
s: STRING
|
||||
do
|
||||
if req.is_get_request_method then
|
||||
create {ANY_CMS_EXECUTION} e.make (req, res, cms)
|
||||
e.set_title ("DEBUG")
|
||||
|
||||
create s.make_empty
|
||||
append_info_to ("Name", cms.site_name, e, s)
|
||||
append_info_to ("Url", cms.site_url, e, s)
|
||||
|
||||
if attached cms.configuration as cfg and then attached cfg.configuration_location as l_loc then
|
||||
s.append ("<hr/>")
|
||||
append_info_to ("Configuration file", l_loc.name, e, s)
|
||||
end
|
||||
|
||||
s.append ("<hr/>")
|
||||
|
||||
append_info_to ("Current dir", execution_environment.current_working_path.utf_8_name, e, s)
|
||||
append_info_to ("Base url", cms.base_url, e, s)
|
||||
append_info_to ("Script url", cms.script_url, e, s)
|
||||
s.append ("<hr/>")
|
||||
append_info_to ("Dir", cms.site_dir.utf_8_name, e, s)
|
||||
append_info_to ("Var dir", cms.site_var_dir.utf_8_name, e, s)
|
||||
s.append ("<hr/>")
|
||||
append_info_to ("Theme", cms.theme_name, e, s)
|
||||
append_info_to ("Theme location", cms.theme_resource_location.utf_8_name, e, s)
|
||||
s.append ("<hr/>")
|
||||
append_info_to ("Files location", cms.files_location.utf_8_name, e, s)
|
||||
s.append ("<hr/>")
|
||||
|
||||
append_info_to ("Url", e.url ("/", Void), e, s)
|
||||
if attached e.user as u then
|
||||
append_info_to ("User", u.name, e, s)
|
||||
append_info_to ("User url", e.user_url (u), e, s)
|
||||
|
||||
end
|
||||
|
||||
e.set_main_content (s)
|
||||
else
|
||||
create {NOT_FOUND_CMS_EXECUTION} e.make (req, res, cms)
|
||||
end
|
||||
e.execute
|
||||
end
|
||||
|
||||
append_info_to (n: READABLE_STRING_8; v: detachable READABLE_STRING_GENERAL; e: CMS_EXECUTION; t: STRING)
|
||||
do
|
||||
t.append ("<li>")
|
||||
t.append ("<strong>" + n + "</strong>: ")
|
||||
if v /= Void then
|
||||
t.append (e.html_encoded (v))
|
||||
end
|
||||
t.append ("</li>")
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-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
|
||||
18
draft/application/cms/src/notification/cms_email.e
Normal file
18
draft/application/cms/src/notification/cms_email.e
Normal file
@@ -0,0 +1,18 @@
|
||||
note
|
||||
description : "[
|
||||
Component representing an email
|
||||
]"
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
CMS_EMAIL
|
||||
|
||||
inherit
|
||||
NOTIFICATION_EMAIL
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
end
|
||||
38
draft/application/cms/src/notification/cms_storage_mailer.e
Normal file
38
draft/application/cms/src/notification/cms_storage_mailer.e
Normal file
@@ -0,0 +1,38 @@
|
||||
note
|
||||
description: "Summary description for {CMS_CHAIN_MAILER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_STORAGE_MAILER
|
||||
|
||||
inherit
|
||||
NOTIFICATION_MAILER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_storage: like storage)
|
||||
do
|
||||
storage := a_storage
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
storage: CMS_STORAGE
|
||||
|
||||
feature -- Status
|
||||
|
||||
is_available: BOOLEAN = True
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
process_email (a_email: NOTIFICATION_EMAIL)
|
||||
do
|
||||
storage.save_email (a_email)
|
||||
end
|
||||
|
||||
end
|
||||
615
draft/application/cms/src/storage/cms_sed_storage.e
Normal file
615
draft/application/cms/src/storage/cms_sed_storage.e
Normal file
@@ -0,0 +1,615 @@
|
||||
note
|
||||
description : "[
|
||||
CMS Storage implemented using SED
|
||||
]"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
CMS_SED_STORAGE
|
||||
|
||||
inherit
|
||||
CMS_STORAGE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (dn: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
create directory_name.make_from_string (dn)
|
||||
ensure_directory_exists (directory_name)
|
||||
create sed
|
||||
initialize
|
||||
end
|
||||
|
||||
directory_name: PATH
|
||||
|
||||
sed: SED_STORABLE_FACILITIES
|
||||
|
||||
sed_file_retrieved (f: FILE): detachable ANY
|
||||
local
|
||||
r: SED_MEDIUM_READER_WRITER
|
||||
do
|
||||
create r.make (f)
|
||||
r.set_for_reading
|
||||
Result := sed.retrieved (r, True)
|
||||
end
|
||||
|
||||
sed_file_store (obj: ANY; f: FILE)
|
||||
local
|
||||
w: SED_MEDIUM_READER_WRITER
|
||||
do
|
||||
create w.make (f)
|
||||
w.set_for_writing
|
||||
sed.store (obj, w)
|
||||
end
|
||||
|
||||
save_object_with_id (obj: ANY; a_id: INTEGER; a_type: STRING)
|
||||
local
|
||||
fn: PATH
|
||||
f: RAW_FILE
|
||||
do
|
||||
fn := directory_name.extended (a_type)
|
||||
ensure_directory_exists (fn)
|
||||
fn := fn.extended (a_id.out)
|
||||
-- .appended_with_extension ("txt")
|
||||
create f.make_with_path (fn)
|
||||
-- check not f.exists end
|
||||
f.create_read_write
|
||||
sed_file_store (obj, f)
|
||||
f.close
|
||||
end
|
||||
|
||||
object_with_id (a_id: INTEGER; a_type: STRING): detachable ANY
|
||||
local
|
||||
fn: PATH
|
||||
f: RAW_FILE
|
||||
do
|
||||
fn := directory_name.extended (a_type)
|
||||
ensure_directory_exists (fn)
|
||||
fn := fn.extended (a_id.out)
|
||||
-- .append_with_extension ("txt")
|
||||
create f.make_with_path (fn)
|
||||
if f.exists and f.is_readable then
|
||||
f.open_read
|
||||
Result := sed_file_retrieved (f)
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access: user
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
do
|
||||
Result := users_count > 0
|
||||
end
|
||||
|
||||
users_count: INTEGER
|
||||
do
|
||||
Result := last_sequence ("user")
|
||||
end
|
||||
|
||||
fill_user_profile (a_user: CMS_USER)
|
||||
do
|
||||
if a_user.profile = Void then
|
||||
if attached user_profile (a_user) as p then
|
||||
a_user.set_profile (p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
all_users: LIST [CMS_USER]
|
||||
local
|
||||
res: ARRAYED_LIST [like all_users.item]
|
||||
i, n: like last_sequence
|
||||
do
|
||||
n := last_sequence ("user")
|
||||
create res.make (n)
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
if attached user_by_id (i) as u then
|
||||
res.force (u)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
Result := res
|
||||
end
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
do
|
||||
if attached {like user_by_id} object_with_id (a_id, "user") as u then
|
||||
Result := u
|
||||
end
|
||||
end
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
local
|
||||
uid: INTEGER
|
||||
do
|
||||
if attached users_index as t then
|
||||
uid := t.by_name.item (a_name)
|
||||
if uid > 0 then
|
||||
Result := user_by_id (uid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
local
|
||||
uid: INTEGER
|
||||
do
|
||||
if attached users_index as t then
|
||||
uid := t.by_email.item (a_email)
|
||||
if uid > 0 then
|
||||
Result := user_by_id (uid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_valid_credential (u, p: READABLE_STRING_32): BOOLEAN
|
||||
do
|
||||
if attached user_by_name (u) as l_user then
|
||||
Result := attached l_user.encoded_password as l_pass and then l_pass.same_string (encoded_password (p))
|
||||
end
|
||||
end
|
||||
|
||||
encoded_password (a_raw_password: STRING_32): attached like {CMS_USER}.encoded_password
|
||||
do
|
||||
Result := a_raw_password.as_string_8 + "!123!"
|
||||
end
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
save_user (a_user: CMS_USER)
|
||||
local
|
||||
uid: INTEGER
|
||||
prof: like {CMS_USER}.profile
|
||||
l_has_new_name: BOOLEAN
|
||||
l_has_new_email: BOOLEAN
|
||||
l_stored_user: like user_by_id
|
||||
do
|
||||
if a_user.has_id then
|
||||
uid := a_user.id
|
||||
l_stored_user := user_by_id (uid)
|
||||
if l_stored_user /= Void then
|
||||
l_has_new_name := not l_stored_user.name.same_string (a_user.name)
|
||||
l_has_new_email := not (l_stored_user.email ~ a_user.email)
|
||||
end
|
||||
else
|
||||
l_has_new_name := True
|
||||
l_has_new_email := True
|
||||
uid := next_sequence ("user")
|
||||
a_user.set_id (uid)
|
||||
end
|
||||
if attached a_user.password as p then
|
||||
a_user.set_encoded_password (encoded_password (p))
|
||||
a_user.set_password (Void)
|
||||
end
|
||||
|
||||
prof := a_user.profile
|
||||
a_user.set_profile (Void)
|
||||
if prof /= Void then
|
||||
save_user_profile (a_user, prof)
|
||||
end
|
||||
save_object_with_id (a_user, uid, "user")
|
||||
if l_has_new_name or l_has_new_email then
|
||||
if attached users_index as l_index then
|
||||
l_index.by_name.force (uid, a_user.name)
|
||||
l_index.by_email.force (uid, a_user.email)
|
||||
store_users_index (l_index)
|
||||
end
|
||||
end
|
||||
a_user.set_profile (prof)
|
||||
end
|
||||
|
||||
feature -- Access: user_role
|
||||
|
||||
user_role_by_id (a_id: INTEGER): detachable CMS_USER_ROLE
|
||||
do
|
||||
if attached {like user_role_by_id} object_with_id (a_id, "user_roles") as ur then
|
||||
Result := ur
|
||||
end
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
local
|
||||
i: INTEGER
|
||||
n: like last_sequence
|
||||
do
|
||||
n := last_sequence ("user_roles")
|
||||
create {ARRAYED_LIST [CMS_USER_ROLE]} Result.make (n)
|
||||
if n > 0 then
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
if attached user_role_by_id (i) as ur then
|
||||
Result.force (ur)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Change: user_role
|
||||
|
||||
save_user_role (a_role: CMS_USER_ROLE)
|
||||
do
|
||||
if not a_role.has_id then
|
||||
a_role.set_id (next_sequence ("user_roles"))
|
||||
end
|
||||
save_object_with_id (a_role, a_role.id, "user_roles")
|
||||
end
|
||||
|
||||
feature -- Email
|
||||
|
||||
save_email (a_email: NOTIFICATION_EMAIL)
|
||||
local
|
||||
dn: PATH
|
||||
fn: PATH
|
||||
f: RAW_FILE
|
||||
ts: INTEGER_64
|
||||
i: INTEGER
|
||||
do
|
||||
dn := directory_name.extended ("emails")
|
||||
ensure_directory_exists (dn)
|
||||
ts := (create {HTTP_DATE_TIME_UTILITIES}).unix_time_stamp (a_email.date)
|
||||
from
|
||||
fn := dn.extended (ts.out).appended_with_extension ("txt")
|
||||
create f.make_with_path (fn)
|
||||
until
|
||||
not f.exists
|
||||
loop
|
||||
i := i + 1
|
||||
fn := dn.extended (ts.out + "-" + i.out).appended_with_extension ("txt")
|
||||
f.make_with_path (fn)
|
||||
end
|
||||
f.create_read_write
|
||||
f.put_string (a_email.message)
|
||||
f.close
|
||||
end
|
||||
|
||||
feature -- Log
|
||||
|
||||
log (a_id: like {CMS_LOG}.id): detachable CMS_LOG
|
||||
do
|
||||
if attached {CMS_LOG} object_with_id (a_id, "log") as l then
|
||||
Result := l
|
||||
end
|
||||
end
|
||||
|
||||
recent_logs (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG]
|
||||
local
|
||||
n: Like last_sequence
|
||||
i, p1, nb: INTEGER
|
||||
do
|
||||
n := last_sequence ("log")
|
||||
p1 := n - a_lower + 1
|
||||
|
||||
if p1 > 0 then
|
||||
create {ARRAYED_LIST [CMS_LOG]} Result.make (a_count)
|
||||
from
|
||||
i := p1
|
||||
until
|
||||
i < 1 or nb = a_count
|
||||
loop
|
||||
if attached log (i) as obj then
|
||||
Result.force (obj)
|
||||
nb := nb + 1
|
||||
end
|
||||
i := i - 1
|
||||
end
|
||||
else
|
||||
create {ARRAYED_LIST [CMS_LOG]} Result.make (0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
save_log (a_log: CMS_LOG)
|
||||
do
|
||||
if not a_log.has_id then
|
||||
a_log.set_id (next_sequence ("log"))
|
||||
end
|
||||
save_object_with_id (a_log, a_log.id, "log")
|
||||
end
|
||||
|
||||
feature -- Node
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
local
|
||||
n: Like last_sequence
|
||||
i, p1, nb: INTEGER
|
||||
do
|
||||
n := last_sequence ("node")
|
||||
p1 := n - a_lower + 1
|
||||
|
||||
if p1 > 0 then
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (a_count)
|
||||
from
|
||||
i := p1
|
||||
until
|
||||
i < 1 or nb = a_count
|
||||
loop
|
||||
if attached node (i) as l_node then
|
||||
Result.force (l_node)
|
||||
nb := nb + 1
|
||||
end
|
||||
i := i - 1
|
||||
end
|
||||
else
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
end
|
||||
end
|
||||
|
||||
node (a_id: INTEGER): detachable CMS_NODE
|
||||
do
|
||||
if attached {like node} object_with_id (a_id, "node") as obj then
|
||||
Result := obj
|
||||
end
|
||||
end
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
local
|
||||
nid: INTEGER
|
||||
do
|
||||
if a_node.has_id then
|
||||
nid := a_node.id
|
||||
else
|
||||
nid := next_sequence ("node")
|
||||
a_node.set_id (nid)
|
||||
end
|
||||
|
||||
save_object_with_id (a_node, nid, "node")
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
last_sequence (a_type: STRING): INTEGER
|
||||
local
|
||||
fn: PATH
|
||||
f: RAW_FILE
|
||||
do
|
||||
fn := directory_name.extended (a_type).appended_with_extension ("last_id")
|
||||
create f.make_with_path (fn)
|
||||
if f.exists and then f.is_readable then
|
||||
f.open_read
|
||||
f.read_line
|
||||
if f.last_string.is_integer then
|
||||
Result := f.last_string.to_integer
|
||||
else
|
||||
check is_integer: False end
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
next_sequence (a_type: STRING): INTEGER
|
||||
local
|
||||
fn: PATH
|
||||
f: RAW_FILE
|
||||
do
|
||||
fn := directory_name.extended (a_type).appended_with_extension ("last_id")
|
||||
create f.make_with_path (fn)
|
||||
if f.exists and then f.is_readable then
|
||||
f.open_read
|
||||
f.read_line
|
||||
if f.last_string.is_integer then
|
||||
Result := f.last_string.to_integer
|
||||
else
|
||||
check is_integer: False end
|
||||
end
|
||||
f.close
|
||||
end
|
||||
Result := Result + 1
|
||||
f.open_write
|
||||
f.put_string (Result.out)
|
||||
f.put_new_line
|
||||
f.close
|
||||
end
|
||||
|
||||
users_index: TUPLE [
|
||||
by_name: HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.name];
|
||||
by_email: HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.email]
|
||||
]
|
||||
local
|
||||
f: RAW_FILE
|
||||
fn: PATH
|
||||
res: detachable like users_index
|
||||
retried: INTEGER
|
||||
do
|
||||
fn := directory_name.extended ("users.db")
|
||||
create f.make_with_path (fn)
|
||||
if retried = 0 then
|
||||
if f.exists and then f.is_readable then
|
||||
f.open_read
|
||||
if attached {like users_index} sed_file_retrieved (f) as r then
|
||||
res := r
|
||||
end
|
||||
f.close
|
||||
else
|
||||
end
|
||||
end
|
||||
if res = Void then
|
||||
res := [ create {HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.name]}.make (1),
|
||||
create {HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.email]}.make (1) ]
|
||||
end
|
||||
Result := res
|
||||
rescue
|
||||
retried := retried + 1
|
||||
retry
|
||||
end
|
||||
|
||||
store_users_index (a_users_index: like users_index)
|
||||
local
|
||||
f: RAW_FILE
|
||||
fn: PATH
|
||||
do
|
||||
fn := directory_name.extended ("users.db")
|
||||
create f.make_with_path (fn)
|
||||
if not f.exists or else f.is_writable then
|
||||
f.open_write
|
||||
sed_file_store (a_users_index, f)
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
user_profile (a_user: CMS_USER): detachable CMS_USER_PROFILE
|
||||
do
|
||||
if attached {like user_profile} object_with_id (a_user.id, "user_profile") as obj then
|
||||
Result := obj
|
||||
end
|
||||
end
|
||||
|
||||
save_user_profile (a_user: CMS_USER; a_prof: CMS_USER_PROFILE)
|
||||
local
|
||||
l_id: INTEGER
|
||||
do
|
||||
if a_user.has_id then
|
||||
l_id := a_user.id
|
||||
end
|
||||
|
||||
save_object_with_id (a_prof, l_id, "user_profile")
|
||||
end
|
||||
|
||||
feature -- Misc
|
||||
|
||||
custom_type (a_type: READABLE_STRING_8): STRING
|
||||
do
|
||||
Result := "custom__" + a_type
|
||||
end
|
||||
|
||||
custom_value_id (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): INTEGER
|
||||
-- Storage `id' for custom value named `a_name' if any.
|
||||
-- If no such data exists, return 0
|
||||
local
|
||||
i,
|
||||
l_id, l_last_id: INTEGER
|
||||
t: STRING
|
||||
do
|
||||
t := custom_type (a_type)
|
||||
l_last_id := last_sequence (t)
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > l_last_id or l_id > 0
|
||||
loop
|
||||
if
|
||||
attached {TUPLE [name: READABLE_STRING_8; value: attached like custom_value]} object_with_id (i, t) as obj and then
|
||||
obj.name.same_string (a_name)
|
||||
then
|
||||
l_id := i
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value ; a_type: READABLE_STRING_8)
|
||||
-- Save data `a_name:a_value' for type `a_type'
|
||||
local
|
||||
t: STRING
|
||||
l_id: INTEGER
|
||||
do
|
||||
t := custom_type (a_type)
|
||||
l_id := custom_value_id (a_name, a_type)
|
||||
if l_id = 0 then
|
||||
l_id := next_sequence (t)
|
||||
end
|
||||
save_object_with_id ([a_name, a_value], l_id, t)
|
||||
end
|
||||
|
||||
custom_value (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable TABLE_ITERABLE [READABLE_STRING_8, STRING_8]
|
||||
-- Data for name `a_name' and type `a_type'.
|
||||
local
|
||||
i,
|
||||
l_id, l_last_id: INTEGER
|
||||
t: STRING
|
||||
do
|
||||
t := custom_type (a_type)
|
||||
l_last_id := last_sequence (t)
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > l_last_id or l_id > 0
|
||||
loop
|
||||
if
|
||||
attached {TUPLE [name: READABLE_STRING_8; value: attached like custom_value]} object_with_id (i, t) as obj and then
|
||||
obj.name.same_string (a_name)
|
||||
then
|
||||
l_id := i
|
||||
Result := obj.value
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
custom_value_names_where (a_where_key, a_where_value: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable LIST [READABLE_STRING_8]
|
||||
-- Name where custom value has item `a_where_key' same as `a_where_value' for type `a_type'.
|
||||
local
|
||||
i, l_last_id: INTEGER
|
||||
t: STRING
|
||||
l_key_found: BOOLEAN
|
||||
res: ARRAYED_LIST [READABLE_STRING_8]
|
||||
do
|
||||
create res.make (0)
|
||||
t := custom_type (a_type)
|
||||
l_last_id := last_sequence (t)
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > l_last_id
|
||||
loop
|
||||
if
|
||||
attached {TUPLE [name: READABLE_STRING_8; value: attached like custom_value]} object_with_id (i, t) as d
|
||||
then
|
||||
l_key_found := False
|
||||
across
|
||||
d.value as c
|
||||
until
|
||||
l_key_found or Result /= Void
|
||||
loop
|
||||
if c.key.same_string (a_where_key) then
|
||||
l_key_found := True
|
||||
if c.item.same_string (a_where_value) then
|
||||
res.force (d.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
if not res.is_empty then
|
||||
Result := res
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
ensure_directory_exists (dn: PATH)
|
||||
local
|
||||
d: DIRECTORY
|
||||
do
|
||||
d := tmp_dir
|
||||
d.make_with_path (dn)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
tmp_dir: DIRECTORY
|
||||
once
|
||||
create Result.make_with_path (directory_name)
|
||||
end
|
||||
|
||||
invariant
|
||||
|
||||
end
|
||||
186
draft/application/cms/src/storage/cms_storage.e
Normal file
186
draft/application/cms/src/storage/cms_storage.e
Normal file
@@ -0,0 +1,186 @@
|
||||
note
|
||||
description : "[
|
||||
CMS interface to storage
|
||||
]"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_STORAGE
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Access: user
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
deferred
|
||||
end
|
||||
|
||||
fill_user_profile (a_user: CMS_USER)
|
||||
deferred
|
||||
end
|
||||
|
||||
all_users: LIST [CMS_USER]
|
||||
deferred
|
||||
end
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
ensure
|
||||
same_id: Result /= Void implies Result.id = a_id
|
||||
no_password: Result /= Void implies Result.password = Void
|
||||
end
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
require
|
||||
a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
ensure
|
||||
no_password: Result /= Void implies Result.password = Void
|
||||
end
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
deferred
|
||||
ensure
|
||||
no_password: Result /= Void implies Result.password = Void
|
||||
end
|
||||
|
||||
is_valid_credential (u, p: READABLE_STRING_32): BOOLEAN
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
save_user (a_user: CMS_USER)
|
||||
deferred
|
||||
ensure
|
||||
a_user_password_is_encoded: a_user.password = Void
|
||||
a_user.has_id
|
||||
end
|
||||
|
||||
feature -- Access: roles and permissions
|
||||
|
||||
user_has_permission (u: detachable CMS_USER; s: detachable READABLE_STRING_8): BOOLEAN
|
||||
-- Anonymous or user `u' has permission for `s' ?
|
||||
--| `s' could be "create page",
|
||||
do
|
||||
if s = Void then
|
||||
Result := True
|
||||
elseif u = Void then
|
||||
Result := user_role_has_permission (anonymous_user_role, s)
|
||||
else
|
||||
Result := user_role_has_permission (authenticated_user_role, s)
|
||||
if not Result and attached u.roles as l_roles then
|
||||
across
|
||||
l_roles as r
|
||||
until
|
||||
Result
|
||||
loop
|
||||
if attached user_role_by_id (r.item) as ur then
|
||||
Result := user_role_has_permission (ur, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
anonymous_user_role: CMS_USER_ROLE
|
||||
do
|
||||
if attached user_role_by_id (1) as l_anonymous then
|
||||
Result := l_anonymous
|
||||
else
|
||||
create Result.make ("anonymous")
|
||||
end
|
||||
end
|
||||
|
||||
authenticated_user_role: CMS_USER_ROLE
|
||||
do
|
||||
if attached user_role_by_id (2) as l_authenticated then
|
||||
Result := l_authenticated
|
||||
else
|
||||
create Result.make ("authenticated")
|
||||
end
|
||||
end
|
||||
|
||||
user_role_has_permission (a_role: CMS_USER_ROLE; s: READABLE_STRING_8): BOOLEAN
|
||||
do
|
||||
Result := a_role.has_permission (s)
|
||||
end
|
||||
|
||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||
deferred
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: roles and permissions
|
||||
|
||||
save_user_role (a_user_role: CMS_USER_ROLE)
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Email
|
||||
|
||||
save_email (a_email: NOTIFICATION_EMAIL)
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Log
|
||||
|
||||
recent_logs (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG]
|
||||
deferred
|
||||
end
|
||||
|
||||
log (a_id: like {CMS_LOG}.id): detachable CMS_LOG
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
save_log (a_log: CMS_LOG)
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Node
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
deferred
|
||||
end
|
||||
|
||||
node (a_id: INTEGER): detachable CMS_NODE
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Misc
|
||||
|
||||
set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value; a_type: READABLE_STRING_8)
|
||||
-- Save data `a_name:a_value' for type `a_type'
|
||||
deferred
|
||||
end
|
||||
|
||||
custom_value (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable TABLE_ITERABLE [READABLE_STRING_8, STRING_8]
|
||||
-- Data for name `a_name' and type `a_type'.
|
||||
deferred
|
||||
end
|
||||
|
||||
custom_value_names_where (a_where_key, a_where_value: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable LIST [READABLE_STRING_8]
|
||||
-- Names where custom value has item `a_where_key' same as `a_where_value' for type `a_type'.
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
@@ -11,7 +11,6 @@
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<precompile name="precomp_wsf-mt" location="..\..\..\..\precomp\wsf-mt-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -160,58 +160,126 @@ feature -- Conversion to string
|
||||
|
||||
feature -- Conversion into string
|
||||
|
||||
append_date_time_to_yyyy_mmm_dd_string (dt: DATE_TIME; s: STRING)
|
||||
append_to_yyyy_mmm_dd_string (s: STRING_GENERAL)
|
||||
local
|
||||
dt: DATE_TIME
|
||||
do
|
||||
s.append_integer (dt.year) -- yyyy
|
||||
s.append_character (' ') -- ' '
|
||||
dt := date_time
|
||||
append_integer_to (dt.year, s) -- yyyy
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_character (' ') -- ' '
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_integer_to (dt.day, s) -- dd
|
||||
end
|
||||
|
||||
append_date_time_to_rfc1123_string (dt: DATE_TIME; s: STRING)
|
||||
append_to_rfc1123_string (s: STRING_GENERAL)
|
||||
local
|
||||
dt: DATE_TIME
|
||||
do
|
||||
dt := date_time
|
||||
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
|
||||
s.append_code (44) -- 44 ',' -- ','
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_integer_to (dt.day, s) -- dd
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_integer_to (dt.year, s) -- YYYY
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
|
||||
s.append (" GMT") -- SPace + GMT
|
||||
end
|
||||
|
||||
append_rfc850_string (s: STRING_GENERAL)
|
||||
local
|
||||
dt: DATE_TIME
|
||||
do
|
||||
dt := date_time
|
||||
append_day_name_to (dt.date.day_of_the_week, s) -- mmm
|
||||
s.append_code (44) -- 44 ',' -- ','
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_integer_to (dt.day, s) -- dd
|
||||
s.append_code (45) -- 45 '-' -- '-'
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_code (45) -- 45 '-' -- '-'
|
||||
append_integer_to (dt.year \\ 100, s) -- yy
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
|
||||
s.append (" GMT") -- SPace + GMT
|
||||
end
|
||||
|
||||
append_to_ansi_c_string (s: STRING_GENERAL)
|
||||
--| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
|
||||
local
|
||||
dt: DATE_TIME
|
||||
do
|
||||
dt := date_time
|
||||
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_integer_to (dt.day, s) -- d
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_integer_to (dt.year, s) -- yyyy
|
||||
end
|
||||
|
||||
feature -- Conversion into string
|
||||
|
||||
append_date_time_to_yyyy_mmm_dd_string (dt: DATE_TIME; s: STRING_GENERAL)
|
||||
do
|
||||
append_integer_to (dt.year, s) -- yyyy
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_integer_to (dt.day, s) -- dd
|
||||
end
|
||||
|
||||
append_date_time_to_rfc1123_string (dt: DATE_TIME; s: STRING_GENERAL)
|
||||
do
|
||||
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
|
||||
s.append_character (',') -- ','
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_code (44) -- 44 ',' -- ','
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_integer_to (dt.day, s) -- dd
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_integer (dt.year) -- yyyy
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_integer_to (dt.year, s) -- yyyy
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
|
||||
s.append (" GMT") -- SPace + GMT
|
||||
end
|
||||
|
||||
append_date_time_to_rfc850_string (dt: DATE_TIME; s: STRING)
|
||||
append_date_time_to_rfc850_string (dt: DATE_TIME; s: STRING_GENERAL)
|
||||
do
|
||||
append_day_name_to (dt.date.day_of_the_week, s) -- mmm
|
||||
s.append_character (',') -- ,
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_code (44) -- 44 ',' -- ','
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_integer_to (dt.day, s) -- dd
|
||||
s.append_character ('-') -- '-'
|
||||
s.append_code (45) -- 45 '-' -- '-'
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_character ('-') -- '-'
|
||||
s.append_integer (dt.year \\ 100) -- yy
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_code (45) -- 45 '-' -- '-'
|
||||
append_integer_to (dt.year \\ 100, s) -- yy
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
|
||||
s.append (" GMT") -- SPace + GMT
|
||||
end
|
||||
|
||||
append_date_time_to_ansi_c_string (dt: DATE_TIME; s: STRING)
|
||||
append_date_time_to_ansi_c_string (dt: DATE_TIME; s: STRING_GENERAL)
|
||||
--| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
|
||||
do
|
||||
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
|
||||
s.append_character (' ') -- SP
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_month_mmm_to (dt.month, s) -- mmm
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_integer (dt.day) -- d
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_integer_to (dt.day, s) -- d
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
|
||||
s.append_character (' ') -- SPace
|
||||
s.append_integer (dt.year) -- yyyy
|
||||
s.append_code (32) -- 32 ' ' -- SPace
|
||||
append_integer_to (dt.year, s) -- yyyy
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
@@ -228,26 +296,26 @@ feature -- Status report
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
append_2_digits_integer_to (i: INTEGER; s: STRING)
|
||||
append_2_digits_integer_to (i: INTEGER; s: STRING_GENERAL)
|
||||
require
|
||||
is_not_negative: i >= 0
|
||||
do
|
||||
if i <= 9 then
|
||||
s.append_character ('0')
|
||||
s.append_code (48) -- 48 '0'
|
||||
end
|
||||
s.append_integer (i)
|
||||
append_integer_to (i, s)
|
||||
end
|
||||
|
||||
append_2_digits_time_to (t: TIME; s: STRING)
|
||||
append_2_digits_time_to (t: TIME; s: STRING_GENERAL)
|
||||
do
|
||||
append_2_digits_integer_to (t.hour, s) -- hh
|
||||
s.append_character (':') -- :
|
||||
s.append_code (58) -- 58 ':' -- :
|
||||
append_2_digits_integer_to (t.minute, s) -- mi
|
||||
s.append_character (':') -- :
|
||||
s.append_code (58) -- 58 ':' -- :
|
||||
append_2_digits_integer_to (t.second, s) -- ss
|
||||
end
|
||||
|
||||
append_day_ddd_to (d: INTEGER; s: STRING)
|
||||
append_day_ddd_to (d: INTEGER; s: STRING_GENERAL)
|
||||
require
|
||||
1 <= d and d <= 7
|
||||
do
|
||||
@@ -264,7 +332,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
append_day_name_to (d: INTEGER; s: STRING)
|
||||
append_day_name_to (d: INTEGER; s: STRING_GENERAL)
|
||||
require
|
||||
1 <= d and d <= 7
|
||||
do
|
||||
@@ -281,7 +349,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
append_month_mmm_to (m: INTEGER; s: STRING)
|
||||
append_month_mmm_to (m: INTEGER; s: STRING_GENERAL)
|
||||
require
|
||||
1 <= m and m <= 12
|
||||
do
|
||||
@@ -303,6 +371,17 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
append_integer_to (i: INTEGER; s: STRING_GENERAL)
|
||||
do
|
||||
if attached {STRING_32} s as s32 then
|
||||
s32.append_integer (i)
|
||||
elseif attached {STRING_8} s as s8 then
|
||||
s8.append_integer (i)
|
||||
else
|
||||
s.append (i.out)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
string_to_date_time (s: READABLE_STRING_8): detachable DATE_TIME
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="tests" uuid="0582ACC2-11D8-4FE5-888D-61837BA8F43E">
|
||||
<target name="tests">
|
||||
<root class="ANY" feature="default_create"/>
|
||||
<root class="AUTOTEST" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
|
||||
10
library/runtime/process/notification_email/license.lic
Normal file
10
library/runtime/process/notification_email/license.lic
Normal file
@@ -0,0 +1,10 @@
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "2011-${YEAR}, 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
|
||||
]"
|
||||
@@ -0,0 +1,68 @@
|
||||
note
|
||||
description: "Summary description for {NOTIFICATION_CHAIN_MAILER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
NOTIFICATION_CHAIN_MAILER
|
||||
|
||||
inherit
|
||||
NOTIFICATION_MAILER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_mailer: like active)
|
||||
do
|
||||
active := a_mailer
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
active: NOTIFICATION_MAILER
|
||||
|
||||
next: detachable NOTIFICATION_MAILER
|
||||
|
||||
feature -- Status
|
||||
|
||||
is_available: BOOLEAN
|
||||
do
|
||||
Result := active.is_available
|
||||
if not Result and attached next as l_next then
|
||||
Result := l_next.is_available
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_next (m: like next)
|
||||
do
|
||||
next := m
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
process_email (a_email: NOTIFICATION_EMAIL)
|
||||
do
|
||||
if active.is_available then
|
||||
active.process_email (a_email)
|
||||
end
|
||||
if attached next as l_next and then l_next.is_available then
|
||||
l_next.process_email (a_email)
|
||||
end
|
||||
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
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="notification_email" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification_email">
|
||||
<target name="notification_email">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<cluster name="src" location="." recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
104
library/runtime/process/notification_email/notification_email.e
Normal file
104
library/runtime/process/notification_email/notification_email.e
Normal file
@@ -0,0 +1,104 @@
|
||||
note
|
||||
description : "[
|
||||
Component representing an email
|
||||
]"
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
NOTIFICATION_EMAIL
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_body: like body)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
initialize
|
||||
from_address := a_from
|
||||
subject := a_subject
|
||||
body := a_body
|
||||
to_addresses.extend (a_to_address)
|
||||
|
||||
end
|
||||
|
||||
initialize
|
||||
do
|
||||
create date.make_now_utc
|
||||
create to_addresses.make (1)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
date: DATE_TIME
|
||||
|
||||
from_address: READABLE_STRING_8
|
||||
|
||||
to_addresses: ARRAYED_LIST [READABLE_STRING_8]
|
||||
|
||||
subject: READABLE_STRING_8
|
||||
|
||||
body: READABLE_STRING_8
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_date (d: like date)
|
||||
do
|
||||
date := d
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
message: STRING_8
|
||||
do
|
||||
Result := header
|
||||
Result.append_character ('%N')
|
||||
Result.append (body)
|
||||
Result.append_character ('%N')
|
||||
Result.append_character ('%N')
|
||||
end
|
||||
|
||||
header: STRING_8
|
||||
local
|
||||
hdate: HTTP_DATE
|
||||
do
|
||||
create Result.make (20)
|
||||
Result.append ("From: ")
|
||||
Result.append (from_address)
|
||||
Result.append_character ('%N')
|
||||
Result.append ("Date: ")
|
||||
create hdate.make_from_date_time (date)
|
||||
hdate.append_to_rfc1123_string (Result)
|
||||
Result.append (" GMT%N")
|
||||
Result.append ("To: ")
|
||||
across
|
||||
to_addresses as c
|
||||
loop
|
||||
Result.append (c.item)
|
||||
Result.append_character (';')
|
||||
end
|
||||
Result.append_character ('%N')
|
||||
Result.append ("Subject: ")
|
||||
Result.append (subject)
|
||||
Result.append_character ('%N')
|
||||
ensure
|
||||
Result.ends_with ("%N")
|
||||
end
|
||||
|
||||
invariant
|
||||
-- invariant_clause: True
|
||||
|
||||
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
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="notification_email" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification_email">
|
||||
<target name="notification_email">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="http" location="..\..\..\network\protocol\http\http.ecf"/>
|
||||
<library name="process" location="$ISE_LIBRARY\library\process\process.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="src" location="." recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -0,0 +1,208 @@
|
||||
note
|
||||
description: "[
|
||||
Component responsible to send email using an external mailer
|
||||
i.e: an external tool such as sendmail or a script, ...
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
NOTIFICATION_EXTERNAL_MAILER
|
||||
|
||||
inherit
|
||||
NOTIFICATION_MAILER
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_exe: READABLE_STRING_GENERAL; args: detachable ITERABLE [READABLE_STRING_GENERAL])
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
set_parameters (a_exe, args)
|
||||
end
|
||||
|
||||
executable_path: PATH
|
||||
|
||||
arguments: detachable ARRAYED_LIST [READABLE_STRING_GENERAL]
|
||||
|
||||
stdin_mode_set: BOOLEAN
|
||||
-- Use `stdin' to pass email message, rather than using local file?
|
||||
|
||||
stdin_termination_sequence: detachable READABLE_STRING_8
|
||||
-- Termination sequence for the stdin mode
|
||||
--| If any, this tells the executable all the data has been provided
|
||||
--| For instance, using sendmail, you should have "%N.%N%N"
|
||||
|
||||
feature -- Status
|
||||
|
||||
is_available: BOOLEAN
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make_with_path (executable_path)
|
||||
Result := f.exists
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_parameters (cmd: READABLE_STRING_GENERAL; args: detachable ITERABLE [READABLE_STRING_GENERAL])
|
||||
-- Set parameters `executable_path' and associated `arguments'
|
||||
local
|
||||
l_args: like arguments
|
||||
do
|
||||
create executable_path.make_from_string (cmd)
|
||||
if args = Void then
|
||||
arguments := Void
|
||||
else
|
||||
create l_args.make (5)
|
||||
across
|
||||
args as c
|
||||
loop
|
||||
l_args.force (c.item)
|
||||
end
|
||||
arguments := l_args
|
||||
end
|
||||
end
|
||||
|
||||
set_stdin_mode (b: BOOLEAN; v: like stdin_termination_sequence)
|
||||
-- Set the `stdin_mode_set' value
|
||||
-- and provide optional termination sequence when stdin mode is selected.
|
||||
do
|
||||
stdin_mode_set := b
|
||||
stdin_termination_sequence := v
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
process_email (a_email: NOTIFICATION_EMAIL)
|
||||
local
|
||||
l_factory: PROCESS_FACTORY
|
||||
args: like arguments
|
||||
p: detachable PROCESS
|
||||
retried: INTEGER
|
||||
do
|
||||
if retried = 0 then
|
||||
create l_factory
|
||||
if stdin_mode_set then
|
||||
p := l_factory.process_launcher (executable_path.name, arguments, Void)
|
||||
p.set_hidden (True)
|
||||
p.set_separate_console (False)
|
||||
|
||||
p.redirect_input_to_stream
|
||||
p.launch
|
||||
if p.launched then
|
||||
p.put_string (a_email.message)
|
||||
if attached stdin_termination_sequence as v then
|
||||
p.put_string (v)
|
||||
end
|
||||
end
|
||||
else
|
||||
if attached arguments as l_args then
|
||||
args := l_args.twin
|
||||
else
|
||||
if attached {RAW_FILE} new_temporary_file (generator) as f then
|
||||
f.create_read_write
|
||||
f.put_string (a_email.message)
|
||||
f.close
|
||||
create args.make (1)
|
||||
args.force (f.name)
|
||||
end
|
||||
end
|
||||
p := l_factory.process_launcher (executable_path.name, args, Void)
|
||||
p.set_hidden (True)
|
||||
p.set_separate_console (False)
|
||||
|
||||
p.launch
|
||||
end
|
||||
if p.launched and not p.has_exited then
|
||||
p.wait_for_exit_with_timeout (1_000_000)
|
||||
if not p.has_exited then
|
||||
p.terminate
|
||||
if not p.has_exited then
|
||||
p.wait_for_exit_with_timeout (1_000_000)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif retried = 1 then
|
||||
if p /= Void and then p.launched and then not p.has_exited then
|
||||
p.terminate
|
||||
if not p.has_exited then
|
||||
p.wait_for_exit_with_timeout (1_000_000)
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := retried + 1
|
||||
retry
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
new_temporary_file (a_extension: detachable READABLE_STRING_8): RAW_FILE
|
||||
-- Create file with temporary name.
|
||||
-- With concurrent execution, noting ensures that {FILE_NAME}.make_temporary_name is unique
|
||||
-- So using `a_extension' may help
|
||||
local
|
||||
bn: STRING_32
|
||||
fn: PATH
|
||||
s: STRING_32
|
||||
f: detachable like new_temporary_file
|
||||
i: INTEGER
|
||||
do
|
||||
-- With concurrent execution, nothing ensures that {FILE_NAME}.make_temporary_name is unique
|
||||
-- So let's try to find
|
||||
from
|
||||
create bn.make_from_string_general ((create {FILE_NAME}.make_temporary_name).string)
|
||||
create s.make_empty
|
||||
until
|
||||
f /= Void or i > 1000
|
||||
loop
|
||||
create fn.make_from_string (bn)
|
||||
s.make_empty
|
||||
if i > 0 then
|
||||
s.append_character ('-')
|
||||
s.append_integer (i)
|
||||
fn := fn.appended (s)
|
||||
end
|
||||
if a_extension /= Void then
|
||||
fn := fn.appended_with_extension (a_extension)
|
||||
end
|
||||
create f.make_with_path (fn)
|
||||
if f.exists then
|
||||
i := i + 1
|
||||
f := Void
|
||||
end
|
||||
end
|
||||
if f = Void then
|
||||
Result := new_temporary_file (Void)
|
||||
else
|
||||
Result := f
|
||||
check not_temporary_file_exists: not Result.exists end
|
||||
check temporary_creatable: Result.is_creatable end
|
||||
end
|
||||
ensure
|
||||
not_result_exists: not Result.exists
|
||||
result_creatable: Result.is_creatable
|
||||
end
|
||||
|
||||
invariant
|
||||
|
||||
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
|
||||
@@ -0,0 +1,58 @@
|
||||
note
|
||||
description: "[
|
||||
Component responsible to send email
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
NOTIFICATION_MAILER
|
||||
|
||||
feature -- Status
|
||||
|
||||
is_available: BOOLEAN
|
||||
-- Is mailer available to use?
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
process_emails (lst: ITERABLE [NOTIFICATION_EMAIL])
|
||||
-- Process set of emails `lst'
|
||||
require
|
||||
is_available
|
||||
do
|
||||
across
|
||||
lst as c
|
||||
loop
|
||||
process_email (c.item)
|
||||
end
|
||||
end
|
||||
|
||||
safe_process_email (a_email: NOTIFICATION_EMAIL)
|
||||
-- Same as `process_email', but include the check of `is_available'
|
||||
do
|
||||
if is_available then
|
||||
process_email (a_email)
|
||||
end
|
||||
end
|
||||
|
||||
process_email (a_email: NOTIFICATION_EMAIL)
|
||||
-- Process the sending of `a_email'
|
||||
require
|
||||
is_available
|
||||
deferred
|
||||
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
|
||||
@@ -0,0 +1,44 @@
|
||||
note
|
||||
description : "[
|
||||
NOTIFICATION_MAILER using sendmail as mailtool
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
NOTIFICATION_SENDMAIL_MAILER
|
||||
|
||||
inherit
|
||||
NOTIFICATION_EXTERNAL_MAILER
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
|
||||
create
|
||||
default_create
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
default_create
|
||||
do
|
||||
Precursor
|
||||
make ("/usr/sbin/sendmail", <<"-t">>)
|
||||
if not is_available then
|
||||
make ("/usr/bin/sendmail", <<"-t">>)
|
||||
end
|
||||
set_stdin_mode (True, "%N.%N%N")
|
||||
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
|
||||
@@ -19,6 +19,11 @@ inherit
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
@@ -42,14 +47,20 @@ feature {NONE} -- Initialization
|
||||
on_launched (conn: WGI_CONNECTOR)
|
||||
local
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
cmd: STRING_32
|
||||
do
|
||||
if attached {WGI_NINO_CONNECTOR} conn as nino then
|
||||
create e
|
||||
if attached e.get ("COMSPEC") as l_comspec then
|
||||
e.launch (l_comspec + " /C start " + "http://localhost:" + nino.port.out + "/")
|
||||
else
|
||||
e.launch ("http://localhost:" + nino.port.out + "/")
|
||||
e := execution_environment
|
||||
create cmd.make (32)
|
||||
if attached e.item ("COMSPEC") as l_comspec then
|
||||
cmd.append (l_comspec)
|
||||
cmd.append ({STRING_32} " /C start ")
|
||||
end
|
||||
cmd.append ("http://localhost:")
|
||||
cmd.append_integer (nino.port)
|
||||
cmd.append_character ({CHARACTER_32} '/')
|
||||
|
||||
e.launch (cmd)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ feature {OPENID_CONSUMER_VALIDATION} -- Implementation
|
||||
sess: HTTP_CLIENT_SESSION
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
xrds_location: detachable READABLE_STRING_8
|
||||
xml: XML_LITE_PARSER
|
||||
xml: XML_STANDARD_PARSER
|
||||
tree: XML_CALLBACKS_DOCUMENT
|
||||
xelt: detachable XML_ELEMENT
|
||||
s: READABLE_STRING_32
|
||||
|
||||
@@ -52,19 +52,23 @@ feature -- Execution
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>" + l_trace + "</pre>")
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (l_trace)
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
if not rescued then
|
||||
rescued := True
|
||||
retry
|
||||
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
|
||||
|
||||
@@ -55,7 +55,7 @@ feature -- Server
|
||||
|
||||
feature -- Execution
|
||||
|
||||
process_fcgi_request (vars: HASH_TABLE [STRING, STRING]; a_input: like input; a_output: like output)
|
||||
process_fcgi_request (vars: STRING_TABLE [READABLE_STRING_8]; a_input: like input; a_output: like output)
|
||||
local
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_RESPONSE_STREAM
|
||||
@@ -73,16 +73,20 @@ feature -- Execution
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>" + l_trace + "</pre>")
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (l_trace)
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
if not rescued then
|
||||
rescued := True
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Input/Output
|
||||
|
||||
@@ -100,7 +104,7 @@ invariant
|
||||
fcgi_attached: fcgi /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2011, 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
|
||||
|
||||
@@ -127,20 +127,28 @@ feature -- Server
|
||||
server.setup (l_http_handler)
|
||||
end
|
||||
|
||||
process_request (env: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_socket: TCP_STREAM_SOCKET)
|
||||
process_request (env: STRING_TABLE [READABLE_STRING_8]; a_headers_text: STRING; a_socket: TCP_STREAM_SOCKET)
|
||||
local
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_NINO_RESPONSE_STREAM
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried then
|
||||
create req.make (env, create {WGI_NINO_INPUT_STREAM}.make (a_socket), Current)
|
||||
create res.make (create {WGI_NINO_OUTPUT_STREAM}.make (a_socket), create {WGI_NINO_ERROR_STREAM}.make_stderr (a_socket.descriptor.out))
|
||||
req.set_meta_string_variable ("RAW_HEADER_DATA", a_headers_text)
|
||||
service.execute (req, res)
|
||||
res.push
|
||||
end
|
||||
rescue
|
||||
if not retried then
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -61,24 +61,24 @@ feature -- Request processing
|
||||
process_request (a_handler: HTTP_CONNECTION_HANDLER; a_socket: TCP_STREAM_SOCKET)
|
||||
-- Process request ...
|
||||
local
|
||||
env: HASH_TABLE [STRING, STRING]
|
||||
env: STRING_TABLE [READABLE_STRING_8]
|
||||
p: INTEGER
|
||||
l_request_uri, l_script_name, l_query_string, l_path_info: STRING
|
||||
l_server_name, l_server_port: detachable STRING
|
||||
a_headers_map: HASH_TABLE [STRING, STRING]
|
||||
l_headers_map: HASH_TABLE [STRING, STRING]
|
||||
vn: STRING
|
||||
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
do
|
||||
l_request_uri := a_handler.uri
|
||||
a_headers_map := a_handler.request_header_map
|
||||
l_headers_map := a_handler.request_header_map
|
||||
create e
|
||||
if attached e.starting_environment_variables as vars then
|
||||
create env.make (vars.count)
|
||||
create env.make_equal (vars.count)
|
||||
across
|
||||
vars as c
|
||||
loop
|
||||
env.force (c.item.to_string_8, c.key.to_string_8)
|
||||
env.force (c.item.to_string_8, c.key)
|
||||
end
|
||||
else
|
||||
create env.make (0)
|
||||
@@ -86,11 +86,11 @@ feature -- Request processing
|
||||
|
||||
--| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `env'
|
||||
from
|
||||
a_headers_map.start
|
||||
l_headers_map.start
|
||||
until
|
||||
a_headers_map.after
|
||||
l_headers_map.after
|
||||
loop
|
||||
create vn.make_from_string (a_headers_map.key_for_iteration.as_upper)
|
||||
create vn.make_from_string (l_headers_map.key_for_iteration.as_upper)
|
||||
vn.replace_substring_all ("-", "_")
|
||||
if
|
||||
vn.starts_with ("CONTENT_") and then
|
||||
@@ -100,8 +100,8 @@ feature -- Request processing
|
||||
else
|
||||
vn.prepend ("HTTP_")
|
||||
end
|
||||
add_environment_variable (a_headers_map.item_for_iteration, vn, env)
|
||||
a_headers_map.forth
|
||||
add_environment_variable (l_headers_map.item_for_iteration, vn, env)
|
||||
l_headers_map.forth
|
||||
end
|
||||
|
||||
--| Specific cases
|
||||
@@ -114,7 +114,7 @@ feature -- Request processing
|
||||
l_script_name := l_request_uri.string
|
||||
l_query_string := ""
|
||||
end
|
||||
if attached a_headers_map.item ("Host") as l_host then
|
||||
if attached l_headers_map.item ("Host") as l_host then
|
||||
check has_host: env.has ("HTTP_HOST") end
|
||||
-- set_environment_variable (l_host, "HTTP_HOST", env)
|
||||
p := l_host.index_of (':', 1)
|
||||
@@ -129,7 +129,7 @@ feature -- Request processing
|
||||
check host_available: False end
|
||||
end
|
||||
|
||||
if attached a_headers_map.item ("Authorization") as l_authorization then
|
||||
if attached l_headers_map.item ("Authorization") as l_authorization then
|
||||
check has_authorization: env.has ("HTTP_AUTHORIZATION") end
|
||||
-- set_environment_variable (l_authorization, "HTTP_AUTHORIZATION", env)
|
||||
p := l_authorization.index_of (' ', 1)
|
||||
@@ -174,7 +174,7 @@ feature -- Request processing
|
||||
callback.process_request (env, a_handler.request_header, a_socket)
|
||||
end
|
||||
|
||||
add_environment_variable (a_value: detachable STRING; a_var_name: STRING; env: HASH_TABLE [STRING, STRING])
|
||||
add_environment_variable (a_value: detachable STRING; a_var_name: READABLE_STRING_GENERAL; env: STRING_TABLE [READABLE_STRING_8])
|
||||
-- Add variable `a_var_name => a_value' to `env'
|
||||
do
|
||||
if a_value /= Void then
|
||||
@@ -188,7 +188,7 @@ feature -- Request processing
|
||||
end
|
||||
end
|
||||
|
||||
set_environment_variable (a_value: detachable STRING; a_var_name: STRING; env: HASH_TABLE [STRING, STRING])
|
||||
set_environment_variable (a_value: detachable STRING; a_var_name: READABLE_STRING_GENERAL; env: STRING_TABLE [READABLE_STRING_8])
|
||||
-- Add variable `a_var_name => a_value' to `env'
|
||||
do
|
||||
if a_value /= Void then
|
||||
@@ -197,7 +197,7 @@ feature -- Request processing
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -88,14 +88,14 @@ feature -- Access: Input
|
||||
|
||||
feature -- Access: CGI meta variables
|
||||
|
||||
meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||
meta_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
|
||||
-- Environment variable related to `a_name'
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
end
|
||||
|
||||
meta_string_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||
meta_string_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
|
||||
-- Environment variable related to `a_name'
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
@@ -105,7 +105,7 @@ feature -- Access: CGI meta variables
|
||||
end
|
||||
end
|
||||
|
||||
meta_variables: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
meta_variables: STRING_TABLE [READABLE_STRING_8]
|
||||
-- These variables are specific to requests made with HTTP.
|
||||
-- Interpretation of these variables may depend on the value of
|
||||
-- SERVER_PROTOCOL.
|
||||
@@ -635,7 +635,7 @@ invariant
|
||||
path_info_identical: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -138,8 +138,6 @@ feature -- Input
|
||||
nb_large_enough: nb > 0
|
||||
local
|
||||
s: like last_string
|
||||
i, end_pos: INTEGER
|
||||
l_count: INTEGER
|
||||
n: INTEGER
|
||||
l_remaining: INTEGER
|
||||
do
|
||||
|
||||
@@ -61,16 +61,16 @@ feature -- EWSGI access
|
||||
|
||||
feature -- Access: CGI meta parameters
|
||||
|
||||
meta_variables: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
meta_variables: STRING_TABLE [READABLE_STRING_8]
|
||||
-- CGI Environment parameters
|
||||
|
||||
meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||
meta_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
|
||||
-- CGI meta variable related to `a_name'
|
||||
do
|
||||
Result := meta_variables.item (a_name)
|
||||
end
|
||||
|
||||
meta_string_variable_or_default (a_name: READABLE_STRING_8; a_default: READABLE_STRING_8; use_default_when_empty: BOOLEAN): READABLE_STRING_8
|
||||
meta_string_variable_or_default (a_name: READABLE_STRING_GENERAL; a_default: READABLE_STRING_8; use_default_when_empty: BOOLEAN): READABLE_STRING_8
|
||||
-- Value for meta parameter `a_name'
|
||||
-- If not found, return `a_default'
|
||||
require
|
||||
@@ -86,14 +86,14 @@ feature -- Access: CGI meta parameters
|
||||
end
|
||||
end
|
||||
|
||||
set_meta_string_variable (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8)
|
||||
set_meta_string_variable (a_name: READABLE_STRING_GENERAL; a_value: READABLE_STRING_8)
|
||||
do
|
||||
meta_variables.force (a_value, a_name)
|
||||
ensure
|
||||
param_set: attached meta_variable (a_name) as val and then val ~ a_value
|
||||
end
|
||||
|
||||
unset_meta_variable (a_name: READABLE_STRING_8)
|
||||
unset_meta_variable (a_name: READABLE_STRING_GENERAL)
|
||||
do
|
||||
meta_variables.remove (a_name)
|
||||
ensure
|
||||
@@ -268,7 +268,7 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
|
||||
-- Fill with variable from `a_vars'
|
||||
local
|
||||
s: like meta_string_variable
|
||||
table: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
table: STRING_TABLE [READABLE_STRING_8]
|
||||
l_query_string: like query_string
|
||||
l_request_uri: detachable STRING_32
|
||||
l_empty_string: like empty_string
|
||||
@@ -276,15 +276,14 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
|
||||
create {STRING_8} l_empty_string.make_empty
|
||||
empty_string := l_empty_string
|
||||
|
||||
create table.make (a_vars.count)
|
||||
table.compare_objects
|
||||
create table.make_equal (a_vars.count)
|
||||
meta_variables := table
|
||||
from
|
||||
a_vars.start
|
||||
until
|
||||
a_vars.after
|
||||
loop
|
||||
table.force (a_vars.item_for_iteration.to_string_8, a_vars.key_for_iteration.to_string_8)
|
||||
table.force (a_vars.item_for_iteration.to_string_8, a_vars.key_for_iteration)
|
||||
a_vars.forth
|
||||
end
|
||||
|
||||
@@ -446,7 +445,7 @@ invariant
|
||||
empty_string_unchanged: empty_string.is_empty
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -19,13 +19,13 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature -- Access
|
||||
|
||||
updated_environ_variables: HASH_TABLE [STRING, STRING]
|
||||
updated_environ_variables: STRING_TABLE [READABLE_STRING_8]
|
||||
local
|
||||
i: INTEGER
|
||||
p, v, null: POINTER
|
||||
do
|
||||
p := fcgi_environ
|
||||
create Result.make (50)
|
||||
create Result.make_equal (50)
|
||||
if p /= null then
|
||||
from
|
||||
i := 0
|
||||
@@ -33,7 +33,7 @@ feature -- Access
|
||||
until
|
||||
v = null
|
||||
loop
|
||||
if attached separated_variables (create {STRING}.make_from_c (v)) as t then
|
||||
if attached separated_variables (create {STRING_8}.make_from_c (v)) as t then
|
||||
Result.force (t.value, t.key)
|
||||
end
|
||||
i := i + 1
|
||||
@@ -196,7 +196,7 @@ feature {NONE} -- Implementation: Environment
|
||||
"return ((char **)$p)[$i];"
|
||||
end
|
||||
|
||||
separated_variables (a_var: STRING): detachable TUPLE [value: STRING; key: STRING]
|
||||
separated_variables (a_var: READABLE_STRING_8): detachable TUPLE [value: READABLE_STRING_8; key: READABLE_STRING_8]
|
||||
-- Given an environment variable `a_var' in form of "key=value",
|
||||
-- return separated key and value.
|
||||
-- Return Void if `a_var' is in incorrect format.
|
||||
@@ -224,7 +224,7 @@ feature {NONE} -- Implementation: Environment
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
copyright: "Copyright (c) 1984-2013, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -24,6 +24,11 @@ inherit
|
||||
initialize
|
||||
end
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make,
|
||||
make_and_launch,
|
||||
@@ -37,15 +42,19 @@ feature {NONE} -- Initialization
|
||||
l_env: EXECUTION_ENVIRONMENT
|
||||
do
|
||||
Precursor
|
||||
create l_env
|
||||
l_env := execution_environment
|
||||
|
||||
if attached l_env.get (Openshift_ip) as l_ip then
|
||||
if attached l_env.item (Openshift_ip) as l_ip then
|
||||
if l_ip.is_valid_as_string_8 then
|
||||
server_name := l_ip.to_string_8
|
||||
else
|
||||
die ("could not parse " + Openshift_ip)
|
||||
end
|
||||
else
|
||||
die (Openshift_ip + " is not defined")
|
||||
end
|
||||
|
||||
if attached l_env.get (Openshift_port) as l_port then
|
||||
if attached l_env.item (Openshift_port) as l_port then
|
||||
if l_port.is_integer then
|
||||
port_number := l_port.to_integer
|
||||
else
|
||||
@@ -77,7 +86,7 @@ feature {NONE} -- Implementation
|
||||
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="encoder_tests" uuid="C6F56AE3-8E9C-4568-85CA-CA5F1EF15DCE">
|
||||
<target name="encoder_tests">
|
||||
<root class="ANY" feature="default_create"/>
|
||||
<root class="TEST_BASE64" feature="default_create"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="error_tests" uuid="54F59BB2-AD49-42C7-ABAA-B60765F4F926">
|
||||
<target name="error_tests">
|
||||
<root class="ANY" feature="default_create"/>
|
||||
<root class="TEST_ERROR" feature="default_create"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
<library name="wsf_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/>
|
||||
<library name="notification_email" location="..\library\runtime\process\notification_email\notification_email-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<target name="all_windows" extends="all">
|
||||
<description>Compiling as Windows , on other platforms than Windows</description>
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
<library name="precomp_wsf" location="..\precomp\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf-scoop-safe" location="..\precomp\wsf-scoop-safe.ecf" readonly="false"/>
|
||||
<library name="wizard" location="..\tools\ise_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/>
|
||||
<library name="notification_email" location="..\library\runtime\process\notification_email\notification_email-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<target name="all_windows" extends="all">
|
||||
<description>Compiling as Windows , on other platforms than Windows</description>
|
||||
|
||||
@@ -87,6 +87,11 @@ echo Install library: openid
|
||||
echo Install library: uri_template
|
||||
%COPYCMD% %TMP_DIR%\library\text\parser\uri_template %TMP_CONTRIB_DIR%\library\text\parser\uri_template
|
||||
|
||||
echo Install library: notification_email
|
||||
%SAFE_MD% %TMP_CONTRIB_DIR%\library\runtime
|
||||
%SAFE_MD% %TMP_CONTRIB_DIR%\library\runtime\process
|
||||
%COPYCMD% %TMP_DIR%\library\runtime\process\notification_email %TMP_CONTRIB_DIR%\library\runtime\process\notification_email
|
||||
|
||||
echo Install contrib library: nino
|
||||
%COPYCMD% %TMP_DIR%\contrib\library\network\server\nino %TMP_CONTRIB_DIR%\library\network\server\nino
|
||||
rem remove fonts folder from nino examples
|
||||
|
||||
@@ -79,7 +79,9 @@ COPYCMD $TMP_DIR/library/security/openid $TMP_CONTRIB_DIR/library/security/openi
|
||||
echo Install library: uri_template
|
||||
mkdir -p $TMP_CONTRIB_DIR/library/text/parser
|
||||
COPYCMD $TMP_DIR/library/text/parser/uri_template $TMP_CONTRIB_DIR/library/text/parser/uri_template
|
||||
|
||||
echo Install library: notification_email
|
||||
mkdir -p $TMP_CONTRIB_DIR/library/runtime/process
|
||||
COPYCMD $TMP_DIR/library/runtime/process/notification_email $TMP_CONTRIB_DIR/library/runtime/process/notification_email
|
||||
echo Install contrib library: nino
|
||||
mkdir -p $TMP_CONTRIB_DIR/library/network/server
|
||||
COPYCMD $TMP_DIR/contrib/library/network/server/nino $TMP_CONTRIB_DIR/library/network/server/nino
|
||||
|
||||
@@ -60,6 +60,8 @@ echo Uninstall library: security\openid
|
||||
%RDCMD% %TMP_CONTRIB_DIR%\library\security\openid
|
||||
echo Uninstall library: uri_template
|
||||
%RDCMD% %TMP_CONTRIB_DIR%\library\text\parser\uri_template
|
||||
echo Uninstall library: runtime\process\notification_email
|
||||
%RDCMD% %TMP_CONTRIB_DIR%\library\runtime\process\notification_email
|
||||
|
||||
echo Uninstall contrib library: nino
|
||||
%RDCMD% %TMP_CONTRIB_DIR%\library\network\server\nino
|
||||
|
||||
Reference in New Issue
Block a user