Redesigned the RESPONSE to remove the output stream from the deferred interface

Redesigned the uploaded file part to be more object oriented
Move some implementation from REQUEST to REQUEST_IMP
This commit is contained in:
Jocelyn Fiat
2011-07-25 11:43:22 +02:00
parent 08bec49da4
commit 5a155e0cee
6 changed files with 228 additions and 114 deletions

View File

@@ -85,7 +85,7 @@ feature -- Form fields and related
deferred deferred
end end
uploaded_files: HASH_TABLE [TUPLE [name: STRING; type: STRING; tmp_name: STRING; tmp_basename: STRING; error: INTEGER; size: INTEGER], STRING] uploaded_files: HASH_TABLE [GW_UPLOADED_FILE_DATA, STRING]
-- Table of uploaded files information -- Table of uploaded files information
--| name: original path from the user --| name: original path from the user
--| type: content type --| type: content type
@@ -203,15 +203,6 @@ feature -- Access: global variable
feature -- Uploaded File Handling feature -- Uploaded File Handling
move_uploaded_file (a_filename: STRING; a_destination: STRING): BOOLEAN
-- Move uploaded file `a_filename' to `a_destination'
--| if this is not an uploaded file, do not move it.
require
a_filename_valid: a_filename /= Void and then not a_filename.is_empty
a_destination_valid: a_destination /= Void and then not a_destination.is_empty
deferred
end
is_uploaded_file (a_filename: STRING): BOOLEAN is_uploaded_file (a_filename: STRING): BOOLEAN
-- Is `a_filename' a file uploaded via HTTP POST -- Is `a_filename' a file uploaded via HTTP POST
deferred deferred
@@ -219,10 +210,10 @@ feature -- Uploaded File Handling
feature {NONE} -- Temporary File handling feature {NONE} -- Temporary File handling
delete_uploaded_file (a_filename: STRING) delete_uploaded_file (f: GW_UPLOADED_FILE_DATA)
-- Delete file `a_filename' -- Delete file `f'
require require
a_filename_valid: a_filename /= Void and then not a_filename.is_empty f_valid: f /= Void
deferred deferred
end end
@@ -230,66 +221,16 @@ feature -- URL Utility
absolute_script_url (a_path: STRING): STRING absolute_script_url (a_path: STRING): STRING
-- Absolute Url for the script if any, extended by `a_path' -- Absolute Url for the script if any, extended by `a_path'
do deferred
Result := script_url (a_path)
if attached environment.http_host as h then
Result.prepend (h)
else
--| Issue ??
end
end end
script_url (a_path: STRING): STRING script_url (a_path: STRING): STRING
-- Url relative to script name if any, extended by `a_path' -- Url relative to script name if any, extended by `a_path'
require require
a_path_attached: a_path /= Void a_path_attached: a_path /= Void
local deferred
l_base_url: like internal_url_base
i,m,n: INTEGER
l_rq_uri: like environment.request_uri
env: like environment
do
l_base_url := internal_url_base
if l_base_url = Void then
env := environment
if attached env.script_name as l_script_name then
l_rq_uri := env.request_uri
if l_rq_uri.starts_with (l_script_name) then
l_base_url := l_script_name
else
--| Handle Rewrite url engine, to have clean path
from
i := 1
m := l_rq_uri.count
n := l_script_name.count
until
i > m or i > n or l_rq_uri[i] /= l_script_name[i]
loop
i := i + 1
end
if i > 1 then
if l_rq_uri[i-1] = '/' then
i := i -1
end
l_base_url := l_rq_uri.substring (1, i - 1)
end
end
end
if l_base_url = Void then
create l_base_url.make_empty
end
internal_url_base := l_base_url
end
Result := l_base_url + a_path
end end
feature {NONE} -- Implementation: URL Utility
internal_url_base: detachable STRING
-- URL base of potential script
invariant
note note
copyright: "2011-2011, Eiffel Software and others" copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -0,0 +1,103 @@
note
description: "Summary description for {GW_UPLOADED_FILE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
GW_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

@@ -26,6 +26,9 @@ feature -- Process request
else else
rescue_execute (req, res, (create {EXCEPTION_MANAGER}).last_exception) rescue_execute (req, res, (create {EXCEPTION_MANAGER}).last_exception)
end end
if res /= Void then
res.commit (a_output)
end
end end
feature {NONE} -- Execution feature {NONE} -- Execution

