Files
EWF/library/server/httpd/httpd_server_i.e
Jocelyn Fiat d3e865cf6c Fixed setting of socket.timeout in httpd (was not currently set before).
Adopted the nanoseconds timeout precision
 - in config file added support for ns, us, ms, s timeout precision (without indication, it uses `seconds` precision).
2018-10-29 11:27:26 +01:00

397 lines
9.5 KiB
Plaintext

note
description: "HTTPD server interface"
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_SERVER_I
inherit
HTTPD_DEBUG_FACILITIES
HTTPD_LOGGER
HTTPD_LOGGER_CONSTANTS
feature {NONE} -- Initialization
make (a_factory: like factory)
-- Create current httpd server with `a_factory' of connection handlers.
-- `a_factory': connection handler builder
require
a_factory_is_separated: {PLATFORM}.is_scoop_capable implies not attached {HTTPD_REQUEST_HANDLER_FACTORY} a_factory
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 <NONE> controller
end
initialize
-- Initialize Current server.
do
is_shutdown_requested := False
end
feature -- Access
is_verbose: BOOLEAN
-- Is verbose for output messages.
verbose_level: INTEGER
-- Verbosity of output.
configuration: HTTPD_CONFIGURATION
-- Associated server configuration.
controller: separate HTTPD_CONTROLLER
factory: separate HTTPD_REQUEST_HANDLER_FACTORY
is_persistent_connection_supported: BOOLEAN = True
-- Is persistent connection supported?
feature -- Callbacks
observer: detachable separate HTTPD_SERVER_OBSERVER
set_observer (obs: like observer)
-- Set `observer' to `obs'.
do
observer := obs
end
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 ...")
log (" - port = " + configuration.http_server_port.out)
log (" - max_tcp_clients = " + configuration.max_tcp_clients.out)
log (" - max_concurrent_connections = " + configuration.max_concurrent_connections.out)
log (" - socket_timeout = " + timeout_representation (configuration.socket_timeout_ns))
log (" - socket_recv_timeout = " + timeout_representation (configuration.socket_recv_timeout_ns))
log (" - keep_alive_timeout = " + timeout_representation (configuration.keep_alive_timeout_ns))
log (" - max_keep_alive_requests = " + configuration.max_keep_alive_requests.out)
if configuration.has_secure_support then
if configuration.is_secure then
log (" - SSL = enabled")
else
log (" - SSL = disabled")
end
else
log (" - SSL = not supported")
end
if configuration.verbose_level > 0 then
log (" - verbose_level = " + logger_level_representation (configuration.verbose_level))
end
end
is_shutdown_requested := False
listen
is_terminated := True
on_terminated
end
shutdown_server
do
debug ("dbglog")
dbglog ("Shutdown requested")
end
is_shutdown_requested := True
controller_shutdown (controller)
end
controller_shutdown (ctl: attached like controller)
do
ctl.shutdown
end
feature -- Listening
listen
-- <Precursor>
-- Creates a socket and connects to the http server.
-- `a_server': The main server object
local
l_listening_socket: 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 then
if configuration.is_secure then
log ("%NListening on port " + l_http_port.out +" : https://localhost:" + l_http_port.out + "/")
else
log ("%NListening on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/")
end
end
on_launched (l_http_port)
until
is_shutdown_requested
loop
request_counter := request_counter + 1
if is_verbose then
log ("#" + request_counter.out + "# Waiting connection...(listening socket:" + l_listening_socket.descriptor.out + ")")
end
debug ("dbglog")
dbglog (generator + ".before process_waiting_incoming_connection")
end
l_connection_handler.accept_incoming_connection (l_listening_socket)
debug ("dbglog")
dbglog (generator + ".after process_waiting_incoming_connection")
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
if attached observer as obs then
observer_on_launched (obs, a_port)
end
ensure
is_launched: is_launched
end
on_stopped
-- Server stopped
require
is_launched: is_launched
do
if attached observer as obs then
observer_on_stopped (obs)
end
end
on_terminated
-- Server terminated
require
is_terminated
do
if is_terminated and is_verbose then
log ("%N%NTerminating Web Application Server (port="+ port.out +"):%N")
end
if attached output as o then
o.flush
o.close
end
if attached observer as obs then
observer_on_terminated (obs)
end
end
feature {NONE} -- Separate event
observer_on_launched (obs: attached like observer; a_port: INTEGER)
do
obs.on_launched (a_port)
end
observer_on_stopped (obs: attached like observer)
do
obs.on_stopped
end
observer_on_terminated (obs: attached like observer)
do
obs.on_terminated
end
feature -- Configuration change
apply_configuration
require
is_not_launched: not is_launched
do
is_verbose := configuration.is_verbose
verbose_level := configuration.verbose_level
end
feature -- Output
output: detachable FILE
set_log_output (f: FILE)
-- Set `output' to `f'.
do
output := f
ensure
output_set: 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
timeout_representation (a_ns: NATURAL_64): STRING
do
if 1_000 * (a_ns // 1_000) = a_ns then
if 1_000_000 * (a_ns // 1_000_000) = a_ns then
if 1_000_000_000 * (a_ns // 1_000_000_000) = a_ns then
Result := (a_ns // 1_000_000_000).out + " seconds"
else
Result := (a_ns // 1_000_000).out + " milliseconds"
end
else
Result := (a_ns // 1_000).out + " microseconds"
end
else
Result := a_ns.out + " nanoseconds"
end
end
note
copyright: "2011-2018, 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