Nino connector:

- fixed issue related to `ready_for_reading'  now use the `try_...' variant
 - for now Nino does not support persistent connection, then we have to respond with "Connection: close"

REQUEST_FILE_SYSTEM_HANDLER:
 - added not_found_handler and access_denied_handler, so that the user can customize related response

WSF_REQUEST and WSF_VALUE:
 - modified how uploaded file are handled, fixed various issues, and added WSF_UPLOADED_FILE (it is a WSF_VALUE)

WSF_VALUE:
 - added change_name (a_name: like name)
 - added url_encoded_name to other WSF_values

WSF_REQUEST:
 - added `destroy' to perform end of request cleaning (such as deleting temp uploaded files)
 - renamed `raw_post_data_recorded' as `raw_input_data_recorded', and related feature
 - do not store the RAW_POST_DATA in meta variable anymore, but in WSF_REQUEST.raw_input_data is asked

Added WSF_HTML_PAGE_RESPONSE to help user

WSF_REPONSE.redirect_... now use "temp_redirect" as default
  instead of "moved_permanently" which is specific usage

Removed many obsolete features.
This commit is contained in:
Jocelyn Fiat
2012-03-13 18:07:28 +01:00
parent c5fe539acb
commit 5abc79b7c3
33 changed files with 993 additions and 306 deletions

View File

@@ -117,7 +117,7 @@ feature -- Server
process_request (env: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_socket: TCP_STREAM_SOCKET)
local
req: WGI_REQUEST_FROM_TABLE
res: detachable WGI_RESPONSE_STREAM
res: detachable WGI_NINO_RESPONSE_STREAM
do
create req.make (env, create {WGI_NINO_INPUT_STREAM}.make (a_socket), Current)
create res.make (create {WGI_NINO_OUTPUT_STREAM}.make (a_socket))

View File

@@ -77,11 +77,11 @@ feature -- Status report
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
do
Result := not source.ready_for_reading
Result := not source.try_ready_for_reading
end
;note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,45 @@
note
description: "[
WGI Response implemented using stream buffer
]"
date: "$Date$"
revision: "$Revision$"
class
WGI_NINO_RESPONSE_STREAM
inherit
WGI_RESPONSE_STREAM
redefine
put_header_text
end
create
make
feature -- Header output operation
put_header_text (a_text: READABLE_STRING_8)
do
write (a_text)
-- Nino does not support persistent connection for now
write ("Connection: close")
write (crlf)
-- end of headers
write (crlf)
header_committed := True
end
;note
copyright: "2011-2012, 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

View File

@@ -1,103 +0,0 @@
note
description: "Summary description for {WGI_UPLOADED_FILE_DATA}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
WGI_UPLOADED_FILE_DATA
create
make
feature {NONE} -- Initialization
make (n: like name; t: like content_type; s: like size)
do
name := n
content_type := t
size := s
end
feature -- Access
name: STRING
-- original filename
content_type: STRING
-- Content type
size: INTEGER
-- Size of uploaded file
tmp_name: detachable STRING
-- Filename of tmp file
tmp_basename: detachable STRING
-- Basename of tmp file
feature -- Basic operation
move_to (a_destination: STRING): BOOLEAN
-- Move current uploaded file to `a_destination'
require
has_no_error: not has_error
local
f: RAW_FILE
do
if attached tmp_name as n then
create f.make (n)
if f.exists then
f.change_name (a_destination)
Result := True
end
end
end
feature -- Status
has_error: BOOLEAN
-- Has error during uploading
do
Result := error /= 0
end
error: INTEGER
-- Eventual error code
--| no error => 0
feature -- Element change
set_error (e: like error)
-- Set `error' to `e'
do
error := e
end
set_tmp_name (n: like tmp_name)
-- Set `tmp_name' to `n'
do
tmp_name := n
end
set_tmp_basename (n: like tmp_basename)
-- Set `tmp_basename' to `n'
do
tmp_basename := n
end
invariant
valid_tmp_name: not has_error implies attached tmp_name as n and then not n.is_empty
note
copyright: "2011-2011, 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

View File

