From 5abc79b7c3efbfece7986058f9a6dd18f06e47c8 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 13 Mar 2012 18:07:28 +0100 Subject: [PATCH] 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. --- contrib/library/server/nino | 2 +- examples/upload_image/htdocs/ewf.jpg | Bin 0 -> 15338 bytes examples/upload_image/htdocs/favicon.ico | Bin 0 -> 10134 bytes .../upload_image/htdocs/files/do_not_remove | 0 examples/upload_image/htdocs/index.html | 10 + examples/upload_image/htdocs/style.css | 4 + examples/upload_image/src/image_uploader.e | 197 ++++++++++++++++ examples/upload_image/upload_image-safe.ecf | 31 +++ .../connectors/nino/src/wgi_nino_connector.e | 2 +- .../nino/src/wgi_nino_input_stream.e | 4 +- .../nino/src/wgi_nino_response_stream.e | 45 ++++ .../request/wgi_uploaded_file_data.e | 103 --------- .../wgi_request_from_table.e | 0 .../wgi_response_stream.e | 0 .../ewsgi/src/wgi_chunked_input_stream.e | 10 +- .../wsf/router/request_file_system_handler.e | 61 +++-- .../wsf/router/request_handler_context.e | 75 +++++- .../value/visitor/wsf_value_iterator.e | 3 + .../value/visitor/wsf_value_null_visitor.e | 4 + .../request/value/visitor/wsf_value_visitor.e | 6 + .../server/wsf/src/request/value/wsf_any.e | 14 +- .../src/request/value/wsf_multiple_string.e | 9 + .../server/wsf/src/request/value/wsf_string.e | 14 +- .../server/wsf/src/request/value/wsf_table.e | 15 +- .../wsf/src/request/value/wsf_uploaded_file.e | 217 ++++++++++++++++++ library/server/wsf/src/request/wsf_value.e | 7 + .../wsf/src/response/wsf_html_page_response.e | 171 ++++++++++++++ .../wsf/src/support/wsf_mime_handler_helper.e | 21 +- ...pplication_x_www_form_urlencoded_handler.e | 2 +- .../wsf/src/wsf_multipart_form_data_handler.e | 15 +- library/server/wsf/src/wsf_request.e | 205 +++++++---------- library/server/wsf/src/wsf_response.e | 44 +--- library/server/wsf/src/wsf_service.e | 8 +- 33 files changed, 993 insertions(+), 306 deletions(-) create mode 100644 examples/upload_image/htdocs/ewf.jpg create mode 100644 examples/upload_image/htdocs/favicon.ico create mode 100644 examples/upload_image/htdocs/files/do_not_remove create mode 100644 examples/upload_image/htdocs/index.html create mode 100644 examples/upload_image/htdocs/style.css create mode 100644 examples/upload_image/src/image_uploader.e create mode 100644 examples/upload_image/upload_image-safe.ecf create mode 100644 library/server/ewsgi/connectors/nino/src/wgi_nino_response_stream.e delete mode 100644 library/server/ewsgi/specification/request/wgi_uploaded_file_data.e rename library/server/ewsgi/src/{helper => implementation}/wgi_request_from_table.e (100%) rename library/server/ewsgi/src/{helper => implementation}/wgi_response_stream.e (100%) create mode 100644 library/server/wsf/src/request/value/wsf_uploaded_file.e create mode 100644 library/server/wsf/src/response/wsf_html_page_response.e diff --git a/contrib/library/server/nino b/contrib/library/server/nino index ab38345c..e8521368 160000 --- a/contrib/library/server/nino +++ b/contrib/library/server/nino @@ -1 +1 @@ -Subproject commit ab38345c250308b937f75dbf1e626518f64e7eb5 +Subproject commit e85213689e33783eb6ad3233efa506318f0656ff diff --git a/examples/upload_image/htdocs/ewf.jpg b/examples/upload_image/htdocs/ewf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4147dd9df76a19e077318f9b1cba4a382597697f GIT binary patch literal 15338 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 literal 0 HcmV?d00001 diff --git a/examples/upload_image/htdocs/files/do_not_remove b/examples/upload_image/htdocs/files/do_not_remove new file mode 100644 index 00000000..e69de29b diff --git a/examples/upload_image/htdocs/index.html b/examples/upload_image/htdocs/index.html new file mode 100644 index 00000000..a58cc5b7 --- /dev/null +++ b/examples/upload_image/htdocs/index.html @@ -0,0 +1,10 @@ + + + EWF: demo upload image file + + + +

