Added class HTTP_CONTENT_TYPE to help manipulation of Content-Type value
Now WSF_REQUEST return a HTTP_CONTENT_TYPE if available Adapted WSF_MIME_HANDLER to use this new class Added one manual autotest to test MIME handler
This commit is contained in:
@@ -14,14 +14,14 @@ inherit
|
||||
|
||||
feature -- Status report
|
||||
|
||||
valid_content_type (a_content_type: READABLE_STRING_8): BOOLEAN
|
||||
valid_content_type (a_content_type: HTTP_CONTENT_TYPE): BOOLEAN
|
||||
do
|
||||
Result := a_content_type.same_string ({HTTP_MIME_TYPES}.application_x_www_form_encoded)
|
||||
Result := a_content_type.same_type_and_subtype ({HTTP_MIME_TYPES}.application_x_www_form_encoded)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
handle (a_content_type: READABLE_STRING_8; req: WSF_REQUEST;
|
||||
handle (a_content_type: HTTP_CONTENT_TYPE; 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
|
||||
|
||||
@@ -9,13 +9,13 @@ deferred class
|
||||
|
||||
feature -- Status report
|
||||
|
||||
valid_content_type (a_content_type: READABLE_STRING_8): BOOLEAN
|
||||
valid_content_type (a_content_type: HTTP_CONTENT_TYPE): BOOLEAN
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
handle (a_content_type: READABLE_STRING_8; req: WSF_REQUEST;
|
||||
handle (a_content_type: HTTP_CONTENT_TYPE; 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'
|
||||
|
||||
@@ -17,33 +17,21 @@ create
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_err_handler: like error_handler)
|
||||
make
|
||||
-- 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
|
||||
valid_content_type (a_content_type: HTTP_CONTENT_TYPE): BOOLEAN
|
||||
do
|
||||
Result := a_content_type.starts_with ({HTTP_MIME_TYPES}.multipart_form_data)
|
||||
Result := a_content_type.same_type_and_subtype ({HTTP_MIME_TYPES}.multipart_form_data)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
handle (a_content_type: READABLE_STRING_8; req: WSF_REQUEST;
|
||||
handle (a_content_type: HTTP_CONTENT_TYPE; req: WSF_REQUEST;
|
||||
a_vars: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]; a_raw_data: detachable CELL [detachable STRING_8])
|
||||
local
|
||||
s: like full_input_data
|
||||
@@ -58,24 +46,23 @@ feature -- Execution
|
||||
|
||||
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 (req: WSF_REQUEST; a_content_type: HTTP_CONTENT_TYPE; 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
|
||||
a_content_type_valid: a_content_type /= Void and not a_content_type.has_error
|
||||
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
|
||||
l_boundary: detachable READABLE_STRING_8
|
||||
m: STRING
|
||||
is_crlf: BOOLEAN
|
||||
do
|
||||
p := t.substring_index ("boundary=", 1)
|
||||
if p > 0 then
|
||||
l_boundary := t.substring (p + 9, t.count)
|
||||
l_boundary := a_content_type.parameter ("boundary")
|
||||
if l_boundary /= Void then
|
||||
p := s.substring_index (l_boundary, 1)
|
||||
if p > 1 then
|
||||
l_boundary_prefix := s.substring (1, p - 1)
|
||||
@@ -116,7 +103,7 @@ feature {NONE} -- Implementation: Form analyzer
|
||||
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")
|
||||
req.error_handler.add_custom_error (0, "Invalid form data", "Invalid ending for form data from input")
|
||||
end
|
||||
i := next_b
|
||||
end
|
||||
@@ -235,10 +222,10 @@ feature {NONE} -- Implementation: Form analyzer
|
||||
add_string_value_to_table (l_name, l_content, vars)
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "unamed multipart entry", Void)
|
||||
req.error_handler.add_custom_error (0, "unamed multipart entry", Void)
|
||||
end
|
||||
else
|
||||
error_handler.add_custom_error (0, "missformed multipart entry", Void)
|
||||
req.error_handler.add_custom_error (0, "missformed multipart entry", Void)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -22,15 +22,15 @@ note
|
||||
class
|
||||
WSF_HEADER
|
||||
|
||||
obsolete "Use HTTP_HEADER [2011-nov-25]"
|
||||
|
||||
inherit
|
||||
HTTP_HEADER
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_count
|
||||
|
||||
make_with_count,
|
||||
make_from_array,
|
||||
make_from_header,
|
||||
make_from_raw_header_data
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
|
||||
@@ -77,6 +77,14 @@ feature {NONE} -- Initialization
|
||||
content_length_value := 0
|
||||
end
|
||||
|
||||
-- Content-Type
|
||||
s8 := wgi_request.content_type
|
||||
if s8 /= Void then
|
||||
content_type := s8
|
||||
else
|
||||
content_type := Void
|
||||
end
|
||||
|
||||
--| PATH_INFO
|
||||
path_info := url_encoder.decoded_string (wgi_request.path_info)
|
||||
|
||||
@@ -396,7 +404,7 @@ feature -- Access: CGI meta parameters - 1.1
|
||||
content_length_value: NATURAL_64
|
||||
-- Integer value related to `content_length"
|
||||
|
||||
content_type: detachable READABLE_STRING_8
|
||||
content_type: detachable HTTP_CONTENT_TYPE
|
||||
-- If the wgi_request includes a message-body, CONTENT_TYPE is set to
|
||||
-- the Internet Media Type [9] of the attached entity if the type
|
||||
-- was provided via a "Content-type" field in the wgi_request header,
|
||||
@@ -436,9 +444,6 @@ feature -- Access: CGI meta parameters - 1.1
|
||||
-- determine the correct datatype, or it MAY omit this
|
||||
-- metavariable when communicating the wgi_request information to the
|
||||
-- script.
|
||||
do
|
||||
Result := wgi_request.content_type
|
||||
end
|
||||
|
||||
gateway_interface: READABLE_STRING_8
|
||||
-- This metavariable is set to the dialect of CGI being used by
|
||||
@@ -1145,7 +1150,7 @@ feature -- Access: MIME handler
|
||||
hdls.force (a_handler)
|
||||
end
|
||||
|
||||
mime_handler (a_content_type: READABLE_STRING_8): detachable WSF_MIME_HANDLER
|
||||
mime_handler (a_content_type: HTTP_CONTENT_TYPE): detachable WSF_MIME_HANDLER
|
||||
-- Mime handler associated with `a_content_type'
|
||||
do
|
||||
if attached mime_handlers as hdls then
|
||||
@@ -1169,7 +1174,7 @@ 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_MULTIPART_FORM_DATA_HANDLER}.make)
|
||||
register_mime_handler (create {WSF_APPLICATION_X_WWW_FORM_URLENCODED_HANDLER})
|
||||
end
|
||||
|
||||
@@ -1566,7 +1571,7 @@ feature {NONE} -- Implementation: utilities
|
||||
|
||||
invariant
|
||||
empty_string_unchanged: empty_string.is_empty
|
||||
|
||||
wgi_request.content_type /= Void implies content_type /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
|
||||
118
library/server/wsf/tests/src/test_wsf_request_mime_handler.e
Normal file
118
library/server/wsf/tests/src/test_wsf_request_mime_handler.e
Normal file
@@ -0,0 +1,118 @@
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
author: "EiffelStudio test wizard"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
testing: "type/manual"
|
||||
|
||||
class
|
||||
TEST_WSF_REQUEST_MIME_HANDLER
|
||||
|
||||
inherit
|
||||
EQA_TEST_SET
|
||||
|
||||
WSF_SERVICE
|
||||
undefine
|
||||
default_create
|
||||
end
|
||||
|
||||
feature {NONE} -- Events
|
||||
|
||||
port_number: INTEGER
|
||||
base_url: detachable STRING
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
--| do nothing
|
||||
end
|
||||
|
||||
feature -- Tests
|
||||
|
||||
test_mime_handler
|
||||
local
|
||||
req: WSF_REQUEST
|
||||
b: STRING_8
|
||||
h: WSF_HEADER
|
||||
ct: HTTP_CONTENT_TYPE
|
||||
m: ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||
do
|
||||
m := <<
|
||||
["REQUEST_METHOD", "GET"],
|
||||
["QUERY_STRING", ""],
|
||||
["REQUEST_URI", "/auto/test/foo"],
|
||||
["SCRIPT_NAME", "/auto/test/test.ews"],
|
||||
["PATH_INFO", "/foo"]
|
||||
>>
|
||||
|
||||
create ct.make_from_content_type_header ({HTTP_MIME_TYPES}.multipart_form_data)
|
||||
ct.set_parameter ("boundary", "__=_the_boundary_1332296477_1804289383_=__")
|
||||
create h.make
|
||||
h.put_content_type (ct)
|
||||
|
||||
b := "[
|
||||
--__=_the_boundary_1332296477_1804289383_=__
|
||||
Content-Disposition: form-data; name="user_name"
|
||||
|
||||
EWFdemo
|
||||
--__=_the_boundary_1332296477_1804289383_=__
|
||||
Content-Disposition: form-data; name="password"
|
||||
|
||||
EWFpassword
|
||||
--__=_the_boundary_1332296477_1804289383_=__--
|
||||
]"
|
||||
|
||||
h.put_content_length (b.count)
|
||||
|
||||
--| Case #1
|
||||
req := new_request (m, h.string, b)
|
||||
assert ("found user_name", attached req.form_parameter ("user_name") as u and then u.same_string ("EWFdemo"))
|
||||
assert ("found password", attached req.form_parameter ("password") as u and then u.same_string ("EWFpassword"))
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
new_request (a_meta: ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]; h: READABLE_STRING_8; s: READABLE_STRING_8): WSF_REQUEST_NULL
|
||||
local
|
||||
wgi_req: WGI_REQUEST
|
||||
l_header: WSF_HEADER
|
||||
lst: ARRAYED_LIST [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||
vn: STRING_8
|
||||
do
|
||||
create lst.make (10)
|
||||
across
|
||||
a_meta as c
|
||||
loop
|
||||
lst.extend (c.item)
|
||||
end
|
||||
|
||||
create l_header.make_from_raw_header_data (h)
|
||||
across
|
||||
l_header.to_name_value_iterable as c
|
||||
loop
|
||||
--| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `env'
|
||||
vn := c.item.name.as_upper
|
||||
|
||||
vn.replace_substring_all ("-", "_")
|
||||
if
|
||||
vn.starts_with ("CONTENT_") and then
|
||||
(vn.same_string_general ({WGI_META_NAMES}.content_type) or vn.same_string_general ({WGI_META_NAMES}.content_length))
|
||||
then
|
||||
--| Keep this name
|
||||
else
|
||||
vn.prepend ("HTTP_")
|
||||
end
|
||||
lst.extend ([vn, c.item.value])
|
||||
-- lst.extend (c.item)
|
||||
end
|
||||
|
||||
create {WGI_REQUEST_NULL} wgi_req.make_with_body (lst, s)
|
||||
create Result.make_from_wgi (wgi_req)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ feature {NONE} -- Implementation
|
||||
local
|
||||
wgi_req: WGI_REQUEST
|
||||
do
|
||||
create {WGI_REQUEST_NULL} wgi_req.make (a_meta)
|
||||
create {WGI_REQUEST_NULL} wgi_req.make_with_file (a_meta, io.input)
|
||||
create Result.make_from_wgi (wgi_req)
|
||||
end
|
||||
|
||||
|
||||
@@ -14,19 +14,20 @@ inherit
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
make_with_file,
|
||||
make_with_body
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_meta: ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||
make_with_file (a_meta: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]; f: FILE)
|
||||
local
|
||||
ht: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
i: WGI_NULL_INPUT_STREAM
|
||||
i: WGI_NULL_FILE_INPUT_STREAM
|
||||
c: WGI_NULL_CONNECTOR
|
||||
do
|
||||
create c.make
|
||||
create i.make
|
||||
create ht.make (a_meta.count)
|
||||
create i.make (f)
|
||||
create ht.make (10)
|
||||
across
|
||||
a_meta as curs
|
||||
loop
|
||||
@@ -35,6 +36,22 @@ feature {NONE} -- Initialization
|
||||
wgi_request_from_table_make (ht, i, c)
|
||||
end
|
||||
|
||||
make_with_body (a_meta: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]; s: READABLE_STRING_8)
|
||||
local
|
||||
ht: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
i: WGI_NULL_STRING_INPUT_STREAM
|
||||
c: WGI_NULL_CONNECTOR
|
||||
do
|
||||
create c.make
|
||||
create i.make (s)
|
||||
create ht.make (10)
|
||||
across
|
||||
a_meta as curs
|
||||
loop
|
||||
ht.force (curs.item.value, curs.item.name)
|
||||
end
|
||||
wgi_request_from_table_make (ht, i, c)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<library name="http_client" location="..\..\..\client\http_client\http_client-safe.ecf" readonly="false"/>
|
||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\wsf-safe.ecf" readonly="false"/>
|
||||
<tests name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
Reference in New Issue
Block a user