From 9cc9b951905ac8dbe53a1dcfd0a3ff6e23039873 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 5 Aug 2016 11:38:35 +0200 Subject: [PATCH 1/3] Added a simple reverse proxy handler. - For now, it does not support SSL connection on the target yet. - No external config file support, this is all about coding. --- examples/proxy/application.e | 29 ++ examples/proxy/application_execution.e | 49 +++ examples/proxy/proxy.ecf | 27 ++ examples/proxy/server.ini | 8 + .../wsf_simple_reverse_proxy_handler.e | 295 ++++++++++++++++++ .../rewriter/wsf_agent_uri_rewriter.e | 38 +++ .../wsf_proxy/rewriter/wsf_uri_rewriter.e | 16 + library/server/wsf_proxy/wsf_proxy-safe.ecf | 12 + library/server/wsf_proxy/wsf_proxy.ecf | 14 + 9 files changed, 488 insertions(+) create mode 100644 examples/proxy/application.e create mode 100644 examples/proxy/application_execution.e create mode 100644 examples/proxy/proxy.ecf create mode 100644 examples/proxy/server.ini create mode 100644 library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e create mode 100644 library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e create mode 100644 library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e create mode 100644 library/server/wsf_proxy/wsf_proxy-safe.ecf create mode 100644 library/server/wsf_proxy/wsf_proxy.ecf diff --git a/examples/proxy/application.e b/examples/proxy/application.e new file mode 100644 index 00000000..a90f4897 --- /dev/null +++ b/examples/proxy/application.e @@ -0,0 +1,29 @@ +note + description: "Launcher for reverse proxy web application." + 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 ("server.ini")) + end + +end diff --git a/examples/proxy/application_execution.e b/examples/proxy/application_execution.e new file mode 100644 index 00000000..44440c88 --- /dev/null +++ b/examples/proxy/application_execution.e @@ -0,0 +1,49 @@ +note + description: "Reverse proxy example." + date: "$Date$" + revision: "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + + WSF_URI_REWRITER + rename + uri as proxy_uri + end + +create + make + +feature -- Basic operations + + execute + do + -- NOTE: please enter the target reverse proxy machine + port number here + -- replace "localhost" and 8080 + send_proxy_response ("localhost", 8080, Current) + end + + send_proxy_response (a_hostname: READABLE_STRING_8; a_port: INTEGER; a_rewriter: detachable WSF_URI_REWRITER) + local + h: WSF_SIMPLE_REVERSE_PROXY_HANDLER + do + create h.make (a_hostname, a_port) + h.set_uri_rewriter (a_rewriter) + h.set_uri_rewriter (create {WSF_AGENT_URI_REWRITER}.make (agent proxy_uri)) + h.set_timeout (30) -- 30 seconds + h.set_connect_timeout (5_000) -- milliseconds = 5 seconds + h.execute (request, response) + end + +feature -- Helpers + + proxy_uri (a_request: WSF_REQUEST): STRING + -- Request uri rewriten as url. + do + Result := a_request.request_uri + end + +end diff --git a/examples/proxy/proxy.ecf b/examples/proxy/proxy.ecf new file mode 100644 index 00000000..e22facd4 --- /dev/null +++ b/examples/proxy/proxy.ecf @@ -0,0 +1,27 @@ + + + + + /.svn$ + /CVS$ + /EIFGENs$ + + + + + + + + + + + + + + + + diff --git a/examples/proxy/server.ini b/examples/proxy/server.ini new file mode 100644 index 00000000..ae90215c --- /dev/null +++ b/examples/proxy/server.ini @@ -0,0 +1,8 @@ +verbose=true +verbose_level=ALERT +port=9090 +#max_concurrent_connections=100 +#keep_alive_timeout=15 +#max_tcp_clients=100 +#socket_timeout=300 +#max_keep_alive_requests=300 diff --git a/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e new file mode 100644 index 00000000..699063df --- /dev/null +++ b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e @@ -0,0 +1,295 @@ +note + description: "Summary description for {WSF_SIMPLE_REVERSE_PROXY_HANDLER}." + date: "$Date$" + revision: "$Revision$" + +class + WSF_SIMPLE_REVERSE_PROXY_HANDLER + +create + make + +feature {NONE} -- Initialization + + make (a_host: READABLE_STRING_8; a_port: INTEGER_32) + do + create host.make_from_string (a_host) + port := a_port + timeout := 30 -- seconds. See {NETWORK_SOCKET}.default_timeout + connect_timeout := 5_000 -- 5 seconds. + is_via_header_supported := True + end + +feature -- Access + + host: IMMUTABLE_STRING_8 + -- Hostname of the targetted service. + + port: INTEGER + -- Port number of the targetted service. + + uri_rewriter: detachable WSF_URI_REWRITER assign set_uri_rewriter + -- URI rewriter component, to compute the URI on targetted service + -- based on current request. + +feature -- Settings + + connect_timeout: INTEGER assign set_connect_timeout + -- In milliseconds. + + timeout: INTEGER assign set_timeout + -- In seconds. + + is_via_header_supported: BOOLEAN + -- Via: header supported. + -- Default: True. + +feature -- Change + + set_uri_rewriter (a_rewriter: like uri_rewriter) + do + uri_rewriter := a_rewriter + end + + set_timeout (a_timeout_in_seconds: INTEGER) + -- in seconds. + do + timeout := a_timeout_in_seconds + end + + set_connect_timeout (a_timeout_in_milliseconds: INTEGER) + -- in milliseconds. + do + connect_timeout := a_timeout_in_milliseconds + end + + set_is_via_header_supported (b: BOOLEAN) + -- Set `is_via_header_supported' to `b'. + do + is_via_header_supported := b + end + +feature -- Execution + + proxy_uri (request: WSF_REQUEST): STRING + -- URI to query on proxyfied host. + do + if attached uri_rewriter as r then + Result := r.uri (request) + else + Result := request.request_uri + end + end + + execute (request: WSF_REQUEST; response: WSF_RESPONSE) + -- Execute reverse proxy request. + local + l_socket: NETWORK_STREAM_SOCKET + h: HTTP_HEADER + l_http_query: STRING + l_status_line: STRING + l_max_forward: INTEGER + l_via: detachable STRING + l_protocol: STRING + i: INTEGER + l_completed: BOOLEAN + do + if attached (create {INET_ADDRESS_FACTORY}).create_from_name (host) as l_peer_address then + create l_socket.make_client_by_address_and_port (l_peer_address, port) + l_socket.set_connect_timeout (connect_timeout) -- milliseconds + l_socket.set_timeout (timeout) -- seconds + + l_socket.connect + if l_socket.is_connected then + create l_http_query.make_from_string (request.request_method) + l_http_query.append_character (' ') + l_http_query.append (proxy_uri (request)) + l_http_query.append_character (' ') + l_http_query.append (request.server_protocol) + if attached request.raw_header_data as l_raw_header then + i := l_raw_header.substring_index ("%R%N", 1) + if i > 0 then + -- Skip the first status line. + create h.make_from_raw_header_data (l_raw_header.substring (i + 2, l_raw_header.count)) + else + create h.make_from_raw_header_data (l_raw_header) + end + + -- Via header + if is_via_header_supported then + if attached h.item ("Via") as v then + l_via := v + l_via.append (", ") + else + create l_via.make_empty + end + l_via.append (request.server_protocol + " " + request.server_name + " (PROXY-" + request.server_software + ")") + h.put_header_key_value ("Via", l_via) + end + + -- Max-Forwards header handling + if attached h.item ("Max-Forwards") as h_max_forward then + -- Max-Forwards: 0 stop, otherwise decrement by one. + -- see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.31 + if h_max_forward.is_integer then + l_max_forward := h_max_forward.to_integer - 1 + if l_max_forward >= 0 then + h.put_header_key_value ("Max-Forwards", l_max_forward.out) + end + end + end + if l_max_forward < 0 then + -- i.e previous Max-Forwards was '0' + send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Reached maximum number of Forwards, not forwarded to " + host + ":" + port.out) + else + l_socket.put_string (l_http_query) + l_socket.put_string ("%R%N") + l_socket.put_string (h.string) + l_socket.put_string ("%R%N") + if request.content_length_value > 0 then + request.read_input_data_into_file (l_socket) + end + + -- Get HTTP status + l_socket.read_line_thread_aware + create l_status_line.make_from_string (l_socket.last_string) + -- Get HTTP header block + if attached next_http_header_block (l_socket) as l_resp_header then + create h.make_from_raw_header_data (l_resp_header) + if attached status_line_info (l_status_line) as l_status_info then + l_protocol := l_status_info.protocol + if attached l_status_info.reason_phrase as l_phrase then + response.set_status_code_with_reason_phrase (l_status_info.status_code, l_phrase) + else + response.set_status_code (l_status_info.status_code) + end + else + check has_status_line: False end + l_protocol := "1.0" -- Default? + response.set_status_code (80) + end + + if is_via_header_supported then + if attached h.item ("Via") as v then + l_via := v + l_via.append (", ") + else + create l_via.make_empty + end + l_via.append (l_protocol + " " + request.server_name + " (PROXY-" + request.server_software + ")") + h.put_header_key_value ("Via", l_via) + end + + response.add_header_lines (h) + from + l_socket.read_stream (2_048) + until + l_socket.was_error + or not l_socket.is_connected + or l_socket.bytes_read <= 0 + or l_completed + loop + response.put_string (l_socket.last_string) + if l_socket.bytes_read = 2_048 then + l_socket.read_stream (2_048) + else + l_completed := True + end + end + else + send_error (request, response, {HTTP_STATUS_CODE}.internal_server_error, "Invalid response header!") + end + end + else + send_error (request, response, {HTTP_STATUS_CODE}.internal_server_error, "Can not access request header!") + end + else + send_error (request, response, {HTTP_STATUS_CODE}.gateway_timeout, "Can not connect " + host + ":" + port.out) + end + else + send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Host not found!") + end + end + +feature {NONE} -- Implementation + + status_line_info (a_line: READABLE_STRING_8): detachable TUPLE [protocol: READABLE_STRING_8; status_code: INTEGER; reason_phrase: detachable READABLE_STRING_8] + -- Info from status line + --| Such as "HTTP/1.1 200 OK" -> ["1.1", 200, "OK"] + local + i,j: INTEGER + p,s: detachable READABLE_STRING_8 + c: INTEGER + do + i := a_line.index_of (' ', 1) + if i > 0 then + p := a_line.substring (1, i - 1) + if p.starts_with_general ("HTTP/") then + p := p.substring (6, p.count) -- We could also keep HTTP/ + end + j := i + 1 + i := a_line.index_of (' ', j) + if i > 0 then + s := a_line.substring (j, i - 1) + if s.is_integer then + c := s.to_integer + s := a_line.substring (i + 1, a_line.count) + if s.is_whitespace then + s := Void + elseif s[s.count].is_space then + s := s.substring (1, s.count - 1) + end + Result := [p, c, s] + end + end + end + end + + next_http_header_block (a_socket: NETWORK_STREAM_SOCKET): detachable STRING + local + h: STRING + do + create h.make_empty + from + a_socket.read_line_thread_aware + until + Result /= Void + or a_socket.was_error + or (a_socket.bytes_read = 0 or a_socket.bytes_read = -1) + or not a_socket.is_connected + loop + if a_socket.last_string.same_string ("%R") then + -- End of header + Result := h + else + h.append (a_socket.last_string) + h.append ("%N") + a_socket.read_line_thread_aware + end + end + end + + send_error (request: WSF_REQUEST; response: WSF_RESPONSE; a_status_code: INTEGER; a_message: READABLE_STRING_8) + local + s: STRING + do + -- To send a response we need to setup, the status code and + -- the response headers. + create s.make_from_string (a_message) + debug + s.append ("%N(UTC time is " + (create {HTTP_DATE}.make_now_utc).rfc850_string + ").%N") + end + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "plain/text"], ["Content-Length", s.count.out]>>) + response.set_status_code (a_status_code) + 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/library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e b/library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e new file mode 100644 index 00000000..fc054b36 --- /dev/null +++ b/library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e @@ -0,0 +1,38 @@ +note + description: "Summary description for {WSF_AGENT_URI_REWRITER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_AGENT_URI_REWRITER + +inherit + WSF_URI_REWRITER + +create + make + +--convert +-- make ({FUNCTION [TUPLE [WSF_REQUEST], STRING]}) + +feature {NONE} -- Initialization + + make (a_rewriter_function: like rewriter_function) + do + rewriter_function := a_rewriter_function + end + +feature -- Access + + rewriter_function: FUNCTION [TUPLE [WSF_REQUEST], STRING] + +feature -- Conversion + + uri (a_request: WSF_REQUEST): STRING + -- . + do + Result := rewriter_function (a_request) + end + +end diff --git a/library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e b/library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e new file mode 100644 index 00000000..6cbc1cad --- /dev/null +++ b/library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {WSF_URI_REWRITER}." + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_URI_REWRITER + +feature -- Conversion + + uri (a_request: WSF_REQUEST): STRING + -- Rewritten request uri based on `a_request'. + deferred + end + +end diff --git a/library/server/wsf_proxy/wsf_proxy-safe.ecf b/library/server/wsf_proxy/wsf_proxy-safe.ecf new file mode 100644 index 00000000..f8a2dffb --- /dev/null +++ b/library/server/wsf_proxy/wsf_proxy-safe.ecf @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/library/server/wsf_proxy/wsf_proxy.ecf b/library/server/wsf_proxy/wsf_proxy.ecf new file mode 100644 index 00000000..01cf4581 --- /dev/null +++ b/library/server/wsf_proxy/wsf_proxy.ecf @@ -0,0 +1,14 @@ + + + + + + + + + + + + + From 210fae5000eb715c31de2914aab6c47e8ef7f774 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Sat, 6 Aug 2016 10:04:45 +0200 Subject: [PATCH 2/3] First step towards SSL support. --- examples/proxy/proxy.ecf | 2 +- .../wsf_simple_reverse_proxy_handler.e | 4 +-- library/server/wsf_proxy/wsf_proxy-safe.ecf | 25 +++++++++++++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/examples/proxy/proxy.ecf b/examples/proxy/proxy.ecf index e22facd4..31ef951a 100644 --- a/examples/proxy/proxy.ecf +++ b/examples/proxy/proxy.ecf @@ -13,7 +13,7 @@ - + diff --git a/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e index 699063df..ac6753c3 100644 --- a/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e +++ b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e @@ -84,7 +84,6 @@ feature -- Execution execute (request: WSF_REQUEST; response: WSF_RESPONSE) -- Execute reverse proxy request. local - l_socket: NETWORK_STREAM_SOCKET h: HTTP_HEADER l_http_query: STRING l_status_line: STRING @@ -94,8 +93,7 @@ feature -- Execution i: INTEGER l_completed: BOOLEAN do - if attached (create {INET_ADDRESS_FACTORY}).create_from_name (host) as l_peer_address then - create l_socket.make_client_by_address_and_port (l_peer_address, port) + if attached (create {WSF_PROXY_SOCKET_FACTORY}).socket (host, port) as l_socket then l_socket.set_connect_timeout (connect_timeout) -- milliseconds l_socket.set_timeout (timeout) -- seconds diff --git a/library/server/wsf_proxy/wsf_proxy-safe.ecf b/library/server/wsf_proxy/wsf_proxy-safe.ecf index f8a2dffb..f07f10df 100644 --- a/library/server/wsf_proxy/wsf_proxy-safe.ecf +++ b/library/server/wsf_proxy/wsf_proxy-safe.ecf @@ -5,8 +5,29 @@ + + + + + - - + + + ssl + no_ssl + + + + + + + + + + + + + + From 5029049ef0e9703d6646b374f1c46c59aee79198 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Mon, 8 Aug 2016 12:30:28 +0200 Subject: [PATCH 3/3] Replaced host+port by uri (http://remotemachine:port/path). Added support for SSL (https). --- examples/proxy/application_execution.e | 10 +-- examples/proxy/proxy.ecf | 1 + .../network/no_ssl/wsf_proxy_socket_factory.e | 20 ++++++ .../network/ssl/wsf_proxy_socket_factory.e | 30 +++++++++ .../network/wsf_proxy_socket_factory_i.e | 67 +++++++++++++++++++ .../wsf_simple_reverse_proxy_handler.e | 34 ++++++---- library/server/wsf_proxy/wsf_proxy-safe.ecf | 9 +-- 7 files changed, 150 insertions(+), 21 deletions(-) create mode 100644 library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e create mode 100644 library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e create mode 100644 library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e diff --git a/examples/proxy/application_execution.e b/examples/proxy/application_execution.e index 44440c88..ab54495e 100644 --- a/examples/proxy/application_execution.e +++ b/examples/proxy/application_execution.e @@ -21,16 +21,16 @@ feature -- Basic operations execute do - -- NOTE: please enter the target reverse proxy machine + port number here - -- replace "localhost" and 8080 - send_proxy_response ("localhost", 8080, Current) + -- NOTE: please enter the target server uri here + -- replace "http://localhost:8080/foobar" + send_proxy_response ("http://localhost:8080/foobar", Current) end - send_proxy_response (a_hostname: READABLE_STRING_8; a_port: INTEGER; a_rewriter: detachable WSF_URI_REWRITER) + send_proxy_response (a_remote: READABLE_STRING_8; a_rewriter: detachable WSF_URI_REWRITER) local h: WSF_SIMPLE_REVERSE_PROXY_HANDLER do - create h.make (a_hostname, a_port) + create h.make (a_remote) h.set_uri_rewriter (a_rewriter) h.set_uri_rewriter (create {WSF_AGENT_URI_REWRITER}.make (agent proxy_uri)) h.set_timeout (30) -- 30 seconds diff --git a/examples/proxy/proxy.ecf b/examples/proxy/proxy.ecf index 31ef951a..9bf59a52 100644 --- a/examples/proxy/proxy.ecf +++ b/examples/proxy/proxy.ecf @@ -10,6 +10,7 @@ + diff --git a/library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e b/library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e new file mode 100644 index 00000000..21c2e7ea --- /dev/null +++ b/library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e @@ -0,0 +1,20 @@ +note + description: "Summary description for {WSF_PROXY_SOCKET_FACTORY}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_PROXY_SOCKET_FACTORY + +inherit + WSF_PROXY_SOCKET_FACTORY_I + +feature {NONE} -- Implementation + + ssl_socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable NETWORK_STREAM_SOCKET + do + check supported: False end + end + +end diff --git a/library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e b/library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e new file mode 100644 index 00000000..ad264908 --- /dev/null +++ b/library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e @@ -0,0 +1,30 @@ +note + description: "Summary description for {WSF_PROXY_SOCKET_FACTORY}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_PROXY_SOCKET_FACTORY + +inherit + WSF_PROXY_SOCKET_FACTORY_I + redefine + is_ssl_supported + end + +feature {NONE} -- Implementation + + ssl_socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable SSL_NETWORK_STREAM_SOCKET + do + if attached create_from_name (a_host) as l_peer_address then + create Result.make_client_by_address_and_port (l_peer_address, a_port) + end + end + +feature -- Status + + is_ssl_supported: BOOLEAN = True + -- Is https:// supported? + +end diff --git a/library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e b/library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e new file mode 100644 index 00000000..900db008 --- /dev/null +++ b/library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e @@ -0,0 +1,67 @@ +note + description: "Summary description for {WSF_PROXY_SOCKET_FACTORY_I}." + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_PROXY_SOCKET_FACTORY_I + +inherit + INET_ADDRESS_FACTORY + +feature -- Access + + socket_from_uri (a_uri: URI): like socket + local + l_port: INTEGER + do + if a_uri.is_valid and then attached a_uri.host as l_host then + l_port := a_uri.port + if a_uri.scheme.is_case_insensitive_equal_general ("https") then + if is_ssl_supported then + if l_port <= 0 then + l_port := 443 + end + Result := ssl_socket (l_host, l_port) + end + elseif a_uri.scheme.is_case_insensitive_equal_general ("http") then + if l_port <= 0 then + l_port := 80 + end + Result := socket (l_host, l_port) + end + end + end + +feature -- Status + + is_uri_supported (a_uri: URI): BOOLEAN + do + Result := a_uri.scheme.is_case_insensitive_equal_general ("http") + or else ( + a_uri.scheme.is_case_insensitive_equal_general ("https") + and is_ssl_supported + ) + end + + is_ssl_supported: BOOLEAN + -- Is https:// supported? + do + end + +feature {NONE} -- Implementation + + socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable NETWORK_STREAM_SOCKET + do + if attached create_from_name (a_host) as l_peer_address then + create Result.make_client_by_address_and_port (l_peer_address, a_port) + end + end + + ssl_socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable NETWORK_STREAM_SOCKET + require + is_ssl_supported: is_ssl_supported + deferred + end + +end diff --git a/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e index ac6753c3..a0ab3c6b 100644 --- a/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e +++ b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e @@ -11,10 +11,9 @@ create feature {NONE} -- Initialization - make (a_host: READABLE_STRING_8; a_port: INTEGER_32) + make (a_remote_uri: READABLE_STRING_8) do - create host.make_from_string (a_host) - port := a_port + create remote_uri.make_from_string (a_remote_uri) timeout := 30 -- seconds. See {NETWORK_SOCKET}.default_timeout connect_timeout := 5_000 -- 5 seconds. is_via_header_supported := True @@ -22,11 +21,8 @@ feature {NONE} -- Initialization feature -- Access - host: IMMUTABLE_STRING_8 - -- Hostname of the targetted service. - - port: INTEGER - -- Port number of the targetted service. + remote_uri: URI + -- Url for the targetted service. uri_rewriter: detachable WSF_URI_REWRITER assign set_uri_rewriter -- URI rewriter component, to compute the URI on targetted service @@ -92,8 +88,14 @@ feature -- Execution l_protocol: STRING i: INTEGER l_completed: BOOLEAN + l_remote_uri: like remote_uri + l_socket_factory: WSF_PROXY_SOCKET_FACTORY do - if attached (create {WSF_PROXY_SOCKET_FACTORY}).socket (host, port) as l_socket then + l_remote_uri := remote_uri + create l_socket_factory + if not l_socket_factory.is_uri_supported (l_remote_uri) then + send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, l_remote_uri.scheme + " is not supported! [for remote " + l_remote_uri.string + "]") + elseif attached l_socket_factory.socket_from_uri (l_remote_uri) as l_socket then l_socket.set_connect_timeout (connect_timeout) -- milliseconds l_socket.set_timeout (timeout) -- seconds @@ -101,6 +103,7 @@ feature -- Execution if l_socket.is_connected then create l_http_query.make_from_string (request.request_method) l_http_query.append_character (' ') + l_http_query.append (l_remote_uri.path) l_http_query.append (proxy_uri (request)) l_http_query.append_character (' ') l_http_query.append (request.server_protocol) @@ -112,6 +115,13 @@ feature -- Execution else create h.make_from_raw_header_data (l_raw_header) end + if attached l_remote_uri.host as l_remote_host then + if l_remote_uri.port > 0 then + h.put_header_key_value ("Host", l_remote_host + ":" + l_remote_uri.port.out) + else + h.put_header_key_value ("Host", l_remote_host) + end + end -- Via header if is_via_header_supported then @@ -138,7 +148,7 @@ feature -- Execution end if l_max_forward < 0 then -- i.e previous Max-Forwards was '0' - send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Reached maximum number of Forwards, not forwarded to " + host + ":" + port.out) + send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Reached maximum number of Forwards, not forwarded to " + l_remote_uri.string) else l_socket.put_string (l_http_query) l_socket.put_string ("%R%N") @@ -202,10 +212,10 @@ feature -- Execution send_error (request, response, {HTTP_STATUS_CODE}.internal_server_error, "Can not access request header!") end else - send_error (request, response, {HTTP_STATUS_CODE}.gateway_timeout, "Can not connect " + host + ":" + port.out) + send_error (request, response, {HTTP_STATUS_CODE}.gateway_timeout, "Unable to connect " + l_remote_uri.string) end else - send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Host not found!") + send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Unable to connect " + l_remote_uri.string) end end diff --git a/library/server/wsf_proxy/wsf_proxy-safe.ecf b/library/server/wsf_proxy/wsf_proxy-safe.ecf index f07f10df..9dd777ce 100644 --- a/library/server/wsf_proxy/wsf_proxy-safe.ecf +++ b/library/server/wsf_proxy/wsf_proxy-safe.ecf @@ -5,23 +5,24 @@ - + + - ssl no_ssl + ssl - + - +