Improved networking implementation for httpd server and sockets.
Use new EiffelNet routines that do not raise exception on error. Made compilable with 16.05 and dev-and-upcoming release 16.11. Fixed various minor issues related to base_url, and added comments.
This commit is contained in:
@@ -18,21 +18,36 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</library>
|
</library>
|
||||||
<cluster name="network" location=".\network\">
|
<cluster name="network" location=".\network\">
|
||||||
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
<file_rule>
|
||||||
<condition>
|
<exclude>/httpd_stream_socket_ext.e$</exclude>
|
||||||
<custom name="net_ssl_enabled" value="true"/>
|
|
||||||
</condition>
|
|
||||||
</cluster>
|
|
||||||
<cluster name="network_until_16_05" location="$|until_16_05\">
|
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="16.11.0.0"/>
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</file_rule>
|
||||||
<cluster name="network_from_16_11" location="$|from_16_11\">
|
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" min="16.11.0.0"/>
|
<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="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="httpd_ssl_enabled" value="true"/>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|
||||||
</target>
|
</target>
|
||||||
</system>
|
</system>
|
||||||
|
|||||||
@@ -19,19 +19,33 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</library>
|
</library>
|
||||||
<cluster name="network" location=".\network\">
|
<cluster name="network" location=".\network\">
|
||||||
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
<file_rule>
|
||||||
<condition>
|
<exclude>/httpd_stream_socket_ext.e$</exclude>
|
||||||
<custom name="net_ssl_enabled" value="true"/>
|
|
||||||
</condition>
|
|
||||||
</cluster>
|
|
||||||
<cluster name="network_until_16_05" location="$|until_16_05\">
|
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="16.11.0.0"/>
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</file_rule>
|
||||||
<cluster name="network_from_16_11" location="$|from_16_11\">
|
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" min="16.11.0.0"/>
|
<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="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="httpd_ssl_enabled" value="true"/>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -11,6 +11,16 @@
|
|||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="scoop"/>
|
<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="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
||||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
||||||
@@ -24,29 +34,12 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</library>
|
</library>
|
||||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
<cluster name="network" location=".\network" recursive="false">
|
|
||||||
<cluster name="ssl_network" location="$|ssl" recursive="true">
|
|
||||||
<condition>
|
|
||||||
<custom name="httpd_ssl_enabled" value="true"/>
|
|
||||||
</condition>
|
|
||||||
</cluster>
|
|
||||||
<cluster name="network_until_16_05" location="$|until_16_05\">
|
|
||||||
<condition>
|
|
||||||
<version type="compiler" max="16.11.0.0"/>
|
|
||||||
</condition>
|
|
||||||
</cluster>
|
|
||||||
<cluster name="network_from_16_11" location="$|from_16_11\">
|
|
||||||
<condition>
|
|
||||||
<version type="compiler" min="16.11.0.0"/>
|
|
||||||
</condition>
|
|
||||||
</cluster>
|
|
||||||
</cluster>
|
|
||||||
<cluster name="httpd_server" location=".\" recursive="true">
|
<cluster name="httpd_server" location=".\" recursive="true">
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/concurrency$</exclude>
|
<exclude>/concurrency$</exclude>
|
||||||
|
<exclude>/network$</exclude>
|
||||||
<exclude>/no_ssl$</exclude>
|
<exclude>/no_ssl$</exclude>
|
||||||
<exclude>/ssl$</exclude>
|
<exclude>/ssl$</exclude>
|
||||||
<exclude>/network$</exclude>
|
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
@@ -74,5 +67,36 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
<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="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="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="httpd_ssl_enabled" value="true"/>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
</system>
|
</system>
|
||||||
|
|||||||
@@ -23,20 +23,34 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</library>
|
</library>
|
||||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
<cluster name="network" location=".\network" recursive="false">
|
<cluster name="network" location=".\network\">
|
||||||
<cluster name="ssl_network" location="$|ssl" recursive="true">
|
<file_rule>
|
||||||
<condition>
|
<exclude>/httpd_stream_socket_ext.e$</exclude>
|
||||||
<custom name="httpd_ssl_enabled" value="true"/>
|
|
||||||
</condition>
|
|
||||||
</cluster>
|
|
||||||
<cluster name="network_until_16_05" location="$|until_16_05\">
|
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="16.11.0.0"/>
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</file_rule>
|
||||||
<cluster name="network_from_16_11" location="$|from_16_11\">
|
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" min="16.11.0.0"/>
|
<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="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="httpd_ssl_enabled" value="true"/>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ feature -- Settings
|
|||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
has_error: BOOLEAN
|
has_error: BOOLEAN
|
||||||
-- Error occurred during `analyze_request_message'
|
-- Error occurred during `get_request_header'
|
||||||
|
|
||||||
feature -- Status change
|
feature -- Status change
|
||||||
|
|
||||||
@@ -208,11 +208,21 @@ feature -- Execution
|
|||||||
is_connected: is_connected
|
is_connected: is_connected
|
||||||
local
|
local
|
||||||
l_socket: like client_socket
|
l_socket: like client_socket
|
||||||
|
l_remote_info: detachable like remote_info
|
||||||
l_exit: BOOLEAN
|
l_exit: BOOLEAN
|
||||||
n,m: INTEGER
|
n,m: INTEGER
|
||||||
do
|
do
|
||||||
l_socket := client_socket
|
l_socket := client_socket
|
||||||
l_socket.set_recv_timeout (socket_recv_timeout)
|
|
||||||
|
-- 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
|
check
|
||||||
socket_attached: l_socket /= Void
|
socket_attached: l_socket /= Void
|
||||||
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
|
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
|
||||||
@@ -252,9 +262,7 @@ feature -- Execution
|
|||||||
reuse_connection_when_possible: a_is_reusing_connection implies is_persistent_connection_supported
|
reuse_connection_when_possible: a_is_reusing_connection implies is_persistent_connection_supported
|
||||||
no_error: not has_error
|
no_error: not has_error
|
||||||
local
|
local
|
||||||
l_remote_info: detachable like remote_info
|
|
||||||
l_socket: like client_socket
|
l_socket: like client_socket
|
||||||
l_is_ready: BOOLEAN
|
|
||||||
do
|
do
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
if a_is_reusing_connection then
|
if a_is_reusing_connection then
|
||||||
@@ -276,50 +284,34 @@ feature -- Execution
|
|||||||
dbglog ("execute_request socket=" + l_socket.descriptor.out + " ENTER")
|
dbglog ("execute_request socket=" + l_socket.descriptor.out + " ENTER")
|
||||||
end
|
end
|
||||||
|
|
||||||
if a_is_reusing_connection then
|
-- Try to get request header.
|
||||||
--| set by default 5 seconds.
|
-- If the request is reusing persistent connection, use `keep_alive_timeout',
|
||||||
l_socket.set_recv_timeout (keep_alive_timeout) -- in seconds!
|
-- otherwise `socket_recv_timeout'.
|
||||||
l_is_ready := socket_has_incoming_data (l_socket)
|
get_request_header (l_socket, a_is_reusing_connection)
|
||||||
else
|
|
||||||
l_is_ready := True
|
|
||||||
end
|
|
||||||
|
|
||||||
if l_is_ready then
|
if has_error then
|
||||||
l_socket.set_recv_timeout (socket_recv_timeout) -- FIXME: return a 408 Request Timeout response ..
|
if a_is_reusing_connection and then request_header.is_empty then
|
||||||
create l_remote_info
|
-- Close persistent connection, since no new connection occurred in the delay `keep_alive_timeout'.
|
||||||
if attached l_socket.peer_address as l_addr then
|
debug ("dbglog")
|
||||||
l_remote_info.addr := l_addr.host_address.host_address
|
dbglog ("execute_request socket=" + l_socket.descriptor.out + "} close persistent connection.")
|
||||||
l_remote_info.hostname := l_addr.host_address.host_name
|
end
|
||||||
l_remote_info.port := l_addr.port
|
else
|
||||||
remote_info := l_remote_info
|
|
||||||
end
|
|
||||||
analyze_request_message (l_socket)
|
|
||||||
|
|
||||||
if has_error then
|
|
||||||
-- check catch_bad_incoming_connection: False end
|
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log (request_header + "%NWARNING: invalid HTTP incoming request", warning_level)
|
log (request_header + "%NWARNING: invalid HTTP incoming request", warning_level)
|
||||||
end
|
end
|
||||||
process_bad_request (l_socket)
|
process_bad_request (l_socket)
|
||||||
is_persistent_connection_requested := False
|
end
|
||||||
else
|
is_persistent_connection_requested := False
|
||||||
if is_verbose then
|
else
|
||||||
log (request_header, information_level)
|
if is_verbose then
|
||||||
end
|
log (request_header, information_level)
|
||||||
process_request (l_socket)
|
end
|
||||||
end
|
process_request (l_socket)
|
||||||
else
|
|
||||||
check is_reusing_connection: a_is_reusing_connection end
|
|
||||||
-- Close persistent connection, since no new connection occurred in the delay `keep_alive_timeout'.
|
|
||||||
is_persistent_connection_requested := False
|
|
||||||
debug ("dbglog")
|
|
||||||
dbglog ("execute_request socket=" + l_socket.descriptor.out + "} close persistent connection.")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
dbglog ("execute_request {" + l_socket.descriptor.out + "} LEAVE")
|
dbglog ("execute_request {" + l_socket.descriptor.out + "} LEAVE")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -377,8 +369,11 @@ feature -- Request processing
|
|||||||
|
|
||||||
feature -- Parsing
|
feature -- Parsing
|
||||||
|
|
||||||
analyze_request_message (a_socket: HTTPD_STREAM_SOCKET)
|
get_request_header (a_socket: HTTPD_STREAM_SOCKET; a_is_reusing_connection: BOOLEAN)
|
||||||
-- Analyze message extracted from `a_socket' as HTTP request
|
-- 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
|
require
|
||||||
input_readable: a_socket /= Void and then a_socket.is_open_read
|
input_readable: a_socket /= Void and then a_socket.is_open_read
|
||||||
local
|
local
|
||||||
@@ -391,76 +386,90 @@ feature -- Parsing
|
|||||||
do
|
do
|
||||||
create txt.make (64)
|
create txt.make (64)
|
||||||
request_header := txt
|
request_header := txt
|
||||||
|
l_is_verbose := is_verbose
|
||||||
|
|
||||||
if
|
if
|
||||||
not has_error and then
|
not has_error and then
|
||||||
a_socket.readable
|
a_socket.readable
|
||||||
then
|
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
|
if
|
||||||
attached next_line (a_socket) as l_request_line and then
|
attached next_line (a_socket) as l_request_line and then
|
||||||
not l_request_line.is_empty
|
not l_request_line.is_empty and then
|
||||||
|
not has_error
|
||||||
then
|
then
|
||||||
txt.append (l_request_line)
|
txt.append (l_request_line)
|
||||||
txt.append_character ('%N')
|
txt.append_character ('%N')
|
||||||
analyze_request_line (l_request_line)
|
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
|
else
|
||||||
report_error ("Bad header line (empty)")
|
report_error ("Bad header line (empty)")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
report_error ("Socket is not readable")
|
report_error ("Socket is not readable")
|
||||||
end
|
end
|
||||||
l_is_verbose := is_verbose
|
|
||||||
if not has_error then
|
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
analyze_request_line (line: STRING)
|
analyze_request_line (line: STRING)
|
||||||
-- Analyze `line' as a HTTP request line
|
-- Analyze `line' as a HTTP request line.
|
||||||
|
-- note: may update `has_error'.
|
||||||
require
|
require
|
||||||
valid_line: line /= Void and then not line.is_empty
|
valid_line: line /= Void and then not line.is_empty
|
||||||
local
|
local
|
||||||
@@ -488,21 +497,19 @@ feature -- Parsing
|
|||||||
|
|
||||||
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
|
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
|
||||||
-- Next line fetched from `a_socket' is available.
|
-- Next line fetched from `a_socket' is available.
|
||||||
|
-- note: may update `has_error'.
|
||||||
require
|
require
|
||||||
not_has_error: not has_error or is_verbose
|
not_has_error: not has_error
|
||||||
is_readable: a_socket.is_open_read
|
is_readable: a_socket.is_open_read
|
||||||
local
|
local
|
||||||
retried: BOOLEAN
|
retried: BOOLEAN
|
||||||
do
|
do
|
||||||
if retried then
|
if retried then
|
||||||
report_error ("Rescue in next_line")
|
report_error ("Rescue in next_line")
|
||||||
|
a_socket.close
|
||||||
Result := Void
|
Result := Void
|
||||||
elseif
|
elseif a_socket.readable then
|
||||||
a_socket.readable and then
|
a_socket.read_line_noexception
|
||||||
socket_has_incoming_data (a_socket)
|
|
||||||
then
|
|
||||||
|
|
||||||
a_socket.read_line_thread_aware
|
|
||||||
Result := a_socket.last_string
|
Result := a_socket.last_string
|
||||||
-- Do no check `socket_ok' before socket operation,
|
-- Do no check `socket_ok' before socket operation,
|
||||||
-- otherwise it may be False, due to error during other socket operation in same thread.
|
-- otherwise it may be False, due to error during other socket operation in same thread.
|
||||||
@@ -520,6 +527,7 @@ feature -- Parsing
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
|
-- In case of network error exception (as EiffelNet reports error raising exception)
|
||||||
retried := True
|
retried := True
|
||||||
retry
|
retry
|
||||||
end
|
end
|
||||||
@@ -558,7 +566,9 @@ feature {NONE} -- Helpers
|
|||||||
a_socket.readable
|
a_socket.readable
|
||||||
do
|
do
|
||||||
-- FIXME: check if both are really needed.
|
-- FIXME: check if both are really needed.
|
||||||
Result := a_socket.ready_for_reading and then a_socket.has_incoming_data
|
-- Result := a_socket.ready_for_reading --and then a_socket.has_incoming_data
|
||||||
|
-- Result := a_socket.has_incoming_data
|
||||||
|
Result := True
|
||||||
end
|
end
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
note
|
|
||||||
description: "[
|
|
||||||
Since 16.11, the EiffelNet socket interface has recv_timeout and send_timeout.
|
|
||||||
]"
|
|
||||||
|
|
||||||
deferred class
|
|
||||||
TCP_STREAM_SOCKET_EXT
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,369 +1,235 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "Summary description for {HTTPD_STREAM_SOCKET}."
|
||||||
Summary description for {HTTPD_STREAM_SOCKET}
|
|
||||||
that can be used for http or https connection.
|
|
||||||
]"
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
class
|
class
|
||||||
HTTPD_STREAM_SOCKET
|
HTTPD_STREAM_SOCKET
|
||||||
|
|
||||||
|
inherit
|
||||||
|
NETWORK_STREAM_SOCKET
|
||||||
|
|
||||||
|
HTTPD_STREAM_SOCKET_EXT
|
||||||
|
|
||||||
create
|
create
|
||||||
make_server_by_address_and_port,
|
make, make_empty,
|
||||||
make_server_by_port,
|
make_client_by_port, make_client_by_address_and_port,
|
||||||
make_client_by_address_and_port,
|
make_server_by_port, make_server_by_address_and_port, make_loopback_server_by_port
|
||||||
make_client_by_port,
|
|
||||||
make_from_separate,
|
|
||||||
make_empty
|
|
||||||
|
|
||||||
create {HTTPD_STREAM_SOCKET}
|
create {NETWORK_STREAM_SOCKET}
|
||||||
make
|
make_from_descriptor_and_address
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature -- Input
|
||||||
|
|
||||||
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
read_character_noexception
|
||||||
|
-- Read a new character.
|
||||||
|
-- Make result available in `last_character'.
|
||||||
|
-- No exception raised!
|
||||||
do
|
do
|
||||||
create {TCP_STREAM_SOCKET} socket.make_server_by_address_and_port (an_address, a_port)
|
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
|
end
|
||||||
|
|
||||||
make_server_by_port (a_port: INTEGER)
|
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
|
do
|
||||||
create {TCP_STREAM_SOCKET} socket.make_server_by_port (a_port)
|
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
|
end
|
||||||
|
|
||||||
make_client_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
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
|
do
|
||||||
create {TCP_STREAM_SOCKET} socket.make_client_by_address_and_port (an_address, a_port)
|
read_into_pointer_noexception (p.item, start_pos, nb_bytes)
|
||||||
end
|
end
|
||||||
|
|
||||||
make_client_by_port (a_peer_port: INTEGER; a_peer_host: STRING)
|
read_line_noexception
|
||||||
|
-- Read a line of characters (ended by a new_line).
|
||||||
|
-- No exception raised!
|
||||||
|
local
|
||||||
|
l_last_string: like last_string
|
||||||
do
|
do
|
||||||
create {TCP_STREAM_SOCKET} socket.make_client_by_port (a_peer_port, a_peer_host)
|
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
|
end
|
||||||
|
|
||||||
make_from_separate (s: separate HTTPD_STREAM_SOCKET)
|
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
|
require
|
||||||
descriptor_available: s.descriptor_available
|
readable: readable
|
||||||
|
socket_exists: exists
|
||||||
|
local
|
||||||
|
ext: C_STRING
|
||||||
|
retval: INTEGER
|
||||||
|
l: like last_string
|
||||||
do
|
do
|
||||||
create {TCP_STREAM_SOCKET} socket.make_from_separate (s.socket)
|
create ext.make_empty (nb_char + 1)
|
||||||
end
|
retval := c_recv_noexception (descriptor, ext.item, nb_char, c_peekmsg)
|
||||||
|
if retval = 0 then
|
||||||
make_empty
|
last_string.wipe_out
|
||||||
do
|
socket_error := Void
|
||||||
create {TCP_STREAM_SOCKET} socket.make_empty
|
elseif retval > 0 then
|
||||||
end
|
ext.set_count (retval)
|
||||||
|
l := last_string
|
||||||
retrieve_socket (s: HTTPD_STREAM_SOCKET): INTEGER
|
l.wipe_out
|
||||||
do
|
l.grow (retval)
|
||||||
Result := s.socket.descriptor
|
l.set_count (retval)
|
||||||
end
|
ext.read_substring_into (l, 1, retval)
|
||||||
|
socket_error := Void
|
||||||
feature -- Change
|
else
|
||||||
|
last_string.wipe_out
|
||||||
set_timeout (n: INTEGER)
|
socket_error := "Socket error (MSG_PEEK)"
|
||||||
-- Set timeout to `n' seconds.
|
|
||||||
do
|
|
||||||
if attached {NETWORK_STREAM_SOCKET} socket as l_socket then
|
|
||||||
l_socket.set_timeout (n)
|
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
last_string_not_void: last_string /= Void
|
||||||
end
|
end
|
||||||
|
|
||||||
set_connect_timeout (n: INTEGER)
|
feature {NONE} -- Input
|
||||||
do
|
|
||||||
if attached {NETWORK_STREAM_SOCKET} socket as l_socket then
|
|
||||||
l_socket.set_connect_timeout (n)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
set_accept_timeout (n: INTEGER)
|
read_into_pointer_noexception (p: POINTER; start_pos, nb_bytes: INTEGER_32)
|
||||||
do
|
-- Read at most `nb_bytes' bound bytes and make result
|
||||||
if attached {NETWORK_STREAM_SOCKET} socket as l_socket then
|
-- available in `p' at position `start_pos'.
|
||||||
l_socket.set_accept_timeout (n)
|
-- No exception raised!
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
set_recv_timeout (a_timeout_seconds: INTEGER)
|
|
||||||
-- Set the receive timeout in seconds on Current socket.
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
l_socket.set_recv_timeout (a_timeout_seconds)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
set_send_timeout (a_timeout_seconds: INTEGER)
|
|
||||||
-- Set the send timeout in seconds on Current socket.
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
l_socket.set_send_timeout (a_timeout_seconds)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
last_string: STRING
|
|
||||||
do
|
|
||||||
Result := socket.last_string
|
|
||||||
end
|
|
||||||
|
|
||||||
last_character: CHARACTER
|
|
||||||
do
|
|
||||||
Result := socket.last_character
|
|
||||||
end
|
|
||||||
|
|
||||||
peer_address: detachable NETWORK_SOCKET_ADDRESS
|
|
||||||
-- Peer address of socket
|
|
||||||
do
|
|
||||||
if attached {NETWORK_SOCKET_ADDRESS} socket.peer_address as l_peer_address then
|
|
||||||
Result := l_peer_address
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Input
|
|
||||||
|
|
||||||
read_line_thread_aware
|
|
||||||
do
|
|
||||||
socket.read_line_thread_aware
|
|
||||||
end
|
|
||||||
|
|
||||||
read_stream_thread_aware (nb: INTEGER)
|
|
||||||
do
|
|
||||||
socket.read_stream_thread_aware (nb)
|
|
||||||
end
|
|
||||||
|
|
||||||
read_stream (nb: INTEGER)
|
|
||||||
do
|
|
||||||
socket.read_stream (nb)
|
|
||||||
end
|
|
||||||
|
|
||||||
read_character
|
|
||||||
do
|
|
||||||
socket.read_character
|
|
||||||
end
|
|
||||||
|
|
||||||
peek_stream (nb_char: INTEGER)
|
|
||||||
require
|
require
|
||||||
nb_char_positive: nb_char > 0
|
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
|
do
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
from
|
||||||
l_socket.peek_stream (nb_char)
|
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
|
end
|
||||||
end
|
bytes_read := l_read
|
||||||
|
ensure
|
||||||
bytes_read: INTEGER
|
bytes_read_updated: 0 <= bytes_read and bytes_read <= nb_bytes
|
||||||
do
|
|
||||||
Result := socket.bytes_read
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Output
|
feature -- Output
|
||||||
|
|
||||||
send_message (a_msg: STRING)
|
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
|
do
|
||||||
put_string (a_msg)
|
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
|
end
|
||||||
|
|
||||||
put_readable_string_8 (s: READABLE_STRING_8)
|
put_readable_string_8 (s: READABLE_STRING_8)
|
||||||
-- Write readable string `s' to socket.
|
-- Write readable string `s' to socket.
|
||||||
|
local
|
||||||
|
ext: C_STRING
|
||||||
do
|
do
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_tcp_stream_socket then
|
create ext.make (s)
|
||||||
l_tcp_stream_socket.put_readable_string_8 (s)
|
put_managed_pointer (ext.managed_data, 0, s.count)
|
||||||
else
|
|
||||||
put_string (s)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
put_string (s: STRING)
|
feature -- Status report
|
||||||
do
|
|
||||||
socket.put_string (s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_character (c: CHARACTER)
|
|
||||||
do
|
|
||||||
socket.put_character (c)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status Report
|
|
||||||
|
|
||||||
descriptor_available: BOOLEAN
|
|
||||||
-- Is descriptor available?
|
|
||||||
do
|
|
||||||
Result := socket.descriptor_available
|
|
||||||
end
|
|
||||||
|
|
||||||
descriptor: INTEGER
|
|
||||||
do
|
|
||||||
Result := socket.descriptor
|
|
||||||
end
|
|
||||||
|
|
||||||
port: INTEGER
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.port
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
exists: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.exists
|
|
||||||
end
|
|
||||||
|
|
||||||
is_blocking: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.is_blocking
|
|
||||||
end
|
|
||||||
|
|
||||||
is_bound: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.is_bound
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_connected: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.is_connected
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_created: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached {NETWORK_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.is_created
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
socket_ok: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.socket_ok
|
|
||||||
end
|
|
||||||
|
|
||||||
is_open_read: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.is_open_read
|
|
||||||
end
|
|
||||||
|
|
||||||
is_open_write: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.is_open_write
|
|
||||||
end
|
|
||||||
|
|
||||||
is_closed: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.is_closed
|
|
||||||
end
|
|
||||||
|
|
||||||
is_readable: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.is_readable
|
|
||||||
end
|
|
||||||
|
|
||||||
cleanup
|
|
||||||
do
|
|
||||||
socket.cleanup
|
|
||||||
end
|
|
||||||
|
|
||||||
ready_for_writing: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.ready_for_writing
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
connect
|
|
||||||
do
|
|
||||||
socket.connect
|
|
||||||
end
|
|
||||||
|
|
||||||
close
|
|
||||||
do
|
|
||||||
socket.close
|
|
||||||
end
|
|
||||||
|
|
||||||
listen (a_queue: INTEGER)
|
|
||||||
do
|
|
||||||
socket.listen (a_queue)
|
|
||||||
end
|
|
||||||
|
|
||||||
accept
|
|
||||||
do
|
|
||||||
socket.accept
|
|
||||||
end
|
|
||||||
|
|
||||||
accept_to (other: separate HTTPD_STREAM_SOCKET)
|
|
||||||
-- Accept a new connection on listen socket.
|
|
||||||
-- Socket of accepted connection is available in `other'.
|
|
||||||
do
|
|
||||||
if
|
|
||||||
attached {NETWORK_STREAM_SOCKET} socket as l_socket and then
|
|
||||||
attached {separate NETWORK_STREAM_SOCKET} other.socket as l_other_socket
|
|
||||||
then
|
|
||||||
l_socket.accept_to (l_other_socket)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
set_blocking
|
|
||||||
do
|
|
||||||
socket.set_blocking
|
|
||||||
end
|
|
||||||
|
|
||||||
set_non_blocking
|
|
||||||
do
|
|
||||||
socket.set_non_blocking
|
|
||||||
end
|
|
||||||
|
|
||||||
readable: BOOLEAN
|
|
||||||
do
|
|
||||||
Result := socket.readable
|
|
||||||
end
|
|
||||||
|
|
||||||
has_incoming_data: BOOLEAN
|
has_incoming_data: BOOLEAN
|
||||||
-- Check if Current has available data to be read.
|
-- Check if Current has available data to be read.
|
||||||
-- note: no data will not be removed from the queue.
|
-- note: no data will not be removed from the queue.
|
||||||
|
require
|
||||||
|
socket_exists: exists
|
||||||
do
|
do
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
peek_stream_noexception (1)
|
||||||
Result := l_socket.has_incoming_data
|
Result := last_string.count = 1
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
ready_for_reading: BOOLEAN
|
note
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.ready_for_reading
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
try_ready_for_reading: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.try_ready_for_reading
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
accepted: detachable HTTPD_STREAM_SOCKET
|
|
||||||
do
|
|
||||||
if attached {NETWORK_STREAM_SOCKET} socket.accepted as l_accepted then
|
|
||||||
create Result.make (l_accepted)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {HTTPD_STREAM_SOCKET} -- Implementation
|
|
||||||
|
|
||||||
make (a_socket: STREAM_SOCKET)
|
|
||||||
do
|
|
||||||
socket := a_socket
|
|
||||||
end
|
|
||||||
|
|
||||||
socket: STREAM_SOCKET
|
|
||||||
|
|
||||||
network_stream_socket: detachable NETWORK_STREAM_SOCKET
|
|
||||||
do
|
|
||||||
if attached {NETWORK_STREAM_SOCKET} socket as s then
|
|
||||||
Result := s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
;note
|
|
||||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
@@ -373,4 +239,5 @@ feature {HTTPD_STREAM_SOCKET} -- Implementation
|
|||||||
Website http://www.eiffel.com
|
Website http://www.eiffel.com
|
||||||
Customer support http://support.eiffel.com
|
Customer support http://support.eiffel.com
|
||||||
]"
|
]"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "SSL tcp stream socket."
|
||||||
Summary description for {HTTPD_STREAM_SSL_SOCKET}
|
|
||||||
that can be used for http or https connection.
|
|
||||||
]"
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
@@ -11,159 +8,142 @@ class
|
|||||||
|
|
||||||
inherit
|
inherit
|
||||||
HTTPD_STREAM_SOCKET
|
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
|
redefine
|
||||||
port,
|
put_managed_pointer,
|
||||||
is_bound,
|
read_stream_noexception,
|
||||||
ready_for_writing,
|
read_into_pointer_noexception,
|
||||||
ready_for_reading,
|
put_pointer_content_noexception
|
||||||
try_ready_for_reading,
|
|
||||||
put_readable_string_8,
|
|
||||||
make_empty
|
|
||||||
end
|
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
|
create
|
||||||
make_ssl_server_by_address_and_port, make_ssl_server_by_port,
|
make, make_empty,
|
||||||
make_server_by_address_and_port, make_server_by_port,
|
make_client_by_port, make_client_by_address_and_port,
|
||||||
make_ssl_client_by_address_and_port, make_ssl_client_by_port,
|
make_server_by_port, make_server_by_address_and_port, make_loopback_server_by_port
|
||||||
make_client_by_address_and_port, make_client_by_port,
|
|
||||||
make_empty
|
|
||||||
|
|
||||||
create {HTTPD_STREAM_SOCKET}
|
create {SSL_NETWORK_STREAM_SOCKET}
|
||||||
make
|
make_from_descriptor_and_address
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature -- Input
|
||||||
|
|
||||||
make_ssl_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
read_stream_noexception (nb_char: INTEGER)
|
||||||
|
-- Read a string of at most `nb_char' characters.
|
||||||
|
-- Make result available in `last_string'.
|
||||||
local
|
local
|
||||||
l_socket: SSL_TCP_STREAM_SOCKET
|
ext: C_STRING
|
||||||
|
return_val: INTEGER
|
||||||
do
|
do
|
||||||
create l_socket.make_server_by_address_and_port (an_address, a_port)
|
if
|
||||||
l_socket.set_tls_protocol (a_ssl_protocol)
|
attached context as l_context and then
|
||||||
socket := l_socket
|
attached l_context.last_ssl as l_ssl
|
||||||
set_certificates (a_crt_fn, a_key_fn)
|
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
|
end
|
||||||
|
|
||||||
make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
feature {NONE} -- Input
|
||||||
local
|
|
||||||
l_socket: SSL_TCP_STREAM_SOCKET
|
|
||||||
do
|
|
||||||
create l_socket.make_server_by_port (a_port)
|
|
||||||
l_socket.set_tls_protocol (a_ssl_protocol)
|
|
||||||
socket := l_socket
|
|
||||||
set_certificates (a_crt_fn, a_key_fn)
|
|
||||||
end
|
|
||||||
|
|
||||||
make_ssl_client_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
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
|
local
|
||||||
l_socket: SSL_TCP_STREAM_SOCKET
|
l_read: INTEGER
|
||||||
|
l_last_read: INTEGER
|
||||||
do
|
do
|
||||||
create l_socket.make_client_by_address_and_port (an_address, a_port)
|
if
|
||||||
l_socket.set_tls_protocol (a_ssl_protocol)
|
attached context as l_context and then
|
||||||
socket := l_socket
|
attached l_context.last_ssl as l_ssl
|
||||||
set_certificates (a_crt_fn, a_key_fn)
|
then
|
||||||
end
|
from
|
||||||
|
l_last_read := 1
|
||||||
make_ssl_client_by_port (a_peer_port: INTEGER; a_peer_host: STRING; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
until
|
||||||
local
|
l_read = nb_bytes or l_last_read <= 0
|
||||||
l_socket: SSL_TCP_STREAM_SOCKET
|
loop
|
||||||
do
|
l_last_read := l_ssl.read (p + start_pos + l_read, nb_bytes - l_read)
|
||||||
create l_socket.make_client_by_port (a_peer_port, a_peer_host)
|
if l_last_read >= 0 then
|
||||||
l_socket.set_tls_protocol (a_ssl_protocol)
|
l_read := l_read + l_last_read
|
||||||
socket := l_socket
|
end
|
||||||
set_certificates (a_crt_fn, a_key_fn)
|
end
|
||||||
end
|
bytes_read := l_read
|
||||||
|
else
|
||||||
make_empty
|
check has_context: False end
|
||||||
-- <Precursor>.
|
end
|
||||||
do
|
|
||||||
create {SSL_TCP_STREAM_SOCKET} socket.make_empty
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Output
|
feature -- Output
|
||||||
|
|
||||||
put_readable_string_8 (s: READABLE_STRING_8)
|
put_managed_pointer (p: MANAGED_POINTER; start_pos, nb_bytes: INTEGER)
|
||||||
-- <Precursor>
|
-- Put data of length `nb_bytes' pointed by `start_pos' index in `p' at
|
||||||
|
-- current position.
|
||||||
do
|
do
|
||||||
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
|
Precursor {HTTPD_STREAM_SOCKET} (p, start_pos, nb_bytes)
|
||||||
l_ssl_socket.put_readable_string_8 (s)
|
|
||||||
else
|
|
||||||
Precursor (s)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Status Report
|
put_pointer_content_noexception (a_pointer: POINTER; a_offset, a_byte_count: INTEGER)
|
||||||
|
-- Write `a_byte_count' bytes to the socket.
|
||||||
port: INTEGER
|
-- The data is taken from the memory area pointed to by `a_pointer', at offset `a_offset'.
|
||||||
-- <Precursor>
|
-- Update `bytes_sent'.
|
||||||
|
-- No exception raised!
|
||||||
|
local
|
||||||
|
l_bytes_sent: INTEGER
|
||||||
do
|
do
|
||||||
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
|
if
|
||||||
Result := l_ssl_socket.port
|
attached context as l_context and then
|
||||||
else
|
attached l_context.last_ssl as l_ssl
|
||||||
Result := Precursor
|
then
|
||||||
end
|
l_bytes_sent := ssl_write (l_ssl, a_pointer + a_offset, a_byte_count)
|
||||||
end
|
if l_bytes_sent < a_byte_count then
|
||||||
|
socket_error := "No all bytes sent!"
|
||||||
is_bound: BOOLEAN
|
|
||||||
-- <Precursor>
|
|
||||||
do
|
|
||||||
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
|
|
||||||
Result := l_ssl_socket.is_bound
|
|
||||||
else
|
|
||||||
Result := Precursor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ready_for_writing: BOOLEAN
|
|
||||||
-- <Precursor>
|
|
||||||
do
|
|
||||||
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
|
|
||||||
Result := l_ssl_socket.ready_for_writing
|
|
||||||
else
|
|
||||||
Result := Precursor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ready_for_reading: BOOLEAN
|
|
||||||
-- <Precursor>
|
|
||||||
do
|
|
||||||
if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then
|
|
||||||
Result := l_ssl_socket.ready_for_reading
|
|
||||||
else
|
|
||||||
Result := Precursor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
try_ready_for_reading: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached {SSL_TCP_STREAM_SOCKET} socket as l_socket then
|
|
||||||
Result := l_socket.try_ready_for_reading
|
|
||||||
else
|
|
||||||
Result := Precursor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {HTTPD_STREAM_SOCKET} -- Implementation
|
|
||||||
|
|
||||||
set_certificates (a_crt_filename, a_key_filename: detachable READABLE_STRING_GENERAL)
|
|
||||||
do
|
|
||||||
if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then
|
|
||||||
if a_crt_filename /= Void then
|
|
||||||
l_socket.set_certificate_file_name (a_crt_filename)
|
|
||||||
end
|
|
||||||
if a_key_filename /= Void then
|
|
||||||
l_socket.set_key_file_name (a_key_filename)
|
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
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
|
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
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
note
|
|
||||||
description: "SSL tcp stream socket."
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
SSL_TCP_STREAM_SOCKET
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
SSL_NETWORK_STREAM_SOCKET
|
|
||||||
|
|
||||||
create
|
|
||||||
make_server_by_address_and_port, make_server_by_port,
|
|
||||||
make_client_by_address_and_port, make_client_by_port,
|
|
||||||
make_empty
|
|
||||||
|
|
||||||
create {SSL_NETWORK_STREAM_SOCKET}
|
|
||||||
make_from_descriptor_and_address
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
|
||||||
-- Create server socket on `an_address' and `a_port'.
|
|
||||||
require
|
|
||||||
valid_port: a_port >= 0
|
|
||||||
do
|
|
||||||
make
|
|
||||||
create address.make_from_address_and_port (an_address, a_port)
|
|
||||||
bind
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Basic operation
|
|
||||||
|
|
||||||
send_message (a_msg: STRING)
|
|
||||||
do
|
|
||||||
put_string (a_msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Output
|
|
||||||
|
|
||||||
put_readable_string_8 (s: READABLE_STRING_8)
|
|
||||||
-- Write readable string `s' to socket.
|
|
||||||
local
|
|
||||||
ext: C_STRING
|
|
||||||
do
|
|
||||||
create ext.make (s)
|
|
||||||
put_managed_pointer (ext.managed_data, 0, s.count)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
try_ready_for_reading: BOOLEAN
|
|
||||||
-- Is data available for reading from the socket right now?
|
|
||||||
require
|
|
||||||
socket_exists: exists
|
|
||||||
local
|
|
||||||
retval: INTEGER
|
|
||||||
do
|
|
||||||
retval := c_select_poll_with_timeout (descriptor, True, 0)
|
|
||||||
Result := (retval > 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE}-- Implementation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
note
|
|
||||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Summary description for {TCP_STREAM_SOCKET}."
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
TCP_STREAM_SOCKET
|
|
||||||
|
|
||||||
inherit
|
|
||||||
NETWORK_STREAM_SOCKET
|
|
||||||
redefine
|
|
||||||
make
|
|
||||||
end
|
|
||||||
|
|
||||||
TCP_STREAM_SOCKET_EXT
|
|
||||||
|
|
||||||
create
|
|
||||||
make_server_by_address_and_port,
|
|
||||||
make_server_by_port,
|
|
||||||
make_client_by_address_and_port,
|
|
||||||
make_client_by_port,
|
|
||||||
make_from_separate,
|
|
||||||
make_empty
|
|
||||||
|
|
||||||
create {NETWORK_STREAM_SOCKET}
|
|
||||||
make_from_descriptor_and_address
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
-- Create a network stream socket.
|
|
||||||
do
|
|
||||||
Precursor
|
|
||||||
debug
|
|
||||||
set_reuse_address
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
|
||||||
-- Create server socket on `an_address' and `a_port'.
|
|
||||||
require
|
|
||||||
valid_port: a_port >= 0
|
|
||||||
do
|
|
||||||
make
|
|
||||||
create address.make_from_address_and_port (an_address, a_port)
|
|
||||||
bind
|
|
||||||
end
|
|
||||||
|
|
||||||
make_from_separate (s: separate STREAM_SOCKET)
|
|
||||||
require
|
|
||||||
descriptor_available: s.descriptor_available
|
|
||||||
do
|
|
||||||
create_from_descriptor (s.descriptor)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Basic operation
|
|
||||||
|
|
||||||
peek_stream (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.
|
|
||||||
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 := clib_recv (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
|
|
||||||
|
|
||||||
send_message (a_msg: STRING)
|
|
||||||
do
|
|
||||||
put_string (a_msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Output
|
|
||||||
|
|
||||||
put_readable_string_8 (s: READABLE_STRING_8)
|
|
||||||
-- Write readable string `s' to socket.
|
|
||||||
local
|
|
||||||
ext: C_STRING
|
|
||||||
do
|
|
||||||
create ext.make (s)
|
|
||||||
put_managed_pointer (ext.managed_data, 0, s.count)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
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 (1)
|
|
||||||
Result := last_string.count = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
try_ready_for_reading: BOOLEAN
|
|
||||||
-- Is data available for reading from the socket right now?
|
|
||||||
require
|
|
||||||
socket_exists: exists
|
|
||||||
local
|
|
||||||
retval: INTEGER
|
|
||||||
do
|
|
||||||
retval := c_select_poll_with_timeout (descriptor, True, 0)
|
|
||||||
Result := (retval > 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- C implementation
|
|
||||||
|
|
||||||
clib_recv (a_fd: INTEGER; buf: POINTER; len: INTEGER; flags: INTEGER): INTEGER
|
|
||||||
-- External routine to receive at most `len' number of
|
|
||||||
-- bytes into buffer `buf' from socket `fd' with `flags' options.
|
|
||||||
external
|
|
||||||
"C inline"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
return (EIF_INTEGER) recv ((int) $a_fd, (char *) $buf, (int) $len, (int) $flags);
|
|
||||||
]"
|
|
||||||
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,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
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
note
|
|
||||||
description: "[
|
|
||||||
Until 16.05, the EiffelNet socket interface DOES NOT have recv_timeout and send_timeout.
|
|
||||||
]"
|
|
||||||
|
|
||||||
deferred class
|
|
||||||
TCP_STREAM_SOCKET_EXT
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
descriptor: INTEGER
|
|
||||||
-- Socket descriptor of current socket
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Socket Recv and Send timeout.
|
|
||||||
|
|
||||||
-- recv_timeout: INTEGER
|
|
||||||
-- -- Receive timeout in seconds on Current socket.
|
|
||||||
-- do
|
|
||||||
-- Result := c_get_sock_recv_timeout (descriptor, level_sol_socket)
|
|
||||||
-- ensure
|
|
||||||
-- result_not_negative: Result >= 0
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- send_timeout: INTEGER
|
|
||||||
-- -- Send timeout in seconds on Current socket.
|
|
||||||
-- do
|
|
||||||
-- Result := c_get_sock_send_timeout (descriptor, level_sol_socket)
|
|
||||||
-- ensure
|
|
||||||
-- result_not_negative: Result >= 0
|
|
||||||
-- end
|
|
||||||
|
|
||||||
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"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
#ifdef EIF_WINDOWS
|
|
||||||
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
|
||||||
setsockopt((SOCKET) $a_fd, (int) $a_level, (int) SO_RCVTIMEO, (char *) &arg, sizeof(arg));
|
|
||||||
#else
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
|
||||||
|
|
||||||
setsockopt((int) $a_fd, (int) $a_level, (int) SO_RCVTIMEO, (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"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
#ifdef EIF_WINDOWS
|
|
||||||
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
|
||||||
setsockopt((SOCKET) $a_fd, (int) $a_level, (int) SO_SNDTIMEO, (char *) &arg, sizeof(arg));
|
|
||||||
#else
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
|
||||||
|
|
||||||
setsockopt((int) $a_fd, (int) $a_level, (int) SO_SNDTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
|
|
||||||
#endif
|
|
||||||
]"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -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, (struct timeval*), int);
|
||||||
|
extern int recv(int, char *, int, int);
|
||||||
|
extern int send(int, char *, int, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,13 +20,19 @@ create
|
|||||||
feature {NONE} -- Factory
|
feature {NONE} -- Factory
|
||||||
|
|
||||||
new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET
|
new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET
|
||||||
|
local
|
||||||
|
s_ssl: HTTPD_STREAM_SSL_SOCKET
|
||||||
do
|
do
|
||||||
if configuration.is_secure then
|
if configuration.is_secure then
|
||||||
if a_addr /= Void then
|
if a_addr /= Void then
|
||||||
create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_address_and_port (a_addr, a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key)
|
create s_ssl.make_server_by_address_and_port (a_addr, a_http_port)
|
||||||
|
Result := s_ssl
|
||||||
else
|
else
|
||||||
create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_port (a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key)
|
create s_ssl.make_server_by_port (a_http_port)
|
||||||
end
|
end
|
||||||
|
s_ssl.set_tls_protocol (configuration.ssl_protocol)
|
||||||
|
s_ssl.set_certificate_filenames (configuration.ca_crt, configuration.ca_key)
|
||||||
|
Result := s_ssl
|
||||||
else
|
else
|
||||||
Result := Precursor (a_addr, a_http_port)
|
Result := Precursor (a_addr, a_http_port)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ feature {NONE} -- Initialization
|
|||||||
initialize_server (server)
|
initialize_server (server)
|
||||||
end
|
end
|
||||||
|
|
||||||
make_with_base (a_base: like base)
|
make_with_base (a_base: detachable separate READABLE_STRING_8)
|
||||||
-- Create current standalone connector with base url `a_base'
|
-- Create current standalone connector with base url `a_base'
|
||||||
require
|
require
|
||||||
a_base_starts_with_slash: (a_base /= Void and then not a_base.is_empty) implies a_base.starts_with ("/")
|
a_base_starts_with_slash: a_base /= Void implies is_valid_base (a_base)
|
||||||
do
|
do
|
||||||
make
|
make
|
||||||
set_base (a_base)
|
set_base (a_base)
|
||||||
@@ -109,7 +109,8 @@ feature -- Status report
|
|||||||
feature -- Callbacks
|
feature -- Callbacks
|
||||||
|
|
||||||
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]]]
|
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]]]
|
||||||
-- Actions triggered when launched
|
-- Actions triggered when launched.
|
||||||
|
-- WARNING: only supported for now with SCOOP concurrency mode. [2016-oct-07]
|
||||||
|
|
||||||
feature -- Event
|
feature -- Event
|
||||||
|
|
||||||
@@ -123,16 +124,25 @@ feature -- Event
|
|||||||
|
|
||||||
feature -- Element change
|
feature -- Element change
|
||||||
|
|
||||||
set_base (v: like base)
|
set_base (v: detachable separate READABLE_STRING_8)
|
||||||
-- Set base url `base' to `v'.
|
-- Set base url `base' to `v'.
|
||||||
require
|
require
|
||||||
b_starts_with_slash: (v /= Void and then not v.is_empty) implies v.starts_with ("/")
|
b_starts_with_slash: (v /= Void and then not v.is_empty) implies is_valid_base (v)
|
||||||
do
|
do
|
||||||
base := v
|
if v = Void then
|
||||||
|
base := Void
|
||||||
|
else
|
||||||
|
create {STRING_8} base.make_from_separate (v)
|
||||||
|
end
|
||||||
ensure
|
ensure
|
||||||
valid_base: (attached base as l_base and then not l_base.is_empty) implies l_base.starts_with ("/")
|
valid_base: (attached base as l_base and then not l_base.is_empty) implies l_base.starts_with ("/")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_valid_base (v: separate READABLE_STRING_8): BOOLEAN
|
||||||
|
do
|
||||||
|
Result := not v.is_whitespace and then v[1] = '/'
|
||||||
|
end
|
||||||
|
|
||||||
set_port_number (a_port_number: INTEGER)
|
set_port_number (a_port_number: INTEGER)
|
||||||
-- Set port number to `a_port_number'.
|
-- Set port number to `a_port_number'.
|
||||||
require
|
require
|
||||||
@@ -141,6 +151,13 @@ feature -- Element change
|
|||||||
set_port_on_configuration (a_port_number, configuration)
|
set_port_on_configuration (a_port_number, configuration)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_socket_recv_timeout (a_nb_seconds: INTEGER)
|
||||||
|
require
|
||||||
|
a_nb_seconds_positive_or_zero: a_nb_seconds >= 0
|
||||||
|
do
|
||||||
|
set_socket_recv_timeout_on_configuration (a_nb_seconds, configuration)
|
||||||
|
end
|
||||||
|
|
||||||
set_max_concurrent_connections (nb: INTEGER)
|
set_max_concurrent_connections (nb: INTEGER)
|
||||||
-- Set maximum concurrent connections to `nb'.
|
-- Set maximum concurrent connections to `nb'.
|
||||||
require
|
require
|
||||||
@@ -189,12 +206,12 @@ feature -- Events
|
|||||||
require
|
require
|
||||||
obs.started -- SCOOP wait condition.
|
obs.started -- SCOOP wait condition.
|
||||||
do
|
do
|
||||||
|
-- FIXME: this works only with SCOOP concurrency mode. [2016-oct-07]
|
||||||
if obs.port > 0 then
|
if obs.port > 0 then
|
||||||
on_launched (obs.port)
|
on_launched (obs.port)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
server_controller (a_server: like server): separate HTTPD_CONTROLLER
|
server_controller (a_server: like server): separate HTTPD_CONTROLLER
|
||||||
@@ -238,6 +255,11 @@ feature {NONE} -- Implementation: element change
|
|||||||
cfg.set_http_server_port (a_port_number)
|
cfg.set_http_server_port (a_port_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_socket_recv_timeout_on_configuration (a_nb_seconds: INTEGER; cfg: like configuration)
|
||||||
|
do
|
||||||
|
cfg.set_socket_recv_timeout (a_nb_seconds)
|
||||||
|
end
|
||||||
|
|
||||||
set_max_concurrent_connections_on_configuration (nb: INTEGER; cfg: like configuration)
|
set_max_concurrent_connections_on_configuration (nb: INTEGER; cfg: like configuration)
|
||||||
do
|
do
|
||||||
cfg.set_max_concurrent_connections (nb)
|
cfg.set_max_concurrent_connections (nb)
|
||||||
|
|||||||
@@ -75,23 +75,23 @@ feature -- Output
|
|||||||
-- Send `s' to http client
|
-- Send `s' to http client
|
||||||
do
|
do
|
||||||
last_target_call_succeed := False
|
last_target_call_succeed := False
|
||||||
target.put_readable_string_8 (s)
|
target.put_readable_string_8_noexception (s)
|
||||||
last_target_call_succeed := True
|
last_target_call_succeed := not target.was_error
|
||||||
end
|
end
|
||||||
|
|
||||||
put_string (s: READABLE_STRING_8)
|
put_string (s: READABLE_STRING_8)
|
||||||
-- Send `s' to http client
|
-- Send `s' to http client
|
||||||
do
|
do
|
||||||
last_target_call_succeed := False
|
last_target_call_succeed := False
|
||||||
target.put_readable_string_8 (s)
|
target.put_readable_string_8_noexception (s)
|
||||||
last_target_call_succeed := True
|
last_target_call_succeed := not target.was_error
|
||||||
end
|
end
|
||||||
|
|
||||||
put_character (c: CHARACTER_8)
|
put_character (c: CHARACTER_8)
|
||||||
do
|
do
|
||||||
last_target_call_succeed := False
|
last_target_call_succeed := False
|
||||||
target.put_character (c)
|
target.put_character (c)
|
||||||
last_target_call_succeed := True
|
last_target_call_succeed := not target.was_error
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
@@ -116,7 +116,7 @@ feature -- Basic operations
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ feature {NONE} -- Initialization
|
|||||||
verbose := False
|
verbose := False
|
||||||
verbose_level := notice_level
|
verbose_level := notice_level
|
||||||
|
|
||||||
base_url := ""
|
base_url := Void
|
||||||
|
|
||||||
if attached options as opts then
|
if attached options as opts then
|
||||||
if attached {READABLE_STRING_GENERAL} opts.option ("server_name") as l_server_name then
|
if attached {READABLE_STRING_GENERAL} opts.option ("server_name") as l_server_name then
|
||||||
@@ -175,7 +175,12 @@ feature -- Execution
|
|||||||
else
|
else
|
||||||
io.error.put_string ("localhost")
|
io.error.put_string ("localhost")
|
||||||
end
|
end
|
||||||
io.error.put_string (":" + port_number.out + "/" + base_url + "%N")
|
io.error.put_string (":" + port_number.out)
|
||||||
|
if attached base_url as b and then not b.is_empty then
|
||||||
|
io.error.put_string (b + "%N")
|
||||||
|
else
|
||||||
|
io.error.put_string ("/%N")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
update_configuration (conn.configuration)
|
update_configuration (conn.configuration)
|
||||||
@@ -201,7 +206,7 @@ feature {NONE} -- Implementation
|
|||||||
|
|
||||||
server_name: detachable READABLE_STRING_8
|
server_name: detachable READABLE_STRING_8
|
||||||
|
|
||||||
base_url: READABLE_STRING_8
|
base_url: detachable READABLE_STRING_8
|
||||||
|
|
||||||
verbose: BOOLEAN
|
verbose: BOOLEAN
|
||||||
verbose_level: INTEGER
|
verbose_level: INTEGER
|
||||||
|
|||||||
Reference in New Issue
Block a user