diff --git a/library/server/ewsgi/connectors/httpd/dev/app_counter.e b/library/server/ewsgi/connectors/httpd/dev/app_counter.e
new file mode 100644
index 00000000..1e4a6489
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/dev/app_counter.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/dev/app_wsf_execution.e b/library/server/ewsgi/connectors/httpd/dev/app_wsf_execution.e
new file mode 100644
index 00000000..b4e817a5
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/dev/app_wsf_execution.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/dev/app_wsf_httpd_request_handler.e b/library/server/ewsgi/connectors/httpd/dev/app_wsf_httpd_request_handler.e
new file mode 100644
index 00000000..e2c3c00f
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/dev/app_wsf_httpd_request_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/dev/httpd_connector_dev.e b/library/server/ewsgi/connectors/httpd/dev/httpd_connector_dev.e
new file mode 100644
index 00000000..89bc7bea
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/dev/httpd_connector_dev.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/dev/wsf/wsf_httpd_request_handler.e b/library/server/ewsgi/connectors/httpd/dev/wsf/wsf_httpd_request_handler.e
new file mode 100644
index 00000000..c5730b33
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/dev/wsf/wsf_httpd_request_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/dev/wsf/wsf_httpd_request_handler_factory.e b/library/server/ewsgi/connectors/httpd/dev/wsf/wsf_httpd_request_handler_factory.e
new file mode 100644
index 00000000..94b667f4
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/dev/wsf/wsf_httpd_request_handler_factory.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/httpd/httpd-safe.ecf
new file mode 100644
index 00000000..38f010d3
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/httpd-safe.ecf
@@ -0,0 +1,74 @@
+
+
+
+
+
+ /EIFGENs$
+ /\.git$
+ /\.svn$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /ssl$
+ /EIFGENs$
+ /no_ssl$
+ /concurrency$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /httpd$
+
+
+
+
+
+
+
+
+
diff --git a/library/server/ewsgi/connectors/httpd/license.lic b/library/server/ewsgi/connectors/httpd/license.lic
new file mode 100644
index 00000000..d4d72876
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/license.lic
@@ -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
+ ]"
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_connection_handler.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_connection_handler.e
new file mode 100644
index 00000000..79ae936a
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_connection_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_request_handler.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_request_handler.e
new file mode 100644
index 00000000..1e607c5e
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_request_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_request_handler_factory.e
new file mode 100644
index 00000000..8bff0870
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/none/httpd_request_handler_factory.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_connection_handler.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_connection_handler.e
new file mode 100644
index 00000000..fcf5c3d7
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_connection_handler.e
@@ -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)
+ --
+ 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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_request_handler.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_request_handler.e
new file mode 100644
index 00000000..2c5754fc
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_request_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_request_handler_factory.e
new file mode 100644
index 00000000..843fc8e3
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/httpd_request_handler_factory.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool.e
new file mode 100644
index 00000000..0bead25a
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool_factory.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool_factory.e
new file mode 100644
index 00000000..497fbb69
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool_factory.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool_item.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool_item.e
new file mode 100644
index 00000000..c197fd88
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/scoop/pool/concurrent_pool_item.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_connection_handler.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_connection_handler.e
new file mode 100644
index 00000000..d3d1354e
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_connection_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_request_handler.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_request_handler.e
new file mode 100644
index 00000000..a119e283
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_request_handler.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_request_handler_factory.e
new file mode 100644
index 00000000..8bff0870
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/httpd_request_handler_factory.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/pool/pooled_thread.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/pool/pooled_thread.e
new file mode 100644
index 00000000..b39e18be
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/pool/pooled_thread.e
@@ -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
+ --
+ 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
+
+
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/pool/thread_pool.e b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/pool/thread_pool.e
new file mode 100644
index 00000000..445aadae
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/concurrency/thread/pool/thread_pool.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/configuration/httpd_configuration_i.e b/library/server/ewsgi/connectors/httpd/src/httpd/configuration/httpd_configuration_i.e
new file mode 100644
index 00000000..7acf397b
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/configuration/httpd_configuration_i.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/httpd/src/httpd/httpd-safe.ecf
new file mode 100644
index 00000000..d6691fca
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd-safe.ecf
@@ -0,0 +1,63 @@
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /EIFGENs$
+ /concurrency$
+ /ssl$
+ /no_ssl$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd.ecf b/library/server/ewsgi/connectors/httpd/src/httpd/httpd.ecf
new file mode 100644
index 00000000..aa6a08a0
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd.ecf
@@ -0,0 +1,62 @@
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /EIFGENs$
+ /concurrency$
+ /ssl$
+ /no_ssl$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_connection_handler_i.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_connection_handler_i.e
new file mode 100644
index 00000000..d9708723
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_connection_handler_i.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_controller.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_controller.e
new file mode 100644
index 00000000..8693a71d
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_controller.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_debug_facilities.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_debug_facilities.e
new file mode 100644
index 00000000..ac1b0051
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_debug_facilities.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_logger.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_logger.e
new file mode 100644
index 00000000..c9668af9
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_logger.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_request_handler_factory_i.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_request_handler_factory_i.e
new file mode 100644
index 00000000..940d7a0a
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_request_handler_factory_i.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_request_handler_i.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_request_handler_i.e
new file mode 100644
index 00000000..5be6fca8
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_request_handler_i.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/httpd_server_i.e b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_server_i.e
new file mode 100644
index 00000000..c0f92b47
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/httpd_server_i.e
@@ -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
+ --
+ -- 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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/network/httpd_stream_socket.e b/library/server/ewsgi/connectors/httpd/src/httpd/network/httpd_stream_socket.e
new file mode 100644
index 00000000..ff4a6361
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/network/httpd_stream_socket.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/network/tcp_stream_socket.e b/library/server/ewsgi/connectors/httpd/src/httpd/network/tcp_stream_socket.e
new file mode 100644
index 00000000..1713779d
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/network/tcp_stream_socket.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/no_ssl/httpd_configuration.e b/library/server/ewsgi/connectors/httpd/src/httpd/no_ssl/httpd_configuration.e
new file mode 100644
index 00000000..b62114ff
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/no_ssl/httpd_configuration.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/no_ssl/httpd_server.e b/library/server/ewsgi/connectors/httpd/src/httpd/no_ssl/httpd_server.e
new file mode 100644
index 00000000..8787e1fc
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/no_ssl/httpd_server.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_configuration.e b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_configuration.e
new file mode 100644
index 00000000..275fd5e4
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_configuration.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_server.e b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_server.e
new file mode 100644
index 00000000..4045aa29
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_server.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_stream_ssl_socket.e b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_stream_ssl_socket.e
new file mode 100644
index 00000000..e1f25ca0
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/httpd_stream_ssl_socket.e
@@ -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)
+ --
+ 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
+ --
+ 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
+ --
+ 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
+ --
+ 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
+ --
+ 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
diff --git a/library/server/ewsgi/connectors/httpd/src/httpd/ssl/ssl_tcp_stream_socket.e b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/ssl_tcp_stream_socket.e
new file mode 100644
index 00000000..c4f5e668
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/httpd/ssl/ssl_tcp_stream_socket.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/wgi_httpd_error_stream.e b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_error_stream.e
new file mode 100644
index 00000000..3cb84e31
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_error_stream.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/wgi_httpd_input_stream.e b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_input_stream.e
new file mode 100644
index 00000000..878db547
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_input_stream.e
@@ -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
diff --git a/library/server/ewsgi/connectors/httpd/src/wgi_httpd_output_stream.e b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_output_stream.e
new file mode 100644
index 00000000..a57095cf
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_output_stream.e
@@ -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)
+ --
+ 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
diff --git a/library/server/ewsgi/connectors/httpd/src/wgi_httpd_response_stream.e b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_response_stream.e
new file mode 100644
index 00000000..acc8a3cd
--- /dev/null
+++ b/library/server/ewsgi/connectors/httpd/src/wgi_httpd_response_stream.e
@@ -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
diff --git a/library/server/ewsgi/specification/request/wgi_request.e b/library/server/ewsgi/specification/request/wgi_request.e
index 5054650b..85a9660e 100644
--- a/library/server/ewsgi/specification/request/wgi_request.e
+++ b/library/server/ewsgi/specification/request/wgi_request.e
@@ -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
diff --git a/library/server/ewsgi/specification/response/wgi_response.e b/library/server/ewsgi/specification/response/wgi_response.e
index 8d8f9de5..d0192a5a 100644
--- a/library/server/ewsgi/specification/response/wgi_response.e
+++ b/library/server/ewsgi/specification/response/wgi_response.e
@@ -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
diff --git a/library/server/ewsgi/src/implementation/wgi_request_from_table.e b/library/server/ewsgi/src/implementation/wgi_request_from_table.e
index 57d7513f..988d0c99 100644
--- a/library/server/ewsgi/src/implementation/wgi_request_from_table.e
+++ b/library/server/ewsgi/src/implementation/wgi_request_from_table.e
@@ -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
diff --git a/library/server/ewsgi/src/wgi_exporter.e b/library/server/ewsgi/src/wgi_exporter.e
new file mode 100644
index 00000000..7fd4e349
--- /dev/null
+++ b/library/server/ewsgi/src/wgi_exporter.e
@@ -0,0 +1,10 @@
+note
+ description: "Summary description for {WGI_EXPORTER}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ WGI_EXPORTER
+
+end
diff --git a/library/server/wsf/src/wsf_execution.e b/library/server/wsf/src/wsf_execution.e
new file mode 100644
index 00000000..582fb6d2
--- /dev/null
+++ b/library/server/wsf/src/wsf_execution.e
@@ -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
diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e
index b36f8fd6..5f17f910 100644
--- a/library/server/wsf/src/wsf_request.e
+++ b/library/server/wsf/src/wsf_request.e
@@ -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
diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e
index f983f9d3..a158fda3 100644
--- a/library/server/wsf/src/wsf_response.e
+++ b/library/server/wsf/src/wsf_response.e
@@ -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}