From 0d5011b03ee6ef5a8f56288fa7c405357c4cccee Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 30 May 2012 09:36:55 +0200 Subject: [PATCH] Added html encoding facility to WSF_STRING Added WSF_STRING.is_empty Improved HTML_ENCODER to be able to decode a STRING_8 or STRING_32 using general_decoded_string (s) Improved tutorial example Added precompilation for WSF library Cosmetic (removed unused locals) --- examples/tutorial/step_2/hello/hello.ecf | 29 +++-- examples/tutorial/step_4/hello/hello.ecf | 3 + .../step_4/hello/src/hello_application.e | 57 ++++++++-- .../step_4/hello/src/user_message_handler.e | 73 +++++++++++++ .../server/wsf/src/request/value/wsf_string.e | 25 +++++ .../wsf/src/response/wsf_html_page_response.e | 1 - library/text/encoder/src/html_encoder.e | 103 +++++++++++++----- precomp/build.bat | 4 + precomp/wsf-mt-safe.ecf | 11 ++ precomp/wsf-safe.ecf | 10 ++ precomp/wsf-scoop-safe.ecf | 11 ++ 11 files changed, 280 insertions(+), 47 deletions(-) create mode 100644 examples/tutorial/step_4/hello/src/user_message_handler.e create mode 100644 precomp/build.bat create mode 100644 precomp/wsf-mt-safe.ecf create mode 100644 precomp/wsf-safe.ecf create mode 100644 precomp/wsf-scoop-safe.ecf diff --git a/examples/tutorial/step_2/hello/hello.ecf b/examples/tutorial/step_2/hello/hello.ecf index 9f85f9ad..9df56668 100644 --- a/examples/tutorial/step_2/hello/hello.ecf +++ b/examples/tutorial/step_2/hello/hello.ecf @@ -1,24 +1,39 @@ - - + + /EIFGENs$ /CVS$ /.svn$ - + - - + + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + - - diff --git a/examples/tutorial/step_4/hello/hello.ecf b/examples/tutorial/step_4/hello/hello.ecf index 1d54ebf1..9a69655b 100644 --- a/examples/tutorial/step_4/hello/hello.ecf +++ b/examples/tutorial/step_4/hello/hello.ecf @@ -10,8 +10,11 @@ + + + diff --git a/examples/tutorial/step_4/hello/src/hello_application.e b/examples/tutorial/step_4/hello/src/hello_application.e index 8797b897..fab7157c 100644 --- a/examples/tutorial/step_4/hello/src/hello_application.e +++ b/examples/tutorial/step_4/hello/src/hello_application.e @@ -1,4 +1,4 @@ -note +note description: "[ This class implements the `Hello World' service. @@ -29,7 +29,12 @@ feature {NONE} -- Initialization setup_router do router.map_agent ("/hello", agent execute_hello) - router.map_agent_response_with_request_methods ("/{user}/bye", agent response_bye, <<"GET">>) + + + router.map_with_request_methods ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>) + router.map_with_request_methods ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>) + + router.map_agent_response_with_request_methods ("/users/{user}/{?op}", agent response_user, <<"GET">>) end feature -- Execution @@ -44,6 +49,7 @@ feature -- Execution -- Computed response message. local mesg: WSF_HTML_PAGE_RESPONSE + s: STRING_8 do --| It is now returning a WSF_HTML_PAGE_RESPONSE --| Since it is easier for building html page @@ -51,21 +57,26 @@ feature -- Execution mesg.set_title ("EWF tutorial / Hello World!") --| Check if the request contains a parameter named "user" --| this could be a query, or a form parameter - if attached req.string_item ("user") as u then + if attached {WSF_STRING} req.item ("user") as u then --| If yes, say hello world #name - mesg.set_body ("Hello " + u + "!
Click here to quit.") + s := "

Hello " + u.html_encoded_string + "!

" + s.append ("Display a message

") + s.append ("

Click here to quit.

