First steps to provide a concurrent compliant EWF connector.

This commit is contained in:
2015-03-13 16:26:07 +01:00
parent f0a49aaf0a
commit 33ec1bc2d3
51 changed files with 4054 additions and 14 deletions

View File

@@ -0,0 +1,38 @@
note
description: "Summary description for {APP_COUNTER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APP_COUNTER
create
put
feature
item: INTEGER
put, replace (i: INTEGER)
do
item := i
end
next_item: INTEGER
do
Result := item + 1
item := Result
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,56 @@
note
description: "Summary description for {APP_WSF_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APP_WSF_EXECUTION
inherit
WSF_EXECUTION
create
make
feature -- Execution
execute
local
s: STRING
do
s := "Hello Concurrent EWF"
s.append (" (counter=")
s.append_integer (next_cell_counter_item (counter_cell))
s.append (")%N")
response.set_status_code (200)
response.put_header_line ("X-EWF-Dev: v1.0")
response.header.put_content_type_text_plain
response.header.put_content_length (s.count)
response.put_string (s)
end
next_cell_counter_item (cl: like counter_cell): INTEGER
do
Result := cl.next_item
end
counter_cell: separate APP_COUNTER
once ("PROCESS")
create Result.put (0)
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,36 @@
note
description: "Summary description for {APP_WSF_HTTPD_REQUEST_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APP_WSF_HTTPD_REQUEST_HANDLER
inherit
WSF_HTTPD_REQUEST_HANDLER
create
make
feature -- Execute
do_more (req: WGI_REQUEST; res: WGI_RESPONSE)
local
exec: WSF_EXECUTION
do
create {APP_WSF_EXECUTION} exec.make (req, res)
exec.execute
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,51 @@
note
description: "[
Objects that ...
]"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONNECTOR_DEV
create
make
feature {NONE} -- Initialization
make
-- Initialize `Current'.
local
server: HTTPD_SERVER
fac: separate WSF_HTTPD_REQUEST_HANDLER_FACTORY [APP_WSF_EXECUTION]
do
print ("Hello%N")
create fac
create server.make (fac)
server.configuration.set_http_server_port (9090)
server.launch
end
feature -- Status
feature -- Access
feature -- Change
feature {NONE} -- Implementation
invariant
-- invariant_clause: True
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,264 @@
note
description: "Summary description for {WSF_HTTPD_REQUEST_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
WSF_HTTPD_REQUEST_HANDLER [G -> WSF_EXECUTION create make end]
inherit
HTTPD_REQUEST_HANDLER
WGI_EXPORTER
REFACTORING_HELPER
create
make
feature -- Request processing
process_request (a_socket: HTTPD_STREAM_SOCKET)
-- Process request ...
local
l_input: WGI_INPUT_STREAM
l_output: WGI_OUTPUT_STREAM
l_error: WGI_ERROR_STREAM
req: WGI_REQUEST_FROM_TABLE
res: detachable WGI_HTTPD_RESPONSE_STREAM
exec: WSF_EXECUTION
retried: BOOLEAN
do
if not retried then
create {WGI_HTTPD_INPUT_STREAM} l_input.make (a_socket)
create {WGI_HTTPD_OUTPUT_STREAM} l_output.make (a_socket)
create {WGI_HTTPD_ERROR_STREAM} l_error.make_stderr (a_socket.descriptor.out)
create req.make (httpd_environment (a_socket), l_input, Void)
create res.make (l_output, l_error)
req.set_meta_string_variable ("RAW_HEADER_DATA", request_header)
exec := new_execution (req, res)
exec.execute
res.push
else
end
rescue
if not retried then
retried := True
retry
end
end
new_execution (req: WGI_REQUEST; res: WGI_RESPONSE): WSF_EXECUTION
do
create {G} Result.make (req, res)
end
base: detachable READABLE_STRING_8
do
--TODO
to_implement ("Base url support")
end
httpd_environment (a_socket: HTTPD_STREAM_SOCKET): STRING_TABLE [READABLE_STRING_8]
local
p: INTEGER
l_request_uri, l_script_name, l_query_string, l_path_info: STRING
l_server_name, l_server_port: detachable STRING
l_headers_map: HASH_TABLE [STRING, STRING]
vn: STRING
e: EXECUTION_ENVIRONMENT
enc: URL_ENCODER
utf: UTF_CONVERTER
do
l_request_uri := uri
l_headers_map := request_header_map
create e
create enc
if attached e.starting_environment as vars then
create Result.make_equal (vars.count)
across
vars as c
loop
Result.force (utf.utf_32_string_to_utf_8_string_8 (c.item), utf.utf_32_string_to_utf_8_string_8 (c.key))
end
else
create Result.make (0)
end
--| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `Result'
from
l_headers_map.start
until
l_headers_map.after
loop
create vn.make_from_string (l_headers_map.key_for_iteration.as_upper)
vn.replace_substring_all ("-", "_")
if
vn.starts_with ("CONTENT_") and then
(vn.same_string_general ({WGI_META_NAMES}.content_type) or vn.same_string_general ({WGI_META_NAMES}.content_length))
then
--| Keep this name
else
vn.prepend ("HTTP_")
end
add_environment_variable (l_headers_map.item_for_iteration, vn, Result)
l_headers_map.forth
end
--| Specific cases
p := l_request_uri.index_of ('?', 1)
if p > 0 then
l_script_name := l_request_uri.substring (1, p - 1)
l_query_string := l_request_uri.substring (p + 1, l_request_uri.count)
else
l_script_name := l_request_uri.string
l_query_string := ""
end
if attached l_headers_map.item ("Host") as l_host then
check has_host: Result.has ("HTTP_HOST") end
-- set_environment_variable (l_host, "HTTP_HOST", Result)
p := l_host.index_of (':', 1)
if p > 0 then
l_server_name := l_host.substring (1, p - 1)
l_server_port := l_host.substring (p+1, l_host.count)
else
l_server_name := l_host
l_server_port := "80" -- Default
end
else
check host_available: False end
end
if attached l_headers_map.item ("Authorization") as l_authorization then
check has_authorization: Result.has ("HTTP_AUTHORIZATION") end
-- set_environment_variable (l_authorization, "HTTP_AUTHORIZATION", Result)
p := l_authorization.index_of (' ', 1)
if p > 0 then
set_environment_variable (l_authorization.substring (1, p - 1), "AUTH_TYPE", Result)
end
end
set_environment_variable ("CGI/1.1", "GATEWAY_INTERFACE", Result)
set_environment_variable (l_query_string, "QUERY_STRING", Result)
if attached remote_info as l_remote_info then
set_environment_variable (l_remote_info.addr, "REMOTE_ADDR", Result)
set_environment_variable (l_remote_info.hostname, "REMOTE_HOST", Result)
set_environment_variable (l_remote_info.port.out, "REMOTE_PORT", Result)
-- set_environment_variable (Void, "REMOTE_IDENT", Result)
-- set_environment_variable (Void, "REMOTE_USER", Result)
end
set_environment_variable (l_request_uri, "REQUEST_URI", Result)
set_environment_variable (method, "REQUEST_METHOD", Result)
set_environment_variable (l_script_name, "SCRIPT_NAME", Result)
set_environment_variable (l_server_name, "SERVER_NAME", Result)
set_environment_variable (l_server_port, "SERVER_PORT", Result)
set_environment_variable (version, "SERVER_PROTOCOL", Result)
set_environment_variable ({HTTPD_CONFIGURATION}.Server_details, "SERVER_SOFTWARE", Result)
--| Apply `base' value
if attached base as l_base and then l_request_uri /= Void then
if l_request_uri.starts_with (l_base) then
l_path_info := l_request_uri.substring (l_base.count + 1, l_request_uri.count)
p := l_path_info.index_of ('?', 1)
if p > 0 then
l_path_info.keep_head (p - 1)
end
Result.force (l_base, "SCRIPT_NAME")
else
-- This should not happen, this means the `base' is not correctly set.
-- It is better to consider base as empty, rather than having empty PATH_INFO
check valid_base_value: False end
l_path_info := l_request_uri
p := l_request_uri.index_of ('?', 1)
if p > 0 then
l_path_info := l_request_uri.substring (1, p - 1)
else
l_path_info := l_request_uri.string
end
Result.force ("", "SCRIPT_NAME")
end
--| In order to have same path value for PATH_INFO on various connectors and servers
--| the multiple slashes must be stripped to single slash.
--| tested with: CGI+apache, libfcgi+apache on Windows and Linux
--|
--| For example: "////abc/def///end////" to "/abc/def/end/" ?
convert_multiple_slashes_to_single (l_path_info)
Result.force (enc.decoded_utf_8_string (l_path_info), "PATH_INFO")
end
end
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
if env.has_key (a_var_name) and then attached env.found_item as l_existing_value then
--| Check http://www.ietf.org/rfc/rfc3875 4.1.18
check find_proper_rewrite_for_same_header: False end
env.force (l_existing_value + " " + a_value, a_var_name)
else
env.force (a_value, a_var_name)
end
end
end
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
env.force (a_value, a_var_name)
end
end
feature {NONE} -- Implementation
convert_multiple_slashes_to_single (s: STRING_8)
-- Replace multiple slashes sequence by a single slash character.
local
i,n: INTEGER
do
from
i := 1
n := s.count
until
i > n
loop
if s[i] = '/' then
-- Remove following slashes '/'.
from
i := i + 1
until
i > n or s[i] /= '/'
loop
s.remove (i)
n := n - 1
end
else
i := i + 1
end
end
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,30 @@
note
description: "Summary description for {WSF_HTTPD_REQUEST_HANDLER_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
WSF_HTTPD_REQUEST_HANDLER_FACTORY [G -> WSF_EXECUTION create make end]
inherit
HTTPD_REQUEST_HANDLER_FACTORY
feature -- Factory
new_handler: separate WSF_HTTPD_REQUEST_HANDLER [G]
do
create Result.make
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="connector_httpd" uuid="49C99A6E-CCC1-4015-81F6-D7C43B592034" library_target="connector_httpd">
<target name="connector_httpd">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
</option>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
<library name="wsf" location="..\..\..\wsf\wsf-safe.ecf" readonly="false"/>
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
<condition>
<custom name="httpd_ssl_enabled" value="true"/>
</condition>
</library>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf">
<condition>
<concurrency excluded_value="none"/>
</condition>
</library>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<cluster name="httpd_server" location=".\src\httpd\" recursive="true">
<file_rule>
<exclude>/ssl$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/no_ssl$</exclude>
<exclude>/concurrency$</exclude>
</file_rule>
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
<condition>
<custom name="httpd_ssl_enabled" excluded_value="true"/>
</condition>
</cluster>
<cluster name="ssl" location="$|ssl\" recursive="true">
<condition>
<custom name="httpd_ssl_enabled" value="true"/>
</condition>
</cluster>
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
<condition>
<concurrency value="none"/>
</condition>
</cluster>
<cluster name="concurrency_thread" location="$|concurrency\thread\" recursive="true">
<condition>
<concurrency value="thread"/>
</condition>
</cluster>
<cluster name="concurrency_scoop" location="$|concurrency\scoop\" recursive="true">
<condition>
<concurrency value="scoop"/>
</condition>
</cluster>
</cluster>
<cluster name="src" location=".\src\" recursive="true">
<file_rule>
<exclude>/httpd$</exclude>
</file_rule>
</cluster>
</target>
<target name="dev" extends="connector_httpd">
<root class="HTTPD_CONNECTOR_DEV" feature="make"/>
<setting name="concurrency" value="scoop"/>
<cluster name="dev" location="dev\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,10 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Jocelyn Fiat, Javier Velilla, 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
]"

