Updated Conneg library, added test cases
This commit is contained in:
@@ -3,3 +3,124 @@ where there are multiple representations available.
|
||||
|
||||
Using this labrary you can retrieve the best Variant for media type, language preference, enconding and compression.
|
||||
The library is based on eMIME Eiffel MIME library based on Joe Gregorio code
|
||||
|
||||
Take into account that the library is under development so is expected that the API chanherge.
|
||||
|
||||
The library contains utilities that deal with content negotiation (server driven negotiation).This utility class
|
||||
is based on ideas taken from the Book Restful WebServices Cookbook
|
||||
|
||||
The class CONNEG_SERVER_SIDE contains several features that helps to write different type of negotiations (media type, language,
|
||||
charset and compression).
|
||||
So for each of the following questions, you will have a corresponding method to help in the solution.
|
||||
|
||||
How to implement Media type negotiation?
|
||||
Hint: Use CONNEG_SERVER_SIDE.media_type_preference
|
||||
|
||||
How to implement Language Negotiation?
|
||||
Hint: Use CONNEG_SERVER_SIDE.language_preference
|
||||
|
||||
|
||||
How to implement Character encoding Negotiation?
|
||||
Hint: Use CONNEG_SERVER_SIDE.charset_preference
|
||||
|
||||
How to implement Compression Negotiation?
|
||||
Hint: Use CONNEG_SERVER_SIDE.encoding_preference
|
||||
|
||||
There is also a test case 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
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
note
|
||||
description: "Summary description for {CHARACTER_ENCODING_VARIANT_RESULTS}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CHARACTER_ENCODING_VARIANT_RESULTS
|
||||
feature
|
||||
character_type : detachable STRING
|
||||
set_character_type ( a_character_type: STRING)
|
||||
do
|
||||
character_type := a_character_type
|
||||
ensure
|
||||
set_character_type : a_character_type ~ character_type
|
||||
end
|
||||
|
||||
variant_header : detachable STRING
|
||||
set_variant_header
|
||||
do
|
||||
variant_header := "Accept-Charset"
|
||||
end
|
||||
|
||||
supported_variants : detachable LIST[STRING]
|
||||
set_supported_variants (a_supported : LIST[STRING])
|
||||
do
|
||||
supported_variants := a_supported
|
||||
ensure
|
||||
set_supported_variants : supported_variants = a_supported
|
||||
end
|
||||
|
||||
is_acceptable : BOOLEAN
|
||||
|
||||
set_acceptable ( acceptable : BOOLEAN)
|
||||
do
|
||||
is_acceptable := acceptable
|
||||
ensure
|
||||
is_acceptable = acceptable
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
44
library/protocol/CONNEG/src/compression_variant_results.e
Normal file
44
library/protocol/CONNEG/src/compression_variant_results.e
Normal file
@@ -0,0 +1,44 @@
|
||||
note
|
||||
description: "Summary description for {COMPRESSION_VARIANT_RESULTS}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
COMPRESSION_VARIANT_RESULTS
|
||||
|
||||
feature
|
||||
compression_type : detachable STRING
|
||||
set_compression_type ( a_compression_type: STRING)
|
||||
do
|
||||
compression_type := a_compression_type
|
||||
ensure
|
||||
set_compression_type : a_compression_type ~ compression_type
|
||||
end
|
||||
|
||||
variant_header : detachable STRING
|
||||
set_variant_header
|
||||
do
|
||||
variant_header := "Accept-Encoding"
|
||||
end
|
||||
|
||||
supported_variants : detachable LIST[STRING]
|
||||
set_supported_variants (a_supported : LIST[STRING])
|
||||
do
|
||||
supported_variants := a_supported
|
||||
ensure
|
||||
set_supported_variants : supported_variants = a_supported
|
||||
end
|
||||
|
||||
is_acceptable : BOOLEAN
|
||||
|
||||
set_acceptable ( acceptable : BOOLEAN)
|
||||
do
|
||||
is_acceptable := acceptable
|
||||
ensure
|
||||
is_acceptable = acceptable
|
||||
end
|
||||
note
|
||||
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -109,29 +109,71 @@ feature -- Media Type Negotiation
|
||||
|
||||
feature -- Encoding Negotiation
|
||||
|
||||
charset_preference (server_charset_supported : LIST[STRING]; header: STRING) : STRING
|
||||
charset_preference (server_charset_supported : LIST[STRING]; header: STRING) : 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
|
||||
local
|
||||
charset_match : STRING
|
||||
do
|
||||
Result := common.best_match (server_charset_supported, header)
|
||||
create Result
|
||||
if header.is_empty then
|
||||
-- the request has no Accept-Charset header, ie the header is empty, in this case use default charset encoding
|
||||
-- (UTF-8)
|
||||
Result.set_acceptable (TRUE)
|
||||
Result.set_character_type (charset_default)
|
||||
else
|
||||
-- select the best match, server support, client preferences
|
||||
charset_match := common.best_match (server_charset_supported, header)
|
||||
if 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 (server_charset_supported)
|
||||
else
|
||||
-- Set the best match
|
||||
Result.set_character_type(charset_match)
|
||||
Result.set_acceptable (True)
|
||||
Result.set_variant_header
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Compression Negotiation
|
||||
|
||||
encoding_preference (server_encoding_supported : LIST[STRING]; header: STRING) : STRING
|
||||
encoding_preference (server_encoding_supported : LIST[STRING]; header: STRING) : 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
|
||||
local
|
||||
compression_match : STRING
|
||||
do
|
||||
Result := common.best_match (server_encoding_supported, header)
|
||||
create Result
|
||||
if 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_compression_type (encoding_default)
|
||||
else
|
||||
-- select the best match, server support, client preferences
|
||||
compression_match := common.best_match (server_encoding_supported, header)
|
||||
if 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 (server_encoding_supported)
|
||||
else
|
||||
-- Set the best match
|
||||
Result.set_compression_type(compression_match)
|
||||
Result.set_acceptable (True)
|
||||
Result.set_variant_header
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
feature -- Language Negotiation
|
||||
|
||||
language_preference (server_language_supported : LIST[STRING]; header: STRING) : LANGUAGE_VARIANT_RESULTS
|
||||
@@ -164,6 +206,8 @@ feature -- Language Negotiation
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Apache Conneg Algorithm
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -17,7 +17,7 @@ feature {NONE} -- Events
|
||||
on_prepare
|
||||
-- Called after all initializations in `default_create'.
|
||||
do
|
||||
create conneg.make ("application/json", "es", "UTF8", "")
|
||||
create conneg.make ("application/json", "es", "UTF-8", "")
|
||||
-- set default values
|
||||
end
|
||||
|
||||
@@ -56,6 +56,77 @@ feature -- Test routines
|
||||
|
||||
|
||||
|
||||
test_charset_negotiation
|
||||
local
|
||||
charset_variants : CHARACTER_ENCODING_VARIANT_RESULTS
|
||||
charset_supported : LIST [STRING]
|
||||
l_charset : STRING
|
||||
do
|
||||
-- Scenario 1, the server side does not support client preferences
|
||||
l_charset := "UTF-8, iso-8859-5"
|
||||
charset_supported := l_charset.split(',')
|
||||
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1")
|
||||
assert ("Expected Not Acceptable", not charset_variants.is_acceptable)
|
||||
assert ("Same Value at 1",charset_supported.at (1).is_equal (charset_variants.supported_variants.at (1)))
|
||||
assert ("Same count",charset_supported.count = charset_variants.supported_variants.count)
|
||||
assert ("Variant header is void",charset_variants.variant_header = Void)
|
||||
assert ("Character type is void",charset_variants.character_type = Void)
|
||||
|
||||
|
||||
-- Scenario 2, the client doesnt send values in the header, Accept-Charset:
|
||||
charset_variants := conneg.charset_preference (charset_supported, "")
|
||||
assert ("Expected Acceptable", charset_variants.is_acceptable)
|
||||
assert ("Variants is dettached",charset_variants.supported_variants = Void)
|
||||
assert ("Charset is defaul", conneg.charset_default.is_equal (charset_variants.character_type))
|
||||
assert ("Variant header", charset_variants.variant_header = Void)
|
||||
|
||||
|
||||
--Scenario 3, the server select the best match, and set the vary header
|
||||
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1, UTF-8;q=0.3, iso-8859-5")
|
||||
assert ("Expected Acceptable", charset_variants.is_acceptable)
|
||||
assert ("Variants is dettached",charset_variants.supported_variants = Void)
|
||||
assert ("Variant Header", charset_variants.variant_header.is_equal ("Accept-Charset"))
|
||||
assert ("Character Type is iso-8859-5", charset_variants.character_type.is_equal ("iso-8859-5"))
|
||||
end
|
||||
|
||||
test_compression_negotiation
|
||||
local
|
||||
compression_variants : COMPRESSION_VARIANT_RESULTS
|
||||
compression_supported : LIST [STRING]
|
||||
l_compression : STRING
|
||||
do
|
||||
-- Scenario 1, the server side does not support client preferences
|
||||
l_compression := ""
|
||||
compression_supported := l_compression.split(',')
|
||||
compression_variants := conneg.encoding_preference (compression_supported, "gzip")
|
||||
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
|
||||
assert ("Same Value at 1",compression_supported.at (1).is_equal (compression_variants.supported_variants.at (1)))
|
||||
assert ("Same count",compression_supported.count = compression_variants.supported_variants.count)
|
||||
assert ("Variant header is void",compression_variants.variant_header = Void)
|
||||
assert ("Compression type is void",compression_variants.compression_type = Void)
|
||||
|
||||
|
||||
-- Scenario 2, the client doesnt send values in the header, Accept-Encoding
|
||||
compression_variants := conneg.encoding_preference (compression_supported, "")
|
||||
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
||||
assert ("Variants is dettached",compression_variants.supported_variants = Void)
|
||||
assert ("Compression is defaul", conneg.encoding_default.is_equal (compression_variants.compression_type))
|
||||
assert ("Variant header", compression_variants.variant_header = Void)
|
||||
|
||||
|
||||
--Scenario 3, the server select the best match, and set the vary header
|
||||
l_compression := "gzip"
|
||||
compression_supported := l_compression.split(',')
|
||||
conneg.set_encoding_defautl ("gzip")
|
||||
compression_variants := conneg.encoding_preference (compression_supported, "compress,gzip;q=0.7")
|
||||
assert ("Expected Acceptable", compression_variants.is_acceptable)
|
||||
assert ("Variants is dettached",compression_variants.supported_variants = Void)
|
||||
assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
|
||||
assert ("Encoding Type is gzip", compression_variants.compression_type.is_equal ("gzip"))
|
||||
end
|
||||
|
||||
|
||||
|
||||
test_language_negotiation
|
||||
local
|
||||
language_variants : LANGUAGE_VARIANT_RESULTS
|
||||
@@ -90,6 +161,7 @@ feature -- Test routines
|
||||
|
||||
|
||||
end
|
||||
|
||||
feature -- Implementation
|
||||
conneg : CONNEG_SERVER_SIDE
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user