") + mesg.set_body (s) --| We should html encode this name --| but to keep the example simple, we don't do that for now. else --| Otherwise, ask for name - mesg.set_body ("[ + s := (create {HTML_ENCODER}).encoded_string ({STRING_32} "Hello / ahoj / नमस्ते / Ciào / مرحبا / Hola / 你好 / Hallo / Selam / Bonjour ") + s.append ("[
-

Hello, what is your name?

+ What is your name?

]" ) + mesg.set_body (s) end --| note: @@ -79,17 +90,39 @@ feature -- Execution res.send (mesg) end - response_bye (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE + response_user (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE -- Computed response message. local html: WSF_HTML_PAGE_RESPONSE redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE + s: STRING_8 do - if attached ctx.string_path_parameter ("user") as u then - create redir.make (req.script_url ("/hello"), 5) - redir.set_title ("Bye " + u) - redir.set_body ("Bye " + u + ",
see you soon.

You will be redirected to " + redir.url_location + " in " + redir.delay.out + " second(s) ...

") - Result := redir + if attached {WSF_STRING} ctx.path_parameter ("user") as u then + if + attached {WSF_STRING} req.query_parameter ("op") as l_op + then + if l_op.is_case_insensitive_equal ("quit") then + create redir.make (req.script_url ("/hello"), 5) + redir.set_title ("Bye " + u.url_encoded_string) + redir.set_body ("Bye " + u.url_encoded_string + ",
see you soon.

You will be redirected to " + + redir.url_location + " in " + redir.delay.out + " second(s) ...

" + ) + Result := redir + else + create html.make + html.set_title ("Bad request") + html.set_body ("Bad request: unknown operation '" + l_op.url_encoded_string + "'.") + Result := html + end + else + s := "

User '" + u.url_encoded_string + "'!

" + s.append ("Display a message

") + s.append ("

Click here to quit.

") + create html.make + html.set_title ("User '" + u.url_encoded_string + "'") + html.set_body (s) + Result := html + end else create html.make html.set_title ("Bad request") diff --git a/examples/tutorial/step_4/hello/src/user_message_handler.e b/examples/tutorial/step_4/hello/src/user_message_handler.e new file mode 100644 index 00000000..3a7d3ffd --- /dev/null +++ b/examples/tutorial/step_4/hello/src/user_message_handler.e @@ -0,0 +1,73 @@ +note + description: "[ + Handler to process /user/{user}/message/ requests + ]" + date: "$Date$" + revision: "$Revision$" + +class + USER_MESSAGE_HANDLER + +inherit + WSF_RESPONSE_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT] + +feature -- Access + + response (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE + do + if attached {WSF_STRING} ctx.path_parameter ("user") as u then + if req.is_request_method ("GET") then + Result := user_message_get (u, ctx, req) + elseif req.is_request_method ("POST") then + Result := user_message_response_post (u, ctx, req) + else + Result := unsupported_method_response (req) + end + else + Result := missing_argument_response ("Missing parameter 'user'.", req) + end + end + + missing_argument_response (m: READABLE_STRING_8; req: WSF_REQUEST): WSF_PAGE_RESPONSE + do + create Result.make + Result.set_status_code ({HTTP_STATUS_CODE}.bad_request) + Result.put_string (req.request_uri + ": " + m) + end + + unsupported_method_response (req: WSF_REQUEST): WSF_PAGE_RESPONSE + do + create Result.make + Result.set_status_code ({HTTP_STATUS_CODE}.bad_request) + Result.put_string (req.request_uri + " only support: GET and POST; " + req.request_method + " is not supported.") + end + + + user_message_get (u: WSF_STRING; ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_HTML_PAGE_RESPONSE + local + s: STRING_8 + do + create Result.make + s := "

No message from user '" + u.html_encoded_string + "'.

" + s.append ("
") + s.append ("") + s.append ("") + s.append ("
") + Result.set_body (s) + end + + user_message_response_post (u: WSF_STRING; ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_HTML_PAGE_RESPONSE + local + s: STRING_8 + do + create Result.make + s := "

Message from user '" + u.html_encoded_string + "'.

" + if attached {WSF_STRING} req.form_parameter ("message") as m and then not m.is_empty then + s.append ("") + else + s.append ("No or empty message!") + end + Result.set_body (s) + end + +end diff --git a/library/server/wsf/src/request/value/wsf_string.e b/library/server/wsf/src/request/value/wsf_string.e index cd945d66..812e205a 100644 --- a/library/server/wsf/src/request/value/wsf_string.e +++ b/library/server/wsf/src/request/value/wsf_string.e @@ -56,6 +56,12 @@ feature -- Status report is_string: BOOLEAN = True -- Is Current as a WSF_STRING representation? + is_empty: BOOLEAN + -- Is empty? + do + Result := string.is_empty + end + feature -- Helper same_string (a_other: READABLE_STRING_GENERAL): BOOLEAN @@ -84,6 +90,25 @@ feature -- Conversion create Result.make_from_string (string) end + html_encoded_name: READABLE_STRING_8 + -- HTML encoded string `name' + do + Result := (create {HTML_ENCODER}).encoded_string (name) + end + + html_encoded_string: READABLE_STRING_8 + -- HTML encoded string `string' + do + Result := (create {HTML_ENCODER}).encoded_string (string) + end + +feature {NONE} -- Conversion + + html_decoded_string (s: READABLE_STRING_GENERAL): READABLE_STRING_32 + do + Result := (create {HTML_ENCODER}).general_decoded_string (s) + end + feature -- Visitor process (vis: WSF_VALUE_VISITOR) diff --git a/library/server/wsf/src/response/wsf_html_page_response.e b/library/server/wsf/src/response/wsf_html_page_response.e index 3c0b33b4..41916a59 100644 --- a/library/server/wsf/src/response/wsf_html_page_response.e +++ b/library/server/wsf/src/response/wsf_html_page_response.e @@ -114,7 +114,6 @@ feature {WSF_SERVICE, WSF_RESPONSE} -- Output send_to (res: WSF_RESPONSE) local - b: like body h: like header s: STRING_8 do diff --git a/library/text/encoder/src/html_encoder.e b/library/text/encoder/src/html_encoder.e index 9bb0fc08..d92a856e 100644 --- a/library/text/encoder/src/html_encoder.e +++ b/library/text/encoder/src/html_encoder.e @@ -91,63 +91,97 @@ feature -- Decoder end end + general_decoded_string (v: READABLE_STRING_GENERAL): STRING_32 + -- The HTML-encoded equivalent of the given string + local + i, n: INTEGER + c: NATURAL_32 + cl_i: CELL [INTEGER] + amp_code: NATURAL_32 + do + has_error := False + n := v.count + create Result.make (n) + create cl_i.put (0) + amp_code := ('&').natural_32_code + from i := 1 until i > n loop + c := v.code (i) + if c = amp_code then + cl_i.replace (i) + Result.append_string_general (next_entity (v, cl_i)) + i := cl_i.item + else + Result.append_character (c.to_character_32) + i := i + 1 + end + end + end + feature {NONE} -- Implementation: decoder - next_entity (v: STRING_8; cl_i: CELL [INTEGER]): STRING_32 + next_entity (v: READABLE_STRING_GENERAL; cl_i: CELL [INTEGER]): STRING_32 -- Return next entity value -- move index local i: INTEGER - c: CHARACTER + l_code: NATURAL_32 is_char: BOOLEAN is_hexa: BOOLEAN s: STRING_32 + sharp_code, + x_code, + semi_colon_code: NATURAL_32 do + sharp_code := ('#').natural_32_code + x_code := ('x').natural_32_code + x_code := (';').natural_32_code + i := cl_i.item create s.make_empty i := i + 1 - c := v[i] - if c = '#' then + l_code := v.code (i) + if l_code = sharp_code then is_char := True i := i + 1 - c := v[i] - if c = 'x' then + l_code := v.code (i) + if l_code = x_code then is_hexa := True i := i + 1 - c := v[i] + l_code := v.code (i) end end + if is_char then if is_hexa then from until - not c.is_hexa_digit or c = ';' + not is_hexa_digit (l_code) or l_code = semi_colon_code loop - s.append_character (c) + s.append_code (l_code) i := i + 1 - c := v[i] + l_code := v.code (i) end else from until - not c.is_digit or c = ';' + not is_digit (l_code) or l_code = semi_colon_code loop - s.append_character (c) + s.append_code (l_code) i := i + 1 - c := v[i] + l_code := v.code (i) end end else from until - not valid_entity_character (c) or c = ';' + not valid_entity_character (l_code) or l_code = semi_colon_code loop - s.append_character (c) + s.append_code (l_code) i := i + 1 - c := v[i] + l_code := v.code (i) end end - if c = ';' then + if l_code = semi_colon_code then if is_char then if is_hexa then -- not yet implemented @@ -242,22 +276,37 @@ feature {NONE} -- Implementation: decoder end end - valid_entity_character (c: CHARACTER): BOOLEAN + valid_entity_character (a_code: NATURAL_32): BOOLEAN -- Is `c' a valid character in html entity value? --| such as & + local + c: CHARACTER_8 do - inspect - c - when 'a'..'z' then - Result := True - when 'A'..'Z' then - Result := True - when '0'..'9' then - Result := True - else + if a_code.is_valid_character_8_code then + c := a_code.to_character_8 + inspect + c + when 'a'..'z' then + Result := True + when 'A'..'Z' then + Result := True + when '0'..'9' then + Result := True + else + end end end + is_hexa_digit (c: NATURAL_32): BOOLEAN + do + Result := c.is_valid_character_8_code and then c.to_character_8.is_hexa_digit + end + + is_digit (c: NATURAL_32): BOOLEAN + do + Result := c.is_valid_character_8_code and then c.to_character_8.is_digit + end + note copyright: "2011-2012, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/precomp/build.bat b/precomp/build.bat new file mode 100644 index 00000000..a09f4c87 --- /dev/null +++ b/precomp/build.bat @@ -0,0 +1,4 @@ +echo Precompiling wsf +ec -config wsf-safe.ecf -precompile -c_compile -clean +ec -config wsf-mt-safe.ecf -precompile -c_compile -clean +ec -config wsf-scoop-safe.ecf -precompile -c_compile -clean diff --git a/precomp/wsf-mt-safe.ecf b/precomp/wsf-mt-safe.ecf new file mode 100644 index 00000000..460ffd13 --- /dev/null +++ b/precomp/wsf-mt-safe.ecf @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/precomp/wsf-safe.ecf b/precomp/wsf-safe.ecf new file mode 100644 index 00000000..7866c305 --- /dev/null +++ b/precomp/wsf-safe.ecf @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/precomp/wsf-scoop-safe.ecf b/precomp/wsf-scoop-safe.ecf new file mode 100644 index 00000000..621ed9eb --- /dev/null +++ b/precomp/wsf-scoop-safe.ecf @@ -0,0 +1,11 @@ + + + + + + + + +