Support for concurrencies: none, thread and SCOOP
This commit is contained in:
@@ -80,4 +80,10 @@
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<cluster name="dev" location="dev\" recursive="true"/>
|
||||
</target>
|
||||
<target name="dev_mt" extends="dev">
|
||||
<setting name="concurrency" value="thread"/>
|
||||
</target>
|
||||
<target name="dev_none" extends="dev">
|
||||
<setting name="concurrency" value="none"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -31,42 +31,25 @@ feature -- Access
|
||||
|
||||
feature -- Execution
|
||||
|
||||
process_incoming_connection (a_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Process incoming connection
|
||||
-- note that the precondition matters for scoop synchronization.
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
local
|
||||
cl: HTTPD_STREAM_SOCKET
|
||||
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)
|
||||
-- Cancel
|
||||
elseif attached factory.new_handler as h then
|
||||
cl := h.client_socket
|
||||
a_listening_socket.accept_to (cl)
|
||||
if h.is_connected then
|
||||
h.execute
|
||||
end
|
||||
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)
|
||||
@@ -89,7 +72,7 @@ feature {HTTPD_SERVER_I} -- Status report
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -10,15 +10,10 @@ deferred class
|
||||
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"
|
||||
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
|
||||
|
||||
@@ -96,7 +96,7 @@ feature {HTTPD_SERVER_I} -- Execution
|
||||
require
|
||||
hdl.is_connected
|
||||
do
|
||||
hdl.separate_execute
|
||||
hdl.safe_execute
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
@@ -20,56 +20,21 @@ inherit
|
||||
release as release_pool_item
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_connected: BOOLEAN
|
||||
-- Is handler connected to incoming request via `client_socket'?
|
||||
do
|
||||
Result := client_socket.descriptor_available
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
separate_execute
|
||||
local
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if retried then
|
||||
release (client_socket)
|
||||
else
|
||||
if
|
||||
not has_error and then
|
||||
is_connected
|
||||
then
|
||||
execute (client_socket)
|
||||
end
|
||||
separate_release
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
separate_release
|
||||
do
|
||||
release (client_socket)
|
||||
end
|
||||
|
||||
release (a_socket: detachable HTTPD_STREAM_SOCKET)
|
||||
release
|
||||
local
|
||||
d: STRING
|
||||
do
|
||||
if a_socket /= Void then
|
||||
d := a_socket.descriptor.out
|
||||
if attached internal_client_socket as l_socket then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I} (a_socket)
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
release_pool_item
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
|
||||
@@ -50,36 +50,27 @@ feature {HTTPD_SERVER_I} -- Execution
|
||||
p.terminate
|
||||
end
|
||||
|
||||
process_incoming_connection (a_socket: HTTPD_STREAM_SOCKET)
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
local
|
||||
cl: separate HTTPD_STREAM_SOCKET
|
||||
do
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".ENTER accept_connection {"+ a_listening_socket.descriptor.out +"}")
|
||||
end
|
||||
|
||||
if is_shutdown_requested then
|
||||
a_socket.cleanup
|
||||
else
|
||||
process_connection_handler (factory.new_handler, a_socket)
|
||||
-- cancel
|
||||
elseif attached factory.new_handler as h then
|
||||
cl := h.client_socket
|
||||
a_listening_socket.accept_to (cl)
|
||||
if h.is_connected then
|
||||
pool.add_work (agent h.safe_execute)
|
||||
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 +"}")
|
||||
dbglog (generator + ".LEAVE accept_incoming_connection {"+ a_listening_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
|
||||
@@ -99,7 +90,7 @@ invariant
|
||||
pool_attached: pool /= Void
|
||||
|
||||
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
|
||||
|
||||
@@ -17,23 +17,27 @@ inherit
|
||||
|
||||
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release (a_socket: HTTPD_STREAM_SOCKET)
|
||||
release
|
||||
local
|
||||
d: STRING
|
||||
do
|
||||
-- FIXME: for log purpose
|
||||
d := a_socket.descriptor.out
|
||||
if attached internal_client_socket as l_socket then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I} (a_socket)
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
@@ -34,7 +34,14 @@ feature {NONE} -- Initialization
|
||||
create request_header.make_empty
|
||||
create request_header_map.make (10)
|
||||
|
||||
is_waiting := False
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_connected: BOOLEAN
|
||||
-- Is handler connected to incoming request via `client_socket'?
|
||||
do
|
||||
Result := client_socket.descriptor_available
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
@@ -78,8 +85,6 @@ feature -- Settings
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_waiting: BOOLEAN
|
||||
|
||||
has_error: BOOLEAN
|
||||
-- Error occurred during `analyze_request_message'
|
||||
|
||||
@@ -92,36 +97,60 @@ feature -- Change
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (a_socket: HTTPD_STREAM_SOCKET)
|
||||
safe_execute
|
||||
local
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if retried then
|
||||
release
|
||||
else
|
||||
if
|
||||
not has_error and then
|
||||
is_connected
|
||||
then
|
||||
execute
|
||||
end
|
||||
release
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
execute
|
||||
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
|
||||
is_connected: is_connected
|
||||
local
|
||||
l_remote_info: detachable like remote_info
|
||||
l_continue: BOOLEAN
|
||||
l_socket: like client_socket
|
||||
do
|
||||
if a_socket.is_closed then
|
||||
l_socket := client_socket
|
||||
check
|
||||
socket_attached: l_socket /= Void
|
||||
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
|
||||
end
|
||||
if l_socket.is_closed then
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".execute {socket is Closed!}")
|
||||
end
|
||||
else
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".execute {" + a_socket.descriptor.out + "} ENTER")
|
||||
dbglog (generator + ".execute socket=" + l_socket.descriptor.out + " ENTER")
|
||||
end
|
||||
from until l_continue loop
|
||||
if a_socket.ready_for_reading then
|
||||
if l_socket.ready_for_reading then
|
||||
l_continue := True
|
||||
create l_remote_info
|
||||
if attached a_socket.peer_address as l_addr then
|
||||
if attached l_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)
|
||||
analyze_request_message (l_socket)
|
||||
else
|
||||
log (generator + ".execute {" + a_socket.descriptor.out + "} WAITING")
|
||||
log (generator + ".execute socket=" + l_socket.descriptor.out + "} WAITING")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -132,20 +161,16 @@ feature -- Execution
|
||||
log ("ERROR: invalid HTTP incoming request")
|
||||
end
|
||||
else
|
||||
process_request (a_socket)
|
||||
process_request (l_socket)
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".execute {" + a_socket.descriptor.out + "} LEAVE")
|
||||
dbglog (generator + ".execute {" + l_socket.descriptor.out + "} LEAVE")
|
||||
end
|
||||
end
|
||||
-- release (a_socket)
|
||||
end
|
||||
|
||||
release (a_socket: detachable HTTPD_STREAM_SOCKET)
|
||||
release
|
||||
do
|
||||
if a_socket /= Void then
|
||||
a_socket.cleanup
|
||||
end
|
||||
reset
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user