View File

@@ -0,0 +1,101 @@
note
description: "Summary description for {HTTPD_CONNECTION_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONNECTION_HANDLER
inherit
HTTPD_CONNECTION_HANDLER_I
create
make
feature {NONE} -- Initialization
initialize
do
end
feature -- Access
is_shutdown_requested: BOOLEAN
shutdown_requested (a_server: like server): BOOLEAN
do
-- FIXME: we should probably remove this possibility, check with EWF if this is needed.
Result := a_server.controller.shutdown_requested
end
feature -- Execution
process_incoming_connection (a_socket: HTTPD_STREAM_SOCKET)
-- Process incoming connection
-- note that the precondition matters for scoop synchronization.
do
is_shutdown_requested := is_shutdown_requested or shutdown_requested (server)
if is_shutdown_requested then
a_socket.cleanup
elseif attached server.factory.new_handler as h then
process_connection_handler (h, a_socket)
else
check is_not_full: False end
a_socket.cleanup
end
update_is_shutdown_requested
end
process_connection_handler (hdl: HTTPD_REQUEST_HANDLER; a_socket: HTTPD_STREAM_SOCKET)
require
not hdl.has_error
do
--| FIXME jfiat [2011/11/03] : should use a Pool of Threads/Handler to process this connection
--| also handle permanent connection...?
hdl.set_client_socket (a_socket)
if not hdl.has_error then
-- hdl.set_logger (server)
hdl.execute
else
log ("Internal error (set_client_socket failed)")
end
rescue
log ("Releasing handler after exception!")
hdl.release
a_socket.cleanup
end
update_is_shutdown_requested
do
is_shutdown_requested := shutdown_requested (server)
end
shutdown
do
if not is_shutdown_requested then
is_shutdown_requested := True
server.controller.shutdown
end
end
feature {HTTPD_SERVER_I} -- Status report
wait_for_completion
-- Wait until Current is ready for shutdown
do
-- no concurrency, then current task should be done.
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,30 @@
note
description : "Concurrent specific feature to implemente HTTPD_REQUEST_HANDLER"
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER
inherit
HTTPD_REQUEST_HANDLER_I
feature -- Change
set_client_socket (a_socket: HTTPD_STREAM_SOCKET)
do
client_socket := a_socket
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,16 @@
note
description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER_FACTORY
inherit
HTTPD_REQUEST_HANDLER_FACTORY_I
note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,160 @@
note
description: "Summary description for {HTTPD_CONNECTION_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONNECTION_HANDLER
inherit
HTTPD_CONNECTION_HANDLER_I
redefine
initialize
end
create
make
feature {NONE} -- Initialization
initialize
local
n: INTEGER
p: like pool
do
n := max_concurrent_connections (server)
create p.make (n)
initialize_pool (p, n)
pool := p
end
initialize_pool (p: like pool; n: INTEGER)
do
p.set_count (n)
end
feature -- Access
is_shutdown_requested: BOOLEAN
max_concurrent_connections (a_server: like server): INTEGER
do
Result := a_server.configuration.max_concurrent_connections
end
feature {HTTPD_SERVER_I} -- Execution
shutdown
do
if not is_shutdown_requested then
is_shutdown_requested := True
pool_gracefull_stop (pool)
end
end
pool_gracefull_stop (p: like pool)
do
p.gracefull_stop
end
process_incoming_connection (a_socket: HTTPD_STREAM_SOCKET)
-- <Precursor>
do
debug ("dbglog")
dbglog (generator + ".before process_incoming_connection {"+ a_socket.descriptor.out +"} -- SCOOP WAIT!")
end
-- if is_shutdown_requested then
-- a_socket.cleanup
-- else
process_connection_on_pool (a_socket, pool) -- Wait on not pool.is_full or is_stop_requested
-- end
debug ("dbglog")
dbglog (generator + ".after process_incoming_connection {"+ a_socket.descriptor.out +"}")
end
end
process_connection_on_pool (a_socket: HTTPD_STREAM_SOCKET; a_pool: like pool)
-- Process incoming connection
-- note that the precondition matters for scoop synchronization.
require
concurrency: not a_pool.is_full or is_shutdown_requested or a_pool.stop_requested
do
debug ("dbglog")
dbglog (generator + ".ENTER process_connection {"+ a_socket.descriptor.out +"}")
end
if is_shutdown_requested then
a_socket.cleanup
elseif attached a_pool.separate_item (factory) as h then
process_request_handler (h, a_socket)
else
check is_not_full: False end
a_socket.cleanup
end
debug ("dbglog")
dbglog (generator + ".LEAVE process_connection {"+ a_socket.descriptor.out +"}")
end
end
process_request_handler (hdl: separate HTTPD_REQUEST_HANDLER; a_socket: HTTPD_STREAM_SOCKET)
require
not hdl.has_error
do
--| FIXME jfiat [2011/11/03] : should use a Pool of Threads/Handler to process this connection
--| also handle permanent connection...?
debug ("dbglog")
dbglog (generator + ".ENTER process_request_handler {"+ a_socket.descriptor.out +"}")
end
hdl.set_client_socket (a_socket)
if hdl.has_error then
log ("Internal error (set_client_socket failed)")
else
-- hdl.set_logger (server)
if attached hdl.separate_execution as l_result then
end
hdl.separate_release
end
debug ("dbglog")
dbglog (generator + ".LEAVE process_request_handler {"+ a_socket.descriptor.out +"}")
end
rescue
log ("Releasing handler after exception!")
hdl.separate_release
-- a_socket.cleanup
end
feature {HTTPD_SERVER_I} -- Status report
wait_for_completion
-- Wait until Current is ready for shutdown
do
wait_for_pool_completion (pool)
end
wait_for_pool_completion (p: like pool)
require
p.is_empty
do
p.terminate
end
feature {NONE} -- Access
pool: separate CONCURRENT_POOL [HTTPD_REQUEST_HANDLER]
-- Pool of separate connection handlers.
invariant
pool_attached: pool /= Void
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,111 @@
note
description: "[
Instance of HTTPD_REQUEST_HANDLER will process the incoming connection
and extract information on the request and the server
]"
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER
inherit
HTTPD_REQUEST_HANDLER_I
redefine
-- set_client_socket,
release,
reset
end
CONCURRENT_POOL_ITEM
rename
release as release_pool_item
end
feature {NONE} -- Initialization
reset
do
if attached client_socket_source as l_sock then
cleanup_separate_socket (l_sock)
end
Precursor
client_socket_source := Void
end
cleanup_separate_socket (a_socket: attached like client_socket_source)
do
a_socket.cleanup
end
feature -- Access
client_socket: detachable HTTPD_STREAM_SOCKET
client_socket_source: detachable separate HTTPD_STREAM_SOCKET
-- Associated original client socket
-- kept to avoid being closed when disposed,
-- and thus avoid closing related `client_socket'.
feature -- Change
set_client_socket (a_socket: separate HTTPD_STREAM_SOCKET)
local
retried: BOOLEAN
do
if retried then
has_error := True
else
create client_socket.make_from_separate (a_socket)
client_socket_source := a_socket
end
rescue
retried := True
retry
end
feature -- Execution
separate_execution: BOOLEAN
do
if attached client_socket as s then
execute (s)
end
Result := True
end
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
separate_release
do
if attached client_socket as s then
release (s)
end
end
release (a_socket: HTTPD_STREAM_SOCKET)
local
d: STRING
do
d := a_socket.descriptor.out
debug ("dbglog")
dbglog (generator + ".release: ENTER {" + d + "}")
end
Precursor {HTTPD_REQUEST_HANDLER_I} (a_socket)
release_pool_item
debug ("dbglog")
dbglog (generator + ".release: LEAVE {" + d + "}")
end
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,21 @@
note
description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER_FACTORY
inherit
HTTPD_REQUEST_HANDLER_FACTORY_I
CONCURRENT_POOL_FACTORY [HTTPD_REQUEST_HANDLER]
rename
new_separate_item as new_handler
end
note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,181 @@
note
description: "Summary description for {CONCURRENT_POOL}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CONCURRENT_POOL [G -> CONCURRENT_POOL_ITEM]
inherit
HTTPD_DEBUG_FACILITIES
create
make
feature {NONE} -- Initialization
make (n: INTEGER)
do
capacity := n
create items.make_empty (n)
-- create busy_items.make_filled (False, n)
create busy_items.make_empty (n)
end
feature -- Access
count: INTEGER
is_full: BOOLEAN
do
Result := count >= capacity
end
is_empty: BOOLEAN
do
Result := count = 0
end
capacity: INTEGER
stop_requested: BOOLEAN
feature -- Access
separate_item (a_factory: separate CONCURRENT_POOL_FACTORY [G]): detachable separate G
require
is_not_full: not is_full
local
i,n,pos: INTEGER
lst: like busy_items
l_item: detachable separate G
do
if not stop_requested then
from
lst := busy_items
pos := -1
i := 0
n := lst.count - 1
until
i > n or l_item /= Void or pos >= 0
loop
if not lst [i] then -- is free (i.e not busy)
pos := i
if items.valid_index (pos) then
l_item := items [pos]
if l_item /= Void then
busy_items [pos] := True
end
end
if l_item = Void then
-- Empty, then let's create one.
l_item := a_factory.new_separate_item
register_item (l_item)
items [pos] := l_item
end
end
i := i + 1
end
if l_item = Void then
-- Pool is FULL ...
check overcapacity: False end
else
debug ("pool", "dbglog")
dbglog ("Lock pool item #" + pos.out + " (free:"+ (capacity - count).out +"))")
end
count := count + 1
busy_items [pos] := True
Result := l_item
end
end
end
feature -- Basic operation
gracefull_stop
do
stop_requested := True
end
feature {NONE} -- Internal
items: SPECIAL [detachable separate G]
busy_items: SPECIAL [BOOLEAN]
feature {CONCURRENT_POOL_ITEM} -- Change
release_item (a_item: separate G)
-- Unregister `a_item' from Current pool.
require
count > 0
local
i,n,pos: INTEGER
lst: like items
do
-- release handler for reuse
from
lst := items
i := 0
n := lst.count - 1
until
i > n or lst [i] = a_item
loop
i := i + 1
end
if i <= n then
pos := i
busy_items [pos] := False
count := count - 1
--reuse items [pos] := Void
debug ("pool", "dbglog")
dbglog ("Released pool item #" + i.out + " (free:"+ (capacity - count).out +"))")
end
else
check known_item: False end
end
end
feature -- Change
set_count (n: INTEGER)
local
g: detachable separate G
do
capacity := n
items.fill_with (g, 0, n - 1)
busy_items.fill_with (False, 0, n - 1)
end
terminate
local
l_items: like items
do
l_items := items
l_items.wipe_out
end
feature {NONE} -- Implementation
-- new_separate_item: separate G
-- deferred
-- end
register_item (a_item: separate G)
do
a_item.set_pool (Current)
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,19 @@
note
description: "Summary description for {CONCURRENT_POOL_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
CONCURRENT_POOL_FACTORY [G -> CONCURRENT_POOL_ITEM]
feature -- Access
new_separate_item: separate G
deferred
end
note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,47 @@
note
description: "Summary description for {CONCURRENT_POOL_ITEM}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
CONCURRENT_POOL_ITEM
feature {NONE} -- Access
pool: detachable separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM]
feature {CONCURRENT_POOL} -- Change
set_pool (p: like pool)
do
pool := p
end
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
release
do
if attached pool as p then
pool_release (p)
end
end
feature {NONE} -- Implementation
pool_release (p: separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM])
do
p.release_item (Current)
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,111 @@
note
description: "Summary description for {HTTPD_CONNECTION_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONNECTION_HANDLER
inherit
HTTPD_CONNECTION_HANDLER_I
redefine
initialize
end
create
make
feature {NONE} -- Initialization
initialize
local
n: INTEGER
do
n := max_concurrent_connections (server)
create pool.make (n.to_natural_32)
end
feature -- Access
is_shutdown_requested: BOOLEAN
max_concurrent_connections (a_server: like server): INTEGER
do
Result := a_server.configuration.max_concurrent_connections
end
feature {HTTPD_SERVER_I} -- Execution
shutdown
do
if not is_shutdown_requested then
is_shutdown_requested := True
pool_gracefull_stop (pool)
end
end
pool_gracefull_stop (p: like pool)
do
p.terminate
end
process_incoming_connection (a_socket: HTTPD_STREAM_SOCKET)
do
if is_shutdown_requested then
a_socket.cleanup
else
process_connection_handler (factory.new_handler, a_socket)
end
end
process_connection_handler (hdl: separate HTTPD_REQUEST_HANDLER; a_socket: HTTPD_STREAM_SOCKET)
require
not hdl.has_error
do
debug ("dbglog")
dbglog (generator + ".ENTER process_connection_handler {"+ a_socket.descriptor.out +"}")
end
if not hdl.has_error then
-- hdl.set_logger (server)
-- hdl.set_client_socket (a_socket)
pool.add_work (agent hdl.execute (a_socket))
else
log ("Internal error (set_client_socket failed)")
end
debug ("dbglog")
dbglog (generator + ".LEAVE process_connection_handler {"+ a_socket.descriptor.out +"}")
end
rescue
log ("Releasing handler after exception!")
hdl.release (a_socket)
-- hdl.client_socket.cleanup
end
feature {HTTPD_SERVER_I} -- Status report
wait_for_completion
-- Wait until Current is ready for shutdown
do
pool.wait_for_completion
end
feature {NONE} -- Access
pool: THREAD_POOL [HTTPD_REQUEST_HANDLER] --ANY] --POOLED_THREAD [HTTP_REQUEST_HANDLER]]
-- Pool of concurrent connection handlers.
invariant
pool_attached: pool /= Void
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,45 @@
note
description: "[
Instance of HTTPD_REQUEST_HANDLER will process the incoming connection
and extract information on the request and the server
]"
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER
inherit
HTTPD_REQUEST_HANDLER_I
redefine
release
end
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
release (a_socket: HTTPD_STREAM_SOCKET)
local
d: STRING
do
-- FIXME: for log purpose
d := a_socket.descriptor.out
debug ("dbglog")
dbglog (generator + ".release: ENTER {" + d + "}")
end
Precursor {HTTPD_REQUEST_HANDLER_I} (a_socket)
debug ("dbglog")
dbglog (generator + ".release: LEAVE {" + d + "}")
end
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,16 @@
note
description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER_FACTORY
inherit
HTTPD_REQUEST_HANDLER_FACTORY_I
note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,121 @@
note
description: "{POOLED_THREAD} is used in combination with {THREAD_POOL} to allow for pooled threads."
legal: "See notice at end of class."
status: "Community Preview 1.0"
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
revision: "$Revision: 80577 $"
class
POOLED_THREAD [G]
inherit
THREAD
rename
make as thread_make
end
create {THREAD_POOL}
make
feature {NONE} -- Initialization
make (a_thread_pool: THREAD_POOL [G]; a_semaphore: SEMAPHORE)
-- `a_thread_pool', the pool in which this thread is managed
-- `a_semaphore' is used for execution suspending
do
thread_make
thread_pool := a_thread_pool
semaphore := a_semaphore
end
feature {NONE} -- Access
thread_pool: THREAD_POOL [G]
-- Pool manager in which this thread is pooled
target: detachable G
-- Target on which the `thread_procedure' should be applied
-- Depending on which launch is used, target is not used
thread_procedure: detachable PROCEDURE [G, TUPLE]
-- Work that should be executed by the thread
semaphore: SEMAPHORE
-- Semaphore share with all threads in a thread pool
-- to suspend execution until more work is available
feature -- Access
set_target (a_target: G)
-- Sets the target on which the work should be executed
do
target := a_target
end
feature {NONE} -- Implementation
execute
-- <Precursor>
local
done: BOOLEAN
do
from
semaphore.wait
thread_procedure := thread_pool.get_work (Current)
until
done
loop
if attached thread_procedure as l_work then
if attached target as t then
l_work.call ([t])
else
l_work.call (Void)
end
end
if thread_pool.over then
done := True
else
thread_procedure := thread_pool.get_work (Current)
if thread_procedure = Void then
semaphore.wait
thread_procedure := thread_pool.get_work (Current)
end
end
end
thread_pool.thread_terminated (Current)
end
note
copyright: "2011-2012, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
licensing_options: "http://www.eiffel.com/licensing"
copying: "[
This file is part of Eiffel Software's Eiffel Development Environment.
Eiffel Software's Eiffel Development Environment is free
software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published
by the Free Software Foundation, version 2 of the License
(available at the URL listed under "license" above).
Eiffel Software's Eiffel Development Environment is
distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with Eiffel Software's Eiffel Development
Environment; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
]"
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

View File

@@ -0,0 +1,228 @@
note
description: "[
A thread pool manager. Manages threads up to `capacity' and queue after that,
till threads get available again.
]"
legal: "See notice at end of class."
status: "Community Preview 1.0"
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
revision: "$Revision: 80577 $"
class
THREAD_POOL [G]
inherit
EXECUTION_ENVIRONMENT
create
make
feature {NONE} -- Initialization
make (n: like capacity)
-- Initialize current pool with capacity `n'.
require
n_positive: n > 0
n_not_too_large: n < {INTEGER_32}.max_value.as_natural_32
local
i: NATURAL
do
capacity := n
create work_queue.make (n.to_integer_32)
create work_queue_mutex.make
create over_mutex.make
create termination_mutex.make
create work_semaphore.make (capacity.as_integer_32)
from
i := 1
until
i > capacity
loop
work_semaphore.wait
i := i + 1
end
initialize_threads
terminated_count := capacity
is_over := False
ensure
capacity_set: capacity = n
work_queue_set: work_queue.is_empty
end
initialize_threads
-- Launches all threads
local
i: NATURAL
thread: POOLED_THREAD [G]
do
from
i := 1
until
i > capacity
loop
create thread.make (Current, work_semaphore)
thread.launch
i := i + 1
end
end
feature -- Access
capacity: NATURAL
-- Maximal number of threads allowed (queuing otherwise)
queue_count: NATURAL
-- Number of items in queue
do
work_queue_mutex.lock
Result := work_queue.count.as_natural_32
work_queue_mutex.unlock
end
feature -- Status report
valid_action (a_action: PROCEDURE [G, TUPLE]): BOOLEAN
-- Is `a_action' a valid action for the current pool.
do
-- There should be no open operands.
Result := a_action.valid_operands (Void)
end
feature -- Basic operations
add_work (work: PROCEDURE [G, TUPLE])
-- Launches a thread with the specified argument `arg'. Reuse of thread if possible.
require
valid_action: valid_action (work)
do
work_queue_mutex.lock
work_queue.extend (work)
if work_queue.count <= capacity.as_integer_32 then
-- Let one thread wake up and do the work
work_semaphore.post
end
work_queue_mutex.unlock
end
over: BOOLEAN
-- Is the thread pool being terminated?
do
over_mutex.lock
Result := is_over
over_mutex.unlock
end
thread_terminated (a_thread: POOLED_THREAD [G])
-- Notifies the thread pool that a thread has terminated its execution.
do
termination_mutex.lock
terminated_count := terminated_count - 1
termination_mutex.unlock
end
get_work (requester: POOLED_THREAD [G]): detachable PROCEDURE [G, TUPLE]
-- If there is work to do, it is returned
-- Yields Void otherwise
do
if not over then
work_queue_mutex.lock
if not work_queue.is_empty then
Result := work_queue.item
work_queue.remove
end
work_queue_mutex.unlock
end
end
wait_for_completion
-- Wait until there is no more work to be completed
local
done: BOOLEAN
do
from
until
done
loop
work_queue_mutex.lock
done := work_queue.is_empty
work_queue_mutex.unlock
if not done then
sleep (1)
end
end
end
terminate
-- Terminates all the threads after their execution
do
over_mutex.lock
is_over := True
over_mutex.unlock
from
termination_mutex.lock
until
terminated_count = 0
loop
work_semaphore.post
termination_mutex.unlock
termination_mutex.lock
end
termination_mutex.unlock
end
feature {NONE} -- Implementation: Access
work_queue: ARRAYED_QUEUE [PROCEDURE [G, TUPLE]]
-- Queue that holds unprocessed requests as agents
-- Thread-safe access when accessor holds `queue_mutex'
work_queue_mutex: MUTEX
-- Mutex for the queue
work_semaphore: SEMAPHORE
-- Semaphore which hols the number of work to be done.
-- Needed to wake up worker threads
terminated_count: NATURAL
--
is_over: BOOLEAN
-- Is the thread pool being terminated?
over_mutex: MUTEX
-- Mutex for the `is_over' variable
termination_mutex: MUTEX
;note
copyright: "2011-2012, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
licensing_options: "http://www.eiffel.com/licensing"
copying: "[
This file is part of Eiffel Software's Eiffel Development Environment.
Eiffel Software's Eiffel Development Environment is free
software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published
by the Free Software Foundation, version 2 of the License
(available at the URL listed under "license" above).
Eiffel Software's Eiffel Development Environment is
distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with Eiffel Software's Eiffel Development
Environment; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
]"
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

View File

@@ -0,0 +1,209 @@
note
description: "Summary description for {HTTPD_CONFIGURATION_I}."
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_CONFIGURATION_I
feature {NONE} -- Initialization
make
do
http_server_port := 80
max_concurrent_connections := 100
max_tcp_clients := 100
socket_accept_timeout := 1_000
socket_connect_timeout := 5_000
keep_alive_timeout := 5
is_secure := False
create ca_crt.make_empty
create ca_key.make_empty
end
feature -- Access
Server_details: STRING_8
deferred
end
http_server_name: detachable READABLE_STRING_8 assign set_http_server_name
http_server_port: INTEGER assign set_http_server_port
max_tcp_clients: INTEGER assign set_max_tcp_clients
max_concurrent_connections: INTEGER assign set_max_concurrent_connections
socket_accept_timeout: INTEGER assign set_socket_accept_timeout
socket_connect_timeout: INTEGER assign set_socket_connect_timeout
force_single_threaded: BOOLEAN assign set_force_single_threaded
do
Result := (max_concurrent_connections = 0)
end
is_verbose: BOOLEAN assign set_is_verbose
-- Display verbose message to the output?
keep_alive_timeout: INTEGER assign set_keep_alive_timeout
-- Persistent connection timeout
-- Timeout unit in Seconds.
has_ssl_support: BOOLEAN
-- Has SSL support?
deferred
end
feature -- Access: SSL
is_secure: BOOLEAN
-- Is SSL/TLS session?.
ca_crt: STRING
ca_key: STRING
ssl_protocol: NATURAL
-- By default protocol is tls 1.2.
feature -- Element change
set_http_server_name (v: detachable separate READABLE_STRING_8)
do
if v = Void then
unset_http_server_name
-- http_server_name := Void
else
create {IMMUTABLE_STRING_8} http_server_name.make_from_separate (v)
end
end
unset_http_server_name
do
http_server_name := Void
end
set_http_server_port (v: like http_server_port)
do
http_server_port := v
end
set_max_tcp_clients (v: like max_tcp_clients)
do
max_tcp_clients := v
end
set_max_concurrent_connections (v: like max_concurrent_connections)
do
max_concurrent_connections := v
end
set_socket_accept_timeout (v: like socket_accept_timeout)
do
socket_accept_timeout := v
end
set_socket_connect_timeout (v: like socket_connect_timeout)
do
socket_connect_timeout := v
end
set_force_single_threaded (v: like force_single_threaded)
do
if v then
set_max_concurrent_connections (0)
end
end
set_is_verbose (b: BOOLEAN)
-- Set `is_verbose' to `b'
do
is_verbose := b
end
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
-- Set `keep_alive_timeout' with `a_seconds'
do
keep_alive_timeout := a_seconds
ensure
keep_alive_timeout_set: keep_alive_timeout = a_seconds
end
mark_secure
-- Set is_secure in True
do
if has_ssl_support then
is_secure := True
if http_server_port = 80 then
set_http_server_port (443)
end
else
is_secure := False
end
end
feature -- Element change
set_ca_crt (a_value: STRING)
-- Set `ca_crt' with `a_value'
do
ca_crt := a_value
ensure
ca_crt_set: ca_crt = a_value
end
set_ca_key (a_value: STRING)
-- Set `ca_key' with `a_value'
do
ca_key := a_value
ensure
ca_key_set: ca_key = a_value
end
set_ssl_protocol (a_version: NATURAL)
-- Set `ssl_protocol' with `a_version'
do
ssl_protocol := a_version
ensure
ssl_protocol_set: ssl_protocol = a_version
end
feature -- SSL Helpers
set_ssl_protocol_to_ssl_2_or_3
-- Set `ssl_protocol' with `Ssl_23'.
deferred
end
set_ssl_protocol_to_ssl_3
-- Set `ssl_protocol' with `Ssl_3'.
deferred
end
set_ssl_protocol_to_tls_1_0
-- Set `ssl_protocol' with `Tls_1_0'.
deferred
end
set_ssl_protocol_to_tls_1_1
-- Set `ssl_protocol' with `Tls_1_1'.
deferred
end
set_ssl_protocol_to_tls_1_2
-- Set `ssl_protocol' with `Tls_1_2'.
deferred
end
set_ssl_protocol_to_dtls_1_0
-- Set `ssl_protocol' with `Dtls_1_0'.
deferred
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="httpd" uuid="50FE258D-CC94-4748-9223-55F1129E5FB3" library_target="httpd">
<target name="httpd">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="standard">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
<condition>
<custom name="httpd_ssl_disabled" excluded_value="true"/>
</condition>
</library>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf">
<condition>
<concurrency excluded_value="none"/>
</condition>
</library>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<cluster name="httpd_server" location=".\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/concurrency$</exclude>
<exclude>/ssl$</exclude>
<exclude>/no_ssl$</exclude>
</file_rule>
<cluster name="no_ssl" location="$|no_ssl" recursive="true">
<condition>
<custom name="httpd_ssl_disabled" value="true"/>
</condition>
</cluster>
<cluster name="ssl" location="$|ssl" recursive="true">
<condition>
<custom name="httpd_ssl_disabled" excluded_value="true"/>
</condition>
</cluster>
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
<condition>
<concurrency value="none"/>
</condition>
</cluster>
<cluster name="concurrency_scoop" location="$|concurrency\scoop\" recursive="true">
<condition>
<concurrency value="scoop"/>
</condition>
</cluster>
<cluster name="concurrency_thread" location="$|concurrency\thread\" recursive="true">
<condition>
<concurrency value="thread"/>
</condition>
</cluster>
</cluster>
</target>
</system>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="httpd" uuid="50FE258D-CC94-4748-9223-55F1129E5FB3" library_target="httpd">
<target name="httpd">
<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>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
<condition>
<custom name="httpd_ssl_disabled" excluded_value="true"/>
</condition>
</library>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread.ecf">
<condition>
<concurrency excluded_value="none"/>
</condition>
</library>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<cluster name="httpd_server" location=".\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/concurrency$</exclude>
<exclude>/ssl$</exclude>
<exclude>/no_ssl$</exclude>
</file_rule>
<cluster name="no_ssl" location="$|no_ssl" recursive="true">
<condition>
<custom name="httpd_ssl_disabled" value="true"/>
</condition>
</cluster>
<cluster name="ssl" location="$|ssl" recursive="true">
<condition>
<custom name="httpd_ssl_disabled" excluded_value="true"/>
</condition>
</cluster>
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
<condition>
<concurrency value="none"/>
</condition>
</cluster>
<cluster name="concurrency_scoop" location="$|concurrency\scoop\" recursive="true">
<condition>
<concurrency value="scoop"/>
</condition>
</cluster>
<cluster name="concurrency_thread" location="$|concurrency\thread\" recursive="true">
<condition>
<concurrency value="thread"/>
</condition>
</cluster>
</cluster>
</target>
</system>

