Merge branch 'master' of https://github.com/EiffelWebFramework/EWF
This commit is contained in:
@@ -1,125 +1,31 @@
|
|||||||
CONNEG is a library that provides utilities to select the best repesentation of a resource for a client
|
CONNEG is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
|
||||||
where there are multiple representations available.
|
|
||||||
|
|
||||||
Using this labrary you can retrieve the best Variant for media type, language preference, enconding and compression.
|
Using this library you can retrieve the best variant for media type, language preference, charset, and enconding/compression.
|
||||||
The library is based on eMIME Eiffel MIME library based on Joe Gregorio code
|
|
||||||
|
|
||||||
Take into account that the library is under development so is expected that the API change.
|
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
|
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
|
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).
|
charset and compression).
|
||||||
So for each of the following questions, you will have a corresponding method to help in the solution.
|
So for each of the following questions, you will have a corresponding method to help in the solution.
|
||||||
|
|
||||||
- How to implement Media type negotiation?
|
- 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?
|
- 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?
|
- How to implement Character Negotiation?
|
||||||
Hint: Use CONNEG_SERVER_SIDE.charset_preference
|
Hint: Use SERVER_CONTENT_NEGOTIATION.charset_preference
|
||||||
|
or SERVER_CHARSET_NEGOTIATION.preference
|
||||||
|
|
||||||
- How to implement Compression Negotiation?
|
- How to implement Encoding Negotiation?
|
||||||
Hint: Use CONNEG_SERVER_SIDE.encoding_preference
|
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.
|
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
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="http" location="..\http\http-safe.ecf" readonly="false"/>
|
<library name="http" location="..\http\http-safe.ecf" readonly="false"/>
|
||||||
<cluster name="conneg" location=".\src\" recursive="true"/>
|
<cluster name="conneg" location=".\src\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/implementation</exclude>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="conneg_imp" location=".\src\implementation" recursive="true" hidden="true">
|
||||||
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
</system>
|
</system>
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
<library name="http" location="../http/http.ecf"/>
|
<library name="http" location="../http/http.ecf"/>
|
||||||
<cluster name="conneg" location=".\src" recursive="true"/>
|
<cluster name="conneg" location=".\src\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/implementation</exclude>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="conneg_imp" location=".\src\implementation" recursive="true" hidden="true">
|
||||||
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
</system>
|
</system>
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
note
|
note
|
||||||
description: "Summary description for {FITNESS_AND_QUALITY}."
|
description: "Summary description for {FITNESS_AND_QUALITY}."
|
||||||
author: ""
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ feature -- Initialization
|
|||||||
do
|
do
|
||||||
fitness := a_fitness
|
fitness := a_fitness
|
||||||
quality := a_quality
|
quality := a_quality
|
||||||
create mime_type.make_empty
|
create {STRING_8} entity.make_empty
|
||||||
ensure
|
ensure
|
||||||
fitness_assigned : fitness = a_fitness
|
fitness_assigned : fitness = a_fitness
|
||||||
quality_assigned : quality = a_quality
|
quality_assigned : quality = a_quality
|
||||||
@@ -36,17 +35,17 @@ feature -- Access
|
|||||||
|
|
||||||
quality: REAL_64
|
quality: REAL_64
|
||||||
|
|
||||||
mime_type: STRING
|
entity: READABLE_STRING_8
|
||||||
-- optionally used
|
-- optionally used
|
||||||
-- empty by default
|
-- empty by default
|
||||||
|
--| Could be a mime type, an encoding, ...
|
||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
debug_output: STRING
|
debug_output: STRING
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
do
|
do
|
||||||
create Result.make_from_string (mime_type)
|
create Result.make_from_string (entity)
|
||||||
Result.append (" (")
|
Result.append (" (")
|
||||||
Result.append ("quality=" + quality.out)
|
Result.append ("quality=" + quality.out)
|
||||||
Result.append (" ; fitness=" + fitness.out)
|
Result.append (" ; fitness=" + fitness.out)
|
||||||
@@ -55,12 +54,12 @@ feature -- Status report
|
|||||||
|
|
||||||
feature -- Element Change
|
feature -- Element Change
|
||||||
|
|
||||||
set_mime_type (a_mime_type: STRING)
|
set_entity (a_entity: READABLE_STRING_8)
|
||||||
-- set mime_type with `a_mime_type'
|
-- set `entity' with `a_entity'
|
||||||
do
|
do
|
||||||
mime_type := a_mime_type
|
entity := a_entity
|
||||||
ensure
|
ensure
|
||||||
mime_type_assigned : mime_type.same_string (a_mime_type)
|
entity_assigned : entity.same_string (a_entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Comparision
|
feature -- Comparision
|
||||||
@@ -75,7 +74,7 @@ feature -- Comparision
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
note
|
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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
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" ":"
|
Accept = "Accept" ":"
|
||||||
#( media-range [ accept-params ] )
|
#( 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"
|
EIS: "name=Accept", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
|
||||||
|
|
||||||
class
|
class
|
||||||
MIME_PARSE
|
HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
|
||||||
|
|
||||||
inherit {NONE}
|
inherit
|
||||||
|
HTTP_HEADER_UTILITIES
|
||||||
MIME_TYPE_PARSER_UTILITIES
|
|
||||||
|
|
||||||
REFACTORING_HELPER
|
|
||||||
|
|
||||||
feature -- Parser
|
feature -- Parser
|
||||||
|
|
||||||
parse_mime_type (a_mime_type: READABLE_STRING_8): HTTP_MEDIA_TYPE
|
media_type (a_range: 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-ranges are mime-types with wild-cards and a 'q' quality parameter.
|
-- 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:
|
-- For example, the media range 'application/*;q=0.5' would get parsed into:
|
||||||
-- ('application', '*', {'q', '0.5'})
|
-- ('application', '*', {'q', '0.5'})
|
||||||
@@ -48,11 +36,11 @@ feature -- Parser
|
|||||||
-- necessary.
|
-- necessary.
|
||||||
do
|
do
|
||||||
fixme ("Improve the code!!!")
|
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 attached Result.parameter ("q") as q then
|
||||||
if
|
if
|
||||||
q.is_double and then
|
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)
|
(r >= 0.0 and r <= 1.0)
|
||||||
then
|
then
|
||||||
--| Keep current value
|
--| Keep current value
|
||||||
@@ -68,111 +56,6 @@ feature -- Parser
|
|||||||
end
|
end
|
||||||
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
|
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
|
-- Returns the quality 'q' of a mime-type when compared against the
|
||||||
-- mediaRanges in ranges.
|
-- mediaRanges in ranges.
|
||||||
@@ -188,14 +71,14 @@ feature -- Parser
|
|||||||
until
|
until
|
||||||
l_ranges.after
|
l_ranges.after
|
||||||
loop
|
loop
|
||||||
p_res := parse_media_range (l_ranges.item_for_iteration)
|
p_res := media_type (l_ranges.item_for_iteration)
|
||||||
res.put_left (p_res)
|
res.force (p_res)
|
||||||
l_ranges.forth
|
l_ranges.forth
|
||||||
end
|
end
|
||||||
Result := quality_parsed (a_mime_type, res)
|
Result := quality_from_list (a_mime_type, res)
|
||||||
end
|
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.
|
-- Choose the mime-type with the highest fitness score and quality ('q') from a list of candidates.
|
||||||
local
|
local
|
||||||
l_header_results: LIST [HTTP_MEDIA_TYPE]
|
l_header_results: LIST [HTTP_MEDIA_TYPE]
|
||||||
@@ -214,22 +97,17 @@ feature -- Parser
|
|||||||
until
|
until
|
||||||
l_res.after
|
l_res.after
|
||||||
loop
|
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_header_results.force (p_res)
|
||||||
l_res.forth
|
l_res.forth
|
||||||
end
|
end
|
||||||
|
|
||||||
create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (supported.count)
|
create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (0)
|
||||||
|
|
||||||
from
|
across supported as ic loop
|
||||||
supported.start
|
fitness_and_quality := fitness_and_quality_from_list (ic.item, l_header_results)
|
||||||
until
|
fitness_and_quality.set_entity (entity_value (ic.item))
|
||||||
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)
|
weighted_matches.force (fitness_and_quality)
|
||||||
supported.forth
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--| Keep only top quality+fitness types
|
--| Keep only top quality+fitness types
|
||||||
@@ -265,7 +143,7 @@ feature -- Parser
|
|||||||
end
|
end
|
||||||
if first_one /= Void and then first_one.quality /= 0.0 then
|
if first_one /= Void and then first_one.quality /= 0.0 then
|
||||||
if weighted_matches.count = 1 then
|
if weighted_matches.count = 1 then
|
||||||
Result := first_one.mime_type
|
Result := first_one.entity
|
||||||
else
|
else
|
||||||
from
|
from
|
||||||
fitness_and_quality := Void
|
fitness_and_quality := Void
|
||||||
@@ -280,7 +158,7 @@ feature -- Parser
|
|||||||
weighted_matches.after or fitness_and_quality /= Void
|
weighted_matches.after or fitness_and_quality /= Void
|
||||||
loop
|
loop
|
||||||
fitness_and_quality := weighted_matches.item
|
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
|
--| Found
|
||||||
else
|
else
|
||||||
fitness_and_quality := Void
|
fitness_and_quality := Void
|
||||||
@@ -290,9 +168,9 @@ feature -- Parser
|
|||||||
l_header_results.forth
|
l_header_results.forth
|
||||||
end
|
end
|
||||||
if fitness_and_quality /= Void then
|
if fitness_and_quality /= Void then
|
||||||
Result := fitness_and_quality.mime_type
|
Result := fitness_and_quality.entity
|
||||||
else
|
else
|
||||||
Result := first_one.mime_type
|
Result := first_one.entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -300,6 +178,108 @@ feature -- Parser
|
|||||||
end
|
end
|
||||||
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
|
note
|
||||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software 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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
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.
|
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
|
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.
|
a response with the list of supported character sets.
|
||||||
@@ -10,20 +10,22 @@ note
|
|||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
class
|
class
|
||||||
CHARACTER_ENCODING_VARIANT_RESULTS
|
HTTP_ACCEPT_CHARSET_VARIANTS
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
HTTP_ACCEPT_VARIANTS
|
||||||
|
rename
|
||||||
|
variant_value as charset
|
||||||
|
end
|
||||||
|
|
||||||
VARIANT_RESULTS
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Change
|
||||||
|
|
||||||
feature -- Change Element
|
set_vary_header_value
|
||||||
|
|
||||||
|
|
||||||
set_variant_header
|
|
||||||
-- Set variant header as `Accept-Charset'
|
|
||||||
do
|
do
|
||||||
variant_header := {HTTP_HEADER_NAMES}.header_accept_charset -- "Accept-Charset"
|
vary_header_value := {HTTP_HEADER_NAMES}.header_accept_charset -- "Accept-Charset"
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
@@ -1,28 +1,31 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
{COMPRESSION_VARIANT_RESULTS}
|
{HTTP_ACCEPT_ENCODING_VARIANTS}
|
||||||
Represent the compression results between client preferences and ccompression variants supported by the server.
|
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
|
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$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
EIS: "name= Compression", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
|
EIS: "name= Compression", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
|
||||||
|
|
||||||
class
|
class
|
||||||
COMPRESSION_VARIANT_RESULTS
|
HTTP_ACCEPT_ENCODING_VARIANTS
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
HTTP_ACCEPT_VARIANTS
|
||||||
|
rename
|
||||||
|
variant_value as encoding
|
||||||
|
end
|
||||||
|
|
||||||
VARIANT_RESULTS
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Change
|
||||||
|
|
||||||
feature -- Change Element
|
set_vary_header_value
|
||||||
|
|
||||||
set_variant_header
|
|
||||||
-- Set variant_header as `Accept-Encoding'
|
|
||||||
do
|
do
|
||||||
variant_header := {HTTP_HEADER_NAMES}.header_accept_encoding -- "Accept-Encoding"
|
vary_header_value := {HTTP_HEADER_NAMES}.header_accept_encoding -- "Accept-Encoding"
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
{LANGUAGE_VARIANT_RESULTS}.
|
{HTTP_ACCEPT_LANGUAGE_VARIANTS}.
|
||||||
Represent the language results between client preferences and language variants supported by the server.
|
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
|
If the server is unable to supports the requested Accept-Language values, the server can build
|
||||||
a response with the list of supported languages
|
a response with the list of supported languages
|
||||||
@@ -9,18 +9,22 @@ note
|
|||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
class
|
class
|
||||||
LANGUAGE_VARIANT_RESULTS
|
HTTP_ACCEPT_LANGUAGE_VARIANTS
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
HTTP_ACCEPT_VARIANTS
|
||||||
|
rename
|
||||||
|
variant_value as language
|
||||||
|
end
|
||||||
|
|
||||||
VARIANT_RESULTS
|
create
|
||||||
|
make
|
||||||
|
|
||||||
feature -- Change Element
|
feature -- Change
|
||||||
|
|
||||||
set_variant_header
|
set_vary_header_value
|
||||||
-- Set variant header as 'Accept-Language'
|
|
||||||
do
|
do
|
||||||
variant_header := {HTTP_HEADER_NAMES}.header_accept_language -- "Accept-Language"
|
vary_header_value := {HTTP_HEADER_NAMES}.header_accept_language -- "Accept-Language"
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
{MEDIA_TYPE_VARIANT_RESULTS}.
|
{HTTP_ACCEPT_MEDIA_TYPE_VARIANTS}.
|
||||||
Represent the media type results between client preferences and media type variants supported by the server..
|
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
|
If the server is unable to supports the requested Accept values, the server can build
|
||||||
a response with the list of supported representations
|
a response with the list of supported representations
|
||||||
]"
|
]"
|
||||||
@@ -9,18 +9,22 @@ note
|
|||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
class
|
class
|
||||||
MEDIA_TYPE_VARIANT_RESULTS
|
HTTP_ACCEPT_MEDIA_TYPE_VARIANTS
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
HTTP_ACCEPT_VARIANTS
|
||||||
|
rename
|
||||||
|
variant_value as media_type
|
||||||
|
end
|
||||||
|
|
||||||
VARIANT_RESULTS
|
create
|
||||||
|
make
|
||||||
|
|
||||||
feature -- Change Element
|
feature -- Change
|
||||||
|
|
||||||
set_variant_header
|
set_vary_header_value
|
||||||
-- Set variant header as `Accept'
|
|
||||||
do
|
do
|
||||||
variant_header := {HTTP_HEADER_NAMES}.header_accept -- "Accept"
|
vary_header_value := {HTTP_HEADER_NAMES}.header_accept -- "Accept"
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -16,10 +16,10 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
make
|
make
|
||||||
local
|
local
|
||||||
mime_parse : MIME_PARSE
|
mime_parse : HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
|
||||||
accept : STRING
|
accept : STRING
|
||||||
charset_parse : COMMON_ACCEPT_HEADER_PARSER
|
charset_parse : HTTP_ANY_ACCEPT_HEADER_UTILITIES
|
||||||
language : LANGUAGE_PARSE
|
language : HTTP_ACCEPT_LANGUAGE_UTILITIES
|
||||||
do
|
do
|
||||||
create mime_parse
|
create mime_parse
|
||||||
-- parse_result := mime_parse.parse_mime_type ("application/xhtml;q=0.5")
|
-- 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)
|
print ("%N"+mime_parse.quality ("*/*;q=0.1", accept).out)
|
||||||
|
|
||||||
accept := "application/atom+xml"
|
accept := "application/atom+xml"
|
||||||
print ("%N"+mime_parse.parse_mime_type (accept).out)
|
print ("%N"+mime_parse.media_type (accept).out)
|
||||||
create charset_parse
|
create charset_parse
|
||||||
accept := "iso-8859-5"
|
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"
|
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"
|
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 (','), "da"))
|
||||||
print (language.best_match (accept.split (','), "en-*"))
|
print (language.best_match (accept.split (','), "en-*"))
|
||||||
|
|
||||||
print ("%N"+language.parse_language_range ("da").out)
|
print ("%N"+language.accept_language ("da").out)
|
||||||
print ("%N"+language.parse_language_range ("en-gb;q=0.8").out)
|
print ("%N"+language.accept_language ("en-gb;q=0.8").out)
|
||||||
print ("%N"+language.parse_language_range ("en;q=0.7").out)
|
print ("%N"+language.accept_language ("en;q=0.7").out)
|
||||||
print ("%N"+language.parse_language_range ("en-*").out)
|
print ("%N"+language.accept_language ("en-*").out)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,33 +23,31 @@ feature {NONE} -- Events
|
|||||||
|
|
||||||
feature -- Helpers
|
feature -- Helpers
|
||||||
|
|
||||||
format (a_common: COMMON_RESULTS): STRING
|
format (a_common: HTTP_ANY_ACCEPT): STRING
|
||||||
-- Representation of the current object
|
-- Representation of the current object
|
||||||
do
|
do
|
||||||
create Result.make_from_string ("(")
|
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 + "',")
|
Result.append_string ("'" + t + "',")
|
||||||
end
|
end
|
||||||
Result.append_string (" {")
|
Result.append_string (" {")
|
||||||
from
|
if attached a_common.parameters as l_parameters then
|
||||||
a_common.params.start
|
across
|
||||||
until
|
l_parameters as ic
|
||||||
a_common.params.after
|
loop
|
||||||
loop
|
Result.append ("'" + ic.key + "':'" + ic.item + "',");
|
||||||
Result.append ("'" + a_common.params.key_for_iteration + "':'" + a_common.params.item_for_iteration + "',");
|
end
|
||||||
a_common.params.forth
|
|
||||||
end
|
end
|
||||||
Result.append ("})")
|
Result.append ("})")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
feature -- Test routines
|
feature -- Test routines
|
||||||
|
|
||||||
test_parse_charsets
|
test_parse_charsets
|
||||||
do
|
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 ('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.parse_common("unicode-1-1;q=0.8")).same_string("('unicode-1-1', {'q':'0.8',})") )
|
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.parse_common("*")).same_string("('*', {'q':'1.0',})") )
|
assert ("Expected ('*', {'q':'1.0',})", format (parser.header("*")).same_string("('*', {'q':'1.0',})") )
|
||||||
end
|
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"))
|
assert ("Expected unicode-1-1", parser.best_match (charset_supported, "unicode-1-1;q=1").same_string ("unicode-1-1"))
|
||||||
end
|
end
|
||||||
|
|
||||||
parser : COMMON_ACCEPT_HEADER_PARSER
|
parser : HTTP_ANY_ACCEPT_HEADER_UTILITIES
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ feature {NONE} -- Events
|
|||||||
feature -- Test routines
|
feature -- Test routines
|
||||||
test_media_type_negotiation
|
test_media_type_negotiation
|
||||||
local
|
local
|
||||||
media_variants : MEDIA_TYPE_VARIANT_RESULTS
|
media_variants : HTTP_ACCEPT_MEDIA_TYPE_VARIANTS
|
||||||
mime_types_supported : LIST [STRING]
|
mime_types_supported : LIST [STRING]
|
||||||
l_types : STRING
|
l_types : STRING
|
||||||
do
|
do
|
||||||
@@ -33,24 +33,28 @@ feature -- Test routines
|
|||||||
mime_types_supported := l_types.split(',')
|
mime_types_supported := l_types.split(',')
|
||||||
media_variants := conneg.media_type_preference (mime_types_supported, "text/html")
|
media_variants := conneg.media_type_preference (mime_types_supported, "text/html")
|
||||||
assert ("Expected Not Acceptable", not media_variants.is_acceptable)
|
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)))
|
if attached media_variants.supported_variants as l_supported_variants then
|
||||||
assert ("Same count",mime_types_supported.count = media_variants.supported_variants.count)
|
assert ("Same Value at 1", same_text (first_of (mime_types_supported), first_of (l_supported_variants)))
|
||||||
assert ("Variant header is void",media_variants.variant_header = Void)
|
assert ("Same count", count_of (mime_types_supported) = count_of (l_supported_variants))
|
||||||
assert ("Media type is void",media_variants.type = Void)
|
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:
|
-- Scenario 2, the client doesnt send values in the header, Accept:
|
||||||
media_variants := conneg.media_type_preference (mime_types_supported, "")
|
media_variants := conneg.media_type_preference (mime_types_supported, "")
|
||||||
assert ("Expected Acceptable", media_variants.is_acceptable)
|
assert ("Expected Acceptable", media_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",media_variants.supported_variants = Void)
|
assert ("Variants is set",media_variants.supported_variants = mime_types_supported)
|
||||||
assert ("Mime is defaul", conneg.mime_default.is_equal (media_variants.type))
|
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.variant_header = Void)
|
assert ("Variant header", media_variants.vary_header_value = Void)
|
||||||
|
|
||||||
--Scenario 3, the server select the best match, and set the vary header
|
--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 ("Expected Acceptable", media_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",media_variants.supported_variants = Void)
|
assert ("Variants is set",media_variants.supported_variants = mime_types_supported)
|
||||||
assert ("Variant Header", media_variants.variant_header.is_equal ("Accept"))
|
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", media_variants.type.is_equal ("application/json"))
|
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
|
end
|
||||||
|
|
||||||
@@ -58,40 +62,44 @@ feature -- Test routines
|
|||||||
|
|
||||||
test_charset_negotiation
|
test_charset_negotiation
|
||||||
local
|
local
|
||||||
charset_variants : CHARACTER_ENCODING_VARIANT_RESULTS
|
charset_variants : HTTP_ACCEPT_CHARSET_VARIANTS
|
||||||
charset_supported : LIST [STRING]
|
charset_supported : LIST [STRING]
|
||||||
l_charset : STRING
|
l_charset_value : STRING
|
||||||
do
|
do
|
||||||
-- Scenario 1, the server side does not support client preferences
|
-- Scenario 1, the server side does not support client preferences
|
||||||
l_charset := "UTF-8, iso-8859-5"
|
l_charset_value := "UTF-8, iso-8859-5"
|
||||||
charset_supported := l_charset.split(',')
|
charset_supported := l_charset_value.split(',')
|
||||||
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1")
|
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1")
|
||||||
assert ("Expected Not Acceptable", not charset_variants.is_acceptable)
|
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)))
|
if attached charset_variants.supported_variants as l_supported_variants then
|
||||||
assert ("Same count",charset_supported.count = charset_variants.supported_variants.count)
|
assert ("Same Value at 1", same_text (first_of (charset_supported), first_of (l_supported_variants)))
|
||||||
assert ("Variant header is void",charset_variants.variant_header = Void)
|
assert ("Same count",charset_supported.count = count_of (l_supported_variants))
|
||||||
assert ("Character type is void",charset_variants.type = Void)
|
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:
|
-- Scenario 2, the client doesnt send values in the header, Accept-Charset:
|
||||||
charset_variants := conneg.charset_preference (charset_supported, "")
|
charset_variants := conneg.charset_preference (charset_supported, "")
|
||||||
assert ("Expected Acceptable", charset_variants.is_acceptable)
|
assert ("Expected Acceptable", charset_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",charset_variants.supported_variants = Void)
|
assert ("Variants is set",charset_variants.supported_variants = charset_supported)
|
||||||
assert ("Charset is defaul", conneg.charset_default.is_equal (charset_variants.type))
|
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.variant_header = Void)
|
assert ("Variant header", charset_variants.vary_header_value = Void)
|
||||||
|
|
||||||
|
|
||||||
--Scenario 3, the server select the best match, and set the vary header
|
--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")
|
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 ("Expected Acceptable", charset_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",charset_variants.supported_variants = Void)
|
assert ("Variants is set",charset_variants.supported_variants = charset_supported)
|
||||||
assert ("Variant Header", charset_variants.variant_header.is_equal ("Accept-Charset"))
|
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", charset_variants.type.is_equal ("iso-8859-5"))
|
assert ("Character Type is iso-8859-5", attached charset_variants.charset as l_charset and then l_charset.same_string ("iso-8859-5"))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_compression_negotiation
|
test_compression_negotiation
|
||||||
local
|
local
|
||||||
compression_variants : COMPRESSION_VARIANT_RESULTS
|
compression_variants : HTTP_ACCEPT_ENCODING_VARIANTS
|
||||||
compression_supported : LIST [STRING]
|
compression_supported : LIST [STRING]
|
||||||
l_compression : STRING
|
l_compression : STRING
|
||||||
do
|
do
|
||||||
@@ -100,91 +108,90 @@ feature -- Test routines
|
|||||||
compression_supported := l_compression.split(',')
|
compression_supported := l_compression.split(',')
|
||||||
compression_variants := conneg.encoding_preference (compression_supported, "gzip")
|
compression_variants := conneg.encoding_preference (compression_supported, "gzip")
|
||||||
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
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)))
|
if attached compression_variants.supported_variants as l_supported_variants then
|
||||||
assert ("Same count",compression_supported.count = compression_variants.supported_variants.count)
|
assert ("Same Value at 1", same_text (first_of (compression_supported), first_of (l_supported_variants)))
|
||||||
assert ("Variant header is void",compression_variants.variant_header = Void)
|
assert ("Same count",compression_supported.count = count_of (l_supported_variants))
|
||||||
assert ("Compression type is void",compression_variants.type = Void)
|
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
|
-- Scenario 2, the client doesnt send values in the header, Accept-Encoding
|
||||||
compression_variants := conneg.encoding_preference (compression_supported, "")
|
compression_variants := conneg.encoding_preference (compression_supported, "")
|
||||||
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",compression_variants.supported_variants = Void)
|
assert ("Variants is set",compression_variants.supported_variants = compression_supported)
|
||||||
assert ("Compression is defaul", conneg.encoding_default.is_equal (compression_variants.type))
|
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.variant_header = Void)
|
assert ("Variant header", compression_variants.vary_header_value = Void)
|
||||||
|
|
||||||
|
|
||||||
--Scenario 3, the server select the best match, and set the vary header
|
--Scenario 3, the server select the best match, and set the vary header
|
||||||
l_compression := "gzip"
|
l_compression := "gzip"
|
||||||
compression_supported := l_compression.split(',')
|
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")
|
compression_variants := conneg.encoding_preference (compression_supported, "compress,gzip;q=0.7")
|
||||||
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",compression_variants.supported_variants = Void)
|
assert ("Variants is set",compression_variants.supported_variants = compression_supported)
|
||||||
assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
|
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", compression_variants.type.is_equal ("gzip"))
|
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
|
-- Scenario 4, the server set `identity' and the client doesn't mention identity
|
||||||
l_compression := "identity"
|
l_compression := "identity"
|
||||||
compression_supported := l_compression.split(',')
|
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")
|
compression_variants := conneg.encoding_preference (compression_supported, "gzip;q=0.7")
|
||||||
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",compression_variants.supported_variants = Void)
|
assert ("Variants is set",compression_variants.supported_variants = compression_supported)
|
||||||
assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
|
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", compression_variants.type.is_equal ("identity"))
|
assert ("Encoding Type is Void", compression_variants.encoding = Void)
|
||||||
|
|
||||||
-- Scenario 5, the server set `identity' and the client mention identity,q=0
|
-- Scenario 5, the server set `identity' and the client mention identity,q=0
|
||||||
l_compression := "identity"
|
l_compression := "identity"
|
||||||
compression_supported := l_compression.split(',')
|
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")
|
compression_variants := conneg.encoding_preference (compression_supported, "identity;q=0")
|
||||||
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
||||||
assert ("Variants is attached",attached compression_variants.supported_variants )
|
assert ("Variants is attached",attached compression_variants.supported_variants )
|
||||||
assert ("Variant Header is void", compression_variants.variant_header = 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.type = Void)
|
assert ("Encoding Type is Void", compression_variants.encoding = Void)
|
||||||
|
|
||||||
-- Scenario 6, the server set `identity' and the client mention *,q=0
|
-- Scenario 6, the server set `identity' and the client mention *,q=0
|
||||||
l_compression := "identity"
|
l_compression := "identity"
|
||||||
compression_supported := l_compression.split(',')
|
compression_supported := l_compression.split(',')
|
||||||
conneg.set_encoding_default("gzip")
|
conneg.set_default_encoding ("gzip")
|
||||||
compression_variants := conneg.encoding_preference (compression_supported, "*;q=0")
|
compression_variants := conneg.encoding_preference (compression_supported, "*;q=0")
|
||||||
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
||||||
assert ("Variants is attached",attached compression_variants.supported_variants )
|
assert ("Variants is attached",attached compression_variants.supported_variants )
|
||||||
assert ("Variant Header is void", compression_variants.variant_header = 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.type = Void)
|
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
|
-- Scenario 7, the server set `identity' and the client mention identity;q=0.5, gzip;q=0.7,compress
|
||||||
l_compression := "identity"
|
l_compression := "identity"
|
||||||
compression_supported := l_compression.split(',')
|
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")
|
compression_variants := conneg.encoding_preference (compression_supported, "identity;q=0.5, gzip;q=0.7,compress")
|
||||||
assert ("Expected Acceptable",compression_variants.is_acceptable)
|
assert ("Expected Acceptable",compression_variants.is_acceptable)
|
||||||
assert ("Variants is void",compression_variants.supported_variants = Void)
|
assert ("Variants is set",compression_variants.supported_variants = compression_supported)
|
||||||
assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
|
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", compression_variants.type.is_equal ("identity"))
|
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
|
-- Scenario 8, the server set `identity' and the client mention identity;q=0.5
|
||||||
l_compression := "identity"
|
l_compression := "identity"
|
||||||
compression_supported := l_compression.split(',')
|
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")
|
compression_variants := conneg.encoding_preference (compression_supported, "identity;q=0.5")
|
||||||
assert ("Expected Acceptable",compression_variants.is_acceptable)
|
assert ("Expected Acceptable",compression_variants.is_acceptable)
|
||||||
assert ("Variants is void",compression_variants.supported_variants = Void)
|
assert ("Variants is set",compression_variants.supported_variants = compression_supported)
|
||||||
assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
|
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", compression_variants.type.is_equal ("identity"))
|
assert ("Encoding Type is identity", attached compression_variants.encoding as l_type and then l_type.same_string ("identity"))
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test_language_negotiation
|
test_language_negotiation
|
||||||
local
|
local
|
||||||
language_variants : LANGUAGE_VARIANT_RESULTS
|
language_variants : HTTP_ACCEPT_LANGUAGE_VARIANTS
|
||||||
languages_supported : LIST [STRING]
|
languages_supported : LIST [STRING]
|
||||||
l_languages : STRING
|
l_languages : STRING
|
||||||
do
|
do
|
||||||
@@ -193,30 +200,61 @@ feature -- Test routines
|
|||||||
languages_supported := l_languages.split(',')
|
languages_supported := l_languages.split(',')
|
||||||
language_variants := conneg.language_preference (languages_supported, "de")
|
language_variants := conneg.language_preference (languages_supported, "de")
|
||||||
assert ("Expected Not Acceptable", not language_variants.is_acceptable)
|
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 ("Variant Header", attached language_variants.vary_header_value as l_variant_header and then l_variant_header.same_string ("Accept-Language"))
|
||||||
assert ("Same count",languages_supported.count = language_variants.supported_variants.count)
|
assert ("Language type is Void",language_variants.language = Void)
|
||||||
assert ("Variant header is void",language_variants.variant_header = Void)
|
if attached language_variants.supported_variants as l_supported_variants then
|
||||||
assert ("Language type is void",language_variants.type = Void)
|
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:
|
-- Scenario 2, the client doesnt send values in the header, Accept-Language:
|
||||||
language_variants := conneg.language_preference (languages_supported, "")
|
language_variants := conneg.language_preference (languages_supported, "")
|
||||||
assert ("Expected Acceptable", language_variants.is_acceptable)
|
assert ("Expected Acceptable", language_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",language_variants.supported_variants = Void)
|
assert ("Variants is attached",language_variants.supported_variants = languages_supported)
|
||||||
assert ("Language is defaul", conneg.language_default.is_equal (language_variants.type))
|
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.variant_header = Void)
|
assert ("Variant header", language_variants.vary_header_value = Void)
|
||||||
|
|
||||||
|
|
||||||
--Scenario 3, the server select the best match, and set the vary header
|
--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")
|
language_variants := conneg.language_preference (languages_supported, "fr,es;q=0.4")
|
||||||
assert ("Expected Acceptable", language_variants.is_acceptable)
|
assert ("Expected Acceptable", language_variants.is_acceptable)
|
||||||
assert ("Variants is dettached",language_variants.supported_variants = Void)
|
assert ("Variants is detached",language_variants.supported_variants = languages_supported)
|
||||||
assert ("Variant Header", language_variants.variant_header.is_equal ("Accept-Language"))
|
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", language_variants.type.is_equal ("fr"))
|
assert ("Language Type is fr", attached language_variants.language as l_lang and then l_lang.same_string ("fr"))
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Implementation
|
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
|
end
|
||||||
|
|||||||
@@ -23,25 +23,22 @@ feature {NONE} -- Events
|
|||||||
|
|
||||||
feature -- Helpers
|
feature -- Helpers
|
||||||
|
|
||||||
format (a_language: LANGUAGE_RESULTS): STRING
|
format (a_language: HTTP_ACCEPT_LANGUAGE): STRING
|
||||||
-- Representation of the current object
|
-- Representation of the current object
|
||||||
do
|
do
|
||||||
create Result.make_from_string ("(")
|
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 + "',")
|
Result.append_string ("'" + t + "',")
|
||||||
end
|
end
|
||||||
if attached a_language.sub_type as st then
|
if attached a_language.specialization as st then
|
||||||
Result.append_string (" '" + st + "',")
|
Result.append_string (" '" + st + "',")
|
||||||
end
|
end
|
||||||
Result.append_string (" {")
|
Result.append_string (" {")
|
||||||
if attached a_language.params as l_params then
|
if attached a_language.parameters as l_params then
|
||||||
from
|
across
|
||||||
l_params.start
|
l_params as ic
|
||||||
until
|
|
||||||
l_params.after
|
|
||||||
loop
|
loop
|
||||||
Result.append ("'" + l_params.key_for_iteration + "':'"+ l_params.item_for_iteration + "',");
|
Result.append ("'" + ic.key + "':'"+ ic.item + "',");
|
||||||
l_params.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Result.append ("})")
|
Result.append ("})")
|
||||||
@@ -52,10 +49,10 @@ feature -- Test routines
|
|||||||
|
|
||||||
test_parse_language
|
test_parse_language
|
||||||
do
|
do
|
||||||
assert ("Expected ('da', {'q':'1.0',})", format (parser.parse_language_range ("da")).same_string ("('da', {'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.parse_language_range ("en-gb;q=0.8")).same_string ("('en', 'gb', {'q':'0.8',})"));
|
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.parse_language_range ("en;q=0.7")).same_string ("('en', {'q':'0.7',})"));
|
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.parse_language_range ("en-*")).same_string ("('en', '*', {'q':'1.0',})"));
|
assert ("Expected ('en', '*', {'q':'1.0',})", format (parser.accept_language ("en-*")).same_string ("('en', '*', {'q':'1.0',})"));
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -73,53 +70,53 @@ feature -- Test routines
|
|||||||
|
|
||||||
test_best_match
|
test_best_match
|
||||||
local
|
local
|
||||||
mime_types_supported : LIST [STRING]
|
langs_supported : LIST [STRING]
|
||||||
l_types : STRING
|
l_types : STRING
|
||||||
do
|
do
|
||||||
l_types := "en-gb,en-us"
|
l_types := "en-gb,en-us"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_supported := l_types.split(',')
|
||||||
assert ("Expected en-us", parser.best_match (mime_types_supported, "en-us").same_string ("en-us"))
|
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 (mime_types_supported, "en-gb;q=1").same_string ("en-gb"))
|
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 (mime_types_supported, "en-us;q=1").same_string ("en-us"))
|
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 (mime_types_supported, "en-*;q=1").is_equal ("en-gb"))
|
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 (mime_types_supported, "*").same_string ("en-gb"))
|
assert ("Match using a type wildcard", parser.best_match (langs_supported, "*").same_string ("en-gb"))
|
||||||
|
|
||||||
l_types := "en-gb,es"
|
l_types := "en-gb,es"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_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 ("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 (mime_types_supported, "fr; q=0.9").same_string (""))
|
assert ("Fail to match anything",parser.best_match (langs_supported, "fr; q=0.9").same_string (""))
|
||||||
|
|
||||||
l_types := "en-gb,en-us"
|
l_types := "en-gb,en-us"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_supported := l_types.split(',')
|
||||||
assert ("Test 1 verify fitness ordering", parser.best_match (mime_types_supported, "en-gb,en-us,*").same_string ("en-gb"))
|
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"
|
l_types := "es,en-gb;q=1.0,fr;q=0.6"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_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"))
|
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"
|
l_types := "en-gb;q=1.0,fr;q=0.6,es"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_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"))
|
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"
|
l_types := "en-gb;q=1.0,fr,es"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_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"))
|
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"
|
l_types := "fr;q=1.0,en,es"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_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"))
|
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"
|
l_types := "fr;q=1.0,en,es"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_supported := l_types.split(',')
|
||||||
assert ("Test 1", parser.best_match (mime_types_supported, "es,*/*;q=0.1,en").same_string ("es"))
|
assert ("Test 1", parser.best_match (langs_supported, "es,*/*;q=0.1,en").same_string ("es"))
|
||||||
|
|
||||||
l_types := "fr;q=1.0,en,es"
|
l_types := "fr;q=1.0,en,es"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_supported := l_types.split(',')
|
||||||
assert ("Test 2", parser.best_match (mime_types_supported, "en,es,*/*;q=0.1").same_string ("en"))
|
assert ("Test 2", parser.best_match (langs_supported, "en,es,*/*;q=0.1").same_string ("en"))
|
||||||
|
|
||||||
l_types := "es,en;q=0.6"
|
l_types := "es,en;q=0.6"
|
||||||
mime_types_supported := l_types.split(',')
|
langs_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"))
|
assert ("Test 2", parser.best_match (langs_supported, "fr;q=1.0, en;q=0.6, es").same_string ("es"))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -137,7 +134,7 @@ feature -- Test routines
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
parser : LANGUAGE_PARSE
|
parser : HTTP_ACCEPT_LANGUAGE_UTILITIES
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -38,13 +38,10 @@ feature -- Helper
|
|||||||
end
|
end
|
||||||
Result.append_string (" {")
|
Result.append_string (" {")
|
||||||
if attached a_mediatype.parameters as l_params then
|
if attached a_mediatype.parameters as l_params then
|
||||||
from
|
across
|
||||||
l_params.start
|
l_params as ic
|
||||||
until
|
|
||||||
l_params.after
|
|
||||||
loop
|
loop
|
||||||
Result.append ("'" + l_params.key_for_iteration + "':'" + l_params.item_for_iteration + "',");
|
Result.append ("'" + ic.key + "':'" + ic.item + "',");
|
||||||
l_params.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Result.append ("})")
|
Result.append ("})")
|
||||||
@@ -54,15 +51,15 @@ feature -- Test routines
|
|||||||
|
|
||||||
test_parse_media_range
|
test_parse_media_range
|
||||||
do
|
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.media_type("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.media_type("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',})", format (parser.media_type("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.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.parse_media_range("application/xml ; q=2;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 *
|
-- 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
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -148,7 +145,7 @@ feature -- Test routines
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
parser : MIME_PARSE
|
parser : HTTP_ACCEPT_MEDIA_TYPE_UTILITIES
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-6-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-6-0 http://www.eiffel.com/developers/xml/configuration-1-6-0.xsd" name="test" uuid="7860561C-779A-4E45-A7B9-06A1E0E984E8">
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="test" uuid="7860561C-779A-4E45-A7B9-06A1E0E984E8">
|
||||||
<target name="test">
|
<target name="test">
|
||||||
<root class="APPLICATION" feature="make"/>
|
<root class="APPLICATION" feature="make"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
<exclude>/EIFGENs$</exclude>
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/CVS$</exclude>
|
<exclude>/CVS$</exclude>
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
<exclude>/.git$</exclude>
|
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true">
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="conneg" location="..\conneg-safe.ecf" readonly="false">
|
||||||
|
<option>
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
</library>
|
||||||
<library name="http" location="..\..\http\http-safe.ecf" readonly="false"/>
|
<library name="http" location="..\..\http\http-safe.ecf" readonly="false"/>
|
||||||
<library name="conneg" location="..\conneg-safe.ecf"/>
|
|
||||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
<cluster name="test" location=".\" recursive="true"/>
|
<cluster name="test" location=".\" recursive="true"/>
|
||||||
</target>
|
</target>
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ feature {NONE} -- Initialization
|
|||||||
t: STRING_8
|
t: STRING_8
|
||||||
i,n: INTEGER
|
i,n: INTEGER
|
||||||
p: INTEGER
|
p: INTEGER
|
||||||
cl: CELL [INTEGER]
|
|
||||||
do
|
do
|
||||||
-- Ignore starting space (should not be any)
|
-- Ignore starting space (should not be any)
|
||||||
from
|
from
|
||||||
@@ -79,15 +78,7 @@ feature {NONE} -- Initialization
|
|||||||
p := s.index_of (';', i)
|
p := s.index_of (';', i)
|
||||||
if p > 0 then
|
if p > 0 then
|
||||||
t := s.substring (i, p - 1)
|
t := s.substring (i, p - 1)
|
||||||
from
|
create parameters.make_from_substring (s, p + 1, s.count)
|
||||||
create cl.put (p)
|
|
||||||
i := p + 1
|
|
||||||
until
|
|
||||||
i >= n
|
|
||||||
loop
|
|
||||||
add_parameter_from_string (s, i, cl)
|
|
||||||
i := cl.item
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
t := s.substring (i, n)
|
t := s.substring (i, n)
|
||||||
end
|
end
|
||||||
@@ -116,7 +107,7 @@ feature {NONE} -- Initialization
|
|||||||
subtype := type
|
subtype := type
|
||||||
end
|
end
|
||||||
ensure
|
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
|
end
|
||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
@@ -149,7 +140,7 @@ feature -- Access
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parameters: detachable HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
parameters: detachable HTTP_PARAMETER_TABLE
|
||||||
-- Parameters
|
-- Parameters
|
||||||
|
|
||||||
feature -- Conversion
|
feature -- Conversion
|
||||||
@@ -262,7 +253,7 @@ feature -- Element change
|
|||||||
-- Remove parameter named `a_name'
|
-- Remove parameter named `a_name'
|
||||||
do
|
do
|
||||||
if attached parameters as plst then
|
if attached parameters as plst then
|
||||||
plst.prune (a_name)
|
plst.remove (a_name)
|
||||||
if plst.is_empty then
|
if plst.is_empty then
|
||||||
parameters := Void
|
parameters := Void
|
||||||
end
|
end
|
||||||
@@ -270,84 +261,6 @@ feature -- Element change
|
|||||||
internal_string := Void
|
internal_string := Void
|
||||||
end
|
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
|
feature {NONE} -- Internal
|
||||||
|
|
||||||
internal_string: detachable STRING_8
|
internal_string: detachable STRING_8
|
||||||
|
|||||||
150
library/network/protocol/http/src/http_parameter_table.e
Normal file
150
library/network/protocol/http/src/http_parameter_table.e
Normal file
@@ -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
|
||||||
@@ -20,8 +20,9 @@ feature {NONE} -- Initialization
|
|||||||
res.set_post_commit_action (agent commit)
|
res.set_post_commit_action (agent commit)
|
||||||
end
|
end
|
||||||
|
|
||||||
wgi_response: WGI_RESPONSE
|
feature -- Access
|
||||||
|
|
||||||
|
wgi_response: WGI_RESPONSE
|
||||||
|
|
||||||
feature {WGI_FILTER_RESPONSE} -- Change
|
feature {WGI_FILTER_RESPONSE} -- Change
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ class
|
|||||||
|
|
||||||
inherit
|
inherit
|
||||||
WGI_INPUT_STREAM
|
WGI_INPUT_STREAM
|
||||||
|
redefine
|
||||||
|
last_character_available
|
||||||
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
@@ -36,11 +39,17 @@ feature -- Input
|
|||||||
index := index + 1
|
index := index + 1
|
||||||
if index > chunk_upper then
|
if index > chunk_upper then
|
||||||
read_chunk_block
|
read_chunk_block
|
||||||
if last_chunk_data = Void then
|
if
|
||||||
|
last_chunk_size = 0
|
||||||
|
then
|
||||||
read_trailer_and_crlf
|
read_trailer_and_crlf
|
||||||
|
last_character := '%U'
|
||||||
|
else
|
||||||
|
last_character := last_chunk_data.item (index)
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
last_character := last_chunk_data.item (index)
|
||||||
end
|
end
|
||||||
last_character := last_chunk_data.item (index)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
read_string (nb: INTEGER)
|
read_string (nb: INTEGER)
|
||||||
@@ -54,7 +63,7 @@ feature -- Input
|
|||||||
i: like index
|
i: like index
|
||||||
do
|
do
|
||||||
last_string.wipe_out
|
last_string.wipe_out
|
||||||
if last_trailer /= Void then
|
if is_trailer_reached then
|
||||||
-- trailer already reached, no more data
|
-- trailer already reached, no more data
|
||||||
check input.end_of_input end
|
check input.end_of_input end
|
||||||
else
|
else
|
||||||
@@ -103,6 +112,12 @@ feature -- Access
|
|||||||
last_character: CHARACTER_8
|
last_character: CHARACTER_8
|
||||||
-- Last item read.
|
-- Last item read.
|
||||||
|
|
||||||
|
last_character_available: BOOLEAN
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Result := not is_trailer_reached
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access: chunk
|
feature -- Access: chunk
|
||||||
|
|
||||||
last_chunk_size: INTEGER
|
last_chunk_size: INTEGER
|
||||||
@@ -142,7 +157,13 @@ feature -- Status report
|
|||||||
end_of_input: BOOLEAN
|
end_of_input: BOOLEAN
|
||||||
-- Has the end of input stream been reached?
|
-- Has the end of input stream been reached?
|
||||||
do
|
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
|
end
|
||||||
|
|
||||||
feature {NONE} -- Parser
|
feature {NONE} -- Parser
|
||||||
@@ -320,11 +341,7 @@ feature {NONE} -- Parser
|
|||||||
check l_input.last_character = '%N' end
|
check l_input.last_character = '%N' end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if s.is_empty then
|
last_trailer := s
|
||||||
last_trailer := Void
|
|
||||||
else
|
|
||||||
last_trailer := s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
@@ -333,7 +350,7 @@ feature {NONE} -- Implementation
|
|||||||
-- Input Stream
|
-- Input Stream
|
||||||
|
|
||||||
;note
|
;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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -62,14 +62,19 @@ feature -- Input
|
|||||||
i > end_pos
|
i > end_pos
|
||||||
loop
|
loop
|
||||||
read_character
|
read_character
|
||||||
a_string.put (last_character, i)
|
if last_character_available then
|
||||||
|
a_string.put (last_character, i)
|
||||||
if end_of_input then
|
if end_of_input then
|
||||||
Result := i
|
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.
|
-- Jump out of the loop.
|
||||||
i := end_pos + 1
|
i := end_pos + 1
|
||||||
else
|
|
||||||
i := i + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not end_of_input then
|
if not end_of_input then
|
||||||
@@ -107,13 +112,20 @@ feature -- Input
|
|||||||
i > end_pos
|
i > end_pos
|
||||||
loop
|
loop
|
||||||
read_character
|
read_character
|
||||||
a_string.extend (last_character)
|
if last_character_available then
|
||||||
l_count := l_count + 1
|
a_string.extend (last_character)
|
||||||
if end_of_input then
|
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.
|
-- Jump out of the loop.
|
||||||
i := end_pos + 1
|
i := end_pos + 1
|
||||||
else
|
|
||||||
i := i + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
last_appended_count := l_count
|
last_appended_count := l_count
|
||||||
@@ -194,6 +206,15 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
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
|
last_appended_count: INTEGER
|
||||||
-- Count of characters actually read by last `append_to_string' call.
|
-- Count of characters actually read by last `append_to_string' call.
|
||||||
|
|
||||||
|
|||||||
@@ -167,12 +167,12 @@ feature -- Content negotiation
|
|||||||
res_attached: res /= Void
|
res_attached: res /= Void
|
||||||
a_handler_attached: a_handler /= Void
|
a_handler_attached: a_handler /= Void
|
||||||
local
|
local
|
||||||
l_conneg: CONNEG_SERVER_SIDE
|
l_conneg: SERVER_CONTENT_NEGOTIATION
|
||||||
h: HTTP_HEADER
|
h: HTTP_HEADER
|
||||||
l_media: MEDIA_TYPE_VARIANT_RESULTS
|
l_media: like {SERVER_CONTENT_NEGOTIATION}.media_type_preference
|
||||||
l_lang: LANGUAGE_VARIANT_RESULTS
|
l_lang: like {SERVER_CONTENT_NEGOTIATION}.language_preference
|
||||||
l_charset: CHARACTER_ENCODING_VARIANT_RESULTS
|
l_charset: like {SERVER_CONTENT_NEGOTIATION}.charset_preference
|
||||||
l_encoding: COMPRESSION_VARIANT_RESULTS
|
l_encoding: like {SERVER_CONTENT_NEGOTIATION}.encoding_preference
|
||||||
l_mime_types, l_langs, l_charsets, l_encodings: LIST [STRING]
|
l_mime_types, l_langs, l_charsets, l_encodings: LIST [STRING]
|
||||||
l_vary_star: BOOLEAN
|
l_vary_star: BOOLEAN
|
||||||
do
|
do
|
||||||
@@ -188,7 +188,7 @@ feature -- Content negotiation
|
|||||||
l_conneg := a_handler.conneg (req)
|
l_conneg := a_handler.conneg (req)
|
||||||
l_mime_types := a_handler.mime_types_supported (req)
|
l_mime_types := a_handler.mime_types_supported (req)
|
||||||
l_media := l_conneg.media_type_preference (l_mime_types, req.http_accept)
|
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)
|
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_media_variant)
|
||||||
end
|
end
|
||||||
if not l_media.is_acceptable then
|
if not l_media.is_acceptable then
|
||||||
@@ -196,26 +196,26 @@ feature -- Content negotiation
|
|||||||
else
|
else
|
||||||
l_langs := a_handler.languages_supported (req)
|
l_langs := a_handler.languages_supported (req)
|
||||||
l_lang := l_conneg.language_preference (l_langs, req.http_accept_language)
|
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)
|
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_lang_variant)
|
||||||
end
|
end
|
||||||
if not l_lang.is_acceptable then
|
if not l_lang.is_acceptable then
|
||||||
handle_not_acceptable ("None of the requested languages were acceptable", l_langs, req, res)
|
handle_not_acceptable ("None of the requested languages were acceptable", l_langs, req, res)
|
||||||
else
|
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)
|
h.put_content_language (l_language_type)
|
||||||
req.set_execution_variable (a_handler.Negotiated_language_execution_variable, l_language_type)
|
req.set_execution_variable (a_handler.Negotiated_language_execution_variable, l_language_type)
|
||||||
end
|
end
|
||||||
l_charsets := a_handler.charsets_supported (req)
|
l_charsets := a_handler.charsets_supported (req)
|
||||||
l_charset := l_conneg.charset_preference (l_charsets, req.http_accept_charset)
|
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)
|
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_charset_variant)
|
||||||
end
|
end
|
||||||
if not l_charset.is_acceptable then
|
if not l_charset.is_acceptable then
|
||||||
handle_not_acceptable ("None of the requested character encodings were acceptable", l_charsets, req, res)
|
handle_not_acceptable ("None of the requested character encodings were acceptable", l_charsets, req, res)
|
||||||
else
|
else
|
||||||
if attached l_media.type as l_media_type then
|
if attached l_media.media_type as l_media_type then
|
||||||
if attached l_charset.type as l_character_type then
|
if attached l_charset.charset as l_character_type then
|
||||||
h.put_content_type (l_media_type + "; charset=" + l_character_type)
|
h.put_content_type (l_media_type + "; charset=" + l_character_type)
|
||||||
req.set_execution_variable (a_handler.Negotiated_charset_execution_variable, l_charset)
|
req.set_execution_variable (a_handler.Negotiated_charset_execution_variable, l_charset)
|
||||||
else
|
else
|
||||||
@@ -225,13 +225,13 @@ feature -- Content negotiation
|
|||||||
end
|
end
|
||||||
l_encodings := a_handler.encodings_supported (req)
|
l_encodings := a_handler.encodings_supported (req)
|
||||||
l_encoding := l_conneg.encoding_preference (l_encodings, req.http_accept_encoding)
|
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)
|
h.add_header_key_value ({HTTP_HEADER_NAMES}.header_vary, l_encoding_variant)
|
||||||
end
|
end
|
||||||
if not l_encoding.is_acceptable then
|
if not l_encoding.is_acceptable then
|
||||||
handle_not_acceptable ("None of the requested transfer encodings were acceptable", l_encodings, req, res)
|
handle_not_acceptable ("None of the requested transfer encodings were acceptable", l_encodings, req, res)
|
||||||
else
|
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)
|
h.put_content_encoding (l_compression_type)
|
||||||
req.set_execution_variable (a_handler.Negotiated_encoding_execution_variable, l_compression_type)
|
req.set_execution_variable (a_handler.Negotiated_encoding_execution_variable, l_compression_type)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
conneg (req: WSF_REQUEST): CONNEG_SERVER_SIDE
|
conneg (req: WSF_REQUEST): SERVER_CONTENT_NEGOTIATION
|
||||||
-- Content negotiation for `req';
|
-- Content negotiation for `req';
|
||||||
-- This would normally be a once object, ignoring `req'.
|
-- This would normally be a once object, ignoring `req'.
|
||||||
require
|
require
|
||||||
@@ -103,7 +103,7 @@ feature -- Access
|
|||||||
req_attached: req /= Void
|
req_attached: req /= Void
|
||||||
deferred
|
deferred
|
||||||
ensure
|
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
|
end
|
||||||
|
|
||||||
languages_supported (req: WSF_REQUEST): LIST [STRING]
|
languages_supported (req: WSF_REQUEST): LIST [STRING]
|
||||||
@@ -112,7 +112,7 @@ feature -- Access
|
|||||||
req_attached: req /= Void
|
req_attached: req /= Void
|
||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
languages_supported_includes_default: Result.has (conneg (req).language_default)
|
languages_supported_includes_default: Result.has (conneg (req).default_language)
|
||||||
end
|
end
|
||||||
|
|
||||||
charsets_supported (req: WSF_REQUEST): LIST [STRING]
|
charsets_supported (req: WSF_REQUEST): LIST [STRING]
|
||||||
@@ -121,7 +121,7 @@ feature -- Access
|
|||||||
req_attached: req /= Void
|
req_attached: req /= Void
|
||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
charsets_supported_includes_default: Result.has (conneg (req).charset_default)
|
charsets_supported_includes_default: Result.has (conneg (req).default_charset)
|
||||||
end
|
end
|
||||||
|
|
||||||
encodings_supported (req: WSF_REQUEST): LIST [STRING]
|
encodings_supported (req: WSF_REQUEST): LIST [STRING]
|
||||||
@@ -130,7 +130,7 @@ feature -- Access
|
|||||||
req_attached: req /= Void
|
req_attached: req /= Void
|
||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
encodings_supported_includes_default: Result.has (conneg (req).encoding_default)
|
encodings_supported_includes_default: Result.has (conneg (req).default_encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
additional_variant_headers (req: WSF_REQUEST): detachable LIST [STRING]
|
additional_variant_headers (req: WSF_REQUEST): detachable LIST [STRING]
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ feature -- Execution
|
|||||||
deferred
|
deferred
|
||||||
end
|
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
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
|||||||
@@ -351,31 +351,9 @@ feature -- Helper
|
|||||||
-- Does client accepts content_type for the response?
|
-- Does client accepts content_type for the response?
|
||||||
--| Based on header "Accept:" that can be for instance
|
--| Based on header "Accept:" that can be for instance
|
||||||
--| text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
--| text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
||||||
local
|
|
||||||
i, j: INTEGER
|
|
||||||
do
|
do
|
||||||
if attached http_accept as l_accept then
|
if attached (create {SERVER_MEDIA_TYPE_NEGOTIATION}.make (a_content_type.as_string_8)).preference (<<a_content_type.as_string_8>>, http_accept) as l_variants then
|
||||||
i := l_accept.substring_index (a_content_type, 1)
|
Result := l_variants.is_acceptable
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -38,12 +38,14 @@ feature {NONE} -- Initialization
|
|||||||
create header.make
|
create header.make
|
||||||
wgi_response := r
|
wgi_response := r
|
||||||
if attached {WSF_WGI_DELAYED_HEADER_RESPONSE} r as r_delayed then
|
if attached {WSF_WGI_DELAYED_HEADER_RESPONSE} r as r_delayed then
|
||||||
wres := r_delayed
|
r_delayed.update_wsf_response (Current)
|
||||||
wres.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
|
else
|
||||||
create wres.make (r, Current)
|
create wres.make (r, Current)
|
||||||
|
wgi_response := wres
|
||||||
end
|
end
|
||||||
wgi_response := wres
|
|
||||||
set_status_code ({HTTP_STATUS_CODE}.ok) -- Default value
|
set_status_code ({HTTP_STATUS_CODE}.ok) -- Default value
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -494,7 +496,7 @@ feature -- Error reporting
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ feature {NONE} -- Events
|
|||||||
create h.make
|
create h.make
|
||||||
b := base_url
|
b := base_url
|
||||||
if b = Void then
|
if b = Void then
|
||||||
b := ""
|
b := "/"
|
||||||
end
|
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
|
http_session := sess
|
||||||
sess.set_timeout (-1)
|
sess.set_timeout (-1)
|
||||||
sess.set_is_debug (True)
|
sess.set_is_debug (True)
|
||||||
@@ -125,10 +125,16 @@ feature {NONE} -- Events
|
|||||||
do
|
do
|
||||||
get_http_session
|
get_http_session
|
||||||
if attached http_session as sess then
|
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
|
if attached sess.get (a_url, adapted_context (ctx)) as res then
|
||||||
assert ("Good answer got=%""+l_body+"%" expected=%""+a_expected_body+"%"", l_body.same_string (a_expected_body))
|
if attached res.body as l_body then
|
||||||
else
|
if res.error_occurred then
|
||||||
assert ("Request %""+a_url+"%" failed", False)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ Content-Disposition: form-data; name="password"
|
|||||||
EWFpassword
|
EWFpassword
|
||||||
--__=_the_boundary_1332296477_1804289383_=__--
|
--__=_the_boundary_1332296477_1804289383_=__--
|
||||||
]"
|
]"
|
||||||
|
b.replace_substring_all ("%N", "%R%N")
|
||||||
h.put_content_length (b.count)
|
h.put_content_length (b.count)
|
||||||
|
|
||||||
--| Case #1
|
--| Case #1
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<library name="error" location="..\..\utility\general\error\error-safe.ecf"/>
|
<library name="error" location="..\..\utility\general\error\error-safe.ecf"/>
|
||||||
<library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/>
|
<library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/>
|
||||||
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
|
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||||
<library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/>
|
<library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
<library name="error" location="../../utility/general/error/error.ecf"/>
|
<library name="error" location="../../utility/general/error/error.ecf"/>
|
||||||
<library name="http" location="../../network/protocol/http/http.ecf"/>
|
<library name="http" location="../../network/protocol/http/http.ecf"/>
|
||||||
|
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg.ecf"/>
|
||||||
<library name="uri_template"
|
<library name="uri_template"
|
||||||
location="../../text/parser/uri_template/uri_template.ecf"/>
|
location="../../text/parser/uri_template/uri_template.ecf"/>
|
||||||
<library name="encoder"
|
<library name="encoder"
|
||||||
|
|||||||
Reference in New Issue
Block a user