View File

@@ -178,7 +178,7 @@ feature -- Form fields and related
Result := vars Result := vars
end end
uploaded_files: HASH_TABLE [TUPLE [name: STRING; type: STRING; tmp_name: STRING; tmp_basename: STRING; error: INTEGER; size: INTEGER], STRING] uploaded_files: HASH_TABLE [GW_UPLOADED_FILE_DATA, STRING]
-- Table of uploaded files information -- Table of uploaded files information
--| name: original path from the user --| name: original path from the user
--| type: content type --| type: content type
@@ -274,6 +274,66 @@ feature -- Access extra information
end end
end end
feature -- URL Utility
absolute_script_url (a_path: STRING): STRING
-- Absolute Url for the script if any, extended by `a_path'
do
Result := script_url (a_path)
if attached environment.http_host as h then
Result.prepend (h)
else
--| Issue ??
end
end
script_url (a_path: STRING): STRING
-- Url relative to script name if any, extended by `a_path'
local
l_base_url: like internal_url_base
i,m,n: INTEGER
l_rq_uri: like environment.request_uri
env: like environment
do
l_base_url := internal_url_base
if l_base_url = Void then
env := environment
if attached env.script_name as l_script_name then
l_rq_uri := env.request_uri
if l_rq_uri.starts_with (l_script_name) then
l_base_url := l_script_name
else
--| Handle Rewrite url engine, to have clean path
from
i := 1
m := l_rq_uri.count
n := l_script_name.count
until
i > m or i > n or l_rq_uri[i] /= l_script_name[i]
loop
i := i + 1
end
if i > 1 then
if l_rq_uri[i-1] = '/' then
i := i -1
end
l_base_url := l_rq_uri.substring (1, i - 1)
end
end
end
if l_base_url = Void then
create l_base_url.make_empty
end
internal_url_base := l_base_url
end
Result := l_base_url + a_path
end
feature {NONE} -- Implementation: URL Utility
internal_url_base: detachable STRING
-- URL base of potential script
feature -- Element change feature -- Element change
set_raw_post_data_recorded (b: BOOLEAN) set_raw_post_data_recorded (b: BOOLEAN)
@@ -313,21 +373,6 @@ feature -- Element change
feature -- Uploaded File Handling feature -- Uploaded File Handling
move_uploaded_file (a_filename: STRING; a_destination: STRING): BOOLEAN
-- Move uploaded file `a_filename' to `a_destination'
--| if this is not an uploaded file, do not move it.
local
f: RAW_FILE
do
if is_uploaded_file (a_filename) then
create f.make (a_filename)
if f.exists then
f.change_name (a_destination)
Result := True
end
end
end
is_uploaded_file (a_filename: STRING): BOOLEAN is_uploaded_file (a_filename: STRING): BOOLEAN
-- Is `a_filename' a file uploaded via HTTP Form -- Is `a_filename' a file uploaded via HTTP Form
local local
@@ -340,7 +385,7 @@ feature -- Uploaded File Handling
until until
l_files.after or Result l_files.after or Result
loop loop
if l_files.item_for_iteration.tmp_name.same_string (a_filename) then if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string (a_filename) then
Result := True Result := True
end end
l_files.forth l_files.forth
@@ -350,24 +395,28 @@ feature -- Uploaded File Handling
feature {NONE} -- Temporary File handling feature {NONE} -- Temporary File handling
delete_uploaded_file (a_filename: STRING) delete_uploaded_file (uf: GW_UPLOADED_FILE_DATA)
-- Delete file `a_filename' -- Delete file `a_filename'
local local
f: RAW_FILE f: RAW_FILE
do do
if is_uploaded_file (a_filename) then if uploaded_files.has_item (uf) then
create f.make (a_filename) if attached uf.tmp_name as fn then
if f.exists and then f.is_writable then create f.make (fn)
f.delete 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 +"%"")
end
else else
error_handler.add_custom_error (0, "Can not delete file", "Can not delete file %""+ a_filename +"%"") error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete uploaded file %""+ uf.name +"%" Tmp File not found")
end end
else else
error_handler.add_custom_error (0, "Not uploaded file", "This file %""+ a_filename +"%" is not an uploaded file.") error_handler.add_custom_error (0, "Not an uploaded file", "This file %""+ uf.name +"%" is not an uploaded file.")
end end
end end
save_uploaded_file (a_content: STRING; a_filename: STRING): detachable TUPLE [name: STRING; basename: STRING] save_uploaded_file (a_content: STRING; a_up_fn_info: GW_UPLOADED_FILE_DATA)
-- Save uploaded file content to `a_filename' -- Save uploaded file content to `a_filename'
local local
bn: STRING bn: STRING
@@ -383,7 +432,7 @@ feature {NONE} -- Temporary File handling
dn := (create {EXECUTION_ENVIRONMENT}).current_working_directory dn := (create {EXECUTION_ENVIRONMENT}).current_working_directory
create d.make (dn) create d.make (dn)
if d.exists and then d.is_writable then if d.exists and then d.is_writable then
l_safe_name := safe_filename (a_filename) l_safe_name := safe_filename (a_up_fn_info.name)
from from
create fn.make_from_string (dn) create fn.make_from_string (dn)
bn := "tmp-" + l_safe_name bn := "tmp-" + l_safe_name
@@ -402,18 +451,19 @@ feature {NONE} -- Temporary File handling
end end
if not f.exists or else f.is_writable then 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)
f.open_write f.open_write
f.put_string (a_content) f.put_string (a_content)
f.close f.close
Result := [f.name, bn]
else else
Result := Void a_up_fn_info.set_error (-1)
end end
else 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", "Can not create file in directory %""+ dn +"%"")
end end
else else
Result := Void a_up_fn_info.set_error (-1)
end end
rescue rescue
rescued := True rescued := True
@@ -533,6 +583,7 @@ feature {NONE} -- Implementation: Form analyzer
l_header: detachable STRING l_header: detachable STRING
l_content: detachable STRING l_content: detachable STRING
l_line: detachable STRING l_line: detachable STRING
l_up_file_info: GW_UPLOADED_FILE_DATA
do do
from from
p := 1 p := 1
@@ -625,11 +676,9 @@ feature {NONE} -- Implementation: Form analyzer
if l_content_type = Void then if l_content_type = Void then
l_content_type := default_content_type l_content_type := default_content_type
end end
if attached save_uploaded_file (l_content, l_filename) as l_saved_fn_info then create l_up_file_info.make (l_filename, l_content_type, l_content.count)
uploaded_files.force ([l_filename, l_content_type, l_saved_fn_info.name, l_saved_fn_info.basename, 0, l_content.count], l_name) save_uploaded_file (l_content, l_up_file_info)
else uploaded_files.force (l_up_file_info, l_name)
uploaded_files.force ([l_filename, l_content_type, "", "", -1, l_content.count], l_name)
end
else else
vars_post.add_variable (l_content, l_name) vars_post.add_variable (l_content, l_name)
end end