View File

@@ -0,0 +1,84 @@
note
description: "Summary description for {HTTPD_CONNECTION_HANDLER_I}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_CONNECTION_HANDLER_I
inherit
HTTPD_DEBUG_FACILITIES
feature {NONE} -- Initialization
frozen make (a_server: like server)
do
server := a_server
factory := separate_factory (a_server)
initialize
end
initialize
deferred
end
separate_factory (a_server: like server): like factory
-- Separate factory from `a_server'.
--| required by SCOOP design.
do
Result := a_server.factory
end
feature {NONE} -- Access
factory: separate HTTPD_REQUEST_HANDLER_FACTORY
server: separate HTTPD_SERVER_I
feature {HTTPD_SERVER_I} -- Execution
process_incoming_connection (a_socket: HTTPD_STREAM_SOCKET)
deferred
end
shutdown
deferred
end
wait_for_completion
-- Wait until Current completed any pending task
deferred
end
feature {HTTPD_SERVER} -- Status report
is_shutdown_requested: BOOLEAN
deferred
end
feature {NONE} -- Output
log (a_message: separate READABLE_STRING_8)
-- Log `a_message'
do
-- FIXME: Concurrency issue on `server'
separate_server_log (server, a_message)
end
separate_server_log (a_server: like server; a_message: separate READABLE_STRING_8)
do
a_server.log (a_message)
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,22 @@
note
description: "Summary description for {HTTPD_CONTROLLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONTROLLER
feature -- Operation
shutdown
do
shutdown_requested := True
end
shutdown_requested: BOOLEAN
;note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,40 @@
note
description: "Summary description for {HTTPD_DEBUG_FACILITIES}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_DEBUG_FACILITIES
feature {NONE} -- Output
dbglog (m: READABLE_STRING_8)
require
not m.ends_with_general ("%N")
do
debug ("dbglog")
print ("[EWF/DBG] <#" + processor_id_from_object (Current).out + "> " + m + "%N")
end
end
feature -- runtime
frozen processor_id_from_object (a_object: separate ANY): INTEGER_32
external
"C inline use %"eif_scoop.h%""
alias
"RTS_PID(eif_access($a_object))"
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,27 @@
note
description: "Summary description for {HTTPD_LOGGER}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_LOGGER
feature -- Logs
log (a_message: separate READABLE_STRING_8)
-- Log `a_message'
deferred
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,26 @@
note
description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY_I}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER_FACTORY_I
feature -- Factory
new_handler: separate HTTPD_REQUEST_HANDLER
deferred
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,278 @@
note
description: "Summary description for {HTTPD_REQUEST_HANDLER_I}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER_I
inherit
HTTPD_DEBUG_FACILITIES
feature {NONE} -- Initialization
make
do
reset
end
reset
do
has_error := False
version := Void
remote_info := Void
-- if attached client_socket as l_sock then
-- l_sock.cleanup
-- end
-- client_socket := Void
-- FIXME: optimize to just wipe_out if needed
create method.make_empty
create uri.make_empty
create request_header.make_empty
create request_header_map.make (10)
end
feature -- Access
-- client_socket: detachable TCP_STREAM_SOCKET
request_header: STRING
-- Header' source
request_header_map: HASH_TABLE [STRING, STRING]
-- Contains key:value of the header
method: STRING
-- http verb
uri: STRING
-- http endpoint
version: detachable STRING
-- http_version
--| unused for now
remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER]
-- Information related to remote client
feature -- Settings
is_verbose: BOOLEAN
feature -- Status report
has_error: BOOLEAN
-- Error occurred during `analyze_request_message'
feature -- Change
-- set_client_socket (a_socket: separate TCP_STREAM_SOCKET)
-- require
-- socket_attached: a_socket /= Void
-- socket_valid: a_socket.is_open_read and then a_socket.is_open_write
-- a_http_socket: not a_socket.is_closed
-- deferred
-- ensure
-- attached client_socket as s implies s.descriptor = a_socket.descriptor
-- end
set_is_verbose (b: BOOLEAN)
do
is_verbose := b
end
feature -- Execution
execute (a_socket: HTTPD_STREAM_SOCKET)
require
socket_attached: a_socket /= Void
socket_valid: a_socket.is_open_read and then a_socket.is_open_write
a_http_socket: not a_socket.is_closed
local
l_remote_info: detachable like remote_info
l_continue: BOOLEAN
do
if a_socket.is_closed then
debug ("dbglog")
dbglog (generator + ".execute {socket is Closed!}")
end
else
debug ("dbglog")
dbglog (generator + ".ENTER execute {" + a_socket.descriptor.out + "}")
end
from until l_continue loop
if a_socket.ready_for_reading then
l_continue := True
create l_remote_info
if attached a_socket.peer_address as l_addr then
l_remote_info.addr := l_addr.host_address.host_address
l_remote_info.hostname := l_addr.host_address.host_name
l_remote_info.port := l_addr.port
remote_info := l_remote_info
end
analyze_request_message (a_socket)
else
log (generator + ".WAITING execute {" + a_socket.descriptor.out + "}")
end
end
if has_error then
-- check catch_bad_incoming_connection: False end
if is_verbose then
-- check invalid_incoming_request: False end
log ("ERROR: invalid HTTP incoming request")
end
else
process_request (a_socket)
end
debug ("dbglog")
dbglog (generator + ".LEAVE execute {" + a_socket.descriptor.out + "}")
end
end
-- release (a_socket)
end
release (a_socket: HTTPD_STREAM_SOCKET)
do
a_socket.cleanup
reset
end
feature -- Request processing
process_request (a_socket: HTTPD_STREAM_SOCKET)
-- Process request ...
require
no_error: not has_error
a_uri_attached: uri /= Void
a_method_attached: method /= Void
a_header_map_attached: request_header_map /= Void
a_header_text_attached: request_header /= Void
a_socket_attached: a_socket /= Void
deferred
end
feature -- Parsing
analyze_request_message (a_socket: HTTPD_STREAM_SOCKET)
-- Analyze message extracted from `a_socket' as HTTP request
require
input_readable: a_socket /= Void and then a_socket.is_open_read
local
end_of_stream: BOOLEAN
pos, n: INTEGER
line: detachable STRING
k, val: STRING
txt: STRING
l_is_verbose: BOOLEAN
do
create txt.make (64)
request_header := txt
if a_socket.is_readable and then attached next_line (a_socket) as l_request_line and then not l_request_line.is_empty then
txt.append (l_request_line)
txt.append_character ('%N')
analyze_request_line (l_request_line)
else
has_error := True
end
l_is_verbose := is_verbose
if not has_error or l_is_verbose then
-- if `is_verbose' we can try to print the request, even if it is a bad HTTP request
from
line := next_line (a_socket)
until
line = Void or end_of_stream
loop
n := line.count
if l_is_verbose then
log (line)
end
pos := line.index_of (':', 1)
if pos > 0 then
k := line.substring (1, pos - 1)
if line [pos + 1].is_space then
pos := pos + 1
end
if line [n] = '%R' then
n := n - 1
end
val := line.substring (pos + 1, n)
request_header_map.put (val, k)
end
txt.append (line)
txt.append_character ('%N')
if line.is_empty or else line [1] = '%R' then
end_of_stream := True
else
line := next_line (a_socket)
end
end
end
end
analyze_request_line (line: STRING)
-- Analyze `line' as a HTTP request line
require
valid_line: line /= Void and then not line.is_empty
local
pos, next_pos: INTEGER
do
if is_verbose then
log ("%N## Parse HTTP request line ##")
log (line)
end
pos := line.index_of (' ', 1)
method := line.substring (1, pos - 1)
next_pos := line.index_of (' ', pos + 1)
uri := line.substring (pos + 1, next_pos - 1)
version := line.substring (next_pos + 1, line.count)
has_error := method.is_empty
end
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
-- Next line fetched from `a_socket' is available.
require
is_readable: a_socket.is_open_read
do
if a_socket.socket_ok then
a_socket.read_line_thread_aware
Result := a_socket.last_string
end
end
feature -- Output
logger: detachable HTTPD_LOGGER
set_logger (a_logger: like logger)
do
logger := a_logger
end
log (m: STRING)
do
if attached logger as l_logger then
l_logger.log (m)
else
io.put_string (m + "%N")
end
end
invariant
request_header_attached: request_header /= Void
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,316 @@
note
description: "Summary description for {HTTPD_SERVER_I}."
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_SERVER_I
inherit
HTTPD_DEBUG_FACILITIES
HTTPD_LOGGER
feature {NONE} -- Initialization
make (a_factory: like factory)
-- `a_cfg': server configuration
-- `a_factory': connection handler builder
do
make_configured (create {like configuration}.make, a_factory)
end
make_configured (a_cfg: like configuration; a_factory: like factory)
-- `a_cfg': server configuration
-- `a_factory': connection handler builder
do
configuration := a_cfg
factory := a_factory
build_controller
initialize
end
build_controller
-- Build `controller'.
do
create controller
end
initialize
-- Initialize Current server.
do
is_shutdown_requested := False
end
feature -- Access
is_verbose: BOOLEAN
-- Is verbose for output messages.
configuration: HTTPD_CONFIGURATION
-- Associated server configuration.
controller: separate HTTPD_CONTROLLER
factory: separate HTTPD_REQUEST_HANDLER_FACTORY
feature -- Access: listening
port: INTEGER
-- Effective listening port.
--| If 0 then it is not launched successfully!
feature -- Status: listening
is_launched: BOOLEAN
-- Server launched and listening on `port'
is_terminated: BOOLEAN
-- Is terminated?
is_shutdown_requested: BOOLEAN
-- Set true to stop accept loop
feature {NONE} -- Access: server
request_counter: INTEGER
-- request counter, incremented for each new incoming connection.
feature -- Execution
launch
do
apply_configuration
is_terminated := False
if is_verbose then
log ("%N%NStarting Web Application Server (port=" + configuration.http_server_port.out + "):%N")
end
is_shutdown_requested := False
listen
on_terminated
end
on_terminated
require
is_terminated
do
if is_terminated then
log ("%N%NTerminating Web Application Server (port="+ port.out +"):%N")
end
if attached output as o then
o.flush
o.close
end
end
shutdown_server
do
debug ("dbglog")
dbglog ("Shutdown requested")
end
is_shutdown_requested := True
controller_shutdown (controller)
end
controller_shutdown (ctl: attached like controller)
do
ctl.shutdown
end
feature -- Listening
listen
-- <Precursor>
-- Creates a socket and connects to the http server.
-- `a_server': The main server object
local
l_listening_socket,
l_accepted_socket: detachable HTTPD_STREAM_SOCKET
l_http_port: INTEGER
l_connection_handler: HTTPD_CONNECTION_HANDLER
do
is_terminated := False
is_launched := False
port := 0
is_shutdown_requested := False
l_http_port := configuration.http_server_port
if
attached configuration.http_server_name as l_servername and then
attached (create {INET_ADDRESS_FACTORY}).create_from_name (l_servername) as l_addr
then
l_listening_socket := new_listening_socket (l_addr, l_http_port)
else
l_listening_socket := new_listening_socket (Void, l_http_port)
end
if not l_listening_socket.is_bound then
if is_verbose then
log ("Socket could not be bound on port " + l_http_port.out)
end
else
l_http_port := l_listening_socket.port
create l_connection_handler.make (Current)
from
l_listening_socket.listen (configuration.max_tcp_clients)
if is_verbose and then configuration.is_secure then
log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : https://localhost:" + l_http_port.out + "/")
elseif is_verbose then
log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/")
end
on_launched (l_http_port)
until
is_shutdown_requested
loop
l_listening_socket.accept
if not is_shutdown_requested then
l_accepted_socket := l_listening_socket.accepted
if l_accepted_socket /= Void then
request_counter := request_counter + 1
if is_verbose then
log ("#" + request_counter.out + "# Incoming connection...(socket:" + l_accepted_socket.descriptor.out + ")")
end
debug ("dbglog")
dbglog (generator + ".before process_incoming_connection {" + l_accepted_socket.descriptor.out + "}" )
end
l_connection_handler.process_incoming_connection (l_accepted_socket)
debug ("dbglog")
dbglog (generator + ".after process_incoming_connection {" + l_accepted_socket.descriptor.out + "}")
end
end
end
update_is_shutdown_requested (l_connection_handler)
end
wait_for_connection_handler_completion (l_connection_handler)
l_listening_socket.cleanup
check
socket_is_closed: l_listening_socket.is_closed
end
end
if is_launched then
on_stopped
end
if is_verbose then
log ("HTTP Connection Server ends.")
end
rescue
log ("HTTP Connection Server shutdown due to exception. Please relaunch manually.")
if l_listening_socket /= Void then
l_listening_socket.cleanup
check
listening_socket_is_closed: l_listening_socket.is_closed
end
end
if is_launched then
on_stopped
end
is_shutdown_requested := True
retry
end
feature {NONE} -- Factory
new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET
do
if a_addr /= Void then
create Result.make_server_by_address_and_port (a_addr, a_http_port)
else
create Result.make_server_by_port (a_http_port)
end
end
feature {NONE} -- Helpers
wait_for_connection_handler_completion (h: HTTPD_CONNECTION_HANDLER)
do
h.wait_for_completion
debug ("dbglog")
dbglog ("Shutdown ready from connection_handler point of view")
end
end
update_is_shutdown_requested (a_connection_handler: HTTPD_CONNECTION_HANDLER)
do
is_shutdown_requested := is_shutdown_requested or shutdown_requested (controller)
if is_shutdown_requested then
a_connection_handler.shutdown
end
end
shutdown_requested (a_controller: separate HTTPD_CONTROLLER): BOOLEAN
-- Shutdown requested on concurrent `a_controller'?
do
Result := a_controller.shutdown_requested
end
feature -- Event
on_launched (a_port: INTEGER)
-- Server launched using port `a_port'
require
not_launched: not is_launched
do
is_launched := True
port := a_port
ensure
is_launched: is_launched
end
on_stopped
-- Server stopped
require
is_launched: is_launched
do
is_launched := False
is_terminated := True
ensure
stopped: not is_launched
end
feature -- Configuration change
apply_configuration
require
is_not_launched: not is_launched
do
is_verbose := configuration.is_verbose
end
feature -- Output
output: detachable FILE
set_log_output (f: FILE)
do
output := f
end
log (a_message: separate READABLE_STRING_8)
-- Log `a_message'
local
m: STRING
do
create m.make_from_separate (a_message)
if attached output as o then
o.put_string (m)
o.put_new_line
else
io.error.put_string (m)
io.error.put_new_line
end
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,252 @@
note
description: "[
Summary description for {HTTPD_STREAM_SOCKET}
that can be used for http or https connection.
]"
date: "$Date$"
revision: "$Revision$"
class
HTTPD_STREAM_SOCKET
create
make_server_by_address_and_port,
make_server_by_port,
make_from_separate
create {HTTPD_STREAM_SOCKET}
make
feature {NONE} -- Initialization
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
do
create {TCP_STREAM_SOCKET} socket.make_server_by_address_and_port (an_address, a_port)
end
make_server_by_port (a_port: INTEGER)
do
create {TCP_STREAM_SOCKET} socket.make_server_by_port (a_port)
end
make_from_separate (s: separate HTTPD_STREAM_SOCKET)
require
descriptor_available: s.descriptor_available
do
create {TCP_STREAM_SOCKET} socket.make_from_separate (s.socket)
end
retrieve_socket (s: HTTPD_STREAM_SOCKET): INTEGER
do
Result := s.socket.descriptor
end
feature -- Access
last_string: STRING
do
Result := socket.last_string
end
last_character: CHARACTER
do
Result := socket.last_character
end
peer_address: detachable NETWORK_SOCKET_ADDRESS
-- Peer address of socket
do
if attached {NETWORK_SOCKET_ADDRESS} socket.peer_address as l_peer_address then
Result := l_peer_address
end
end
feature -- Input
read_line_thread_aware
do
socket.read_line_thread_aware
end
read_stream_thread_aware (nb: INTEGER)
do
socket.read_stream_thread_aware (nb)
end
read_stream (nb: INTEGER)
do
socket.read_stream (nb)
end
read_character
do
socket.read_character
end
bytes_read: INTEGER
do
Result := socket.bytes_read
end
feature -- Output
send_message (a_msg: STRING)
do
put_string (a_msg)
end
put_readable_string_8 (s: READABLE_STRING_8)
-- Write readable string `s' to socket.
do
if attached {TCP_STREAM_SOCKET} socket as l_tcp_stream_socket then
l_tcp_stream_socket.put_readable_string_8 (s)
else
put_string (s)
end
end
put_string (s: STRING)
do
socket.put_string (s)
end
put_character (c: CHARACTER)
do
socket.put_character (c)
end
feature -- Status Report
descriptor_available: BOOLEAN
-- Is descriptor available?
do
Result := socket.descriptor_available
end
descriptor: INTEGER
do
Result := socket.descriptor
end
port: INTEGER
do
if attached {TCP_STREAM_SOCKET} socket as l_socket then
Result := l_socket.port
end
end
is_blocking: BOOLEAN
do
Result := socket.is_blocking
end
is_bound: BOOLEAN
do
if attached {TCP_STREAM_SOCKET} socket as l_socket then
Result := l_socket.is_bound
end
end
socket_ok: BOOLEAN
do
Result := socket.socket_ok
end
is_open_read: BOOLEAN
do
Result := socket.is_open_read
end
is_open_write: BOOLEAN
do
Result := socket.is_open_write
end
is_closed: BOOLEAN
do
Result := socket.is_closed
end
is_readable: BOOLEAN
do
Result := socket.is_readable
end
cleanup
do
socket.cleanup
end
ready_for_writing: BOOLEAN
do
if attached {TCP_STREAM_SOCKET} socket as l_socket then
Result := l_socket.ready_for_writing
end
end
listen (a_queue: INTEGER)
do
socket.listen (a_queue)
end
accept
do
socket.accept
end
set_blocking
do
socket.set_blocking
end
set_non_blocking
do
socket.set_non_blocking
end
readable: BOOLEAN
do
Result := socket.readable
end
ready_for_reading: BOOLEAN
do
if attached {TCP_STREAM_SOCKET} socket as l_socket then
Result := l_socket.ready_for_reading
end
end
try_ready_for_reading: BOOLEAN
do
if attached {TCP_STREAM_SOCKET} socket as l_socket then
Result := l_socket.try_ready_for_reading
end
end
accepted: detachable HTTPD_STREAM_SOCKET
do
if attached socket.accepted as l_accepted then
create Result.make (l_accepted)
end
end
feature {HTTPD_STREAM_SOCKET} -- Implementation
make (a_socket: STREAM_SOCKET)
do
socket := a_socket
end
socket: STREAM_SOCKET
;note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,92 @@
note
description: "Summary description for {TCP_STREAM_SOCKET}."
date: "$Date$"
revision: "$Revision$"
class
TCP_STREAM_SOCKET
inherit
NETWORK_STREAM_SOCKET
redefine
make
end
create
make_server_by_address_and_port,
make_server_by_port,
make_from_separate
create {NETWORK_STREAM_SOCKET}
make_from_descriptor_and_address,
make_empty
feature {NONE} -- Initialization
make
-- Create a network stream socket.
do
Precursor
set_reuse_address
end
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
-- Create server socket on `an_address' and `a_port'.
require
valid_port: a_port >= 0
do
make
create address.make_from_address_and_port (an_address, a_port)
bind
end
make_from_separate (s: separate STREAM_SOCKET)
require
descriptor_available: s.descriptor_available
do
create_from_descriptor (s.descriptor)
end
feature -- Basic operation
send_message (a_msg: STRING)
do
put_string (a_msg)
end
feature -- Output
put_readable_string_8 (s: READABLE_STRING_8)
-- Write readable string `s' to socket.
local
ext: C_STRING
do
create ext.make (s)
put_managed_pointer (ext.managed_data, 0, s.count)
end
feature -- Status report
try_ready_for_reading: BOOLEAN
-- Is data available for reading from the socket right now?
require
socket_exists: exists
local
retval: INTEGER
do
retval := c_select_poll_with_timeout (descriptor, True, 0)
Result := (retval > 0)
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,71 @@
note
description: "Summary description for {HTTPD_CONFIGURATION}."
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONFIGURATION
inherit
HTTPD_CONFIGURATION_I
create
make
feature -- Status
Server_details: STRING_8 = "Server : NINO Eiffel Server"
has_ssl_support: BOOLEAN = False
-- Precursor
feature -- SSL Helpers
set_ssl_protocol_to_ssl_2_or_3
-- Set `ssl_protocol' with `Ssl_23'.
do
-- Ignored
end
set_ssl_protocol_to_ssl_3
-- Set `ssl_protocol' with `Ssl_3'.
do
-- Ignored
end
set_ssl_protocol_to_tls_1_0
-- Set `ssl_protocol' with `Tls_1_0'.
do
-- Ignored
end
set_ssl_protocol_to_tls_1_1
-- Set `ssl_protocol' with `Tls_1_1'.
do
-- Ignored
end
set_ssl_protocol_to_tls_1_2
-- Set `ssl_protocol' with `Tls_1_2'.
do
-- Ignored
end
set_ssl_protocol_to_dtls_1_0
-- Set `ssl_protocol' with `Dtls_1_0'.
do
-- Ignored
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,27 @@
note
description: "[
httpd server
]"
date: "$Date$"
revision: "$Revision$"
class
HTTPD_SERVER
inherit
HTTPD_SERVER_I
create
make
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,82 @@
note
description: "Summary description for {HTTPD_CONFIGURATION}."
date: "$Date$"
revision: "$Revision$"
class
HTTPD_CONFIGURATION
inherit
HTTPD_CONFIGURATION_I
redefine
make
end
create
make
feature {NONE} -- Initialization
make
do
Precursor
ssl_protocol := {SSL_PROTOCOL}.tls_1_2
end
feature -- Access
Server_details: STRING_8 = "Server : NINO Eiffel Server (https)"
has_ssl_support: BOOLEAN = True
-- Precursor
feature -- SSL Helpers
set_ssl_protocol_to_ssl_2_or_3
-- Set `ssl_protocol' with `Ssl_23'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Ssl_23)
end
set_ssl_protocol_to_ssl_3
-- Set `ssl_protocol' with `Ssl_3'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Ssl_3)
end
set_ssl_protocol_to_tls_1_0
-- Set `ssl_protocol' with `Tls_1_0'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_0)
end
set_ssl_protocol_to_tls_1_1
-- Set `ssl_protocol' with `Tls_1_1'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_1)
end
set_ssl_protocol_to_tls_1_2
-- Set `ssl_protocol' with `Tls_1_2'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_2)
end
set_ssl_protocol_to_dtls_1_0
-- Set `ssl_protocol' with `Dtls_1_0'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Dtls_1_0)
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,35 @@
note
description: "[
SSL enabled server
]"
date: "$Date$"
revision: "$Revision$"
class
HTTPD_SERVER
inherit
HTTPD_SERVER_I
redefine
new_listening_socket
end
create
make
feature {NONE} -- Factory
new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET
do
if configuration.is_secure then
if a_addr /= Void then
create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_address_and_port (a_addr, a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key)
else
create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_port (a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key)
end
else
Result := Precursor (a_addr, a_http_port)
end
end
end

