Integrated new system to handle form_parameter, input_data in relation with MIME handling
This is not yet clear how to let the user precise its own MIME handler but it is in progress
This commit is contained in:
143
library/server/wsf/src/support/wsf_mime_handler_helper.e
Normal file
143
library/server/wsf/src/support/wsf_mime_handler_helper.e
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_MIME_HANDLER_HELPER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_MIME_HANDLER_HELPER
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
read_input_data (a_input: WGI_INPUT_STREAM; nb: NATURAL_64): READABLE_STRING_8
|
||||||
|
-- All data from input form
|
||||||
|
local
|
||||||
|
nb32: INTEGER
|
||||||
|
n64: NATURAL_64
|
||||||
|
n: INTEGER
|
||||||
|
t: STRING
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
from
|
||||||
|
n64 := nb
|
||||||
|
nb32 := n64.to_integer_32
|
||||||
|
create s.make (nb32)
|
||||||
|
Result := s
|
||||||
|
n := nb32
|
||||||
|
if n > 1_024 then
|
||||||
|
n := 1_024
|
||||||
|
end
|
||||||
|
until
|
||||||
|
n64 <= 0
|
||||||
|
loop
|
||||||
|
a_input.read_string (n)
|
||||||
|
t := a_input.last_string
|
||||||
|
s.append_string (t)
|
||||||
|
if t.count < n then
|
||||||
|
n64 := 0
|
||||||
|
else
|
||||||
|
n64 := n64 - t.count.as_natural_64
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
add_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32])
|
||||||
|
local
|
||||||
|
|
||||||
|
v: detachable WSF_VALUE
|
||||||
|
n,k,r: STRING_8
|
||||||
|
k32: STRING_32
|
||||||
|
p,q: INTEGER
|
||||||
|
tb,ptb: detachable WSF_TABLE
|
||||||
|
do
|
||||||
|
--| Check if this is a list format such as choice[] or choice[a] or even choice[a][] or choice[a][b][c]...
|
||||||
|
p := a_name.index_of ('[', 1)
|
||||||
|
if p > 0 then
|
||||||
|
q := a_name.index_of (']', p + 1)
|
||||||
|
if q > p then
|
||||||
|
n := a_name.substring (1, p - 1)
|
||||||
|
r := a_name.substring (q + 1, a_name.count)
|
||||||
|
r.left_adjust; r.right_adjust
|
||||||
|
|
||||||
|
create tb.make (n)
|
||||||
|
if a_table.has_key (tb.name) and then attached {WSF_TABLE} a_table.found_item as l_existing_table then
|
||||||
|
tb := l_existing_table
|
||||||
|
end
|
||||||
|
|
||||||
|
k := a_name.substring (p + 1, q - 1)
|
||||||
|
k.left_adjust; k.right_adjust
|
||||||
|
if k.is_empty then
|
||||||
|
k.append_integer (tb.count + 1)
|
||||||
|
end
|
||||||
|
v := tb
|
||||||
|
n.append_character ('[')
|
||||||
|
n.append (k)
|
||||||
|
n.append_character (']')
|
||||||
|
|
||||||
|
from
|
||||||
|
until
|
||||||
|
r.is_empty
|
||||||
|
loop
|
||||||
|
ptb := tb
|
||||||
|
p := r.index_of ({CHARACTER_8} '[', 1)
|
||||||
|
if p > 0 then
|
||||||
|
q := r.index_of ({CHARACTER_8} ']', p + 1)
|
||||||
|
if q > p then
|
||||||
|
k32 := url_encoder.decoded_string (k)
|
||||||
|
if attached {WSF_TABLE} ptb.value (k32) as l_tb_value then
|
||||||
|
tb := l_tb_value
|
||||||
|
else
|
||||||
|
create tb.make (n)
|
||||||
|
ptb.add_value (tb, k32)
|
||||||
|
end
|
||||||
|
|
||||||
|
k := r.substring (p + 1, q - 1)
|
||||||
|
r := r.substring (q + 1, r.count)
|
||||||
|
r.left_adjust; r.right_adjust
|
||||||
|
if k.is_empty then
|
||||||
|
k.append_integer (tb.count + 1)
|
||||||
|
end
|
||||||
|
n.append_character ('[')
|
||||||
|
n.append (k)
|
||||||
|
n.append_character (']')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
r.wipe_out
|
||||||
|
--| Ignore bad value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tb.add_value (new_string_value (n, a_value), k)
|
||||||
|
else
|
||||||
|
--| Missing end bracket
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if v = Void then
|
||||||
|
v := new_string_value (a_name, a_value)
|
||||||
|
end
|
||||||
|
if a_table.has_key (v.name) and then attached a_table.found_item as l_existing_value then
|
||||||
|
if tb /= Void then
|
||||||
|
--| Already done in previous part
|
||||||
|
elseif attached {WSF_MULTIPLE_STRING} l_existing_value as l_multi then
|
||||||
|
l_multi.add_value (v)
|
||||||
|
else
|
||||||
|
a_table.force (create {WSF_MULTIPLE_STRING}.make_with_array (<<l_existing_value, v>>), v.name)
|
||||||
|
check replaced: a_table.found and then a_table.found_item ~ l_existing_value end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
a_table.force (v, v.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
new_string_value (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8): WSF_STRING
|
||||||
|
do
|
||||||
|
create Result.make (a_name, a_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
url_encoder: URL_ENCODER
|
||||||
|
once
|
||||||
|
create {UTF8_URL_ENCODER} Result
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_APPLICATION_X_WWW_FORM_URLENCODED_HANDLER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_APPLICATION_X_WWW_FORM_URLENCODED_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_MIME_HANDLER
|
||||||
|
|
||||||
|
WSF_MIME_HANDLER_HELPER
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
valid_content_type (a_content_type: READABLE_STRING_8): BOOLEAN
|
||||||
|
do
|
||||||
|
Result := a_content_type.same_string ({HTTP_MIME_TYPES}.application_x_www_form_encoded)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
handle (a_content_type: READABLE_STRING_8; a_content_length: NATURAL_64; req: WSF_REQUEST;
|
||||||
|
a_vars: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]; a_raw_data: detachable CELL [detachable STRING_8])
|
||||||
|
local
|
||||||
|
l_content: READABLE_STRING_8
|
||||||
|
n, p, i, j: INTEGER
|
||||||
|
s: READABLE_STRING_8
|
||||||
|
l_name, l_value: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
l_content := read_input_data (req.input, a_content_length)
|
||||||
|
if a_raw_data /= Void then
|
||||||
|
a_raw_data.replace (l_content)
|
||||||
|
end
|
||||||
|
n := l_content.count
|
||||||
|
check n_same_as_content_length: n = a_content_length.to_integer_32 end --| FIXME: truncated value
|
||||||
|
if n > 0 then
|
||||||
|
from
|
||||||
|
p := 1
|
||||||
|
until
|
||||||
|
p = 0
|
||||||
|
loop
|
||||||
|
i := l_content.index_of ('&', p)
|
||||||
|
if i = 0 then
|
||||||
|
s := l_content.substring (p, n)
|
||||||
|
p := 0
|
||||||
|
else
|
||||||
|
s := l_content.substring (p, i - 1)
|
||||||
|
p := i + 1
|
||||||
|
end
|
||||||
|
if not s.is_empty then
|
||||||
|
j := s.index_of ('=', 1)
|
||||||
|
if j > 0 then
|
||||||
|
l_name := s.substring (1, j - 1)
|
||||||
|
l_value := s.substring (j + 1, s.count)
|
||||||
|
add_value_to_table (l_name, l_value, a_vars)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
27
library/server/wsf/src/wsf_mime_handler.e
Normal file
27
library/server/wsf/src/wsf_mime_handler.e
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_MIME_HANDLER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_MIME_HANDLER
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
valid_content_type (a_content_type: READABLE_STRING_8): BOOLEAN
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
handle (a_content_type: READABLE_STRING_8; a_content_length: NATURAL_64; req: WSF_REQUEST;
|
||||||
|
a_vars: TABLE [WSF_VALUE, READABLE_STRING_32]; a_raw_data: detachable CELL [detachable STRING_8])
|
||||||
|
-- Handle MIME content from request `req', eventually fill the `a_vars' (not yet available from `req')
|
||||||
|
-- and if `a_raw_data' is attached, store any read data inside `a_raw_data'
|
||||||
|
require
|
||||||
|
valid_content_type: valid_content_type (a_content_type)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
248
library/server/wsf/src/wsf_multipart_form_data_handler.e
Normal file
248
library/server/wsf/src/wsf_multipart_form_data_handler.e
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_MULTIPART_FORM_DATA_HANDLER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_MULTIPART_FORM_DATA_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_MIME_HANDLER
|
||||||
|
|
||||||
|
WSF_MIME_HANDLER_HELPER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_err_handler: like error_handler)
|
||||||
|
-- Instantiate Current
|
||||||
|
do
|
||||||
|
error_handler := a_err_handler
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Error handling
|
||||||
|
|
||||||
|
has_error: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := error_handler.has_error
|
||||||
|
end
|
||||||
|
|
||||||
|
error_handler: ERROR_HANDLER
|
||||||
|
-- Error handler
|
||||||
|
-- By default initialized to new handler
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
valid_content_type (a_content_type: READABLE_STRING_8): BOOLEAN
|
||||||
|
do
|
||||||
|
Result := a_content_type.starts_with ({HTTP_MIME_TYPES}.multipart_form_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
handle (a_content_type: READABLE_STRING_8; a_content_length: NATURAL_64; req: WSF_REQUEST;
|
||||||
|
a_vars: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]; a_raw_data: detachable CELL [detachable STRING_8])
|
||||||
|
local
|
||||||
|
s: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
s := read_input_data (req.input, a_content_length)
|
||||||
|
if a_raw_data /= Void then
|
||||||
|
a_raw_data.replace (s)
|
||||||
|
end
|
||||||
|
--| FIXME: optimization ... fetch the input data progressively, otherwise we might run out of memory ...
|
||||||
|
analyze_multipart_form (req, a_content_type, s, a_vars)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: Form analyzer
|
||||||
|
|
||||||
|
analyze_multipart_form (req: WSF_REQUEST; t: READABLE_STRING_8; s: READABLE_STRING_8; vars: HASH_TABLE [WSF_VALUE, READABLE_STRING_32])
|
||||||
|
-- Analyze multipart form content
|
||||||
|
--| FIXME[2011-06-21]: integrate eMIME parser library
|
||||||
|
require
|
||||||
|
t_attached: t /= Void
|
||||||
|
s_attached: s /= Void
|
||||||
|
vars_attached: vars /= Void
|
||||||
|
local
|
||||||
|
p,i,next_b: INTEGER
|
||||||
|
l_boundary_prefix: STRING
|
||||||
|
l_boundary: STRING
|
||||||
|
l_boundary_len: INTEGER
|
||||||
|
m: STRING
|
||||||
|
is_crlf: BOOLEAN
|
||||||
|
do
|
||||||
|
p := t.substring_index ("boundary=", 1)
|
||||||
|
if p > 0 then
|
||||||
|
l_boundary := t.substring (p + 9, t.count)
|
||||||
|
p := s.substring_index (l_boundary, 1)
|
||||||
|
if p > 1 then
|
||||||
|
l_boundary_prefix := s.substring (1, p - 1)
|
||||||
|
l_boundary := l_boundary_prefix + l_boundary
|
||||||
|
else
|
||||||
|
create l_boundary_prefix.make_empty
|
||||||
|
end
|
||||||
|
l_boundary_len := l_boundary.count
|
||||||
|
--| Let's support either %R%N and %N ...
|
||||||
|
--| Since both cases might occurs (for instance, our implementation of CGI does not have %R%N)
|
||||||
|
--| then let's be as flexible as possible on this.
|
||||||
|
is_crlf := s[l_boundary_len + 1] = '%R'
|
||||||
|
from
|
||||||
|
i := 1 + l_boundary_len + 1
|
||||||
|
if is_crlf then
|
||||||
|
i := i + 1 --| +1 = CR = %R
|
||||||
|
end
|
||||||
|
next_b := i
|
||||||
|
until
|
||||||
|
i = 0
|
||||||
|
loop
|
||||||
|
next_b := s.substring_index (l_boundary, i)
|
||||||
|
if next_b > 0 then
|
||||||
|
if is_crlf then
|
||||||
|
m := s.substring (i, next_b - 1 - 2) --| 2 = CR LF = %R %N
|
||||||
|
else
|
||||||
|
m := s.substring (i, next_b - 1 - 1) --| 1 = LF = %N
|
||||||
|
end
|
||||||
|
analyze_multipart_form_input (req, m, vars)
|
||||||
|
i := next_b + l_boundary_len + 1
|
||||||
|
if is_crlf then
|
||||||
|
i := i + 1 --| +1 = CR = %R
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if is_crlf then
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
m := s.substring (i - 1, s.count)
|
||||||
|
m.right_adjust
|
||||||
|
if not l_boundary_prefix.same_string (m) then
|
||||||
|
error_handler.add_custom_error (0, "Invalid form data", "Invalid ending for form data from input")
|
||||||
|
end
|
||||||
|
i := next_b
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
analyze_multipart_form_input (req: WSF_REQUEST; s: STRING; vars: HASH_TABLE [WSF_VALUE, READABLE_STRING_32])
|
||||||
|
-- Analyze multipart entry
|
||||||
|
require
|
||||||
|
s_not_empty: s /= Void and then not s.is_empty
|
||||||
|
local
|
||||||
|
n, i,p, b,e: INTEGER
|
||||||
|
l_name, l_filename, l_content_type: detachable STRING_8
|
||||||
|
l_header: detachable STRING_8
|
||||||
|
l_content: detachable STRING_8
|
||||||
|
l_line: detachable STRING_8
|
||||||
|
l_up_file_info: WGI_UPLOADED_FILE_DATA
|
||||||
|
do
|
||||||
|
from
|
||||||
|
p := 1
|
||||||
|
n := s.count
|
||||||
|
until
|
||||||
|
p > n or l_header /= Void
|
||||||
|
loop
|
||||||
|
inspect s[p]
|
||||||
|
when '%R' then -- CR
|
||||||
|
if
|
||||||
|
n >= p + 3 and then
|
||||||
|
s[p+1] = '%N' and then -- LF
|
||||||
|
s[p+2] = '%R' and then -- CR
|
||||||
|
s[p+3] = '%N' -- LF
|
||||||
|
then
|
||||||
|
l_header := s.substring (1, p + 1)
|
||||||
|
l_content := s.substring (p + 4, n)
|
||||||
|
end
|
||||||
|
when '%N' then
|
||||||
|
if
|
||||||
|
n >= p + 1 and then
|
||||||
|
s[p+1] = '%N'
|
||||||
|
then
|
||||||
|
l_header := s.substring (1, p)
|
||||||
|
l_content := s.substring (p + 2, n)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
end
|
||||||
|
p := p + 1
|
||||||
|
end
|
||||||
|
if l_header /= Void and l_content /= Void then
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := l_header.count
|
||||||
|
until
|
||||||
|
i = 0 or i > n
|
||||||
|
loop
|
||||||
|
l_line := Void
|
||||||
|
b := i
|
||||||
|
p := l_header.index_of ('%N', b)
|
||||||
|
if p > 0 then
|
||||||
|
if l_header[p - 1] = '%R' then
|
||||||
|
p := p - 1
|
||||||
|
i := p + 2
|
||||||
|
else
|
||||||
|
i := p + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if p > 0 then
|
||||||
|
l_line := l_header.substring (b, p - 1)
|
||||||
|
if l_line.starts_with ("Content-Disposition: form-data") then
|
||||||
|
p := l_line.substring_index ("name=", 1)
|
||||||
|
if p > 0 then
|
||||||
|
p := p + 4 --| 4 = ("name=").count - 1
|
||||||
|
if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then
|
||||||
|
p := p + 1
|
||||||
|
e := l_line.index_of ('"', p + 1)
|
||||||
|
else
|
||||||
|
e := l_line.index_of (';', p + 1)
|
||||||
|
if e = 0 then
|
||||||
|
e := l_line.count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
l_name := l_header.substring (p + 1, e - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
p := l_line.substring_index ("filename=", 1)
|
||||||
|
if p > 0 then
|
||||||
|
p := p + 8 --| 8 = ("filename=").count - 1
|
||||||
|
if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then
|
||||||
|
p := p + 1
|
||||||
|
e := l_line.index_of ('"', p + 1)
|
||||||
|
else
|
||||||
|
e := l_line.index_of (';', p + 1)
|
||||||
|
if e = 0 then
|
||||||
|
e := l_line.count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
l_filename := l_header.substring (p + 1, e - 1)
|
||||||
|
end
|
||||||
|
elseif l_line.starts_with ("Content-Type: ") then
|
||||||
|
l_content_type := l_line.substring (15, l_line.count)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
i := 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if l_name /= Void then
|
||||||
|
if l_filename /= Void then
|
||||||
|
if l_content_type = Void then
|
||||||
|
l_content_type := default_content_type
|
||||||
|
end
|
||||||
|
create l_up_file_info.make (l_filename, l_content_type, l_content.count)
|
||||||
|
req.save_uploaded_file (l_content, l_up_file_info)
|
||||||
|
req.uploaded_files.force (l_up_file_info, l_name)
|
||||||
|
else
|
||||||
|
add_value_to_table (l_name, l_content, vars)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error_handler.add_custom_error (0, "unamed multipart entry", Void)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error_handler.add_custom_error (0, "missformed multipart entry", Void)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default_content_type: STRING = "text/plain"
|
||||||
|
-- Default content type
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -53,6 +53,8 @@ feature {NONE} -- Initialization
|
|||||||
local
|
local
|
||||||
s8: detachable READABLE_STRING_8
|
s8: detachable READABLE_STRING_8
|
||||||
do
|
do
|
||||||
|
init_mime_handlers
|
||||||
|
|
||||||
--| Content-Length
|
--| Content-Length
|
||||||
if attached content_length as s and then s.is_natural_64 then
|
if attached content_length as s and then s.is_natural_64 then
|
||||||
content_length_value := s.to_natural_64
|
content_length_value := s.to_natural_64
|
||||||
@@ -1017,40 +1019,112 @@ feature -- Form fields and related
|
|||||||
--| error: if /= 0 , there was an error : TODO ...
|
--| error: if /= 0 , there was an error : TODO ...
|
||||||
--| size: size of the file given by the http request
|
--| size: size of the file given by the http request
|
||||||
|
|
||||||
|
feature -- Access: MIME handler
|
||||||
|
|
||||||
|
has_mime_handler (a_content_type: READABLE_STRING_8): BOOLEAN
|
||||||
|
-- Has a MIME handler registered for `a_content_type'?
|
||||||
|
do
|
||||||
|
if attached mime_handlers as hdls then
|
||||||
|
from
|
||||||
|
hdls.start
|
||||||
|
until
|
||||||
|
hdls.after or Result
|
||||||
|
loop
|
||||||
|
Result := hdls.item_for_iteration.valid_content_type (a_content_type)
|
||||||
|
hdls.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
register_mime_handler (a_handler: WSF_MIME_HANDLER)
|
||||||
|
-- Register `a_handler' for `a_content_type'
|
||||||
|
local
|
||||||
|
hdls: like mime_handlers
|
||||||
|
do
|
||||||
|
hdls := mime_handlers
|
||||||
|
if hdls = Void then
|
||||||
|
create hdls.make (3)
|
||||||
|
hdls.compare_objects
|
||||||
|
mime_handlers := hdls
|
||||||
|
end
|
||||||
|
hdls.force (a_handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
mime_handler (a_content_type: READABLE_STRING_8): detachable WSF_MIME_HANDLER
|
||||||
|
-- Mime handler associated with `a_content_type'
|
||||||
|
do
|
||||||
|
if attached mime_handlers as hdls then
|
||||||
|
from
|
||||||
|
hdls.start
|
||||||
|
until
|
||||||
|
hdls.after or Result /= Void
|
||||||
|
loop
|
||||||
|
Result := hdls.item_for_iteration
|
||||||
|
if not Result.valid_content_type (a_content_type) then
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
hdls.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
has_mime_handler_implies_attached: has_mime_handler (a_content_type) implies Result /= Void
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: MIME handler
|
||||||
|
|
||||||
|
init_mime_handlers
|
||||||
|
do
|
||||||
|
register_mime_handler (create {WSF_MULTIPART_FORM_DATA_HANDLER}.make (error_handler))
|
||||||
|
register_mime_handler (create {WSF_APPLICATION_X_WWW_FORM_URLENCODED_HANDLER})
|
||||||
|
end
|
||||||
|
|
||||||
|
mime_handlers: detachable ARRAYED_LIST [WSF_MIME_HANDLER]
|
||||||
|
-- Table of mime handles
|
||||||
|
|
||||||
feature {NONE} -- Form fields and related
|
feature {NONE} -- Form fields and related
|
||||||
|
|
||||||
form_parameters_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]
|
form_parameters_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]
|
||||||
-- Variables sent by POST request
|
-- Variables sent by POST request
|
||||||
local
|
local
|
||||||
vars: like internal_form_data_parameters_table
|
vars: like internal_form_data_parameters_table
|
||||||
s: READABLE_STRING_8
|
l_raw_data_cell: detachable CELL [detachable STRING_8]
|
||||||
n: NATURAL_64
|
n: NATURAL_64
|
||||||
l_type: like content_type
|
l_type: like content_type
|
||||||
do
|
do
|
||||||
vars := internal_form_data_parameters_table
|
vars := internal_form_data_parameters_table
|
||||||
if vars = Void then
|
if vars = Void then
|
||||||
n := content_length_value
|
n := content_length_value
|
||||||
if n > 0 then
|
if n = 0 then
|
||||||
l_type := content_type
|
|
||||||
if
|
|
||||||
l_type /= Void and then
|
|
||||||
l_type.starts_with ({HTTP_MIME_TYPES}.multipart_form_data)
|
|
||||||
then
|
|
||||||
create vars.make (5)
|
|
||||||
vars.compare_objects
|
|
||||||
--| FIXME: optimization ... fetch the input data progressively, otherwise we might run out of memory ...
|
|
||||||
s := form_input_data (n)
|
|
||||||
analyze_multipart_form (l_type, s, vars)
|
|
||||||
else
|
|
||||||
s := form_input_data (n)
|
|
||||||
vars := urlencoded_parameters (s)
|
|
||||||
end
|
|
||||||
if raw_post_data_recorded then
|
|
||||||
set_meta_string_variable ("RAW_POST_DATA", s)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
create vars.make (0)
|
create vars.make (0)
|
||||||
vars.compare_objects
|
vars.compare_objects
|
||||||
|
else
|
||||||
|
if raw_post_data_recorded then
|
||||||
|
create l_raw_data_cell.put (Void)
|
||||||
|
end
|
||||||
|
create vars.make (5)
|
||||||
|
vars.compare_objects
|
||||||
|
|
||||||
|
l_type := content_type
|
||||||
|
if l_type /= Void and then attached mime_handler (l_type) as hdl then
|
||||||
|
hdl.handle (l_type, n, Current, vars, l_raw_data_cell)
|
||||||
|
end
|
||||||
|
if l_raw_data_cell /= Void and then attached l_raw_data_cell.item as l_raw_data then
|
||||||
|
set_meta_string_variable ("RAW_POST_DATA", l_raw_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if
|
||||||
|
-- l_type /= Void and then
|
||||||
|
-- l_type.starts_with ({HTTP_MIME_TYPES}.multipart_form_data)
|
||||||
|
-- then
|
||||||
|
-- create vars.make (5)
|
||||||
|
-- vars.compare_objects
|
||||||
|
-- --| FIXME: optimization ... fetch the input data progressively, otherwise we might run out of memory ...
|
||||||
|
-- s := form_input_data (n)
|
||||||
|
-- analyze_multipart_form (l_type, s, vars)
|
||||||
|
-- else
|
||||||
|
-- s := form_input_data (n)
|
||||||
|
-- vars := urlencoded_parameters (s)
|
||||||
|
-- end
|
||||||
end
|
end
|
||||||
internal_form_data_parameters_table := vars
|
internal_form_data_parameters_table := vars
|
||||||
end
|
end
|
||||||
@@ -1130,7 +1204,8 @@ feature -- URL Utility
|
|||||||
end
|
end
|
||||||
internal_url_base := l_base_url
|
internal_url_base := l_base_url
|
||||||
end
|
end
|
||||||
Result := l_base_url + a_path
|
create Result.make_from_string (l_base_url)
|
||||||
|
Result.append (a_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation: URL Utility
|
feature {NONE} -- Implementation: URL Utility
|
||||||
@@ -1152,7 +1227,7 @@ feature -- Element change
|
|||||||
error_handler := ehdl
|
error_handler := ehdl
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Temporary File handling
|
feature {WSF_MIME_HANDLER} -- Temporary File handling
|
||||||
|
|
||||||
delete_uploaded_file (uf: WGI_UPLOADED_FILE_DATA)
|
delete_uploaded_file (uf: WGI_UPLOADED_FILE_DATA)
|
||||||
-- Delete file `a_filename'
|
-- Delete file `a_filename'
|
||||||
@@ -1312,224 +1387,41 @@ feature {NONE} -- Temporary File handling
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation: Form analyzer
|
feature {WSF_MIME_HANDLER} -- Input data access
|
||||||
|
|
||||||
analyze_multipart_form (t: STRING; s: STRING; vars: like form_parameters_table)
|
|
||||||
-- Analyze multipart form content
|
|
||||||
--| FIXME[2011-06-21]: integrate eMIME parser library
|
|
||||||
require
|
|
||||||
t_attached: t /= Void
|
|
||||||
s_attached: s /= Void
|
|
||||||
vars_attached: vars /= Void
|
|
||||||
local
|
|
||||||
p,i,next_b: INTEGER
|
|
||||||
l_boundary_prefix: STRING
|
|
||||||
l_boundary: STRING
|
|
||||||
l_boundary_len: INTEGER
|
|
||||||
m: STRING
|
|
||||||
is_crlf: BOOLEAN
|
|
||||||
do
|
|
||||||
p := t.substring_index ("boundary=", 1)
|
|
||||||
if p > 0 then
|
|
||||||
l_boundary := t.substring (p + 9, t.count)
|
|
||||||
p := s.substring_index (l_boundary, 1)
|
|
||||||
if p > 1 then
|
|
||||||
l_boundary_prefix := s.substring (1, p - 1)
|
|
||||||
l_boundary := l_boundary_prefix + l_boundary
|
|
||||||
else
|
|
||||||
create l_boundary_prefix.make_empty
|
|
||||||
end
|
|
||||||
l_boundary_len := l_boundary.count
|
|
||||||
--| Let's support either %R%N and %N ...
|
|
||||||
--| Since both cases might occurs (for instance, our implementation of CGI does not have %R%N)
|
|
||||||
--| then let's be as flexible as possible on this.
|
|
||||||
is_crlf := s[l_boundary_len + 1] = '%R'
|
|
||||||
from
|
|
||||||
i := 1 + l_boundary_len + 1
|
|
||||||
if is_crlf then
|
|
||||||
i := i + 1 --| +1 = CR = %R
|
|
||||||
end
|
|
||||||
next_b := i
|
|
||||||
until
|
|
||||||
i = 0
|
|
||||||
loop
|
|
||||||
next_b := s.substring_index (l_boundary, i)
|
|
||||||
if next_b > 0 then
|
|
||||||
if is_crlf then
|
|
||||||
m := s.substring (i, next_b - 1 - 2) --| 2 = CR LF = %R %N
|
|
||||||
else
|
|
||||||
m := s.substring (i, next_b - 1 - 1) --| 1 = LF = %N
|
|
||||||
end
|
|
||||||
analyze_multipart_form_input (m, vars)
|
|
||||||
i := next_b + l_boundary_len + 1
|
|
||||||
if is_crlf then
|
|
||||||
i := i + 1 --| +1 = CR = %R
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if is_crlf then
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
m := s.substring (i - 1, s.count)
|
|
||||||
m.right_adjust
|
|
||||||
if not l_boundary_prefix.same_string (m) then
|
|
||||||
error_handler.add_custom_error (0, "Invalid form data", "Invalid ending for form data from input")
|
|
||||||
end
|
|
||||||
i := next_b
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
analyze_multipart_form_input (s: STRING; vars_post: like form_parameters_table)
|
|
||||||
-- Analyze multipart entry
|
|
||||||
require
|
|
||||||
s_not_empty: s /= Void and then not s.is_empty
|
|
||||||
local
|
|
||||||
n, i,p, b,e: INTEGER
|
|
||||||
l_name, l_filename, l_content_type: detachable STRING_8
|
|
||||||
l_header: detachable STRING_8
|
|
||||||
l_content: detachable STRING_8
|
|
||||||
l_line: detachable STRING_8
|
|
||||||
l_up_file_info: WGI_UPLOADED_FILE_DATA
|
|
||||||
do
|
|
||||||
from
|
|
||||||
p := 1
|
|
||||||
n := s.count
|
|
||||||
until
|
|
||||||
p > n or l_header /= Void
|
|
||||||
loop
|
|
||||||
inspect s[p]
|
|
||||||
when '%R' then -- CR
|
|
||||||
if
|
|
||||||
n >= p + 3 and then
|
|
||||||
s[p+1] = '%N' and then -- LF
|
|
||||||
s[p+2] = '%R' and then -- CR
|
|
||||||
s[p+3] = '%N' -- LF
|
|
||||||
then
|
|
||||||
l_header := s.substring (1, p + 1)
|
|
||||||
l_content := s.substring (p + 4, n)
|
|
||||||
end
|
|
||||||
when '%N' then
|
|
||||||
if
|
|
||||||
n >= p + 1 and then
|
|
||||||
s[p+1] = '%N'
|
|
||||||
then
|
|
||||||
l_header := s.substring (1, p)
|
|
||||||
l_content := s.substring (p + 2, n)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
end
|
|
||||||
p := p + 1
|
|
||||||
end
|
|
||||||
if l_header /= Void and l_content /= Void then
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
n := l_header.count
|
|
||||||
until
|
|
||||||
i = 0 or i > n
|
|
||||||
loop
|
|
||||||
l_line := Void
|
|
||||||
b := i
|
|
||||||
p := l_header.index_of ('%N', b)
|
|
||||||
if p > 0 then
|
|
||||||
if l_header[p - 1] = '%R' then
|
|
||||||
p := p - 1
|
|
||||||
i := p + 2
|
|
||||||
else
|
|
||||||
i := p + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if p > 0 then
|
|
||||||
l_line := l_header.substring (b, p - 1)
|
|
||||||
if l_line.starts_with ("Content-Disposition: form-data") then
|
|
||||||
p := l_line.substring_index ("name=", 1)
|
|
||||||
if p > 0 then
|
|
||||||
p := p + 4 --| 4 = ("name=").count - 1
|
|
||||||
if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then
|
|
||||||
p := p + 1
|
|
||||||
e := l_line.index_of ('"', p + 1)
|
|
||||||
else
|
|
||||||
e := l_line.index_of (';', p + 1)
|
|
||||||
if e = 0 then
|
|
||||||
e := l_line.count
|
|
||||||
end
|
|
||||||
end
|
|
||||||
l_name := l_header.substring (p + 1, e - 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
p := l_line.substring_index ("filename=", 1)
|
|
||||||
if p > 0 then
|
|
||||||
p := p + 8 --| 8 = ("filename=").count - 1
|
|
||||||
if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then
|
|
||||||
p := p + 1
|
|
||||||
e := l_line.index_of ('"', p + 1)
|
|
||||||
else
|
|
||||||
e := l_line.index_of (';', p + 1)
|
|
||||||
if e = 0 then
|
|
||||||
e := l_line.count
|
|
||||||
end
|
|
||||||
end
|
|
||||||
l_filename := l_header.substring (p + 1, e - 1)
|
|
||||||
end
|
|
||||||
elseif l_line.starts_with ("Content-Type: ") then
|
|
||||||
l_content_type := l_line.substring (15, l_line.count)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
i := 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if l_name /= Void then
|
|
||||||
if l_filename /= Void then
|
|
||||||
if l_content_type = Void then
|
|
||||||
l_content_type := default_content_type
|
|
||||||
end
|
|
||||||
create l_up_file_info.make (l_filename, l_content_type, l_content.count)
|
|
||||||
save_uploaded_file (l_content, l_up_file_info)
|
|
||||||
uploaded_files.force (l_up_file_info, l_name)
|
|
||||||
else
|
|
||||||
add_value_to_table (l_name, l_content, vars_post)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
error_handler.add_custom_error (0, "unamed multipart entry", Void)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
error_handler.add_custom_error (0, "missformed multipart entry", Void)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Internal value
|
|
||||||
|
|
||||||
default_content_type: STRING = "text/plain"
|
|
||||||
-- Default content type
|
|
||||||
|
|
||||||
form_input_data (nb: NATURAL_64): READABLE_STRING_8
|
form_input_data (nb: NATURAL_64): READABLE_STRING_8
|
||||||
-- data from input form
|
-- All data from input form
|
||||||
local
|
local
|
||||||
nb32: INTEGER
|
nb32: INTEGER
|
||||||
|
n64: NATURAL_64
|
||||||
n: INTEGER
|
n: INTEGER
|
||||||
t: STRING
|
t: STRING
|
||||||
s: STRING_8
|
s: STRING_8
|
||||||
do
|
do
|
||||||
from
|
from
|
||||||
nb32 := nb.to_integer_32
|
n64 := nb
|
||||||
n := nb32
|
nb32 := n64.to_integer_32
|
||||||
create s.make (n)
|
create s.make (nb32)
|
||||||
Result := s
|
Result := s
|
||||||
|
n := nb32
|
||||||
if n > 1_024 then
|
if n > 1_024 then
|
||||||
n := 1_024
|
n := 1_024
|
||||||
end
|
end
|
||||||
until
|
until
|
||||||
n <= 0
|
n64 <= 0
|
||||||
loop
|
loop
|
||||||
input.read_string (n)
|
input.read_string (n)
|
||||||
t := input.last_string
|
t := input.last_string
|
||||||
s.append_string (t)
|
s.append_string (t)
|
||||||
if t.count < n then
|
if t.count < n then
|
||||||
n := 0
|
n64 := 0
|
||||||
end
|
else
|
||||||
n := nb32 - t.count
|
n64 := n64 - t.count.as_natural_64
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Internal value
|
||||||
|
|
||||||
internal_query_parameters_table: detachable like query_parameters_table
|
internal_query_parameters_table: detachable like query_parameters_table
|
||||||
-- cached value for `query_parameters'
|
-- cached value for `query_parameters'
|
||||||
|
|||||||
Reference in New Issue
Block a user