Renamed CONNEG to content_negotiation.

Update MIME_PARSER to use HTTP_MEDIA_TYPE.
This commit is contained in:
jvelilla
2013-09-16 23:56:01 -03:00
parent a6260ed5a2
commit f2ee91764d
36 changed files with 550 additions and 570 deletions

View File

@@ -1,79 +0,0 @@
#!/usr/bin/env ruby
# Niklaus Giger, 15.01.2011
# Small ruby-script run all tests using ec (the Eiffel compiler)
# we assumen that ec outputs everything in english!
# For the command line options look at
# http://docs.eiffel.com/book/eiffelstudio/eiffelstudio-command-line-options
# we use often the -batch open.
#
# TODO: Fix problems when compiling takes too long and/or there
# are ec process lingering around from a previous failed build
require 'tempfile'
require 'fileutils'
# Override system command.
# run command. if not successful, complain and exit with error
def system(cmd)
puts cmd
res = Kernel.system(cmd)
if !res
puts "Failed running: #{cmd}"
exit 2
end
end
def runTestForProject(where)
if !File.directory?(where)
puts "Directory #{where} does not exist"
exit 2
end
# create a temporary file with input for the
# interactive mode of ec
commands2run=<<EOF
T
E
q
EOF
file = Tempfile.new('commands2run')
file.puts commands2run
file.close
Dir.chdir(where)
# First we have to remove old compilation
FileUtils.rm_rf("EIFGENs")
# compile the library
cmd = "ec -config library/emime-safe.ecf -target emime -batch -c_compile"
res = system(cmd)
# compile the test
cmd = "ec -config test/test-safe.ecf -target test -batch -c_compile"
res = system(cmd)
logFile = "#{__FILE__}.log"
sleep 1
cmd = "ec -config test/test-safe.ecf -target test -batch -loop 1>#{logFile} 2>#{__FILE__}.auto_test_output <#{file.path}"
res = system(cmd)
m= nil
IO.readlines(logFile).each{
|line|
m = /(\d+) tests total \((\d+) executed, (\d+) failing, (\d+) unresolved/.match(line)
break if m
}
puts
if m[3].to_i == 0 and m[4].to_i == 0 then
puts "#{m[1]} tests completed successfully"
else
puts "Failures while running #{m[1]} failed. #{m[2]} executed #{m[3]} failures #{m[4]} unresolved"
exit 2
end
end
runTestForProject(Dir.pwd)

View File

@@ -1,45 +0,0 @@
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

View File

@@ -1,44 +0,0 @@
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

View File

@@ -1,46 +0,0 @@
note
description: "Summary description for {LANGUAGE_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
LANGUAGE_VARIANT_RESULTS
feature
language_type : detachable STRING
set_language_type ( a_language_type: STRING)
do
language_type := a_language_type
ensure
set_language_type : a_language_type ~ language_type
end
variant_header : detachable STRING
set_variant_header
do
variant_header := "Accept-Language"
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

View File

@@ -1,47 +0,0 @@
note
description: "Summary description for {MEDIA_TYPE_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
MEDIA_TYPE_VARIANT_RESULTS
feature
media_type : detachable STRING
set_media_type ( a_media_type: STRING)
do
media_type := a_media_type
ensure
set_media_type : a_media_type ~ media_type
end
variant_header : detachable STRING
set_variant_header
do
variant_header := "Accept"
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

View File

@@ -1,58 +0,0 @@
note
description: "Summary description for {VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
VARIANT_RESULTS
feature -- Mime, Language, Charset and Encoding Results
mime_result : detachable STRING
set_mime_result ( a_mime: STRING)
-- set the mime_result with `a_mime'
do
mime_result := a_mime
ensure
set_mime_result: a_mime ~ mime_result
end
language_result : detachable STRING
set_language_result (a_language : STRING)
-- set the language_result with `a_language'
do
language_result := a_language
ensure
set_language : a_language ~ language_result
end
charset_result : detachable STRING
set_charset_result (a_charset : STRING)
-- set the charset_result with `a_charset'
do
charset_result := a_charset
ensure
set_charset : a_charset ~ charset_result
end
encoding_result : detachable STRING
set_encoding_defautl (an_encoding : STRING)
do
encoding_result := an_encoding
ensure
set_encoding : an_encoding ~ encoding_result
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

View File

@@ -12,7 +12,7 @@
<assertions precondition="true"/> <assertions 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="http" location="..\http\http-safe.ecf"/> <library name="http" location="..\http\http-safe.ecf" readonly="false"/>
<cluster name="conneg" location=".\src\" recursive="true"/> <cluster name="conneg" location=".\src\" recursive="true"/>
</target> </target>
</system> </system>

View File

@@ -0,0 +1,58 @@
note
description: "Summary description for {CHARACTER_ENCODING_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CHARACTER_ENCODING_VARIANT_RESULTS
feature -- Access
character_type: detachable STRING
variant_header: detachable STRING
supported_variants: detachable LIST [STRING]
is_acceptable: BOOLEAN
feature -- Change Element
set_character_type (a_character_type: STRING)
-- Set `character_type' with `a_character_type'
do
character_type := a_character_type
ensure
character_type_set: character_type /= Void implies a_character_type = character_type
end
set_variant_header
-- Set variant header as `Accept-Charset'
do
variant_header := "Accept-Charset"
ensure
variant_header_set: attached variant_header as l_variant_header implies l_variant_header.same_string ("Accept-Charset")
end
set_supported_variants (a_supported: LIST [STRING])
-- Set `supported_variants' with `a_supported'
do
supported_variants := a_supported
ensure
supported_variants_set: supported_variants /= Void implies supported_variants = a_supported
end
set_acceptable (acceptable: BOOLEAN)
-- Set `is_acceptable' with `acceptabe'
do
is_acceptable := acceptable
ensure
is_acceptable_set: is_acceptable = acceptable
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

View File

@@ -3,17 +3,15 @@ note
author: "" author: ""
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
description : "[ EIS: "name=Charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
Charset Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2 EIS: "name=Encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
Encoding Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
]"
class class
COMMON_ACCEPT_HEADER_PARSER COMMON_ACCEPT_HEADER_PARSER
feature -- Parser feature -- Parser
parse_common (header: STRING): COMMON_RESULTS
parse_common (header: STRING): COMMON_RESULTS
-- Parses `header' charset/encoding into its component parts. -- Parses `header' charset/encoding into its component parts.
-- For example, the charset 'iso-8889-5' would get parsed -- For example, the charset 'iso-8889-5' would get parsed
-- into: -- into:
@@ -28,7 +26,7 @@ feature -- Parser
create Result.make create Result.make
l_parts := header.split (';') l_parts := header.split (';')
if l_parts.count = 1 then if l_parts.count = 1 then
Result.put ("1.0", "q") Result.put ("1.0", "q")
else else
from from
i := 1 i := 1
@@ -38,16 +36,15 @@ feature -- Parser
p := l_parts.at (i) p := l_parts.at (i)
sub_parts := p.split ('=') sub_parts := p.split ('=')
if sub_parts.count = 2 then if sub_parts.count = 2 then
Result.put (trim (sub_parts[2]), trim (sub_parts[1])) Result.put (trim (sub_parts [2]), trim (sub_parts [1]))
end end
i := i + 1 i := i + 1
end end
end end
l_header := trim (l_parts[1]) l_header := trim (l_parts [1])
Result.set_field (trim (l_header)) Result.set_field (trim (l_header))
end end
fitness_and_quality_parsed (a_field: STRING; parsed_charsets: LIST [COMMON_RESULTS]): FITNESS_AND_QUALITY fitness_and_quality_parsed (a_field: STRING; parsed_charsets: LIST [COMMON_RESULTS]): FITNESS_AND_QUALITY
-- Find the best match for a given charset/encoding against a list of charsets/encodings -- 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 -- that have already been parsed by parse_common. Returns a
@@ -65,7 +62,7 @@ feature -- Parser
do do
best_fitness := -1 best_fitness := -1
best_fit_q := 0.0 best_fit_q := 0.0
target := parse_common(a_field) target := parse_common (a_field)
if attached target.item ("q") as q and then q.is_double then if attached target.item ("q") as q and then q.is_double then
target_q := q.to_double target_q := q.to_double
if target_q < 0.0 then if target_q < 0.0 then
@@ -76,9 +73,7 @@ feature -- Parser
else else
target_q := 1.0 target_q := 1.0
end end
if attached target.field as l_target_field then
if attached target.field as l_target_field
then
from from
parsed_charsets.start parsed_charsets.start
until until
@@ -86,7 +81,7 @@ feature -- Parser
loop loop
range := parsed_charsets.item_for_iteration range := parsed_charsets.item_for_iteration
if attached range.field as l_range_common then 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 ("*") then if l_target_field.same_string (l_range_common) or l_target_field.same_string ("*") or l_range_common.same_string ("*") then
if l_range_common.same_string (l_target_field) then if l_range_common.same_string (l_target_field) then
l_fitness := 100 l_fitness := 100
else else
@@ -109,7 +104,6 @@ feature -- Parser
create Result.make (best_fitness, best_fit_q) create Result.make (best_fitness, best_fit_q)
end end
quality_parsed (a_field: STRING; parsed_common: LIST [COMMON_RESULTS]): REAL_64 quality_parsed (a_field: STRING; parsed_common: LIST [COMMON_RESULTS]): REAL_64
-- Find the best match for a given charset/encoding against a list of charsets/encodings that -- 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 -- have already been parsed by parse_charsets(). Returns the 'q' quality
@@ -119,14 +113,13 @@ feature -- Parser
Result := fitness_and_quality_parsed (a_field, parsed_common).quality Result := fitness_and_quality_parsed (a_field, parsed_common).quality
end end
quality (a_field: STRING; commons: STRING): REAL_64 quality (a_field: STRING; commons: STRING): REAL_64
-- Returns the quality 'q' of a charset/encoding when compared against the -- Returns the quality 'q' of a charset/encoding when compared against the
-- a list of charsets/encodings/ -- a list of charsets/encodings/
local local
l_commons : LIST [STRING] l_commons: LIST [STRING]
res : ARRAYED_LIST [COMMON_RESULTS] res: ARRAYED_LIST [COMMON_RESULTS]
p_res : COMMON_RESULTS p_res: COMMON_RESULTS
do do
l_commons := commons.split (',') l_commons := commons.split (',')
from from
@@ -153,8 +146,6 @@ feature -- Parser
do do
l_res := header.split (',') l_res := header.split (',')
create {ARRAYED_LIST [COMMON_RESULTS]} l_header_results.make (l_res.count) create {ARRAYED_LIST [COMMON_RESULTS]} l_header_results.make (l_res.count)
from from
l_res.start l_res.start
until until
@@ -164,9 +155,7 @@ feature -- Parser
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 (supported.count)
from from
supported.start supported.start
until until
@@ -201,12 +190,16 @@ feature -- Parser
end end
weighted_matches.forth weighted_matches.forth
end end
check weighted_matches.item = fitness_and_quality end check
weighted_matches.item = fitness_and_quality
end
weighted_matches.forth weighted_matches.forth
elseif first_one.is_equal (fitness_and_quality) then elseif first_one.is_equal (fitness_and_quality) then
weighted_matches.forth weighted_matches.forth
else else
check first_one > fitness_and_quality end check
first_one > fitness_and_quality
end
weighted_matches.remove weighted_matches.remove
end end
end end
@@ -228,14 +221,16 @@ feature -- Parser
loop loop
fitness_and_quality := weighted_matches.item fitness_and_quality := weighted_matches.item
if fitness_and_quality.mime_type.same_string (l_field) then if fitness_and_quality.mime_type.same_string (l_field) then
--| Found --| Found
else else
fitness_and_quality := Void fitness_and_quality := Void
weighted_matches.forth weighted_matches.forth
end end
end end
else else
check has_field: False end check
has_field: False
end
end end
l_header_results.forth l_header_results.forth
end end
@@ -267,7 +262,7 @@ feature -- Util
trim (a_string: STRING): STRING trim (a_string: STRING): STRING
-- trim whitespace from the beginning and end of a string -- trim whitespace from the beginning and end of a string
require require
valid_argument : a_string /= Void valid_argument: a_string /= Void
do do
a_string.left_adjust a_string.left_adjust
a_string.right_justify a_string.right_justify
@@ -277,6 +272,7 @@ feature -- Util
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

