diff --git a/examples/simple_ssl/application.e b/examples/simple_ssl/application.e new file mode 100644 index 00000000..e890c187 --- /dev/null +++ b/examples/simple_ssl/application.e @@ -0,0 +1,29 @@ +note + description : "simple application root class" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION + +inherit + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] + redefine + initialize + end + +create + make_and_launch + +feature {NONE} -- Initialization + + initialize + -- Initialize current service. + do + -- Specific to `standalone' connector (the EiffelWeb server). + -- See `{WSF_STANDALONE_SERVICE_LAUNCHER}.initialize' + set_service_option ("port", 9090) + import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("simple.ini")) + end + +end diff --git a/examples/simple_ssl/application_execution.e b/examples/simple_ssl/application_execution.e new file mode 100644 index 00000000..2d6d0a75 --- /dev/null +++ b/examples/simple_ssl/application_execution.e @@ -0,0 +1,41 @@ +note + description : "simple application execution" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + local + s: STRING + dt: HTTP_DATE + do + -- To send a response we need to setup, the status code and + -- the response headers. + s := "Hello World!" + create dt.make_now_utc + s.append (" (UTC time is " + dt.rfc850_string + ").") + if request.is_https then + s.append ("

This is a secured connection! (https)

%N") + end + + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>) + response.set_status_code ({HTTP_STATUS_CODE}.ok) + response.header.put_content_type_text_html + response.header.put_content_length (s.count) + if attached request.http_connection as l_connection and then l_connection.is_case_insensitive_equal_general ("keep-alive") then + response.header.put_header_key_value ("Connection", "keep-alive") + end + response.put_string (s) + end + +end diff --git a/examples/simple_ssl/simple.crt b/examples/simple_ssl/simple.crt new file mode 100644 index 00000000..6147c200 --- /dev/null +++ b/examples/simple_ssl/simple.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICWDCCAcGgAwIBAgIJAJnXGtV+PtiYMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTUwNDAzMjIxNTA0WhcNMTYwNDAyMjIxNTA0WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDFMK6ojzg+KlklhTossR13c51izMgGc3B0z9ttfHIcx2kxra3HtHcKIl5wSUvn +G8zmSyFAyQTs5LUv65q46FM9qU8tP+vTeFCfNXvjRcIEpouta3J53K0xuUlxz4d4 +4D6qvdDWAez/0AkI4y5etW5zXtg7IQorJhsI9TmfGuruzwIDAQABo1AwTjAdBgNV +HQ4EFgQUbWpk2HoHa0YqpEwr7CGEatBFTMkwHwYDVR0jBBgwFoAUbWpk2HoHa0Yq +pEwr7CGEatBFTMkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAi+h4/ +IgEocWkdRZBKHEcTrRxz5WhEDJMoVo9LhnXvCfn1G/4p6Un6sYv7Xzpi9NuSY8uV +cjfJJXhtF3AtyZ70iTAxWaRWjGaZ03PYOjlledJ5rqJEt6CCn8m+JsfznduZvbxQ +zQ6jCLXfyD/tvemB+yYEI3NntvRKx5/zt6Q26Q== +-----END CERTIFICATE----- diff --git a/examples/simple_ssl/simple.ini b/examples/simple_ssl/simple.ini new file mode 100644 index 00000000..2ec39e14 --- /dev/null +++ b/examples/simple_ssl/simple.ini @@ -0,0 +1,28 @@ +########################################################## +### EiffelWeb settings for related connector ### +### Mostly for EiffelWeb standalone connector ### +### See {WGI_STANDALONE_CONSTANTS} for default values. ### +########################################################## + +### Connection settings +port=9090 +#max_concurrent_connections=100 +#max_tcp_clients=100 + +### Timeout settings +#socket_timeout=60 +#socket_recv_timeout=5 + +### Persistent connection settings +#keep_alive_timeout=15 +#max_keep_alive_requests=100 + +### SSL settings +# enable SSL, with file certificate. +ssl_enabled=true +ssl_ca_key=simple.key +ssl_ca_crt=simple.crt + +### App settings +verbose=true +verbose_level=ALERT diff --git a/examples/simple_ssl/simple.key b/examples/simple_ssl/simple.key new file mode 100644 index 00000000..e5e22a52 --- /dev/null +++ b/examples/simple_ssl/simple.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDFMK6ojzg+KlklhTossR13c51izMgGc3B0z9ttfHIcx2kxra3H +tHcKIl5wSUvnG8zmSyFAyQTs5LUv65q46FM9qU8tP+vTeFCfNXvjRcIEpouta3J5 +3K0xuUlxz4d44D6qvdDWAez/0AkI4y5etW5zXtg7IQorJhsI9TmfGuruzwIDAQAB +AoGAR5efMg+dieRyLU8rieJcImxVbfOPg9gRsjdtIVkXTR+RL7ow59q7hXBo/Td/ +WU8cm1gXoJ/bK+71YYqWyB+BaLRIWvRWb7Gdw203tu4e136Ca5uuY+71qdbVTVcl +NQ7J+T+eAQFP+a+DdT3ZQxu9eze87SMbu6i5YSpIk2kusOECQQDunv/DQ+nc+NgR +DF+Td3sNYUVRT9a1CWi6abAG6reXwp8MS4NobWDf+Ps4JODhEEwlIdq5qL7qqYBZ +Gc1TJJ53AkEA0404Fn6vAzzegBcS4RLlYTK7nMr0m4pMmDMCI6YzAYdMmKHp1e6f +IwxSmQrmwyAgwcT01bc0+A8yipcC2BWQaQJBAJ01QZm635OGmos41KsKF5bsE8gL +SpBBH69Yu/ECqGwie7iU84FUNnO4zIHjwghlPVVlZX3Vz9o4S+fn2N9DC+cCQGyZ +QyCxGdC0r5fbwHJQS/ZQn+UGfvlVzqoXDVMVn3t6ZES6YZrT61eHnOM5qGqklIxE +Old3vDZXPt/MU8Zvk3kCQBOgUx2VxvTrHN37hk9/QIDiM62+RenBm1M3ah8xTosf +1mSeEb6d9Kwb3TgPBmA7YXzJuAQfRIvEPMPxT5SSr6Q= +-----END RSA PRIVATE KEY----- diff --git a/examples/simple_ssl/simple_ssl.ecf b/examples/simple_ssl/simple_ssl.ecf new file mode 100644 index 00000000..51e2b9a8 --- /dev/null +++ b/examples/simple_ssl/simple_ssl.ecf @@ -0,0 +1,27 @@ + + + + Simple EiffelWeb standalone server with SSL support (Concurrent connection supported thanks to SCOOP). + + + /.svn$ + /CVS$ + /EIFGENs$ + + + + + + + + + + + + + Simple EiffelWeb standalone server with SSL support (Single threaded, thus no concurrent connection.) + + + diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e index 9335e76f..2defb093 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e @@ -25,20 +25,27 @@ feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation release -- local - d: STRING + d: detachable STRING do - if attached internal_client_socket as l_socket then - d := l_socket.descriptor.out - else - d := "N/A" - end 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") - dbglog (generator + ".release: LEAVE {" + d + "}") + if d /= Void then + dbglog (generator + ".release: LEAVE {" + d + "}") + else + dbglog (generator + ".release: LEAVE {N/A}") + end end end diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e index e053bfe7..57c6ecd6 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e @@ -18,21 +18,28 @@ inherit feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation release + -- local - d: STRING + d: detachable STRING do - -- FIXME: for log purpose - if attached internal_client_socket as l_socket then - d := l_socket.descriptor.out - else - d := "N/A" - end 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") - dbglog (generator + ".release: LEAVE {" + d + "}") + if d /= Void then + dbglog (generator + ".release: LEAVE {" + d + "}") + else + dbglog (generator + ".release: LEAVE {N/A}") + end end end diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e index 48bdff7a..7c06b59f 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e @@ -6,6 +6,11 @@ note deferred class HTTPD_CONFIGURATION_I +inherit + ANY + + HTTPD_CONSTANTS + feature {NONE} -- Initialization make @@ -14,6 +19,7 @@ feature {NONE} -- Initialization 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 @@ -21,15 +27,6 @@ feature {NONE} -- Initialization create ca_key.make_empty end -feature -- Defaults - - default_http_server_port: INTEGER = 80 - default_max_concurrent_connections: INTEGER = 100 - default_max_tcp_clients: INTEGER = 100 - default_socket_timeout: INTEGER = 300 -- seconds - default_keep_alive_timeout: INTEGER = 15 -- seconds - default_max_keep_alive_requests: INTEGER = 100 - feature -- Access Server_details: STRING_8 @@ -45,7 +42,12 @@ feature -- Access 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: 300 seconds, which is appropriate for most situations. + -- 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. @@ -83,8 +85,10 @@ feature -- Access 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 @@ -92,10 +96,10 @@ feature -- Access: SSL is_secure: BOOLEAN -- Is SSL/TLS session?. - ca_crt: IMMUTABLE_STRING_8 + ca_crt: detachable IMMUTABLE_STRING_32 -- the signed certificate. - ca_key: IMMUTABLE_STRING_8 + ca_key: detachable IMMUTABLE_STRING_32 -- private key to the certificate. ssl_protocol: NATURAL @@ -103,6 +107,22 @@ feature -- Access: SSL 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 @@ -152,6 +172,14 @@ feature -- Element change 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 @@ -198,17 +226,33 @@ feature -- Element change verbose_level_set: verbose_level = lev end - mark_secure - -- Set is_secure in True + set_is_secure (b: BOOLEAN) + -- Set `is_secure' to `b'. do - if has_ssl_support then + if b and has_ssl_support then is_secure := True - if http_server_port = 80 then + 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 @@ -218,16 +262,24 @@ feature -- Element change feature -- Element change - set_ca_crt (a_value: separate READABLE_STRING_8) + set_ca_crt (a_value: detachable separate READABLE_STRING_GENERAL) -- Set `ca_crt' from `a_value'. do - create ca_crt.make_from_separate (a_value) + if a_value /= Void then + create ca_crt.make_from_separate (a_value) + else + ca_crt := Void + end end - set_ca_key (a_value: separate READABLE_STRING_8) + set_ca_key (a_value: detachable separate READABLE_STRING_GENERAL) -- Set `ca_key' with `a_value'. do - create ca_key.make_from_separate (a_value) + 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) @@ -238,6 +290,24 @@ feature -- Element change 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 diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_constants.e b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_constants.e new file mode 100644 index 00000000..71e4dcc1 --- /dev/null +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_constants.e @@ -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 diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e index 146b193a..a591cac3 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e @@ -17,9 +17,15 @@ feature -- Access 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. @@ -42,12 +48,24 @@ feature -- Change 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 diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf index 20a62c0c..faea6dd5 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf @@ -10,20 +10,29 @@ - - + - - + + + + + + + + + + + + diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf index 18719f75..25cc31ea 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf @@ -24,6 +24,16 @@ + + + + + + + + + + diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf index b29b1277..d25947d3 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf @@ -30,6 +30,16 @@ + + + + + + + + + + diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf index 982378fa..9d62c604 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf @@ -29,6 +29,16 @@ + + + + + + + + + + diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e index 1c38a3ff..439d9122 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e @@ -11,6 +11,8 @@ inherit HTTPD_LOGGER_CONSTANTS + HTTPD_SOCKET_FACTORY + feature {NONE} -- Initialization make (a_request_settings: HTTPD_REQUEST_SETTINGS) @@ -18,11 +20,13 @@ feature {NONE} -- Initialization 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 @@ -68,7 +72,7 @@ feature -- Access do s := internal_client_socket if s = Void then - create s.make_empty + s := new_client_socket (is_secure) internal_client_socket := s end Result := s @@ -121,6 +125,10 @@ feature -- Settings verbose_level: INTEGER -- Output verbosity. + is_secure: BOOLEAN + -- Is secure socket? + -- i.e: SSL? + is_persistent_connection_supported: BOOLEAN -- Is persistent connection supported? do @@ -134,6 +142,9 @@ feature -- Settings 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. @@ -187,6 +198,7 @@ feature -- Execution n,m: INTEGER do l_socket := client_socket + l_socket.set_recv_timeout (socket_recv_timeout) check socket_attached: l_socket /= Void socket_valid: l_socket.is_open_read and then l_socket.is_open_write @@ -206,18 +218,24 @@ feature -- Execution 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 + 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 end + if l_exit and has_error and not l_socket.is_closed then + l_socket.close + end end - execute_request + 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 local l_remote_info: detachable like remote_info l_socket: like client_socket @@ -237,13 +255,16 @@ feature -- Execution dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + " ENTER") end - --| TODO: add configuration options for socket timeout. - --| set by default 5 seconds. - l_socket.set_timeout (keep_alive_timeout) -- 5 seconds! - l_is_ready := l_socket.ready_for_reading + if a_is_reusing_connection then + --| set by default 5 seconds. + l_socket.set_recv_timeout (keep_alive_timeout) -- in seconds! + l_is_ready := l_socket.ready_for_reading + else + l_is_ready := True + end if l_is_ready then - l_socket.set_timeout (timeout) -- FIXME: return a 408 Request Timeout response .. + l_socket.set_recv_timeout (socket_recv_timeout) -- FIXME: return a 408 Request Timeout response .. create l_remote_info if attached l_socket.peer_address as l_addr then l_remote_info.addr := l_addr.host_address.host_address @@ -326,8 +347,7 @@ feature -- Parsing has_error := True end l_is_verbose := is_verbose - if not has_error or l_is_verbose then - -- if `is_verbose' we can try to print the request, even if it is a bad HTTP request + if not has_error then from line := next_line (a_socket) until diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e index ec02bd07..a5935aa1 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e @@ -108,6 +108,7 @@ feature -- Execution 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.verbose_level > 0 then diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/from_16_11/tcp_stream_socket_ext.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/from_16_11/tcp_stream_socket_ext.e new file mode 100644 index 00000000..65d4d70a --- /dev/null +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/from_16_11/tcp_stream_socket_ext.e @@ -0,0 +1,9 @@ +note + description: "[ + Since 16.11, the EiffelNet socket interface has recv_timeout and send_timeout. + ]" + +deferred class + TCP_STREAM_SOCKET_EXT + +end diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e index f3f3209d..76c0bb34 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e @@ -62,6 +62,7 @@ feature {NONE} -- Initialization feature -- Change set_timeout (n: INTEGER) + -- Set timeout to `n' seconds. do if attached {NETWORK_STREAM_SOCKET} socket as l_socket then l_socket.set_timeout (n) @@ -82,6 +83,22 @@ feature -- Change 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 diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e index 8b0be0da..1217d0d1 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e @@ -17,58 +17,66 @@ inherit ready_for_writing, ready_for_reading, try_ready_for_reading, - put_readable_string_8 + put_readable_string_8, + make_empty end create make_ssl_server_by_address_and_port, make_ssl_server_by_port, make_server_by_address_and_port, make_server_by_port, make_ssl_client_by_address_and_port, make_ssl_client_by_port, - make_client_by_address_and_port, make_client_by_port + make_client_by_address_and_port, make_client_by_port, + make_empty create {HTTPD_STREAM_SOCKET} make feature {NONE} -- Initialization - make_ssl_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING) + 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) local l_socket: SSL_TCP_STREAM_SOCKET do create l_socket.make_server_by_address_and_port (an_address, a_port) l_socket.set_tls_protocol (a_ssl_protocol) socket := l_socket - set_certificates (a_crt, a_key) + set_certificates (a_crt_fn, a_key_fn) end - make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING) + make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL) local l_socket: SSL_TCP_STREAM_SOCKET do create l_socket.make_server_by_port (a_port) l_socket.set_tls_protocol (a_ssl_protocol) socket := l_socket - set_certificates (a_crt, a_key) + 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: STRING; a_key: STRING) + 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) local l_socket: SSL_TCP_STREAM_SOCKET do create l_socket.make_client_by_address_and_port (an_address, a_port) l_socket.set_tls_protocol (a_ssl_protocol) socket := l_socket - set_certificates (a_crt, a_key) + set_certificates (a_crt_fn, a_key_fn) end - make_ssl_client_by_port (a_peer_port: INTEGER; a_peer_host: STRING; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING) + 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) local l_socket: SSL_TCP_STREAM_SOCKET do create l_socket.make_client_by_port (a_peer_port, a_peer_host) l_socket.set_tls_protocol (a_ssl_protocol) socket := l_socket - set_certificates (a_crt, a_key) + set_certificates (a_crt_fn, a_key_fn) + end + + make_empty + -- . + do + create {SSL_TCP_STREAM_SOCKET} socket.make_empty end feature -- Output @@ -136,15 +144,15 @@ feature -- Status Report feature {HTTPD_STREAM_SOCKET} -- Implementation - set_certificates (a_crt: STRING; a_key: STRING) - local - a_file_name: FILE_NAME + set_certificates (a_crt_filename, a_key_filename: detachable READABLE_STRING_GENERAL) do if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then - create a_file_name.make_from_string (a_crt) - l_socket.set_certificate_file_name (a_file_name) - create a_file_name.make_from_string (a_key) - l_socket.set_key_file_name (a_file_name) + 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 end diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e index 774b3bb5..6961a777 100644 --- a/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e @@ -12,6 +12,8 @@ inherit make end + TCP_STREAM_SOCKET_EXT + create make_server_by_address_and_port, make_server_by_port, diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/until_16_05/tcp_stream_socket_ext.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/until_16_05/tcp_stream_socket_ext.e new file mode 100644 index 00000000..73480ca3 --- /dev/null +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/until_16_05/tcp_stream_socket_ext.e @@ -0,0 +1,104 @@ +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 + +-- set_so_rcvtimeo (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 + + 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 diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_socket_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_socket_factory.e new file mode 100644 index 00000000..6c08bc32 --- /dev/null +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_socket_factory.e @@ -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 diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_socket_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_socket_factory.e new file mode 100644 index 00000000..ff410db5 --- /dev/null +++ b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_socket_factory.e @@ -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 diff --git a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e index dc95fb21..4ff9ac89 100644 --- a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e +++ b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e @@ -230,6 +230,9 @@ feature -- Request processing set_environment_variable (l_server_port, "SERVER_PORT", Result) set_environment_variable (version, "SERVER_PROTOCOL", Result) set_environment_variable ({HTTPD_CONFIGURATION}.Server_details, "SERVER_SOFTWARE", Result) + if is_secure then + set_environment_variable ("on", "HTTPS", Result) + end --| Apply `base' value l_base := base diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e index 8efd1910..0d227df9 100644 --- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e +++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e @@ -2,8 +2,8 @@ note description: "[ Standalone Web Server connector. ]" - date: "$Date$" - revision: "$Revision$" + date: "$Date: 2016-08-06 13:34:52 +0200 (sam., 06 août 2016) $" + revision: "$Revision: 99106 $" class WGI_STANDALONE_CONNECTOR [G -> WGI_EXECUTION create make end] @@ -155,6 +155,12 @@ feature -- Element change set_is_verbose_on_configuration (b, configuration) end + set_is_secure (b: BOOLEAN) + -- Set is_secure connection mode. + -- i.e: using SSL. + do + set_is_secure_on_configuration (b, configuration) + end feature -- Server @@ -242,6 +248,11 @@ feature {NONE} -- Implementation: element change cfg.set_is_verbose (b) end + set_is_secure_on_configuration (b: BOOLEAN; cfg: like configuration) + do + cfg.set_is_secure (b) + end + note copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_constants.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_constants.e new file mode 100644 index 00000000..dd5914c9 --- /dev/null +++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_constants.e @@ -0,0 +1,18 @@ +note + description: "[ + Constants value related to Standalone connector, + and indirectly to `httpd' component. + ]" + author: "$Author$" + date: "$Date$" + revision: "$Revision$" + +deferred class + WGI_STANDALONE_CONSTANTS + +inherit + ANY + + HTTPD_CONSTANTS + +end diff --git a/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e b/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e index 3ce801f4..e4169605 100644 --- a/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e +++ b/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e @@ -2,14 +2,27 @@ note description: "[ Component to launch the service using the default connector - Eiffel Web httpd for this class + EiffelWeb httpd for this class + The httpd default connector support options: + verbose: to display verbose output + port: numeric such as 8099 (or equivalent string as "8099") + base: base_url (very specific to standalone server) + + max_concurrent_connections: set one, for single threaded behavior + max_tcp_clients: max number of open tcp connection + + socket_timeout: connection timeout + socket_recv_timeout: read data timeout + + keep_alive_timeout: amount of time the server will wait for subsequent + requests on a persistent connection, + max_keep_alive_requests: number of requests allowed on a persistent connection, + + ssl_enabled: set to True for https support. + ssl_ca_crt: path to the certificat crt file (relevant when ssl_enabled is True) + ssl_ca_key: path to the certificat key file (relevant when ssl_enabled is True) - The httpd default connector support options: - port: numeric such as 8099 (or equivalent string as "8099") - base: base_url (very specific to standalone server) - verbose: to display verbose output, useful for standalone connector - force_single_threaded: use only one thread, useful for standalone connector check WSF_SERVICE_LAUNCHER for more documentation ]" @@ -41,12 +54,13 @@ feature {NONE} -- Initialization create on_launched_actions create on_stopped_actions - port_number := 80 --| Default, but quite often, this port is already used ... - max_concurrent_connections := 100 - max_tcp_clients := 100 - socket_timeout := 300 -- 300 seconds - keep_alive_timeout := 15 -- 15 seconds. - max_keep_alive_requests := 100 + port_number := {WGI_STANDALONE_CONSTANTS}.default_http_server_port --| Default, but quite often, this port is already used ... + max_concurrent_connections := {WGI_STANDALONE_CONSTANTS}.default_max_concurrent_connections + max_tcp_clients := {WGI_STANDALONE_CONSTANTS}.default_max_tcp_clients + socket_timeout := {WGI_STANDALONE_CONSTANTS}.default_socket_timeout -- seconds + socket_recv_timeout := {WGI_STANDALONE_CONSTANTS}.default_socket_recv_timeout -- seconds + keep_alive_timeout := {WGI_STANDALONE_CONSTANTS}.default_keep_alive_timeout -- seconds. + max_keep_alive_requests := {WGI_STANDALONE_CONSTANTS}.default_max_keep_alive_requests verbose := False verbose_level := notice_level @@ -59,6 +73,7 @@ feature {NONE} -- Initialization if attached {READABLE_STRING_GENERAL} opts.option ("base") as l_base_str then base_url := l_base_str.as_string_8 end + verbose := opts.option_boolean_value ("verbose", verbose) -- See `{HTTPD_REQUEST_HANDLER_I}.*_verbose_level` @@ -96,8 +111,16 @@ feature {NONE} -- Initialization max_concurrent_connections := opts.option_integer_value ("max_concurrent_connections", max_concurrent_connections) max_tcp_clients := opts.option_integer_value ("max_tcp_clients", max_tcp_clients) socket_timeout := opts.option_integer_value ("socket_timeout", socket_timeout) + socket_recv_timeout := opts.option_integer_value ("socket_recv_timeout", socket_recv_timeout) keep_alive_timeout := opts.option_integer_value ("keep_alive_timeout", keep_alive_timeout) max_keep_alive_requests := opts.option_integer_value ("max_keep_alive_requests", max_keep_alive_requests) + + if + opts.option_boolean_value ("ssl_enabled", ssl_enabled) and then + attached opts.option_string_32_value ("ssl_protocol", "tls_1_2") as ssl_prot + then + ssl_settings := [ssl_prot, opts.option_string_32_value ("ssl_ca_crt", Void), opts.option_string_32_value ("ssl_ca_key", Void)] + end end create conn.make @@ -120,11 +143,13 @@ feature -- Execution do cfg.set_is_verbose (verbose) cfg.set_verbose_level (verbose_level) + cfg.set_ssl_settings (ssl_settings) cfg.set_http_server_name (server_name) cfg.http_server_port := port_number cfg.set_max_concurrent_connections (max_concurrent_connections) cfg.set_max_tcp_clients (max_tcp_clients) cfg.set_socket_timeout (socket_timeout) + cfg.set_socket_recv_timeout (socket_recv_timeout) cfg.set_keep_alive_timeout (keep_alive_timeout) cfg.set_max_keep_alive_requests (max_keep_alive_requests) end @@ -140,11 +165,17 @@ feature -- Execution debug ("ew_standalone") if verbose then io.error.put_string ("Launching standalone web server on port " + port_number.out) - if attached server_name as l_name then - io.error.put_string ("%N http://" + l_name + ":" + port_number.out + "/" + base_url + "%N") + if ssl_enabled then + io.error.put_string ("%N https://") else - io.error.put_string ("%N http://localhost:" + port_number.out + "/" + base_url + "%N") + io.error.put_string ("%N http://") end + if attached server_name as l_name then + io.error.put_string (l_name) + else + io.error.put_string ("localhost") + end + io.error.put_string (":" + port_number.out + "/" + base_url + "%N") end end update_configuration (conn.configuration) @@ -177,9 +208,18 @@ feature {NONE} -- Implementation -- Help defining the verbosity. -- The higher, the more output. + ssl_settings: detachable TUPLE [protocol: READABLE_STRING_GENERAL; ca_crt, ca_key: detachable READABLE_STRING_GENERAL] + + ssl_enabled: BOOLEAN + -- Is secure server? i.e using SSL? + do + Result := attached ssl_settings as ssl and then attached ssl.protocol as prot and then not prot.is_whitespace + end + max_concurrent_connections: INTEGER max_tcp_clients: INTEGER socket_timeout: INTEGER + socket_recv_timeout: INTEGER keep_alive_timeout: INTEGER max_keep_alive_requests: INTEGER diff --git a/library/server/wsf/src/service/wsf_service_launcher.e b/library/server/wsf/src/service/wsf_service_launcher.e index 2568a5e0..86c41a75 100644 --- a/library/server/wsf/src/service/wsf_service_launcher.e +++ b/library/server/wsf/src/service/wsf_service_launcher.e @@ -22,11 +22,11 @@ note For instance, you can use create s.make_and_launch_and_options (agent execute, <<["port", 8099]>>) - And if Nino is the default connector it will support: + And if the connector is the Standalone connector, + check {WSF_STANDALONE_SERVICE_LAUNCHER} for options description, such as: port: numeric such as 8099 (or equivalent string as "8099") base: base_url (very specific to standalone server) - force_single_threaded: use only one thread, useful for Nino - verbose: to display verbose output, useful for Nino + verbose: to display verbose output. ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/src/service/wsf_service_launcher_options.e b/library/server/wsf/src/service/wsf_service_launcher_options.e index 82e65a6f..1394c17d 100644 --- a/library/server/wsf/src/service/wsf_service_launcher_options.e +++ b/library/server/wsf/src/service/wsf_service_launcher_options.e @@ -8,8 +8,8 @@ note force_single_threaded: use only one thread, useful for Nino verbose: to display verbose output, useful for Nino ]" - date: "$Date$" - revision: "$Revision$" + date: "$Date: 2016-08-06 13:34:52 +0200 (sam., 06 août 2016) $" + revision: "$Revision: 99106 $" class WSF_SERVICE_LAUNCHER_OPTIONS @@ -85,6 +85,12 @@ feature -- Access feature -- Helpers + has_option (a_opt_name: READABLE_STRING_GENERAL): BOOLEAN + -- Is there any value associated to option name `a_opt_name'? + do + Result := attached option (a_opt_name) + end + has_integer_option (a_opt_name: READABLE_STRING_GENERAL): BOOLEAN -- Is there any INTEGER value associated to option name `a_opt_name'? local @@ -100,6 +106,29 @@ feature -- Helpers end end + has_string_32_option (a_opt_name: READABLE_STRING_GENERAL): BOOLEAN + -- Is there any string 32 value associated to option name `a_opt_name'? + do + if attached option (a_opt_name) as opt then + Result := attached {READABLE_STRING_GENERAL} opt + end + end + + option_string_32_value (a_opt_name: READABLE_STRING_GENERAL; a_default: detachable READABLE_STRING_GENERAL): detachable IMMUTABLE_STRING_32 + -- Unicode String value associated to option name `a_opt_name', other return `a_default'. + do + if attached option (a_opt_name) as opt then + if attached {READABLE_STRING_32} opt as s32 then + create Result.make_from_string (s32) + elseif attached {READABLE_STRING_GENERAL} opt as s then + create Result.make_from_string_general (s) + end + end + if Result = Void and a_default /= Void then + create Result.make_from_string_general (a_default) + end + end + option_integer_value (a_opt_name: READABLE_STRING_GENERAL; a_default: INTEGER): INTEGER -- INTEGER value associated to option name `a_opt_name', other return `a_default'. local