View File

@@ -0,0 +1,139 @@
note
description: "[
Summary description for {HTTPD_STREAM_SSL_SOCKET}
that can be used for http or https connection.
]"
date: "$Date$"
revision: "$Revision$"
class
HTTPD_STREAM_SSL_SOCKET
inherit
HTTPD_STREAM_SOCKET
redefine
port,
is_bound,
ready_for_writing,
ready_for_reading,
try_ready_for_reading,
put_readable_string_8
end
create
make_ssl_server_by_address_and_port, make_ssl_server_by_port,
make_server_by_address_and_port, make_server_by_port
create {HTTPD_STREAM_SOCKET}
make
feature {NONE} -- Initialization
make_ssl_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING)
local
l_socket: SSL_TCP_STREAM_SOCKET
do
create l_socket.make_server_by_address_and_port (an_address, a_port)
l_socket.set_tls_protocol (a_ssl_protocol)
socket := l_socket
set_certificates (a_crt, a_key)
end
make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING)
local
l_socket: SSL_TCP_STREAM_SOCKET
do
create l_socket.make_server_by_port (a_port)
l_socket.set_tls_protocol (a_ssl_protocol)
socket := l_socket
set_certificates (a_crt, a_key)
end
feature -- Output
put_readable_string_8 (s: READABLE_STRING_8)
-- <Precursor>
do
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
l_ssl_socket.put_readable_string_8 (s)
else
Precursor (s)
end
end
feature -- Status Report
port: INTEGER
-- <Precursor>
do
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
Result := l_ssl_socket.port
else
Result := Precursor
end
end
is_bound: BOOLEAN
-- <Precursor>
do
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
Result := l_ssl_socket.is_bound
else
Result := Precursor
end
end
ready_for_writing: BOOLEAN
-- <Precursor>
do
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
Result := l_ssl_socket.ready_for_writing
else
Result := Precursor
end
end
ready_for_reading: BOOLEAN
-- <Precursor>
do
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
Result := l_ssl_socket.ready_for_reading
else
Result := Precursor
end
end
try_ready_for_reading: BOOLEAN
do
if attached {SSL_TCP_STREAM_SOCKET} socket as l_socket then
Result := l_socket.try_ready_for_reading
else
Result := Precursor
end
end
feature {HTTPD_STREAM_SOCKET} -- Implementation
set_certificates (a_crt: STRING; a_key: STRING)
local
a_file_name: FILE_NAME
do
if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then
create a_file_name.make_from_string (a_crt)
l_socket.set_certificate_file_name (a_file_name)
create a_file_name.make_from_string (a_key)
l_socket.set_key_file_name (a_file_name)
end
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,72 @@
note
description: "Summary description for {SSL_TCP_STREAM_SOCKET}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
SSL_TCP_STREAM_SOCKET
inherit
SSL_NETWORK_STREAM_SOCKET
create
make_server_by_address_and_port, make_server_by_port
create {SSL_NETWORK_STREAM_SOCKET}
make_from_descriptor_and_address
feature {NONE} -- Initialization
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
-- Create server socket on `an_address' and `a_port'.
require
valid_port: a_port >= 0
do
make
create address.make_from_address_and_port (an_address, a_port)
bind
end
feature -- Basic operation
send_message (a_msg: STRING)
do
put_string (a_msg)
end
feature -- Output
put_readable_string_8 (s: READABLE_STRING_8)
-- Write readable string `s' to socket.
local
ext: C_STRING
do
create ext.make (s)
put_managed_pointer (ext.managed_data, 0, s.count)
end
feature -- Status report
try_ready_for_reading: BOOLEAN
-- Is data available for reading from the socket right now?
require
socket_exists: exists
local
retval: INTEGER
do
retval := c_select_poll_with_timeout (descriptor, True, 0)
Result := (retval > 0)
end
feature {NONE}-- Implementation
note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,70 @@
note
description: "Summary description for WGI_HTTPD_ERROR_STREAM."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_ERROR_STREAM
inherit
WGI_ERROR_STREAM
create
make,
make_stderr,
make_stdout
feature {NONE} -- Initialization
make (a_identifier: READABLE_STRING_8; a_file: PLAIN_TEXT_FILE)
do
identifier := a_identifier
output := a_file
end
make_stderr (a_identifier: READABLE_STRING_8)
do
make (a_identifier, io.error)
end
make_stdout (a_identifier: READABLE_STRING_8)
do
make (a_identifier, io.error)
end
feature -- Access
identifier: READABLE_STRING_8
output: FILE
feature -- Error
put_error (a_message: READABLE_STRING_8)
local
s: STRING
do
create s.make (a_message.count + identifier.count + 4)
s.append_character ('[')
s.append (identifier)
s.append_character (']')
s.append_character (' ')
s.append (a_message)
s.append_character ('%N')
-- Display it at once.
output.put_string (s)
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

View File

@@ -0,0 +1,100 @@
note
description: "Summary description for {WGI_HTTPD_INPUT_STREAM}."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_INPUT_STREAM
inherit
WGI_INPUT_STREAM
create
make
feature {NONE} -- Initialization
make (a_source: like source)
do
create last_string.make_empty
set_source (a_source)
end
feature {WGI_NINO_CONNECTOR, WGI_SERVICE} -- Nino
set_source (i: like source)
do
source := i
end
source: HTTPD_STREAM_SOCKET
feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'.
local
src: like source
do
src := source
if src.readable then
src.read_character
last_character := src.last_character
else
last_character := '%U'
end
end
read_string (nb: INTEGER)
local
src: like source
do
src := source
last_string.wipe_out
if src.readable then
src.read_stream_thread_aware (nb)
last_string.append_string (src.last_string)
end
end
feature -- Access
last_string: STRING_8
-- Last string read
-- (Note: this query *might* return the same object.
-- Therefore a clone should be used if the result
-- is to be kept beyond the next call to this feature.
-- However `last_string' is not shared between input objects.)
last_character: CHARACTER_8
-- Last item read
feature -- Status report
is_open_read: BOOLEAN
-- Can items be read from input stream?
do
Result := source.is_open_read
end
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
do
Result := not source.try_ready_for_reading
end
;note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,104 @@
note
description: "Summary description for {WGI_HTTPD_OUTPUT_STREAM}."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_OUTPUT_STREAM
inherit
WGI_OUTPUT_STREAM
HTTP_STATUS_CODE_MESSAGES
export
{NONE} all
end
create
make
feature {NONE} -- Initialization
make (a_target: like target)
do
set_target (a_target)
end
feature {WGI_NINO_CONNECTOR, WGI_SERVICE} -- Nino
set_target (o: like target)
do
target := o
end
target: HTTPD_STREAM_SOCKET
feature -- Status writing
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- <Precursor>
local
s: STRING
m: detachable READABLE_STRING_8
do
create s.make (16)
s.append ({HTTP_CONSTANTS}.http_version_1_1)
s.append_character (' ')
s.append_integer (a_code)
m := a_reason_phrase
if m = Void then
m := http_status_code_message (a_code)
end
if m /= Void then
s.append_character (' ')
s.append_string (m)
end
put_header_line (s)
end
feature -- Output
put_readable_string_8 (s: READABLE_STRING_8)
-- Send `s' to http client
do
target.put_readable_string_8 (s)
end
put_string (s: READABLE_STRING_8)
-- Send `s' to http client
do
target.put_readable_string_8 (s)
end
put_character (c: CHARACTER_8)
do
target.put_character (c)
end
feature -- Status report
is_open_write: BOOLEAN
-- Can items be written to output stream?
do
Result := target.is_open_write
end
feature -- Basic operations
flush
do
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -0,0 +1,50 @@
note
description: "[
WGI Response implemented using stream buffer
]"
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_RESPONSE_STREAM
inherit
WGI_RESPONSE_STREAM
redefine
put_header_text
end
create
make
feature -- Header output operation
put_header_text (a_text: READABLE_STRING_8)
local
o: like output
do
o := output
o.put_string (a_text)
-- Nino does not support persistent connection for now
o.put_string ("Connection: close")
o.put_crlf
-- end of headers
o.put_crlf
header_committed := True
end
;note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -157,7 +157,7 @@ feature -- Eiffel WGI access
deferred
end
wgi_connector: WGI_CONNECTOR
wgi_connector: detachable WGI_CONNECTOR
-- Associated Eiffel WGI connector
deferred
end
@@ -685,7 +685,7 @@ invariant
path_info_identical: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -6,7 +6,7 @@ note
deferred class
WGI_RESPONSE
feature {WGI_CONNECTOR, WGI_SERVICE} -- Commit
feature {WGI_CONNECTOR, WGI_SERVICE, WGI_EXPORTER} -- Commit
push
-- Commit and push response
@@ -156,7 +156,7 @@ feature -- Error reporting
end
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -57,7 +57,7 @@ feature -- EWSGI access
wgi_implementation: STRING = "Eiffel Web Framework 0.1"
wgi_connector: WGI_CONNECTOR
wgi_connector: detachable WGI_CONNECTOR
feature -- Access: CGI meta parameters
@@ -289,7 +289,7 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1
do
Result := meta_string_variable ({WGI_META_NAMES}.http_range)
end
http_content_range: detachable READABLE_STRING_8
-- Partial range of selected representation enclosed in message payload
do
@@ -301,8 +301,8 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1
do
Result := meta_string_variable ({WGI_META_NAMES}.http_content_encoding)
end
feature -- Access: Extension to CGI meta parameters - 1.1
request_uri: READABLE_STRING_8
@@ -507,7 +507,7 @@ invariant
empty_string_unchanged: empty_string.is_empty
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,10 @@
note
description: "Summary description for {WGI_EXPORTER}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
WGI_EXPORTER
end

