diff --git a/examples/filter/filter-safe.ecf b/examples/filter/filter-safe.ecf
index a1b5c3fd..8edae596 100644
--- a/examples/filter/filter-safe.ecf
+++ b/examples/filter/filter-safe.ecf
@@ -13,6 +13,7 @@
+
diff --git a/examples/filter/src/filter_server.e b/examples/filter/src/filter_server.e
index 1c7a257c..7368581d 100644
--- a/examples/filter/src/filter_server.e
+++ b/examples/filter/src/filter_server.e
@@ -24,38 +24,60 @@ create
feature {NONE} -- Initialization
make
+ local
+ l_message: STRING
+ l_factory: INET_ADDRESS_FACTORY
do
+ create router.make (1)
initialize_filter
initialize_json
- set_service_option ("port", 9090)
+ set_service_option ("port", port)
+ create l_message.make_empty
+ l_message.append_string ("Launching filter server at ")
+ create l_factory
+ l_message.append_string (l_factory.create_localhost.host_name)
+ l_message.append_string (" port ")
+ l_message.append_integer (port)
+ io.put_string (l_message)
+ io.put_new_line
make_and_launch
end
create_filter
-- Create `filter'
local
- l_authentication_filter_hdl: AUTHENTICATION_FILTER
- l_user_filter: USER_HANDLER
- l_routing_filter: WSF_ROUTING_FILTER
+ l_cors_filter: WSF_CORS_FILTER
do
- create router.make (1)
- create l_authentication_filter_hdl
- create l_user_filter
- l_authentication_filter_hdl.set_next (l_user_filter)
-
- router.handle_with_request_methods ("/user/{userid}", l_authentication_filter_hdl, router.methods_get)
- create l_routing_filter.make (router)
- l_routing_filter.set_execute_default_action (agent execute_default)
- filter := l_routing_filter
+ create l_cors_filter
+ filter := l_cors_filter
end
setup_filter
-- Setup `filter'
local
+ l_options_filter: WSF_CORS_OPTIONS_FILTER
+ l_authentication_filter: AUTHENTICATION_FILTER
+ l_user_filter: USER_HANDLER
+ l_methods: WSF_REQUEST_METHODS
+ l_routing_filter: WSF_ROUTING_FILTER
l_logging_filter: WSF_LOGGING_FILTER
do
+ create l_options_filter.make (router)
+ create l_authentication_filter
+ l_options_filter.set_next (l_authentication_filter)
+ create l_user_filter
+ l_authentication_filter.set_next (l_user_filter)
+
+ create l_methods
+ l_methods.enable_options
+ l_methods.enable_get
+ router.handle_with_request_methods ("/user/{userid}", l_options_filter, l_methods)
+ create l_routing_filter.make (router)
+ l_routing_filter.set_execute_default_action (agent execute_default)
+ filter.set_next (l_routing_filter)
+
create l_logging_filter
- filter.set_next (l_logging_filter)
+ l_routing_filter.set_next (l_logging_filter)
end
initialize_json
@@ -82,6 +104,9 @@ feature -- Basic operations
feature {NONE} -- Implementation
+ port: INTEGER = 9090
+ -- Port number
+
router: WSF_ROUTER;
-- Router
diff --git a/library/network/protocol/http/src/http_header.e b/library/network/protocol/http/src/http_header.e
index a9cee805..82281ccd 100644
--- a/library/network/protocol/http/src/http_header.e
+++ b/library/network/protocol/http/src/http_header.e
@@ -504,6 +504,32 @@ feature -- Content-type helpers
put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end
put_content_type_application_x_www_form_encoded do put_content_type ({HTTP_MIME_TYPES}.application_x_www_form_encoded) end
+feature -- Cross-Origin Resource Sharing
+
+ put_access_control_allow_origin (s: READABLE_STRING_8)
+ -- Put "Access-Control-Allow-Origin" header.
+ do
+ put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_origin, s)
+ end
+
+ put_access_control_allow_all_origin
+ -- Put "Access-Control-Allow-Origin: *" header.
+ do
+ put_access_control_allow_origin ("*")
+ end
+
+ put_access_control_allow_methods (a_methods: ITERABLE [READABLE_STRING_8])
+ -- If `a_methods' is not empty, put `Access-Control-Allow-Methods' header with list `a_methods' of methods
+ do
+ put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_methods, a_methods, Void)
+ end
+
+ put_access_control_allow_headers (s: READABLE_STRING_8)
+ -- Put "Access-Control-Allow-Headers" header.
+ do
+ put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, s)
+ end
+
feature -- Method related
put_allow (a_methods: ITERABLE [READABLE_STRING_8])
diff --git a/library/network/protocol/http/src/http_header_names.e b/library/network/protocol/http/src/http_header_names.e
index 8d679ea9..4bab76e8 100644
--- a/library/network/protocol/http/src/http_header_names.e
+++ b/library/network/protocol/http/src/http_header_names.e
@@ -194,6 +194,23 @@ feature -- Response header name
-- Indicates the authentication scheme that should be used to access the requested entity.
--| Example: WWW-Authenticate: Basic
+feature -- Cross-Origin Resource Sharing
+
+ header_access_control_allow_origin: STRING = "Access-Control-Allow-Origin"
+ -- Indicates whether a resource can be shared based by returning
+ -- the value of the Origin request header in the response.
+ -- | Example: Access-Control-Allow-Origin: http://example.org
+
+ header_access_control_allow_methods: STRING = "Access-Control-Allow-Methods"
+ -- Indicates, as part of the response to a preflight request,
+ -- which methods can be used during the actual request.
+ -- | Example: Access-Control-Allow-Methods: PUT, DELETE
+
+ header_access_control_allow_headers: STRING = "Access-Control-Allow-Headers"
+ -- Indicates, as part of the response to a preflight request,
+ -- which header field names can be used during the actual request.
+ -- | Example: Access-Control-Allow-Headers: Authorization
+
feature -- Request or Response header name
header_cache_control: STRING = "Cache-Control"
@@ -248,7 +265,7 @@ feature -- MIME related
header_content_transfer_encoding: STRING = "Content-Transfer-Encoding"
note
- copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
+ copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
diff --git a/library/server/ewsgi/specification/request/wgi_meta_names.e b/library/server/ewsgi/specification/request/wgi_meta_names.e
index 4b2f10b8..7eeb913e 100644
--- a/library/server/ewsgi/specification/request/wgi_meta_names.e
+++ b/library/server/ewsgi/specification/request/wgi_meta_names.e
@@ -50,6 +50,8 @@ feature -- Access
http_transfer_encoding: STRING = "HTTP_TRANSFER_ENCODING"
+ http_access_control_request_headers: STRING = "HTTP_ACCESS_CONTROL_REQUEST_HEADERS"
+
gateway_interface: STRING = "GATEWAY_INTERFACE"
auth_type: STRING = "AUTH_TYPE"
diff --git a/library/server/ewsgi/specification/request/wgi_request.e b/library/server/ewsgi/specification/request/wgi_request.e
index 1dccd709..86e1e489 100644
--- a/library/server/ewsgi/specification/request/wgi_request.e
+++ b/library/server/ewsgi/specification/request/wgi_request.e
@@ -598,6 +598,12 @@ feature -- HTTP_*
deferred
end
+ http_access_control_request_headers: detachable READABLE_STRING_8
+ -- Indicates which headers will be used in the actual request
+ -- as part of the preflight request
+ deferred
+ end
+
feature -- Extra CGI environment variables
request_uri: READABLE_STRING_8
diff --git a/library/server/ewsgi/src/implementation/wgi_request_from_table.e b/library/server/ewsgi/src/implementation/wgi_request_from_table.e
index 2bfa00d6..79fb3007 100644
--- a/library/server/ewsgi/src/implementation/wgi_request_from_table.e
+++ b/library/server/ewsgi/src/implementation/wgi_request_from_table.e
@@ -241,6 +241,13 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1
Result := meta_string_variable ({WGI_META_NAMES}.http_transfer_encoding)
end
+ http_access_control_request_headers: detachable READABLE_STRING_8
+ -- Indicates which headers will be used in the actual request
+ -- as part of the preflight request
+ do
+ Result := meta_string_variable ({WGI_META_NAMES}.http_access_control_request_headers)
+ end
+
feature -- Access: Extension to CGI meta parameters - 1.1
request_uri: READABLE_STRING_8
diff --git a/library/server/wsf/router/filter/wsf_cors_filter.e b/library/server/wsf/router/filter/wsf_cors_filter.e
new file mode 100644
index 00000000..75db6afe
--- /dev/null
+++ b/library/server/wsf/router/filter/wsf_cors_filter.e
@@ -0,0 +1,37 @@
+note
+ description: "Cross-Origin Resource Sharing filter."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+ EIS: "name=Cross-Origin Resource Sharing", "src=http://www.w3.org/TR/cors/", "tag=W3C"
+
+class
+ WSF_CORS_FILTER
+
+inherit
+ WSF_FILTER
+
+feature -- Basic operations
+
+ execute (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the filter.
+ local
+ l_header: HTTP_HEADER
+ do
+ create l_header.make
+ l_header.put_access_control_allow_all_origin
+ res.put_header_text (l_header.string)
+ execute_next (req, res)
+ end
+
+note
+ copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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
diff --git a/library/server/wsf/router/filter/wsf_cors_options_filter.e b/library/server/wsf/router/filter/wsf_cors_options_filter.e
new file mode 100644
index 00000000..7ca0bd87
--- /dev/null
+++ b/library/server/wsf/router/filter/wsf_cors_options_filter.e
@@ -0,0 +1,59 @@
+note
+ description: "Filter that handles an OPTIONS request, with Cross-Origin Resource Sharing support."
+ author: "Olvier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+ EIS: "name=Cross-Origin Resource Sharing", "src=http://www.w3.org/TR/cors/", "tag=W3C"
+
+class
+ WSF_CORS_OPTIONS_FILTER
+
+inherit
+ WSF_FILTER
+
+ WSF_URI_TEMPLATE_HANDLER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_router: like router)
+ -- Initialize Current with `a_router'.
+ do
+ router := a_router
+ ensure
+ router_set: router = a_router
+ end
+
+feature -- Access
+
+ router: WSF_ROUTER
+ -- Associated router
+
+feature -- Basic operations
+
+ execute (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the filter.
+ local
+ msg: WSF_CORS_OPTIONS_RESPONSE
+ do
+ if req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) then
+ create msg.make (req, router)
+ res.send (msg)
+ else
+ execute_next (req, res)
+ end
+ end
+
+note
+ copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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
diff --git a/library/server/wsf/src/response/wsf_cors_options_response.e b/library/server/wsf/src/response/wsf_cors_options_response.e
new file mode 100644
index 00000000..0c928e2a
--- /dev/null
+++ b/library/server/wsf/src/response/wsf_cors_options_response.e
@@ -0,0 +1,68 @@
+note
+ description: "Response to an OPTIONS request, with Cross-Origin Resource Sharing support."
+ author: "Olivier Ligt"
+ date: "$Date$"
+ revision: "$Revision$"
+ EIS: "name=Cross-Origin Resource Sharing", "src=http://www.w3.org/TR/cors/", "tag=W3C"
+
+class
+ WSF_CORS_OPTIONS_RESPONSE
+
+inherit
+ WSF_RESPONSE_MESSAGE
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (req: WSF_REQUEST; a_router: like router)
+ do
+ request := req
+ router := a_router
+ create header.make
+ end
+
+feature -- Access
+
+ request: WSF_REQUEST
+ -- Associated request
+
+ router: WSF_ROUTER
+ -- Associated router
+
+ header: HTTP_HEADER
+ -- Response' header
+
+feature {WSF_RESPONSE} -- Output
+
+ send_to (res: WSF_RESPONSE)
+ local
+ l_methods: WSF_REQUEST_METHODS
+ do
+ res.set_status_code ({HTTP_STATUS_CODE}.Ok)
+ header.put_content_type ({HTTP_MIME_TYPES}.text_plain)
+ header.put_current_date
+ header.put_content_length (0)
+ if attached request.http_access_control_request_headers as l_headers then
+ header.put_access_control_allow_headers (l_headers)
+ end
+ l_methods := router.allowed_methods_for_request (request)
+ if not l_methods.is_empty then
+ header.put_allow (l_methods)
+ header.put_access_control_allow_methods (l_methods)
+ end
+ res.put_header_text (header.string)
+ end
+
+note
+ copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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
diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e
index 129c9937..bc755715 100644
--- a/library/server/wsf/src/wsf_request.e
+++ b/library/server/wsf/src/wsf_request.e
@@ -1041,6 +1041,13 @@ feature -- HTTP_*
Result := wgi_request.http_transfer_encoding
end
+ http_access_control_request_headers: detachable READABLE_STRING_8
+ -- Indicates which headers will be used in the actual request
+ -- as part of the preflight request
+ do
+ Result := wgi_request.http_access_control_request_headers
+ end
+
feature -- Extra CGI environment variables
request_uri: READABLE_STRING_8