restructured CONNEG library
fixed various issue in .ecf files
This commit is contained in:
282
library/protocol/CONNEG/src/common_accept_header_parser.e
Normal file
282
library/protocol/CONNEG/src/common_accept_header_parser.e
Normal file
@@ -0,0 +1,282 @@
|
||||
note
|
||||
description: "COMMON_ACCEPT_HEADER_PARSER, this class allows to parse Accept-Charset and Accept-Encoding headers"
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
description : "[
|
||||
Charset Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
|
||||
Encoding Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
|
||||
]"
|
||||
|
||||
class
|
||||
COMMON_ACCEPT_HEADER_PARSER
|
||||
|
||||
|
||||
feature -- Parser
|
||||
parse_common (header: STRING): 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 [STRING]
|
||||
sub_parts: LIST [STRING]
|
||||
p: STRING
|
||||
i: INTEGER
|
||||
l_header: STRING
|
||||
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: STRING; 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 STRING
|
||||
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 ("*") 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: STRING; 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: STRING; commons: STRING): REAL_64
|
||||
-- Returns the quality 'q' of a charset/encoding when compared against the
|
||||
-- a list of charsets/encodings/
|
||||
local
|
||||
l_commons : LIST [STRING]
|
||||
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 [STRING]; header: STRING): STRING
|
||||
-- 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 [STRING]
|
||||
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
|
||||
|
||||
feature -- Util
|
||||
|
||||
mime_type (s: STRING): STRING
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := s.index_of (';', 1)
|
||||
if p > 0 then
|
||||
Result := trim (s.substring (1, p - 1))
|
||||
else
|
||||
Result := trim (s.string)
|
||||
end
|
||||
end
|
||||
|
||||
trim (a_string: STRING): STRING
|
||||
-- trim whitespace from the beginning and end of a string
|
||||
require
|
||||
valid_argument : a_string /= Void
|
||||
do
|
||||
a_string.left_adjust
|
||||
a_string.right_justify
|
||||
Result := a_string
|
||||
ensure
|
||||
result_same_as_argument: a_string = 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
|
||||
Reference in New Issue
Block a user