First steps to provide a concurrent compliant EWF connector.
This commit is contained in:
38
library/server/ewsgi/connectors/httpd/dev/app_counter.e
Normal file
38
library/server/ewsgi/connectors/httpd/dev/app_counter.e
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
74
library/server/ewsgi/connectors/httpd/httpd-safe.ecf
Normal file
74
library/server/ewsgi/connectors/httpd/httpd-safe.ecf
Normal 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>
|
||||
10
library/server/ewsgi/connectors/httpd/license.lic
Normal file
10
library/server/ewsgi/connectors/httpd/license.lic
Normal 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
|
||||
]"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
62
library/server/ewsgi/connectors/httpd/src/httpd/httpd.ecf
Normal file
62
library/server/ewsgi/connectors/httpd/src/httpd/httpd.ecf
Normal 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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
316
library/server/ewsgi/connectors/httpd/src/httpd/httpd_server_i.e
Normal file
316
library/server/ewsgi/connectors/httpd/src/httpd/httpd_server_i.e
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
library/server/ewsgi/src/wgi_exporter.e
Normal file
10
library/server/ewsgi/src/wgi_exporter.e
Normal file
@@ -0,0 +1,10 @@
|
||||
note
|
||||
description: "Summary description for {WGI_EXPORTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WGI_EXPORTER
|
||||
|
||||
end
|
||||
43
library/server/wsf/src/wsf_execution.e
Normal file
43
library/server/wsf/src/wsf_execution.e
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user