Moved httpd library from ewsgi/connectors/standalone/lib/httpd to httpd.
Reused the http_network library as well inside httpd library.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: none
|
||||
]"
|
||||
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
|
||||
-- <Precursor>
|
||||
|
||||
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 {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
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
|
||||
-- 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.safe_execute
|
||||
end
|
||||
else
|
||||
check is_not_full: False end
|
||||
end
|
||||
update_is_shutdown_requested
|
||||
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-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
note
|
||||
description : "Concurrent specific feature to implement HTTPD_REQUEST_HANDLER"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
redefine
|
||||
is_persistent_connection_supported
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_persistent_connection_supported: BOOLEAN = False
|
||||
-- <Precursor>
|
||||
-- When there is no concurrency support, do not try to support
|
||||
-- persistent connection!
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: none"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,146 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: SCOOP
|
||||
]"
|
||||
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).max (1) -- At least one processor!
|
||||
create p.make (n)
|
||||
initialize_pool (p, n)
|
||||
pool := p
|
||||
end
|
||||
|
||||
initialize_pool (p: like pool; n: INTEGER)
|
||||
-- Initialize Concurrent pool of `n' potential separate connection handlers.
|
||||
do
|
||||
p.set_count (n)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
-- <Precursor>
|
||||
|
||||
max_concurrent_connections (a_server: like server): INTEGER
|
||||
-- Max concurrent connection settings from server `a_server'.
|
||||
do
|
||||
Result := a_server.configuration.max_concurrent_connections
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
shutdown
|
||||
-- <Precursor>
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
pool_gracefull_stop (pool)
|
||||
end
|
||||
end
|
||||
|
||||
pool_gracefull_stop (p: like pool)
|
||||
-- Graceful stop concurrent pool of separate connection handlers.
|
||||
do
|
||||
p.gracefull_stop
|
||||
end
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- <Precursor>
|
||||
do
|
||||
accept_connection_on_pool (pool, a_listening_socket) -- Wait on not pool.is_full or is_stop_requested
|
||||
end
|
||||
|
||||
accept_connection_on_pool (a_pool: like pool; a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Process accept 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
|
||||
local
|
||||
cl: separate HTTPD_STREAM_SOCKET
|
||||
do
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".ENTER accept_connection_on_pool")
|
||||
end
|
||||
if is_shutdown_requested then
|
||||
-- Cancel
|
||||
elseif attached a_pool.separate_item (factory) as h then
|
||||
cl := separate_client_socket (h)
|
||||
a_listening_socket.accept_to (cl)
|
||||
process_handler (h)
|
||||
else
|
||||
check is_not_full: False end
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".LEAVE accept_connection_on_pool")
|
||||
end
|
||||
end
|
||||
|
||||
process_handler (hdl: separate HTTPD_REQUEST_HANDLER)
|
||||
-- Process request handler `hdl' as soon as `hdl' is connected to accepted socket.
|
||||
require
|
||||
hdl.is_connected
|
||||
do
|
||||
hdl.safe_execute
|
||||
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)
|
||||
-- Wait until concurrent pool is empty and terminated.
|
||||
require
|
||||
p.is_empty -- SCOOP wait condition.
|
||||
do
|
||||
p.terminate
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
separate_client_socket (hdl: separate HTTPD_REQUEST_HANDLER): separate HTTPD_STREAM_SOCKET
|
||||
-- Client socket for request handler `hdl'.
|
||||
do
|
||||
Result := hdl.client_socket
|
||||
end
|
||||
|
||||
pool: separate CONCURRENT_POOL [HTTPD_REQUEST_HANDLER]
|
||||
-- Pool of separate connection handlers.
|
||||
|
||||
invariant
|
||||
pool_attached: pool /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
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
|
||||
|
||||
CONCURRENT_POOL_ITEM
|
||||
rename
|
||||
release as release_pool_item
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- <Precursor>
|
||||
local
|
||||
d: detachable STRING
|
||||
do
|
||||
debug ("dbglog")
|
||||
if
|
||||
attached internal_client_socket as l_socket and then
|
||||
l_socket.descriptor_available
|
||||
then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
release_pool_item
|
||||
debug ("dbglog")
|
||||
if d /= Void then
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
else
|
||||
dbglog (generator + ".release: LEAVE {N/A}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: SCOOP"
|
||||
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-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
|
||||
190
library/server/httpd/concurrency/scoop/pool/concurrent_pool.e
Normal file
190
library/server/httpd/concurrency/scoop/pool/concurrent_pool.e
Normal file
@@ -0,0 +1,190 @@
|
||||
note
|
||||
description: "Concurrent pool for SCOOP concurrency mode."
|
||||
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_empty (n)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
count: INTEGER
|
||||
-- Number of concurrent items managed by Current pool.
|
||||
|
||||
capacity: INTEGER
|
||||
-- Maximum number of concurrent items managed by Current pool.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_full: BOOLEAN
|
||||
-- Pool is full?
|
||||
do
|
||||
Result := count >= capacity
|
||||
end
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- No concurrent item waiting in current pool.
|
||||
do
|
||||
Result := count = 0
|
||||
end
|
||||
|
||||
stop_requested: BOOLEAN
|
||||
-- Current pool received a request to terminate.
|
||||
|
||||
feature -- Access
|
||||
|
||||
separate_item (a_factory: separate CONCURRENT_POOL_FACTORY [G]): detachable separate G
|
||||
-- Reused, or new separate item of type {G} created by `a_factory'.
|
||||
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
|
||||
a_factory.update_item (l_item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
gracefull_stop
|
||||
-- Request the Current pool to terminate.
|
||||
do
|
||||
stop_requested := True
|
||||
end
|
||||
|
||||
feature {NONE} -- Internal
|
||||
|
||||
items: SPECIAL [detachable separate G]
|
||||
-- List of concurrent items.
|
||||
|
||||
busy_items: SPECIAL [BOOLEAN]
|
||||
-- Map of items being proceed.
|
||||
|
||||
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)
|
||||
-- Set capacity of Current pool to `n'.
|
||||
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
|
||||
-- Terminate current pool.
|
||||
local
|
||||
l_items: like items
|
||||
do
|
||||
l_items := items
|
||||
l_items.wipe_out
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
register_item (a_item: separate G)
|
||||
-- Adopt `a_item' in current pool.
|
||||
do
|
||||
a_item.set_pool (Current)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
note
|
||||
description: "Factory in charge of creating new concurrent pool item."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CONCURRENT_POOL_FACTORY [G -> CONCURRENT_POOL_ITEM]
|
||||
|
||||
feature -- Access
|
||||
|
||||
update_item (a_item: separate G)
|
||||
-- Update `a_item' for optionally purpose.
|
||||
do
|
||||
end
|
||||
|
||||
new_separate_item: separate G
|
||||
-- New separated object of type {G}.
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
note
|
||||
description: "[
|
||||
Item create by the CONCURRENT_POOL_FACTORY, and managed by the CONCURRENT_POOL
|
||||
for SCOOP concurrency mode.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CONCURRENT_POOL_ITEM
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
pool: detachable separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM]
|
||||
-- Associated concurrent pool component.
|
||||
|
||||
feature {CONCURRENT_POOL} -- Change
|
||||
|
||||
set_pool (p: like pool)
|
||||
-- Set associated `pool' to `p'.
|
||||
do
|
||||
pool := p
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- Release Current pool item from associated pool.
|
||||
do
|
||||
if attached pool as p then
|
||||
pool_release (p)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
pool_release (p: separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM])
|
||||
do
|
||||
p.release_item (Current)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,103 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: Thread
|
||||
]"
|
||||
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).max (1) -- At least one thread!
|
||||
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
|
||||
|
||||
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
|
||||
-- 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
|
||||
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".LEAVE accept_incoming_connection {"+ a_listening_socket.descriptor.out +"}")
|
||||
end
|
||||
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-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,56 @@
|
||||
note
|
||||
description: "[
|
||||
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
|
||||
-- <Precursor>
|
||||
local
|
||||
d: detachable STRING
|
||||
do
|
||||
debug ("dbglog")
|
||||
if
|
||||
attached internal_client_socket as l_socket and then
|
||||
l_socket.descriptor_available
|
||||
then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
debug ("dbglog")
|
||||
if d /= Void then
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
else
|
||||
dbglog (generator + ".release: LEAVE {N/A}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: Thread"
|
||||
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
|
||||
121
library/server/httpd/concurrency/thread/pool/pooled_thread.e
Normal file
121
library/server/httpd/concurrency/thread/pool/pooled_thread.e
Normal file
@@ -0,0 +1,121 @@
|
||||
note
|
||||
description: "{POOLED_THREAD} is used in combination with {THREAD_POOL} to allow for pooled threads."
|
||||
legal: "See notice at end of class."
|
||||
status: "Community Preview 1.0"
|
||||
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
|
||||
revision: "$Revision: 80577 $"
|
||||
|
||||
class
|
||||
POOLED_THREAD [G]
|
||||
|
||||
inherit
|
||||
THREAD
|
||||
rename
|
||||
make as thread_make
|
||||
end
|
||||
|
||||
create {THREAD_POOL}
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_thread_pool: THREAD_POOL [G]; a_semaphore: SEMAPHORE)
|
||||
-- `a_thread_pool', the pool in which this thread is managed
|
||||
-- `a_semaphore' is used for execution suspending
|
||||
do
|
||||
thread_make
|
||||
thread_pool := a_thread_pool
|
||||
semaphore := a_semaphore
|
||||
end
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
thread_pool: THREAD_POOL [G]
|
||||
-- Pool manager in which this thread is pooled
|
||||
|
||||
target: detachable G
|
||||
-- Target on which the `thread_procedure' should be applied
|
||||
-- Depending on which launch is used, target is not used
|
||||
|
||||
thread_procedure: detachable PROCEDURE
|
||||
-- Work that should be executed by the thread
|
||||
|
||||
semaphore: SEMAPHORE
|
||||
-- Semaphore share with all threads in a thread pool
|
||||
-- to suspend execution until more work is available
|
||||
|
||||
feature -- Access
|
||||
|
||||
set_target (a_target: G)
|
||||
-- Sets the target on which the work should be executed
|
||||
do
|
||||
target := a_target
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
execute
|
||||
-- <Precursor>
|
||||
local
|
||||
done: BOOLEAN
|
||||
do
|
||||
from
|
||||
semaphore.wait
|
||||
thread_procedure := thread_pool.get_work (Current)
|
||||
until
|
||||
done
|
||||
loop
|
||||
if attached thread_procedure as l_work then
|
||||
if attached target as t then
|
||||
l_work.call ([t])
|
||||
else
|
||||
l_work.call (Void)
|
||||
end
|
||||
end
|
||||
if thread_pool.over then
|
||||
done := True
|
||||
else
|
||||
thread_procedure := thread_pool.get_work (Current)
|
||||
if thread_procedure = Void then
|
||||
semaphore.wait
|
||||
thread_procedure := thread_pool.get_work (Current)
|
||||
end
|
||||
end
|
||||
end
|
||||
thread_pool.thread_terminated (Current)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
licensing_options: "http://www.eiffel.com/licensing"
|
||||
copying: "[
|
||||
This file is part of Eiffel Software's Eiffel Development Environment.
|
||||
|
||||
Eiffel Software's Eiffel Development Environment is free
|
||||
software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, version 2 of the License
|
||||
(available at the URL listed under "license" above).
|
||||
|
||||
Eiffel Software's Eiffel Development Environment is
|
||||
distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with Eiffel Software's Eiffel Development
|
||||
Environment; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
]"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
|
||||
|
||||
228
library/server/httpd/concurrency/thread/pool/thread_pool.e
Normal file
228
library/server/httpd/concurrency/thread/pool/thread_pool.e
Normal file
@@ -0,0 +1,228 @@
|
||||
note
|
||||
description: "[
|
||||
A thread pool manager. Manages threads up to `capacity' and queue after that,
|
||||
till threads get available again.
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "Community Preview 1.0"
|
||||
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
|
||||
revision: "$Revision: 80577 $"
|
||||
|
||||
class
|
||||
THREAD_POOL [G]
|
||||
|
||||
inherit
|
||||
EXECUTION_ENVIRONMENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: like capacity)
|
||||
-- Initialize current pool with capacity `n'.
|
||||
require
|
||||
n_positive: n > 0
|
||||
n_not_too_large: n < {INTEGER_32}.max_value.as_natural_32
|
||||
local
|
||||
i: NATURAL
|
||||
do
|
||||
capacity := n
|
||||
create work_queue.make (n.to_integer_32)
|
||||
create work_queue_mutex.make
|
||||
create over_mutex.make
|
||||
create termination_mutex.make
|
||||
create work_semaphore.make (capacity.as_integer_32)
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > capacity
|
||||
loop
|
||||
work_semaphore.wait
|
||||
i := i + 1
|
||||
end
|
||||
initialize_threads
|
||||
terminated_count := capacity
|
||||
is_over := False
|
||||
ensure
|
||||
capacity_set: capacity = n
|
||||
work_queue_set: work_queue.is_empty
|
||||
end
|
||||
|
||||
initialize_threads
|
||||
-- Launches all threads
|
||||
local
|
||||
i: NATURAL
|
||||
thread: POOLED_THREAD [G]
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > capacity
|
||||
loop
|
||||
create thread.make (Current, work_semaphore)
|
||||
thread.launch
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
capacity: NATURAL
|
||||
-- Maximal number of threads allowed (queuing otherwise)
|
||||
|
||||
queue_count: NATURAL
|
||||
-- Number of items in queue
|
||||
do
|
||||
work_queue_mutex.lock
|
||||
Result := work_queue.count.as_natural_32
|
||||
work_queue_mutex.unlock
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
valid_action (a_action: PROCEDURE): 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)
|
||||
-- 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
|
||||
-- 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]
|
||||
-- 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
|
||||
348
library/server/httpd/configuration/httpd_configuration_i.e
Normal file
348
library/server/httpd/configuration/httpd_configuration_i.e
Normal file
@@ -0,0 +1,348 @@
|
||||
note
|
||||
description: "Configuration for the standalone HTTPd server."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_CONFIGURATION_I
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
HTTPD_CONSTANTS
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
http_server_port := default_http_server_port
|
||||
max_concurrent_connections := default_max_concurrent_connections
|
||||
max_tcp_clients := default_max_tcp_clients
|
||||
socket_timeout := default_socket_timeout
|
||||
socket_recv_timeout := default_socket_recv_timeout
|
||||
keep_alive_timeout := default_keep_alive_timeout
|
||||
max_keep_alive_requests := default_max_keep_alive_requests
|
||||
is_secure := False
|
||||
create ca_crt.make_empty
|
||||
create ca_key.make_empty
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
Server_details: STRING_8
|
||||
-- Detail of the server.
|
||||
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
|
||||
-- Listen on socket for at most `queue' connections.
|
||||
|
||||
socket_timeout: INTEGER assign set_socket_timeout
|
||||
-- Amount of seconds that the server waits for receipts and transmissions during communications.
|
||||
-- note: with timeout of 0, socket can wait for ever.
|
||||
-- By default: 60 seconds, which is appropriate for most situations.
|
||||
|
||||
socket_recv_timeout: INTEGER assign set_socket_recv_timeout
|
||||
-- Amount of seconds that the server waits for receiving data during communications.
|
||||
-- note: with timeout of 0, socket can wait for ever.
|
||||
-- By default: 5 seconds.
|
||||
|
||||
max_concurrent_connections: INTEGER assign set_max_concurrent_connections
|
||||
-- Max number of concurrent connections.
|
||||
|
||||
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?
|
||||
|
||||
verbose_level: INTEGER assign set_verbose_level
|
||||
-- Verbosity of output.
|
||||
|
||||
keep_alive_timeout: INTEGER assign set_keep_alive_timeout
|
||||
-- Persistent connection timeout.
|
||||
-- Number of seconds the server waits after a request has been served before it closes the connection.
|
||||
-- Timeout unit in Seconds.
|
||||
-- By default: 5 seconds.
|
||||
|
||||
max_keep_alive_requests: INTEGER assign set_max_keep_alive_requests
|
||||
-- Maximum number of requests allowed per persistent connection.
|
||||
-- Recommended a high setting.
|
||||
-- To disable KeepAlive, set `max_keep_alive_requests' to 0.
|
||||
-- By default: 100 .
|
||||
|
||||
has_ssl_support: BOOLEAN
|
||||
-- Has SSL support?
|
||||
deferred
|
||||
end
|
||||
|
||||
request_settings: HTTPD_REQUEST_SETTINGS
|
||||
do
|
||||
Result.is_verbose := is_verbose
|
||||
Result.verbose_level := verbose_level
|
||||
Result.timeout := socket_timeout
|
||||
Result.socket_recv_timeout := socket_recv_timeout
|
||||
Result.keep_alive_timeout := keep_alive_timeout
|
||||
Result.max_keep_alive_requests := max_keep_alive_requests
|
||||
Result.is_secure := is_secure
|
||||
end
|
||||
|
||||
feature -- Access: SSL
|
||||
|
||||
is_secure: BOOLEAN
|
||||
-- Is SSL/TLS session?.
|
||||
|
||||
ca_crt: detachable IMMUTABLE_STRING_32
|
||||
-- the signed certificate.
|
||||
|
||||
ca_key: detachable IMMUTABLE_STRING_32
|
||||
-- private key to the certificate.
|
||||
|
||||
ssl_protocol: NATURAL
|
||||
-- By default protocol is tls 1.2.
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_ssl_settings (v: detachable separate TUPLE [protocol: separate READABLE_STRING_GENERAL; ca_crt, ca_key: detachable separate READABLE_STRING_GENERAL])
|
||||
local
|
||||
prot: STRING_32
|
||||
do
|
||||
is_secure := False
|
||||
ca_crt := Void
|
||||
ca_key := Void
|
||||
if v /= Void then
|
||||
is_secure := True
|
||||
create prot.make_from_separate (v.protocol)
|
||||
set_ssl_protocol_from_string (prot)
|
||||
set_ca_crt (v.ca_crt)
|
||||
set_ca_key (v.ca_key)
|
||||
end
|
||||
end
|
||||
|
||||
set_http_server_name (v: detachable separate READABLE_STRING_8)
|
||||
do
|
||||
if v = Void then
|
||||
unset_http_server_name
|
||||
else
|
||||
create {IMMUTABLE_STRING_8} http_server_name.make_from_separate (v)
|
||||
end
|
||||
end
|
||||
|
||||
unset_http_server_name
|
||||
-- Unset `http_server_name' value.
|
||||
do
|
||||
http_server_name := Void
|
||||
ensure
|
||||
unset_http_server_name: http_server_name = Void
|
||||
end
|
||||
|
||||
set_http_server_port (v: like http_server_port)
|
||||
-- Set `http_server_port' with `v'.
|
||||
do
|
||||
http_server_port := v
|
||||
ensure
|
||||
http_server_port_set: http_server_port = v
|
||||
end
|
||||
|
||||
set_max_tcp_clients (v: like max_tcp_clients)
|
||||
-- Set `max_tcp_clients' with `v'.
|
||||
do
|
||||
max_tcp_clients := v
|
||||
ensure
|
||||
max_tcp_clients_set: max_tcp_clients = v
|
||||
end
|
||||
|
||||
set_max_concurrent_connections (v: like max_concurrent_connections)
|
||||
-- Set `max_concurrent_connections' with `v'.
|
||||
do
|
||||
max_concurrent_connections := v
|
||||
ensure
|
||||
max_concurrent_connections_set : max_concurrent_connections = v
|
||||
end
|
||||
|
||||
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
||||
-- Set `socket_timeout' with `a_nb_seconds'
|
||||
do
|
||||
socket_timeout := a_nb_seconds
|
||||
ensure
|
||||
socket_timeout_set: socket_timeout = a_nb_seconds
|
||||
end
|
||||
|
||||
set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout)
|
||||
-- Set `socket_recv_timeout' with `a_nb_seconds'
|
||||
do
|
||||
socket_recv_timeout := a_nb_seconds
|
||||
ensure
|
||||
socket_recv_timeout_set: socket_recv_timeout = a_nb_seconds
|
||||
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
|
||||
|
||||
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
||||
-- Set `max_keep_alive_requests' with `nb'
|
||||
do
|
||||
max_keep_alive_requests := nb
|
||||
ensure
|
||||
max_keep_alive_requests_set: max_keep_alive_requests = nb
|
||||
end
|
||||
|
||||
set_force_single_threaded (v: like force_single_threaded)
|
||||
-- Force server to handle incoming request in a single thread.
|
||||
-- i.e set max_concurrent_connections to 0!
|
||||
obsolete
|
||||
"Use set_max_concurrent_connections (0) [June/2016]"
|
||||
do
|
||||
if v then
|
||||
set_max_concurrent_connections (0)
|
||||
end
|
||||
--|Missing postcondition
|
||||
--| force_single_thread_set: v implies max_concurrent_connections = 0
|
||||
--| not_single_thread: not v implies max_concurrent_connections > 0
|
||||
end
|
||||
|
||||
set_is_verbose (b: BOOLEAN)
|
||||
-- Set `is_verbose' to `b'
|
||||
do
|
||||
is_verbose := b
|
||||
ensure
|
||||
is_verbose_set: is_verbose = b
|
||||
end
|
||||
|
||||
set_verbose_level (lev: INTEGER)
|
||||
-- Set `verbose_level' to `lev'.
|
||||
do
|
||||
verbose_level := lev
|
||||
ensure
|
||||
verbose_level_set: verbose_level = lev
|
||||
end
|
||||
|
||||
set_is_secure (b: BOOLEAN)
|
||||
-- Set `is_secure' to `b'.
|
||||
do
|
||||
if b and has_ssl_support then
|
||||
is_secure := True
|
||||
if
|
||||
http_server_port = 80
|
||||
then
|
||||
set_http_server_port (443)
|
||||
end
|
||||
else
|
||||
is_secure := False
|
||||
if
|
||||
http_server_port = 443
|
||||
then
|
||||
set_http_server_port (80)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
is_secure_set: has_ssl_support implies is_secure
|
||||
is_not_secure: not has_ssl_support implies not is_secure
|
||||
end
|
||||
|
||||
mark_secure
|
||||
-- Set is_secure in True
|
||||
do
|
||||
set_is_secure (True)
|
||||
ensure
|
||||
is_secure_set: has_ssl_support implies is_secure
|
||||
-- http_server_port_set: has_ssl_support implies http_server_port = 443
|
||||
is_not_secure: not has_ssl_support implies not is_secure
|
||||
-- default_port: not has_ssl_support implies http_server_port = 80
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_ca_crt (a_value: detachable separate READABLE_STRING_GENERAL)
|
||||
-- Set `ca_crt' from `a_value'.
|
||||
do
|
||||
if a_value /= Void then
|
||||
create ca_crt.make_from_separate (a_value)
|
||||
else
|
||||
ca_crt := Void
|
||||
end
|
||||
end
|
||||
|
||||
set_ca_key (a_value: detachable separate READABLE_STRING_GENERAL)
|
||||
-- Set `ca_key' with `a_value'.
|
||||
do
|
||||
if a_value /= Void then
|
||||
create ca_key.make_from_separate (a_value)
|
||||
else
|
||||
ca_key := Void
|
||||
end
|
||||
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
|
||||
|
||||
set_ssl_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL)
|
||||
-- Set `ssl_protocol' with `a_ssl_version'
|
||||
do
|
||||
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
||||
set_ssl_protocol_to_ssl_2_or_3
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then
|
||||
set_ssl_protocol_to_tls_1_0
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_1") then
|
||||
set_ssl_protocol_to_tls_1_1
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_2") then
|
||||
set_ssl_protocol_to_tls_1_2
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("dtls_1_0") then
|
||||
set_ssl_protocol_to_dtls_1_0
|
||||
else -- Default
|
||||
set_ssl_protocol_to_tls_1_2
|
||||
end
|
||||
end
|
||||
|
||||
feature -- SSL Helpers
|
||||
|
||||
set_ssl_protocol_to_ssl_2_or_3
|
||||
-- Set `ssl_protocol' with `Ssl_23'.
|
||||
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
|
||||
28
library/server/httpd/configuration/httpd_constants.e
Normal file
28
library/server/httpd/configuration/httpd_constants.e
Normal file
@@ -0,0 +1,28 @@
|
||||
note
|
||||
description: "[
|
||||
Various constant values used in httpd settings.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_CONSTANTS
|
||||
|
||||
feature -- Default connection settings
|
||||
|
||||
default_http_server_port: INTEGER = 80
|
||||
default_max_concurrent_connections: INTEGER = 100
|
||||
default_max_tcp_clients: INTEGER = 100
|
||||
|
||||
feature -- Default timeout settings
|
||||
|
||||
default_socket_timeout: INTEGER = 60 -- seconds
|
||||
default_socket_recv_timeout: INTEGER = 5 -- seconds
|
||||
|
||||
feature -- Default persistent connection settings
|
||||
|
||||
default_keep_alive_timeout: INTEGER = 15 -- seconds
|
||||
default_max_keep_alive_requests: INTEGER = 100
|
||||
|
||||
end
|
||||
82
library/server/httpd/configuration/httpd_request_settings.e
Normal file
82
library/server/httpd/configuration/httpd_request_settings.e
Normal file
@@ -0,0 +1,82 @@
|
||||
note
|
||||
description: "[
|
||||
Request settings for the standalone HTTPd server.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
expanded class
|
||||
HTTPD_REQUEST_SETTINGS
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_verbose: BOOLEAN assign set_is_verbose
|
||||
-- Is verbose?
|
||||
|
||||
verbose_level: INTEGER assign set_verbose_level
|
||||
-- Verbosity of output.
|
||||
|
||||
is_secure: BOOLEAN assign set_is_secure
|
||||
-- Is using secure connection? i.e SSL?
|
||||
|
||||
timeout: INTEGER assign set_timeout
|
||||
-- Amount of seconds that the server waits for receipts and transmissions during communications.
|
||||
|
||||
socket_recv_timeout: INTEGER assign set_socket_recv_timeout
|
||||
-- Amount of seconds that the server waits for receiving data on socket during communications.
|
||||
|
||||
keep_alive_timeout: INTEGER assign set_keep_alive_timeout
|
||||
-- Keep-alive timeout, also known as persistent-connection timeout.
|
||||
-- Number of seconds the server waits after a request has been served before it closes the connection.
|
||||
-- Unit in Seconds.
|
||||
|
||||
max_keep_alive_requests: INTEGER assign set_max_keep_alive_requests
|
||||
-- Maximum number of requests allowed per persistent connection.
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_is_verbose (b: BOOLEAN)
|
||||
-- Set `is_verbose' to `b'.
|
||||
do
|
||||
is_verbose := b
|
||||
end
|
||||
|
||||
set_verbose_level (lev: INTEGER)
|
||||
-- Set `verbose_level' to `lev'.
|
||||
do
|
||||
verbose_level := lev
|
||||
end
|
||||
|
||||
set_is_secure (b: BOOLEAN)
|
||||
-- Set `is_secure' to `b'.
|
||||
do
|
||||
is_secure := b
|
||||
end
|
||||
|
||||
set_timeout (a_timeout_in_seconds: INTEGER)
|
||||
-- Set `timeout' to `a_timeout_in_seconds'.
|
||||
do
|
||||
timeout := a_timeout_in_seconds
|
||||
end
|
||||
|
||||
set_socket_recv_timeout (a_timeout_in_seconds: INTEGER)
|
||||
-- Set `socket_recv_timeout' to `a_timeout_in_seconds'.
|
||||
do
|
||||
socket_recv_timeout := a_timeout_in_seconds
|
||||
end
|
||||
|
||||
set_keep_alive_timeout (a_timeout_in_seconds: INTEGER)
|
||||
-- Set `keep_alive_timeout' to `a_timeout_in_seconds'.
|
||||
do
|
||||
keep_alive_timeout := a_timeout_in_seconds
|
||||
end
|
||||
|
||||
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
||||
-- Set `max_keep_alive_requests' with `nb'
|
||||
do
|
||||
max_keep_alive_requests := nb
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
82
library/server/httpd/http_network-safe.ecf
Normal file
82
library/server/httpd/http_network-safe.ecf
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="http_network" uuid="56DAA1CE-0A2E-451A-BFC9-7821578E79F0" library_target="http_network">
|
||||
<target name="http_network">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="false"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<cluster name="network" location=".\network\">
|
||||
<file_rule>
|
||||
<exclude>/httpd_stream_socket_ext.e$</exclude>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<file_rule>
|
||||
<exclude>/httpd_stream_ssl_socket_ext.e$</exclude>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</cluster>
|
||||
<cluster name="network_until_16_05" location=".\network\until_16_05\" recursive="false">
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
<cluster name="ssl_network_until_16_05" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
|
||||
</target>
|
||||
</system>
|
||||
81
library/server/httpd/http_network.ecf
Normal file
81
library/server/httpd/http_network.ecf
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="http_network" uuid="56DAA1CE-0A2E-451A-BFC9-7821578E79F0" library_target="http_network">
|
||||
<target name="http_network">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="false" void_safety="none" syntax="standard">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<cluster name="network" location=".\network\">
|
||||
<file_rule>
|
||||
<exclude>/httpd_stream_socket_ext.e$</exclude>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<file_rule>
|
||||
<exclude>/httpd_stream_ssl_socket_ext.e$</exclude>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</cluster>
|
||||
<cluster name="network_until_16_05" location=".\network\until_16_05\" recursive="false">
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
<cluster name="ssl_network_until_16_05" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
79
library/server/httpd/httpd-safe.ecf
Normal file
79
library/server/httpd/httpd-safe.ecf
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="httpd" uuid="50FE258D-CC94-4748-9223-55F1129E5FB3" library_target="httpd">
|
||||
<target name="httpd">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include">
|
||||
<condition>
|
||||
<version type="compiler" min="16.11.0.0"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include_until_16_05">
|
||||
<condition>
|
||||
<version type="compiler" max="16.11.0.0"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="http_network" location="http_network-safe.ecf" readonly="false"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf">
|
||||
<condition>
|
||||
<concurrency excluded_value="none"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<cluster name="httpd_server" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/concurrency$</exclude>
|
||||
<exclude>/network$</exclude>
|
||||
<exclude>/no_ssl$</exclude>
|
||||
<exclude>/ssl$</exclude>
|
||||
</file_rule>
|
||||
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="ssl" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
|
||||
<condition>
|
||||
<concurrency value="none"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_scoop" location="$|concurrency\scoop\" recursive="true">
|
||||
<condition>
|
||||
<concurrency value="scoop"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_thread" location="$|concurrency\thread\" recursive="true">
|
||||
<condition>
|
||||
<concurrency value="thread"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
68
library/server/httpd/httpd.ecf
Normal file
68
library/server/httpd/httpd.ecf
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="httpd" uuid="50FE258D-CC94-4748-9223-55F1129E5FB3" library_target="httpd">
|
||||
<target name="httpd">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="http_network" location="http_network.ecf" readonly="false"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread.ecf">
|
||||
<condition>
|
||||
<concurrency excluded_value="none"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="httpd_server" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/concurrency$</exclude>
|
||||
<exclude>/no_ssl$</exclude>
|
||||
<exclude>/ssl$</exclude>
|
||||
<exclude>/network$</exclude>
|
||||
</file_rule>
|
||||
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="ssl" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
|
||||
<condition>
|
||||
<concurrency value="none"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_scoop" location="$|concurrency\scoop\" recursive="true">
|
||||
<condition>
|
||||
<concurrency value="scoop"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_thread" location="$|concurrency\thread\" recursive="true">
|
||||
<condition>
|
||||
<concurrency value="thread"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
97
library/server/httpd/httpd_connection_handler_i.e
Normal file
97
library/server/httpd/httpd_connection_handler_i.e
Normal file
@@ -0,0 +1,97 @@
|
||||
note
|
||||
description: "[
|
||||
Interface for the incoming connection handler.
|
||||
|
||||
Each incoming socket connection is processed by
|
||||
an implementation of HTTPD_CONNECTION_HANDLER_I.
|
||||
|
||||
Note there are 3 implementations, one for each concurrent mode: none, thread, scoop.
|
||||
]"
|
||||
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
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
factory: separate HTTPD_REQUEST_HANDLER_FACTORY
|
||||
-- Request handler factory.
|
||||
|
||||
server: separate HTTPD_SERVER_I
|
||||
-- Associated server.
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Accept incoming connection from `a_listening_socket'.
|
||||
deferred
|
||||
end
|
||||
|
||||
shutdown
|
||||
-- Shutdown server.
|
||||
deferred
|
||||
end
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current completed any pending task.
|
||||
--| Used for SCOOP synchronisation.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER} -- Status report
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
-- Any request to shutdown the server?
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
log (a_message: separate READABLE_STRING_8)
|
||||
-- Log `a_message'
|
||||
do
|
||||
-- FIXME: Concurrency issue on `server'
|
||||
separate_server_log (server, a_message)
|
||||
end
|
||||
|
||||
separate_factory (a_server: like server): like factory
|
||||
-- Separate factory from `a_server'.
|
||||
--| required by SCOOP design.
|
||||
do
|
||||
Result := a_server.factory
|
||||
end
|
||||
|
||||
separate_server_log (a_server: like server; a_message: separate READABLE_STRING_8)
|
||||
-- Concurrent call to `a_server.log (a_message)'.
|
||||
do
|
||||
a_server.log (a_message)
|
||||
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
|
||||
28
library/server/httpd/httpd_controller.e
Normal file
28
library/server/httpd/httpd_controller.e
Normal file
@@ -0,0 +1,28 @@
|
||||
note
|
||||
description: "[
|
||||
Object used to control (i.e shutdown) the server.
|
||||
Mostly needed in SCOOP concurrency mode.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONTROLLER
|
||||
|
||||
feature -- Operation
|
||||
|
||||
shutdown
|
||||
-- Request the associated server to be shutdown.
|
||||
do
|
||||
shutdown_requested := True
|
||||
end
|
||||
|
||||
feature -- Status report.
|
||||
|
||||
shutdown_requested: BOOLEAN
|
||||
-- Shutdown requested.
|
||||
|
||||
;note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
50
library/server/httpd/httpd_debug_facilities.e
Normal file
50
library/server/httpd/httpd_debug_facilities.e
Normal file
@@ -0,0 +1,50 @@
|
||||
note
|
||||
description: " Routines used for debug logging."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_DEBUG_FACILITIES
|
||||
|
||||
feature {NONE} -- Output
|
||||
|
||||
dbglog (m: READABLE_STRING_8)
|
||||
require
|
||||
not m.ends_with_general ("%N")
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
debug ("dbglog")
|
||||
create s.make (24)
|
||||
s.append ("[EWF/DBG] <#")
|
||||
s.append_integer (processor_id_from_object (Current))
|
||||
s.append ("> ")
|
||||
s.append (generator)
|
||||
s.append (create {STRING}.make_filled (' ', (46 - s.count).max (0)))
|
||||
s.append (" | ")
|
||||
s.append (m)
|
||||
s.append ("%N")
|
||||
print (s)
|
||||
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-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
|
||||
26
library/server/httpd/httpd_logger.e
Normal file
26
library/server/httpd/httpd_logger.e
Normal file
@@ -0,0 +1,26 @@
|
||||
note
|
||||
description: "Logging facilities component"
|
||||
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
|
||||
22
library/server/httpd/httpd_logger_constants.e
Normal file
22
library/server/httpd/httpd_logger_constants.e
Normal file
@@ -0,0 +1,22 @@
|
||||
note
|
||||
description: "[
|
||||
Constant value to define the logging level.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_LOGGER_CONSTANTS
|
||||
|
||||
feature -- Access
|
||||
|
||||
alert_level: INTEGER = 1 -- 0000 0001
|
||||
critical_level: INTEGER = 2 -- 0000 0010
|
||||
error_level: INTEGER = 4 -- 0000 0100
|
||||
warning_level: INTEGER = 8 -- 0000 1000
|
||||
|
||||
notice_level: INTEGER = 16 -- 0001 0000
|
||||
information_level: INTEGER = 32 -- 0010 0000
|
||||
debug_level: INTEGER = 64 -- 0100 0000
|
||||
|
||||
end
|
||||
26
library/server/httpd/httpd_request_handler_factory_i.e
Normal file
26
library/server/httpd/httpd_request_handler_factory_i.e
Normal file
@@ -0,0 +1,26 @@
|
||||
note
|
||||
description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY_I}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_handler: separate HTTPD_REQUEST_HANDLER
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
597
library/server/httpd/httpd_request_handler_i.e
Normal file
597
library/server/httpd/httpd_request_handler_i.e
Normal file
@@ -0,0 +1,597 @@
|
||||
note
|
||||
description: "HTTPD handler interface processing request."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
|
||||
inherit
|
||||
HTTPD_DEBUG_FACILITIES
|
||||
|
||||
HTTPD_LOGGER_CONSTANTS
|
||||
|
||||
HTTPD_SOCKET_FACTORY
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_request_settings: HTTPD_REQUEST_SETTINGS)
|
||||
do
|
||||
reset
|
||||
-- Import global request settings.
|
||||
timeout := a_request_settings.timeout -- seconds
|
||||
socket_recv_timeout := a_request_settings.socket_recv_timeout -- seconds
|
||||
keep_alive_timeout := a_request_settings.keep_alive_timeout -- seconds
|
||||
max_keep_alive_requests := a_request_settings.max_keep_alive_requests
|
||||
|
||||
is_verbose := a_request_settings.is_verbose
|
||||
verbose_level := a_request_settings.verbose_level
|
||||
is_secure := a_request_settings.is_secure
|
||||
end
|
||||
|
||||
reset
|
||||
do
|
||||
reset_request (False)
|
||||
|
||||
reset_error
|
||||
if attached internal_client_socket as l_sock then
|
||||
l_sock.cleanup
|
||||
end
|
||||
internal_client_socket := Void
|
||||
end
|
||||
|
||||
reset_request (a_is_reusing_connection: BOOLEAN)
|
||||
-- Reset the request, and `a_is_reusing_connection' says if the peristent connection is
|
||||
-- still alive.
|
||||
do
|
||||
if a_is_reusing_connection then
|
||||
-- Keep `remote_info' as it stays the same for the successive
|
||||
-- persistent connections.
|
||||
else
|
||||
remote_info := Void
|
||||
end
|
||||
|
||||
version := 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)
|
||||
|
||||
is_persistent_connection_requested := 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
|
||||
|
||||
internal_client_socket: detachable HTTPD_STREAM_SOCKET
|
||||
|
||||
client_socket: HTTPD_STREAM_SOCKET
|
||||
local
|
||||
s: like internal_client_socket
|
||||
do
|
||||
s := internal_client_socket
|
||||
if s = Void then
|
||||
s := new_client_socket (is_secure)
|
||||
internal_client_socket := s
|
||||
end
|
||||
Result := s
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
is_persistent_connection_requested: BOOLEAN
|
||||
-- Persistent connection requested?
|
||||
-- either has "Connection: keep-alive" header,
|
||||
-- or is HTTP/1.1 and no header "Connection: close".
|
||||
|
||||
is_http_version_1_0: BOOLEAN
|
||||
do
|
||||
Result := not attached version as v or else v.same_string ("HTTP/1.0")
|
||||
end
|
||||
|
||||
is_http_version_1_1: BOOLEAN
|
||||
do
|
||||
Result := not attached version as v or else v.same_string ("HTTP/1.1")
|
||||
end
|
||||
|
||||
is_http_version_2: BOOLEAN
|
||||
do
|
||||
Result := not attached version as v or else v.same_string ("HTTP/2.0")
|
||||
end
|
||||
|
||||
feature -- Settings
|
||||
|
||||
is_verbose: BOOLEAN
|
||||
-- Output messages?
|
||||
|
||||
verbose_level: INTEGER
|
||||
-- Output verbosity.
|
||||
|
||||
is_secure: BOOLEAN
|
||||
-- Is secure socket?
|
||||
-- i.e: SSL?
|
||||
|
||||
is_persistent_connection_supported: BOOLEAN
|
||||
-- Is persistent connection supported?
|
||||
do
|
||||
Result := {HTTPD_SERVER}.is_persistent_connection_supported and then max_keep_alive_requests > 0
|
||||
end
|
||||
|
||||
is_next_persistent_connection_supported: BOOLEAN
|
||||
-- Is next persistent connection supported?
|
||||
-- note: it is relevant only if `is_persistent_connection_supported' is True.
|
||||
|
||||
timeout: INTEGER -- seconds
|
||||
-- Amount of seconds that the server waits for receipts and transmissions during communications.
|
||||
|
||||
socket_recv_timeout: INTEGER -- seconds
|
||||
-- Amount of seconds that the server waits for receiving data on socket during communications.
|
||||
|
||||
max_keep_alive_requests: INTEGER
|
||||
-- Maximum number of requests allowed per persistent connection.
|
||||
|
||||
keep_alive_timeout: INTEGER -- seconds
|
||||
-- Number of seconds for persistent connection timeout.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
-- Error occurred during `get_request_header'
|
||||
|
||||
feature -- Status change
|
||||
|
||||
report_error (m: detachable READABLE_STRING_GENERAL)
|
||||
-- Report error occurred, with optional message `m'.
|
||||
do
|
||||
has_error := True
|
||||
end
|
||||
|
||||
reset_error
|
||||
-- Reset previous error for current request handler.
|
||||
do
|
||||
has_error := False
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_is_verbose (b: BOOLEAN)
|
||||
-- Set `is_verbose' with `b'.
|
||||
do
|
||||
is_verbose := b
|
||||
ensure
|
||||
is_verbose_set: is_verbose = b
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
safe_execute
|
||||
-- Execute accepted incoming connection as request.
|
||||
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
|
||||
is_connected: is_connected
|
||||
local
|
||||
l_socket: like client_socket
|
||||
l_remote_info: detachable like remote_info
|
||||
l_exit: BOOLEAN
|
||||
n,m: INTEGER
|
||||
do
|
||||
l_socket := client_socket
|
||||
|
||||
-- Compute remote info once for the persistent connection.
|
||||
create l_remote_info
|
||||
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
|
||||
end
|
||||
remote_info := l_remote_info
|
||||
|
||||
check
|
||||
socket_attached: l_socket /= Void
|
||||
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
|
||||
end
|
||||
from
|
||||
-- Process persistent connection as long the socket is not closed.
|
||||
n := 0
|
||||
m := max_keep_alive_requests
|
||||
is_next_persistent_connection_supported := True
|
||||
until
|
||||
l_exit
|
||||
loop
|
||||
n := n + 1
|
||||
if n >= m then
|
||||
is_next_persistent_connection_supported := False
|
||||
elseif n > 1 and is_verbose then
|
||||
log ("Reuse connection (" + n.out + ")", information_level)
|
||||
end
|
||||
-- FIXME: it seems to be called one more time, mostly to see this is done.
|
||||
execute_request (n > 1)
|
||||
l_exit := not is_persistent_connection_supported
|
||||
or not is_next_persistent_connection_supported -- related to `max_keep_alive_requests'
|
||||
or not is_persistent_connection_requested
|
||||
or has_error or l_socket.is_closed or not l_socket.is_open_read
|
||||
reset_request (not l_exit)
|
||||
end
|
||||
if l_exit and has_error and not l_socket.is_closed then
|
||||
l_socket.close
|
||||
end
|
||||
end
|
||||
|
||||
execute_request (a_is_reusing_connection: BOOLEAN)
|
||||
-- Execute http request, and if `a_is_reusing_connection' is True
|
||||
-- the execution is reusing the persistent connection.
|
||||
require
|
||||
is_connected: is_connected
|
||||
reuse_connection_when_possible: a_is_reusing_connection implies is_persistent_connection_supported
|
||||
no_error: not has_error
|
||||
remote_info_set: remote_info /= Void
|
||||
local
|
||||
l_socket: like client_socket
|
||||
do
|
||||
debug ("dbglog")
|
||||
if a_is_reusing_connection then
|
||||
dbglog ("execute_request: wait on persistent connection.")
|
||||
end
|
||||
end
|
||||
reset_error
|
||||
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 ("execute_request {socket is Closed!}")
|
||||
end
|
||||
else
|
||||
debug ("dbglog")
|
||||
dbglog ("execute_request socket=" + l_socket.descriptor.out + " ENTER")
|
||||
end
|
||||
|
||||
-- Try to get request header.
|
||||
-- If the request is reusing persistent connection, use `keep_alive_timeout',
|
||||
-- otherwise `socket_recv_timeout'.
|
||||
get_request_header (l_socket, a_is_reusing_connection)
|
||||
|
||||
if has_error then
|
||||
if a_is_reusing_connection and then request_header.is_empty then
|
||||
-- Close persistent connection, since no new connection occurred in the delay `keep_alive_timeout'.
|
||||
debug ("dbglog")
|
||||
dbglog ("execute_request socket=" + l_socket.descriptor.out + "} close persistent connection.")
|
||||
end
|
||||
else
|
||||
if is_verbose then
|
||||
log (request_header + "%NWARNING: invalid HTTP incoming request", warning_level)
|
||||
end
|
||||
process_bad_request (l_socket)
|
||||
end
|
||||
is_persistent_connection_requested := False
|
||||
else
|
||||
if is_verbose then
|
||||
log (request_header, information_level)
|
||||
end
|
||||
process_request (l_socket)
|
||||
end
|
||||
|
||||
debug ("dbglog")
|
||||
dbglog ("execute_request {" + l_socket.descriptor.out + "} LEAVE")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
release
|
||||
do
|
||||
reset
|
||||
end
|
||||
|
||||
feature -- Request processing
|
||||
|
||||
process_request (a_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Process request on socket `a_socket'.
|
||||
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
|
||||
|
||||
process_bad_request (a_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Process bad request catched on `a_socket'.
|
||||
require
|
||||
has_error: has_error
|
||||
a_socket_attached: a_socket /= Void
|
||||
local
|
||||
-- h: STRING
|
||||
-- s: STRING
|
||||
do
|
||||
-- NOTE: this is experiment code, and not ready yet.
|
||||
|
||||
-- if a_socket.ready_for_writing then
|
||||
-- s := "{
|
||||
--<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
--<html><head>
|
||||
--<title>400 Bad Request</title>
|
||||
--</head><body>
|
||||
--<h1>Bad Request</h1>
|
||||
--</body></html>
|
||||
-- }"
|
||||
-- create h.make (1_024)
|
||||
-- h.append ("HTTP/1.1 400 Bad Request%R%N")
|
||||
-- h.append ("Content-Length: " + s.count.out + "%R%N")
|
||||
-- h.append ("Connection: close%R%N")
|
||||
-- h.append ("Content-Type: text/html; charset=iso-8859-1%R%N")
|
||||
-- h.append ("%R%N")
|
||||
-- a_socket.put_string (h)
|
||||
-- if a_socket.ready_for_writing then
|
||||
-- a_socket.put_string (s)
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
|
||||
feature -- Parsing
|
||||
|
||||
get_request_header (a_socket: HTTPD_STREAM_SOCKET; a_is_reusing_connection: BOOLEAN)
|
||||
-- Analyze message extracted from `a_socket' as HTTP request.
|
||||
-- If `a_is_reusing_connection' is True, then first use
|
||||
-- Note: it reads from socket.
|
||||
-- Note: it updates `request_header' and `request_header_map', and eventually `is_persistent_connection_requested'.
|
||||
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
|
||||
l_is_verbose := is_verbose
|
||||
|
||||
if
|
||||
not has_error and then
|
||||
a_socket.readable
|
||||
then
|
||||
if a_is_reusing_connection then
|
||||
a_socket.set_recv_timeout (keep_alive_timeout) -- in seconds!
|
||||
else
|
||||
a_socket.set_recv_timeout (socket_recv_timeout) -- FIXME: return a 408 Request Timeout response ..
|
||||
end
|
||||
|
||||
if
|
||||
attached next_line (a_socket) as l_request_line and then
|
||||
not l_request_line.is_empty and then
|
||||
not has_error
|
||||
then
|
||||
txt.append (l_request_line)
|
||||
txt.append_character ('%N')
|
||||
analyze_request_line (l_request_line)
|
||||
|
||||
if not has_error then
|
||||
if a_is_reusing_connection then
|
||||
-- Restore normal recv timeout!
|
||||
a_socket.set_recv_timeout (socket_recv_timeout) -- FIXME: return a 408 Request Timeout response ..
|
||||
end
|
||||
from
|
||||
line := next_line (a_socket)
|
||||
until
|
||||
line = Void or end_of_stream or has_error
|
||||
loop
|
||||
n := line.count
|
||||
debug ("ew_standalone")
|
||||
if l_is_verbose then
|
||||
log (line, debug_level)
|
||||
end
|
||||
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
|
||||
-- Except for HTTP/1.0, persistent connection is the default.
|
||||
is_persistent_connection_requested := True
|
||||
if is_http_version_1_0 then
|
||||
is_persistent_connection_requested := attached request_header_map.item ("Connection") as l_connection and then
|
||||
l_connection.is_case_insensitive_equal_general ("keep-alive")
|
||||
else
|
||||
-- By default HTTP:1/1 support persistent connection.
|
||||
if attached request_header_map.item ("Connection") as l_connection then
|
||||
if l_connection.is_case_insensitive_equal_general ("close") then
|
||||
is_persistent_connection_requested := False
|
||||
end
|
||||
else
|
||||
is_persistent_connection_requested := True
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
report_error ("Bad header line (empty)")
|
||||
end
|
||||
else
|
||||
report_error ("Socket is not readable")
|
||||
end
|
||||
end
|
||||
|
||||
analyze_request_line (line: STRING)
|
||||
-- Analyze `line' as a HTTP request line.
|
||||
-- note: may update `has_error'.
|
||||
require
|
||||
valid_line: line /= Void and then not line.is_empty
|
||||
local
|
||||
n, pos, next_pos: INTEGER
|
||||
do
|
||||
debug ("ew_standalone")
|
||||
if is_verbose then
|
||||
log ("%N## Parse HTTP request line ##", debug_level)
|
||||
log (line, debug_level)
|
||||
end
|
||||
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)
|
||||
n := line.count
|
||||
if line[n] = '%R' then
|
||||
n := n - 1
|
||||
end
|
||||
version := line.substring (next_pos + 1, n)
|
||||
if method.is_empty then
|
||||
report_error ("Missing request method data")
|
||||
end
|
||||
end
|
||||
|
||||
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
|
||||
-- Next line fetched from `a_socket' is available.
|
||||
-- note: may update `has_error'.
|
||||
require
|
||||
not_has_error: not has_error
|
||||
is_readable: a_socket.is_open_read
|
||||
local
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if retried then
|
||||
report_error ("Rescue in next_line")
|
||||
a_socket.close
|
||||
Result := Void
|
||||
elseif a_socket.readable then
|
||||
a_socket.read_line_noexception
|
||||
Result := a_socket.last_string
|
||||
-- Do no check `was_error' before socket operation,
|
||||
-- otherwise it may be False, due to error during other socket operation in same thread.
|
||||
if a_socket.was_error then
|
||||
report_error ("Socket error")
|
||||
if is_verbose then
|
||||
log (request_header +"%N" + Result + "%N## was_error=False! ##", debug_level)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Error with socket...
|
||||
report_error ("Socket error: not readable")
|
||||
if is_verbose then
|
||||
log (request_header + "%N## Socket is not readable! ##", debug_level)
|
||||
end
|
||||
end
|
||||
rescue
|
||||
-- In case of network error exception (as EiffelNet reports error raising exception)
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
logger: detachable HTTPD_LOGGER
|
||||
|
||||
set_logger (a_logger: like logger)
|
||||
-- Set `logger' with `a_logger'.
|
||||
do
|
||||
logger := a_logger
|
||||
ensure
|
||||
logger_set: logger = a_logger
|
||||
end
|
||||
|
||||
log (m: STRING; a_level: INTEGER)
|
||||
-- Log message `m'.
|
||||
require
|
||||
is_verbose: is_verbose
|
||||
do
|
||||
if is_verbose and (verbose_level & a_level) = a_level then
|
||||
if attached logger as l_logger then
|
||||
l_logger.log (m)
|
||||
else
|
||||
io.put_string (m + "%N")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Helpers
|
||||
|
||||
socket_has_incoming_data (a_socket: HTTPD_STREAM_SOCKET): BOOLEAN
|
||||
-- Is there any data to read on `a_socket' ?
|
||||
require
|
||||
a_socket.readable
|
||||
do
|
||||
-- FIXME: check if both are really needed.
|
||||
-- Result := a_socket.ready_for_reading --and then a_socket.has_incoming_data
|
||||
-- Result := a_socket.has_incoming_data
|
||||
Result := True
|
||||
end
|
||||
|
||||
invariant
|
||||
request_header_attached: request_header /= 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
|
||||
377
library/server/httpd/httpd_server_i.e
Normal file
377
library/server/httpd/httpd_server_i.e
Normal file
@@ -0,0 +1,377 @@
|
||||
note
|
||||
description: "HTTPD server interface"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_SERVER_I
|
||||
|
||||
inherit
|
||||
HTTPD_DEBUG_FACILITIES
|
||||
|
||||
HTTPD_LOGGER
|
||||
|
||||
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 = " + configuration.socket_timeout.out + " seconds")
|
||||
log (" - socket_recv_timeout = " + configuration.socket_recv_timeout.out + " seconds")
|
||||
log (" - keep_alive_timeout = " + configuration.keep_alive_timeout.out + " seconds")
|
||||
log (" - max_keep_alive_requests = " + configuration.max_keep_alive_requests.out)
|
||||
if configuration.has_ssl_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 = " + configuration.verbose_level.out)
|
||||
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
|
||||
|
||||
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
|
||||
27
library/server/httpd/httpd_server_observer.e
Normal file
27
library/server/httpd/httpd_server_observer.e
Normal file
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "Summary description for {HTTPD_SERVER_OBSERVER}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_SERVER_OBSERVER
|
||||
|
||||
feature -- Event
|
||||
|
||||
on_launched (a_port: INTEGER)
|
||||
-- Associated server launched listening on port `a_port'.
|
||||
deferred
|
||||
end
|
||||
|
||||
on_stopped
|
||||
-- Associated server stopped.
|
||||
--| the server may restart itself after being rescued.
|
||||
deferred
|
||||
end
|
||||
|
||||
on_terminated
|
||||
-- Associated server terminated.
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
243
library/server/httpd/network/httpd_stream_socket.e
Normal file
243
library/server/httpd/network/httpd_stream_socket.e
Normal file
@@ -0,0 +1,243 @@
|
||||
note
|
||||
description: "Summary description for {HTTPD_STREAM_SOCKET}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_STREAM_SOCKET
|
||||
|
||||
inherit
|
||||
NETWORK_STREAM_SOCKET
|
||||
|
||||
HTTPD_STREAM_SOCKET_EXT
|
||||
|
||||
create
|
||||
make, make_empty,
|
||||
make_client_by_port, make_client_by_address_and_port,
|
||||
make_server_by_port, make_server_by_address_and_port, make_loopback_server_by_port
|
||||
|
||||
create {NETWORK_STREAM_SOCKET}
|
||||
make_from_descriptor_and_address
|
||||
|
||||
feature -- Input
|
||||
|
||||
read_character_noexception
|
||||
-- Read a new character.
|
||||
-- Make result available in `last_character'.
|
||||
-- No exception raised!
|
||||
do
|
||||
read_to_managed_pointer_noexception (socket_buffer, 0, character_8_bytes)
|
||||
if bytes_read /= character_8_bytes then
|
||||
socket_error := "Peer closed connection"
|
||||
else
|
||||
last_character := socket_buffer.read_character (0)
|
||||
socket_error := Void
|
||||
end
|
||||
end
|
||||
|
||||
read_stream_noexception (nb_char: INTEGER)
|
||||
-- Read a string of at most `nb_char' characters.
|
||||
-- Make result available in `last_string'.
|
||||
local
|
||||
ext: C_STRING
|
||||
return_val: INTEGER
|
||||
do
|
||||
create ext.make_empty (nb_char + 1)
|
||||
return_val := c_read_stream_noexception (descriptor, nb_char, ext.item)
|
||||
bytes_read := return_val
|
||||
if return_val >= 0 then
|
||||
ext.set_count (return_val)
|
||||
last_string := ext.substring (1, return_val)
|
||||
else
|
||||
socket_error := "Peer error [0x" + return_val.to_hex_string + "]"
|
||||
last_string.wipe_out
|
||||
end
|
||||
end
|
||||
|
||||
read_to_managed_pointer_noexception (p: MANAGED_POINTER; start_pos, nb_bytes: INTEGER)
|
||||
-- Read at most `nb_bytes' bound bytes and make result
|
||||
-- available in `p' at position `start_pos'.
|
||||
-- No exception raised!
|
||||
do
|
||||
read_into_pointer_noexception (p.item, start_pos, nb_bytes)
|
||||
end
|
||||
|
||||
read_line_noexception
|
||||
-- Read a line of characters (ended by a new_line).
|
||||
-- No exception raised!
|
||||
local
|
||||
l_last_string: like last_string
|
||||
do
|
||||
create l_last_string.make (512)
|
||||
read_character_noexception
|
||||
from
|
||||
until
|
||||
last_character = '%N' or else was_error
|
||||
loop
|
||||
l_last_string.extend (last_character)
|
||||
read_character_noexception
|
||||
end
|
||||
last_string := l_last_string
|
||||
end
|
||||
|
||||
peek_stream_noexception (nb_char: INTEGER)
|
||||
-- Read a string of at most `nb_char' characters without removing the data from the queue.
|
||||
-- Make result available in last_string.
|
||||
-- No exception raised!
|
||||
require
|
||||
readable: readable
|
||||
socket_exists: exists
|
||||
local
|
||||
ext: C_STRING
|
||||
retval: INTEGER
|
||||
l: like last_string
|
||||
do
|
||||
create ext.make_empty (nb_char + 1)
|
||||
retval := c_recv_noexception (descriptor, ext.item, nb_char, c_peekmsg)
|
||||
if retval = 0 then
|
||||
last_string.wipe_out
|
||||
socket_error := Void
|
||||
elseif retval > 0 then
|
||||
ext.set_count (retval)
|
||||
l := last_string
|
||||
l.wipe_out
|
||||
l.grow (retval)
|
||||
l.set_count (retval)
|
||||
ext.read_substring_into (l, 1, retval)
|
||||
socket_error := Void
|
||||
else
|
||||
last_string.wipe_out
|
||||
socket_error := "Socket error (MSG_PEEK)"
|
||||
end
|
||||
ensure
|
||||
last_string_not_void: last_string /= Void
|
||||
end
|
||||
|
||||
feature {NONE} -- Input
|
||||
|
||||
read_into_pointer_noexception (p: POINTER; start_pos, nb_bytes: INTEGER_32)
|
||||
-- Read at most `nb_bytes' bound bytes and make result
|
||||
-- available in `p' at position `start_pos'.
|
||||
-- No exception raised!
|
||||
require
|
||||
p_not_void: p /= default_pointer
|
||||
nb_bytes_non_negative: nb_bytes >= 0
|
||||
is_readable: readable
|
||||
local
|
||||
l_read: INTEGER_32
|
||||
l_last_read: INTEGER_32
|
||||
do
|
||||
from
|
||||
l_last_read := 1
|
||||
until
|
||||
l_read = nb_bytes or l_last_read <= 0
|
||||
loop
|
||||
l_last_read := c_read_stream_noexception (descriptor, nb_bytes - l_read, p + start_pos + l_read)
|
||||
if l_last_read >= 0 then
|
||||
l_read := l_read + l_last_read
|
||||
end
|
||||
end
|
||||
bytes_read := l_read
|
||||
ensure
|
||||
bytes_read_updated: 0 <= bytes_read and bytes_read <= nb_bytes
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
bytes_sent: INTEGER
|
||||
-- Last number of bytes sent by `put_managed_pointer_noexception' (i.e `put_pointer_content_noexception').
|
||||
|
||||
put_managed_pointer_noexception (p: MANAGED_POINTER; start_pos, nb_bytes: INTEGER_32)
|
||||
-- Put data of length `nb_bytes' pointed by `start_pos' index in `p' at
|
||||
-- current position.
|
||||
-- Update `bytes_sent'.
|
||||
-- No exception raised!
|
||||
require
|
||||
p_not_void: p /= Void
|
||||
p_large_enough: p.count >= nb_bytes + start_pos
|
||||
nb_bytes_non_negative: nb_bytes >= 0
|
||||
extendible: extendible
|
||||
do
|
||||
put_pointer_content_noexception (p.item, start_pos, nb_bytes)
|
||||
end
|
||||
|
||||
put_pointer_content_noexception (a_pointer: POINTER; a_offset, a_byte_count: INTEGER)
|
||||
-- Write `a_byte_count' bytes to the socket.
|
||||
-- The data is taken from the memory area pointed to by `a_pointer', at offset `a_offset'.
|
||||
-- Update `bytes_sent'.
|
||||
-- No exception raised!
|
||||
require
|
||||
pointer_not_void: a_pointer /= default_pointer
|
||||
byte_count_non_negative: a_byte_count >= 0
|
||||
extendible: extendible
|
||||
local
|
||||
l_sent: INTEGER_32
|
||||
l_last_sent: INTEGER_32
|
||||
do
|
||||
from
|
||||
l_last_sent := 1
|
||||
until
|
||||
l_sent = a_byte_count or l_last_sent <= 0
|
||||
loop
|
||||
l_last_sent := c_put_stream_noexception (descriptor, a_pointer + a_offset + l_sent, a_byte_count - l_sent)
|
||||
if l_last_sent >= 0 then
|
||||
l_sent := l_sent + l_last_sent
|
||||
elseif l_sent < a_byte_count then
|
||||
socket_error := "No all bytes sent!"
|
||||
end
|
||||
end
|
||||
bytes_sent := l_sent
|
||||
ensure
|
||||
bytes_sent_updated: not was_error implies (0 <= bytes_sent and bytes_sent <= a_byte_count)
|
||||
end
|
||||
|
||||
put_character_noexception (c: CHARACTER)
|
||||
-- Write character `c' to socket.
|
||||
do
|
||||
socket_buffer.put_character (c, 0)
|
||||
put_managed_pointer_noexception (socket_buffer, 0, character_8_bytes)
|
||||
end
|
||||
|
||||
put_readable_string_8_noexception (s: READABLE_STRING_8)
|
||||
-- Write readable string `s' to socket.
|
||||
-- No exception raised!
|
||||
local
|
||||
ext: C_STRING
|
||||
do
|
||||
create ext.make (s)
|
||||
put_managed_pointer_noexception (ext.managed_data, 0, s.count)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
has_incoming_data: BOOLEAN
|
||||
-- Check if Current has available data to be read.
|
||||
-- note: no data will not be removed from the queue.
|
||||
require
|
||||
socket_exists: exists
|
||||
do
|
||||
peek_stream_noexception (1)
|
||||
Result := last_string.count = 1
|
||||
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
|
||||
13
library/server/httpd/network/httpd_stream_socket_ext.e
Normal file
13
library/server/httpd/network/httpd_stream_socket_ext.e
Normal file
@@ -0,0 +1,13 @@
|
||||
note
|
||||
description: "[
|
||||
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTPD_STREAM_SOCKET_EXT
|
||||
|
||||
feature {NONE} -- No-Exception network operation
|
||||
|
||||
end
|
||||
149
library/server/httpd/network/ssl/httpd_stream_ssl_socket.e
Normal file
149
library/server/httpd/network/ssl/httpd_stream_ssl_socket.e
Normal file
@@ -0,0 +1,149 @@
|
||||
note
|
||||
description: "SSL tcp stream socket."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_STREAM_SSL_SOCKET
|
||||
|
||||
inherit
|
||||
HTTPD_STREAM_SOCKET
|
||||
undefine
|
||||
make_empty, make_from_descriptor_and_address,
|
||||
error_number,
|
||||
readstream, read_stream,
|
||||
read_into_pointer,
|
||||
read_to_managed_pointer,
|
||||
put_pointer_content,
|
||||
write, send,
|
||||
close_socket,
|
||||
connect, shutdown,
|
||||
do_accept
|
||||
redefine
|
||||
put_managed_pointer,
|
||||
read_stream_noexception,
|
||||
read_into_pointer_noexception,
|
||||
put_pointer_content_noexception
|
||||
end
|
||||
|
||||
SSL_NETWORK_STREAM_SOCKET
|
||||
redefine
|
||||
put_managed_pointer -- Redefine to allow support of compiler before 16.11.
|
||||
end
|
||||
|
||||
HTTPD_STREAM_SSL_SOCKET_EXT
|
||||
|
||||
create
|
||||
make, make_empty,
|
||||
make_client_by_port, make_client_by_address_and_port,
|
||||
make_server_by_port, make_server_by_address_and_port, make_loopback_server_by_port
|
||||
|
||||
create {SSL_NETWORK_STREAM_SOCKET}
|
||||
make_from_descriptor_and_address
|
||||
|
||||
feature -- Input
|
||||
|
||||
read_stream_noexception (nb_char: INTEGER)
|
||||
-- Read a string of at most `nb_char' characters.
|
||||
-- Make result available in `last_string'.
|
||||
local
|
||||
ext: C_STRING
|
||||
return_val: INTEGER
|
||||
do
|
||||
if
|
||||
attached context as l_context and then
|
||||
attached l_context.last_ssl as l_ssl
|
||||
then
|
||||
create ext.make_empty (nb_char + 1)
|
||||
return_val := l_ssl.read (ext.item , nb_char)
|
||||
bytes_read := return_val
|
||||
if return_val >= 0 then
|
||||
ext.set_count (return_val)
|
||||
last_string := ext.substring (1, return_val)
|
||||
else
|
||||
socket_error := "Peer error [0x" + return_val.to_hex_string + "]"
|
||||
last_string.wipe_out
|
||||
end
|
||||
else
|
||||
check has_context: False end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Input
|
||||
|
||||
read_into_pointer_noexception (p: POINTER; start_pos, nb_bytes: INTEGER_32)
|
||||
-- Read at most `nb_bytes' bound bytes and make result
|
||||
-- available in `p' at position `start_pos'.
|
||||
-- No exception raised!
|
||||
local
|
||||
l_read: INTEGER
|
||||
l_last_read: INTEGER
|
||||
do
|
||||
if
|
||||
attached context as l_context and then
|
||||
attached l_context.last_ssl as l_ssl
|
||||
then
|
||||
from
|
||||
l_last_read := 1
|
||||
until
|
||||
l_read = nb_bytes or l_last_read <= 0
|
||||
loop
|
||||
l_last_read := l_ssl.read (p + start_pos + l_read, nb_bytes - l_read)
|
||||
if l_last_read >= 0 then
|
||||
l_read := l_read + l_last_read
|
||||
end
|
||||
end
|
||||
bytes_read := l_read
|
||||
else
|
||||
check has_context: False end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
put_managed_pointer (p: MANAGED_POINTER; start_pos, nb_bytes: INTEGER)
|
||||
-- Put data of length `nb_bytes' pointed by `start_pos' index in `p' at
|
||||
-- current position.
|
||||
do
|
||||
Precursor {HTTPD_STREAM_SOCKET} (p, start_pos, nb_bytes)
|
||||
end
|
||||
|
||||
put_pointer_content_noexception (a_pointer: POINTER; a_offset, a_byte_count: INTEGER)
|
||||
-- Write `a_byte_count' bytes to the socket.
|
||||
-- The data is taken from the memory area pointed to by `a_pointer', at offset `a_offset'.
|
||||
-- Update `bytes_sent'.
|
||||
-- No exception raised!
|
||||
local
|
||||
l_bytes_sent: INTEGER
|
||||
do
|
||||
if
|
||||
attached context as l_context and then
|
||||
attached l_context.last_ssl as l_ssl
|
||||
then
|
||||
l_bytes_sent := ssl_write (l_ssl, a_pointer + a_offset, a_byte_count)
|
||||
if l_bytes_sent < a_byte_count then
|
||||
socket_error := "No all bytes sent!"
|
||||
end
|
||||
bytes_sent := l_bytes_sent
|
||||
else
|
||||
check has_last_ssl: False end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_certificate_filenames (a_crt_filename, a_key_filename: detachable READABLE_STRING_GENERAL)
|
||||
do
|
||||
if a_crt_filename /= Void then
|
||||
set_certificate_file_name (a_crt_filename)
|
||||
end
|
||||
if a_key_filename /= Void then
|
||||
set_key_file_name (a_key_filename)
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
note
|
||||
description: "[
|
||||
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTPD_STREAM_SSL_SOCKET_EXT
|
||||
|
||||
feature {NONE} -- SSL bridge
|
||||
|
||||
ssl_write (a_ssl: SSL; a_pointer: POINTER; a_byte_count: INTEGER): INTEGER
|
||||
do
|
||||
Result := a_ssl.write (a_pointer, a_byte_count)
|
||||
if a_ssl.was_error then
|
||||
if Result >= 0 then
|
||||
Result := -1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,160 @@
|
||||
note
|
||||
description: "[
|
||||
Until 16.05, the EiffelNet socket interface DOES NOT have
|
||||
- make_server_by_address_and_port
|
||||
- recv_timeout
|
||||
- send_timeout.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTPD_STREAM_SOCKET_EXT
|
||||
|
||||
inherit
|
||||
PLATFORM
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make
|
||||
deferred
|
||||
end
|
||||
|
||||
make_server_by_address_and_port (a_address: INET_ADDRESS; a_port: INTEGER)
|
||||
-- Create server socket on `a_address' and `a_port'.
|
||||
require
|
||||
valid_port: a_port >= 0
|
||||
do
|
||||
make
|
||||
set_address (create {like address_type}.make_from_address_and_port (a_address, a_port))
|
||||
bind
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
bind
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
set_address (addr: detachable like address_type)
|
||||
deferred
|
||||
end
|
||||
|
||||
address_type: NETWORK_SOCKET_ADDRESS
|
||||
deferred
|
||||
end
|
||||
|
||||
descriptor: INTEGER
|
||||
-- Socket descriptor of current socket
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Socket Recv and Send timeout.
|
||||
|
||||
set_recv_timeout (a_timeout_seconds: INTEGER)
|
||||
-- Set the receive timeout in seconds on Current socket.
|
||||
-- if `0' the related operations will never timeout.
|
||||
require
|
||||
positive_timeout: a_timeout_seconds >= 0
|
||||
do
|
||||
c_set_sock_recv_timeout (descriptor, level_sol_socket, a_timeout_seconds)
|
||||
end
|
||||
|
||||
set_send_timeout (a_timeout_seconds: INTEGER)
|
||||
-- Set the send timeout in milliseconds on Current socket.
|
||||
-- if `0' the related operations will never timeout.
|
||||
require
|
||||
positive_timeout: a_timeout_seconds >= 0
|
||||
do
|
||||
c_set_sock_send_timeout (descriptor, level_sol_socket, a_timeout_seconds)
|
||||
end
|
||||
|
||||
feature {NONE} -- Externals
|
||||
|
||||
level_sol_socket: INTEGER
|
||||
-- SOL_SOCKET level of options
|
||||
deferred
|
||||
end
|
||||
|
||||
c_set_sock_recv_timeout (a_fd, a_level: INTEGER; a_timeout_seconds: INTEGER)
|
||||
-- C routine to set socket option `SO_RCVTIMEO' with `a_timeout_seconds' seconds.
|
||||
external
|
||||
"C inline use %"ew_httpd_net.h%""
|
||||
alias
|
||||
"[
|
||||
#ifdef SO_RCVTIMEO
|
||||
int flag = SO_RCVTIMEO;
|
||||
#else
|
||||
int flag = 0x1006;
|
||||
#endif
|
||||
|
||||
#ifdef EIF_WINDOWS
|
||||
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (char *) &arg, sizeof(arg));
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
||||
tv.tv_usec = 0;
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (struct timeval *)&tv, sizeof(struct timeval));
|
||||
#endif
|
||||
]"
|
||||
end
|
||||
|
||||
c_set_sock_send_timeout (a_fd, a_level: INTEGER; a_timeout_seconds: INTEGER)
|
||||
-- C routine to set socket option `SO_SNDTIMEO' with `a_timeout_seconds' seconds.
|
||||
external
|
||||
"C inline use %"ew_httpd_net.h%""
|
||||
alias
|
||||
"[
|
||||
#ifdef SO_RCVTIMEO
|
||||
int flag = SO_SNDTIMEO;
|
||||
#else
|
||||
int flag = 0x1005;
|
||||
#endif
|
||||
#ifdef EIF_WINDOWS
|
||||
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (char *) &arg, sizeof(arg));
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
||||
tv.tv_usec = 0;
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (struct timeval *)&tv, sizeof(struct timeval));
|
||||
#endif
|
||||
]"
|
||||
end
|
||||
|
||||
feature {NONE} -- No-Exception network operation
|
||||
|
||||
c_recv_noexception (a_fd: INTEGER; buf: POINTER; len: INTEGER; flags: INTEGER): INTEGER
|
||||
-- External routine to read a `len' number of characters
|
||||
-- into buffer `buf' from socket `a_fd' with options `flags'.
|
||||
external
|
||||
"C inline use %"ew_httpd_net.h%""
|
||||
alias
|
||||
"[
|
||||
recv((int) $a_fd, (char *) $buf, (int) $len, (int) $flags)
|
||||
]"
|
||||
end
|
||||
|
||||
c_read_stream_noexception (a_fd: INTEGER; len: INTEGER; buf: POINTER): INTEGER
|
||||
-- External routine to read a `len' number of characters
|
||||
-- into buffer `buf' from socket `a_fd'.
|
||||
do
|
||||
Result := c_recv_noexception (a_fd, buf, len, 0)
|
||||
end
|
||||
|
||||
c_put_stream_noexception (a_fd: INTEGER; buf: POINTER; len: INTEGER): INTEGER
|
||||
-- External routine to write stream pointed by `s' of
|
||||
-- length `length' to socket `fd'.
|
||||
-- Note: does not raise exception on error, but return error value as Result.
|
||||
external
|
||||
"C inline use %"ew_httpd_net.h%""
|
||||
alias
|
||||
"[
|
||||
send((int) $a_fd, (char *) $buf, (int) $len, (int) 0)
|
||||
]"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
note
|
||||
description: "[
|
||||
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTPD_STREAM_SSL_SOCKET_EXT
|
||||
|
||||
feature {NONE} -- SSL bridge
|
||||
|
||||
ssl_write (a_ssl: SSL; a_pointer: POINTER; a_byte_count: INTEGER): INTEGER
|
||||
do
|
||||
-- In delivery until 16.05
|
||||
-- SSL.write does not return any value!
|
||||
-- So let's use `c_ssl_write' from Current class
|
||||
-- instead of:
|
||||
-- a_ssl.write (a_pointer, a_byte_count)
|
||||
|
||||
Result := c_ssl_write (a_ssl.ptr, a_pointer, a_byte_count)
|
||||
if a_ssl.was_error then
|
||||
-- Until 16.05, there is no error check for `SSL.write'
|
||||
-- so nothing can be done here.
|
||||
|
||||
if Result >= 0 then
|
||||
Result := -1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
c_ssl_write (an_ssl_ptr: POINTER; buffer: POINTER; nb_bytes: INTEGER_32): INTEGER_32
|
||||
-- External call to SSL_write
|
||||
-- (export status {NONE})
|
||||
external
|
||||
"C use %"eif_openssl.h%""
|
||||
alias
|
||||
"SSL_write"
|
||||
end
|
||||
|
||||
end
|
||||
66
library/server/httpd/no_ssl/httpd_configuration.e
Normal file
66
library/server/httpd/no_ssl/httpd_configuration.e
Normal file
@@ -0,0 +1,66 @@
|
||||
note
|
||||
description: "Standalone server configuration (ssl NOT supported)."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONFIGURATION
|
||||
|
||||
inherit
|
||||
HTTPD_CONFIGURATION_I
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Status
|
||||
|
||||
Server_details: STRING_8 = "Server: Standalone 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_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
|
||||
27
library/server/httpd/no_ssl/httpd_server.e
Normal file
27
library/server/httpd/no_ssl/httpd_server.e
Normal file
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "[
|
||||
httpd server
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_SERVER
|
||||
|
||||
inherit
|
||||
HTTPD_SERVER_I
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
17
library/server/httpd/no_ssl/httpd_socket_factory.e
Normal file
17
library/server/httpd/no_ssl/httpd_socket_factory.e
Normal file
@@ -0,0 +1,17 @@
|
||||
note
|
||||
description: "Summary description for {HTTPD_SOCKET_FACTORY}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_SOCKET_FACTORY
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_client_socket (a_is_secure: BOOLEAN): HTTPD_STREAM_SOCKET
|
||||
do
|
||||
check not_secure: not a_is_secure end
|
||||
create Result.make_empty
|
||||
end
|
||||
|
||||
end
|
||||
20
library/server/httpd/package.iron
Normal file
20
library/server/httpd/package.iron
Normal file
@@ -0,0 +1,20 @@
|
||||
package httpd
|
||||
|
||||
project
|
||||
httpd = "httpd-safe.ecf"
|
||||
httpd = "httpd.ecf"
|
||||
|
||||
note
|
||||
title: HTTP server
|
||||
description: "[
|
||||
Simple HTTP listener and handler, that can be extended easily.
|
||||
]"
|
||||
tags: http,httpd,server,web
|
||||
collection: EWF
|
||||
copyright: 2011-2016, 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)
|
||||
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||
link[source]: "Github" https://github.com/EiffelWebFramework/EWF/library/server/httpd
|
||||
link[doc]: "Documentation" http://eiffelwebframework.github.io/EWF/
|
||||
|
||||
end
|
||||
52
library/server/httpd/spec/include_until_16_05/ew_httpd_net.h
Normal file
52
library/server/httpd/spec/include_until_16_05/ew_httpd_net.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
indexing
|
||||
description: "Functions used by the EiffelWeb httpd networking classes. "
|
||||
copyright: "Copyright (c) 2011-2016, Jocelyn Fiat, 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
|
||||
]"
|
||||
*/
|
||||
|
||||
#ifndef _ew_httpd_net_h_
|
||||
#define _ew_httpd_net_h_
|
||||
|
||||
#include "eif_config.h"
|
||||
|
||||
#ifdef EIF_WINDOWS
|
||||
# ifndef _WINSOCKAPI_
|
||||
# define FD_SETSIZE 256
|
||||
# include <winsock2.h>
|
||||
# include <Ws2tcpip.h>
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
#else /* unix-specific */
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* extern declarations ... */
|
||||
#ifdef EIF_WINDOWS
|
||||
extern int setsockopt(int, int, int, char*, int);
|
||||
extern int recv(int, char *, int, int);
|
||||
extern int send(int, char *, int, int);
|
||||
#else
|
||||
extern int setsockopt(int, int, int, const void*, socklen_t);
|
||||
extern ssize_t recv(int, void *, size_t, int);
|
||||
extern ssize_t send(int, const void *, size_t, int);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
79
library/server/httpd/ssl/httpd_configuration.e
Normal file
79
library/server/httpd/ssl/httpd_configuration.e
Normal file
@@ -0,0 +1,79 @@
|
||||
note
|
||||
description: "Standalone server configuration (ssl supported)."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONFIGURATION
|
||||
|
||||
inherit
|
||||
HTTPD_CONFIGURATION_I
|
||||
redefine
|
||||
make
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Create a new instance and set ssl protocol to tls_1_2.
|
||||
do
|
||||
Precursor
|
||||
set_ssl_protocol_to_tls_1_2
|
||||
ensure then
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.tls_1_2
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
Server_details: STRING_8 = "Server: Standalone 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_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
|
||||
41
library/server/httpd/ssl/httpd_server.e
Normal file
41
library/server/httpd/ssl/httpd_server.e
Normal file
@@ -0,0 +1,41 @@
|
||||
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
|
||||
local
|
||||
s_ssl: HTTPD_STREAM_SSL_SOCKET
|
||||
do
|
||||
if configuration.is_secure then
|
||||
if a_addr /= Void then
|
||||
create s_ssl.make_server_by_address_and_port (a_addr, a_http_port)
|
||||
Result := s_ssl
|
||||
else
|
||||
create s_ssl.make_server_by_port (a_http_port)
|
||||
end
|
||||
s_ssl.set_tls_protocol (configuration.ssl_protocol)
|
||||
s_ssl.set_certificate_filenames (configuration.ca_crt, configuration.ca_key)
|
||||
Result := s_ssl
|
||||
else
|
||||
Result := Precursor (a_addr, a_http_port)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
20
library/server/httpd/ssl/httpd_socket_factory.e
Normal file
20
library/server/httpd/ssl/httpd_socket_factory.e
Normal file
@@ -0,0 +1,20 @@
|
||||
note
|
||||
description: "Summary description for {HTTPD_SOCKET_FACTORY}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_SOCKET_FACTORY
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_client_socket (a_is_secure: BOOLEAN): HTTPD_STREAM_SOCKET
|
||||
do
|
||||
if a_is_secure then
|
||||
create {HTTPD_STREAM_SSL_SOCKET} Result.make_empty
|
||||
else
|
||||
create Result.make_empty
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user