EWF: demo upload image file

+ Click for the demo + + diff --git a/examples/upload_image/htdocs/style.css b/examples/upload_image/htdocs/style.css new file mode 100644 index 00000000..2a2faf74 --- /dev/null +++ b/examples/upload_image/htdocs/style.css @@ -0,0 +1,4 @@ +h1 { border: solid 1px #00f; margin: 5px; padding: 5px; background-color: #009; color: #fff; margin: 10px;} +form { border: solid 1px #999; margin: 20px; padding: 10px;} +img { width: 60%; } +img.hover { width: 100%; } diff --git a/examples/upload_image/src/image_uploader.e b/examples/upload_image/src/image_uploader.e new file mode 100644 index 00000000..fcf3fce1 --- /dev/null +++ b/examples/upload_image/src/image_uploader.e @@ -0,0 +1,197 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + IMAGE_UPLOADER + +inherit + ANY + + URI_TEMPLATE_ROUTED_SERVICE + + ROUTED_SERVICE_HELPER + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize Current + local + s: DEFAULT_SERVICE_LAUNCHER + do + initialize_router + create s.make_and_launch (agent execute) + -- Use the following line to use particular port number (as 9090) with Nino connector + -- create s.make_and_launch_with_options (agent execute, <<["port", 9090]>>) + end + + create_router + -- Create router + do + create router.make (5) + end + + setup_router + -- Setup router + local + www: REQUEST_FILE_SYSTEM_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + do + router.map_agent ("/upload{?nb}", agent execute_upload) + + create www.make (document_root) + www.set_directory_index (<<"index.html">>) + www.set_not_found_handler (agent execute_not_found) + router.map_with_request_methods ("{/path}{?query}", www, <<"GET">>) + end + +feature -- Configuration + + document_root: READABLE_STRING_8 + -- Document root to look for files or directories + local + e: EXECUTION_ENVIRONMENT + dn: DIRECTORY_NAME + once + create e + create dn.make_from_string (e.current_working_directory) + dn.extend ("htdocs") + Result := dn.string + if Result [Result.count] = Operating_environment.directory_separator then + Result := Result.substring (1, Result.count - 1) + end + end + + files_root: READABLE_STRING_8 + -- Uploaded files will be stored in `files_root' folder + local + dn: DIRECTORY_NAME + once + create dn.make_from_string (document_root) + dn.extend ("files") + Result := dn.string + end + +feature -- Execution + + execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Default request handler if no other are relevant + do + res.redirect_now_with_content (req.script_url ("/"), "Redirection to " + req.script_url ("/"), "text/html") + end + + execute_not_found (uri: READABLE_STRING_8; ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) + -- `uri' is not found, redirect to default page + do + res.redirect_now_with_content (req.script_url ("/"), uri + ": not found.%NRedirection to " + req.script_url ("/"), "text/html") + end + + execute_upload (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Upload page is requested, either GET or POST + -- On GET display the web form to upload file, by passing ?nb=5 you can upload 5 images + -- On POST display the uploaded files + local + l_body: STRING_8 + l_safe_filename: STRING_8 + fn: FILE_NAME + page: WSF_HTML_PAGE_RESPONSE + n: INTEGER + do + if req.is_request_method ("GET") or else not req.has_uploaded_file then + create page.make + page.set_title ("EWF: Upload file") + page.add_style (req.script_url ("style.css"), "all") + create l_body.make_empty + page.set_body (l_body) + l_body.append ("

EWF: Upload image file

%N") + l_body.append ("
%N") + if attached ctx.string_query_parameter ("nb") as p_nb and then p_nb.is_integer then + n := p_nb.to_integer + else + n := 1 + end + if attached ctx.string_query_parameter ("demo") as p_demo then + create fn.make_from_string (document_root) + fn.set_file_name (p_demo.string) + l_body.append ("File:
%N") + end + + from + until + n = 0 + loop + l_body.append ("File:
%N") + n := n - 1 + end + l_body.append (" %N
") + page.send_to (res) + else + create l_body.make (255) + l_body.append ("

EWF: Uploaded files

%N") + l_body.append ("
    ") + across + req.uploaded_files as c + loop + l_body.append ("
  • ") + l_body.append ("
    " + c.item.name + "=" + html_encode (c.item.filename) + " size=" + c.item.size.out + " type=" + c.item.content_type + "
    ") + create fn.make_from_string (files_root) + l_safe_filename := c.item.safe_filename + fn.set_file_name (l_safe_filename) + if c.item.move_to (fn.string) then + if c.item.content_type.starts_with ("image") then + l_body.append ("%N") + else + l_body.append ("File " + html_encode (c.item.filename) + " is not a supported image
    %N") + end + end + l_body.append ("
  • ") + end + l_body.append ("
") + + create page.make + page.set_title ("EWF: uploaded image") + page.add_style ("../style.css", "all") + page.set_body (l_body) + page.send_to (res) + end + end + +feature {NONE} -- Encoder + + url_encode (s: READABLE_STRING_32): STRING_8 + -- URL Encode `s' as Result + do + Result := url_encoder.encoded_string (s) + end + + url_encoder: URL_ENCODER + once + create Result + end + + html_encode (s: READABLE_STRING_32): STRING_8 + -- HTML Encode `s' as Result + do + Result := html_encoder.encoded_string (s) + end + + html_encoder: HTML_ENCODER + once + create Result + 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 diff --git a/examples/upload_image/upload_image-safe.ecf b/examples/upload_image/upload_image-safe.ecf new file mode 100644 index 00000000..8906381f --- /dev/null +++ b/examples/upload_image/upload_image-safe.ecf @@ -0,0 +1,31 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + + + diff --git a/library/server/ewsgi/connectors/nino/src/wgi_nino_connector.e b/library/server/ewsgi/connectors/nino/src/wgi_nino_connector.e index 72a51e7d..efd6b78b 100644 --- a/library/server/ewsgi/connectors/nino/src/wgi_nino_connector.e +++ b/library/server/ewsgi/connectors/nino/src/wgi_nino_connector.e @@ -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)) diff --git a/library/server/ewsgi/connectors/nino/src/wgi_nino_input_stream.e b/library/server/ewsgi/connectors/nino/src/wgi_nino_input_stream.e index b707afb7..d11d2f7c 100644 --- a/library/server/ewsgi/connectors/nino/src/wgi_nino_input_stream.e +++ b/library/server/ewsgi/connectors/nino/src/wgi_nino_input_stream.e @@ -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 diff --git a/library/server/ewsgi/connectors/nino/src/wgi_nino_response_stream.e b/library/server/ewsgi/connectors/nino/src/wgi_nino_response_stream.e new file mode 100644 index 00000000..c98789ff --- /dev/null +++ b/library/server/ewsgi/connectors/nino/src/wgi_nino_response_stream.e @@ -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 diff --git a/library/server/ewsgi/specification/request/wgi_uploaded_file_data.e b/library/server/ewsgi/specification/request/wgi_uploaded_file_data.e deleted file mode 100644 index 339febae..00000000 --- a/library/server/ewsgi/specification/request/wgi_uploaded_file_data.e +++ /dev/null @@ -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 diff --git a/library/server/ewsgi/src/helper/wgi_request_from_table.e b/library/server/ewsgi/src/implementation/wgi_request_from_table.e similarity index 100% rename from library/server/ewsgi/src/helper/wgi_request_from_table.e rename to library/server/ewsgi/src/implementation/wgi_request_from_table.e diff --git a/library/server/ewsgi/src/helper/wgi_response_stream.e b/library/server/ewsgi/src/implementation/wgi_response_stream.e similarity index 100% rename from library/server/ewsgi/src/helper/wgi_response_stream.e rename to library/server/ewsgi/src/implementation/wgi_response_stream.e diff --git a/library/server/ewsgi/src/wgi_chunked_input_stream.e b/library/server/ewsgi/src/wgi_chunked_input_stream.e index e3699444..90db6692 100644 --- a/library/server/ewsgi/src/wgi_chunked_input_stream.e +++ b/library/server/ewsgi/src/wgi_chunked_input_stream.e @@ -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 diff --git a/library/server/wsf/router/request_file_system_handler.e b/library/server/wsf/router/request_file_system_handler.e index fd973ee6..b9002556 100644 --- a/library/server/wsf/router/request_file_system_handler.e +++ b/library/server/wsf/router/request_file_system_handler.e @@ -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 diff --git a/library/server/wsf/router/request_handler_context.e b/library/server/wsf/router/request_handler_context.e index 90a80d5a..82799173 100644 --- a/library/server/wsf/router/request_handler_context.e +++ b/library/server/wsf/router/request_handler_context.e @@ -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 diff --git a/library/server/wsf/src/request/value/visitor/wsf_value_iterator.e b/library/server/wsf/src/request/value/visitor/wsf_value_iterator.e index 32ad02fc..d66fad73 100644 --- a/library/server/wsf/src/request/value/visitor/wsf_value_iterator.e +++ b/library/server/wsf/src/request/value/visitor/wsf_value_iterator.e @@ -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" diff --git a/library/server/wsf/src/request/value/visitor/wsf_value_null_visitor.e b/library/server/wsf/src/request/value/visitor/wsf_value_null_visitor.e index f18dd979..6e801e23 100644 --- a/library/server/wsf/src/request/value/visitor/wsf_value_null_visitor.e +++ b/library/server/wsf/src/request/value/visitor/wsf_value_null_visitor.e @@ -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)" diff --git a/library/server/wsf/src/request/value/visitor/wsf_value_visitor.e b/library/server/wsf/src/request/value/visitor/wsf_value_visitor.e index 0f5bceb4..58ad3fbc 100644 --- a/library/server/wsf/src/request/value/visitor/wsf_value_visitor.e +++ b/library/server/wsf/src/request/value/visitor/wsf_value_visitor.e @@ -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)" diff --git a/library/server/wsf/src/request/value/wsf_any.e b/library/server/wsf/src/request/value/wsf_any.e index 68d60fd9..92664d21 100644 --- a/library/server/wsf/src/request/value/wsf_any.e +++ b/library/server/wsf/src/request/value/wsf_any.e @@ -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 diff --git a/library/server/wsf/src/request/value/wsf_multiple_string.e b/library/server/wsf/src/request/value/wsf_multiple_string.e index e048cacc..8ee57398 100644 --- a/library/server/wsf/src/request/value/wsf_multiple_string.e +++ b/library/server/wsf/src/request/value/wsf_multiple_string.e @@ -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 diff --git a/library/server/wsf/src/request/value/wsf_string.e b/library/server/wsf/src/request/value/wsf_string.e index 56ad96b3..a0abe2c3 100644 --- a/library/server/wsf/src/request/value/wsf_string.e +++ b/library/server/wsf/src/request/value/wsf_string.e @@ -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 diff --git a/library/server/wsf/src/request/value/wsf_table.e b/library/server/wsf/src/request/value/wsf_table.e index 9bf17386..5533415f 100644 --- a/library/server/wsf/src/request/value/wsf_table.e +++ b/library/server/wsf/src/request/value/wsf_table.e @@ -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 diff --git a/library/server/wsf/src/request/value/wsf_uploaded_file.e b/library/server/wsf/src/request/value/wsf_uploaded_file.e new file mode 100644 index 00000000..43b21729 --- /dev/null +++ b/library/server/wsf/src/request/value/wsf_uploaded_file.e @@ -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 diff --git a/library/server/wsf/src/request/wsf_value.e b/library/server/wsf/src/request/wsf_value.e index 5a7a51df..7296f8fd 100644 --- a/library/server/wsf/src/request/wsf_value.e +++ b/library/server/wsf/src/request/wsf_value.e @@ -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 diff --git a/library/server/wsf/src/response/wsf_html_page_response.e b/library/server/wsf/src/response/wsf_html_page_response.e new file mode 100644 index 00000000..07be5263 --- /dev/null +++ b/library/server/wsf/src/response/wsf_html_page_response.e @@ -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 := "" + 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 := "" + head_lines.extend (s) + end + + add_meta_http_equiv (a_http_equiv: STRING; a_content: STRING) + local + s: STRING_8 + do + s := "" + head_lines.extend (s) + end + + add_style (a_href: STRING; a_media: detachable STRING) + local + s: STRING_8 + do + s := "") + head_lines.extend (s) + end + + add_javascript_url (a_src: STRING) + local + s: STRING_8 + do + s := "" + head_lines.extend (s) + end + + add_javascript_content (a_script: STRING) + local + s: STRING_8 + do + s := "" + 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 ("%N") + + t := title + lines := head_lines + if t /= Void or else lines.count > 0 then + s.append ("") + if t /= Void then + s.append ("" + t + "%N") + end + s.append_character ('%N') + across + lines as l + loop + s.append (l.item) + s.append_character ('%N') + end + s.append ("%N") + end + + b := body + s.append ("%N") + if b /= Void then + s.append (b) + end + s.append ("%N%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 diff --git a/library/server/wsf/src/support/wsf_mime_handler_helper.e b/library/server/wsf/src/support/wsf_mime_handler_helper.e index ca554ed6..bc057d4b 100644 --- a/library/server/wsf/src/support/wsf_mime_handler_helper.e +++ b/library/server/wsf/src/support/wsf_mime_handler_helper.e @@ -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 diff --git a/library/server/wsf/src/wsf_application_x_www_form_urlencoded_handler.e b/library/server/wsf/src/wsf_application_x_www_form_urlencoded_handler.e index 3433b6a7..308debde 100644 --- a/library/server/wsf/src/wsf_application_x_www_form_urlencoded_handler.e +++ b/library/server/wsf/src/wsf_application_x_www_form_urlencoded_handler.e @@ -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 diff --git a/library/server/wsf/src/wsf_multipart_form_data_handler.e b/library/server/wsf/src/wsf_multipart_form_data_handler.e index edc15afe..fc20b675 100644 --- a/library/server/wsf/src/wsf_multipart_form_data_handler.e +++ b/library/server/wsf/src/wsf_multipart_form_data_handler.e @@ -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) diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e index be77a412..3684d9a2 100644 --- a/library/server/wsf/src/wsf_request.e +++ b/library/server/wsf/src/wsf_request.e @@ -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 diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e index 5fc4a69e..be214460 100644 --- a/library/server/wsf/src/wsf_response.e +++ b/library/server/wsf/src/wsf_response.e @@ -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 diff --git a/library/server/wsf/src/wsf_service.e b/library/server/wsf/src/wsf_service.e index c2b36e0e..2a48df75 100644 --- a/library/server/wsf/src/wsf_service.e +++ b/library/server/wsf/src/wsf_service.e @@ -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