View File

@@ -6,7 +6,9 @@ note
class class
COMMON_RESULTS COMMON_RESULTS
inherit inherit
ANY ANY
redefine redefine
out out
@@ -31,7 +33,6 @@ feature -- Access
field: detachable STRING field: detachable STRING
item (a_key: STRING): detachable STRING item (a_key: STRING): detachable STRING
-- Item associated with `a_key', if present -- Item associated with `a_key', if present
-- otherwise default value of type `STRING' -- otherwise default value of type `STRING'
@@ -57,15 +58,14 @@ feature -- Access
feature -- Element change feature -- Element change
set_field (a_field: STRING) set_field (a_field: STRING)
-- Set type with `a_charset' -- Set type with `a_charset'
do do
field := a_field field := a_field
ensure ensure
field_assigned: field ~ field field_assigned: field /= Void implies field = a_field
end end
put (new: STRING; key: STRING)
put (new: STRING; key: STRING)
-- Insert `new' with `key' if there is no other item -- Insert `new' with `key' if there is no other item
-- associated with the same key. If present, replace -- associated with the same key. If present, replace
-- the old value with `new' -- the old value with `new'
@@ -90,7 +90,6 @@ feature -- Status Report
Result.append_string ("'" + t + "',") Result.append_string ("'" + t + "',")
end end
Result.append_string (" {") Result.append_string (" {")
from from
params.start params.start
until until
@@ -113,7 +112,10 @@ feature {NONE} -- Implementation
params: HASH_TABLE [STRING, STRING] params: HASH_TABLE [STRING, STRING]
--dictionary of all the parameters for the media range --dictionary of all the parameters for the media range
;note ;
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -0,0 +1,59 @@
note
description: "Summary description for {COMPRESSION_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
EIS: "name= Compression", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
class
COMPRESSION_VARIANT_RESULTS
feature -- Access
compression_type: detachable STRING
variant_header: detachable STRING
supported_variants: detachable LIST [STRING]
is_acceptable: BOOLEAN
feature -- Change Element
set_compression_type (a_compression_type: STRING)
-- Set `compression_type' with `a_compression_type'
do
compression_type := a_compression_type
ensure
compression_type_set: compression_type /= Void implies a_compression_type = compression_type
end
set_variant_header
-- Set variant_header as `Accept-Encoding'
do
variant_header := "Accept-Encoding"
ensure
variant_header_set: attached variant_header as l_variant_header implies l_variant_header.same_string ("Accept-Encoding")
end
set_supported_variants (a_supported: LIST [STRING])
-- Set `supported_variants' with `a_supported'
do
supported_variants := a_supported
ensure
supported_variants_set: supported_variants /= Void implies supported_variants = a_supported
end
set_acceptable (acceptable: BOOLEAN)
-- Set `is_acceptable' with `acceptable'
do
is_acceptable := acceptable
ensure
is_acceptable_set: is_acceptable = acceptable
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