View File

@@ -7,32 +7,30 @@ note
deferred class deferred class
GW_RESPONSE GW_RESPONSE
feature {NONE} -- Implementation: Output feature {GW_APPLICATION} -- Commit
output: GW_OUTPUT_STREAM commit (a_output_stream: GW_OUTPUT_STREAM)
-- Server output channel -- Commit the current response
deferred
end
feature -- Output header
write_header_object (h: GW_HEADER)
-- Send `header' to `output'.
do do
h.send_to (output) --| To be redefined as needed, to flush, or what you need...
a_output_stream.flush
end end
feature -- Output operation feature -- Output operation
write_string (s: STRING) write_string (s: STRING)
do -- Send the content of `s'
output.put_string (s) deferred
end end
write_file_content (fn: STRING) write_file_content (fn: STRING)
-- Send the content of file `fn' -- Send the content of file `fn'
do deferred
output.put_file_content (fn) end
write_header_object (h: GW_HEADER)
-- Send `header' to `output'.
deferred
end end
write_header (a_status: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]]) write_header (a_status: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])

View File

@@ -20,6 +20,26 @@ feature {NONE} -- Initialization
output := a_output output := a_output
end end
feature -- Output operation
write_string (s: STRING)
-- Send the content of `s'
do
output.put_string (s)
end
write_file_content (fn: STRING)
-- Send the content of file `fn'
do
output.put_file_content (fn)
end
write_header_object (h: GW_HEADER)
-- Send `header' to `output'.
do
h.send_to (output)
end
feature {NONE} -- Implementation: Access feature {NONE} -- Implementation: Access
output: GW_OUTPUT_STREAM output: GW_OUTPUT_STREAM