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 37e4dbdc..00000000 --- a/library/network/protocol/content_negotiation/src/conneg_server_side.e +++ /dev/null @@ -1,249 +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 - REFACTORING_HELPER - -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 - initialize - set_default_media_type (a_mediatype_dft) - set_default_language (a_language_dft) - set_default_charset (a_charset_dft) - set_default_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 - - initialize - -- Initialize Current - do - create accept_media_type_parser - create any_header_parser - create accept_language_parser - end - - accept_media_type_parser: HTTP_ACCEPT_MEDIA_TYPE_PARSER - -- MIME - - any_header_parser: HTTP_ANY_ACCEPT_HEADER_PARSER - -- Charset and Encoding - - accept_language_parser: HTTP_ACCEPT_LANGUAGE_PARSER - -- Language - -feature -- Access: Server Side Defaults Formats - - default_media_type: READABLE_STRING_8 - -- Media type which is acceptable for the response. - - default_language: READABLE_STRING_8 - -- Natural language that is preferred as a response to the request. - - default_charset: READABLE_STRING_8 - -- Character set that is acceptable for the response. - - default_encoding: READABLE_STRING_8 - -- Content-coding that is acceptable in 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 - - 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 - - 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 - - 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 -- Media Type Negotiation - - media_type_preference (a_mime_types_supported: LIST [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_parser.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 - -feature -- Encoding Negotiation - - charset_preference (a_server_charset_supported: LIST [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 := any_header_parser.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 - -feature -- Compression Negotiation - - encoding_preference (a_server_encoding_supported: LIST [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 := any_header_parser.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 - -feature -- Language Negotiation - - language_preference (a_server_language_supported: LIST [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_parser.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/parsers/http_accept_language_parser.e b/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e similarity index 85% rename from library/network/protocol/content_negotiation/src/parsers/http_accept_language_parser.e rename to library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e index 4f7b08d2..6d69f6f8 100644 --- a/library/network/protocol/content_negotiation/src/parsers/http_accept_language_parser.e +++ b/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e @@ -1,6 +1,6 @@ note description: "[ - {HTTP_ACCEPT_LANGUAGE_PARSER} is encharge to parse language tags defined as follow: + {HTTP_ACCEPT_LANGUAGE_UTILITIES} is in charge to parse language tags defined as follow: Accept-Language = "Accept-Language" ":" 1#( language-l_range [ ";" "q" "=" qvalue ] ) @@ -15,13 +15,10 @@ note EIS: "name=Accept-Language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri" class - HTTP_ACCEPT_LANGUAGE_PARSER + HTTP_ACCEPT_LANGUAGE_UTILITIES inherit - - HTTP_HEADER_PARSER - - REFACTORING_HELPER + HTTP_HEADER_UTILITIES feature -- Parser @@ -68,29 +65,22 @@ feature -- Parser Result := quality_from_list (a_language, accept_language_list (a_ranges)) end - best_match (a_supported: LIST [READABLE_STRING_8]; a_header_value: READABLE_STRING_8): READABLE_STRING_8 + 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_res: LIST [READABLE_STRING_8] - p_res: HTTP_ACCEPT_LANGUAGE 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 (a_supported.count) - from - a_supported.start - until - a_supported.after - loop - l_fitness_and_quality := fitness_and_quality_from_list (a_supported.item_for_iteration, l_header_results) - l_fitness_and_quality.set_entity (entity_value (a_supported.item_for_iteration)) + 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) - a_supported.forth end --| Keep only top quality+fitness types @@ -177,7 +167,6 @@ feature {NONE} -- Implementation l_target: HTTP_ACCEPT_LANGUAGE l_target_type: READABLE_STRING_8 l_range: HTTP_ACCEPT_LANGUAGE - l_keys: LIST [READABLE_STRING_8] l_param_matches: INTEGER l_element: detachable READABLE_STRING_8 l_fitness: INTEGER @@ -201,23 +190,21 @@ feature {NONE} -- Implementation or l_target_type.same_string ("*") ) then - from - l_param_matches := 0 - l_keys := l_target.keys - l_keys.start - until - l_keys.after - loop - l_element := l_keys.item_for_iteration - if - not l_element.same_string ("q") and then - l_range.has_key (l_element) and then - (attached l_target.item (l_element) as t_item and attached l_range.item (l_element) as r_item) and then - t_item.same_string (r_item) - then - l_param_matches := l_param_matches + 1 + 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 - l_keys.forth end if l_range_type.same_string (l_target_type) then l_fitness := 100 @@ -239,7 +226,7 @@ feature {NONE} -- Implementation l_fitness := l_fitness + l_param_matches if l_fitness > l_best_fitness then l_best_fitness := l_fitness - l_element := l_range.item ("q") + 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 diff --git a/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_parser.e b/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e similarity index 91% rename from library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_parser.e rename to library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e index b29369be..c57e060a 100644 --- a/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_parser.e +++ b/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e @@ -1,6 +1,6 @@ note description: "[ - {HTTP_ACCEPT_MEDIA_TYPE_PARSER}. 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,13 +20,10 @@ EIS: "name=Accept", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri" class - HTTP_ACCEPT_MEDIA_TYPE_PARSER + HTTP_ACCEPT_MEDIA_TYPE_UTILITIES inherit - - HTTP_HEADER_PARSER - - REFACTORING_HELPER + HTTP_HEADER_UTILITIES feature -- Parser @@ -81,7 +78,7 @@ feature -- Parser 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] @@ -105,17 +102,12 @@ feature -- Parser 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_from_list (supported.item_for_iteration, l_header_results) - fitness_and_quality.set_entity (entity_value (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 @@ -236,13 +228,9 @@ feature {NONE} -- Implementation ) 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 + 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 @@ -251,7 +239,6 @@ feature {NONE} -- Implementation then param_matches := param_matches + 1 end - l_keys.forth end end if l_range_type.same_string (l_target_type) then diff --git a/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_parser.e b/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_utilities.e similarity index 74% rename from library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_parser.e rename to library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_utilities.e index b0d4931f..4bb1038f 100644 --- a/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_parser.e +++ b/library/network/protocol/content_negotiation/src/parsers/http_any_accept_header_utilities.e @@ -9,56 +9,34 @@ note EIS: "name=Encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri" class - HTTP_ANY_ACCEPT_HEADER_PARSER + HTTP_ANY_ACCEPT_HEADER_UTILITIES inherit - HTTP_HEADER_PARSER + HTTP_HEADER_UTILITIES feature -- Parser - header (a_header: READABLE_STRING_8): HTTP_ANY_ACCEPT_HEADER + 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'}) - 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 := a_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 [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 + create Result.make_from_string (a_header) + if Result.parameter ("q") = Void then + Result.put_parameter ("1.0", "q") end - l_header := trim (l_parts [1]) - Result.set_field (trim (l_header)) end - quality (a_field: READABLE_STRING_8; a_commons: READABLE_STRING_8): REAL_64 + 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_HEADER] - p_res: HTTP_ANY_ACCEPT_HEADER + res: ARRAYED_LIST [HTTP_ANY_ACCEPT] + p_res: HTTP_ANY_ACCEPT do - l_commons := a_commons.split (',') + l_commons := a_header.split (',') from create res.make (10) l_commons.start @@ -72,17 +50,17 @@ feature -- Parser Result := quality_from_list (a_field, res) end - best_match (a_supported: LIST [READABLE_STRING_8]; a_header: READABLE_STRING_8): READABLE_STRING_8 + 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_HEADER] + 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_HEADER + 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_HEADER]} l_header_results.make (l_res.count) + create {ARRAYED_LIST [HTTP_ANY_ACCEPT]} l_header_results.make (l_res.count) from l_res.start until @@ -92,16 +70,11 @@ feature -- Parser l_header_results.force (p_res) l_res.forth end - create {ARRAYED_LIST [FITNESS_AND_QUALITY]} l_weighted_matches.make (a_supported.count) - from - a_supported.start - until - a_supported.after - loop - l_fitness_and_quality := fitness_and_quality_from_list (a_supported.item_for_iteration, l_header_results) - l_fitness_and_quality.set_entity (entity_value (a_supported.item_for_iteration)) + 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) - a_supported.forth end --| Keep only top quality+fitness types @@ -150,7 +123,7 @@ feature -- Parser until l_header_results.after or l_fitness_and_quality /= Void loop - if attached l_header_results.item.field as l_field then + if attached l_header_results.item.value as l_field then from l_weighted_matches.start until @@ -184,7 +157,7 @@ feature -- Parser feature {NONE} -- Implementation - fitness_and_quality_from_list (a_field: READABLE_STRING_8; a_parsed_charsets: LIST [HTTP_ANY_ACCEPT_HEADER]): FITNESS_AND_QUALITY + 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 @@ -194,15 +167,15 @@ feature {NONE} -- Implementation best_fitness: INTEGER target_q: REAL_64 best_fit_q: REAL_64 - target: HTTP_ANY_ACCEPT_HEADER - range: HTTP_ANY_ACCEPT_HEADER + 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.item ("q") as q and then q.is_double then + 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 @@ -212,14 +185,14 @@ feature {NONE} -- Implementation else target_q := 1.0 end - if attached target.field as l_target_field then + 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.field as l_range_common then + 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 ("*") then if l_range_common.same_string (l_target_field) then l_fitness := 100 @@ -228,7 +201,7 @@ feature {NONE} -- Implementation end if l_fitness > best_fitness then best_fitness := l_fitness - element := range.item ("q") + element := range.parameter ("q") if element /= Void then best_fit_q := element.to_double.min (target_q) else @@ -243,7 +216,7 @@ feature {NONE} -- Implementation create Result.make (best_fitness, best_fit_q) end - quality_from_list (a_field: READABLE_STRING_8; a_parsed_common: LIST [HTTP_ANY_ACCEPT_HEADER]): REAL_64 + 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 @@ -252,7 +225,6 @@ feature {NONE} -- Implementation 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)" diff --git a/library/network/protocol/content_negotiation/src/parsers/http_header_parser.e b/library/network/protocol/content_negotiation/src/parsers/http_header_utilities.e similarity index 73% rename from library/network/protocol/content_negotiation/src/parsers/http_header_parser.e rename to library/network/protocol/content_negotiation/src/parsers/http_header_utilities.e index 0d08278e..9f739088 100644 --- a/library/network/protocol/content_negotiation/src/parsers/http_header_parser.e +++ b/library/network/protocol/content_negotiation/src/parsers/http_header_utilities.e @@ -1,11 +1,14 @@ note - description: "Summary description for {HTTP_HEADER_PARSER}." + description: "Summary description for {HTTP_HEADER_UTILITIES}." author: "" date: "$Date$" revision: "$Revision$" deferred class - HTTP_HEADER_PARSER + HTTP_HEADER_UTILITIES + +inherit + REFACTORING_HELPER feature {NONE} -- Helpers @@ -16,13 +19,13 @@ feature {NONE} -- Helpers do p := a_str.index_of (';', 1) if p > 0 then - Result := trim (a_str.substring (1, p - 1)) + Result := trimmed_string (a_str.substring (1, p - 1)) else - Result := trim (a_str.string) + Result := trimmed_string (a_str.string) end end - trim (a_string: READABLE_STRING_8): STRING_8 + trimmed_string (a_string: READABLE_STRING_8): STRING_8 -- trim whitespace from the beginning and end of a string -- `a_string' require 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 index afbf8a9c..9b6b9be9 100644 --- a/library/network/protocol/content_negotiation/src/results/http_accept_language.e +++ b/library/network/protocol/content_negotiation/src/results/http_accept_language.e @@ -28,74 +28,50 @@ feature {NONE} -- Initialization -- 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. - require - a_accept_language_item_not_empty: not a_accept_language_item.is_empty local - l_parts: LIST [READABLE_STRING_8] - p: READABLE_STRING_8 i: INTEGER - l_tag: STRING_8 do fixme (generator + ".make_from_string: improve code!!!") - l_parts := a_accept_language_item.split (';') - from - l_parts.start - make_with_language (trimmed_string (l_parts.item)) - if not l_parts.after then - l_parts.forth - end - until - l_parts.after - loop - p := l_parts.item - i := p.index_of ('=', 1) - if i > 0 then - put (trimmed_string (p.substring (i + 1, p.count)), trimmed_string (p.substring (1, i - 1))) - else - check is_well_formed_parameter: False end - end - l_parts.forth + 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 item ("q") as q then + if attached parameter ("q") as q then if q.same_string ("1") then --| Use 1.0 formatting - put ("1.0", "q") + 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 ("1.0", "q") + put_parameter ("1.0", "q") quality := 1.0 end else - put ("1.0", "q") + put_parameter ("1.0", "q") end end make_with_language (a_lang_tag: READABLE_STRING_8) -- Instantiate Current from language tag `a_lang_tag'. - local - i: INTEGER do initialize - - create language_range.make_from_string (a_lang_tag) - i := a_lang_tag.index_of ('-', 1) - if i > 0 then - language := a_lang_tag.substring (1, i - 1) - specialization := a_lang_tag.substring (i + 1, a_lang_tag.count) - else - language := a_lang_tag - end + set_language_range (a_lang_tag) ensure language_range_set: language_range.same_string (a_lang_tag) and a_lang_tag /= language_range end @@ -119,7 +95,7 @@ feature {NONE} -- Initialization initialize -- Initialize Current do - create params.make (2) + create parameters.make (1) quality := 1.0 end @@ -148,37 +124,24 @@ feature -- Status report Result.append_double (quality) end -feature -- Parameters - - 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_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 @@ -199,19 +162,47 @@ feature -- Element change specialization_assigned: specialization ~ a_specialization 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' +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 params.has_key (key) then - params.replace (new, key) - else - params.force (new, key) + 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 - has_key: params.has_key (key) - has_item: params.has_item (new) + 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 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/http_any_accept_header.e b/library/network/protocol/content_negotiation/src/results/http_any_accept_header.e deleted file mode 100644 index 502ee3cc..00000000 --- a/library/network/protocol/content_negotiation/src/results/http_any_accept_header.e +++ /dev/null @@ -1,89 +0,0 @@ -note - description: "Object that represents a results after parsing Accept-* headers." - date: "$Date$" - revision: "$Revision$" - -class - HTTP_ANY_ACCEPT_HEADER - -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] - -- Table of all 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_field' - 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/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 fdfd9fdd..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: HTTP_ACCEPT_MEDIA_TYPE_PARSER - once - create Result - end - - Common: HTTP_ANY_ACCEPT_HEADER_PARSER - -- Charset and Encoding - once - create Result - end - - Language: HTTP_ACCEPT_LANGUAGE_PARSER - 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/http_accept_variants.e b/library/network/protocol/content_negotiation/src/variants/http_accept_variants.e index 86295d8b..78a39be2 100644 --- a/library/network/protocol/content_negotiation/src/variants/http_accept_variants.e +++ b/library/network/protocol/content_negotiation/src/variants/http_accept_variants.e @@ -28,7 +28,7 @@ feature -- Access -- 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 LIST [READABLE_STRING_8] + supported_variants: detachable ITERABLE [READABLE_STRING_8] -- Set of supported variants for the response variant_value: detachable READABLE_STRING_8 @@ -77,7 +77,7 @@ feature -- Change Element is_acceptable_set: is_acceptable = b end - set_supported_variants (a_supported: LIST [READABLE_STRING_8]) + set_supported_variants (a_supported: ITERABLE [READABLE_STRING_8]) -- Set `supported variants' with `a_supported' do supported_variants := a_supported diff --git a/library/network/protocol/content_negotiation/test/application.e b/library/network/protocol/content_negotiation/test/application.e index b7152129..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 : HTTP_ACCEPT_MEDIA_TYPE_PARSER + mime_parse : HTTP_ACCEPT_MEDIA_TYPE_UTILITIES accept : STRING - charset_parse : HTTP_ANY_ACCEPT_HEADER_PARSER - language : HTTP_ACCEPT_LANGUAGE_PARSER + 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") 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 3c3dcbf6..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,26 +23,24 @@ feature {NONE} -- Events feature -- Helpers - format (a_common: HTTP_ANY_ACCEPT_HEADER): 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 @@ -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 : HTTP_ANY_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 d0c1e518..5ba5930d 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 @@ -34,8 +34,8 @@ feature -- Test routines media_variants := conneg.media_type_preference (mime_types_supported, "text/html") assert ("Expected Not Acceptable", not media_variants.is_acceptable) if attached media_variants.supported_variants as l_supported_variants then - assert ("Same Value at 1",mime_types_supported.first.same_string (l_supported_variants.first)) - assert ("Same count",mime_types_supported.count = l_supported_variants.count) + 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 @@ -72,8 +72,8 @@ feature -- Test routines charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1") assert ("Expected Not Acceptable", not charset_variants.is_acceptable) if attached charset_variants.supported_variants as l_supported_variants then - assert ("Same Value at 1",charset_supported.first.same_string (l_supported_variants.first)) - assert ("Same count",charset_supported.count = l_supported_variants.count) + 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 @@ -109,8 +109,8 @@ feature -- Test routines compression_variants := conneg.encoding_preference (compression_supported, "gzip") assert ("Expected Not Acceptable", not compression_variants.is_acceptable) if attached compression_variants.supported_variants as l_supported_variants then - assert ("Same Value at 1",compression_supported.first.same_string (l_supported_variants.first)) - assert ("Same count",compression_supported.count = l_supported_variants.count) + 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 @@ -153,8 +153,8 @@ feature -- Test routines 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", languages_supported.first.same_string (l_supported_variants.first)) - assert ("Same count",languages_supported.count = l_supported_variants.count) + 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 @@ -175,5 +175,36 @@ feature -- Test routines 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/exception_trace.log b/library/network/protocol/content_negotiation/test/exception_trace.log index 3d5d5442..e268a695 100644 --- a/library/network/protocol/content_negotiation/test/exception_trace.log +++ b/library/network/protocol/content_negotiation/test/exception_trace.log @@ -3,3 +3,16 @@ Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected REA Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void +Catcall detected in {READABLE_STRING_8}.make_from_string for arg#1: expected READABLE_STRING_8 but got Void 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 42acbbb8..fe937a20 100644 --- a/library/network/protocol/content_negotiation/test/language_parser_test.e +++ b/library/network/protocol/content_negotiation/test/language_parser_test.e @@ -34,14 +34,11 @@ feature -- Helpers 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 ("})") @@ -137,7 +134,7 @@ feature -- Test routines - parser : HTTP_ACCEPT_LANGUAGE_PARSER + 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 0dbe8034..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 ("})") @@ -148,7 +145,7 @@ feature -- Test routines - parser : HTTP_ACCEPT_MEDIA_TYPE_PARSER + parser : HTTP_ACCEPT_MEDIA_TYPE_UTILITIES end 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/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 e2c92fb2..447e78bc 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]