@@ -20,7 +20,7 @@ feature {NONE} -- Implementation
feature -- Input
data: READABLE_STRING_8
data: STRING_8
local
d: like internal_data
do
@@ -34,13 +34,13 @@ feature -- Input
feature {NONE} -- Parser
internal_data: detachable READABLE_STRING_8
internal_data: detachable STRING_8
tmp_hex_chunk_size: STRING_8
last_chunk_size: INTEGER
last_chunk: detachable STRING_8
fetched_data: READABLE_STRING_8
fetched_data: STRING_8
-- Read all the data in a chunked stream.
-- Make the result available in `last_chunked'.
-- Chunked-Body = *chunk
@@ -57,7 +57,7 @@ feature {NONE} -- Parser
-- chunk-data = chunk-size(OCTET)
-- trailer = *(entity-header CRLF)
local
eoc : BOOLEAN
eoc: BOOLEAN
s: STRING_8
do
from
@@ -69,7 +69,7 @@ feature {NONE} -- Parser
if attached last_chunk as l_last_chunk then
s.append (l_last_chunk)
else
eoc := true
eoc := True
end
if last_chunk_size = 0 then
eoc := True

View File

@@ -31,6 +31,11 @@ feature -- Access
directory_index: detachable ARRAY [READABLE_STRING_8]
-- File serve if a directory index is requested
not_found_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
access_denied_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
feature -- Element change
set_directory_index (idx: like directory_index)
@@ -43,6 +48,18 @@ feature -- Element change
end
end
set_not_found_handler (h: like not_found_handler)
-- Set `not_found_handler' to `h'
do
not_found_handler := h
end
set_access_denied_handler (h: like access_denied_handler)
-- Set `access_denied_handler' to `h'
do
access_denied_handler := h
end
feature -- Execution
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
@@ -168,15 +185,19 @@ feature -- Execution
h: HTTP_HEADER
s: STRING_8
do
create h.make
h.put_content_type_text_plain
create s.make_empty
s.append ("Resource %"" + uri + "%" not found%N")
res.set_status_code ({HTTP_STATUS_CODE}.not_found)
h.put_content_length (s.count)
res.put_header_text (h.string)
res.put_string (s)
res.flush
if attached not_found_handler as hdl then
hdl.call ([uri, ctx, req, res])
else
create h.make
h.put_content_type_text_plain
create s.make_empty
s.append ("Resource %"" + uri + "%" not found%N")
res.set_status_code ({HTTP_STATUS_CODE}.not_found)
h.put_content_length (s.count)
res.put_header_text (h.string)
res.put_string (s)
res.flush
end
end
respond_access_denied (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
@@ -184,15 +205,19 @@ feature -- Execution
h: HTTP_HEADER
s: STRING_8
do
create h.make
h.put_content_type_text_plain
create s.make_empty
s.append ("Resource %"" + uri + "%": Access denied%N")
res.set_status_code ({HTTP_STATUS_CODE}.forbidden)
h.put_content_length (s.count)
res.put_header_text (h.string)
res.put_string (s)
res.flush
if attached access_denied_handler as hdl then
hdl.call ([uri, ctx, req, res])
else
create h.make
h.put_content_type_text_plain
create s.make_empty
s.append ("Resource %"" + uri + "%": Access denied%N")
res.set_status_code ({HTTP_STATUS_CODE}.forbidden)
h.put_content_length (s.count)
res.put_header_text (h.string)
res.put_string (s)
res.flush
end
end
feature {NONE} -- Implementation

View File

@@ -127,21 +127,50 @@ feature -- Query
end
end
feature -- String query
feature -- Convertion
string_from (a_value: detachable WSF_VALUE): detachable READABLE_STRING_32
-- String value from `a_value' if relevant.
do
if attached {WSF_STRING} a_value as val then
Result := val.string
end
end
integer_from (a_value: detachable WSF_VALUE): INTEGER
-- String value from `a_value' if relevant.
do
if attached string_from (a_value) as val then
if val.is_integer then
Result := val.to_integer
end
end
end
feature -- Path parameter
is_integer_path_parameter (a_name: READABLE_STRING_8): BOOLEAN
-- Is path parameter related to `a_name' an integer value?
do
Result := attached string_path_parameter (a_name) as s and then s.is_integer
end
integer_path_parameter (a_name: READABLE_STRING_8): INTEGER
-- Integer value for path parameter `a_name' if relevant.
require
is_integer_path_parameter: is_integer_path_parameter (a_name)
do
Result := integer_from (path_parameter (a_name))
end
string_path_parameter (a_name: READABLE_STRING_8): detachable READABLE_STRING_32
-- String value for path parameter `a_name' if relevant.
do
Result := string_from (path_parameter (a_name))
end
string_array_path_parameter (a_name: READABLE_STRING_8): detachable ARRAY [READABLE_STRING_32]
-- Array of string values for path parameter `a_name' if relevant.
local
i: INTEGER
n: INTEGER
@@ -164,12 +193,56 @@ feature -- String query
Result.keep_head (n - 1)
end
feature -- String parameter
is_integer_query_parameter (a_name: READABLE_STRING_8): BOOLEAN
-- Is query parameter related to `a_name' an integer value?
do
Result := attached string_query_parameter (a_name) as s and then s.is_integer
end
integer_query_parameter (a_name: READABLE_STRING_8): INTEGER
-- Integer value for query parameter `a_name' if relevant.
require
is_integer_query_parameter: is_integer_query_parameter (a_name)
do
Result := integer_from (query_parameter (a_name))
end
string_query_parameter (a_name: READABLE_STRING_8): detachable READABLE_STRING_32
-- String value for query parameter `a_name' if relevant.
do
Result := string_from (query_parameter (a_name))
end
string_array_query_parameter (a_name: READABLE_STRING_8): detachable ARRAY [READABLE_STRING_32]
-- Array of string values for query parameter `a_name' if relevant.
local
i: INTEGER
n: INTEGER
do
from
i := 1
n := 1
create Result.make_filled ("", 1, 5)
until
i = 0
loop
if attached string_query_parameter (a_name + "[" + i.out + "]") as v then
Result.force (v, n)
n := n + 1
i := i + 1
else
i := 0 -- Exit
end
end
Result.keep_head (n - 1)
end
feature -- Parameter
string_parameter (a_name: READABLE_STRING_8): detachable READABLE_STRING_32
-- String value for path or query parameter `a_name' if relevant.
do
Result := string_from (parameter (a_name))
end

View File

@@ -42,6 +42,9 @@ feature -- Visitor
do
end
process_uploaded_file (v: WSF_UPLOADED_FILE)
do
end
;note
copyright: "2011-2011, Eiffel Software and others"

View File

@@ -29,6 +29,10 @@ feature -- Visitor
do
end
process_uploaded_file (v: WSF_UPLOADED_FILE)
do
end
;note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -41,6 +41,12 @@ feature -- Visitor
deferred
end
process_uploaded_file (v: WSF_UPLOADED_FILE)
require
v_attached: v /= Void
deferred
end
;note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -18,6 +18,7 @@ feature {NONE} -- Initialization
make (a_name: READABLE_STRING_8; a_value: like item)
do
name := url_decoded_string (a_name)
url_encoded_name := a_name
item := a_value
end
@@ -25,8 +26,19 @@ feature -- Access
name: READABLE_STRING_32
url_encoded_name: READABLE_STRING_8
item: detachable ANY
feature -- Element change
change_name (a_name: like name)
do
name := url_decoded_string (a_name)
ensure then
a_name.same_string (url_encoded_name)
end
feature -- Status report
is_string: BOOLEAN = False
@@ -43,7 +55,7 @@ feature -- Query
else
Result := "Void"
end
end
end
feature -- Visitor

View File

@@ -65,6 +65,15 @@ feature -- Access
Result := string_values.first
end
feature -- Element change
change_name (a_name: like name)
do
name := a_name
ensure then
a_name.same_string (name)
end
feature -- Status report
is_string: BOOLEAN

View File

@@ -37,9 +37,19 @@ feature -- Access
string: READABLE_STRING_32
url_encoded_name: READABLE_STRING_32
url_encoded_name: READABLE_STRING_8
url_encoded_string: READABLE_STRING_32
url_encoded_string: READABLE_STRING_8
feature -- Element change
change_name (a_name: like name)
do
name := url_decoded_string (a_name)
url_encoded_name := a_name
ensure then
a_name.same_string (url_encoded_name)
end
feature -- Status report

View File

@@ -24,13 +24,16 @@ feature {NONE} -- Initialization
make (a_name: READABLE_STRING_8)
do
name := url_decoded_string (a_name)
url_encoded_name := a_name
create values.make (5)
end
feature -- Access
name: READABLE_STRING_32
-- Parameter name
-- Parameter name
url_encoded_name: READABLE_STRING_8
first_value: detachable WSF_VALUE
-- First value if any.
@@ -67,6 +70,16 @@ feature -- Access
Result := values.count
end
feature -- Element change
change_name (a_name: like name)
do
name := url_decoded_string (a_name)
url_encoded_name := a_name
ensure then
a_name.same_string (url_encoded_name)
end
feature -- Status report
is_string: BOOLEAN

View File

@@ -0,0 +1,217 @@
note
description: "Summary description for {WSF_UPLOADED_FILE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
WSF_UPLOADED_FILE
inherit
WSF_VALUE
create
make
feature {NONE} -- Initialization
make (a_name: READABLE_STRING_8; n: like filename; t: like content_type; s: like size)
do
name := url_decoded_string (a_name)
url_encoded_name := a_name
filename := n
content_type := t
size := s
end
feature -- Access
name: READABLE_STRING_32
url_encoded_name: READABLE_STRING_8
feature -- Element change
change_name (a_name: like name)
do
name := url_decoded_string (a_name)
url_encoded_name := a_name
ensure then
a_name.same_string (url_encoded_name)
end
feature -- Status report
is_string: BOOLEAN = False
-- Is Current as a WSF_STRING representation?
feature -- Conversion
string_representation: STRING_32
do
Result := filename
end
feature -- Visitor
process (vis: WSF_VALUE_VISITOR)
do
vis.process_uploaded_file (Current)
end
feature -- Access: Uploaded File
filename: STRING
-- original filename
content_type: STRING
-- Content type
size: INTEGER
-- Size of uploaded file
tmp_name: detachable STRING
-- Filename of tmp file
tmp_basename: detachable STRING
-- Basename of tmp file
feature -- Conversion
safe_filename: STRING
local
fn: like filename
c: CHARACTER
i, n: INTEGER
do
fn := filename
--| Compute safe filename, to avoid creating impossible filename, or dangerous one
from
i := 1
n := fn.count
create Result.make (n)
until
i > n
loop
c := fn[i]
inspect c
when '.', '-', '_' then
Result.extend (c)
when 'A' .. 'Z', 'a' .. 'z', '0' .. '9' then
Result.extend (c)
else
inspect c
when '%/192/' then Result.extend ('A') -- À
when '%/193/' then Result.extend ('A') -- Á
when '%/194/' then Result.extend ('A') -- Â
when '%/195/' then Result.extend ('A') -- Ã
when '%/196/' then Result.extend ('A') -- Ä
when '%/197/' then Result.extend ('A') -- Å
when '%/199/' then Result.extend ('C') -- Ç
when '%/200/' then Result.extend ('E') -- È
when '%/201/' then Result.extend ('E') -- É
when '%/202/' then Result.extend ('E') -- Ê
when '%/203/' then Result.extend ('E') -- Ë
when '%/204/' then Result.extend ('I') -- Ì
when '%/205/' then Result.extend ('I') -- Í
when '%/206/' then Result.extend ('I') -- Î
when '%/207/' then Result.extend ('I') -- Ï
when '%/210/' then Result.extend ('O') -- Ò
when '%/211/' then Result.extend ('O') -- Ó
when '%/212/' then Result.extend ('O') -- Ô
when '%/213/' then Result.extend ('O') -- Õ
when '%/214/' then Result.extend ('O') -- Ö
when '%/217/' then Result.extend ('U') -- Ù
when '%/218/' then Result.extend ('U') -- Ú
when '%/219/' then Result.extend ('U') -- Û
when '%/220/' then Result.extend ('U') -- Ü
when '%/221/' then Result.extend ('Y') -- Ý
when '%/224/' then Result.extend ('a') -- à
when '%/225/' then Result.extend ('a') -- á
when '%/226/' then Result.extend ('a') -- â
when '%/227/' then Result.extend ('a') -- ã
when '%/228/' then Result.extend ('a') -- ä
when '%/229/' then Result.extend ('a') -- å
when '%/231/' then Result.extend ('c') -- ç
when '%/232/' then Result.extend ('e') -- è
when '%/233/' then Result.extend ('e') -- é
when '%/234/' then Result.extend ('e') -- ê
when '%/235/' then Result.extend ('e') -- ë
when '%/236/' then Result.extend ('i') -- ì
when '%/237/' then Result.extend ('i') -- í
when '%/238/' then Result.extend ('i') -- î
when '%/239/' then Result.extend ('i') -- ï
when '%/240/' then Result.extend ('o') -- ð
when '%/242/' then Result.extend ('o') -- ò
when '%/243/' then Result.extend ('o') -- ó
when '%/244/' then Result.extend ('o') -- ô
when '%/245/' then Result.extend ('o') -- õ
when '%/246/' then Result.extend ('o') -- ö
when '%/249/' then Result.extend ('u') -- ù
when '%/250/' then Result.extend ('u') -- ú
when '%/251/' then Result.extend ('u') -- û
when '%/252/' then Result.extend ('u') -- ü
when '%/253/' then Result.extend ('y') -- ý
when '%/255/' then Result.extend ('y') -- ÿ
else
Result.extend ('-')
end
end
i := i + 1
end
end
feature -- Basic operation
move_to (a_destination: STRING): BOOLEAN
-- Move current uploaded file to `a_destination'
require
has_no_error: not has_error
local
f: RAW_FILE
do
if attached tmp_name as n then
create f.make (n)
if f.exists then
f.change_name (a_destination)
Result := True
end
end
end
feature -- Status
has_error: BOOLEAN
-- Has error during uploading
do
Result := error /= 0
end
error: INTEGER
-- Eventual error code
--| no error => 0
feature -- Element change
set_error (e: like error)
-- Set `error' to `e'
do
error := e
end
set_tmp_name (n: like tmp_name)
-- Set `tmp_name' to `n'
do
tmp_name := n
end
set_tmp_basename (n: like tmp_basename)
-- Set `tmp_basename' to `n'
do
tmp_basename := n
end
end

View File

@@ -16,6 +16,13 @@ feature -- Access
deferred
end
feature -- Element change
change_name (a_name: like name)
-- Change parameter name
deferred
end
feature -- Status report
is_string: BOOLEAN

View File

@@ -0,0 +1,171 @@
note
description: "Summary description for {WSF_PAGE_RESPONSE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
WSF_HTML_PAGE_RESPONSE
inherit
WSF_RESPONSE_MESSAGE
create
make
feature {NONE} -- Initialization
make
do
status_code := {HTTP_STATUS_CODE}.ok
create header.make
create {ARRAYED_LIST [STRING]} head_lines.make (5)
doctype := "<!DOCTYPE html PUBLIC %"-//W3C//DTD XHTML 1.0 Strict//EN%" %"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd%">"
header.put_content_type_text_html
end
feature -- Status
status_code: INTEGER
feature -- Header
header: HTTP_HEADER
feature -- Html access
doctype: STRING
language: detachable STRING
title: detachable STRING
head_lines: LIST [STRING]
body: detachable STRING
feature -- Element change
set_status_code (c: like status_code)
do
status_code := c
end
set_language (s: like language)
do
language := s
end
set_title (s: like title)
do
title := s
end
add_meta_name_content (a_name: STRING; a_content: STRING)
local
s: STRING_8
do
s := "<meta name=%"" + a_name + "%" content=%"" + a_content + "%" />"
head_lines.extend (s)
end
add_meta_http_equiv (a_http_equiv: STRING; a_content: STRING)
local
s: STRING_8
do
s := "<meta http-equiv=%"" + a_http_equiv + "%" content=%"" + a_content + "%" />"
head_lines.extend (s)
end
add_style (a_href: STRING; a_media: detachable STRING)
local
s: STRING_8
do
s := "<link rel=%"stylesheet%" href=%""+ a_href + "%" type=%"text/css%""
if a_media /= Void then
s.append (" media=%""+ a_media + "%"")
end
s.append ("/>")
head_lines.extend (s)
end
add_javascript_url (a_src: STRING)
local
s: STRING_8
do
s := "<script type=%"text/javascript%" src=%"" + a_src + "%"></script>"
head_lines.extend (s)
end
add_javascript_content (a_script: STRING)
local
s: STRING_8
do
s := "<script type=%"text/javascript%">%N" + a_script + "%N</script>"
head_lines.extend (s)
end
set_body (b: like body)
do
body := b
end
feature -- Output
send_to (res: WSF_RESPONSE)
local
t: like title
lines: like head_lines
b: like body
h: like header
s: STRING_8
do
create s.make (64)
if attached doctype as l_doctype then
s.append (l_doctype)
s.append_character ('%N')
end
s.append ("<html xmlns=%"http://www.w3.org/1999/xhtml%"")
if attached language as lang then
s.append (" xml:lang=%""+ lang +"%" lang=%""+ lang +"%"")
end
s.append (">%N")
t := title
lines := head_lines
if t /= Void or else lines.count > 0 then
s.append ("<head>")
if t /= Void then
s.append ("<title>" + t + "</title>%N")
end
s.append_character ('%N')
across
lines as l
loop
s.append (l.item)
s.append_character ('%N')
end
s.append ("</head>%N")
end
b := body
s.append ("<body>%N")
if b /= Void then
s.append (b)
end
s.append ("%N</body></html>%N")
h := header
res.set_status_code (status_code)
if not h.has_content_length then
h.put_content_length (s.count)
end
if not h.has_content_type then
h.put_content_type_text_html
end
res.put_header_text (h.string)
res.put_string (s)
end
end

View File

@@ -23,20 +23,18 @@ feature {NONE} -- Implementation
end
end
read_input_data (a_input: WGI_INPUT_STREAM; nb: NATURAL_64): READABLE_STRING_8
read_input_data (a_input: WGI_INPUT_STREAM; nb: NATURAL_64): 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
create Result.make (nb32)
n := nb32
if n > 1_024 then
n := 1_024
@@ -46,7 +44,7 @@ feature {NONE} -- Implementation
loop
a_input.read_string (n)
t := a_input.last_string
s.append_string (t)
Result.append_string (t)
if t.count < n then
n64 := 0
else
@@ -55,7 +53,12 @@ feature {NONE} -- Implementation
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])
add_string_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32])
do
add_value_to_table (a_name, new_string_value (a_name, a_value), a_table)
end
add_value_to_table (a_name: READABLE_STRING_8; a_value: WSF_VALUE; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32])
local
l_decoded_name: STRING_32
v: detachable WSF_VALUE
@@ -121,13 +124,15 @@ feature {NONE} -- Implementation
--| Ignore bad value
end
end
tb.add_value (new_string_value (n, a_value), k)
a_value.change_name (n)
tb.add_value (a_value, k)
else
--| Missing end bracket
end
end
if v = Void then
v := new_string_value (a_name, a_value)
a_value.change_name (a_name)
v := 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