View File

@@ -11,129 +11,154 @@ note
Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent, 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). 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. 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 class
CONNEG_SERVER_SIDE CONNEG_SERVER_SIDE
inherit inherit
SHARED_CONNEG SHARED_CONNEG
REFACTORING_HELPER REFACTORING_HELPER
create create
make make
feature -- Initialization feature -- Initialization
make ( a_mime: STRING; a_language : STRING; a_charset :STRING; an_encoding: STRING)
make (a_mime: STRING; a_language: STRING; a_charset: STRING; a_encoding: STRING)
do do
set_mime_default (a_mime) set_mime_default (a_mime)
set_language_default (a_language) set_language_default (a_language)
set_charset_default (a_charset) set_charset_default (a_charset)
set_encoding_defautl (an_encoding) set_encoding_default (a_encoding)
ensure
mime_default_set: mime = a_mime
language_default_set: language_default = a_language
charset_default_set: charset_default = a_charset
encoding_default_set: encoding_default = a_encoding
end end
feature -- Server Side Defaults Formats
mime_default : STRING
set_mime_default ( a_mime: STRING) feature -- AccessServer Side Defaults Formats
-- set the mime_default with `a_mime'
mime_default: STRING
language_default: STRING
charset_default: STRING
encoding_default: STRING
set_encoding_defautl (an_encoding: STRING)
do
encoding_default := an_encoding
ensure
set_encoding: an_encoding ~ encoding_default
end
feature -- Change Element
set_mime_default (a_mime: STRING)
-- set the mime_default with `a_mime'
do do
mime_default := a_mime mime_default := a_mime
ensure ensure
set_mime_default: a_mime ~ mime_default set_mime_default: a_mime = mime_default
end end
set_language_default (a_language: STRING)
language_default : STRING
set_language_default (a_language : STRING)
-- set the language_default with `a_language' -- set the language_default with `a_language'
do do
language_default := a_language language_default := a_language
ensure ensure
set_language : a_language ~ language_default set_language: a_language = language_default
end end
set_charset_default (a_charset: STRING)
charset_default : STRING
set_charset_default (a_charset : STRING)
-- set the charset_default with `a_charset' -- set the charset_default with `a_charset'
do do
charset_default := a_charset charset_default := a_charset
ensure ensure
set_charset : a_charset ~ charset_default set_charset: a_charset = charset_default
end end
set_encoding_default (a_encoding: STRING)
encoding_default : STRING
set_encoding_defautl (an_encoding : STRING)
do do
encoding_default := an_encoding encoding_default := a_encoding
ensure ensure
set_encoding : an_encoding ~ encoding_default set_encoding: a_encoding = encoding_default
end end
feature -- Media Type Negotiation feature -- Media Type Negotiation
media_type_preference ( mime_types_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : MEDIA_TYPE_VARIANT_RESULTS media_type_preference (mime_types_supported: LIST [STRING]; header: detachable READABLE_STRING_8): MEDIA_TYPE_VARIANT_RESULTS
-- mime_types_supported represent media types supported by the server. -- mime_types_supported represent media types supported by the server.
-- header represent the Accept header, ie, the client preferences. -- header represent the Accept header, ie, the client preferences.
-- Return which media type to use for representaion in a response, if the server support -- Return which media type to use for representaion in a response, if the server support
-- one media type, or empty in other case. -- one media type, or empty in other case.
-- Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 note
EIS: "name=media type", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
local local
mime_match: STRING mime_match: STRING
do do
create Result create Result
if header = Void or else header.is_empty then if header = Void or else header.is_empty then
-- the request has no Accept header, ie the header is empty, in this case we use the default format -- 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_acceptable (TRUE)
Result.set_media_type (mime_default) Result.set_media_type (mime_default)
else else
-- select the best match, server support, client preferences -- select the best match, server support, client preferences
mime_match := mime.best_match (mime_types_supported, header) mime_match := mime.best_match (mime_types_supported, header)
if mime_match.is_empty then if mime_match.is_empty then
-- The server does not support any of the media types prefered by the client -- The server does not support any of the media types prefered by the client
Result.set_acceptable (False) Result.set_acceptable (False)
Result.set_supported_variants (mime_types_supported) Result.set_supported_variants (mime_types_supported)
else else
-- Set the best match -- Set the best match
Result.set_media_type(mime_match) Result.set_media_type (mime_match)
Result.set_acceptable (True) Result.set_acceptable (True)
Result.set_variant_header Result.set_variant_header
end end
end end
end end
feature -- Encoding Negotiation feature -- Encoding Negotiation
charset_preference (server_charset_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : CHARACTER_ENCODING_VARIANT_RESULTS charset_preference (server_charset_supported: LIST [STRING]; header: detachable READABLE_STRING_8): CHARACTER_ENCODING_VARIANT_RESULTS
-- server_charset_supported represent a list of charset supported by the server. -- server_charset_supported represent a list of charset supported by the server.
-- header represent the Accept-Charset header, ie, the client preferences. -- header represent the Accept-Charset header, ie, the client preferences.
-- Return which Charset to use in a response, if the server support -- Return which Charset to use in a response, if the server support
-- one Charset, or empty in other case. -- one Charset, or empty in other case.
-- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2 note
EIS: "name=charset", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2", "protocol=uri"
local local
charset_match : STRING charset_match: STRING
do do
create Result create Result
if header = Void or else header.is_empty then if header = Void or else header.is_empty then
-- the request has no Accept-Charset header, ie the header is empty, in this case use default charset encoding -- the request has no Accept-Charset header, ie the header is empty, in this case use default charset encoding
-- (UTF-8) -- (UTF-8)
Result.set_acceptable (TRUE) Result.set_acceptable (TRUE)
Result.set_character_type (charset_default) Result.set_character_type (charset_default)
else else
-- select the best match, server support, client preferences -- select the best match, server support, client preferences
charset_match := common.best_match (server_charset_supported, header) charset_match := common.best_match (server_charset_supported, header)
if charset_match.is_empty then if charset_match.is_empty then
-- The server does not support any of the compression types prefered by the client -- The server does not support any of the compression types prefered by the client
Result.set_acceptable (False) Result.set_acceptable (False)
Result.set_supported_variants (server_charset_supported) Result.set_supported_variants (server_charset_supported)
else else
-- Set the best match -- Set the best match
Result.set_character_type(charset_match) Result.set_character_type (charset_match)
Result.set_acceptable (True) Result.set_acceptable (True)
Result.set_variant_header Result.set_variant_header
end end
@@ -142,75 +167,74 @@ feature -- Encoding Negotiation
feature -- Compression Negotiation feature -- Compression Negotiation
encoding_preference (server_encoding_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : COMPRESSION_VARIANT_RESULTS encoding_preference (server_encoding_supported: LIST [STRING]; header: detachable READABLE_STRING_8): COMPRESSION_VARIANT_RESULTS
-- server_encoding_supported represent a list of encoding supported by the server. -- server_encoding_supported represent a list of encoding supported by the server.
-- header represent the Accept-Encoding header, ie, the client preferences. -- header represent the Accept-Encoding header, ie, the client preferences.
-- Return which Encoding to use in a response, if the server support -- Return which Encoding to use in a response, if the server support
-- one Encoding, or empty in other case. -- one Encoding, or empty in other case.
-- Representation: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 note
EIS: "name=encoding", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3", "protocol=uri"
local local
compression_match : STRING compression_match: STRING
do do
create Result create Result
if header = Void or else header.is_empty then if header = Void or else header.is_empty then
-- the request has no Accept-Encoding header, ie the header is empty, in this case do not compress representations -- 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_acceptable (TRUE)
Result.set_compression_type (encoding_default) Result.set_compression_type (encoding_default)
else else
-- select the best match, server support, client preferences -- select the best match, server support, client preferences
compression_match := common.best_match (server_encoding_supported, header) compression_match := common.best_match (server_encoding_supported, header)
if compression_match.is_empty then if compression_match.is_empty then
-- The server does not support any of the compression types prefered by the client -- The server does not support any of the compression types prefered by the client
Result.set_acceptable (False) Result.set_acceptable (False)
Result.set_supported_variants (server_encoding_supported) Result.set_supported_variants (server_encoding_supported)
else else
-- Set the best match -- Set the best match
Result.set_compression_type(compression_match) Result.set_compression_type (compression_match)
Result.set_acceptable (True) Result.set_acceptable (True)
Result.set_variant_header Result.set_variant_header
end end
end end
end end
feature -- Language Negotiation feature -- Language Negotiation
language_preference (server_language_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : LANGUAGE_VARIANT_RESULTS language_preference (server_language_supported: LIST [STRING]; header: detachable READABLE_STRING_8): LANGUAGE_VARIANT_RESULTS
-- server_language_supported represent a list of languages supported by the server. -- server_language_supported represent a list of languages supported by the server.
-- header represent the Accept-Language header, ie, the client preferences. -- header represent the Accept-Language header, ie, the client preferences.
-- Return which Language to use in a response, if the server support -- Return which Language to use in a response, if the server support
-- one Language, or empty in other case. -- one Language, or empty in other case.
-- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 note
EIS: "name=language", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4", "protocol=uri"
local local
language_match: STRING language_match: STRING
do do
create Result create Result
if header = Void or else header.is_empty then if header = Void or else header.is_empty then
-- the request has no Accept header, ie the header is empty, in this case we use the default format -- 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_acceptable (TRUE)
Result.set_language_type (language_default) Result.set_language_type (language_default)
else else
-- select the best match, server support, client preferences -- select the best match, server support, client preferences
language_match := language.best_match (server_language_supported, header) language_match := language.best_match (server_language_supported, header)
if language_match.is_empty then if language_match.is_empty then
-- The server does not support any of the media types prefered by the client -- The server does not support any of the media types prefered by the client
Result.set_acceptable (False) Result.set_acceptable (False)
Result.set_supported_variants (server_language_supported) Result.set_supported_variants (server_language_supported)
else else
-- Set the best match -- Set the best match
Result.set_language_type(language_match) Result.set_language_type (language_match)
Result.set_acceptable (True) Result.set_acceptable (True)
Result.set_variant_header Result.set_variant_header
end end
end end
end end
feature -- Apache Conneg Algorithm
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

View File

@@ -3,11 +3,13 @@ note
author: "" author: ""
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
description : "Language Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4" description: "Language Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4"
class class
LANGUAGE_PARSE LANGUAGE_PARSE
inherit inherit
REFACTORING_HELPER REFACTORING_HELPER
feature -- Parser feature -- Parser
@@ -36,23 +38,23 @@ feature -- Parser
p := l_parts.at (i) p := l_parts.at (i)
sub_parts := p.split ('=') sub_parts := p.split ('=')
if sub_parts.count = 2 then if sub_parts.count = 2 then
Result.put (trim (sub_parts[2]), trim (sub_parts[1])) Result.put (trim (sub_parts [2]), trim (sub_parts [1]))
end end
i := i + 1 i := i + 1
end end
--Java URLConnection class sends an Accept header that includes a --Java URLConnection class sends an Accept header that includes a
--single "*" - Turn it into a legal wildcard. --single "*" - Turn it into a legal wildcard.
l_full_type := trim (l_parts[1]) l_full_type := trim (l_parts [1])
if l_full_type.same_string ("*") then if l_full_type.same_string ("*") then
l_full_type := "*" l_full_type := "*"
end end
l_types := l_full_type.split ('-') l_types := l_full_type.split ('-')
if l_types.count = 1 then if l_types.count = 1 then
Result.set_type (trim (l_types[1])) Result.set_type (trim (l_types [1]))
else else
Result.set_type (trim (l_types[1])) Result.set_type (trim (l_types [1]))
Result.set_sub_type (trim (l_types[2])) Result.set_sub_type (trim (l_types [2]))
end end
end end
@@ -67,12 +69,8 @@ feature -- Parser
fixme ("Improve the code!!!") fixme ("Improve the code!!!")
Result := parse_mime_type (a_range) Result := parse_mime_type (a_range)
if attached Result.item ("q") as q then if attached Result.item ("q") as q then
if if q.is_double and then attached {REAL_64} q.to_double as r and then (r >= 0.0 and r <= 1.0) then
q.is_double and then --| Keep current value
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 if q.same_string ("1") then
--| Use 1.0 formatting --| Use 1.0 formatting
Result.put ("1.0", "q") Result.put ("1.0", "q")
@@ -85,7 +83,6 @@ feature -- Parser
end end
end end
fitness_and_quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [LANGUAGE_RESULTS]): FITNESS_AND_QUALITY fitness_and_quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [LANGUAGE_RESULTS]): FITNESS_AND_QUALITY
-- Find the best match for a given mimeType against a list of media_ranges -- Find the best match for a given mimeType against a list of media_ranges
-- that have already been parsed by parse_media_range. Returns a -- that have already been parsed by parse_media_range. Returns a
@@ -116,22 +113,14 @@ feature -- Parser
else else
target_q := 1.0 target_q := 1.0
end end
if attached target.type as l_target_type then
if
attached target.type as l_target_type
then
from from
parsed_ranges.start parsed_ranges.start
until until
parsed_ranges.after parsed_ranges.after
loop loop
range := parsed_ranges.item_for_iteration range := parsed_ranges.item_for_iteration
if 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
(
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 from
param_matches := 0 param_matches := 0
keys := target.keys keys := target.keys
@@ -140,33 +129,22 @@ feature -- Parser
keys.after keys.after
loop loop
element := keys.item_for_iteration element := keys.item_for_iteration
if 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
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 param_matches := param_matches + 1
end end
keys.forth keys.forth
end end
if l_range_type.same_string (l_target_type) then if l_range_type.same_string (l_target_type) then
l_fitness := 100 l_fitness := 100
else else
l_fitness := 0 l_fitness := 0
end end
if ( 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
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 if l_range_sub_type.same_string (l_target_sub_type) then
l_fitness := l_fitness + 10 l_fitness := l_fitness + 10
end end
end end
l_fitness := l_fitness + param_matches l_fitness := l_fitness + param_matches
if l_fitness > best_fitness then if l_fitness > best_fitness then
best_fitness := l_fitness best_fitness := l_fitness
element := range.item ("q") element := range.item ("q")
@@ -197,9 +175,9 @@ feature -- Parser
-- 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.
local local
l_ranges : LIST [STRING] l_ranges: LIST [STRING]
res : ARRAYED_LIST [LANGUAGE_RESULTS] res: ARRAYED_LIST [LANGUAGE_RESULTS]
p_res : LANGUAGE_RESULTS p_res: LANGUAGE_RESULTS
do do
l_ranges := ranges.split (',') l_ranges := ranges.split (',')
from from
@@ -227,8 +205,7 @@ feature -- Parser
do do
l_res := header.split (',') l_res := header.split (',')
create {ARRAYED_LIST [LANGUAGE_RESULTS]} l_header_results.make (l_res.count) create {ARRAYED_LIST [LANGUAGE_RESULTS]} l_header_results.make (l_res.count)
fixme ("Extract method!!!")
fixme("Extract method!!!")
from from
l_res.start l_res.start
until until
@@ -238,9 +215,7 @@ feature -- Parser
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 (supported.count)
from from
supported.start supported.start
until until
@@ -274,12 +249,16 @@ feature -- Parser
end end
weighted_matches.forth weighted_matches.forth
end end
check weighted_matches.item = fitness_and_quality end check
weighted_matches.item = fitness_and_quality
end
weighted_matches.forth weighted_matches.forth
elseif first_one.is_equal (fitness_and_quality) then elseif first_one.is_equal (fitness_and_quality) then
weighted_matches.forth weighted_matches.forth
else else
check first_one > fitness_and_quality end check
first_one > fitness_and_quality
end
weighted_matches.remove weighted_matches.remove
end end
end end
@@ -301,7 +280,7 @@ feature -- Parser
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.mime_type.same_string (s) then
--| Found --| Found
else else
fitness_and_quality := Void fitness_and_quality := Void
weighted_matches.forth weighted_matches.forth
@@ -337,7 +316,7 @@ feature {NONE} -- Implementation
trim (a_string: STRING): STRING trim (a_string: STRING): STRING
-- trim whitespace from the beginning and end of a string -- trim whitespace from the beginning and end of a string
require require
valid_argument : a_string /= Void valid_argument: a_string /= Void
do do
a_string.left_adjust a_string.left_adjust
a_string.right_justify a_string.right_justify
@@ -347,6 +326,7 @@ feature {NONE} -- Implementation
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

View File

@@ -6,7 +6,9 @@ note
class class
LANGUAGE_RESULTS LANGUAGE_RESULTS
inherit inherit
ANY ANY
redefine redefine
out out
@@ -61,7 +63,7 @@ feature -- Access
feature -- Element change feature -- Element change
set_type (a_type: STRING) set_type (a_type: STRING)
-- Set type with `a_type' -- Set type with `a_type'
do do
type := a_type type := a_type
if attached sub_type as st then if attached sub_type as st then
@@ -74,7 +76,7 @@ feature -- Element change
end end
set_sub_type (a_sub_type: STRING) set_sub_type (a_sub_type: STRING)
-- Set sub_type with `a_sub_type -- Set sub_type with `a_sub_type
do do
sub_type := a_sub_type sub_type := a_sub_type
if attached type as t then if attached type as t then
@@ -86,7 +88,7 @@ feature -- Element change
sub_type_assigned: sub_type ~ a_sub_type sub_type_assigned: sub_type ~ a_sub_type
end end
put (new: STRING; key: STRING) put (new: STRING; key: STRING)
-- Insert `new' with `key' if there is no other item -- Insert `new' with `key' if there is no other item
-- associated with the same key. If present, replace -- associated with the same key. If present, replace
-- the old value with `new' -- the old value with `new'
@@ -114,7 +116,6 @@ feature -- Status Report
Result.append_string (" '" + st + "',") Result.append_string (" '" + st + "',")
end end
Result.append_string (" {") Result.append_string (" {")
from from
params.start params.start
until until
@@ -137,7 +138,10 @@ feature {NONE} -- Implementation
params: HASH_TABLE [STRING, STRING] params: HASH_TABLE [STRING, STRING]
--dictionary of all the parameters for the media range --dictionary of all the parameters for the media range
;note ;
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -0,0 +1,63 @@
note
description: "Summary description for {LANGUAGE_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
LANGUAGE_VARIANT_RESULTS
feature -- Access
language_type: detachable STRING
variant_header: detachable STRING
supported_variants: detachable LIST [STRING]
is_acceptable: BOOLEAN
feature -- Change Element
set_acceptable (acceptable: BOOLEAN)
-- Set `is_acceptable' with `acceptable'
do
is_acceptable := acceptable
ensure
is_acceptable_set: is_acceptable = acceptable
end
set_language_type (a_language_type: STRING)
-- Set `language_type' with `a_language_type'
do
language_type := a_language_type
ensure
language_type_set: language_type/= Void implies a_language_type = language_type
end
set_variant_header
-- Set variant header as 'Accept-Language'
do
variant_header := "Accept-Language"
ensure
variant_header_set: attached variant_header as l_variant_header implies l_variant_header.same_string ("Accept-Language")
end
set_supported_variants (a_supported: LIST [STRING])
-- Set `supported vairants' with `a_supported'
do
supported_variants := a_supported
ensure
set_supported_variants: supported_variants /= Void implies 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

View File

@@ -0,0 +1,62 @@
note
description: "Summary description for {MEDIA_TYPE_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
MEDIA_TYPE_VARIANT_RESULTS
feature -- Access
media_type: detachable STRING
variant_header: detachable STRING
supported_variants: detachable LIST [STRING]
is_acceptable: BOOLEAN
feature -- Change Element
set_media_type (a_media_type: STRING)
-- Set `media_type' as `a_media_type'
do
media_type := a_media_type
ensure
media_type_set: media_type /= Void implies media_type = a_media_type
end
set_variant_header
-- Set variant header as `Accept'
do
variant_header := "Accept"
ensure
variant_header_set: attached variant_header as l_variant_header implies l_variant_header.same_string ("Accept")
end
set_supported_variants (a_supported: LIST [STRING])
-- Set `supported_variants' with `a_supported'
do
supported_variants := a_supported
ensure
supported_variants_variants: supported_variants /= Void implies supported_variants = a_supported
end
set_acceptable (acceptable: BOOLEAN)
-- Set `is_acceptable' with `acceptable'
do
is_acceptable := acceptable
ensure
is_acceptable_set: is_acceptable = acceptable
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

View File

@@ -3,7 +3,7 @@
author: "" author: ""
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
description : "Accept Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1" EIS: "name=Accept", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1", "protocol=uri"
class class
MIME_PARSE MIME_PARSE
@@ -12,47 +12,16 @@ inherit
feature -- Parser feature -- Parser
parse_mime_type (a_mime_type: STRING): PARSE_RESULTS parse_mime_type (a_mime_type: STRING): HTTP_MEDIA_TYPE
-- Parses a mime-type into its component parts. -- Parses a mime-type into its component parts.
-- For example, the media range 'application/xhtml;q=0.5' would get parsed -- For example, the media range 'application/xhtml;q=0.5' would get parsed
-- into: -- into:
-- ('application', 'xhtml', {'q', '0.5'}) -- ('application', 'xhtml', {'q', '0.5'})
local
l_parts: LIST [STRING]
p: STRING
sub_parts: LIST [STRING]
i: INTEGER
l_full_type: STRING
l_types: LIST [STRING]
do do
fixme ("Improve code!!!") create Result.make_from_string (a_mime_type)
create Result.make
l_parts := a_mime_type.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
--Java URLConnection class sends an Accept header that includes a
--single "*" - Turn it into a legal wildcard.
l_full_type := trim (l_parts[1])
if l_full_type.same_string ("*") then
l_full_type := "*/*"
end
l_types := l_full_type.split ('/')
Result.set_type (trim (l_types[1]))
Result.set_sub_type (trim (l_types[2]))
end end
parse_media_range (a_range: STRING): PARSE_RESULTS parse_media_range (a_range: STRING): 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'})
@@ -62,7 +31,7 @@ feature -- Parser
do do
fixme ("Improve the code!!!") fixme ("Improve the code!!!")
Result := parse_mime_type (a_range) Result := parse_mime_type (a_range)
if attached Result.item ("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_double as r and then
@@ -71,18 +40,18 @@ feature -- Parser
--| Keep current value --| Keep current value
if q.same_string ("1") then if q.same_string ("1") then
--| Use 1.0 formatting --| Use 1.0 formatting
Result.put ("1.0", "q") Result.add_parameter ("q", "1.0")
end end
else else
Result.put ("1.0", "q") Result.add_parameter ("q", "1.0")
end end
else else
Result.put ("1.0", "q") Result.add_parameter ("q", "1.0")
end end
end end
fitness_and_quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [PARSE_RESULTS]): FITNESS_AND_QUALITY fitness_and_quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [HTTP_MEDIA_TYPE]): FITNESS_AND_QUALITY
-- Find the best match for a given mimeType against a list of media_ranges -- Find the best match for a given mimeType against a list of media_ranges
-- that have already been parsed by parse_media_range. Returns a -- that have already been parsed by parse_media_range. Returns a
-- tuple of the fitness value and the value of the 'q' quality parameter of -- tuple of the fitness value and the value of the 'q' quality parameter of
@@ -92,17 +61,16 @@ feature -- Parser
best_fitness: INTEGER best_fitness: INTEGER
target_q: REAL_64 target_q: REAL_64
best_fit_q: REAL_64 best_fit_q: REAL_64
target: PARSE_RESULTS target: HTTP_MEDIA_TYPE
range: PARSE_RESULTS range: HTTP_MEDIA_TYPE
keys: LIST [STRING]
param_matches: INTEGER param_matches: INTEGER
element: detachable STRING element: detachable READABLE_STRING_8
l_fitness: INTEGER l_fitness: INTEGER
do do
best_fitness := -1 best_fitness := -1
best_fit_q := 0.0 best_fit_q := 0.0
target := parse_media_range (a_mime_type) target := parse_media_range (a_mime_type)
if attached target.item ("q") as q and then q.is_double then if attached target.parameter ("q") as q and then q.is_double then
target_q := q.to_double target_q := q.to_double
if target_q < 0.0 then if target_q < 0.0 then
target_q := 0.0 target_q := 0.0
@@ -115,7 +83,7 @@ feature -- Parser
if if
attached target.type as l_target_type and attached target.type as l_target_type and
attached target.sub_type as l_target_sub_type attached target.subtype as l_target_sub_type
then then
from from
parsed_ranges.start parsed_ranges.start
@@ -129,29 +97,29 @@ feature -- Parser
(l_target_type.same_string (l_range_type) or l_range_type.same_string ("*") or l_target_type.same_string ("*")) (l_target_type.same_string (l_range_type) or l_range_type.same_string ("*") or l_target_type.same_string ("*"))
) and ) and
( (
attached range.sub_type as l_range_sub_type and then 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 ("*")) (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 then
from if attached target.parameters as l_keys then
param_matches := 0 from
keys := target.keys param_matches := 0
keys.start l_keys.start
until until
keys.after l_keys.after
loop loop
element := keys.item_for_iteration element := l_keys.key_for_iteration
if if
not element.same_string ("q") and then not element.same_string ("q") and then
range.has_key (element) and then range.has_parameter (element) and then
(attached target.item (element) as t_item and attached range.item (element) as r_item) 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) t_item.same_string (r_item)
then then
param_matches := param_matches + 1 param_matches := param_matches + 1
end
l_keys.forth
end end
keys.forth
end end
if l_range_type.same_string (l_target_type) then if l_range_type.same_string (l_target_type) then
l_fitness := 100 l_fitness := 100
else else
@@ -166,7 +134,7 @@ feature -- Parser
if l_fitness > best_fitness then if l_fitness > best_fitness then
best_fitness := l_fitness best_fitness := l_fitness
element := range.item ("q") element := range.parameter ("q")
if element /= Void then if element /= Void then
best_fit_q := element.to_double.min (target_q) best_fit_q := element.to_double.min (target_q)
else else
@@ -180,7 +148,7 @@ feature -- Parser
create Result.make (best_fitness, best_fit_q) create Result.make (best_fitness, best_fit_q)
end end
quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [PARSE_RESULTS]): REAL_64 quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [HTTP_MEDIA_TYPE]): REAL_64
-- Find the best match for a given mime-type against a list of ranges that -- Find the best match for a given mime-type against a list of ranges that
-- have already been parsed by parseMediaRange(). Returns the 'q' quality -- have already been parsed by parseMediaRange(). Returns the 'q' quality
-- parameter of the best match, 0 if no match was found. This function -- parameter of the best match, 0 if no match was found. This function
@@ -195,8 +163,8 @@ feature -- Parser
-- mediaRanges in ranges. -- mediaRanges in ranges.
local local
l_ranges : LIST [STRING] l_ranges : LIST [STRING]
res : ARRAYED_LIST [PARSE_RESULTS] res : ARRAYED_LIST [HTTP_MEDIA_TYPE]
p_res : PARSE_RESULTS p_res : HTTP_MEDIA_TYPE
do do
l_ranges := ranges.split (',') l_ranges := ranges.split (',')
from from
@@ -215,15 +183,15 @@ feature -- Parser
best_match (supported: LIST [STRING]; header: STRING): STRING best_match (supported: LIST [STRING]; header: STRING): STRING
-- 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 [PARSE_RESULTS] l_header_results: LIST [HTTP_MEDIA_TYPE]
weighted_matches: LIST [FITNESS_AND_QUALITY] weighted_matches: LIST [FITNESS_AND_QUALITY]
l_res: LIST [STRING] l_res: LIST [STRING]
p_res: PARSE_RESULTS p_res: HTTP_MEDIA_TYPE
fitness_and_quality, first_one: detachable FITNESS_AND_QUALITY fitness_and_quality, first_one: detachable FITNESS_AND_QUALITY
s: STRING s: STRING
do do
l_res := header.split (',') l_res := header.split (',')
create {ARRAYED_LIST [PARSE_RESULTS]} l_header_results.make (l_res.count) create {ARRAYED_LIST [HTTP_MEDIA_TYPE]} l_header_results.make (l_res.count)
fixme("Extract method!!!") fixme("Extract method!!!")
from from
@@ -290,7 +258,7 @@ feature -- Parser
until until
l_header_results.after or fitness_and_quality /= Void l_header_results.after or fitness_and_quality /= Void
loop loop
s := l_header_results.item.mime_type s := l_header_results.item.simple_type
from from
weighted_matches.start weighted_matches.start
until until
@@ -344,6 +312,6 @@ feature {NONE} -- Implementation
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

