Merge branch 'master' into handler
pull from upstream
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
note
|
||||
description: "Objects to access the shared once WSF_PERCENT_ENCODER ..."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
percent_encoder: WSF_PERCENT_ENCODER
|
||||
-- Shared Percent encoding engine.
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, 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
|
||||
523
library/server/wsf/src/implementation/wsf_percent_encoder.e
Normal file
523
library/server/wsf/src/implementation/wsf_percent_encoder.e
Normal file
@@ -0,0 +1,523 @@
|
||||
note
|
||||
description: "[
|
||||
Component to handle percent encoding
|
||||
]"
|
||||
date: "$Date: 2013-05-21 01:15:17 +0200 (mar., 21 mai 2013) $"
|
||||
revision: "$Revision: 92557 $"
|
||||
EIS: "name=Percent-encoding", "protocol=URI", "src=http://en.wikipedia.org/wiki/Percent-encoding"
|
||||
|
||||
class
|
||||
WSF_PERCENT_ENCODER
|
||||
|
||||
feature -- Percent encoding
|
||||
|
||||
percent_encoded_string (v: READABLE_STRING_GENERAL): STRING_8
|
||||
-- Return `a_string' percent-encoded
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_encoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append `a_string' as percent-encoded value to `a_result'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i,n: INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := s.code (i)
|
||||
if
|
||||
--| unreserved ALPHA / DIGIT
|
||||
(48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
or (65 <= c and c <= 90) -- ALPHA: A .. Z
|
||||
or (97 <= c and c <= 122) -- ALPHA: a .. z
|
||||
then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
inspect c
|
||||
when
|
||||
45, 46, 95, 126 -- unreserved characters: -._~
|
||||
then
|
||||
a_result.append_code (c)
|
||||
when
|
||||
58, 64, -- reserved =+ gen-delims: :@
|
||||
33, 36, 38, 39, 40, 41, 42, -- reserved =+ sub-delims: !$&'()*
|
||||
43, 44, 59, 61, -- reserved = sub-delims: +,;=
|
||||
37 -- percent encoding: %
|
||||
then
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Percent encoding: character
|
||||
|
||||
append_percent_encoded_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append character code `a_code' as percent-encoded content into `a_result'
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
elseif a_code > 0x7F then
|
||||
-- Extended ASCII
|
||||
-- This requires percent-encoding on UTF-8 converted character.
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- ASCII
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: character encoding
|
||||
|
||||
append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append extended ascii character code `a_code' as percent-encoded content into `a_result'
|
||||
-- Note: it does not UTF-8 convert this extended ASCII.
|
||||
require
|
||||
is_extended_ascii: a_code <= 0xFF
|
||||
local
|
||||
c: INTEGER
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- Extended ASCII
|
||||
c := a_code.to_integer_32
|
||||
a_result.append_code (37) -- 37 '%%'
|
||||
a_result.append_code (hex_digit [c |>> 4])
|
||||
a_result.append_code (hex_digit [c & 0xF])
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
append_percent_encoded_unicode_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append Unicode character code `a_code' as UTF-8 and percent-encoded content into `a_result'
|
||||
-- Note: it does include UTF-8 conversion of extended ASCII and Unicode.
|
||||
do
|
||||
if a_code <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
elseif a_code <= 0x7FF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 6) | 0xC0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
elseif a_code <= 0xFFFF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 12) | 0xE0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
else
|
||||
-- c <= 1FFFFF - there are no higher code points
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 18) | 0xF0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 12) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature -- Percent decoding
|
||||
|
||||
percent_decoded_string (v: READABLE_STRING_GENERAL): STRING_32
|
||||
-- Return the percent decoded string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_decoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_decoded_string_to (v: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append to `a_result' a string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
local
|
||||
i,n: INTEGER
|
||||
c: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
a_result_is_string_32: BOOLEAN
|
||||
do
|
||||
a_result_is_string_32 := attached {STRING_32} a_result
|
||||
from
|
||||
i := 1
|
||||
create pr.put (i)
|
||||
n := v.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := v.code (i)
|
||||
inspect c
|
||||
when 43 then -- 43 '+'
|
||||
-- Some implementation are replacing spaces with "+" instead of "%20"
|
||||
a_result.append_code (32) -- 32 ' '
|
||||
when 37 then -- 37 '%%'
|
||||
-- An escaped character ?
|
||||
if i = n then -- Error?
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
-- Convert UTF-8 to UTF-32
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_unicode_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
else
|
||||
-- Keep UTF-8
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
end
|
||||
end
|
||||
else
|
||||
if c <= 0x7F then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: decoding
|
||||
|
||||
next_percent_decoded_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Character decoded from string `v' starting from index `a_position.item'
|
||||
-- note: it also updates `a_position.item' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i, n: INTEGER
|
||||
not_a_digit: BOOLEAN
|
||||
ascii_pos: NATURAL_32
|
||||
ival: NATURAL_32
|
||||
pos: INTEGER
|
||||
c_is_digit: BOOLEAN
|
||||
do
|
||||
--| pos is index in stream of escape character ('%')
|
||||
pos := a_position.item
|
||||
c := v.code (pos + 1)
|
||||
if c = 85 or c = 117 then -- 117 'u' 85 'U'
|
||||
-- NOTE: this is not a standard, but it can occur, so use this for decoding only
|
||||
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||
-- has the form: %u<n> where <n> is the UCS value
|
||||
-- of the character (two byte integer, one to 4 chars
|
||||
-- after escape sequence).
|
||||
-- See: http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations
|
||||
-- UTF-8 result can be 1 to 4 characters.
|
||||
from
|
||||
i := pos + 2
|
||||
n := v.count
|
||||
until
|
||||
(i > n) or not_a_digit
|
||||
loop
|
||||
c := v.code (i)
|
||||
c_is_digit := (48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
if
|
||||
c_is_digit
|
||||
or (97 <= c and c <= 102) -- ALPHA: a..f
|
||||
or (65 <= c and c <= 70) -- ALPHA: A..F
|
||||
then
|
||||
ival := ival * 16
|
||||
if c_is_digit then
|
||||
ival := ival + (c - 48) -- 48 '0'
|
||||
else
|
||||
if c > 70 then -- a..f
|
||||
ival := ival + (c - 97) + 10 -- 97 'a'
|
||||
else -- A..F
|
||||
ival := ival + (c - 65) + 10 -- 65 'A'
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
else
|
||||
not_a_digit := True
|
||||
i := i - 1
|
||||
end
|
||||
end
|
||||
a_position.replace (i)
|
||||
Result := ival
|
||||
else
|
||||
-- ASCII char?
|
||||
ascii_pos := hexadecimal_string_to_natural_32 (v.substring (pos + 1, pos + 2))
|
||||
Result := ascii_pos
|
||||
a_position.replace (pos + 2)
|
||||
end
|
||||
end
|
||||
|
||||
next_percent_decoded_unicode_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Next decoded character from `v' at position `a_position.item'
|
||||
-- note: it also updates `a_position' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
n, j: INTEGER
|
||||
c: NATURAL_32
|
||||
c1, c2, c3, c4: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
do
|
||||
create pr.put (a_position.item)
|
||||
c1 := next_percent_decoded_character_code (v, pr)
|
||||
|
||||
j := pr.item
|
||||
n := v.count
|
||||
|
||||
Result := c1
|
||||
a_position.replace (j)
|
||||
|
||||
if c1 <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
Result := c1
|
||||
elseif c1 <= 0xDF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
Result := (
|
||||
((c1 & 0x1F) |<< 6) |
|
||||
( c2 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xEF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
Result := (
|
||||
((c1 & 0xF) |<< 12) |
|
||||
((c2 & 0x3F) |<< 6) |
|
||||
( c3 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xF7 then
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c4 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
a_position.replace (j)
|
||||
|
||||
Result := (
|
||||
((c1 & 0x7) |<< 18 ) |
|
||||
((c2 & 0x3F) |<< 12) |
|
||||
((c3 & 0x3F) |<< 6) |
|
||||
( c4 & 0x3F )
|
||||
)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
Result := c1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- RFC and characters
|
||||
|
||||
is_hexa_decimal_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is hexadecimal character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F') -- HEXA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_or_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA or DIGIT character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z')
|
||||
end
|
||||
|
||||
is_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is DIGIT character ?
|
||||
do
|
||||
Result := ('0' <= c and c <= '9')
|
||||
end
|
||||
|
||||
is_unreserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
do
|
||||
if
|
||||
('a' <= c and c <= 'z') -- ALPHA
|
||||
or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
inspect c
|
||||
when '-', '_', '.', '~' then -- unreserved
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_reserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- reserved = gen-delims / sub-delims
|
||||
do
|
||||
Result := is_gen_delims_character (c) or is_sub_delims_character (c)
|
||||
end
|
||||
|
||||
is_gen_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
do
|
||||
inspect c
|
||||
when ':' , '/', '?' , '#' , '[' , ']' , '@' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
is_sub_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
-- / "*" / "+" / "," / ";" / "="
|
||||
do
|
||||
inspect c
|
||||
when '!' , '$' , '&' , '%'' , '(' , ')' , '*' , '+' , ',' , ';' , '=' then -- sub-delims
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
hex_digit: SPECIAL [NATURAL_32]
|
||||
-- Hexadecimal digits.
|
||||
once
|
||||
create Result.make_filled (0, 16)
|
||||
Result [0] := {NATURAL_32} 48 -- 48 '0'
|
||||
Result [1] := {NATURAL_32} 49 -- 49 '1'
|
||||
Result [2] := {NATURAL_32} 50 -- 50 '2'
|
||||
Result [3] := {NATURAL_32} 51 -- 51 '3'
|
||||
Result [4] := {NATURAL_32} 52 -- 52 '4'
|
||||
Result [5] := {NATURAL_32} 53 -- 53 '5'
|
||||
Result [6] := {NATURAL_32} 54 -- 54 '6'
|
||||
Result [7] := {NATURAL_32} 55 -- 55 '7'
|
||||
Result [8] := {NATURAL_32} 56 -- 56 '8'
|
||||
Result [9] := {NATURAL_32} 57 -- 57 '9'
|
||||
Result [10] := {NATURAL_32} 65 -- 65 'A'
|
||||
Result [11] := {NATURAL_32} 66 -- 66 'B'
|
||||
Result [12] := {NATURAL_32} 67 -- 67 'C'
|
||||
Result [13] := {NATURAL_32} 68 -- 68 'D'
|
||||
Result [14] := {NATURAL_32} 69 -- 69 'E'
|
||||
Result [15] := {NATURAL_32} 70 -- 70 'F'
|
||||
end
|
||||
|
||||
is_hexa_decimal (a_string: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Is `a_string' a valid hexadecimal sequence?
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_string, {NUMERIC_INFORMATION}.type_natural_32)
|
||||
Result := l_convertor.is_integral_integer
|
||||
end
|
||||
|
||||
hexadecimal_string_to_natural_32 (a_hex_string: READABLE_STRING_GENERAL): NATURAL_32
|
||||
-- Convert hexadecimal value `a_hex_string' to its corresponding NATURAL_32 value.
|
||||
require
|
||||
is_hexa: is_hexa_decimal (a_hex_string)
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_hex_string, {NUMERIC_INFORMATION}.type_no_limitation)
|
||||
Result := l_convertor.parsed_natural_32
|
||||
end
|
||||
|
||||
ctoi_convertor: HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
|
||||
-- Converter used to convert string to integer or natural.
|
||||
once
|
||||
create Result.make
|
||||
Result.set_leading_separators_acceptable (False)
|
||||
Result.set_trailing_separators_acceptable (False)
|
||||
ensure
|
||||
ctoi_convertor_not_void: Result /= Void
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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
|
||||
@@ -62,7 +62,7 @@ feature -- Access
|
||||
url_encoded_name: READABLE_STRING_8
|
||||
-- URL encoded string of `name'.
|
||||
do
|
||||
Result := url_encoder.encoded_string (name)
|
||||
Result := url_encoded_string (name)
|
||||
end
|
||||
|
||||
values: LIST [WSF_STRING]
|
||||
|
||||
@@ -50,20 +50,6 @@ feature -- Access
|
||||
url_encoded_value: READABLE_STRING_8
|
||||
-- URL encoded string of `value'.
|
||||
|
||||
frozen string: like value
|
||||
obsolete
|
||||
"Use value [2012-May-31]"
|
||||
do
|
||||
Result := value
|
||||
end
|
||||
|
||||
frozen url_encoded_string: like url_encoded_value
|
||||
obsolete
|
||||
"Use url_encoded_value [2012-May-31]"
|
||||
do
|
||||
Result := url_encoded_value
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
integer_value: INTEGER
|
||||
@@ -137,7 +123,7 @@ feature -- Visitor
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -36,17 +36,17 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: STRING_32
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := Precursor
|
||||
if
|
||||
exists and then
|
||||
attached tmp_name as n
|
||||
attached tmp_path as p
|
||||
then
|
||||
Result.append_character (' ')
|
||||
Result.append_character ('%"')
|
||||
Result.append (n)
|
||||
Result.append (p.name)
|
||||
Result.append_character ('%"')
|
||||
end
|
||||
Result.append (" filename=%"")
|
||||
@@ -108,14 +108,56 @@ feature -- Access: Uploaded File
|
||||
size: INTEGER
|
||||
-- Size of uploaded file
|
||||
|
||||
tmp_name: detachable STRING
|
||||
tmp_path: detachable PATH
|
||||
-- Filename of tmp file
|
||||
|
||||
tmp_name: detachable READABLE_STRING_GENERAL
|
||||
do
|
||||
if attached tmp_path as p then
|
||||
Result := p.name
|
||||
end
|
||||
end
|
||||
|
||||
tmp_basename: detachable STRING
|
||||
-- Basename of tmp file
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
append_content_to_string (a_target: STRING)
|
||||
-- Append the content of the uploaded file to `a_target'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
s: STRING
|
||||
done: BOOLEAN
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried and attached tmp_name as fn then
|
||||
create f.make_with_name (fn)
|
||||
if f.exists then
|
||||
f.open_read
|
||||
from
|
||||
until
|
||||
done
|
||||
loop
|
||||
f.read_stream_thread_aware (1_024)
|
||||
s := f.last_string
|
||||
if s.is_empty then
|
||||
done := True
|
||||
else
|
||||
a_target.append (s)
|
||||
done := f.exhausted or f.end_of_file
|
||||
end
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature -- Implementation
|
||||
|
||||
safe_filename: STRING
|
||||
local
|
||||
fn: like filename
|
||||
@@ -202,7 +244,7 @@ feature -- Conversion
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
move_to (a_destination: STRING): BOOLEAN
|
||||
move_to (a_destination: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Move current uploaded file to `a_destination'
|
||||
--| Violates CQS principle.
|
||||
require
|
||||
@@ -211,10 +253,10 @@ feature -- Basic operation
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
if attached tmp_name as n then
|
||||
create f.make (n)
|
||||
if attached tmp_path as p then
|
||||
create f.make_with_path (p)
|
||||
if f.exists then
|
||||
f.change_name (a_destination)
|
||||
f.rename_file (a_destination)
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
@@ -239,8 +281,8 @@ feature -- Status
|
||||
local
|
||||
f: PLAIN_TEXT_FILE
|
||||
do
|
||||
if attached tmp_name as n then
|
||||
create f.make (n)
|
||||
if attached tmp_path as p then
|
||||
create f.make_with_path (p)
|
||||
Result := f.exists
|
||||
end
|
||||
end
|
||||
@@ -253,10 +295,19 @@ feature -- Element change
|
||||
error := e
|
||||
end
|
||||
|
||||
set_tmp_path (p: like tmp_path)
|
||||
do
|
||||
tmp_path := p
|
||||
end
|
||||
|
||||
set_tmp_name (n: like tmp_name)
|
||||
-- Set `tmp_name' to `n'
|
||||
do
|
||||
tmp_name := n
|
||||
if n /= Void then
|
||||
set_tmp_path (create {PATH}.make_from_string (n))
|
||||
else
|
||||
set_tmp_path (Void)
|
||||
end
|
||||
end
|
||||
|
||||
set_tmp_basename (n: like tmp_basename)
|
||||
|
||||
@@ -9,6 +9,13 @@ deferred class
|
||||
inherit
|
||||
DEBUG_OUTPUT
|
||||
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoder as url_encoder
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: READABLE_STRING_32
|
||||
@@ -91,23 +98,26 @@ feature -- Helper
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: STRING_32
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
create Result.make_from_string (url_encoder.encoded_string (name) + "=" + url_encoder.encoded_string (string_representation))
|
||||
create Result.make_from_string (name + {STRING_32} "=" + string_representation)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
url_decoded_string (s: READABLE_STRING_8): READABLE_STRING_32
|
||||
url_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
-- Decoded url-encoded string `s'
|
||||
do
|
||||
Result := url_encoder.decoded_string (s)
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_encoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create {UTF8_URL_ENCODER} Result --| Chrome is UTF-8 encoding the non ascii in query
|
||||
url_decoded_string (s: READABLE_STRING_GENERAL): STRING_32
|
||||
-- Decoded url-encoded string `s'
|
||||
do
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_decoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
feature -- Visitor
|
||||
@@ -117,7 +127,7 @@ feature -- Visitor
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -24,6 +24,7 @@ feature {NONE} -- Initialization
|
||||
do
|
||||
router := a_router
|
||||
make (req)
|
||||
set_suggestion_only_method (True)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
@@ -36,6 +37,9 @@ feature -- Settings
|
||||
documentation_included: BOOLEAN
|
||||
-- Include self-documentation from `router' in the response?
|
||||
|
||||
suggestion_only_method: BOOLEAN
|
||||
-- Display only suggestion for `req' method ?
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_documentation_included (b: BOOLEAN)
|
||||
@@ -43,6 +47,14 @@ feature -- Change
|
||||
documentation_included := b
|
||||
end
|
||||
|
||||
set_suggestion_only_method (b: BOOLEAN)
|
||||
-- Set `suggestion_only_method' to `b'
|
||||
do
|
||||
suggestion_only_method := b
|
||||
ensure
|
||||
suggestion_only_method_set: suggestion_only_method = b
|
||||
end
|
||||
|
||||
feature {WSF_RESPONSE} -- Output
|
||||
|
||||
send_to (res: WSF_RESPONSE)
|
||||
@@ -138,10 +150,14 @@ feature {NONE} -- Implementation
|
||||
not_found_message (req: WSF_REQUEST): WSF_NOT_FOUND_RESPONSE
|
||||
local
|
||||
vis: WSF_ROUTER_AGENT_ITERATOR
|
||||
l_method: detachable READABLE_STRING_8
|
||||
do
|
||||
Result := Precursor (req)
|
||||
if documentation_included then
|
||||
create vis
|
||||
if suggestion_only_method then
|
||||
l_method := req.request_method
|
||||
end
|
||||
vis.on_item_actions.extend (agent (i: WSF_ROUTER_ITEM; r: WSF_NOT_FOUND_RESPONSE; m: detachable READABLE_STRING_8)
|
||||
local
|
||||
l_is_hidden: BOOLEAN
|
||||
@@ -174,7 +190,7 @@ feature {NONE} -- Implementation
|
||||
r.add_suggested_text (s, Void)
|
||||
end
|
||||
end
|
||||
end (?, Result, req.request_method))
|
||||
end (?, Result, l_method))
|
||||
vis.process_router (router)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,6 +10,8 @@ class
|
||||
inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
SHARED_UTF8_URL_ENCODER
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_content_type,
|
||||
@@ -17,26 +19,26 @@ create
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_file_name: READABLE_STRING_8)
|
||||
make (a_file_name: READABLE_STRING_GENERAL)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_file_name
|
||||
base_name := basename (a_file_name)
|
||||
create file_path.make_from_string (a_file_name)
|
||||
base_name := basename (file_path)
|
||||
get_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_filename: READABLE_STRING_8)
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_filename
|
||||
base_name := basename (a_filename)
|
||||
create file_path.make_from_string (a_filename)
|
||||
base_name := basename (file_path)
|
||||
content_type := a_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_html (a_filename: READABLE_STRING_8)
|
||||
make_html (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type ({HTTP_MIME_TYPES}.text_html, a_filename)
|
||||
@@ -45,15 +47,14 @@ feature {NONE} -- Initialization
|
||||
initialize
|
||||
local
|
||||
h: like header
|
||||
d: HTTP_DATE
|
||||
do
|
||||
create h.make
|
||||
header := h
|
||||
h.put_content_type (content_type)
|
||||
h.put_transfer_encoding_binary
|
||||
h.put_content_length (filesize (file_name))
|
||||
h.put_content_length (filesize (file_path))
|
||||
h.put_content_disposition ("attachment", "filename=%""+ base_name +"%"")
|
||||
if attached filedate (file_name) as dt then
|
||||
if attached filedate (file_path) as dt then
|
||||
h.put_last_modified (dt)
|
||||
end
|
||||
end
|
||||
@@ -89,7 +90,14 @@ feature -- Access
|
||||
|
||||
status_code: INTEGER assign set_status_code
|
||||
|
||||
file_path: PATH
|
||||
|
||||
file_name: READABLE_STRING_8
|
||||
obsolete
|
||||
"Use `file_path.name' for unicode support [2013-may]"
|
||||
do
|
||||
Result := file_path.utf_8_name
|
||||
end
|
||||
|
||||
base_name: READABLE_STRING_8
|
||||
|
||||
@@ -125,73 +133,57 @@ feature {WSF_RESPONSE} -- Output
|
||||
res.set_status_code (status_code)
|
||||
res.put_header_text (header.string)
|
||||
if not answer_head_request_method then
|
||||
send_file_content_to (file_name, res)
|
||||
send_file_content_to (file_path, res)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: file system helper
|
||||
|
||||
filesize (fn: STRING): INTEGER
|
||||
filesize (fn: PATH): INTEGER
|
||||
-- Size of the file `fn'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
if f.exists then
|
||||
Result := f.count
|
||||
end
|
||||
end
|
||||
|
||||
filedate (fn: STRING): detachable DATE_TIME
|
||||
filedate (fn: PATH): detachable DATE_TIME
|
||||
-- Size of the file `fn'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
d: HTTP_DATE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
if f.exists then
|
||||
create d.make_from_timestamp (f.date)
|
||||
Result := d.date_time
|
||||
end
|
||||
end
|
||||
|
||||
file_extension (fn: STRING): STRING
|
||||
file_extension (fn: PATH): STRING_32
|
||||
-- Extension of file `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := fn.last_index_of ('.', fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (p + 1, fn.count)
|
||||
if attached fn.extension as ext then
|
||||
Result := ext
|
||||
else
|
||||
create Result.make_empty
|
||||
end
|
||||
end
|
||||
|
||||
basename (fn: STRING): STRING
|
||||
basename (fn: PATH): STRING
|
||||
-- Basename of `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
s: READABLE_STRING_32
|
||||
do
|
||||
p := fn.last_index_of ((create {OPERATING_ENVIRONMENT}).Directory_separator, fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (p + 1, fn.count)
|
||||
if attached fn.entry as p then
|
||||
s := p.name
|
||||
else
|
||||
Result := fn
|
||||
end
|
||||
end
|
||||
|
||||
dirname (fn: STRING): STRING
|
||||
-- Dirname of `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := fn.last_index_of ((create {OPERATING_ENVIRONMENT}).Directory_separator, fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (1, p - 1)
|
||||
else
|
||||
create Result.make_empty
|
||||
s := fn.name
|
||||
end
|
||||
Result := url_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
feature -- Content-type related
|
||||
@@ -203,7 +195,7 @@ feature -- Content-type related
|
||||
m: detachable READABLE_STRING_8
|
||||
do
|
||||
create m_map.make_default
|
||||
m := m_map.mime_type (file_extension (file_name).as_lower)
|
||||
m := m_map.mime_type (file_extension (file_path).as_lower)
|
||||
if m = Void then
|
||||
m := {HTTP_MIME_TYPES}.application_force_download
|
||||
end
|
||||
@@ -212,15 +204,15 @@ feature -- Content-type related
|
||||
|
||||
feature -- Implementation: output
|
||||
|
||||
send_file_content_to (fn: READABLE_STRING_8; res: WSF_RESPONSE)
|
||||
send_file_content_to (fn: PATH; res: WSF_RESPONSE)
|
||||
-- Send the content of file `fn'
|
||||
require
|
||||
string_not_empty: not fn.is_empty
|
||||
is_readable: (create {RAW_FILE}.make (fn)).is_readable
|
||||
is_readable: (create {RAW_FILE}.make_with_path (fn)).is_readable
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
check f.exists and then f.is_readable end
|
||||
|
||||
f.open_read
|
||||
|
||||
@@ -11,30 +11,49 @@ inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
create
|
||||
make_with_path,
|
||||
make_with_content_type_and_path,
|
||||
make_html_with_path,
|
||||
make,
|
||||
make_with_content_type,
|
||||
make_html
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_file_name: READABLE_STRING_8)
|
||||
make_with_path (a_path: PATH)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_file_name
|
||||
file_path := a_path
|
||||
get_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_filename: READABLE_STRING_8)
|
||||
-- Initialize `Current'.
|
||||
make_with_content_type_and_path (a_content_type: READABLE_STRING_8; a_path: PATH)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
file_name := a_filename
|
||||
file_path := a_path
|
||||
content_type := a_content_type
|
||||
initialize
|
||||
end
|
||||
|
||||
make_html (a_filename: READABLE_STRING_8)
|
||||
make_html_with_path (a_path: PATH)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type_and_path ({HTTP_MIME_TYPES}.text_html, a_path)
|
||||
end
|
||||
|
||||
make (a_file_name: READABLE_STRING_GENERAL)
|
||||
do
|
||||
make_with_path (create {PATH}.make_from_string (a_file_name))
|
||||
end
|
||||
|
||||
make_with_content_type (a_content_type: READABLE_STRING_8; a_file_name: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type_and_path (a_content_type, create {PATH}.make_from_string (a_file_name))
|
||||
end
|
||||
|
||||
make_html (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_with_content_type ({HTTP_MIME_TYPES}.text_html, a_filename)
|
||||
@@ -118,13 +137,21 @@ feature -- Access
|
||||
content_type: READABLE_STRING_8
|
||||
-- Content-Type of the response
|
||||
|
||||
file_path: path
|
||||
-- File path
|
||||
|
||||
file_name: READABLE_STRING_8
|
||||
obsolete
|
||||
"Use `file_path.name' for unicode support [2013-may]"
|
||||
do
|
||||
Result := file_path.utf_8_name
|
||||
end
|
||||
|
||||
file_exists: BOOLEAN
|
||||
-- File exists?
|
||||
|
||||
file_size: INTEGER
|
||||
-- Size of file named `file_name'
|
||||
-- Size of file `file_path'
|
||||
|
||||
head, bottom: detachable READABLE_STRING_8
|
||||
-- Eventual head and bottom part
|
||||
@@ -184,7 +211,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
res.put_string (s)
|
||||
end
|
||||
if not answer_head_request_method then
|
||||
send_file_content_to (file_name, res)
|
||||
send_file_content_to (file_path, res)
|
||||
end
|
||||
s := bottom
|
||||
if s /= Void then
|
||||
@@ -200,40 +227,37 @@ feature {NONE} -- Implementation: file system helper
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name)
|
||||
create f.make_with_path (file_path)
|
||||
file_exists := f.exists
|
||||
end
|
||||
|
||||
get_file_size
|
||||
-- Get `file_size' from file named `file_name'
|
||||
-- Get `file_size' from file named `file_path'
|
||||
require
|
||||
file_exists: file_exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name)
|
||||
create f.make_with_path (file_path)
|
||||
file_size := f.count
|
||||
end
|
||||
|
||||
file_last_modified: detachable DATE_TIME
|
||||
-- Get `file_size' from file named `file_name'
|
||||
-- Get `file_size' from file named `file_path'
|
||||
require
|
||||
file_exists: file_exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (file_name)
|
||||
create f.make_with_path (file_path)
|
||||
create Result.make_from_epoch (f.change_date)
|
||||
end
|
||||
|
||||
file_extension (fn: STRING): STRING
|
||||
file_extension (fn: PATH): STRING_32
|
||||
-- Extension of file `fn'.
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
p := fn.last_index_of ('.', fn.count)
|
||||
if p > 0 then
|
||||
Result := fn.substring (p + 1, fn.count)
|
||||
if attached fn.extension as ext then
|
||||
Result := ext
|
||||
else
|
||||
create Result.make_empty
|
||||
end
|
||||
@@ -242,13 +266,13 @@ feature {NONE} -- Implementation: file system helper
|
||||
feature -- Content-type related
|
||||
|
||||
get_content_type
|
||||
-- Content type associated with `file_name'
|
||||
-- Content type associated with `file_path'
|
||||
local
|
||||
m_map: HTTP_FILE_EXTENSION_MIME_MAPPING
|
||||
m: detachable READABLE_STRING_8
|
||||
do
|
||||
create m_map.make_default
|
||||
m := m_map.mime_type (file_extension (file_name).as_lower)
|
||||
m := m_map.mime_type (file_extension (file_path).as_lower)
|
||||
if m = Void then
|
||||
m := {HTTP_MIME_TYPES}.application_force_download
|
||||
end
|
||||
@@ -257,16 +281,16 @@ feature -- Content-type related
|
||||
|
||||
feature {NONE} -- Implementation: output
|
||||
|
||||
send_file_content_to (fn: READABLE_STRING_8; res: WSF_RESPONSE)
|
||||
send_file_content_to (fn: PATH; res: WSF_RESPONSE)
|
||||
-- Send the content of file `fn'
|
||||
require
|
||||
string_not_empty: not fn.is_empty
|
||||
is_readable: (create {RAW_FILE}.make (fn)).is_readable
|
||||
is_readable: (create {RAW_FILE}.make_with_path (fn)).is_readable
|
||||
file_exists: file_exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
create f.make_with_path (fn)
|
||||
check f.is_readable end
|
||||
|
||||
f.open_read
|
||||
|
||||
@@ -136,11 +136,11 @@ feature {WSF_RESPONSE} -- Output
|
||||
s.append (
|
||||
"[
|
||||
<style type="text/css">
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; width: 100%; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; width: 100%; text-align: center; font-size: 1.5em; }
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; text-align: center; font-size: 1.5em; }
|
||||
div#suggestions { margin: auto; width: 60%;}
|
||||
div#suggestions ul { }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; width: 100%; text-align: center; }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; text-align: center; }
|
||||
div#logo { float: right; margin: 20px; width: 60px height: auto; font-size: 0.8em; text-align: center; }
|
||||
div#logo div.outter { padding: 6px; width: 60px; border: solid 3px #500; background-color: #b00;}
|
||||
div#logo div.outter div.inner1 { display: block; margin: 10px 15px; width: 30px; height: 50px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
|
||||
@@ -81,11 +81,11 @@ feature {WSF_RESPONSE} -- Output
|
||||
s.append ("</title>%N")
|
||||
s.append ("[
|
||||
<style type="text/css">
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; width: 100%; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; width: 100%; text-align: center; font-size: 1.5em; }
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; text-align: center; font-size: 1.5em; }
|
||||
div#suggestions { margin: auto; width: 60%;}
|
||||
div#suggestions ul { }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; width: 100%; text-align: center; }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; text-align: center; }
|
||||
div#logo { float: right; margin: 20px; width: 60px height: auto; font-size: 0.8em; text-align: center; }
|
||||
div#logo div.outter { padding: 6px; width: 60px; border: solid 3px #500; background-color: #b00;}
|
||||
div#logo div.outter div.inner1 { display: block; margin: 10px 15px; width: 30px; height: 50px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
@@ -198,7 +198,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -53,8 +53,6 @@ feature {WSF_RESPONSE} -- Output
|
||||
send_to (res: WSF_RESPONSE)
|
||||
local
|
||||
s: STRING
|
||||
l_text: detachable READABLE_STRING_GENERAL
|
||||
l_loc: detachable READABLE_STRING_8
|
||||
h: like header
|
||||
do
|
||||
h := header
|
||||
@@ -68,9 +66,9 @@ feature {WSF_RESPONSE} -- Output
|
||||
s.append ("</title>%N")
|
||||
s.append ("[
|
||||
<style type="text/css">
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; width: 100%; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; width: 100%; text-align: center; font-size: 1.5em; }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; width: 100%; text-align: center; }
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; text-align: center; font-size: 1.5em; }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; text-align: center; }
|
||||
div#logo { float: right; margin: 20px; width: 60px height: auto; font-size: 0.8em; text-align: center; }
|
||||
div#logo div.outter { padding: 6px; width: 60px; border: solid 3px #500; background-color: #b00;}
|
||||
div#logo div.outter div.inner1 { display: block; margin: 10px 15px; width: 30px; height: 50px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
@@ -117,8 +115,8 @@ feature {WSF_RESPONSE} -- Output
|
||||
end
|
||||
|
||||
note
|
||||
|
||||
copyright: "2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -7,45 +7,19 @@ deferred class
|
||||
WSF_DEFAULT_SERVICE_I [G -> WSF_SERVICE_LAUNCHER create make_and_launch end]
|
||||
|
||||
inherit
|
||||
WSF_SERVICE
|
||||
WSF_LAUNCHABLE_SERVICE
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
frozen make_and_launch
|
||||
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
l_launcher: G
|
||||
do
|
||||
initialize
|
||||
create l_launcher.make_and_launch (Current, service_options)
|
||||
end
|
||||
|
||||
initialize
|
||||
-- Initialize current service
|
||||
--| Could be redefine to set custom service option(s)
|
||||
do
|
||||
end
|
||||
|
||||
service_options: detachable WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
|
||||
feature -- Default service options
|
||||
|
||||
set_service_option (a_name: READABLE_STRING_GENERAL; a_value: detachable ANY)
|
||||
-- Set options related to WSF_DEFAULT_SERVICE
|
||||
local
|
||||
opts: like service_options
|
||||
do
|
||||
opts := service_options
|
||||
if opts = Void then
|
||||
create opts.make
|
||||
service_options := opts
|
||||
end
|
||||
opts.set_option (a_name, a_value)
|
||||
ensure
|
||||
attached service_options as l_options and then l_options.option (a_name) = a_value
|
||||
create l_launcher.make_and_launch (a_service, opts)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -15,7 +15,7 @@ class
|
||||
WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
|
||||
inherit
|
||||
ANY
|
||||
TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
@@ -23,7 +23,8 @@ inherit
|
||||
create
|
||||
default_create,
|
||||
make,
|
||||
make_from_array
|
||||
make_from_array,
|
||||
make_from_iterable
|
||||
|
||||
convert
|
||||
make_from_array ({ARRAY [TUPLE [name: READABLE_STRING_GENERAL; value: detachable ANY]]})
|
||||
@@ -44,6 +45,19 @@ feature {NONE} -- Initialization
|
||||
make_from_array (a_options: ARRAY [TUPLE [name: READABLE_STRING_GENERAL; value: detachable ANY]])
|
||||
do
|
||||
make
|
||||
append_array_of_options (a_options)
|
||||
end
|
||||
|
||||
make_from_iterable (a_options: TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL])
|
||||
do
|
||||
make
|
||||
append_options (a_options)
|
||||
end
|
||||
|
||||
feature -- Merging
|
||||
|
||||
append_array_of_options (a_options: ARRAY [TUPLE [name: READABLE_STRING_GENERAL; value: detachable ANY]])
|
||||
do
|
||||
across
|
||||
a_options as opt
|
||||
loop
|
||||
@@ -53,6 +67,15 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
end
|
||||
|
||||
append_options (a_options: TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL])
|
||||
do
|
||||
across
|
||||
a_options as o
|
||||
loop
|
||||
set_option (o.key, o.item)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
option (a_name: READABLE_STRING_GENERAL): detachable ANY
|
||||
@@ -60,6 +83,14 @@ feature -- Access
|
||||
Result := options.item (a_name)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_cursor: TABLE_ITERATION_CURSOR [detachable ANY, READABLE_STRING_GENERAL]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := options.new_cursor
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_option (a_name: READABLE_STRING_GENERAL; a_value: detachable ANY)
|
||||
@@ -75,13 +106,13 @@ feature -- Element change
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
options: HASH_TABLE [detachable ANY, READABLE_STRING_GENERAL]
|
||||
options: STRING_TABLE [detachable ANY]
|
||||
-- Custom options which might be support (or not) by the default service
|
||||
|
||||
invariant
|
||||
options_attached: options /= Void
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -11,28 +11,40 @@ inherit
|
||||
WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
|
||||
create
|
||||
make_from_file
|
||||
make_from_file,
|
||||
make_from_file_and_defaults
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_from_file (a_filename: READABLE_STRING_32)
|
||||
make_from_file (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make
|
||||
import (a_filename)
|
||||
end
|
||||
|
||||
make_from_file_and_defaults (a_filename: READABLE_STRING_GENERAL; dft: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make
|
||||
|
||||
if dft /= Void then
|
||||
append_options (dft)
|
||||
end
|
||||
|
||||
import (a_filename)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
import (a_filename: READABLE_STRING_32)
|
||||
import (a_filename: READABLE_STRING_GENERAL)
|
||||
-- Import ini file content
|
||||
local
|
||||
f: PLAIN_TEXT_FILE
|
||||
l,v: STRING_8
|
||||
p: INTEGER
|
||||
do
|
||||
--FIXME: handle unicode filename here.
|
||||
create f.make (a_filename)
|
||||
create f.make_with_name (a_filename)
|
||||
if f.exists and f.is_readable then
|
||||
f.open_read
|
||||
from
|
||||
@@ -60,7 +72,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -42,6 +42,9 @@ feature {WGI_CONNECTOR} -- Implementation: Execution
|
||||
w_req.destroy
|
||||
rescue
|
||||
if w_res /= Void then
|
||||
if not (w_res.status_committed or w_res.header_committed) then
|
||||
w_res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
|
||||
end
|
||||
w_res.flush
|
||||
end
|
||||
if w_req /= Void then
|
||||
|
||||
@@ -26,6 +26,18 @@ class
|
||||
inherit
|
||||
DEBUG_OUTPUT
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoder as url_encoder
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create {WSF_TO_WGI_SERVICE}
|
||||
make_from_wgi
|
||||
|
||||
@@ -40,26 +52,25 @@ feature {NONE} -- Initialization
|
||||
do
|
||||
wgi_request := r
|
||||
|
||||
create string_equality_tester
|
||||
if attached r.meta_variables as l_vars then
|
||||
create tb.make_with_key_tester (l_vars.count, string_equality_tester)
|
||||
create tb.make_equal (l_vars.count)
|
||||
across
|
||||
l_vars as c
|
||||
loop
|
||||
tb.force (new_string_value (c.key, c.item), c.key)
|
||||
if attached {READABLE_STRING_8} c.key as s8 then
|
||||
tb.force (new_string_value (s8, c.item), c.key)
|
||||
else
|
||||
tb.force (new_string_value (url_encoded_string (c.key), c.item), c.key)
|
||||
end
|
||||
end
|
||||
else
|
||||
create tb.make_with_key_tester (0, string_equality_tester)
|
||||
create tb.make_equal (0)
|
||||
end
|
||||
meta_variables_table := tb
|
||||
meta_variables := tb
|
||||
create error_handler.make
|
||||
create uploaded_files_table.make_with_key_tester (0, string_equality_tester)
|
||||
create uploaded_files_table.make_equal (0)
|
||||
set_raw_input_data_recorded (False)
|
||||
create {IMMUTABLE_STRING_32} empty_string.make_empty
|
||||
|
||||
create execution_variables_table.make_with_key_tester (0, string_equality_tester)
|
||||
execution_variables_table.compare_objects
|
||||
create execution_variables_table.make_equal (0)
|
||||
|
||||
initialize
|
||||
analyze
|
||||
@@ -96,12 +107,13 @@ feature {NONE} -- Initialization
|
||||
request_method := req.request_method
|
||||
|
||||
--| PATH_INFO
|
||||
path_info := raw_url_encoder.decoded_string (req.path_info)
|
||||
percent_encoded_path_info := req.path_info
|
||||
path_info := url_decoded_string (req.path_info)
|
||||
|
||||
--| PATH_TRANSLATED
|
||||
s8 := req.path_translated
|
||||
if s8 /= Void then
|
||||
path_translated := raw_url_encoder.decoded_string (s8)
|
||||
path_translated := url_decoded_string (s8)
|
||||
end
|
||||
|
||||
--| Here one can set its own environment entries if needed
|
||||
@@ -111,6 +123,7 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
|
||||
wgi_request: WGI_REQUEST
|
||||
-- Associated WGI request
|
||||
|
||||
feature -- Destroy
|
||||
|
||||
@@ -125,6 +138,26 @@ feature -- Destroy
|
||||
loop
|
||||
delete_uploaded_file (c.item)
|
||||
end
|
||||
|
||||
content_length_value := 0
|
||||
content_type := Void
|
||||
execution_variables_table.wipe_out
|
||||
internal_cookies_table := Void
|
||||
internal_form_data_parameters_table := Void
|
||||
internal_query_parameters_table := Void
|
||||
internal_server_url := Void
|
||||
internal_url_base := Void
|
||||
form_parameters_table.wipe_out
|
||||
mime_handlers := Void
|
||||
path_info := empty_string_32
|
||||
path_parameters_source := Void
|
||||
path_parameters_table := Void
|
||||
path_translated := Void
|
||||
raw_input_data := Void
|
||||
raw_input_data_recorded := False
|
||||
request_method := empty_string_8
|
||||
set_uploaded_file_path (Void)
|
||||
-- wgi_request
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
@@ -199,17 +232,16 @@ feature -- Access: Input
|
||||
local
|
||||
l_input: WGI_INPUT_STREAM
|
||||
n: INTEGER
|
||||
s: STRING
|
||||
do
|
||||
if raw_input_data_recorded and then attached raw_input_data as d then
|
||||
buf.copy (d)
|
||||
buf.append (d)
|
||||
else
|
||||
l_input := input
|
||||
if is_chunked_input then
|
||||
from
|
||||
n := 8_192
|
||||
until
|
||||
n = 0
|
||||
n = 0 or l_input.end_of_input
|
||||
loop
|
||||
l_input.append_to_string (buf, n)
|
||||
if l_input.last_appended_count < n then
|
||||
@@ -230,6 +262,47 @@ feature -- Access: Input
|
||||
end
|
||||
end
|
||||
|
||||
read_input_data_into_file (a_file: FILE)
|
||||
-- retrieve the content from the `input' stream into `s'
|
||||
-- warning: if the input data has already been retrieved
|
||||
-- you might not get anything
|
||||
require
|
||||
a_file_is_open_write: a_file.is_open_write
|
||||
local
|
||||
s: STRING
|
||||
l_input: WGI_INPUT_STREAM
|
||||
l_raw_data: detachable STRING_8
|
||||
n: INTEGER
|
||||
do
|
||||
if raw_input_data_recorded and then attached raw_input_data as d then
|
||||
a_file.put_string (d)
|
||||
else
|
||||
if raw_input_data_recorded then
|
||||
create l_raw_data.make_empty
|
||||
end
|
||||
l_input := input
|
||||
from
|
||||
n := 8_192
|
||||
create s.make (n)
|
||||
until
|
||||
n = 0 or l_input.end_of_input
|
||||
loop
|
||||
l_input.append_to_string (s, n)
|
||||
a_file.put_string (s)
|
||||
if l_raw_data /= Void then
|
||||
l_raw_data.append (s)
|
||||
end
|
||||
s.wipe_out
|
||||
if l_input.last_appended_count < n then
|
||||
n := 0
|
||||
end
|
||||
end
|
||||
if l_raw_data /= Void then
|
||||
set_raw_input_data (l_raw_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Helper
|
||||
|
||||
is_request_method (m: READABLE_STRING_GENERAL): BOOLEAN
|
||||
@@ -313,12 +386,12 @@ feature {WSF_REQUEST_EXPORTER} -- Override value
|
||||
|
||||
feature {NONE} -- Access: global variable
|
||||
|
||||
items_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
items_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Table containing all the various variables
|
||||
-- Warning: this is computed each time, if you change the content of other containers
|
||||
-- this won't update this Result's content, unless you query it again
|
||||
do
|
||||
create Result.make_with_key_tester (20, string_equality_tester)
|
||||
create Result.make_equal (20)
|
||||
|
||||
if attached path_parameters as l_path_parameters then
|
||||
across
|
||||
@@ -486,6 +559,14 @@ feature -- Helpers: global variables
|
||||
|
||||
feature -- Execution variables
|
||||
|
||||
has_execution_variable (a_name: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Has execution variable related to `a_name'?
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
do
|
||||
Result := execution_variables_table.has (a_name)
|
||||
end
|
||||
|
||||
execution_variable (a_name: READABLE_STRING_GENERAL): detachable ANY
|
||||
-- Execution variable related to `a_name'
|
||||
require
|
||||
@@ -510,7 +591,7 @@ feature -- Execution variables
|
||||
|
||||
feature {NONE} -- Execution variables: implementation
|
||||
|
||||
execution_variables_table: HASH_TABLE_EX [detachable ANY, READABLE_STRING_GENERAL]
|
||||
execution_variables_table: STRING_TABLE [detachable ANY]
|
||||
|
||||
feature -- Access: CGI Meta variables
|
||||
|
||||
@@ -534,6 +615,9 @@ feature -- Access: CGI Meta variables
|
||||
|
||||
meta_variables: ITERABLE [WSF_STRING]
|
||||
-- CGI meta variables values
|
||||
do
|
||||
Result := meta_variables_table
|
||||
end
|
||||
|
||||
meta_string_variable_or_default (a_name: READABLE_STRING_GENERAL; a_default: READABLE_STRING_32; use_default_when_empty: BOOLEAN): READABLE_STRING_32
|
||||
-- Value for meta parameter `a_name'
|
||||
@@ -569,7 +653,7 @@ feature -- Access: CGI Meta variables
|
||||
|
||||
feature {NONE} -- Access: CGI meta parameters
|
||||
|
||||
meta_variables_table: HASH_TABLE_EX [WSF_STRING, READABLE_STRING_GENERAL]
|
||||
meta_variables_table: STRING_TABLE [WSF_STRING]
|
||||
-- CGI Environment parameters
|
||||
|
||||
feature -- Access: CGI meta parameters - 1.1
|
||||
@@ -691,6 +775,11 @@ feature -- Access: CGI meta parameters - 1.1
|
||||
Result := wgi_request.gateway_interface
|
||||
end
|
||||
|
||||
percent_encoded_path_info: READABLE_STRING_8
|
||||
-- Non decoded PATH_INFO value from CGI.
|
||||
-- See `path_info' for the related percent decoded value.
|
||||
--| This value should be used by component dealing only with ASCII path
|
||||
|
||||
path_info: READABLE_STRING_32
|
||||
-- The PATH_INFO metavariable specifies a path to be interpreted
|
||||
-- by the CGI script. It identifies the resource or sub-resource
|
||||
@@ -719,6 +808,8 @@ feature -- Access: CGI meta parameters - 1.1
|
||||
-- The PATH_INFO value is case-sensitive, and the server MUST
|
||||
-- preserve the case of the PATH_INFO element of the URI when
|
||||
-- making it available to scripts.
|
||||
--
|
||||
-- See `percent_encoded_path_info' to get the original non decoded path info.
|
||||
|
||||
path_translated: detachable READABLE_STRING_32
|
||||
-- PATH_TRANSLATED is derived by taking any path-info component
|
||||
@@ -1138,7 +1229,7 @@ feature -- Cookies
|
||||
|
||||
feature {NONE} -- Cookies
|
||||
|
||||
cookies_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
cookies_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Expanded cookies variable
|
||||
local
|
||||
i,j,p,n: INTEGER
|
||||
@@ -1149,8 +1240,7 @@ feature {NONE} -- Cookies
|
||||
if l_cookies = Void then
|
||||
if attached {WSF_STRING} meta_variable ({WSF_META_NAMES}.http_cookie) as val then
|
||||
s := val.value
|
||||
create l_cookies.make_with_key_tester (5, string_equality_tester)
|
||||
l_cookies.compare_objects
|
||||
create l_cookies.make_equal (5)
|
||||
from
|
||||
n := s.count
|
||||
p := 1
|
||||
@@ -1178,8 +1268,7 @@ feature {NONE} -- Cookies
|
||||
end
|
||||
end
|
||||
else
|
||||
create l_cookies.make_with_key_tester (0, string_equality_tester)
|
||||
l_cookies.compare_objects
|
||||
create l_cookies.make_equal (0)
|
||||
end
|
||||
internal_cookies_table := l_cookies
|
||||
end
|
||||
@@ -1205,7 +1294,7 @@ feature -- Path parameters
|
||||
|
||||
feature {NONE} -- Query parameters: implementation
|
||||
|
||||
path_parameters_table: detachable HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
path_parameters_table: detachable STRING_TABLE [WSF_VALUE]
|
||||
-- Parameters computed from `path_parameters_source'
|
||||
--| most often coming from the associated route from WSF_ROUTER
|
||||
|
||||
@@ -1228,8 +1317,7 @@ feature {WSF_REQUEST_PATH_PARAMETERS_SOURCE} -- Path parameters: Element change
|
||||
if l_count = 0 then
|
||||
l_table := Void
|
||||
else
|
||||
create l_table.make_with_key_tester (l_count, string_equality_tester)
|
||||
l_table.compare_objects
|
||||
create l_table.make_equal (l_count)
|
||||
if attached src.path_parameters as tb then
|
||||
across
|
||||
tb as c
|
||||
@@ -1266,7 +1354,7 @@ feature -- Query parameters
|
||||
|
||||
feature {NONE} -- Query parameters: implementation
|
||||
|
||||
query_parameters_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
query_parameters_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Parameters extracted from QUERY_STRING
|
||||
local
|
||||
vars: like internal_query_parameters_table
|
||||
@@ -1291,13 +1379,12 @@ feature {NONE} -- Query parameters: implementation
|
||||
end
|
||||
end
|
||||
vars := urlencoded_parameters (s)
|
||||
vars.compare_objects
|
||||
internal_query_parameters_table := vars
|
||||
end
|
||||
Result := vars
|
||||
end
|
||||
|
||||
urlencoded_parameters (a_content: detachable READABLE_STRING_8): HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
urlencoded_parameters (a_content: detachable READABLE_STRING_8): STRING_TABLE [WSF_VALUE]
|
||||
-- Import `a_content'
|
||||
local
|
||||
n, p, i, j: INTEGER
|
||||
@@ -1305,13 +1392,13 @@ feature {NONE} -- Query parameters: implementation
|
||||
l_name, l_value: READABLE_STRING_8
|
||||
do
|
||||
if a_content = Void then
|
||||
create Result.make_with_key_tester (0, string_equality_tester)
|
||||
create Result.make_equal (0)
|
||||
else
|
||||
n := a_content.count
|
||||
if n = 0 then
|
||||
create Result.make_with_key_tester (0, string_equality_tester)
|
||||
create Result.make_equal (0)
|
||||
else
|
||||
create Result.make_with_key_tester (3, string_equality_tester) --| 3 = arbitrary value
|
||||
create Result.make_equal (3) --| 3 = arbitrary value
|
||||
from
|
||||
p := 1
|
||||
until
|
||||
@@ -1336,6 +1423,8 @@ feature {NONE} -- Query parameters: implementation
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_with_object_comparison: Result.object_comparison
|
||||
end
|
||||
|
||||
feature -- Form fields and related
|
||||
@@ -1440,7 +1529,7 @@ feature {NONE} -- Implementation: MIME handler
|
||||
|
||||
feature {NONE} -- Form fields and related
|
||||
|
||||
uploaded_files_table: HASH_TABLE_EX [WSF_UPLOADED_FILE, READABLE_STRING_GENERAL]
|
||||
uploaded_files_table: STRING_TABLE [WSF_UPLOADED_FILE]
|
||||
|
||||
get_form_parameters
|
||||
-- Variables sent by POST, ... request
|
||||
@@ -1452,14 +1541,12 @@ feature {NONE} -- Form fields and related
|
||||
vars := internal_form_data_parameters_table
|
||||
if vars = Void then
|
||||
if not is_chunked_input and content_length_value = 0 then
|
||||
create vars.make_with_key_tester (0, string_equality_tester)
|
||||
vars.compare_objects
|
||||
create vars.make_equal (0)
|
||||
else
|
||||
if raw_input_data_recorded then
|
||||
create l_raw_data_cell.put (Void)
|
||||
end
|
||||
create vars.make_with_key_tester (5, string_equality_tester)
|
||||
vars.compare_objects
|
||||
create vars.make_equal (5)
|
||||
|
||||
l_type := content_type
|
||||
if l_type /= Void and then attached mime_handler (l_type) as hdl then
|
||||
@@ -1476,7 +1563,7 @@ feature {NONE} -- Form fields and related
|
||||
internal_form_data_parameters_table /= Void
|
||||
end
|
||||
|
||||
form_parameters_table: HASH_TABLE_EX [WSF_VALUE, READABLE_STRING_GENERAL]
|
||||
form_parameters_table: STRING_TABLE [WSF_VALUE]
|
||||
-- Variables sent by POST request
|
||||
local
|
||||
vars: like internal_form_data_parameters_table
|
||||
@@ -1485,14 +1572,14 @@ feature {NONE} -- Form fields and related
|
||||
vars := internal_form_data_parameters_table
|
||||
if vars = Void then
|
||||
check form_parameters_already_retrieved: False end
|
||||
create vars.make_with_key_tester (0, string_equality_tester)
|
||||
create vars.make_equal (0)
|
||||
end
|
||||
Result := vars
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: smart parameter identification
|
||||
|
||||
add_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL])
|
||||
add_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: STRING_TABLE [WSF_VALUE])
|
||||
-- Add urlencoded parameter `a_name'=`a_value' to `a_table'
|
||||
-- following smart computation such as handling the "..[..]" as table
|
||||
local
|
||||
@@ -1536,7 +1623,7 @@ feature {NONE} -- Implementation: smart parameter identification
|
||||
if p > 0 then
|
||||
q := r.index_of ({CHARACTER_8} ']', p + 1)
|
||||
if q > p then
|
||||
k32 := url_encoder.decoded_string (k)
|
||||
k32 := url_decoded_string (k)
|
||||
if attached {WSF_TABLE} ptb.value (k32) as l_tb_value then
|
||||
tb := l_tb_value
|
||||
else
|
||||
@@ -1598,7 +1685,7 @@ feature -- Uploaded File Handling
|
||||
until
|
||||
l_files.after or Result
|
||||
loop
|
||||
if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string_general (a_filename) then
|
||||
if attached l_files.item_for_iteration.tmp_path as l_tmp_path and then a_filename.same_string (l_tmp_path.name) then
|
||||
Result := True
|
||||
end
|
||||
l_files.forth
|
||||
@@ -1674,7 +1761,7 @@ feature -- URL Utility
|
||||
elseif spos > 0 then
|
||||
i := spos
|
||||
end
|
||||
spos := l_rq_uri.substring_index (path_info, i)
|
||||
spos := l_rq_uri.substring_index (percent_encoded_path_info, i)
|
||||
if spos > 0 then
|
||||
l_base_url := l_rq_uri.substring (1, spos - 1)
|
||||
else
|
||||
@@ -1714,7 +1801,7 @@ feature -- Element change
|
||||
error_handler := ehdl
|
||||
end
|
||||
|
||||
feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
|
||||
delete_uploaded_file (uf: WSF_UPLOADED_FILE)
|
||||
-- Delete file `a_filename'
|
||||
@@ -1724,18 +1811,18 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
f: RAW_FILE
|
||||
do
|
||||
if uploaded_files_table.has_item (uf) then
|
||||
if attached uf.tmp_name as fn then
|
||||
create f.make (fn)
|
||||
if attached uf.tmp_path as fn then
|
||||
create f.make_with_path (fn)
|
||||
if f.exists and then f.is_writable then
|
||||
f.delete
|
||||
else
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete file %""+ fn +"%"")
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", {STRING_32} "Can not delete file %""+ fn.name + {STRING_32} "%"")
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete uploaded file %""+ uf.name +"%" Tmp File not found")
|
||||
error_handler.add_custom_error (0, "Can not delete uploaded file", {STRING_32} "Can not delete uploaded file %""+ uf.name + {STRING_32} "%" Tmp File not found")
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "Not an uploaded file", "This file %""+ uf.name +"%" is not an uploaded file.")
|
||||
error_handler.add_custom_error (0, "Not an uploaded file", {STRING_32} "This file %""+ uf.name + {STRING_32} "%" is not an uploaded file.")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1745,37 +1832,39 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
bn: STRING
|
||||
l_safe_name: STRING
|
||||
f: RAW_FILE
|
||||
dn: STRING
|
||||
fn: FILE_NAME
|
||||
dn: PATH
|
||||
fn: PATH
|
||||
d: DIRECTORY
|
||||
n: INTEGER
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
-- FIXME: should it be configured somewhere?
|
||||
dn := (create {EXECUTION_ENVIRONMENT}).current_working_directory
|
||||
create d.make (dn)
|
||||
if attached uploaded_file_path as p then
|
||||
dn := p
|
||||
else
|
||||
-- FIXME: should it be configured somewhere?
|
||||
dn := execution_environment.current_working_path
|
||||
end
|
||||
create d.make_with_path (dn)
|
||||
if d.exists and then d.is_writable then
|
||||
l_safe_name := a_up_file.safe_filename
|
||||
from
|
||||
create fn.make_from_string (dn)
|
||||
bn := "tmp-" + l_safe_name
|
||||
fn.set_file_name (bn)
|
||||
create f.make (fn.string)
|
||||
fn := dn.extended (bn)
|
||||
create f.make_with_path (fn)
|
||||
n := 0
|
||||
until
|
||||
not f.exists
|
||||
or else n > 1_000
|
||||
loop
|
||||
n := n + 1
|
||||
fn.make_from_string (dn)
|
||||
bn := "tmp-" + n.out + "-" + l_safe_name
|
||||
fn.set_file_name (bn)
|
||||
f.make (fn.string)
|
||||
fn := dn.extended (bn)
|
||||
f.make_with_path (fn)
|
||||
end
|
||||
|
||||
if not f.exists or else f.is_writable then
|
||||
a_up_file.set_tmp_name (f.name)
|
||||
a_up_file.set_tmp_path (f.path)
|
||||
a_up_file.set_tmp_basename (bn)
|
||||
f.open_write
|
||||
f.put_string (a_content)
|
||||
@@ -1784,7 +1873,7 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
a_up_file.set_error (-1)
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "Directory not writable", "Can not create file in directory %""+ dn +"%"")
|
||||
error_handler.add_custom_error (0, "Directory not writable", {STRING_32} "Can not create file in directory %""+ dn.name + {STRING_32} "%"")
|
||||
end
|
||||
uploaded_files_table.force (a_up_file, a_up_file.name)
|
||||
else
|
||||
@@ -1795,6 +1884,19 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||
retry
|
||||
end
|
||||
|
||||
feature {WSF_REQUEST_EXPORTER} -- Settings
|
||||
|
||||
uploaded_file_path: detachable PATH
|
||||
-- Optional folder path used to store uploaded files
|
||||
|
||||
set_uploaded_file_path (p: like uploaded_file_path)
|
||||
-- Set `uploaded_file_path' to `p'.
|
||||
require
|
||||
path_exists: p /= Void implies (create {DIRECTORY}.make_with_path (p)).exists
|
||||
do
|
||||
uploaded_file_path := p
|
||||
end
|
||||
|
||||
feature {NONE} -- Internal value
|
||||
|
||||
internal_query_parameters_table: detachable like query_parameters_table
|
||||
@@ -1845,8 +1947,6 @@ feature {NONE} -- Implementation
|
||||
|
||||
feature {NONE} -- Implementation: utilities
|
||||
|
||||
string_equality_tester: STRING_EQUALITY_TESTER
|
||||
|
||||
single_slash_starting_string (s: READABLE_STRING_32): STRING_32
|
||||
-- Return the string `s' (or twin) with one and only one starting slash
|
||||
local
|
||||
@@ -1898,17 +1998,27 @@ feature {NONE} -- Implementation: utilities
|
||||
create Result.make (a_name, a_value)
|
||||
end
|
||||
|
||||
empty_string: READABLE_STRING_32
|
||||
empty_string_32: IMMUTABLE_STRING_32
|
||||
-- Reusable empty string
|
||||
|
||||
raw_url_encoder: URL_ENCODER
|
||||
once
|
||||
create {URL_ENCODER} Result
|
||||
create Result.make_empty
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
empty_string_8: IMMUTABLE_STRING_8
|
||||
once
|
||||
create {UTF8_URL_ENCODER} Result
|
||||
create Result.make_empty
|
||||
end
|
||||
|
||||
url_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
do
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_encoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
url_decoded_string (s: READABLE_STRING_GENERAL): STRING_32
|
||||
do
|
||||
create Result.make (s.count)
|
||||
url_encoder.append_percent_decoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
date_time_utilities: HTTP_DATE_TIME_UTILITIES
|
||||
@@ -1918,7 +2028,8 @@ feature {NONE} -- Implementation: utilities
|
||||
end
|
||||
|
||||
invariant
|
||||
empty_string_unchanged: empty_string.is_empty
|
||||
empty_string_32_unchanged: empty_string_32.is_empty
|
||||
empty_string_8_unchanged: empty_string_8.is_empty
|
||||
wgi_request.content_type /= Void implies content_type /= Void
|
||||
|
||||
note
|
||||
|
||||
Reference in New Issue
Block a user