View File

@@ -54,7 +54,7 @@ feature -- Execution
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)
add_string_value_to_table (l_name, l_value, a_vars)
end
end
end

View File

@@ -46,7 +46,7 @@ feature -- Execution
handle (a_content_type: READABLE_STRING_8; 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
s: like full_input_data
do
s := full_input_data (req)
if a_raw_data /= Void then
@@ -134,7 +134,7 @@ feature {NONE} -- Implementation: Form analyzer
l_header: detachable STRING_8
l_content: detachable STRING_8
l_line: detachable STRING_8
l_up_file_info: WGI_UPLOADED_FILE_DATA
l_up_file: WSF_UPLOADED_FILE
do
from
p := 1
@@ -223,15 +223,16 @@ feature {NONE} -- Implementation: Form analyzer
end
end
if l_name /= Void then
if l_filename /= Void then
if l_filename /= Void and then not l_filename.is_empty 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)
create l_up_file.make (l_name, l_filename, l_content_type, l_content.count)
add_value_to_table (l_name, l_up_file, vars)
--| `l_up_file' might have a new name
req.save_uploaded_file (l_up_file, l_content)
else
add_value_to_table (l_name, l_content, vars)
add_string_value_to_table (l_name, l_content, vars)
end
else
error_handler.add_custom_error (0, "unamed multipart entry", Void)

View File

@@ -52,8 +52,8 @@ feature {NONE} -- Initialization
meta_variables_table := tb
meta_variables := tb
create error_handler.make
create uploaded_files.make (0)
raw_post_data_recorded := True
create uploaded_files_table.make (0)
set_raw_input_data_recorded (False)
create {STRING_32} empty_string.make_empty
create execution_variables_table.make (0)
@@ -94,6 +94,21 @@ feature {NONE} -- Initialization
wgi_request: WGI_REQUEST
feature -- Destroy
destroy
-- Destroy the object when request is completed
do
-- Removed uploaded files
across
-- Do not use `uploaded_files' directly
-- just to avoid processing input data if not yet done
uploaded_files_table as c
loop
delete_uploaded_file (c.item)
end
end
feature -- Status report
debug_output: STRING_8
@@ -101,14 +116,24 @@ feature -- Status report
create Result.make_from_string (request_method + " " + request_uri)
end
feature -- Status
feature -- Setting
raw_post_data_recorded: BOOLEAN assign set_raw_post_data_recorded
-- Record RAW POST DATA in meta parameters
raw_input_data_recorded: BOOLEAN assign set_raw_input_data_recorded
-- Record RAW Input datas into `raw_input_data'
-- otherwise just forget about it
-- Default: true
-- Default: False
--| warning: you might keep in memory big amount of memory ...
feature -- Raw input data
raw_input_data: detachable READABLE_STRING_8
-- Raw input data is `raw_input_data_recorded' is True
set_raw_input_data (d: READABLE_STRING_8)
do
raw_input_data := d
end
feature -- Error handling
has_error: BOOLEAN
@@ -1055,18 +1080,6 @@ feature {NONE} -- Query parameters: implementation
feature -- Form fields and related
form_data_parameters: like form_parameters
obsolete "[2011-oct-24] Use form_parameters"
do
Result := form_parameters
end
form_data_parameter (a_name: READABLE_STRING_8): like form_parameter
obsolete "[2011-oct-24] Use form_parameter (a_name:...)"
do
Result := form_parameter (a_name)
end
form_parameters: ITERABLE [WSF_VALUE]
do
Result := form_parameters_table
@@ -1078,14 +1091,30 @@ feature -- Form fields and related
Result := form_parameters_table.item (a_name)
end
uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, STRING]
-- Table of uploaded files information
--| name: original path from the user
has_uploaded_file: BOOLEAN
-- Has any uploaded file?
do
-- Be sure, the `form_parameters' are already processed
get_form_parameters
Result := not uploaded_files_table.is_empty
end
uploaded_files: ITERABLE [WSF_UPLOADED_FILE]
-- uploaded files values
--| filename: original path from the user
--| type: content type
--| tmp_name: path to temp file that resides on server
--| tmp_base_name: basename of `tmp_name'
--| error: if /= 0 , there was an error : TODO ...
--| size: size of the file given by the http request
do
-- Be sure, the `form_parameters' are already processed
get_form_parameters
-- return uploaded files table
Result := uploaded_files_table
end
feature -- Access: MIME handler
@@ -1151,8 +1180,10 @@ feature {NONE} -- Implementation: MIME handler
feature {NONE} -- Form fields and related
form_parameters_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]
-- Variables sent by POST request
uploaded_files_table: HASH_TABLE [WSF_UPLOADED_FILE, READABLE_STRING_32]
get_form_parameters
-- Variables sent by POST, ... request
local
vars: like internal_form_data_parameters_table
l_raw_data_cell: detachable CELL [detachable STRING_8]
@@ -1164,7 +1195,7 @@ feature {NONE} -- Form fields and related
create vars.make (0)
vars.compare_objects
else
if raw_post_data_recorded then
if raw_input_data_recorded then
create l_raw_data_cell.put (Void)
end
create vars.make (5)
@@ -1176,11 +1207,26 @@ feature {NONE} -- Form fields and related
end
if l_raw_data_cell /= Void and then attached l_raw_data_cell.item as l_raw_data then
-- What if no mime handler is associated to `l_type' ?
set_meta_string_variable ("RAW_POST_DATA", l_raw_data)
set_raw_input_data (l_raw_data)
end
end
internal_form_data_parameters_table := vars
end
ensure
internal_form_data_parameters_table /= Void
end
form_parameters_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_32]
-- Variables sent by POST request
local
vars: like internal_form_data_parameters_table
do
get_form_parameters
vars := internal_form_data_parameters_table
if vars = Void then
check form_parameters_already_retrieved: False end
create vars.make (0)
end
Result := vars
end
@@ -1189,9 +1235,9 @@ feature -- Uploaded File Handling
is_uploaded_file (a_filename: STRING): BOOLEAN
-- Is `a_filename' a file uploaded via HTTP Form
local
l_files: like uploaded_files
l_files: like uploaded_files_table
do
l_files := uploaded_files
l_files := uploaded_files_table
if not l_files.is_empty then
from
l_files.start
@@ -1278,10 +1324,10 @@ feature {NONE} -- Implementation: URL Utility
feature -- Element change
set_raw_post_data_recorded (b: BOOLEAN)
-- Set `raw_post_data_recorded' to `b'
set_raw_input_data_recorded (b: BOOLEAN)
-- Set `raw_input_data_recorded' to `b'
do
raw_post_data_recorded := b
raw_input_data_recorded := b
end
set_error_handler (ehdl: like error_handler)
@@ -1292,14 +1338,14 @@ feature -- Element change
feature {WSF_MIME_HANDLER} -- Temporary File handling
delete_uploaded_file (uf: WGI_UPLOADED_FILE_DATA)
delete_uploaded_file (uf: WSF_UPLOADED_FILE)
-- Delete file `a_filename'
require
uf_valid: uf /= Void
local
f: RAW_FILE
do
if uploaded_files.has_item (uf) then
if uploaded_files_table.has_item (uf) then
if attached uf.tmp_name as fn then
create f.make (fn)
if f.exists and then f.is_writable then
@@ -1315,7 +1361,7 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
end
end
save_uploaded_file (a_content: STRING; a_up_fn_info: WGI_UPLOADED_FILE_DATA)
save_uploaded_file (a_up_file: WSF_UPLOADED_FILE; a_content: STRING)
-- Save uploaded file content to `a_filename'
local
bn: STRING
@@ -1328,10 +1374,11 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
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 d.exists and then d.is_writable then
l_safe_name := safe_filename (a_up_fn_info.name)
l_safe_name := a_up_file.safe_filename
from
create fn.make_from_string (dn)
bn := "tmp-" + l_safe_name
@@ -1350,106 +1397,26 @@ feature {WSF_MIME_HANDLER} -- Temporary File handling
end
if not f.exists or else f.is_writable then
a_up_fn_info.set_tmp_name (f.name)
a_up_fn_info.set_tmp_basename (bn)
a_up_file.set_tmp_name (f.name)
a_up_file.set_tmp_basename (bn)
f.open_write
f.put_string (a_content)
f.close
else
a_up_fn_info.set_error (-1)
a_up_file.set_error (-1)
end
else
error_handler.add_custom_error (0, "Directory not writable", "Can not create file in directory %""+ dn +"%"")
end
uploaded_files_table.force (a_up_file, a_up_file.name)
else
a_up_fn_info.set_error (-1)
a_up_file.set_error (-1)
end
rescue
rescued := True
retry
end
safe_filename (fn: STRING): STRING
local
c: CHARACTER
i, n: INTEGER
do
--| Compute safe filename, to avoid creating impossible filename, or dangerous one
from
i := 1
n := fn.count
create Result.make (n)
until
i > n
loop
c := fn[i]
inspect c
when '.', '-', '_' then
Result.extend (c)
when 'A' .. 'Z', 'a' .. 'z', '0' .. '9' then
Result.extend (c)
else
inspect c
when '%/192/' then Result.extend ('A') -- À
when '%/193/' then Result.extend ('A') -- Á
when '%/194/' then Result.extend ('A') -- Â
when '%/195/' then Result.extend ('A') -- Ã
when '%/196/' then Result.extend ('A') -- Ä
when '%/197/' then Result.extend ('A') -- Å
when '%/199/' then Result.extend ('C') -- Ç
when '%/200/' then Result.extend ('E') -- È
when '%/201/' then Result.extend ('E') -- É
when '%/202/' then Result.extend ('E') -- Ê
when '%/203/' then Result.extend ('E') -- Ë
when '%/204/' then Result.extend ('I') -- Ì
when '%/205/' then Result.extend ('I') -- Í
when '%/206/' then Result.extend ('I') -- Î
when '%/207/' then Result.extend ('I') -- Ï
when '%/210/' then Result.extend ('O') -- Ò
when '%/211/' then Result.extend ('O') -- Ó
when '%/212/' then Result.extend ('O') -- Ô
when '%/213/' then Result.extend ('O') -- Õ
when '%/214/' then Result.extend ('O') -- Ö
when '%/217/' then Result.extend ('U') -- Ù
when '%/218/' then Result.extend ('U') -- Ú
when '%/219/' then Result.extend ('U') -- Û
when '%/220/' then Result.extend ('U') -- Ü
when '%/221/' then Result.extend ('Y') -- Ý
when '%/224/' then Result.extend ('a') -- à
when '%/225/' then Result.extend ('a') -- á
when '%/226/' then Result.extend ('a') -- â
when '%/227/' then Result.extend ('a') -- ã
when '%/228/' then Result.extend ('a') -- ä
when '%/229/' then Result.extend ('a') -- å
when '%/231/' then Result.extend ('c') -- ç
when '%/232/' then Result.extend ('e') -- è
when '%/233/' then Result.extend ('e') -- é
when '%/234/' then Result.extend ('e') -- ê
when '%/235/' then Result.extend ('e') -- ë
when '%/236/' then Result.extend ('i') -- ì
when '%/237/' then Result.extend ('i') -- í
when '%/238/' then Result.extend ('i') -- î
when '%/239/' then Result.extend ('i') -- ï
when '%/240/' then Result.extend ('o') -- ð
when '%/242/' then Result.extend ('o') -- ò
when '%/243/' then Result.extend ('o') -- ó
when '%/244/' then Result.extend ('o') -- ô
when '%/245/' then Result.extend ('o') -- õ
when '%/246/' then Result.extend ('o') -- ö
when '%/249/' then Result.extend ('u') -- ù
when '%/250/' then Result.extend ('u') -- ú
when '%/251/' then Result.extend ('u') -- û
when '%/252/' then Result.extend ('u') -- ü
when '%/253/' then Result.extend ('y') -- ý
when '%/255/' then Result.extend ('y') -- ÿ
else
Result.extend ('-')
end
end
i := i + 1
end
end
feature {WSF_MIME_HANDLER} -- Input data access
form_input_data (nb: NATURAL_64): READABLE_STRING_8