View File

@@ -8,6 +8,7 @@ class
PARSE_RESULTS PARSE_RESULTS
inherit inherit
ANY ANY
redefine redefine
out out
@@ -62,7 +63,7 @@ feature -- Access
feature -- Element change feature -- Element change
set_type (a_type: STRING) set_type (a_type: STRING)
-- Set type with `a_type' -- Set type with `a_type'
do do
type := a_type type := a_type
if attached sub_type as st then if attached sub_type as st then
@@ -75,7 +76,7 @@ feature -- Element change
end end
set_sub_type (a_sub_type: STRING) set_sub_type (a_sub_type: STRING)
-- Set sub_type with `a_sub_type -- Set sub_type with `a_sub_type
do do
sub_type := a_sub_type sub_type := a_sub_type
if attached type as t then if attached type as t then
@@ -87,7 +88,7 @@ feature -- Element change
sub_type_assigned: sub_type ~ a_sub_type sub_type_assigned: sub_type ~ a_sub_type
end end
put (new: STRING; key: STRING) put (new: STRING; key: STRING)
-- Insert `new' with `key' if there is no other item -- Insert `new' with `key' if there is no other item
-- associated with the same key. If present, replace -- associated with the same key. If present, replace
-- the old value with `new' -- the old value with `new'
@@ -115,7 +116,6 @@ feature -- Status Report
Result.append_string (" '" + st + "',") Result.append_string (" '" + st + "',")
end end
Result.append_string (" {") Result.append_string (" {")
from from
params.start params.start
until until
@@ -138,7 +138,10 @@ feature {NONE} -- Implementation
params: HASH_TABLE [STRING, STRING] params: HASH_TABLE [STRING, STRING]
--dictionary of all the parameters for the media range --dictionary of all the parameters for the media range
;note ;
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -1,5 +1,5 @@
note note
description: "Summary description for {SHARED_MIME}." description: "Summary description for {SHARED_CONNEG}."
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
@@ -8,23 +8,24 @@ class
feature feature
mime: MIME_PARSE Mime: MIME_PARSE
once once
create Result create Result
end end
common: COMMON_ACCEPT_HEADER_PARSER Common: COMMON_ACCEPT_HEADER_PARSER
-- Charset and Encoding -- Charset and Encoding
once once
create Result create Result
end end
language: LANGUAGE_PARSE Language: LANGUAGE_PARSE
once once
create Result create Result
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