View File

@@ -0,0 +1,43 @@
note
description: "Summary description for {WSF_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_EXECUTION
--create
-- make
feature {NONE} -- Initialization
make (req: WGI_REQUEST; res: WGI_RESPONSE)
do
create request.make_from_wgi (req)
create response.make_from_wgi (res)
end
request: WSF_REQUEST
response: WSF_RESPONSE
feature -- Execution
execute
deferred
ensure
response.status_is_set
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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

View File

@@ -41,7 +41,7 @@ inherit
{NONE} all
end
create {WSF_TO_WGI_SERVICE}
create {WSF_TO_WGI_SERVICE, WSF_EXECUTION}
make_from_wgi
convert
@@ -426,7 +426,7 @@ feature -- Eiffel WGI access
Result := wgi_request.wgi_implementation
end
wgi_connector: WGI_CONNECTOR
wgi_connector: detachable WGI_CONNECTOR
-- Associated Eiffel WGI connector
do
Result := wgi_request.wgi_connector
@@ -2173,7 +2173,7 @@ invariant
wgi_request.content_type /= Void implies content_type /= Void
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -19,7 +19,7 @@ note
class
WSF_RESPONSE
create {WSF_TO_WGI_SERVICE}
create {WSF_TO_WGI_SERVICE, WSF_EXECUTION}
make_from_wgi
create {WSF_RESPONSE}
@@ -520,7 +520,7 @@ feature -- Error reporting
end
note
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software