View File

@@ -115,40 +115,8 @@ feature -- Header output operation
wgi_response.put_header_lines (a_lines)
end
feature -- Obsolete: Header output operation
write_header_text (a_headers: READABLE_STRING_8)
obsolete "[2011-dec-15] use put_header_text"
do
put_header_text (a_headers)
end
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
obsolete "[2011-dec-15] use put_header"
do
put_header (a_status_code, a_headers)
end
write_header_lines (a_lines: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
obsolete "[2011-dec-15] use put_header_lines"
do
put_header_lines (a_lines)
end
feature -- Output operation
write_string (s: READABLE_STRING_8)
obsolete "[2011-dec-15] use put_string"
do
put_string (s)
end
write_substring (s: READABLE_STRING_8; a_begin_index, a_end_index: INTEGER)
obsolete "[2011-dec-15] use put_substring"
do
put_substring (s, a_begin_index, a_end_index)
end
put_string (s: READABLE_STRING_8)
-- Send the string `s'
require
@@ -205,6 +173,12 @@ feature -- Output operation
flush
end
put_chunk_end
-- Put end of chunked content
do
put_chunk (Void, Void)
end
flush
-- Flush if it makes sense
do
@@ -244,7 +218,7 @@ feature -- Redirect
end
h.put_location (a_url)
if a_status_code = 0 then
set_status_code ({HTTP_STATUS_CODE}.moved_permanently)
set_status_code ({HTTP_STATUS_CODE}.temp_redirect)
else
set_status_code (a_status_code)
end
@@ -265,13 +239,13 @@ feature -- Redirect
require
header_not_committed: not header_committed
do
redirect_now_custom (a_url, {HTTP_STATUS_CODE}.moved_permanently, Void, Void)
redirect_now_custom (a_url, {HTTP_STATUS_CODE}.temp_redirect, Void, Void)
end
redirect_now_with_content (a_url: READABLE_STRING_8; a_content: READABLE_STRING_8; a_content_type: READABLE_STRING_8)
-- Redirect to the given url `a_url'
do
redirect_now_custom (a_url, {HTTP_STATUS_CODE}.moved_permanently, Void, [a_content, a_content_type])
redirect_now_custom (a_url, {HTTP_STATUS_CODE}.temp_redirect, Void, [a_content, a_content_type])
end
note

View File

@@ -31,13 +31,19 @@ feature {WGI_CONNECTOR} -- WGI Execution
wgi_execute (req: WGI_REQUEST; res: WGI_RESPONSE)
local
w_res: detachable WSF_RESPONSE
w_req: detachable WSF_REQUEST
do
create w_res.make_from_wgi (res)
execute (create {WSF_REQUEST}.make_from_wgi (req), w_res)
create w_req.make_from_wgi (req)
execute (w_req, w_res)
w_req.destroy
rescue
if w_res /= Void then
w_res.flush
end
if w_req /= Void then
w_req.destroy
end
end
end