View File

@@ -0,0 +1,55 @@
note
description: "Summary description for {VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
VARIANT_RESULTS
feature -- Mime, Language, Charset and Encoding Results
mime_result: detachable STRING
set_mime_result (a_mime: STRING)
-- set the mime_result with `a_mime'
do
mime_result := a_mime
ensure
set_mime_result: a_mime = mime_result
end
language_result: detachable STRING
set_language_result (a_language: STRING)
-- set the language_result with `a_language'
do
language_result := a_language
ensure
set_language: a_language = language_result
end
charset_result: detachable STRING
set_charset_result (a_charset: STRING)
-- set the charset_result with `a_charset'
do
charset_result := a_charset
ensure
set_charset: a_charset = charset_result
end
encoding_result: detachable STRING
set_encoding_default (an_encoding: STRING)
do
encoding_result := an_encoding
ensure
set_encoding: an_encoding = encoding_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

View File

@@ -28,15 +28,15 @@ feature -- Test routines
test_parse_media_range test_parse_media_range
do do
assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml;q=1").out.same_string("('application', 'xml', {'q':'1.0',})") ) assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml;q=1").format.same_string("('application', 'xml', {'q':'1.0',})") )
assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml").out.same_string("('application', 'xml', {'q':'1.0',})") ) assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml").format.same_string("('application', 'xml', {'q':'1.0',})") )
assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml;q=").out.same_string("('application', 'xml', {'q':'1.0',})") ) assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml;q=").format.same_string("('application', 'xml', {'q':'1.0',})") )
assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml ; q=").out.same_string("('application', 'xml', {'q':'1.0',})") ) assert ("Expected ('application', 'xml', {'q':'1',})", parser.parse_media_range("application/xml ; q=").format.same_string("('application', 'xml', {'q':'1.0',})") )
assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", parser.parse_media_range("application/xml ; q=1;b=other").out.same_string("('application', 'xml', {'q':'1.0','b':'other',})") ) assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", parser.parse_media_range("application/xml ; q=1;b=other").format.same_string("('application', 'xml', {'q':'1.0','b':'other',})") )
assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", parser.parse_media_range("application/xml ; q=2;b=other").out.same_string("('application', 'xml', {'q':'1.0','b':'other',})") ) assert ("Expected ('application', 'xml', {'q':'1','b':'other',})", parser.parse_media_range("application/xml ; q=2;b=other").format.same_string("('application', 'xml', {'q':'1.0','b':'other',})") )
-- Accept header that includes * -- Accept header that includes *
assert ("Expected ('*', '*', {'q':'.2',})", parser.parse_media_range(" *; q=.2").out.same_string("('*', '*', {'q':'.2',})")) assert ("Expected ('*', '*', {'q':'.2',})", parser.parse_media_range(" *; q=.2").format.same_string("('*', '*', {'q':'.2',})"))
end end

View File

@@ -97,9 +97,9 @@ feature {NONE} -- Initialization
-- Extract type and subtype -- Extract type and subtype
p := t.index_of ('/', 1) p := t.index_of ('/', 1)
if p = 0 then if p = 0 then
has_error := True --| Accept *; should be */*
type := t type := t
subtype := "" subtype := "*"
else else
subtype := t.substring (p + 1, t.count) subtype := t.substring (p + 1, t.count)
type := t type := t
@@ -368,6 +368,30 @@ feature -- Status report
end end
end end
format : STRING
-- Representation of the current object
do
create Result.make_from_string ("(")
if attached type as t then
Result.append_string ("'" + t + "',")
end
if attached subtype as st then
Result.append_string (" '" + st + "',")
end
Result.append_string (" {")
if attached parameters as l_params then
from
l_params.start
until
l_params.after
loop
Result.append ("'" + l_params.key_for_iteration + "':'" + l_params.item_for_iteration + "',");
l_params.forth
end
end
Result.append ("})")
end
invariant invariant
type_and_subtype_not_empty: not has_error implies not type.is_empty and not subtype.is_empty type_and_subtype_not_empty: not has_error implies not type.is_empty and not subtype.is_empty