diff --git a/library/network/protocol/content_negotiation/README.md b/library/network/protocol/content_negotiation/README.md
index d86bcedb..bb4f9b2e 100644
--- a/library/network/protocol/content_negotiation/README.md
+++ b/library/network/protocol/content_negotiation/README.md
@@ -1,125 +1,31 @@
-CONNEG is a library that provides utilities to select the best repesentation of a resource for a client
-where there are multiple representations available.
+CONNEG is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
-Using this labrary you can retrieve the best Variant for media type, language preference, enconding and compression.
-The library is based on eMIME Eiffel MIME library based on Joe Gregorio code
+Using this library you can retrieve the best variant for media type, language preference, charset, and enconding/compression.
Take into account that the library is under development so is expected that the API change.
The library contains utilities that deal with content negotiation (server driven negotiation).This utility class
is based on ideas taken from the Book Restful WebServices Cookbook
-The class CONNEG_SERVER_SIDE contains several features that helps to write different type of negotiations (media type, language,
+The class SERVER_CONTENT_NEGOTIATION contains several features that helps to write different types of negotiation (media type, language,
charset and compression).
So for each of the following questions, you will have a corresponding method to help in the solution.
- How to implement Media type negotiation?
- Hint: Use CONNEG_SERVER_SIDE.media_type_preference
+ Hint: Use SERVER_CONTENT_NEGOTIATION.media_type_preference
+ or SERVER_MEDIA_TYPE_NEGOTIATION.preference
- How to implement Language Negotiation?
- Hint: Use CONNEG_SERVER_SIDE.language_preference
+ Hint: Use SERVER_CONTENT_NEGOTIATION.language_preference
+ or SERVER_LANGUAGE_NEGOTIATION.preference
-- How to implement Character encoding Negotiation?
- Hint: Use CONNEG_SERVER_SIDE.charset_preference
+- How to implement Character Negotiation?
+ Hint: Use SERVER_CONTENT_NEGOTIATION.charset_preference
+ or SERVER_CHARSET_NEGOTIATION.preference
-- How to implement Compression Negotiation?
- Hint: Use CONNEG_SERVER_SIDE.encoding_preference
+- How to implement Encoding Negotiation?
+ Hint: Use SERVER_CONTENT_NEGOTIATION.encoding_preference
+ or SERVER_ENCODING_NEGOTIATION.preference
There is also a [test case](test/conneg_server_side_test.e "conneg_server_side_test") where you can check how to use this class.
- note
- description: "Summary description for CONNEG_SERVER_SIDE. Utility class to support Server Side Content Negotiation "
- author: ""
- date: "$Date$"
- revision: "$Revision$"
- description: "[
- Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
- Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
- it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
- and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
- Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
- or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
- In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
- ]"
-
- class interface
- CONNEG_SERVER_SIDE
-
- create
- make
-
- feature -- Initialization
-
- make (a_mime: STRING_8; a_language: STRING_8; a_charset: STRING_8; an_encoding: STRING_8)
-
- feature -- Compression Negotiation
-
- encoding_preference (server_encoding_supported: LIST [STRING_8]; header: STRING_8): COMPRESSION_VARIANT_RESULTS
- -- server_encoding_supported represent a list of encoding supported by the server.
- -- header represent the Accept-Encoding header, ie, the client preferences.
- -- Return which Encoding to use in a response, if the server support
- -- one Encoding, or empty in other case.
- -- Representation: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
-
- feature -- Encoding Negotiation
-
- charset_preference (server_charset_supported: LIST [STRING_8]; header: STRING_8): CHARACTER_ENCODING_VARIANT_RESULTS
- -- server_charset_supported represent a list of charset supported by the server.
- -- header represent the Accept-Charset header, ie, the client preferences.
- -- Return which Charset to use in a response, if the server support
- -- one Charset, or empty in other case.
- -- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
-
- feature -- Language Negotiation
-
- language_preference (server_language_supported: LIST [STRING_8]; header: STRING_8): LANGUAGE_VARIANT_RESULTS
- -- server_language_supported represent a list of languages supported by the server.
- -- header represent the Accept-Language header, ie, the client preferences.
- -- Return which Language to use in a response, if the server support
- -- one Language, or empty in other case.
- -- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
-
- feature -- Media Type Negotiation
-
- media_type_preference (mime_types_supported: LIST [STRING_8]; header: STRING_8): MEDIA_TYPE_VARIANT_RESULTS
- -- mime_types_supported represent media types supported by the server.
- -- header represent the Accept header, ie, the client preferences.
- -- Return which media type to use for representaion in a response, if the server support
- -- one media type, or empty in other case.
- -- Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
-
- feature -- Server Side Defaults Formats
-
- charset_default: STRING_8
-
- encoding_default: STRING_8
-
- language_default: STRING_8
-
- mime_default: STRING_8
-
- set_charset_default (a_charset: STRING_8)
- -- set the charset_default with `a_charset'
- ensure
- set_charset: a_charset ~ charset_default
-
- set_encoding_defautl (an_encoding: STRING_8)
- ensure
- set_encoding: an_encoding ~ encoding_default
-
- set_language_default (a_language: STRING_8)
- -- set the language_default with `a_language'
- ensure
- set_language: a_language ~ language_default
-
- set_mime_default (a_mime: STRING_8)
- -- set the mime_default with `a_mime'
- ensure
- set_mime_default: a_mime ~ mime_default
-
- note
- copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
- end -- class CONNEG_SERVER_SIDE
-
diff --git a/library/network/protocol/content_negotiation/conneg-safe.ecf b/library/network/protocol/content_negotiation/conneg-safe.ecf
index 06a7bda6..2bb7d7b2 100644
--- a/library/network/protocol/content_negotiation/conneg-safe.ecf
+++ b/library/network/protocol/content_negotiation/conneg-safe.ecf
@@ -13,6 +13,12 @@
-
+
+
+ /implementation
+
+
+
+
diff --git a/library/network/protocol/content_negotiation/conneg.ecf b/library/network/protocol/content_negotiation/conneg.ecf
index a4db8e63..6677144a 100644
--- a/library/network/protocol/content_negotiation/conneg.ecf
+++ b/library/network/protocol/content_negotiation/conneg.ecf
@@ -13,6 +13,12 @@
-
+
+
+ /implementation
+
+
+
+
diff --git a/library/network/protocol/content_negotiation/src/conneg_server_side.e b/library/network/protocol/content_negotiation/src/conneg_server_side.e
deleted file mode 100644
index 7440a799..00000000
--- a/library/network/protocol/content_negotiation/src/conneg_server_side.e
+++ /dev/null
@@ -1,230 +0,0 @@
-note
- description: "Summary description for {CONNEG_SERVER_SIDE}. Utility class to support Server Side Content Negotiation "
- date: "$Date$"
- revision: "$Revision$"
- description: "[
- Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
- Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
- it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
- and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
- Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
- or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
- In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
- ]"
- EIS: "name=server driven negotiation", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.", "protocol=uri"
-
-class
- CONNEG_SERVER_SIDE
-
-inherit
-
- SHARED_CONNEG
-
- REFACTORING_HELPER
-
-create
- make
-
-feature -- Initialization
-
- make (a_mime: READABLE_STRING_8; a_language: READABLE_STRING_8; a_charset: READABLE_STRING_8; a_encoding: READABLE_STRING_8)
- do
- set_mime_default (a_mime)
- set_language_default (a_language)
- set_charset_default (a_charset)
- set_encoding_default (a_encoding)
- ensure
- mime_default_set: mime_default = a_mime
- language_default_set: language_default = a_language
- charset_default_set: charset_default = a_charset
- encoding_default_set: encoding_default = a_encoding
- end
-
-feature -- AccessServer Side Defaults Formats
-
- mime_default: READABLE_STRING_8
- -- Media type which is acceptable for the response.
-
- language_default: READABLE_STRING_8
- -- Natural language that is preferred as a response to the request.
-
- charset_default: READABLE_STRING_8
- -- Character set that is acceptable for the response.
-
- encoding_default: READABLE_STRING_8
- -- Content-coding that is acceptable in the response.
-
-feature -- Change Element
-
- set_mime_default (a_mime: READABLE_STRING_8)
- -- Set the mime_default with `a_mime'
- do
- mime_default := a_mime
- ensure
- mime_default_set: a_mime = mime_default
- end
-
- set_language_default (a_language: READABLE_STRING_8)
- -- Set the language_default with `a_language'
- do
- language_default := a_language
- ensure
- language_default_set: a_language = language_default
- end
-
- set_charset_default (a_charset: READABLE_STRING_8)
- -- Set the charset_default with `a_charset'
- do
- charset_default := a_charset
- ensure
- charset_default_set: a_charset = charset_default
- end
-
- set_encoding_default (a_encoding: READABLE_STRING_8)
- do
- encoding_default := a_encoding
- ensure
- encoding_default_set: a_encoding = encoding_default
- end
-
-
-
-feature -- Media Type Negotiation
-
- media_type_preference (a_mime_types_supported: LIST [READABLE_STRING_8]; a_header: detachable READABLE_STRING_8): MEDIA_TYPE_VARIANT_RESULTS
- -- `a_mime_types_supported' represent media types supported by the server.
- -- `a_header represent' the Accept header, ie, the client preferences.
- -- Return which media type to use for representation in a response, if the server supports
- -- the requested media type, or empty in other case.
- note
- EIS: "name=media type", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
- local
- l_mime_match: READABLE_STRING_8
- do
- create Result
- if a_header = Void or else a_header.is_empty then
- -- the request has no Accept header, ie the header is empty, in this case we use the default format
- Result.set_acceptable (TRUE)
- Result.set_type (mime_default)
- else
- -- select the best match, server support, client preferences
- l_mime_match := mime.best_match (a_mime_types_supported, a_header)
- if l_mime_match.is_empty then
- -- The server does not support any of the media types preferred by the client
- Result.set_acceptable (False)
- Result.set_supported_variants (a_mime_types_supported)
- else
- -- Set the best match
- Result.set_type (l_mime_match)
- Result.set_acceptable (True)
- Result.set_variant_header
- end
- end
- end
-
-feature -- Encoding Negotiation
-
- charset_preference (a_server_charset_supported: LIST [READABLE_STRING_8]; a_header: detachable READABLE_STRING_8): CHARACTER_ENCODING_VARIANT_RESULTS
- -- `a_server_charset_supported' represent a list of character sets supported by the server.
- -- `a_header' represents the Accept-Charset header, ie, the client preferences.
- -- Return which Charset to use in a response, if the server supports
- -- the requested Charset, or empty in other case.
- note
- EIS: "name=charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
- local
- l_charset_match: READABLE_STRING_8
- do
- create Result
- if a_header = Void or else a_header.is_empty then
- -- the request has no Accept-Charset header, ie the header is empty, in this case use default charset encoding
- Result.set_acceptable (TRUE)
- Result.set_type (charset_default)
- else
- -- select the best match, server support, client preferences
- l_charset_match := common.best_match (a_server_charset_supported, a_header)
- if l_charset_match.is_empty then
- -- The server does not support any of the compression types prefered by the client
- Result.set_acceptable (False)
- Result.set_supported_variants (a_server_charset_supported)
- else
- -- Set the best match
- Result.set_type (l_charset_match)
- Result.set_acceptable (True)
- Result.set_variant_header
- end
- end
- end
-
-feature -- Compression Negotiation
-
- encoding_preference (a_server_encoding_supported: LIST [READABLE_STRING_8]; a_header: detachable READABLE_STRING_8): COMPRESSION_VARIANT_RESULTS
- -- `a_server_encoding_supported' represent a list of encoding supported by the server.
- -- `a_header' represent the Accept-Encoding header, ie, the client preferences.
- -- Return which Encoding to use in a response, if the server supports
- -- the requested Encoding, or empty in other case.
- note
- EIS: "name=encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
- local
- l_compression_match: READABLE_STRING_8
- do
- create Result
- if a_header = Void or else a_header.is_empty then
- -- the request has no Accept-Encoding header, ie the header is empty, in this case do not compress representations
- Result.set_acceptable (TRUE)
- Result.set_type (encoding_default)
- else
- -- select the best match, server support, client preferences
- l_compression_match := common.best_match (a_server_encoding_supported, a_header)
- if l_compression_match.is_empty then
- -- The server does not support any of the compression types prefered by the client
- Result.set_acceptable (False)
- Result.set_supported_variants (a_server_encoding_supported)
- else
- -- Set the best match
- Result.set_type (l_compression_match)
- Result.set_acceptable (True)
- Result.set_variant_header
- end
- end
- end
-
-feature -- Language Negotiation
-
- language_preference (a_server_language_supported: LIST [READABLE_STRING_8]; a_header: detachable READABLE_STRING_8): LANGUAGE_VARIANT_RESULTS
- -- `a_server_language_supported' represent a list of languages supported by the server.
- -- `a_header' represent the Accept-Language header, ie, the client preferences.
- -- Return which Language to use in a response, if the server supports
- -- the requested Language, or empty in other case.
- note
- EIS: "name=language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
-
- local
- l_language_match: READABLE_STRING_8
- do
- create Result
- if a_header = Void or else a_header.is_empty then
- -- the request has no Accept header, ie the header is empty, in this case we use the default format
- Result.set_acceptable (TRUE)
- Result.set_type (language_default)
- else
- -- select the best match, server support, client preferences
- l_language_match := language.best_match (a_server_language_supported, a_header)
- if l_language_match.is_empty then
- -- The server does not support any of the media types prefered by the client
- Result.set_acceptable (False)
- Result.set_supported_variants (a_server_language_supported)
- else
- -- Set the best match
- Result.set_type (l_language_match)
- Result.set_acceptable (True)
- Result.set_variant_header
- end
- end
- end
-
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/src/parsers/fitness_and_quality.e b/library/network/protocol/content_negotiation/src/implementation/fitness_and_quality.e
similarity index 75%
rename from library/network/protocol/content_negotiation/src/parsers/fitness_and_quality.e
rename to library/network/protocol/content_negotiation/src/implementation/fitness_and_quality.e
index a851ecde..0b7ab39f 100644
--- a/library/network/protocol/content_negotiation/src/parsers/fitness_and_quality.e
+++ b/library/network/protocol/content_negotiation/src/implementation/fitness_and_quality.e
@@ -1,6 +1,5 @@
note
description: "Summary description for {FITNESS_AND_QUALITY}."
- author: ""
date: "$Date$"
revision: "$Revision$"
@@ -24,7 +23,7 @@ feature -- Initialization
do
fitness := a_fitness
quality := a_quality
- create mime_type.make_empty
+ create {STRING_8} entity.make_empty
ensure
fitness_assigned : fitness = a_fitness
quality_assigned : quality = a_quality
@@ -36,17 +35,17 @@ feature -- Access
quality: REAL_64
- mime_type: STRING
+ entity: READABLE_STRING_8
-- optionally used
-- empty by default
-
+ --| Could be a mime type, an encoding, ...
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
- create Result.make_from_string (mime_type)
+ create Result.make_from_string (entity)
Result.append (" (")
Result.append ("quality=" + quality.out)
Result.append (" ; fitness=" + fitness.out)
@@ -55,12 +54,12 @@ feature -- Status report
feature -- Element Change
- set_mime_type (a_mime_type: STRING)
- -- set mime_type with `a_mime_type'
+ set_entity (a_entity: READABLE_STRING_8)
+ -- set `entity' with `a_entity'
do
- mime_type := a_mime_type
+ entity := a_entity
ensure
- mime_type_assigned : mime_type.same_string (a_mime_type)
+ entity_assigned : entity.same_string (a_entity)
end
feature -- Comparision
@@ -75,7 +74,7 @@ feature -- Comparision
end
end
note
- copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end
diff --git a/library/network/protocol/content_negotiation/src/parsers/common_accept_header_parser.e b/library/network/protocol/content_negotiation/src/parsers/common_accept_header_parser.e
deleted file mode 100644
index 172d0e58..00000000
--- a/library/network/protocol/content_negotiation/src/parsers/common_accept_header_parser.e
+++ /dev/null
@@ -1,260 +0,0 @@
-note
- description: "[
- COMMON_ACCEPT_HEADER_PARSER, this class allows to parse Accept-Charset and Accept-Encoding headers
-
- ]"
- date: "$Date$"
- revision: "$Revision$"
- EIS: "name=Charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
- EIS: "name=Encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
-
-class
- COMMON_ACCEPT_HEADER_PARSER
-
-inherit {NONE}
-
- MIME_TYPE_PARSER_UTILITIES
-
-
-feature -- Parser
-
- parse_common (header: READABLE_STRING_8): COMMON_RESULTS
- -- Parses `header' charset/encoding into its component parts.
- -- For example, the charset 'iso-8889-5' would get parsed
- -- into:
- -- ('iso-8889-5', {'q':'1.0'})
- local
- l_parts: LIST [READABLE_STRING_8]
- sub_parts: LIST [READABLE_STRING_8]
- p: READABLE_STRING_8
- i: INTEGER
- l_header: READABLE_STRING_8
- do
- create Result.make
- l_parts := header.split (';')
- if l_parts.count = 1 then
- Result.put ("1.0", "q")
- else
- from
- i := 1
- until
- i > l_parts.count
- loop
- p := l_parts.at (i)
- sub_parts := p.split ('=')
- if sub_parts.count = 2 then
- Result.put (trim (sub_parts [2]), trim (sub_parts [1]))
- end
- i := i + 1
- end
- end
- l_header := trim (l_parts [1])
- Result.set_field (trim (l_header))
- end
-
- fitness_and_quality_parsed (a_field: READABLE_STRING_8; parsed_charsets: LIST [COMMON_RESULTS]): FITNESS_AND_QUALITY
- -- Find the best match for a given charset/encoding against a list of charsets/encodings
- -- that have already been parsed by parse_common. Returns a
- -- tuple of the fitness value and the value of the 'q' quality parameter of
- -- the best match, or (-1, 0) if no match was found. Just as for
- -- quality_parsed().
- local
- best_fitness: INTEGER
- target_q: REAL_64
- best_fit_q: REAL_64
- target: COMMON_RESULTS
- range: COMMON_RESULTS
- element: detachable READABLE_STRING_8
- l_fitness: INTEGER
- do
- best_fitness := -1
- best_fit_q := 0.0
- target := parse_common (a_field)
- if attached target.item ("q") as q and then q.is_double then
- target_q := q.to_double
- if target_q < 0.0 then
- target_q := 0.0
- elseif target_q > 1.0 then
- target_q := 1.0
- end
- else
- target_q := 1.0
- end
- if attached target.field as l_target_field then
- from
- parsed_charsets.start
- until
- parsed_charsets.after
- loop
- range := parsed_charsets.item_for_iteration
- if attached range.field as l_range_common then
- if l_target_field.same_string (l_range_common) or l_target_field.same_string ("*") or l_range_common.same_string ("*")
- or l_target_field.same_string ("identity") then
- if l_range_common.same_string (l_target_field) then
- l_fitness := 100
- else
- l_fitness := 0
- end
- if l_fitness > best_fitness then
- best_fitness := l_fitness
- element := range.item ("q")
- if element /= Void then
- best_fit_q := element.to_double.min (target_q)
- else
- best_fit_q := 0.0
- end
- end
- end
- end
- parsed_charsets.forth
- end
- end
- create Result.make (best_fitness, best_fit_q)
- end
-
- quality_parsed (a_field: READABLE_STRING_8; parsed_common: LIST [COMMON_RESULTS]): REAL_64
- -- Find the best match for a given charset/encoding against a list of charsets/encodings that
- -- have already been parsed by parse_charsets(). Returns the 'q' quality
- -- parameter of the best match, 0 if no match was found. This function
- -- bahaves the same as quality()
- do
- Result := fitness_and_quality_parsed (a_field, parsed_common).quality
- end
-
- quality (a_field: READABLE_STRING_8; commons: READABLE_STRING_8): REAL_64
- -- Returns the quality 'q' of a charset/encoding when compared against the
- -- a list of charsets/encodings/
- local
- l_commons: LIST [READABLE_STRING_8]
- res: ARRAYED_LIST [COMMON_RESULTS]
- p_res: COMMON_RESULTS
- do
- l_commons := commons.split (',')
- from
- create res.make (10);
- l_commons.start
- until
- l_commons.after
- loop
- p_res := parse_common (l_commons.item_for_iteration)
- res.put_left (p_res)
- l_commons.forth
- end
- Result := quality_parsed (a_field, res)
- end
-
- best_match (supported: LIST [READABLE_STRING_8]; header: READABLE_STRING_8): READABLE_STRING_8
- -- Choose the accept with the highest fitness score and quality ('q') from a list of candidates.
- local
- l_header_results: LIST [COMMON_RESULTS]
- weighted_matches: LIST [FITNESS_AND_QUALITY]
- l_res: LIST [READABLE_STRING_8]
- p_res: COMMON_RESULTS
- fitness_and_quality, first_one: detachable FITNESS_AND_QUALITY
- do
- l_res := header.split (',')
- create {ARRAYED_LIST [COMMON_RESULTS]} l_header_results.make (l_res.count)
- from
- l_res.start
- until
- l_res.after
- loop
- p_res := parse_common (l_res.item_for_iteration)
- l_header_results.force (p_res)
- l_res.forth
- end
- create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (supported.count)
- from
- supported.start
- until
- supported.after
- loop
- fitness_and_quality := fitness_and_quality_parsed (supported.item_for_iteration, l_header_results)
- fitness_and_quality.set_mime_type (mime_type (supported.item_for_iteration))
- weighted_matches.force (fitness_and_quality)
- supported.forth
- end
-
- --| Keep only top quality+fitness types
- --| TODO extract method
- from
- weighted_matches.start
- first_one := weighted_matches.item
- weighted_matches.forth
- until
- weighted_matches.after
- loop
- fitness_and_quality := weighted_matches.item
- if first_one < fitness_and_quality then
- first_one := fitness_and_quality
- if not weighted_matches.isfirst then
- from
- weighted_matches.back
- until
- weighted_matches.before
- loop
- weighted_matches.remove
- weighted_matches.back
- end
- weighted_matches.forth
- end
- check
- weighted_matches.item = fitness_and_quality
- end
- weighted_matches.forth
- elseif first_one.is_equal (fitness_and_quality) then
- weighted_matches.forth
- else
- check
- first_one > fitness_and_quality
- end
- weighted_matches.remove
- end
- end
- if first_one /= Void and then first_one.quality /= 0.0 then
- if weighted_matches.count = 1 then
- Result := first_one.mime_type
- else
- from
- fitness_and_quality := Void
- l_header_results.start
- until
- l_header_results.after or fitness_and_quality /= Void
- loop
- if attached l_header_results.item.field as l_field then
- from
- weighted_matches.start
- until
- weighted_matches.after or fitness_and_quality /= Void
- loop
- fitness_and_quality := weighted_matches.item
- if fitness_and_quality.mime_type.same_string (l_field) then
- --| Found
- else
- fitness_and_quality := Void
- weighted_matches.forth
- end
- end
- else
- check
- has_field: False
- end
- end
- l_header_results.forth
- end
- if fitness_and_quality /= Void then
- Result := fitness_and_quality.mime_type
- else
- Result := first_one.mime_type
- end
- end
- else
- Result := ""
- end
- end
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e b/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e
new file mode 100644
index 00000000..6d69f6f8
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e
@@ -0,0 +1,256 @@
+note
+ description: "[
+ {HTTP_ACCEPT_LANGUAGE_UTILITIES} is in charge to parse language tags defined as follow:
+
+ Accept-Language = "Accept-Language" ":"
+ 1#( language-l_range [ ";" "q" "=" qvalue ] )
+ language-l_range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+
+ Example:
+ Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+ ]"
+ date: "$Date$"
+ revision: "$Revision$"
+ EIS: "name=Accept-Language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
+
+class
+ HTTP_ACCEPT_LANGUAGE_UTILITIES
+
+inherit
+ HTTP_HEADER_UTILITIES
+
+feature -- Parser
+
+ accept_language_list (a_header_value: READABLE_STRING_8): LIST [HTTP_ACCEPT_LANGUAGE]
+ -- Languages-ranges are languages with wild-cards and a 'q' quality parameter.
+ -- For example, the language l_range ('en-* ;q=0.5') would get parsed into:
+ -- ('en', '*', {'q', '0.5'})
+ -- In addition this function also guarantees that there is a value for 'q'
+ -- in the params dictionary, filling it in with a proper default if
+ -- necessary.
+ local
+ l_res: LIST [READABLE_STRING_8]
+ l_lang: HTTP_ACCEPT_LANGUAGE
+ do
+ l_res := a_header_value.split (',')
+ create {ARRAYED_LIST [HTTP_ACCEPT_LANGUAGE]} Result.make (l_res.count)
+
+ from
+ l_res.start
+ until
+ l_res.after
+ loop
+ create l_lang.make_from_string (l_res.item_for_iteration)
+ Result.force (l_lang)
+ l_res.forth
+ end
+ end
+
+ accept_language (a_accept_language_item: READABLE_STRING_8): HTTP_ACCEPT_LANGUAGE
+ -- Languages-ranges are languages with wild-cards and a 'q' quality parameter.
+ -- For example, the language l_range ('en-* ;q=0.5') would get parsed into:
+ -- ('en', '*', {'q', '0.5'})
+ -- In addition this function also guarantees that there is a value for 'q'
+ -- in the params dictionary, filling it in with a proper default if
+ -- necessary.
+ do
+ create Result.make_from_string (a_accept_language_item)
+ end
+
+ quality (a_language: READABLE_STRING_8; a_ranges: READABLE_STRING_8): REAL_64
+ -- Returns the quality 'q' of a `a_language' when compared against the
+ -- language l_range in `a_ranges'.
+ do
+ Result := quality_from_list (a_language, accept_language_list (a_ranges))
+ end
+
+ best_match (a_supported: ITERABLE [READABLE_STRING_8]; a_header_value: READABLE_STRING_8): READABLE_STRING_8
+ -- Choose the `parse_language' with the highest fitness score and quality ('q') from a list of candidates.
+ local
+ l_header_results: LIST [HTTP_ACCEPT_LANGUAGE]
+ l_weighted_matches: LIST [FITNESS_AND_QUALITY]
+ l_fitness_and_quality, l_first_one: detachable FITNESS_AND_QUALITY
+ s: READABLE_STRING_8
+ do
+ l_header_results := accept_language_list (a_header_value)
+
+ --| weighted matches
+ create {ARRAYED_LIST [FITNESS_AND_QUALITY]} l_weighted_matches.make (0)
+ across a_supported as ic loop
+ l_fitness_and_quality := fitness_and_quality_from_list (ic.item, l_header_results)
+ l_fitness_and_quality.set_entity (entity_value (ic.item))
+ l_weighted_matches.force (l_fitness_and_quality)
+ end
+
+ --| Keep only top quality+fitness types
+ from
+ l_weighted_matches.start
+ l_first_one := l_weighted_matches.item
+ l_weighted_matches.forth
+ until
+ l_weighted_matches.after
+ loop
+ l_fitness_and_quality := l_weighted_matches.item
+ if l_first_one < l_fitness_and_quality then
+ l_first_one := l_fitness_and_quality
+ if not l_weighted_matches.isfirst then
+ from
+ l_weighted_matches.back
+ until
+ l_weighted_matches.before
+ loop
+ l_weighted_matches.remove
+ l_weighted_matches.back
+ end
+ l_weighted_matches.forth
+ end
+ check
+ l_weighted_matches.item = l_fitness_and_quality
+ end
+ l_weighted_matches.forth
+ elseif l_first_one ~ l_fitness_and_quality then
+ l_weighted_matches.forth
+ else
+ check
+ l_first_one > l_fitness_and_quality
+ end
+ l_weighted_matches.remove
+ end
+ end
+ if l_first_one /= Void and then l_first_one.quality /= 0.0 then
+ if l_weighted_matches.count = 1 then
+ Result := l_first_one.entity
+ else
+ from
+ l_fitness_and_quality := Void
+ l_header_results.start
+ until
+ l_header_results.after or l_fitness_and_quality /= Void
+ loop
+ s := l_header_results.item.language_range
+ from
+ l_weighted_matches.start
+ until
+ l_weighted_matches.after or l_fitness_and_quality /= Void
+ loop
+ l_fitness_and_quality := l_weighted_matches.item
+ if l_fitness_and_quality.entity.same_string (s) then
+ --| Found
+ else
+ l_fitness_and_quality := Void
+ l_weighted_matches.forth
+ end
+ end
+ l_header_results.forth
+ end
+ if l_fitness_and_quality /= Void then
+ Result := l_fitness_and_quality.entity
+ else
+ Result := l_first_one.entity
+ end
+ end
+ else
+ Result := ""
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ fitness_and_quality_from_list (a_language: READABLE_STRING_8; a_parsed_ranges: LIST [HTTP_ACCEPT_LANGUAGE]): FITNESS_AND_QUALITY
+ -- Find the best match for a given `a_language' against a list of language ranges `a_parsed_ranges'
+ -- that have already been parsed by parse_language_range.
+ local
+ l_best_fitness: INTEGER
+ l_target_q: REAL_64
+ l_best_fit_q: REAL_64
+ l_target: HTTP_ACCEPT_LANGUAGE
+ l_target_type: READABLE_STRING_8
+ l_range: HTTP_ACCEPT_LANGUAGE
+ l_param_matches: INTEGER
+ l_element: detachable READABLE_STRING_8
+ l_fitness: INTEGER
+ do
+ l_best_fitness := -1
+ l_best_fit_q := 0.0
+ create l_target.make_from_string (a_language)
+ l_target_q := l_target.quality
+
+ l_target_type := l_target.language
+ from
+ a_parsed_ranges.start
+ until
+ a_parsed_ranges.after
+ loop
+ l_range := a_parsed_ranges.item_for_iteration
+ if
+ attached l_range.language as l_range_type and then
+ ( l_target_type.same_string (l_range_type)
+ or l_range_type.same_string ("*")
+ or l_target_type.same_string ("*")
+ )
+ then
+ l_param_matches := 0
+ if attached l_target.parameters as l_target_parameters then
+ across
+ l_target_parameters as ic
+ loop
+ l_element := ic.key
+ if
+ not l_element.same_string ("q") and then
+ l_range.has_parameter (l_element) and then
+ (attached ic.item as t_item and attached l_range.parameter (l_element) as r_item) and then
+ t_item.same_string (r_item)
+ then
+ l_param_matches := l_param_matches + 1
+ end
+ end
+ end
+ if l_range_type.same_string (l_target_type) then
+ l_fitness := 100
+ else
+ l_fitness := 0
+ end
+ if
+ attached l_range.specialization as l_range_sub_type and then
+ attached l_target.specialization as l_target_sub_type and then
+ ( l_target_sub_type.same_string (l_range_sub_type)
+ or l_range_sub_type.same_string ("*")
+ or l_target_sub_type.same_string ("*")
+ )
+ then
+ if l_range_sub_type.same_string (l_target_sub_type) then
+ l_fitness := l_fitness + 10
+ end
+ end
+ l_fitness := l_fitness + l_param_matches
+ if l_fitness > l_best_fitness then
+ l_best_fitness := l_fitness
+ l_element := l_range.parameter ("q")
+ if l_element /= Void then
+ l_best_fit_q := l_element.to_real_64.min (l_target_q)
+ else
+ l_best_fit_q := 0.0
+ end
+ end
+ end
+ a_parsed_ranges.forth
+ end
+ create Result.make (l_best_fitness, l_best_fit_q)
+ end
+
+ quality_from_list (a_language: READABLE_STRING_8; a_parsed_ranges: LIST [HTTP_ACCEPT_LANGUAGE]): REAL_64
+ -- Find the best match for a given `a_language' against a list of ranges `parsed_ranges' that
+ -- have already been parsed by parse_language_range. Returns the 'q' quality
+ -- parameter of the best match, 0 if no match was found. This function
+ -- bahaves the same as quality except that 'a_parsed_ranges' must be a list
+ -- of parsed language ranges.
+ do
+ Result := fitness_and_quality_from_list (a_language, a_parsed_ranges).quality
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/parsers/mime_parse.e b/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e
similarity index 78%
rename from library/network/protocol/content_negotiation/src/parsers/mime_parse.e
rename to library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e
index 5e9dd923..c57e060a 100644
--- a/library/network/protocol/content_negotiation/src/parsers/mime_parse.e
+++ b/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e
@@ -1,6 +1,6 @@
note
description: "[
- {MIME_PARSE}. is encharge to parse Accept request-header field defined as follow:
+ {HTTP_ACCEPT_MEDIA_TYPE_UTILITIES}. is encharge to parse Accept request-header field defined as follow:
Accept = "Accept" ":"
#( media-range [ accept-params ] )
@@ -20,26 +20,14 @@
EIS: "name=Accept", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
class
- MIME_PARSE
+ HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
-inherit {NONE}
-
- MIME_TYPE_PARSER_UTILITIES
-
- REFACTORING_HELPER
+inherit
+ HTTP_HEADER_UTILITIES
feature -- Parser
- parse_mime_type (a_mime_type: READABLE_STRING_8): HTTP_MEDIA_TYPE
- -- Parses a mime-type into its component parts.
- -- For example, the media range 'application/xhtml;q=0.5' would get parsed
- -- into:
- -- ('application', 'xhtml', {'q', '0.5'})
- do
- create Result.make_from_string (a_mime_type)
- end
-
- parse_media_range (a_range: READABLE_STRING_8): HTTP_MEDIA_TYPE
+ media_type (a_range: READABLE_STRING_8): HTTP_MEDIA_TYPE
-- Media-ranges are mime-types with wild-cards and a 'q' quality parameter.
-- For example, the media range 'application/*;q=0.5' would get parsed into:
-- ('application', '*', {'q', '0.5'})
@@ -48,11 +36,11 @@ feature -- Parser
-- necessary.
do
fixme ("Improve the code!!!")
- Result := parse_mime_type (a_range)
+ create Result.make_from_string (a_range)
if attached Result.parameter ("q") as q then
if
q.is_double and then
- attached {REAL_64} q.to_double as r and then
+ attached {REAL_64} q.to_real_64 as r and then
(r >= 0.0 and r <= 1.0)
then
--| Keep current value
@@ -68,111 +56,6 @@ feature -- Parser
end
end
-
- fitness_and_quality_parsed (a_mime_type: READABLE_STRING_8; parsed_ranges: LIST [HTTP_MEDIA_TYPE]): FITNESS_AND_QUALITY
- -- Find the best match for a given mimeType against a list of media_ranges
- -- that have already been parsed by parse_media_range.
- local
- best_fitness: INTEGER
- target_q: REAL_64
- best_fit_q: REAL_64
- target: HTTP_MEDIA_TYPE
- range: HTTP_MEDIA_TYPE
- param_matches: INTEGER
- element: detachable READABLE_STRING_8
- l_fitness: INTEGER
- do
- best_fitness := -1
- best_fit_q := 0.0
- target := parse_media_range (a_mime_type)
- if attached target.parameter ("q") as q and then q.is_double then
- target_q := q.to_double
- if target_q < 0.0 then
- target_q := 0.0
- elseif target_q > 1.0 then
- target_q := 1.0
- end
- else
- target_q := 1.0
- end
-
- if
- attached target.type as l_target_type and
- attached target.subtype as l_target_sub_type
- then
- from
- parsed_ranges.start
- until
- parsed_ranges.after
- loop
- range := parsed_ranges.item_for_iteration
- if
- (
- attached range.type as l_range_type and then
- (l_target_type.same_string (l_range_type) or l_range_type.same_string ("*") or l_target_type.same_string ("*"))
- ) and
- (
- attached range.subtype as l_range_sub_type and then
- (l_target_sub_type.same_string (l_range_sub_type) or l_range_sub_type.same_string ("*") or l_target_sub_type.same_string ("*"))
- )
- then
- if attached target.parameters as l_keys then
- from
- param_matches := 0
- l_keys.start
- until
- l_keys.after
- loop
- element := l_keys.key_for_iteration
- if
- not element.same_string ("q") and then
- range.has_parameter (element) and then
- (attached target.parameter (element) as t_item and attached range.parameter (element) as r_item) and then
- t_item.same_string (r_item)
- then
- param_matches := param_matches + 1
- end
- l_keys.forth
- end
- end
- if l_range_type.same_string (l_target_type) then
- l_fitness := 100
- else
- l_fitness := 0
- end
-
- if l_range_sub_type.same_string (l_target_sub_type) then
- l_fitness := l_fitness + 10
- end
-
- l_fitness := l_fitness + param_matches
-
- if l_fitness > best_fitness then
- best_fitness := l_fitness
- element := range.parameter ("q")
- if element /= Void then
- best_fit_q := element.to_double.min (target_q)
- else
- best_fit_q := 0.0
- end
- end
- end
- parsed_ranges.forth
- end
- end
- create Result.make (best_fitness, best_fit_q)
- end
-
- quality_parsed (a_mime_type: READABLE_STRING_8; parsed_ranges: LIST [HTTP_MEDIA_TYPE]): REAL_64
- -- Find the best match for a given mime-type against a list of ranges that
- -- have already been parsed by parse_media_range. Returns the 'q' quality
- -- parameter of the best match, 0 if no match was found. This function
- -- bahaves the same as quality except that 'parsed_ranges' must be a list
- -- of parsed media ranges.
- do
- Result := fitness_and_quality_parsed (a_mime_type, parsed_ranges).quality
- end
-
quality (a_mime_type: READABLE_STRING_8; ranges: READABLE_STRING_8): REAL_64
-- Returns the quality 'q' of a mime-type when compared against the
-- mediaRanges in ranges.
@@ -188,14 +71,14 @@ feature -- Parser
until
l_ranges.after
loop
- p_res := parse_media_range (l_ranges.item_for_iteration)
- res.put_left (p_res)
+ p_res := media_type (l_ranges.item_for_iteration)
+ res.force (p_res)
l_ranges.forth
end
- Result := quality_parsed (a_mime_type, res)
+ Result := quality_from_list (a_mime_type, res)
end
- best_match (supported: LIST [READABLE_STRING_8]; header: READABLE_STRING_8): READABLE_STRING_8
+ best_match (supported: ITERABLE [READABLE_STRING_8]; header: READABLE_STRING_8): READABLE_STRING_8
-- Choose the mime-type with the highest fitness score and quality ('q') from a list of candidates.
local
l_header_results: LIST [HTTP_MEDIA_TYPE]
@@ -214,22 +97,17 @@ feature -- Parser
until
l_res.after
loop
- p_res := parse_media_range (l_res.item_for_iteration)
+ p_res := media_type (l_res.item_for_iteration)
l_header_results.force (p_res)
l_res.forth
end
- create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (supported.count)
+ create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (0)
- from
- supported.start
- until
- supported.after
- loop
- fitness_and_quality := fitness_and_quality_parsed (supported.item_for_iteration, l_header_results)
- fitness_and_quality.set_mime_type (mime_type (supported.item_for_iteration))
+ across supported as ic loop
+ fitness_and_quality := fitness_and_quality_from_list (ic.item, l_header_results)
+ fitness_and_quality.set_entity (entity_value (ic.item))
weighted_matches.force (fitness_and_quality)
- supported.forth
end
--| Keep only top quality+fitness types
@@ -265,7 +143,7 @@ feature -- Parser
end
if first_one /= Void and then first_one.quality /= 0.0 then
if weighted_matches.count = 1 then
- Result := first_one.mime_type
+ Result := first_one.entity
else
from
fitness_and_quality := Void
@@ -280,7 +158,7 @@ feature -- Parser
weighted_matches.after or fitness_and_quality /= Void
loop
fitness_and_quality := weighted_matches.item
- if fitness_and_quality.mime_type.same_string (s) then
+ if fitness_and_quality.entity.same_string (s) then
--| Found
else
fitness_and_quality := Void
@@ -290,9 +168,9 @@ feature -- Parser
l_header_results.forth
end
if fitness_and_quality /= Void then
- Result := fitness_and_quality.mime_type
+ Result := fitness_and_quality.entity
else
- Result := first_one.mime_type
+ Result := first_one.entity
end
end
else
@@ -300,6 +178,108 @@ feature -- Parser
end
end
+feature {NONE} -- Implementation
+
+ fitness_and_quality_from_list (a_mime_type: READABLE_STRING_8; parsed_ranges: LIST [HTTP_MEDIA_TYPE]): FITNESS_AND_QUALITY
+ -- Find the best match for a given mimeType against a list of media_ranges
+ -- that have already been parsed by parse_media_range.
+ local
+ best_fitness: INTEGER
+ target_q: REAL_64
+ best_fit_q: REAL_64
+ target: HTTP_MEDIA_TYPE
+ range: HTTP_MEDIA_TYPE
+ param_matches: INTEGER
+ element: detachable READABLE_STRING_8
+ l_fitness: INTEGER
+ do
+ best_fitness := -1
+ best_fit_q := 0.0
+ target := media_type (a_mime_type)
+ if attached target.parameter ("q") as q and then q.is_double then
+ target_q := q.to_double
+ if target_q < 0.0 then
+ target_q := 0.0
+ elseif target_q > 1.0 then
+ target_q := 1.0
+ end
+ else
+ target_q := 1.0
+ end
+
+ if
+ attached target.type as l_target_type and
+ attached target.subtype as l_target_sub_type
+ then
+ from
+ parsed_ranges.start
+ until
+ parsed_ranges.after
+ loop
+ range := parsed_ranges.item_for_iteration
+ if
+ (
+ attached range.type as l_range_type and then
+ (l_target_type.same_string (l_range_type) or l_range_type.same_string ("*") or l_target_type.same_string ("*"))
+ ) and
+ (
+ attached range.subtype as l_range_sub_type and then
+ (l_target_sub_type.same_string (l_range_sub_type) or l_range_sub_type.same_string ("*") or l_target_sub_type.same_string ("*"))
+ )
+ then
+ if attached target.parameters as l_keys then
+ param_matches := 0
+ across l_keys as ic loop
+ element := ic.key
+ if
+ not element.same_string ("q") and then
+ range.has_parameter (element) and then
+ (attached target.parameter (element) as t_item and attached range.parameter (element) as r_item) and then
+ t_item.same_string (r_item)
+ then
+ param_matches := param_matches + 1
+ end
+ end
+ end
+ if l_range_type.same_string (l_target_type) then
+ l_fitness := 100
+ else
+ l_fitness := 0
+ end
+
+ if l_range_sub_type.same_string (l_target_sub_type) then
+ l_fitness := l_fitness + 10
+ end
+
+ l_fitness := l_fitness + param_matches
+
+ if l_fitness > best_fitness then
+ best_fitness := l_fitness
+ element := range.parameter ("q")
+ if element /= Void then
+ best_fit_q := element.to_double.min (target_q)
+ else
+ best_fit_q := 0.0
+ end
+ end
+ end
+ parsed_ranges.forth
+ end
+ end
+ create Result.make (best_fitness, best_fit_q)
+ end
+
+ quality_from_list (a_mime_type: READABLE_STRING_8; parsed_ranges: LIST [HTTP_MEDIA_TYPE]): REAL_64
+ -- Find the best match for a given mime-type against a list of ranges that
+ -- have already been parsed by parse_media_range. Returns the 'q' quality
+ -- parameter of the best match, 0 if no match was found. This function
+ -- bahaves the same as quality except that 'parsed_ranges' must be a list
+ -- of parsed media ranges.
+ do
+ Result := fitness_and_quality_from_list (a_mime_type, parsed_ranges).quality
+ end
+
+
note
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
diff --git a/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_utilities.e b/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_utilities.e
new file mode 100644
index 00000000..2551d071
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_utilities.e
@@ -0,0 +1,237 @@
+note
+ description: "[
+ HTTP_ANY_ACCEPT_HEADER_PARSER, this class allows to parse Accept-* headers
+
+ ]"
+ date: "$Date$"
+ revision: "$Revision$"
+ EIS: "name=Charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
+ EIS: "name=Encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
+
+class
+ HTTP_ANY_ACCEPT_HEADER_UTILITIES
+
+inherit
+ HTTP_HEADER_UTILITIES
+
+feature -- Parser
+
+ header (a_header: READABLE_STRING_8): HTTP_ANY_ACCEPT
+ -- Parses `a_header' charset/encoding into its component parts.
+ -- For example, the charset 'iso-8889-5' would get parsed
+ -- into:
+ -- ('iso-8889-5', {'q':'1.0'})
+ do
+ create Result.make_from_string (a_header)
+ if Result.parameter ("q") = Void then
+ Result.put_parameter ("1.0", "q")
+ end
+ end
+
+ quality (a_field: READABLE_STRING_8; a_header: READABLE_STRING_8): REAL_64
+ -- Returns the quality 'q' of a charset/encoding when compared against the
+ -- a list of charsets/encodings/
+ local
+ l_commons: LIST [READABLE_STRING_8]
+ res: ARRAYED_LIST [HTTP_ANY_ACCEPT]
+ p_res: HTTP_ANY_ACCEPT
+ do
+ l_commons := a_header.split (',')
+ from
+ create res.make (10)
+ l_commons.start
+ until
+ l_commons.after
+ loop
+ p_res := header (l_commons.item_for_iteration)
+ res.force (p_res)
+ l_commons.forth
+ end
+ Result := quality_from_list (a_field, res)
+ end
+
+ best_match (a_supported: ITERABLE [READABLE_STRING_8]; a_header: READABLE_STRING_8): READABLE_STRING_8
+ -- Choose the accept with the highest fitness score and quality ('q') from a list of candidates.
+ local
+ l_header_results: LIST [HTTP_ANY_ACCEPT]
+ l_weighted_matches: LIST [FITNESS_AND_QUALITY]
+ l_res: LIST [READABLE_STRING_8]
+ p_res: HTTP_ANY_ACCEPT
+ l_fitness_and_quality, l_first_one: detachable FITNESS_AND_QUALITY
+ do
+ l_res := a_header.split (',')
+ create {ARRAYED_LIST [HTTP_ANY_ACCEPT]} l_header_results.make (l_res.count)
+ from
+ l_res.start
+ until
+ l_res.after
+ loop
+ p_res := header (l_res.item_for_iteration)
+ l_header_results.force (p_res)
+ l_res.forth
+ end
+ create {ARRAYED_LIST [FITNESS_AND_QUALITY]} l_weighted_matches.make (0)
+ across a_supported as ic loop
+ l_fitness_and_quality := fitness_and_quality_from_list (ic.item, l_header_results)
+ l_fitness_and_quality.set_entity (entity_value (ic.item))
+ l_weighted_matches.force (l_fitness_and_quality)
+ end
+
+ --| Keep only top quality+fitness types
+ --| TODO extract method
+ from
+ l_weighted_matches.start
+ l_first_one := l_weighted_matches.item
+ l_weighted_matches.forth
+ until
+ l_weighted_matches.after
+ loop
+ l_fitness_and_quality := l_weighted_matches.item
+ if l_first_one < l_fitness_and_quality then
+ l_first_one := l_fitness_and_quality
+ if not l_weighted_matches.isfirst then
+ from
+ l_weighted_matches.back
+ until
+ l_weighted_matches.before
+ loop
+ l_weighted_matches.remove
+ l_weighted_matches.back
+ end
+ l_weighted_matches.forth
+ end
+ check
+ l_weighted_matches.item = l_fitness_and_quality
+ end
+ l_weighted_matches.forth
+ elseif l_first_one.is_equal (l_fitness_and_quality) then
+ l_weighted_matches.forth
+ else
+ check
+ l_first_one > l_fitness_and_quality
+ end
+ l_weighted_matches.remove
+ end
+ end
+ if l_first_one /= Void and then l_first_one.quality /= 0.0 then
+ if l_weighted_matches.count = 1 then
+ Result := l_first_one.entity
+ else
+ from
+ l_fitness_and_quality := Void
+ l_header_results.start
+ until
+ l_header_results.after or l_fitness_and_quality /= Void
+ loop
+ if attached l_header_results.item.value as l_field then
+ from
+ l_weighted_matches.start
+ until
+ l_weighted_matches.after or l_fitness_and_quality /= Void
+ loop
+ l_fitness_and_quality := l_weighted_matches.item
+ if l_fitness_and_quality.entity.same_string (l_field) then
+ --| Found
+ else
+ l_fitness_and_quality := Void
+ l_weighted_matches.forth
+ end
+ end
+ else
+ check
+ has_field: False
+ end
+ end
+ l_header_results.forth
+ end
+ if l_fitness_and_quality /= Void then
+ Result := l_fitness_and_quality.entity
+ else
+ Result := l_first_one.entity
+ end
+ end
+ else
+ Result := ""
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ fitness_and_quality_from_list (a_field: READABLE_STRING_8; a_parsed_charsets: LIST [HTTP_ANY_ACCEPT]): FITNESS_AND_QUALITY
+ -- Find the best match for a given charset/encoding against a list of charsets/encodings
+ -- that have already been parsed by parse_common. Returns a
+ -- tuple of the fitness value and the value of the 'q' quality parameter of
+ -- the best match, or (-1, 0) if no match was found. Just as for
+ -- quality_parsed().
+ local
+ best_fitness: INTEGER
+ target_q: REAL_64
+ best_fit_q: REAL_64
+ target: HTTP_ANY_ACCEPT
+ range: HTTP_ANY_ACCEPT
+ element: detachable READABLE_STRING_8
+ l_fitness: INTEGER
+ do
+ best_fitness := -1
+ best_fit_q := 0.0
+ target := header (a_field)
+ if attached target.parameter ("q") as q and then q.is_double then
+ target_q := q.to_double
+ if target_q < 0.0 then
+ target_q := 0.0
+ elseif target_q > 1.0 then
+ target_q := 1.0
+ end
+ else
+ target_q := 1.0
+ end
+ if attached target.value as l_target_field then
+ from
+ a_parsed_charsets.start
+ until
+ a_parsed_charsets.after
+ loop
+ range := a_parsed_charsets.item_for_iteration
+ if attached range.value as l_range_common then
+ if
+ l_target_field.same_string (l_range_common)
+ or l_target_field.same_string ("*")
+ or l_range_common.same_string ("*")
+ or l_range_common.same_string ("identity")
+ then
+ if l_range_common.same_string (l_target_field) then
+ l_fitness := 100
+ else
+ l_fitness := 0
+ end
+ if l_fitness > best_fitness then
+ best_fitness := l_fitness
+ element := range.parameter ("q")
+ if element /= Void then
+ best_fit_q := element.to_double.min (target_q)
+ else
+ best_fit_q := 0.0
+ end
+ end
+ end
+ end
+ a_parsed_charsets.forth
+ end
+ end
+ create Result.make (best_fitness, best_fit_q)
+ end
+
+ quality_from_list (a_field: READABLE_STRING_8; a_parsed_common: LIST [HTTP_ANY_ACCEPT]): REAL_64
+ -- Find the best match for a given charset/encoding against a list of charsets/encodings that
+ -- have already been parsed by parse_charsets(). Returns the 'q' quality
+ -- parameter of the best match, 0 if no match was found. This function
+ -- bahaves the same as quality()
+ do
+ Result := fitness_and_quality_from_list (a_field, a_parsed_common).quality
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/parsers/http_header_utilities.e b/library/network/protocol/content_negotiation/src/parsers/http_header_utilities.e
new file mode 100644
index 00000000..9f739088
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/parsers/http_header_utilities.e
@@ -0,0 +1,44 @@
+note
+ description: "Summary description for {HTTP_HEADER_UTILITIES}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ HTTP_HEADER_UTILITIES
+
+inherit
+ REFACTORING_HELPER
+
+feature {NONE} -- Helpers
+
+ entity_value (a_str: READABLE_STRING_8): READABLE_STRING_8
+ -- `s' with any trailing parameters stripped
+ local
+ p: INTEGER
+ do
+ p := a_str.index_of (';', 1)
+ if p > 0 then
+ Result := trimmed_string (a_str.substring (1, p - 1))
+ else
+ Result := trimmed_string (a_str.string)
+ end
+ end
+
+ trimmed_string (a_string: READABLE_STRING_8): STRING_8
+ -- trim whitespace from the beginning and end of a string
+ -- `a_string'
+ require
+ valid_argument : a_string /= Void
+ do
+ create Result.make_from_string (a_string)
+ Result.left_adjust
+ Result.right_adjust
+ ensure
+ result_trimmed: a_string.has_substring (Result)
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/library/network/protocol/content_negotiation/src/parsers/language_parse.e b/library/network/protocol/content_negotiation/src/parsers/language_parse.e
deleted file mode 100644
index bbb39cb9..00000000
--- a/library/network/protocol/content_negotiation/src/parsers/language_parse.e
+++ /dev/null
@@ -1,312 +0,0 @@
-note
- description: "[
- {LANGUAGE_PARSE} is encharge to parse language tags defined as follow:
-
- Accept-Language = "Accept-Language" ":"
- 1#( language-range [ ";" "q" "=" qvalue ] )
- language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
-
- Example:
- Accept-Language: da, en-gb;q=0.8, en;q=0.7
-
- ]"
- date: "$Date$"
- revision: "$Revision$"
- EIS: "name=Accept-Language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
-
-class
- LANGUAGE_PARSE
-
-inherit {NONE}
-
- MIME_TYPE_PARSER_UTILITIES
-
- REFACTORING_HELPER
-
-feature -- Parser
-
- parse_language (a_accept_language: READABLE_STRING_8): LANGUAGE_RESULTS
- -- Parses `a_accept_language' request-header field into its component parts.
- -- For example, the language range 'en-gb;q=0.8' would get parsed
- -- into:
- -- ('en-gb', {'q':'0.8',})
- local
- l_parts: LIST [READABLE_STRING_8]
- p: READABLE_STRING_8
- sub_parts: LIST [READABLE_STRING_8]
- i: INTEGER
- l_full_type: READABLE_STRING_8
- l_types: LIST [READABLE_STRING_8]
- do
- fixme ("Improve code!!!")
- create Result.make
- l_parts := a_accept_language.split (';')
- from
- i := 1
- until
- i > l_parts.count
- loop
- p := l_parts.at (i)
- sub_parts := p.split ('=')
- if sub_parts.count = 2 then
- Result.put (trim (sub_parts [2]), trim (sub_parts [1]))
- end
- i := i + 1
- end
-
- l_full_type := trim (l_parts [1])
- if l_full_type.same_string ("*") then
- l_full_type := "*"
- end
- l_types := l_full_type.split ('-')
- if l_types.count = 1 then
- Result.set_type (trim (l_types [1]))
- else
- Result.set_type (trim (l_types [1]))
- Result.set_sub_type (trim (l_types [2]))
- end
- end
-
- parse_language_range (a_language_range: READABLE_STRING_8): LANGUAGE_RESULTS
- -- Languages-ranges are languages with wild-cards and a 'q' quality parameter.
- -- For example, the language range ('en-* ;q=0.5') would get parsed into:
- -- ('en', '*', {'q', '0.5'})
- -- In addition this function also guarantees that there is a value for 'q'
- -- in the params dictionary, filling it in with a proper default if
- -- necessary.
- do
- fixme ("Improve the code!!!")
- Result := parse_language (a_language_range)
- if attached Result.item ("q") as q then
- if q.is_double and then attached {REAL_64} q.to_double as r and then (r >= 0.0 and r <= 1.0) then
- --| Keep current value
- if q.same_string ("1") then
- --| Use 1.0 formatting
- Result.put ("1.0", "q")
- end
- else
- Result.put ("1.0", "q")
- end
- else
- Result.put ("1.0", "q")
- end
- end
-
- fitness_and_quality_parsed (a_language: READABLE_STRING_8; a_parsed_ranges: LIST [LANGUAGE_RESULTS]): FITNESS_AND_QUALITY
- -- Find the best match for a given `a_language' against a list of language ranges `a_parsed_ranges'
- -- that have already been parsed by parse_language_range.
- local
- best_fitness: INTEGER
- target_q: REAL_64
- best_fit_q: REAL_64
- target: LANGUAGE_RESULTS
- range: LANGUAGE_RESULTS
- keys: LIST [READABLE_STRING_8]
- param_matches: INTEGER
- element: detachable READABLE_STRING_8
- l_fitness: INTEGER
- do
- best_fitness := -1
- best_fit_q := 0.0
- target := parse_language_range (a_language)
- if attached target.item ("q") as q and then q.is_double then
- target_q := q.to_double
- if target_q < 0.0 then
- target_q := 0.0
- elseif target_q > 1.0 then
- target_q := 1.0
- end
- else
- target_q := 1.0
- end
- if attached target.type as l_target_type then
- from
- a_parsed_ranges.start
- until
- a_parsed_ranges.after
- loop
- range := a_parsed_ranges.item_for_iteration
- if (attached range.type as l_range_type and then (l_target_type.same_string (l_range_type) or l_range_type.same_string ("*") or l_target_type.same_string ("*"))) then
- from
- param_matches := 0
- keys := target.keys
- keys.start
- until
- keys.after
- loop
- element := keys.item_for_iteration
- if not element.same_string ("q") and then range.has_key (element) and then (attached target.item (element) as t_item and attached range.item (element) as r_item) and then t_item.same_string (r_item) then
- param_matches := param_matches + 1
- end
- keys.forth
- end
- if l_range_type.same_string (l_target_type) then
- l_fitness := 100
- else
- l_fitness := 0
- end
- if (attached range.sub_type as l_range_sub_type and then attached target.sub_type as l_target_sub_type and then (l_target_sub_type.same_string (l_range_sub_type) or l_range_sub_type.same_string ("*") or l_target_sub_type.same_string ("*"))) then
- if l_range_sub_type.same_string (l_target_sub_type) then
- l_fitness := l_fitness + 10
- end
- end
- l_fitness := l_fitness + param_matches
- if l_fitness > best_fitness then
- best_fitness := l_fitness
- element := range.item ("q")
- if element /= Void then
- best_fit_q := element.to_double.min (target_q)
- else
- best_fit_q := 0.0
- end
- end
- end
- a_parsed_ranges.forth
- end
- end
- create Result.make (best_fitness, best_fit_q)
- end
-
- quality_parsed (a_language: READABLE_STRING_8; a_parsed_ranges: LIST [LANGUAGE_RESULTS]): REAL_64
- -- Find the best match for a given `a_language' against a list of ranges `parsed_ranges' that
- -- have already been parsed by parse_language_range. Returns the 'q' quality
- -- parameter of the best match, 0 if no match was found. This function
- -- bahaves the same as quality except that 'a_parsed_ranges' must be a list
- -- of parsed language ranges.
- do
- Result := fitness_and_quality_parsed (a_language, a_parsed_ranges).quality
- end
-
- quality (a_language: READABLE_STRING_8; a_ranges: READABLE_STRING_8): REAL_64
- -- Returns the quality 'q' of a `a_language' when compared against the
- -- language range in `a_ranges'.
- local
- l_ranges: LIST [READABLE_STRING_8]
- res: ARRAYED_LIST [LANGUAGE_RESULTS]
- p_res: LANGUAGE_RESULTS
- do
- l_ranges := a_ranges.split (',')
- from
- create res.make (10);
- l_ranges.start
- until
- l_ranges.after
- loop
- p_res := parse_language_range (l_ranges.item_for_iteration)
- res.put_left (p_res)
- l_ranges.forth
- end
- Result := quality_parsed (a_language, res)
- end
-
- best_match (a_supported: LIST [READABLE_STRING_8]; a_header: READABLE_STRING_8): READABLE_STRING_8
- -- Choose the `language' with the highest fitness score and quality ('q') from a list of candidates.
- local
- l_header_results: LIST [LANGUAGE_RESULTS]
- weighted_matches: LIST [FITNESS_AND_QUALITY]
- l_res: LIST [READABLE_STRING_8]
- p_res: LANGUAGE_RESULTS
- fitness_and_quality, first_one: detachable FITNESS_AND_QUALITY
- s: READABLE_STRING_8
- do
- l_res := a_header.split (',')
- create {ARRAYED_LIST [LANGUAGE_RESULTS]} l_header_results.make (l_res.count)
- fixme ("Extract method!!!")
- from
- l_res.start
- until
- l_res.after
- loop
- p_res := parse_language_range (l_res.item_for_iteration)
- l_header_results.force (p_res)
- l_res.forth
- end
- create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (a_supported.count)
- from
- a_supported.start
- until
- a_supported.after
- loop
- fitness_and_quality := fitness_and_quality_parsed (a_supported.item_for_iteration, l_header_results)
- fitness_and_quality.set_mime_type (mime_type (a_supported.item_for_iteration))
- weighted_matches.force (fitness_and_quality)
- a_supported.forth
- end
-
- --| Keep only top quality+fitness types
- from
- weighted_matches.start
- first_one := weighted_matches.item
- weighted_matches.forth
- until
- weighted_matches.after
- loop
- fitness_and_quality := weighted_matches.item
- if first_one < fitness_and_quality then
- first_one := fitness_and_quality
- if not weighted_matches.isfirst then
- from
- weighted_matches.back
- until
- weighted_matches.before
- loop
- weighted_matches.remove
- weighted_matches.back
- end
- weighted_matches.forth
- end
- check
- weighted_matches.item = fitness_and_quality
- end
- weighted_matches.forth
- elseif first_one.is_equal (fitness_and_quality) then
- weighted_matches.forth
- else
- check
- first_one > fitness_and_quality
- end
- weighted_matches.remove
- end
- end
- if first_one /= Void and then first_one.quality /= 0.0 then
- if weighted_matches.count = 1 then
- Result := first_one.mime_type
- else
- from
- fitness_and_quality := Void
- l_header_results.start
- until
- l_header_results.after or fitness_and_quality /= Void
- loop
- s := l_header_results.item.mime_type
- from
- weighted_matches.start
- until
- weighted_matches.after or fitness_and_quality /= Void
- loop
- fitness_and_quality := weighted_matches.item
- if fitness_and_quality.mime_type.same_string (s) then
- --| Found
- else
- fitness_and_quality := Void
- weighted_matches.forth
- end
- end
- l_header_results.forth
- end
- if fitness_and_quality /= Void then
- Result := fitness_and_quality.mime_type
- else
- Result := first_one.mime_type
- end
- end
- else
- Result := ""
- end
- end
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/src/parsers/mime_type_parser_utilities.e b/library/network/protocol/content_negotiation/src/parsers/mime_type_parser_utilities.e
deleted file mode 100644
index 7011a93b..00000000
--- a/library/network/protocol/content_negotiation/src/parsers/mime_type_parser_utilities.e
+++ /dev/null
@@ -1,43 +0,0 @@
-note
- description: "{MIME_TYPE_PARSER_UTILITIES}."
- date: "$Date$"
- revision: "$Revision$"
-
-class
- MIME_TYPE_PARSER_UTILITIES
-
-feature {NONE} -- Implementation
-
- mime_type (a_str: READABLE_STRING_8): READABLE_STRING_8
- -- `s' with any trailing parameters stripped
- local
- p: INTEGER
- do
- p := a_str.index_of (';', 1)
- if p > 0 then
- Result := trim (a_str.substring (1, p - 1))
- else
- Result := trim (a_str.string)
- end
- end
-
- trim (a_string: READABLE_STRING_8): READABLE_STRING_8
- -- trim whitespace from the beginning and end of a string
- -- `a_string'
- require
- valid_argument : a_string /= Void
- local
- l_result: STRING
- do
- l_result := a_string.as_string_8
- l_result.left_adjust
- l_result.right_adjust
- Result := l_result
- ensure
- result_same_as_argument: Result.same_string_general (a_string)
- end
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-end
diff --git a/library/network/protocol/content_negotiation/src/results/common_results.e b/library/network/protocol/content_negotiation/src/results/common_results.e
deleted file mode 100644
index 627ba520..00000000
--- a/library/network/protocol/content_negotiation/src/results/common_results.e
+++ /dev/null
@@ -1,90 +0,0 @@
-note
- description: "Object that represents a results after parsing Charset or Encoding Accept headers."
- date: "$Date$"
- revision: "$Revision$"
-
-class
- COMMON_RESULTS
-
-create
- make
-
-feature -- Initialization
-
- make
- do
- create params.make (2)
- end
-
-feature -- Access
-
- field: detachable STRING
-
- item (a_key: STRING): detachable STRING
- -- Item associated with `a_key', if present
- -- otherwise default value of type `STRING'
- do
- Result := params.item (a_key)
- end
-
- keys: LIST [STRING]
- -- arrays of currents keys
- local
- res: ARRAYED_LIST [STRING]
- do
- create res.make_from_array (params.current_keys)
- Result := res
- end
-
-
- params: HASH_TABLE [STRING, STRING]
- --dictionary of all the parameters for the media range
-
-feature -- Status Report
-
- has_key (a_key: STRING): BOOLEAN
- -- Is there an item in the table with key `a_key'?
- do
- Result := params.has_key (a_key)
- end
-
-feature -- Element change
-
- set_field (a_field: STRING)
- -- Set type with `a_charset'
- do
- field := a_field
- ensure
- field_set: attached field as l_field implies l_field = a_field
- end
-
- put (new: STRING; key: STRING)
- -- Insert `new' with `key' if there is no other item
- -- associated with the same key. If present, replace
- -- the old value with `new'
- do
- if params.has_key (key) then
- params.replace (new, key)
- else
- params.force (new, key)
- end
- ensure
- has_key: params.has_key (key)
- has_item: params.has_item (new)
- end
-
-feature -- Status Report
-
- debug_output: STRING
- -- String that should be displayed in debugger to represent `Current'.
- do
- Result := out
- end
-
-
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/src/results/http_accept_language.e b/library/network/protocol/content_negotiation/src/results/http_accept_language.e
new file mode 100644
index 00000000..9b6b9be9
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/results/http_accept_language.e
@@ -0,0 +1,242 @@
+note
+ description: "Object that represents a result after parsing Language Headers."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ HTTP_ACCEPT_LANGUAGE
+
+inherit
+ REFACTORING_HELPER
+
+ DEBUG_OUTPUT
+
+create
+ make_from_string,
+ make,
+ make_with_language,
+ make_default
+
+feature {NONE} -- Initialization
+
+ make_from_string (a_accept_language_item: READABLE_STRING_8)
+ -- Instantiate Current from part of accept-language header, i.e language tag and parameters.
+ --
+ -- Languages-ranges are languages with specialization and a 'q' quality parameter.
+ -- For example, the language l_range ('en-* ;q=0.5') would get parsed into:
+ -- ('en', '*', {'q', '0.5'})
+ -- In addition this also guarantees that there is a value for 'q'
+ -- in the params dictionary, filling it in with a proper default if
+ -- necessary.
+ local
+ i: INTEGER
+ do
+ fixme (generator + ".make_from_string: improve code!!!")
+ i := a_accept_language_item.index_of (';', 1)
+ if i > 0 then
+ make_with_language (trimmed_string (a_accept_language_item.substring (1, i - 1)))
+ create parameters.make_from_substring (a_accept_language_item, i + 1, a_accept_language_item.count)
+ check attached parameters as l_params and then not l_params.has_error end
+ else
+ make_with_language (trimmed_string (a_accept_language_item))
+ end
+
+ check quality_initialized_to_1: quality = 1.0 end
+
+ -- Get quality from parameter if any, and format the value as expected.
+ if attached parameter ("q") as q then
+ if q.same_string ("1") then
+ --| Use 1.0 formatting
+ put_parameter ("1.0", "q")
+ elseif q.is_double and then attached q.to_real_64 as r then
+ if r <= 0.0 then
+ quality := 0.0 --| Should it be 1.0 ?
+ put_parameter ("0.0", "q")
+ elseif r >= 1.0 then
+ quality := 1.0
+ put_parameter ("1.0", "q")
+ else
+ quality := r
+ end
+ else
+ put_parameter ("1.0", "q")
+ quality := 1.0
+ end
+ else
+ put_parameter ("1.0", "q")
+ end
+ end
+
+ make_with_language (a_lang_tag: READABLE_STRING_8)
+ -- Instantiate Current from language tag `a_lang_tag'.
+ do
+ initialize
+ set_language_range (a_lang_tag)
+ ensure
+ language_range_set: language_range.same_string (a_lang_tag) and a_lang_tag /= language_range
+ end
+
+ make (a_root_lang: READABLE_STRING_8; a_specialization: detachable READABLE_STRING_8)
+ -- Instantiate Current with `a_root_lang' and `a_specialization'.
+ do
+ initialize
+ create language_range.make_empty
+ language := a_root_lang
+ specialization := a_specialization
+ update_language_range (a_root_lang, a_specialization)
+ end
+
+ make_default
+ -- Instantiate Current with default "*" language.
+ do
+ make ("*", Void)
+ end
+
+ initialize
+ -- Initialize Current
+ do
+ create parameters.make (1)
+ quality := 1.0
+ end
+
+feature -- Access
+
+ language_range: STRING_8
+ -- language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+
+ language: READABLE_STRING_8
+ -- First part of the language range, i.e the root language
+
+ specialization: detachable READABLE_STRING_8
+ -- Optional second part of the language range, i.e the dialect, or specialized language type
+
+ quality: REAL_64
+ -- Associated quality, by default 1.0
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ create Result.make_from_string (language_range)
+ Result.append_character (';')
+ Result.append ("q=")
+ Result.append_double (quality)
+ end
+
+feature -- Element change
+
+ set_language_range (a_lang_range: READABLE_STRING_8)
+ local
+ i: INTEGER
+ do
+ create language_range.make_from_string (a_lang_range)
+ i := a_lang_range.index_of ('-', 1)
+ if i > 0 then
+ language := a_lang_range.substring (1, i - 1)
+ specialization := a_lang_range.substring (i + 1, a_lang_range.count)
+ else
+ language := a_lang_range
+ end
+ ensure
+ language_range_set: language_range.same_string (a_lang_range) and a_lang_range /= language_range
+ end
+
+ set_language (a_root_lang: READABLE_STRING_8)
+ -- Set `'anguage' with `a_root_lang'
+ require
+ a_root_lang_attached: a_root_lang /= Void
+ do
+ language := a_root_lang
+ update_language_range (a_root_lang, specialization)
+ ensure
+ type_assigned: language ~ a_root_lang
+ end
+
+ set_specialization (a_specialization: detachable READABLE_STRING_8)
+ -- Set `specialization' with `a_specialization'
+ do
+ specialization := a_specialization
+ update_language_range (language, a_specialization)
+ ensure
+ specialization_assigned: specialization ~ a_specialization
+ end
+
+feature -- Parameters: Access
+
+ parameter (a_key: READABLE_STRING_8): detachable READABLE_STRING_8
+ -- Parameter associated with `a_key', if present
+ -- otherwise default value of type `STRING'
+ do
+ if attached parameters as l_params then
+ Result := l_params.item (a_key)
+ end
+ end
+
+ parameters: detachable HTTP_PARAMETER_TABLE
+ -- Table of all parameters for the media range
+
+feature -- Parameters: Status report
+
+ has_parameter (a_key: READABLE_STRING_8): BOOLEAN
+ -- Is there an parameter in the parameters table with key `a_key'?
+ do
+ if attached parameters as l_params then
+ Result := l_params.has_key (a_key)
+ end
+ end
+
+feature -- Parameters: Change
+
+ put_parameter (a_value: READABLE_STRING_8; a_key: READABLE_STRING_8)
+ -- Insert `a_value' with `a_key' if there is no other item
+ -- associated with the same key. If present, replace
+ -- the old value with `a_value'
+ local
+ l_parameters: like parameters
+ do
+ l_parameters := parameters
+ if l_parameters = Void then
+ create l_parameters.make (1)
+ parameters := l_parameters
+ end
+ l_parameters.force (a_value, a_key)
+ ensure
+ is_set: attached parameters as l_params and then (l_params.has_key (a_key) and l_params.has_item (a_value))
+ end
+
+feature {NONE} -- Implementation
+
+ update_language_range (a_lang: like language; a_specialization: like specialization)
+ -- Update `language_range' with `a_lang' and `a_specialization'
+ local
+ l_language_range: like language_range
+ do
+ l_language_range := language_range -- Reuse same object, be careful not to keep reference on existing string at first.
+ l_language_range.wipe_out
+ l_language_range.append (a_lang)
+
+ if a_specialization /= Void then
+ l_language_range.append_character ('-')
+ l_language_range.append (a_specialization)
+ end
+ end
+
+feature {NONE} -- Helper
+
+ trimmed_string (s: READABLE_STRING_8): STRING_8
+ -- Copy of `s', where whitespace were stripped from the beginning and end of the string
+ do
+ create Result.make_from_string (s)
+ Result.left_adjust
+ Result.right_adjust
+ end
+
+invariant
+ valid_quality: 0.0 <= quality and quality <= 1.0
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/results/http_any_accept.e b/library/network/protocol/content_negotiation/src/results/http_any_accept.e
new file mode 100644
index 00000000..f35bbb4d
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/results/http_any_accept.e
@@ -0,0 +1,118 @@
+note
+ description: "Object that represents a results after parsing Accept(-*) headers."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ HTTP_ANY_ACCEPT
+
+inherit
+ REFACTORING_HELPER
+
+ DEBUG_OUTPUT
+
+create
+ make_from_string
+
+feature -- Initialization
+
+ make_from_string (a_string: READABLE_STRING_8)
+ local
+ l_parts: LIST [READABLE_STRING_8]
+ sub_parts: LIST [READABLE_STRING_8]
+ p: READABLE_STRING_8
+ i: INTEGER
+ do
+ initialize
+ i := a_string.index_of (';', 1)
+ if i > 0 then
+ set_value (trimmed_string (a_string.substring (1, i - 1)))
+ create parameters.make_from_substring (a_string, i + 1, a_string.count)
+ else
+ set_value (trimmed_string (a_string))
+ end
+ end
+
+ initialize
+ do
+ end
+
+feature -- Access
+
+ value: READABLE_STRING_8
+ -- Value composing an Accept(-*) header value
+
+feature -- Access: parameters
+
+ parameter (a_key: READABLE_STRING_8): detachable READABLE_STRING_8
+ -- Item associated with `a_key', if present
+ -- otherwise default value of type `STRING'
+ do
+ if attached parameters as l_parameters then
+ Result := l_parameters.item (a_key)
+ end
+ end
+
+ parameters: detachable HTTP_PARAMETER_TABLE
+ -- Table of all parameters for the media range
+
+feature -- Status Report
+
+ has_parameter (a_key: READABLE_STRING_8): BOOLEAN
+ -- Is there an item in the table with key `a_key'?
+ do
+ if attached parameters as l_parameters then
+ Result := l_parameters.has_key (a_key)
+ end
+ end
+
+feature -- Element change
+
+ set_value (v: READABLE_STRING_8)
+ -- Set `value' with `v'
+ do
+ value := v
+ ensure
+ value_set: attached value as l_value implies l_value.same_string (v)
+ end
+
+ put_parameter (a_value: READABLE_STRING_8; a_key: READABLE_STRING_8)
+ -- Insert `a_value' with `a_key' if there is no other item
+ -- associated with the same key. If present, replace
+ -- the old value with `a_value'
+ local
+ l_parameters: like parameters
+ do
+ l_parameters := parameters
+ if l_parameters = Void then
+ create l_parameters.make (1)
+ parameters := l_parameters
+ end
+ l_parameters.force (a_value, a_key)
+ ensure
+ is_set: attached parameters as l_params and then (l_params.has_key (a_key) and l_params.has_item (a_value))
+ end
+
+feature -- Status Report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ create Result.make_from_string (value)
+ end
+
+feature {NONE} -- Helper
+
+ trimmed_string (s: READABLE_STRING_8): STRING_8
+ -- Copy of `s', where whitespace were stripped from the beginning and end of the string
+ do
+ create Result.make_from_string (s)
+ Result.left_adjust
+ Result.right_adjust
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/results/language_results.e b/library/network/protocol/content_negotiation/src/results/language_results.e
deleted file mode 100644
index 23211c03..00000000
--- a/library/network/protocol/content_negotiation/src/results/language_results.e
+++ /dev/null
@@ -1,112 +0,0 @@
-note
- description: "Object that represents a result after parsing Language Headers."
- date: "$Date$"
- revision: "$Revision$"
-
-class
- LANGUAGE_RESULTS
-
-create
- make
-
-feature -- Initialization
-
- make
- --Create an object LANGUAGE_RESULTS.
- do
- create params.make (2)
- create mime_type.make_from_string ("*")
- end
-
-feature -- Access
-
- type: detachable STRING
-
- sub_type: detachable STRING
-
- mime_type: STRING
-
- item (a_key: STRING): detachable STRING
- -- Item associated with `a_key', if present
- -- otherwise default value of type `STRING'
- do
- Result := params.item (a_key)
- end
-
- keys: LIST [STRING]
- -- arrays of currents keys
- local
- res: ARRAYED_LIST [STRING]
- do
- create res.make_from_array (params.current_keys)
- Result := res
- end
-
- params: HASH_TABLE [STRING, STRING]
- --dictionary of all the parameters for the media range
-
-feature -- Status Report
-
- has_key (a_key: STRING): BOOLEAN
- -- Is there an item in the table with key `a_key'?
- do
- Result := params.has_key (a_key)
- end
-
-feature -- Element change
-
- set_type (a_type: STRING)
- -- Set type with `a_type'
- do
- type := a_type
- if attached sub_type as st then
- mime_type := a_type + "-" + st
- else
- mime_type := a_type
- end
- ensure
- type_assigned: type ~ a_type
- end
-
- set_sub_type (a_sub_type: STRING)
- -- Set sub_type with `a_sub_type
- do
- sub_type := a_sub_type
- if attached type as t then
- mime_type := t + "-" + a_sub_type
- else
- mime_type := "*"
- end
- ensure
- sub_type_assigned: sub_type ~ a_sub_type
- end
-
- put (new: STRING; key: STRING)
- -- Insert `new' with `key' if there is no other item
- -- associated with the same key. If present, replace
- -- the old value with `new'
- do
- if params.has_key (key) then
- params.replace (new, key)
- else
- params.force (new, key)
- end
- ensure
- has_key: params.has_key (key)
- has_item: params.has_item (new)
- end
-
-feature -- Status Report
-
- debug_output: STRING
- -- String that should be displayed in debugger to represent `Current'.
- do
- Result := out
- end
-
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/src/server_charset_negotiation.e b/library/network/protocol/content_negotiation/src/server_charset_negotiation.e
new file mode 100644
index 00000000..9652fcf3
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/server_charset_negotiation.e
@@ -0,0 +1,92 @@
+note
+ description: "Summary description for {SERVER_CHARSET_NEGOTIATION}. Utility class to support Server Side Content Negotiation on charset "
+ date: "$Date$"
+ revision: "$Revision$"
+ description: "[
+ Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
+ Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
+ it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
+ and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
+ Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
+ or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
+ In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
+ ]"
+ EIS: "name=server driven negotiation", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.", "protocol=uri"
+
+class
+ SERVER_CHARSET_NEGOTIATION
+
+inherit
+ REFACTORING_HELPER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_charset_dft: READABLE_STRING_8)
+ do
+ create accept_charset_utilities
+ set_default_charset (a_charset_dft)
+ ensure
+ default_charset_set: default_charset = a_charset_dft
+ end
+
+ accept_charset_utilities: HTTP_ANY_ACCEPT_HEADER_UTILITIES
+ -- Charset
+
+feature -- Access: Server Side Defaults Formats
+
+ default_charset: READABLE_STRING_8
+ -- Character set that is acceptable for the response.
+
+feature -- Change Element
+
+ set_default_charset (a_charset: READABLE_STRING_8)
+ -- Set `default_charset' with `a_charset'
+ do
+ default_charset := a_charset
+ ensure
+ default_charset_set: a_charset = default_charset
+ end
+
+feature -- Charset Negotiation
+
+ preference (a_server_charset_supported: ITERABLE [READABLE_STRING_8]; a_header: detachable READABLE_STRING_8): HTTP_ACCEPT_CHARSET_VARIANTS
+ -- `a_server_charset_supported' represent a list of character sets supported by the server.
+ -- `a_header' represents the Accept-Charset header, ie, the client preferences.
+ -- Return which Charset to use in a response, if the server supports
+ -- the requested Charset, or empty in other case.
+ note
+ EIS: "name=charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
+ local
+ l_charset_match: READABLE_STRING_8
+ do
+ create Result.make
+ Result.set_supported_variants (a_server_charset_supported)
+ if a_header = Void or else a_header.is_empty then
+ -- the request has no Accept-Charset header, ie the header is empty, in this case use default charset encoding
+ Result.set_acceptable (True)
+ Result.set_variant_value (default_charset)
+ else
+ Result.set_vary_header_value
+
+ -- select the best match, server support, client preferences
+ l_charset_match := accept_charset_utilities.best_match (a_server_charset_supported, a_header)
+ if l_charset_match.is_empty then
+ -- The server does not support any of the compression types prefered by the client
+ Result.set_acceptable (False)
+ else
+ -- Set the best match
+ Result.set_variant_value (l_charset_match)
+ Result.set_acceptable (True)
+ end
+ end
+ end
+
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/server_content_negotiation.e b/library/network/protocol/content_negotiation/src/server_content_negotiation.e
new file mode 100644
index 00000000..a8f9319b
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/server_content_negotiation.e
@@ -0,0 +1,67 @@
+note
+ description: "Summary description for {SERVER_CONTENT_NEGOTIATION}. Utility class to support Server Side Content Negotiation "
+ date: "$Date$"
+ revision: "$Revision$"
+ description: "[
+ Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
+ Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
+ it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
+ and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
+ Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
+ or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
+ In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
+ ]"
+ EIS: "name=server driven negotiation", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.", "protocol=uri"
+
+class
+ SERVER_CONTENT_NEGOTIATION
+
+inherit
+ SERVER_MEDIA_TYPE_NEGOTIATION
+ rename
+ make as make_media_type,
+ preference as media_type_preference
+ end
+
+ SERVER_LANGUAGE_NEGOTIATION
+ rename
+ make as make_language,
+ preference as language_preference
+ end
+
+ SERVER_CHARSET_NEGOTIATION
+ rename
+ make as make_charset,
+ preference as charset_preference
+ end
+
+ SERVER_ENCODING_NEGOTIATION
+ rename
+ make as make_encoding,
+ preference as encoding_preference
+ end
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_mediatype_dft: READABLE_STRING_8; a_language_dft: READABLE_STRING_8; a_charset_dft: READABLE_STRING_8; a_encoding_dft: READABLE_STRING_8)
+ -- Initialize Current with default Media type, language, charset and encoding.
+ do
+ make_media_type (a_mediatype_dft)
+ make_language (a_language_dft)
+ make_charset (a_charset_dft)
+ make_encoding (a_encoding_dft)
+ ensure
+ default_media_type_set: default_media_type = a_mediatype_dft
+ default_language_set: default_language = a_language_dft
+ default_charset_set: default_charset = a_charset_dft
+ default_encoding_set: default_encoding = a_encoding_dft
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/server_encoding_negotiation.e b/library/network/protocol/content_negotiation/src/server_encoding_negotiation.e
new file mode 100644
index 00000000..65e04bb2
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/server_encoding_negotiation.e
@@ -0,0 +1,91 @@
+note
+ description: "Summary description for {SERVER_ENCODING_NEGOTIATION}. Utility class to support Server Side Content Negotiation on encoding"
+ date: "$Date$"
+ revision: "$Revision$"
+ description: "[
+ Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
+ Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
+ it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
+ and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
+ Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
+ or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
+ In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
+ ]"
+ EIS: "name=server driven negotiation", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.", "protocol=uri"
+
+class
+ SERVER_ENCODING_NEGOTIATION
+
+inherit
+ REFACTORING_HELPER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_encoding_dft: READABLE_STRING_8)
+ do
+ create accept_encoding_utilities
+ set_default_encoding (a_encoding_dft)
+ ensure
+ default_encoding_set: default_encoding = a_encoding_dft
+ end
+
+ accept_encoding_utilities: HTTP_ANY_ACCEPT_HEADER_UTILITIES
+ -- Encoding
+
+feature -- Access: Server Side Defaults Formats
+
+ default_encoding: READABLE_STRING_8
+ -- Content-coding that is acceptable in the response.
+
+feature -- Change Element
+
+ set_default_encoding (a_encoding: READABLE_STRING_8)
+ -- Set `default_encoding' with `a_encoding'
+ do
+ default_encoding := a_encoding
+ ensure
+ default_encoding_set: a_encoding = default_encoding
+ end
+
+feature -- Encoding Negotiation
+
+ preference (a_server_encoding_supported: ITERABLE [READABLE_STRING_8]; a_header_value: detachable READABLE_STRING_8): HTTP_ACCEPT_ENCODING_VARIANTS
+ -- `a_server_encoding_supported' represent a list of encoding supported by the server.
+ -- `a_header_value' represent the Accept-Encoding header, ie, the client preferences.
+ -- Return which Encoding to use in a response, if the server supports
+ -- the requested Encoding, or empty in other case.
+ note
+ EIS: "name=encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
+ local
+ l_compression_match: READABLE_STRING_8
+ do
+ create Result.make
+ Result.set_supported_variants (a_server_encoding_supported)
+ if a_header_value = Void or else a_header_value.is_empty then
+ -- the request has no Accept-Encoding header, ie the header is empty, in this case do not compress representations
+ Result.set_acceptable (True)
+ Result.set_variant_value (default_encoding)
+ else
+ Result.set_vary_header_value
+
+ -- select the best match, server support, client preferences
+ l_compression_match := accept_encoding_utilities.best_match (a_server_encoding_supported, a_header_value)
+ if l_compression_match.is_empty then
+ -- The server does not support any of the compression types prefered by the client
+ Result.set_acceptable (False)
+ else
+ -- Set the best match
+ Result.set_variant_value (l_compression_match)
+ Result.set_acceptable (True)
+ end
+ end
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/server_language_negotiation.e b/library/network/protocol/content_negotiation/src/server_language_negotiation.e
new file mode 100644
index 00000000..f01d51d2
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/server_language_negotiation.e
@@ -0,0 +1,93 @@
+note
+ description: "Summary description for {SERVER_LANGUAGE_NEGOTIATION}. Utility class to support Server Side Content Negotiation on language"
+ date: "$Date$"
+ revision: "$Revision$"
+ description: "[
+ Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
+ Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
+ it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
+ and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
+ Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
+ or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
+ In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
+ ]"
+ EIS: "name=server driven negotiation", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.", "protocol=uri"
+
+class
+ SERVER_LANGUAGE_NEGOTIATION
+
+inherit
+ REFACTORING_HELPER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_language_dft: READABLE_STRING_8)
+ do
+ create accept_language_utilities
+ set_default_language (a_language_dft)
+ ensure
+ default_language_set: default_language = a_language_dft
+ end
+
+ accept_language_utilities: HTTP_ACCEPT_LANGUAGE_UTILITIES
+ -- Language
+
+feature -- Access: Server Side Defaults Formats
+
+ default_language: READABLE_STRING_8
+ -- Natural language that is preferred as a response to the request.
+
+feature -- Change Element
+
+ set_default_language (a_language: READABLE_STRING_8)
+ -- Set `default_language' with `a_language'
+ do
+ default_language := a_language
+ ensure
+ default_language_set: a_language = default_language
+ end
+
+feature -- Language Negotiation
+
+ preference (a_server_language_supported: ITERABLE [READABLE_STRING_8]; a_header_value: detachable READABLE_STRING_8): HTTP_ACCEPT_LANGUAGE_VARIANTS
+ -- `a_server_language_supported' represent a list of languages supported by the server.
+ -- `a_header_value' represent the Accept-Language header, ie, the client preferences.
+ -- Return which Language to use in a response, if the server supports
+ -- the requested Language, or empty in other case.
+ note
+ EIS: "name=language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
+
+ local
+ l_language_match: READABLE_STRING_8
+ do
+ create Result.make
+ Result.set_supported_variants (a_server_language_supported)
+
+ if a_header_value = Void or else a_header_value.is_empty then
+ -- the request has no Accept header, ie the header is empty, in this case we use the default format
+ Result.set_acceptable (True)
+ Result.set_variant_value (default_language)
+ else
+ Result.set_vary_header_value
+
+ -- select the best match, server support, client preferences
+ l_language_match := accept_language_utilities.best_match (a_server_language_supported, a_header_value)
+ if l_language_match.is_empty then
+ -- The server does not support any of the media types prefered by the client
+ Result.set_acceptable (False)
+ else
+ -- Set the best match
+ Result.set_variant_value (l_language_match)
+ Result.set_acceptable (True)
+ end
+ end
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/server_media_type_negotiation.e b/library/network/protocol/content_negotiation/src/server_media_type_negotiation.e
new file mode 100644
index 00000000..76c84a70
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/server_media_type_negotiation.e
@@ -0,0 +1,91 @@
+note
+ description: "Summary description for {SERVER_MEDIA_TYPE_NEGOTIATION}. Utility class to support Server Side Content Negotiation on media type"
+ date: "$Date$"
+ revision: "$Revision$"
+ description: "[
+ Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
+ Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
+ it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
+ and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
+ Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
+ or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
+ In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
+ ]"
+ EIS: "name=server driven negotiation", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.", "protocol=uri"
+
+class
+ SERVER_MEDIA_TYPE_NEGOTIATION
+
+inherit
+ REFACTORING_HELPER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_mediatype_dft: READABLE_STRING_8)
+ do
+ create accept_media_type_utilities
+ set_default_media_type (a_mediatype_dft)
+ ensure
+ default_media_type_set: default_media_type = a_mediatype_dft
+ end
+
+ accept_media_type_utilities: HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
+ -- MIME
+
+feature -- Access: Server Side Defaults Formats
+
+ default_media_type: READABLE_STRING_8
+ -- Media type which is acceptable for the response.
+
+feature -- Change Element
+
+ set_default_media_type (a_mediatype: READABLE_STRING_8)
+ -- Set `default_media_type' with `a_mediatype'
+ do
+ default_media_type := a_mediatype
+ ensure
+ default_media_type_set: a_mediatype = default_media_type
+ end
+
+feature -- Media Type Negotiation
+
+ preference (a_mime_types_supported: ITERABLE [READABLE_STRING_8]; a_header: detachable READABLE_STRING_8): HTTP_ACCEPT_MEDIA_TYPE_VARIANTS
+ -- `a_mime_types_supported' represent media types supported by the server.
+ -- `a_header represent' the Accept header, ie, the client preferences.
+ -- Return which media type to use for representation in a response, if the server supports
+ -- the requested media type, or empty in other case.
+ note
+ EIS: "name=media type", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
+ local
+ l_mime_match: READABLE_STRING_8
+ do
+ create Result.make
+ Result.set_supported_variants (a_mime_types_supported)
+ if a_header = Void or else a_header.is_empty then
+ -- the request has no Accept header, ie the header is empty, in this case we use the default format
+ Result.set_acceptable (True)
+ Result.set_variant_value (default_media_type)
+ else
+ Result.set_vary_header_value
+
+ -- select the best match, server support, client preferences
+ l_mime_match := accept_media_type_utilities.best_match (a_mime_types_supported, a_header)
+ if l_mime_match.is_empty then
+ -- The server does not support any of the media types preferred by the client
+ Result.set_acceptable (False)
+ else
+ -- Set the best match
+ Result.set_variant_value (l_mime_match)
+ Result.set_acceptable (True)
+ end
+ end
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/shared_conneg.e b/library/network/protocol/content_negotiation/src/shared_conneg.e
deleted file mode 100644
index 08c8d174..00000000
--- a/library/network/protocol/content_negotiation/src/shared_conneg.e
+++ /dev/null
@@ -1,31 +0,0 @@
-note
- description: "Summary description for {SHARED_CONNEG}."
- date: "$Date$"
- revision: "$Revision$"
-
-class
- SHARED_CONNEG
-
-feature
-
- Mime: MIME_PARSE
- once
- create Result
- end
-
- Common: COMMON_ACCEPT_HEADER_PARSER
- -- Charset and Encoding
- once
- create Result
- end
-
- Language: LANGUAGE_PARSE
- once
- create Result
- end
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/src/variants/character_encoding_variant_results.e b/library/network/protocol/content_negotiation/src/variants/http_accept_charset_variants.e
similarity index 67%
rename from library/network/protocol/content_negotiation/src/variants/character_encoding_variant_results.e
rename to library/network/protocol/content_negotiation/src/variants/http_accept_charset_variants.e
index 862507cd..3a36e0a8 100644
--- a/library/network/protocol/content_negotiation/src/variants/character_encoding_variant_results.e
+++ b/library/network/protocol/content_negotiation/src/variants/http_accept_charset_variants.e
@@ -1,6 +1,6 @@
note
description: "[
- {CHARACTER_ENCODING_VARIANT_RESULTS}
+ {HTTP_ACCEPT_CHARSET_VARIANTS}
Represent the character sets results between client preferences and character sets variants supported by the server.
If the server is unable to supports the requested Accept-Charset values, the server can build
a response with the list of supported character sets.
@@ -10,20 +10,22 @@ note
revision: "$Revision$"
class
- CHARACTER_ENCODING_VARIANT_RESULTS
+ HTTP_ACCEPT_CHARSET_VARIANTS
inherit
+ HTTP_ACCEPT_VARIANTS
+ rename
+ variant_value as charset
+ end
- VARIANT_RESULTS
+create
+ make
+feature -- Change
-feature -- Change Element
-
-
- set_variant_header
- -- Set variant header as `Accept-Charset'
+ set_vary_header_value
do
- variant_header := {HTTP_HEADER_NAMES}.header_accept_charset -- "Accept-Charset"
+ vary_header_value := {HTTP_HEADER_NAMES}.header_accept_charset -- "Accept-Charset"
end
note
diff --git a/library/network/protocol/content_negotiation/src/variants/compression_variant_results.e b/library/network/protocol/content_negotiation/src/variants/http_accept_encoding_variants.e
similarity index 52%
rename from library/network/protocol/content_negotiation/src/variants/compression_variant_results.e
rename to library/network/protocol/content_negotiation/src/variants/http_accept_encoding_variants.e
index 22d0893d..805bf1a9 100644
--- a/library/network/protocol/content_negotiation/src/variants/compression_variant_results.e
+++ b/library/network/protocol/content_negotiation/src/variants/http_accept_encoding_variants.e
@@ -1,28 +1,31 @@
note
description: "[
- {COMPRESSION_VARIANT_RESULTS}
- Represent the compression results between client preferences and ccompression variants supported by the server.
+ {HTTP_ACCEPT_ENCODING_VARIANTS}
+ Represent the encoding results between client preferences and encoding variants supported by the server.
If the server is unable to supports the requested Accept-Encoding values, the server can build
- a response with the list of supported encodings/compressions
+ a response with the list of supported encodings
]"
date: "$Date$"
revision: "$Revision$"
EIS: "name= Compression", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
class
- COMPRESSION_VARIANT_RESULTS
+ HTTP_ACCEPT_ENCODING_VARIANTS
inherit
+ HTTP_ACCEPT_VARIANTS
+ rename
+ variant_value as encoding
+ end
- VARIANT_RESULTS
+create
+ make
+feature -- Change
-feature -- Change Element
-
- set_variant_header
- -- Set variant_header as `Accept-Encoding'
+ set_vary_header_value
do
- variant_header := {HTTP_HEADER_NAMES}.header_accept_encoding -- "Accept-Encoding"
+ vary_header_value := {HTTP_HEADER_NAMES}.header_accept_encoding -- "Accept-Encoding"
end
note
diff --git a/library/network/protocol/content_negotiation/src/variants/language_variant_results.e b/library/network/protocol/content_negotiation/src/variants/http_accept_language_variants.e
similarity index 65%
rename from library/network/protocol/content_negotiation/src/variants/language_variant_results.e
rename to library/network/protocol/content_negotiation/src/variants/http_accept_language_variants.e
index 7bfb6059..f51b1f87 100644
--- a/library/network/protocol/content_negotiation/src/variants/language_variant_results.e
+++ b/library/network/protocol/content_negotiation/src/variants/http_accept_language_variants.e
@@ -1,6 +1,6 @@
note
description: "[
- {LANGUAGE_VARIANT_RESULTS}.
+ {HTTP_ACCEPT_LANGUAGE_VARIANTS}.
Represent the language results between client preferences and language variants supported by the server.
If the server is unable to supports the requested Accept-Language values, the server can build
a response with the list of supported languages
@@ -9,18 +9,22 @@ note
revision: "$Revision$"
class
- LANGUAGE_VARIANT_RESULTS
+ HTTP_ACCEPT_LANGUAGE_VARIANTS
inherit
+ HTTP_ACCEPT_VARIANTS
+ rename
+ variant_value as language
+ end
- VARIANT_RESULTS
+create
+ make
-feature -- Change Element
+feature -- Change
- set_variant_header
- -- Set variant header as 'Accept-Language'
+ set_vary_header_value
do
- variant_header := {HTTP_HEADER_NAMES}.header_accept_language -- "Accept-Language"
+ vary_header_value := {HTTP_HEADER_NAMES}.header_accept_language -- "Accept-Language"
end
note
diff --git a/library/network/protocol/content_negotiation/src/variants/media_type_variant_results.e b/library/network/protocol/content_negotiation/src/variants/http_accept_media_type_variants.e
similarity index 52%
rename from library/network/protocol/content_negotiation/src/variants/media_type_variant_results.e
rename to library/network/protocol/content_negotiation/src/variants/http_accept_media_type_variants.e
index 988f8cad..00900ce3 100644
--- a/library/network/protocol/content_negotiation/src/variants/media_type_variant_results.e
+++ b/library/network/protocol/content_negotiation/src/variants/http_accept_media_type_variants.e
@@ -1,7 +1,7 @@
note
description: "[
- {MEDIA_TYPE_VARIANT_RESULTS}.
- Represent the media type results between client preferences and media type variants supported by the server..
+ {HTTP_ACCEPT_MEDIA_TYPE_VARIANTS}.
+ Represents the media type results between client preferences and media type variants supported by the server..
If the server is unable to supports the requested Accept values, the server can build
a response with the list of supported representations
]"
@@ -9,18 +9,22 @@ note
revision: "$Revision$"
class
- MEDIA_TYPE_VARIANT_RESULTS
+ HTTP_ACCEPT_MEDIA_TYPE_VARIANTS
inherit
+ HTTP_ACCEPT_VARIANTS
+ rename
+ variant_value as media_type
+ end
- VARIANT_RESULTS
+create
+ make
-feature -- Change Element
+feature -- Change
- set_variant_header
- -- Set variant header as `Accept'
+ set_vary_header_value
do
- variant_header := {HTTP_HEADER_NAMES}.header_accept -- "Accept"
+ vary_header_value := {HTTP_HEADER_NAMES}.header_accept -- "Accept"
end
note
diff --git a/library/network/protocol/content_negotiation/src/variants/http_accept_variants.e b/library/network/protocol/content_negotiation/src/variants/http_accept_variants.e
new file mode 100644
index 00000000..78a39be2
--- /dev/null
+++ b/library/network/protocol/content_negotiation/src/variants/http_accept_variants.e
@@ -0,0 +1,92 @@
+note
+ description: "Generic {HTTP_ACCEPT_VARIANTS}.with common functionality to most header variants.."
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ HTTP_ACCEPT_VARIANTS
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ end
+
+feature -- Change
+
+ set_vary_header_value
+ -- Set the `vary_header_value'
+ deferred
+ ensure
+ is_valid_header_set : is_valid_header_name (vary_header_value)
+ end
+
+feature -- Access
+
+ vary_header_value: detachable READABLE_STRING_8
+ -- Name of header to be added to the Vary header of the response
+ -- this indicates the Accept-* header source of the matched `variant_value' if any,
+ -- if this is using the default, the `vary_header_value' is Void.
+
+ supported_variants: detachable ITERABLE [READABLE_STRING_8]
+ -- Set of supported variants for the response
+
+ variant_value: detachable READABLE_STRING_8
+ -- Associated value, it could be value of:
+ -- content type
+ -- language
+ -- character set
+ -- encoding.
+
+feature -- Status_Report
+
+ is_acceptable: BOOLEAN
+ -- is the current variant accepted?
+
+ is_valid_header_name (a_header_name: detachable READABLE_STRING_8): BOOLEAN
+ -- is `a_header_name' a valid accept header name?
+ note
+ EIS:"name=Accept", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
+ EIS:"name=Accept-Charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
+ EIS:"name=Accept-Encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
+ EIS:"name=Accept-Language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
+ do
+ if a_header_name /= Void then
+ Result := a_header_name.same_string ({HTTP_HEADER_NAMES}.header_accept) -- "Accept",
+ or else a_header_name.same_string ({HTTP_HEADER_NAMES}.header_accept_language) -- "Accept-Language",
+ or else a_header_name.same_string ({HTTP_HEADER_NAMES}.header_accept_encoding) -- "Accept-Encoding",
+ or else a_header_name.same_string ({HTTP_HEADER_NAMES}.header_accept_charset) -- "Accept-Charset"
+ end
+ end
+
+feature -- Change Element
+
+ set_variant_value (v: READABLE_STRING_8)
+ -- Set `variant_value' as `v'
+ do
+ variant_value := v
+ ensure
+ type_set: attached variant_value as l_variant implies l_variant = v
+ end
+
+ set_acceptable (b: BOOLEAN)
+ -- Set `is_acceptable' with `b'
+ do
+ is_acceptable := b
+ ensure
+ is_acceptable_set: is_acceptable = b
+ end
+
+ set_supported_variants (a_supported: ITERABLE [READABLE_STRING_8])
+ -- Set `supported variants' with `a_supported'
+ do
+ supported_variants := a_supported
+ ensure
+ set_supported_variants: attached supported_variants as l_supported_variants implies l_supported_variants = a_supported
+ end
+
+note
+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+
+end
diff --git a/library/network/protocol/content_negotiation/src/variants/variant_results.e b/library/network/protocol/content_negotiation/src/variants/variant_results.e
deleted file mode 100644
index bb48cacf..00000000
--- a/library/network/protocol/content_negotiation/src/variants/variant_results.e
+++ /dev/null
@@ -1,91 +0,0 @@
-note
- description: "Generic {VARIANT_RESULTS}.with common functionality to most header variants.."
- date: "$Date$"
- revision: "$Revision$"
-
-deferred class
- VARIANT_RESULTS
-
-feature -- Access
-
- variant_header: detachable READABLE_STRING_8
- -- Name of variant header to be added to the Vary header of the response
-
- supported_variants: detachable LIST [READABLE_STRING_8]
- -- Set of supported variants for the response
-
- is_acceptable: BOOLEAN
- -- is the current variant accepted?
-
- type: detachable READABLE_STRING_8
- -- Associated type, it could be:
- -- media type
- -- language
- -- character_sets
- -- encoding.
-
-feature {NONE} -- Implementation
-
- accept_headers_set: ARRAY [READABLE_STRING_8]
- -- Set of valid accept headers headers
- note
- EIS:"name=Accept", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
- EIS:"name=Accept-Charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
- EIS:"name=Accept-Encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
- EIS:"name=Accept-Language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
- once
- Result:= <<
- {HTTP_HEADER_NAMES}.header_accept, -- "Accept",
- {HTTP_HEADER_NAMES}.header_accept_language, -- "Accept-Language",
- {HTTP_HEADER_NAMES}.header_accept_encoding, -- "Accept-Encoding",
- {HTTP_HEADER_NAMES}.header_accept_charset --"Accept-Charset"
- >>
- Result.compare_objects
- end
-
-feature -- Status_Report
-
- is_valid_header (a_header: READABLE_STRING_8): BOOLEAN
- -- is `a_header' a valid accept header?
- do
- Result := accept_headers_set.has (a_header)
- end
-
-feature -- Change Element
-
- set_type (a_type: READABLE_STRING_8)
- -- Set `type' as `a_type'
- do
- type := a_type
- ensure
- type_set: attached type as l_type implies l_type = a_type
- end
-
- set_acceptable (acceptable: BOOLEAN)
- -- Set `is_acceptable' with `acceptable'
- do
- is_acceptable := acceptable
- ensure
- is_acceptable_set: is_acceptable = acceptable
- end
-
- set_variant_header
- -- Set variant header
- deferred
- ensure
- is_valid_header_set : attached variant_header as l_header implies is_valid_header (l_header)
- end
-
- set_supported_variants (a_supported: LIST [READABLE_STRING_8])
- -- Set `supported variants' with `a_supported'
- do
- supported_variants := a_supported
- ensure
- set_supported_variants: attached supported_variants as l_supported_variants implies l_supported_variants = a_supported
- end
-
-note
- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
-
-end
diff --git a/library/network/protocol/content_negotiation/test/application.e b/library/network/protocol/content_negotiation/test/application.e
index a7078001..74cd00d7 100644
--- a/library/network/protocol/content_negotiation/test/application.e
+++ b/library/network/protocol/content_negotiation/test/application.e
@@ -16,10 +16,10 @@ feature {NONE} -- Initialization
make
local
- mime_parse : MIME_PARSE
+ mime_parse : HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
accept : STRING
- charset_parse : COMMON_ACCEPT_HEADER_PARSER
- language : LANGUAGE_PARSE
+ charset_parse : HTTP_ANY_ACCEPT_HEADER_UTILITIES
+ language : HTTP_ACCEPT_LANGUAGE_UTILITIES
do
create mime_parse
-- parse_result := mime_parse.parse_mime_type ("application/xhtml;q=0.5")
@@ -59,12 +59,12 @@ feature {NONE} -- Initialization
print ("%N"+mime_parse.quality ("*/*;q=0.1", accept).out)
accept := "application/atom+xml"
- print ("%N"+mime_parse.parse_mime_type (accept).out)
+ print ("%N"+mime_parse.media_type (accept).out)
create charset_parse
accept := "iso-8859-5"
- print ("%N" + charset_parse.parse_common (accept).out)
+ print ("%N" + charset_parse.header (accept).out)
accept := "unicode-1-1;q=0.8"
- print ("%N" + charset_parse.parse_common (accept).out)
+ print ("%N" + charset_parse.header (accept).out)
accept:= "iso-8859-5, unicode-1-1;q=0.8"
@@ -78,10 +78,10 @@ feature {NONE} -- Initialization
print (language.best_match (accept.split (','), "da"))
print (language.best_match (accept.split (','), "en-*"))
- print ("%N"+language.parse_language_range ("da").out)
- print ("%N"+language.parse_language_range ("en-gb;q=0.8").out)
- print ("%N"+language.parse_language_range ("en;q=0.7").out)
- print ("%N"+language.parse_language_range ("en-*").out)
+ print ("%N"+language.accept_language ("da").out)
+ print ("%N"+language.accept_language ("en-gb;q=0.8").out)
+ print ("%N"+language.accept_language ("en;q=0.7").out)
+ print ("%N"+language.accept_language ("en-*").out)
end
end
diff --git a/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e b/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e
index 9cd88ad5..1c736576 100644
--- a/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e
+++ b/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e
@@ -23,33 +23,31 @@ feature {NONE} -- Events
feature -- Helpers
- format (a_common: COMMON_RESULTS): STRING
+ format (a_common: HTTP_ANY_ACCEPT): STRING
-- Representation of the current object
do
create Result.make_from_string ("(")
- if attached a_common.field as t then
+ if attached a_common.value as t then
Result.append_string ("'" + t + "',")
end
Result.append_string (" {")
- from
- a_common.params.start
- until
- a_common.params.after
- loop
- Result.append ("'" + a_common.params.key_for_iteration + "':'" + a_common.params.item_for_iteration + "',");
- a_common.params.forth
+ if attached a_common.parameters as l_parameters then
+ across
+ l_parameters as ic
+ loop
+ Result.append ("'" + ic.key + "':'" + ic.item + "',");
+ end
end
Result.append ("})")
end
-
feature -- Test routines
test_parse_charsets
do
- assert ("Expected ('iso-8859-5', {'q':'1.0',})", format (parser.parse_common("iso-8859-5")).same_string("('iso-8859-5', {'q':'1.0',})") )
- assert ("Expected ('unicode-1-1', {'q':'0.8',})", format (parser.parse_common("unicode-1-1;q=0.8")).same_string("('unicode-1-1', {'q':'0.8',})") )
- assert ("Expected ('*', {'q':'1.0',})", format (parser.parse_common("*")).same_string("('*', {'q':'1.0',})") )
+ assert ("Expected ('iso-8859-5', {'q':'1.0',})", format (parser.header("iso-8859-5")).same_string("('iso-8859-5', {'q':'1.0',})") )
+ assert ("Expected ('unicode-1-1', {'q':'0.8',})", format (parser.header("unicode-1-1;q=0.8")).same_string("('unicode-1-1', {'q':'0.8',})") )
+ assert ("Expected ('*', {'q':'1.0',})", format (parser.header("*")).same_string("('*', {'q':'1.0',})") )
end
@@ -74,6 +72,6 @@ feature -- Test routines
assert ("Expected unicode-1-1", parser.best_match (charset_supported, "unicode-1-1;q=1").same_string ("unicode-1-1"))
end
- parser : COMMON_ACCEPT_HEADER_PARSER
+ parser : HTTP_ANY_ACCEPT_HEADER_UTILITIES
end
diff --git a/library/network/protocol/content_negotiation/test/conneg_server_side_test.e b/library/network/protocol/content_negotiation/test/conneg_server_side_test.e
index 55d29e79..6bf9f7ed 100644
--- a/library/network/protocol/content_negotiation/test/conneg_server_side_test.e
+++ b/library/network/protocol/content_negotiation/test/conneg_server_side_test.e
@@ -24,7 +24,7 @@ feature {NONE} -- Events
feature -- Test routines
test_media_type_negotiation
local
- media_variants : MEDIA_TYPE_VARIANT_RESULTS
+ media_variants : HTTP_ACCEPT_MEDIA_TYPE_VARIANTS
mime_types_supported : LIST [STRING]
l_types : STRING
do
@@ -33,24 +33,28 @@ feature -- Test routines
mime_types_supported := l_types.split(',')
media_variants := conneg.media_type_preference (mime_types_supported, "text/html")
assert ("Expected Not Acceptable", not media_variants.is_acceptable)
- assert ("Same Value at 1",mime_types_supported.at (1).is_equal (media_variants.supported_variants.at (1)))
- assert ("Same count",mime_types_supported.count = media_variants.supported_variants.count)
- assert ("Variant header is void",media_variants.variant_header = Void)
- assert ("Media type is void",media_variants.type = Void)
+ if attached media_variants.supported_variants as l_supported_variants then
+ assert ("Same Value at 1", same_text (first_of (mime_types_supported), first_of (l_supported_variants)))
+ assert ("Same count", count_of (mime_types_supported) = count_of (l_supported_variants))
+ else
+ assert ("Has supported_variants results", False)
+ end
+ assert ("Variant Header", attached media_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept"))
+ assert ("Media type is void",media_variants.media_type = Void)
-- Scenario 2, the client doesnt send values in the header, Accept:
media_variants := conneg.media_type_preference (mime_types_supported, "")
assert ("Expected Acceptable", media_variants.is_acceptable)
- assert ("Variants is dettached",media_variants.supported_variants = Void)
- assert ("Mime is defaul", conneg.mime_default.is_equal (media_variants.type))
- assert ("Variant header", media_variants.variant_header = Void)
+ assert ("Variants is set",media_variants.supported_variants = mime_types_supported)
+ assert ("Mime is default", attached media_variants.media_type as l_media_type and then conneg.default_media_type.same_string (l_media_type))
+ assert ("Variant header", media_variants.vary_header_value = Void)
--Scenario 3, the server select the best match, and set the vary header
- media_variants := conneg.media_type_preference (mime_types_supported, "text/*,application/json;q=0.5")
+ media_variants := conneg.media_type_preference (mime_types_supported, "text/*,application/xml;q=0.5,application/json;q=0.6")
assert ("Expected Acceptable", media_variants.is_acceptable)
- assert ("Variants is dettached",media_variants.supported_variants = Void)
- assert ("Variant Header", media_variants.variant_header.is_equal ("Accept"))
- assert ("Media Type is application/json", media_variants.type.is_equal ("application/json"))
+ assert ("Variants is set",media_variants.supported_variants = mime_types_supported)
+ assert ("Variant Header", attached media_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept"))
+ assert ("Media Type is application/json", attached media_variants.media_type as l_media_type and then l_media_type.same_string ("application/json"))
end
@@ -58,40 +62,44 @@ feature -- Test routines
test_charset_negotiation
local
- charset_variants : CHARACTER_ENCODING_VARIANT_RESULTS
+ charset_variants : HTTP_ACCEPT_CHARSET_VARIANTS
charset_supported : LIST [STRING]
- l_charset : STRING
+ l_charset_value : STRING
do
-- Scenario 1, the server side does not support client preferences
- l_charset := "UTF-8, iso-8859-5"
- charset_supported := l_charset.split(',')
+ l_charset_value := "UTF-8, iso-8859-5"
+ charset_supported := l_charset_value.split(',')
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1")
assert ("Expected Not Acceptable", not charset_variants.is_acceptable)
- assert ("Same Value at 1",charset_supported.at (1).is_equal (charset_variants.supported_variants.at (1)))
- assert ("Same count",charset_supported.count = charset_variants.supported_variants.count)
- assert ("Variant header is void",charset_variants.variant_header = Void)
- assert ("Character type is void",charset_variants.type = Void)
+ if attached charset_variants.supported_variants as l_supported_variants then
+ assert ("Same Value at 1", same_text (first_of (charset_supported), first_of (l_supported_variants)))
+ assert ("Same count",charset_supported.count = count_of (l_supported_variants))
+ else
+ assert("Has supported_variants results", False)
+ end
+ assert ("Variant Header", attached charset_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Charset"))
+ assert ("Character type is void",charset_variants.charset = Void)
-- Scenario 2, the client doesnt send values in the header, Accept-Charset:
charset_variants := conneg.charset_preference (charset_supported, "")
assert ("Expected Acceptable", charset_variants.is_acceptable)
- assert ("Variants is dettached",charset_variants.supported_variants = Void)
- assert ("Charset is defaul", conneg.charset_default.is_equal (charset_variants.type))
- assert ("Variant header", charset_variants.variant_header = Void)
+ assert ("Variants is set",charset_variants.supported_variants = charset_supported)
+ assert ("Charset is default", attached charset_variants.charset as l_charset and then conneg.default_charset.same_string (l_charset))
+ assert ("Variant header", charset_variants.vary_header_value = Void)
--Scenario 3, the server select the best match, and set the vary header
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1, UTF-8;q=0.3, iso-8859-5")
assert ("Expected Acceptable", charset_variants.is_acceptable)
- assert ("Variants is dettached",charset_variants.supported_variants = Void)
- assert ("Variant Header", charset_variants.variant_header.is_equal ("Accept-Charset"))
- assert ("Character Type is iso-8859-5", charset_variants.type.is_equal ("iso-8859-5"))
+ assert ("Variants is set",charset_variants.supported_variants = charset_supported)
+ assert ("Variant Header", attached charset_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Charset"))
+ assert ("Character Type is iso-8859-5", attached charset_variants.charset as l_charset and then l_charset.same_string ("iso-8859-5"))
end
test_compression_negotiation
local
- compression_variants : COMPRESSION_VARIANT_RESULTS
+ compression_variants : HTTP_ACCEPT_ENCODING_VARIANTS
compression_supported : LIST [STRING]
l_compression : STRING
do
@@ -100,91 +108,90 @@ feature -- Test routines
compression_supported := l_compression.split(',')
compression_variants := conneg.encoding_preference (compression_supported, "gzip")
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
- assert ("Same Value at 1",compression_supported.at (1).is_equal (compression_variants.supported_variants.at (1)))
- assert ("Same count",compression_supported.count = compression_variants.supported_variants.count)
- assert ("Variant header is void",compression_variants.variant_header = Void)
- assert ("Compression type is void",compression_variants.type = Void)
+ if attached compression_variants.supported_variants as l_supported_variants then
+ assert ("Same Value at 1", same_text (first_of (compression_supported), first_of (l_supported_variants)))
+ assert ("Same count",compression_supported.count = count_of (l_supported_variants))
+ else
+ assert ("Has supported_variants results", False)
+ end
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Compression type is void",compression_variants.encoding = Void)
-- Scenario 2, the client doesnt send values in the header, Accept-Encoding
compression_variants := conneg.encoding_preference (compression_supported, "")
assert ("Expected Acceptable", compression_variants.is_acceptable)
- assert ("Variants is dettached",compression_variants.supported_variants = Void)
- assert ("Compression is defaul", conneg.encoding_default.is_equal (compression_variants.type))
- assert ("Variant header", compression_variants.variant_header = Void)
+ assert ("Variants is set",compression_variants.supported_variants = compression_supported)
+ assert ("Compression is default", attached compression_variants.encoding as l_encoding and then conneg.default_encoding.same_string (l_encoding))
+ assert ("Variant header", compression_variants.vary_header_value = Void)
--Scenario 3, the server select the best match, and set the vary header
l_compression := "gzip"
compression_supported := l_compression.split(',')
- conneg.set_encoding_default("gzip")
+ conneg.set_default_encoding("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "compress,gzip;q=0.7")
assert ("Expected Acceptable", compression_variants.is_acceptable)
- assert ("Variants is dettached",compression_variants.supported_variants = Void)
- assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
- assert ("Encoding Type is gzip", compression_variants.type.is_equal ("gzip"))
-
+ assert ("Variants is set",compression_variants.supported_variants = compression_supported)
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Encoding Type is gzip", attached compression_variants.encoding as l_type and then l_type.same_string ("gzip"))
-- Scenario 4, the server set `identity' and the client doesn't mention identity
l_compression := "identity"
compression_supported := l_compression.split(',')
- conneg.set_encoding_default("gzip")
+ conneg.set_default_encoding ("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "gzip;q=0.7")
- assert ("Expected Acceptable", compression_variants.is_acceptable)
- assert ("Variants is dettached",compression_variants.supported_variants = Void)
- assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
- assert ("Encoding Type is identity", compression_variants.type.is_equal ("identity"))
+ assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
+ assert ("Variants is set",compression_variants.supported_variants = compression_supported)
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Encoding Type is Void", compression_variants.encoding = Void)
-- Scenario 5, the server set `identity' and the client mention identity,q=0
l_compression := "identity"
compression_supported := l_compression.split(',')
- conneg.set_encoding_default("gzip")
+ conneg.set_default_encoding ("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "identity;q=0")
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
assert ("Variants is attached",attached compression_variants.supported_variants )
- assert ("Variant Header is void", compression_variants.variant_header = Void)
- assert ("Encoding Type is Void", compression_variants.type = Void)
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Encoding Type is Void", compression_variants.encoding = Void)
-- Scenario 6, the server set `identity' and the client mention *,q=0
l_compression := "identity"
compression_supported := l_compression.split(',')
- conneg.set_encoding_default("gzip")
+ conneg.set_default_encoding ("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "*;q=0")
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
assert ("Variants is attached",attached compression_variants.supported_variants )
- assert ("Variant Header is void", compression_variants.variant_header = Void)
- assert ("Encoding Type is Void", compression_variants.type = Void)
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Encoding Type is Void", compression_variants.encoding = Void)
-- Scenario 7, the server set `identity' and the client mention identity;q=0.5, gzip;q=0.7,compress
l_compression := "identity"
compression_supported := l_compression.split(',')
- conneg.set_encoding_default("gzip")
+ conneg.set_default_encoding ("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "identity;q=0.5, gzip;q=0.7,compress")
assert ("Expected Acceptable",compression_variants.is_acceptable)
- assert ("Variants is void",compression_variants.supported_variants = Void)
- assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
- assert ("Encoding Type is identity", compression_variants.type.is_equal ("identity"))
+ assert ("Variants is set",compression_variants.supported_variants = compression_supported)
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Encoding Type is identity", attached compression_variants.encoding as l_type and then l_type.same_string ("identity"))
-- Scenario 8, the server set `identity' and the client mention identity;q=0.5
l_compression := "identity"
compression_supported := l_compression.split(',')
- conneg.set_encoding_default("gzip")
+ conneg.set_default_encoding ("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "identity;q=0.5")
assert ("Expected Acceptable",compression_variants.is_acceptable)
- assert ("Variants is void",compression_variants.supported_variants = Void)
- assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
- assert ("Encoding Type is identity", compression_variants.type.is_equal ("identity"))
-
-
+ assert ("Variants is set",compression_variants.supported_variants = compression_supported)
+ assert ("Variant Header", attached compression_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Encoding"))
+ assert ("Encoding Type is identity", attached compression_variants.encoding as l_type and then l_type.same_string ("identity"))
end
-
-
test_language_negotiation
local
- language_variants : LANGUAGE_VARIANT_RESULTS
+ language_variants : HTTP_ACCEPT_LANGUAGE_VARIANTS
languages_supported : LIST [STRING]
l_languages : STRING
do
@@ -193,30 +200,61 @@ feature -- Test routines
languages_supported := l_languages.split(',')
language_variants := conneg.language_preference (languages_supported, "de")
assert ("Expected Not Acceptable", not language_variants.is_acceptable)
- assert ("Same Value at 1",languages_supported.at (1).is_equal (language_variants.supported_variants.at (1)))
- assert ("Same count",languages_supported.count = language_variants.supported_variants.count)
- assert ("Variant header is void",language_variants.variant_header = Void)
- assert ("Language type is void",language_variants.type = Void)
-
+ assert ("Variant Header", attached language_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Language"))
+ assert ("Language type is Void",language_variants.language = Void)
+ if attached language_variants.supported_variants as l_supported_variants then
+ assert ("Same Value at 1", same_text (first_of (languages_supported), first_of (l_supported_variants)))
+ assert ("Same count",languages_supported.count = count_of (l_supported_variants))
+ else
+ assert ("Has supported variants results", False)
+ end
-- Scenario 2, the client doesnt send values in the header, Accept-Language:
language_variants := conneg.language_preference (languages_supported, "")
assert ("Expected Acceptable", language_variants.is_acceptable)
- assert ("Variants is dettached",language_variants.supported_variants = Void)
- assert ("Language is defaul", conneg.language_default.is_equal (language_variants.type))
- assert ("Variant header", language_variants.variant_header = Void)
-
+ assert ("Variants is attached",language_variants.supported_variants = languages_supported)
+ assert ("Language is default", attached language_variants.language as l_lang and then conneg.default_language.same_string (l_lang))
+ assert ("Variant header", language_variants.vary_header_value = Void)
--Scenario 3, the server select the best match, and set the vary header
language_variants := conneg.language_preference (languages_supported, "fr,es;q=0.4")
assert ("Expected Acceptable", language_variants.is_acceptable)
- assert ("Variants is dettached",language_variants.supported_variants = Void)
- assert ("Variant Header", language_variants.variant_header.is_equal ("Accept-Language"))
- assert ("Language Type is fr", language_variants.type.is_equal ("fr"))
-
-
+ assert ("Variants is detached",language_variants.supported_variants = languages_supported)
+ assert ("Variant Header", attached language_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Language"))
+ assert ("Language Type is fr", attached language_variants.language as l_lang and then l_lang.same_string ("fr"))
end
feature -- Implementation
- conneg : CONNEG_SERVER_SIDE
+ conneg : SERVER_CONTENT_NEGOTIATION
+
+ same_text (s1,s2: detachable READABLE_STRING_8): BOOLEAN
+ do
+ if s1 = Void then
+ Result := s2 = Void
+ elseif s2 = Void then
+ Result := False
+ else
+ Result := s1.same_string (s2)
+ end
+ end
+
+ count_of (i: ITERABLE [READABLE_STRING_8]): INTEGER
+ do
+ across
+ i as ic
+ loop
+ Result := Result + 1
+ end
+ end
+
+ first_of (i: ITERABLE [READABLE_STRING_8]): detachable READABLE_STRING_8
+ do
+ across
+ i as ic
+ until
+ ic.item /= Void
+ loop
+ end
+ end
+
end
diff --git a/library/network/protocol/content_negotiation/test/language_parser_test.e b/library/network/protocol/content_negotiation/test/language_parser_test.e
index fe557164..fe937a20 100644
--- a/library/network/protocol/content_negotiation/test/language_parser_test.e
+++ b/library/network/protocol/content_negotiation/test/language_parser_test.e
@@ -23,25 +23,22 @@ feature {NONE} -- Events
feature -- Helpers
- format (a_language: LANGUAGE_RESULTS): STRING
+ format (a_language: HTTP_ACCEPT_LANGUAGE): STRING
-- Representation of the current object
do
create Result.make_from_string ("(")
- if attached a_language.type as t then
+ if attached a_language.language as t then
Result.append_string ("'" + t + "',")
end
- if attached a_language.sub_type as st then
+ if attached a_language.specialization as st then
Result.append_string (" '" + st + "',")
end
Result.append_string (" {")
- if attached a_language.params as l_params then
- from
- l_params.start
- until
- l_params.after
+ if attached a_language.parameters as l_params then
+ across
+ l_params as ic
loop
- Result.append ("'" + l_params.key_for_iteration + "':'"+ l_params.item_for_iteration + "',");
- l_params.forth
+ Result.append ("'" + ic.key + "':'"+ ic.item + "',");
end
end
Result.append ("})")
@@ -52,10 +49,10 @@ feature -- Test routines
test_parse_language
do
- assert ("Expected ('da', {'q':'1.0',})", format (parser.parse_language_range ("da")).same_string ("('da', {'q':'1.0',})"));
- assert ("Expected ('en', 'gb', {'q':'0.8',})", format (parser.parse_language_range ("en-gb;q=0.8")).same_string ("('en', 'gb', {'q':'0.8',})"));
- assert ("Expected ('en', {'q':'0.7',})", format (parser.parse_language_range ("en;q=0.7")).same_string ("('en', {'q':'0.7',})"));
- assert ("Expected ('en', '*', {'q':'1.0',})", format (parser.parse_language_range ("en-*")).same_string ("('en', '*', {'q':'1.0',})"));
+ assert ("Expected ('da', {'q':'1.0',})", format (parser.accept_language ("da")).same_string ("('da', {'q':'1.0',})"));
+ assert ("Expected ('en', 'gb', {'q':'0.8',})", format (parser.accept_language ("en-gb;q=0.8")).same_string ("('en', 'gb', {'q':'0.8',})"));
+ assert ("Expected ('en', {'q':'0.7',})", format (parser.accept_language ("en;q=0.7")).same_string ("('en', {'q':'0.7',})"));
+ assert ("Expected ('en', '*', {'q':'1.0',})", format (parser.accept_language ("en-*")).same_string ("('en', '*', {'q':'1.0',})"));
end
@@ -73,53 +70,53 @@ feature -- Test routines
test_best_match
local
- mime_types_supported : LIST [STRING]
+ langs_supported : LIST [STRING]
l_types : STRING
do
l_types := "en-gb,en-us"
- mime_types_supported := l_types.split(',')
- assert ("Expected en-us", parser.best_match (mime_types_supported, "en-us").same_string ("en-us"))
- assert ("Direct match with a q parameter", parser.best_match (mime_types_supported, "en-gb;q=1").same_string ("en-gb"))
- assert ("Direct match second choice with a q parameter", parser.best_match (mime_types_supported, "en-us;q=1").same_string ("en-us"))
- assert ("Direct match using a subtype wildcard", parser.best_match (mime_types_supported, "en-*;q=1").is_equal ("en-gb"))
- assert ("Match using a type wildcard", parser.best_match (mime_types_supported, "*").same_string ("en-gb"))
+ langs_supported := l_types.split(',')
+ assert ("Expected en-us", parser.best_match (langs_supported, "en-us").same_string ("en-us"))
+ assert ("Direct match with a q parameter", parser.best_match (langs_supported, "en-gb;q=1").same_string ("en-gb"))
+ assert ("Direct match second choice with a q parameter", parser.best_match (langs_supported, "en-us;q=1").same_string ("en-us"))
+ assert ("Direct match using a subtype wildcard", parser.best_match (langs_supported, "en-*;q=1").is_equal ("en-gb"))
+ assert ("Match using a type wildcard", parser.best_match (langs_supported, "*").same_string ("en-gb"))
l_types := "en-gb,es"
- mime_types_supported := l_types.split(',')
- assert ("Match using a type versus a lower weighted subtype", parser.best_match (mime_types_supported, "es-*;q=0.5,*;q=0.1").same_string ("es"))
- assert ("Fail to match anything",parser.best_match (mime_types_supported, "fr; q=0.9").same_string (""))
+ langs_supported := l_types.split(',')
+ assert ("Match using a type versus a lower weighted subtype", parser.best_match (langs_supported, "es-*;q=0.5,*;q=0.1").same_string ("es"))
+ assert ("Fail to match anything",parser.best_match (langs_supported, "fr; q=0.9").same_string (""))
l_types := "en-gb,en-us"
- mime_types_supported := l_types.split(',')
- assert ("Test 1 verify fitness ordering", parser.best_match (mime_types_supported, "en-gb,en-us,*").same_string ("en-gb"))
+ langs_supported := l_types.split(',')
+ assert ("Test 1 verify fitness ordering", parser.best_match (langs_supported, "en-gb,en-us,*").same_string ("en-gb"))
l_types := "es,en-gb;q=1.0,fr;q=0.6"
- mime_types_supported := l_types.split(',')
- assert ("Match default es at first position", parser.best_match (mime_types_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
+ langs_supported := l_types.split(',')
+ assert ("Match default es at first position", parser.best_match (langs_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
l_types := "en-gb;q=1.0,fr;q=0.6,es"
- mime_types_supported := l_types.split(',')
- assert ("Match default es at last position", parser.best_match (mime_types_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
+ langs_supported := l_types.split(',')
+ assert ("Match default es at last position", parser.best_match (langs_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
l_types := "en-gb;q=1.0,fr,es"
- mime_types_supported := l_types.split(',')
- assert ("Match first top quality and fitness", parser.best_match (mime_types_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
+ langs_supported := l_types.split(',')
+ assert ("Match first top quality and fitness", parser.best_match (langs_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
l_types := "fr;q=1.0,en,es"
- mime_types_supported := l_types.split(',')
- assert ("Test 1", parser.best_match (mime_types_supported, "es;q=1.0,*/*;q=0.1,en;q=0.9").same_string ("es"))
+ langs_supported := l_types.split(',')
+ assert ("Test 1", parser.best_match (langs_supported, "es;q=1.0,*/*;q=0.1,en;q=0.9").same_string ("es"))
l_types := "fr;q=1.0,en,es"
- mime_types_supported := l_types.split(',')
- assert ("Test 1", parser.best_match (mime_types_supported, "es,*/*;q=0.1,en").same_string ("es"))
+ langs_supported := l_types.split(',')
+ assert ("Test 1", parser.best_match (langs_supported, "es,*/*;q=0.1,en").same_string ("es"))
l_types := "fr;q=1.0,en,es"
- mime_types_supported := l_types.split(',')
- assert ("Test 2", parser.best_match (mime_types_supported, "en,es,*/*;q=0.1").same_string ("en"))
+ langs_supported := l_types.split(',')
+ assert ("Test 2", parser.best_match (langs_supported, "en,es,*/*;q=0.1").same_string ("en"))
l_types := "es,en;q=0.6"
- mime_types_supported := l_types.split(',')
- assert ("Test 2", parser.best_match (mime_types_supported, "fr;q=1.0, en;q=0.6, es").same_string ("es"))
+ langs_supported := l_types.split(',')
+ assert ("Test 2", parser.best_match (langs_supported, "fr;q=1.0, en;q=0.6, es").same_string ("es"))
end
@@ -137,7 +134,7 @@ feature -- Test routines
- parser : LANGUAGE_PARSE
+ parser : HTTP_ACCEPT_LANGUAGE_UTILITIES
end
diff --git a/library/network/protocol/content_negotiation/test/mime_parser_test.e b/library/network/protocol/content_negotiation/test/mime_parser_test.e
index a63b8505..2a861868 100644
--- a/library/network/protocol/content_negotiation/test/mime_parser_test.e
+++ b/library/network/protocol/content_negotiation/test/mime_parser_test.e
@@ -38,13 +38,10 @@ feature -- Helper
end
Result.append_string (" {")
if attached a_mediatype.parameters as l_params then
- from
- l_params.start
- until
- l_params.after
+ across
+ l_params as ic
loop
- Result.append ("'" + l_params.key_for_iteration + "':'" + l_params.item_for_iteration + "',");
- l_params.forth
+ Result.append ("'" + ic.key + "':'" + ic.item + "',");
end
end
Result.append ("})")
@@ -54,15 +51,15 @@ feature -- Test routines
test_parse_media_range
do
- assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.parse_media_range("application/xml;q=1")).same_string("('application', 'xml', {'q':'1.0',})") )
+ assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.media_type("application/xml;q=1")).same_string("('application', 'xml', {'q':'1.0',})") )
- assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.parse_media_range("application/xml")).same_string("('application', 'xml', {'q':'1.0',})") )
- assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.parse_media_range("application/xml;q=")).same_string("('application', 'xml', {'q':'1.0',})") )
- assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.parse_media_range("application/xml ; q=")).same_string("('application', 'xml', {'q':'1.0',})") )
- assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", format (parser.parse_media_range("application/xml ; q=1;b=other")).same_string("('application', 'xml', {'q':'1.0','b':'other',})") )
- assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", format (parser.parse_media_range("application/xml ; q=2;b=other")).same_string("('application', 'xml', {'q':'1.0','b':'other',})") )
+ assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.media_type("application/xml")).same_string("('application', 'xml', {'q':'1.0',})") )
+ assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.media_type("application/xml;q=")).same_string("('application', 'xml', {'q':'1.0',})") )
+ assert ("Expected ('application', 'xml', {'q':'1',})", format (parser.media_type("application/xml ; q=")).same_string("('application', 'xml', {'q':'1.0',})") )
+ assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", format (parser.media_type("application/xml ; q=1;b=other")).same_string("('application', 'xml', {'q':'1.0','b':'other',})") )
+ assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", format (parser.media_type("application/xml ; q=2;b=other")).same_string("('application', 'xml', {'q':'1.0','b':'other',})") )
-- Accept header that includes *
- assert ("Expected ('*', '*', {'q':'.2',})", format (parser.parse_media_range(" *; q=.2")).same_string("('*', '*', {'q':'.2',})"))
+ assert ("Expected ('*', '*', {'q':'.2',})", format (parser.media_type(" *; q=.2")).same_string("('*', '*', {'q':'.2',})"))
end
@@ -148,7 +145,7 @@ feature -- Test routines
- parser : MIME_PARSE
+ parser : HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
end
diff --git a/library/network/protocol/content_negotiation/test/test-safe.ecf b/library/network/protocol/content_negotiation/test/test-safe.ecf
index 18eb204d..996f55a6 100644
--- a/library/network/protocol/content_negotiation/test/test-safe.ecf
+++ b/library/network/protocol/content_negotiation/test/test-safe.ecf
@@ -1,19 +1,23 @@
-
+
+ /.git$/EIFGENs$/CVS$/.svn$
- /.git$
-
+
+
+
-
diff --git a/library/network/protocol/http/src/http_media_type.e b/library/network/protocol/http/src/http_media_type.e
index fbe67cb2..d2d9614e 100644
--- a/library/network/protocol/http/src/http_media_type.e
+++ b/library/network/protocol/http/src/http_media_type.e
@@ -63,7 +63,6 @@ feature {NONE} -- Initialization
t: STRING_8
i,n: INTEGER
p: INTEGER
- cl: CELL [INTEGER]
do
-- Ignore starting space (should not be any)
from
@@ -79,15 +78,7 @@ feature {NONE} -- Initialization
p := s.index_of (';', i)
if p > 0 then
t := s.substring (i, p - 1)
- from
- create cl.put (p)
- i := p + 1
- until
- i >= n
- loop
- add_parameter_from_string (s, i, cl)
- i := cl.item
- end
+ create parameters.make_from_substring (s, p + 1, s.count)
else
t := s.substring (i, n)
end
@@ -116,7 +107,7 @@ feature {NONE} -- Initialization
subtype := type
end
ensure
- not has_error implies (create {HTTP_CONTENT_TYPE}.make_from_string (string)).same_string (string)
+ not has_error implies (create {HTTP_MEDIA_TYPE}.make_from_string (string)).same_string (string)
end
feature -- Status report
@@ -149,7 +140,7 @@ feature -- Access
end
end
- parameters: detachable HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
+ parameters: detachable HTTP_PARAMETER_TABLE
-- Parameters
feature -- Conversion
@@ -262,7 +253,7 @@ feature -- Element change
-- Remove parameter named `a_name'
do
if attached parameters as plst then
- plst.prune (a_name)
+ plst.remove (a_name)
if plst.is_empty then
parameters := Void
end
@@ -270,84 +261,6 @@ feature -- Element change
internal_string := Void
end
-feature {NONE} -- Implementation
-
- add_parameter_from_string (s: READABLE_STRING_8; start_index: INTEGER; out_end_index: CELL [INTEGER])
- -- Add parameter from string " attribute=value "
- -- and put in `out_end_index' the index after found parameter.
- local
- n: INTEGER
- pn,pv: STRING_8
- i: INTEGER
- p, q: INTEGER
- err: BOOLEAN
- do
- n := s.count
- -- Skip spaces
- from
- i := start_index
- until
- i > n or not s[i].is_space
- loop
- i := i + 1
- end
- if s[i] = ';' then
- -- empty parameter
- out_end_index.replace (i + 1)
- elseif i < n then
- p := s.index_of ('=', i)
- if p > 0 then
- pn := s.substring (i, p - 1)
- if p >= n then
- pv := ""
- out_end_index.replace (n + 1)
- else
- if s[p+1] = '%"' then
- q := s.index_of ('%"', p + 2)
- if q > 0 then
- pv := s.substring (p + 2, q - 1)
- from
- i := q + 1
- until
- i > n or not s[i].is_space
- loop
- i := i + 1
- end
- if s[i] = ';' then
- i := i + 1
- end
- out_end_index.replace (i)
- else
- err := True
- pv := ""
- -- missing closing double quote.
- end
- else
- q := s.index_of (';', p + 1)
- if q = 0 then
- q := n + 1
- end
- pv := s.substring (p + 1, q - 1)
- out_end_index.replace (q + 1)
- end
- pv.right_adjust
- if not err then
- add_parameter (pn, pv)
- end
- end
- else
- -- expecting: attribute "=" value
- err := True
- end
- end
- if err then
- out_end_index.replace (n + 1)
- end
- has_error := has_error or err
- ensure
- entry_processed: out_end_index.item > start_index
- end
-
feature {NONE} -- Internal
internal_string: detachable STRING_8
diff --git a/library/network/protocol/http/src/http_parameter_table.e b/library/network/protocol/http/src/http_parameter_table.e
new file mode 100644
index 00000000..21d8995c
--- /dev/null
+++ b/library/network/protocol/http/src/http_parameter_table.e
@@ -0,0 +1,150 @@
+note
+ description: "[
+ Table representing parameters of the form q=1.0;note="blabla";foo=bar
+ ]"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ HTTP_PARAMETER_TABLE
+
+inherit
+ HASH_TABLE [READABLE_STRING_8, STRING_8]
+ redefine
+ empty_duplicate
+ end
+
+create
+ make,
+ make_from_string,
+ make_from_substring
+
+feature {NONE} -- Initialization
+
+ make_from_string (s: READABLE_STRING_8)
+ -- Build table of parameters for `s'
+ do
+ make_from_substring (s, 1, s.count)
+ end
+
+ make_from_substring (s: READABLE_STRING_8; a_start_index: INTEGER; a_end_index: INTEGER)
+ -- Build table of parameters for `s.substring (a_start_index, a_end_index)'
+ local
+ cl: CELL [INTEGER]
+ i: INTEGER
+ do
+ make (1)
+ from
+ i := a_start_index
+ create cl.put (i)
+ until
+ i >= a_end_index
+ loop
+ force_substring (s, i, cl)
+ i := cl.item
+ end
+ end
+
+feature -- Status report
+
+ has_error: BOOLEAN
+ -- Current has error?
+ --| Mainly in relation with `make_from_string' and `force_substring'
+
+feature {NONE} -- Implementation
+
+ force_substring (s: READABLE_STRING_8; start_index: INTEGER; out_end_index: CELL [INTEGER])
+ -- Add parameter from string " attribute=value "
+ -- and put in `out_end_index' the index after found parameter.
+ local
+ n: INTEGER
+ pn,pv: STRING_8
+ i: INTEGER
+ p, q: INTEGER
+ err: BOOLEAN
+ do
+ n := s.count
+ -- Skip spaces
+ from
+ i := start_index
+ until
+ i > n or not s[i].is_space
+ loop
+ i := i + 1
+ end
+ if s[i] = ';' then
+ -- empty parameter
+ out_end_index.replace (i + 1)
+ elseif i < n then
+ p := s.index_of ('=', i)
+ if p > 0 then
+ pn := s.substring (i, p - 1)
+ if p >= n then
+ pv := ""
+ out_end_index.replace (n + 1)
+ else
+ if s[p+1] = '%"' then
+ q := s.index_of ('%"', p + 2)
+ if q > 0 then
+ pv := s.substring (p + 2, q - 1)
+ from
+ i := q + 1
+ until
+ i > n or not s[i].is_space
+ loop
+ i := i + 1
+ end
+ if s[i] = ';' then
+ i := i + 1
+ end
+ out_end_index.replace (i)
+ else
+ err := True
+ pv := ""
+ -- missing closing double quote.
+ end
+ else
+ q := s.index_of (';', p + 1)
+ if q = 0 then
+ q := n + 1
+ end
+ pv := s.substring (p + 1, q - 1)
+ out_end_index.replace (q + 1)
+ end
+ pv.right_adjust
+ if not err then
+ force (pv, pn)
+ end
+ end
+ else
+ -- expecting: attribute "=" value
+ err := True
+ end
+ end
+ if err then
+ out_end_index.replace (n + 1)
+ end
+ has_error := has_error or err
+ ensure
+ entry_processed: out_end_index.item > start_index
+ end
+
+feature {NONE} -- Duplication
+
+ empty_duplicate (n: INTEGER): like Current
+ -- Create an empty copy of Current that can accommodate `n' items
+ do
+ Result := Precursor (n)
+ end
+
+note
+ 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
+ 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/ewsgi/specification/response/wgi_filter_response.e b/library/server/ewsgi/specification/response/wgi_filter_response.e
index 7cd9226c..02485387 100644
--- a/library/server/ewsgi/specification/response/wgi_filter_response.e
+++ b/library/server/ewsgi/specification/response/wgi_filter_response.e
@@ -20,8 +20,9 @@ feature {NONE} -- Initialization
res.set_post_commit_action (agent commit)
end
- wgi_response: WGI_RESPONSE
+feature -- Access
+ wgi_response: WGI_RESPONSE
feature {WGI_FILTER_RESPONSE} -- Change
diff --git a/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e b/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e
index 9068ba46..4722591d 100644
--- a/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e
+++ b/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e
@@ -9,6 +9,9 @@ class
inherit
WGI_INPUT_STREAM
+ redefine
+ last_character_available
+ end
create
make
@@ -36,11 +39,17 @@ feature -- Input
index := index + 1
if index > chunk_upper then
read_chunk_block
- if last_chunk_data = Void then
+ if
+ last_chunk_size = 0
+ then
read_trailer_and_crlf
+ last_character := '%U'
+ else
+ last_character := last_chunk_data.item (index)
end
+ else
+ last_character := last_chunk_data.item (index)
end
- last_character := last_chunk_data.item (index)
end
read_string (nb: INTEGER)
@@ -54,7 +63,7 @@ feature -- Input
i: like index
do
last_string.wipe_out
- if last_trailer /= Void then
+ if is_trailer_reached then
-- trailer already reached, no more data
check input.end_of_input end
else
@@ -103,6 +112,12 @@ feature -- Access
last_character: CHARACTER_8
-- Last item read.
+ last_character_available: BOOLEAN
+ --
+ do
+ Result := not is_trailer_reached
+ end
+
feature -- Access: chunk
last_chunk_size: INTEGER
@@ -142,7 +157,13 @@ feature -- Status report
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
do
- Result := input.end_of_input
+ Result := input.end_of_input or is_trailer_reached
+ end
+
+ is_trailer_reached: BOOLEAN
+ -- Trailer reached?
+ do
+ Result := last_trailer /= Void
end
feature {NONE} -- Parser
@@ -320,11 +341,7 @@ feature {NONE} -- Parser
check l_input.last_character = '%N' end
end
end
- if s.is_empty then
- last_trailer := Void
- else
- last_trailer := s
- end
+ last_trailer := s
end
feature {NONE} -- Implementation
@@ -333,7 +350,7 @@ feature {NONE} -- Implementation
-- Input Stream
;note
- copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
+ copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, 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/stream/wgi_input_stream.e b/library/server/ewsgi/specification/stream/wgi_input_stream.e
index 63f1cb66..4fb778d8 100644
--- a/library/server/ewsgi/specification/stream/wgi_input_stream.e
+++ b/library/server/ewsgi/specification/stream/wgi_input_stream.e
@@ -62,14 +62,19 @@ feature -- Input
i > end_pos
loop
read_character
- a_string.put (last_character, i)
-
- if end_of_input then
- Result := i
+ if last_character_available then
+ a_string.put (last_character, i)
+ if end_of_input then
+ Result := i
+ -- Jump out of the loop.
+ i := end_pos + 1
+ else
+ i := i + 1
+ end
+ else
+ -- reached end of input
-- Jump out of the loop.
i := end_pos + 1
- else
- i := i + 1
end
end
if not end_of_input then
@@ -107,13 +112,20 @@ feature -- Input
i > end_pos
loop
read_character
- a_string.extend (last_character)
- l_count := l_count + 1
- if end_of_input then
+ if last_character_available then
+ a_string.extend (last_character)
+ l_count := l_count + 1
+
+ if end_of_input then
+ -- Jump out of the loop.
+ i := end_pos + 1
+ else
+ i := i + 1
+ end
+ else
+ -- reached end of input
-- Jump out of the loop.
i := end_pos + 1
- else
- i := i + 1
end
end
last_appended_count := l_count
@@ -194,6 +206,15 @@ feature -- Access
deferred
end
+ last_character_available: BOOLEAN
+ -- Is `last_character' available? i.e read?
+ --| with chunked encoding, we may reach the end and the `last_character'
+ --| should not be used.
+ --| to redefine in descendant if needed
+ do
+ Result := True
+ end
+
last_appended_count: INTEGER
-- Count of characters actually read by last `append_to_string' call.
diff --git a/library/server/wsf/policy_driven/wsf_method_helper.e b/library/server/wsf/policy_driven/wsf_method_helper.e
index 5a28bed9..a2f280f9 100644
--- a/library/server/wsf/policy_driven/wsf_method_helper.e
+++ b/library/server/wsf/policy_driven/wsf_method_helper.e
@@ -167,12 +167,12 @@ feature -- Content negotiation
res_attached: res /= Void
a_handler_attached: a_handler /= Void
local
- l_conneg: CONNEG_SERVER_SIDE
+ l_conneg: SERVER_CONTENT_NEGOTIATION
h: HTTP_HEADER
- l_media: MEDIA_TYPE_VARIANT_RESULTS
- l_lang: LANGUAGE_VARIANT_RESULTS
- l_charset: CHARACTER_ENCODING_VARIANT_RESULTS
- l_encoding: COMPRESSION_VARIANT_RESULTS
+ l_media: like {SERVER_CONTENT_NEGOTIATION}.media_type_preference
+ l_lang: like {SERVER_CONTENT_NEGOTIATION}.language_preference
+ l_charset: like {SERVER_CONTENT_NEGOTIATION}.charset_preference
+ l_encoding: like {SERVER_CONTENT_NEGOTIATION}.encoding_preference
l_mime_types, l_langs, l_charsets, l_encodings: LIST [STRING]
l_vary_star: BOOLEAN
do
@@ -188,7 +188,7 @@ feature -- Content negotiation
l_conneg := a_handler.conneg (req)
l_mime_types := a_handler.mime_types_supported (req)
l_media := l_conneg.media_type_preference (l_mime_types, req.http_accept)
- if not l_vary_star and l_mime_types.count > 1 and attached l_media.variant_header as l_media_variant then
+ if not l_vary_star and l_mime_types.count > 1 and attached l_media.media_type as l_media_variant then
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_media_variant)
end
if not l_media.is_acceptable then
@@ -196,26 +196,26 @@ feature -- Content negotiation
else
l_langs := a_handler.languages_supported (req)
l_lang := l_conneg.language_preference (l_langs, req.http_accept_language)
- if not l_vary_star and l_langs.count > 1 and attached l_lang.variant_header as l_lang_variant then
+ if not l_vary_star and l_langs.count > 1 and attached l_lang.language as l_lang_variant then
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_lang_variant)
end
if not l_lang.is_acceptable then
handle_not_acceptable ("None of the requested languages were acceptable", l_langs, req, res)
else
- if attached l_lang.type as l_language_type then
+ if attached l_lang.language as l_language_type then
h.put_content_language (l_language_type)
req.set_execution_variable (a_handler.Negotiated_language_execution_variable, l_language_type)
end
l_charsets := a_handler.charsets_supported (req)
l_charset := l_conneg.charset_preference (l_charsets, req.http_accept_charset)
- if not l_vary_star and l_charsets.count > 1 and attached l_charset.variant_header as l_charset_variant then
+ if not l_vary_star and l_charsets.count > 1 and attached l_charset.charset as l_charset_variant then
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_charset_variant)
end
if not l_charset.is_acceptable then
handle_not_acceptable ("None of the requested character encodings were acceptable", l_charsets, req, res)
else
- if attached l_media.type as l_media_type then
- if attached l_charset.type as l_character_type then
+ if attached l_media.media_type as l_media_type then
+ if attached l_charset.charset as l_character_type then
h.put_content_type (l_media_type + "; charset=" + l_character_type)
req.set_execution_variable (a_handler.Negotiated_charset_execution_variable, l_charset)
else
@@ -225,13 +225,13 @@ feature -- Content negotiation
end
l_encodings := a_handler.encodings_supported (req)
l_encoding := l_conneg.encoding_preference (l_encodings, req.http_accept_encoding)
- if not l_vary_star and l_encodings.count > 1 and attached l_encoding.variant_header as l_encoding_variant then
+ if not l_vary_star and l_encodings.count > 1 and attached l_encoding.encoding as l_encoding_variant then
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_encoding_variant)
end
if not l_encoding.is_acceptable then
handle_not_acceptable ("None of the requested transfer encodings were acceptable", l_encodings, req, res)
else
- if attached l_encoding.type as l_compression_type then
+ if attached l_encoding.encoding as l_compression_type then
h.put_content_encoding (l_compression_type)
req.set_execution_variable (a_handler.Negotiated_encoding_execution_variable, l_compression_type)
end
diff --git a/library/server/wsf/policy_driven/wsf_skeleton_handler.e b/library/server/wsf/policy_driven/wsf_skeleton_handler.e
index 0e22817d..48b88423 100644
--- a/library/server/wsf/policy_driven/wsf_skeleton_handler.e
+++ b/library/server/wsf/policy_driven/wsf_skeleton_handler.e
@@ -89,7 +89,7 @@ feature -- Access
deferred
end
- conneg (req: WSF_REQUEST): CONNEG_SERVER_SIDE
+ conneg (req: WSF_REQUEST): SERVER_CONTENT_NEGOTIATION
-- Content negotiation for `req';
-- This would normally be a once object, ignoring `req'.
require
@@ -103,7 +103,7 @@ feature -- Access
req_attached: req /= Void
deferred
ensure
- mime_types_supported_includes_default: Result.has (conneg (req).mime_default)
+ mime_types_supported_includes_default: Result.has (conneg (req).default_media_type)
end
languages_supported (req: WSF_REQUEST): LIST [STRING]
@@ -112,7 +112,7 @@ feature -- Access
req_attached: req /= Void
deferred
ensure
- languages_supported_includes_default: Result.has (conneg (req).language_default)
+ languages_supported_includes_default: Result.has (conneg (req).default_language)
end
charsets_supported (req: WSF_REQUEST): LIST [STRING]
@@ -121,7 +121,7 @@ feature -- Access
req_attached: req /= Void
deferred
ensure
- charsets_supported_includes_default: Result.has (conneg (req).charset_default)
+ charsets_supported_includes_default: Result.has (conneg (req).default_charset)
end
encodings_supported (req: WSF_REQUEST): LIST [STRING]
@@ -130,7 +130,7 @@ feature -- Access
req_attached: req /= Void
deferred
ensure
- encodings_supported_includes_default: Result.has (conneg (req).encoding_default)
+ encodings_supported_includes_default: Result.has (conneg (req).default_encoding)
end
additional_variant_headers (req: WSF_REQUEST): detachable LIST [STRING]
diff --git a/library/server/wsf/src/service/wsf_service.e b/library/server/wsf/src/service/wsf_service.e
index e8cb4e0b..38aef9ac 100644
--- a/library/server/wsf/src/service/wsf_service.e
+++ b/library/server/wsf/src/service/wsf_service.e
@@ -20,6 +20,14 @@ feature -- Execution
deferred
end
+feature -- Conversion
+
+ to_wgi_service: WGI_SERVICE
+ -- Adapt Current WSF Service to plug into WGI component
+ do
+ create {WSF_TO_WGI_SERVICE} Result.make_from_service (Current)
+ end
+
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e
index 299cd912..2659deeb 100644
--- a/library/server/wsf/src/wsf_request.e
+++ b/library/server/wsf/src/wsf_request.e
@@ -351,31 +351,9 @@ feature -- Helper
-- Does client accepts content_type for the response?
--| Based on header "Accept:" that can be for instance
--| text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- local
- i, j: INTEGER
do
- if attached http_accept as l_accept then
- i := l_accept.substring_index (a_content_type, 1)
- if i > 0 then
- -- contains the text, now check if this is the exact text
- if
- i = 1 -- At the beginning of text
- or else l_accept[i-1].is_space -- preceded by space
- or else l_accept[i-1] = ',' -- preceded by other mime type
- then
- j := i + a_content_type.count
- if l_accept.valid_index (j) then
- Result := l_accept[j] = ',' -- followed by other mime type
- or else l_accept[j] = ';' -- followed by quality ;q=...
- or else l_accept[j].is_space -- followed by space
- else -- end of text
- Result := True
- end
- end
- end
- Result := l_accept.has_substring (a_content_type)
- else
- Result := True
+ if attached (create {SERVER_MEDIA_TYPE_NEGOTIATION}.make (a_content_type.as_string_8)).preference (<>, http_accept) as l_variants then
+ Result := l_variants.is_acceptable
end
end
diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e
index 5ec5c0f6..dbb36855 100644
--- a/library/server/wsf/src/wsf_response.e
+++ b/library/server/wsf/src/wsf_response.e
@@ -38,12 +38,14 @@ feature {NONE} -- Initialization
create header.make
wgi_response := r
if attached {WSF_WGI_DELAYED_HEADER_RESPONSE} r as r_delayed then
- wres := r_delayed
- wres.update_wsf_response (Current)
+ r_delayed.update_wsf_response (Current)
+ wgi_response := r_delayed
+ elseif attached {WGI_FILTER_RESPONSE} r as r_filter then
+ wgi_response := r_filter.wgi_response
else
create wres.make (r, Current)
+ wgi_response := wres
end
- wgi_response := wres
set_status_code ({HTTP_STATUS_CODE}.ok) -- Default value
end
@@ -494,7 +496,7 @@ feature -- Error reporting
end
note
- copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
+ copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
diff --git a/library/server/wsf/tests/src/test_wsf_request.e b/library/server/wsf/tests/src/test_wsf_request.e
index 8d086b67..c011f03c 100644
--- a/library/server/wsf/tests/src/test_wsf_request.e
+++ b/library/server/wsf/tests/src/test_wsf_request.e
@@ -110,9 +110,9 @@ feature {NONE} -- Events
create h.make
b := base_url
if b = Void then
- b := ""
+ b := "/"
end
- if attached {HTTP_CLIENT_SESSION} h.new_session ("localhost:" + port_number.out + "/" + b) as sess then
+ if attached {HTTP_CLIENT_SESSION} h.new_session ("localhost:" + port_number.out + b) as sess then
http_session := sess
sess.set_timeout (-1)
sess.set_is_debug (True)
@@ -125,10 +125,16 @@ feature {NONE} -- Events
do
get_http_session
if attached http_session as sess then
- if attached sess.get (a_url, adapted_context (ctx)) as res and then not res.error_occurred and then attached res.body as l_body then
- assert ("Good answer got=%""+l_body+"%" expected=%""+a_expected_body+"%"", l_body.same_string (a_expected_body))
- else
- assert ("Request %""+a_url+"%" failed", False)
+ if attached sess.get (a_url, adapted_context (ctx)) as res then
+ if attached res.body as l_body then
+ if res.error_occurred then
+ assert ("Request %""+a_url+"%" failed, got=[" + l_body + "]", False)
+ else
+ assert ("Good answer got=%""+l_body+"%" expected=%""+a_expected_body+"%"", l_body.same_string (a_expected_body))
+ end
+ else
+ assert ("Request %""+a_url+"%" failed, no body, status=" + res.status.out , False)
+ end
end
end
end
diff --git a/library/server/wsf/tests/src/test_wsf_request_mime_handler.e b/library/server/wsf/tests/src/test_wsf_request_mime_handler.e
index 0827fdd7..1231b245 100644
--- a/library/server/wsf/tests/src/test_wsf_request_mime_handler.e
+++ b/library/server/wsf/tests/src/test_wsf_request_mime_handler.e
@@ -64,7 +64,7 @@ Content-Disposition: form-data; name="password"
EWFpassword
--__=_the_boundary_1332296477_1804289383_=__--
]"
-
+ b.replace_substring_all ("%N", "%R%N")
h.put_content_length (b.count)
--| Case #1
diff --git a/library/server/wsf/wsf-safe.ecf b/library/server/wsf/wsf-safe.ecf
index efeb0034..7cf1b0bf 100644
--- a/library/server/wsf/wsf-safe.ecf
+++ b/library/server/wsf/wsf-safe.ecf
@@ -15,6 +15,7 @@
+
diff --git a/library/server/wsf/wsf.ecf b/library/server/wsf/wsf.ecf
index b8088db3..5f0269d8 100644
--- a/library/server/wsf/wsf.ecf
+++ b/library/server/wsf/wsf.ecf
@@ -15,6 +15,7 @@
+