Compare commits
12 Commits
v1.0.2
...
v1_executo
| Author | SHA1 | Date | |
|---|---|---|---|
| 91fbb3866f | |||
| 903f925a79 | |||
| 80709578d6 | |||
| c0d5b7c968 | |||
| 7bea163f46 | |||
| 8992dbc515 | |||
| c2d3ea6138 | |||
| 9e336deb49 | |||
| 0160ce05dd | |||
| 7d089a88c2 | |||
| ab0bc7b314 | |||
| 0e3e97a7fd |
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that Generates Plain Text"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,15 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
|
||||
res.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
26
doc/workbook/basics/simple/application_execution.e
Normal file
26
doc/workbook/basics/simple/application_execution.e
Normal file
@@ -0,0 +1,26 @@
|
||||
note
|
||||
description : "Basic Service that Generates Plain Text"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
|
||||
response.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that Generate HTML"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,55 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
res.put_string (web_page)
|
||||
end
|
||||
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Resume</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Your Name Here</p>
|
||||
<a href="mailto:you@yourdomain.com"><p id="email">you@yourdomain.com</p></a>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>Objective</h4>
|
||||
<p>To take a position as a software engineer.</p>
|
||||
<h4>Experience</h4>
|
||||
<p>Junior Developer, Software Company (2010 - Present)</p>
|
||||
<ul>
|
||||
<li>Designed and implemented end-user features for Flagship Product</li>
|
||||
<li>Wrote third-party JavaScript and Eiffel libraries</li>
|
||||
</ul>
|
||||
<h4>Skills</h4>
|
||||
<p>Languages: C#, JavaScript, Python, Ruby, Eiffel</p>
|
||||
<p>Frameworks: .NET, Node.js, Django, Ruby on Rails, EWF</p>
|
||||
<h4>Education</h4>
|
||||
<p>BS, Economics, My University</p>
|
||||
<ul>
|
||||
<li>Award for best senior thesis</li>
|
||||
<li>GPA: 3.8</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>123 Your Street, Anytown, State 12345-6789 | Tel: (555) 555-5555</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
|
||||
66
doc/workbook/basics/simple_html/application_execution.e
Normal file
66
doc/workbook/basics/simple_html/application_execution.e
Normal file
@@ -0,0 +1,66 @@
|
||||
note
|
||||
description : "Basic Service that Generate HTML"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
response.put_string (web_page)
|
||||
end
|
||||
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Resume</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Your Name Here</p>
|
||||
<a href="mailto:you@yourdomain.com"><p id="email">you@yourdomain.com</p></a>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>Objective</h4>
|
||||
<p>To take a position as a software engineer.</p>
|
||||
<h4>Experience</h4>
|
||||
<p>Junior Developer, Software Company (2010 - Present)</p>
|
||||
<ul>
|
||||
<li>Designed and implemented end-user features for Flagship Product</li>
|
||||
<li>Wrote third-party JavaScript and Eiffel libraries</li>
|
||||
</ul>
|
||||
<h4>Skills</h4>
|
||||
<p>Languages: C#, JavaScript, Python, Ruby, Eiffel</p>
|
||||
<p>Frameworks: .NET, Node.js, Django, Ruby on Rails, EWF</p>
|
||||
<h4>Education</h4>
|
||||
<p>BS, Economics, My University</p>
|
||||
<ul>
|
||||
<li>Award for best senior thesis</li>
|
||||
<li>GPA: 3.8</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>123 Your Street, Anytown, State 12345-6789 | Tel: (555) 555-5555</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that show how to use common Status Code"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,25 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/csv"],["Content-Disposition","attachment;filename=Report.xls"],["Content-Length", sheet.count.out]>>)
|
||||
res.put_string (sheet)
|
||||
end
|
||||
|
||||
-- ,["Content-Disposition","attachment;filename=Report.xls"]
|
||||
|
||||
|
||||
sheet: STRING ="[
|
||||
Q1 Q2 Q3 Q4 Total
|
||||
Cherries 78 87 92 29 =SUM(B2:E2)
|
||||
Grapes 77 86 93 30 =SUM(B3:E3)
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
note
|
||||
description : "Basic Service that show how to use common Status Code"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/csv"],["Content-Disposition","attachment;filename=Report.xls"],["Content-Length", sheet.count.out]>>)
|
||||
response.put_string (sheet)
|
||||
end
|
||||
|
||||
-- ,["Content-Disposition","attachment;filename=Report.xls"]
|
||||
|
||||
|
||||
sheet: STRING ="[
|
||||
Q1 Q2 Q3 Q4 Total
|
||||
Cherries 78 87 92 29 =SUM(B2:E2)
|
||||
Grapes 77 86 93 30 =SUM(B3:E3)
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that build a generic front end for the most used search engines."
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,46 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
-- (1) To send a response we need to setup, the status code and the response headers.
|
||||
-- res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
-- res.put_string (web_page)
|
||||
|
||||
-- (2) Using put_header_line
|
||||
-- res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
-- res.put_header_line ("Content-Type:text/html")
|
||||
res.put_header_line ("Content-Length:"+ web_page.count.out)
|
||||
res.put_header_line ("Content-Type:text/plain")
|
||||
|
||||
res.put_string (web_page)
|
||||
end
|
||||
|
||||
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EWF Headers Responses</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>Example Header Response</h2>
|
||||
<p>Response headers</p>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>EWF Response Header</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
note
|
||||
description : "Basic Service that build a generic front end for the most used search engines."
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
-- (1) To send a response we need to setup, the status code and the response headers.
|
||||
-- response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
-- response.put_string (web_page)
|
||||
|
||||
-- (2) Using put_header_line
|
||||
-- response.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
-- response.put_header_line ("Content-Type:text/html")
|
||||
response.put_header_line ("Content-Length:"+ web_page.count.out)
|
||||
response.put_header_line ("Content-Type:text/plain")
|
||||
|
||||
response.put_string (web_page)
|
||||
end
|
||||
|
||||
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EWF Headers Responses</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>Example Header Response</h2>
|
||||
<p>Response headers</p>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>EWF Response Header</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that build a generic front end for the most used search engines."
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,161 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
if req.is_get_request_method then
|
||||
if req.path_info.same_string ("/") then
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
res.put_string (web_page)
|
||||
else
|
||||
send_resouce_not_found (req, res)
|
||||
end
|
||||
elseif req.is_post_request_method then
|
||||
if req.path_info.same_string ("/search") then
|
||||
if attached {WSF_STRING} req.form_parameter ("query") as l_query then
|
||||
if attached {WSF_STRING} req.form_parameter ("engine") as l_engine then
|
||||
if attached {STRING} map.at (l_engine.value) as l_engine_url then
|
||||
l_engine_url.append (l_query.value)
|
||||
send_redirect (req, res, l_engine_url)
|
||||
-- res.redirect_now (l_engine_url)
|
||||
else
|
||||
send_bad_request (req, res, " <strong>search engine: " + l_engine.value + "</strong> not supported,<br> try with Google or Bing")
|
||||
end
|
||||
else
|
||||
send_bad_request (req, res, " <strong>search engine</strong> not selected")
|
||||
end
|
||||
else
|
||||
send_bad_request (req, res, " form_parameter <strong>query</strong> is not present")
|
||||
end
|
||||
else
|
||||
send_resouce_not_found (req, res)
|
||||
end
|
||||
else
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Method Not Allowed")
|
||||
l_message.replace_substring_all ("$status", "Method Not Allowed 405")
|
||||
-- Method not allowed
|
||||
res.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Engine Map
|
||||
|
||||
map : STRING_TABLE[STRING]
|
||||
do
|
||||
create Result.make (2)
|
||||
Result.put ("http://www.google.com/search?q=", "Google")
|
||||
Result.put ("http://www.bing.com/search?q=", "Bing")
|
||||
end
|
||||
|
||||
feature -- Redirect
|
||||
|
||||
send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
|
||||
-- Redirect to `a_location'
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
h.put_current_date
|
||||
h.put_location (a_location)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
|
||||
res.put_header_text (h.string)
|
||||
end
|
||||
|
||||
feature -- Bad Request
|
||||
|
||||
send_bad_request (req: WSF_REQUEST; res: WSF_RESPONSE; description: STRING)
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Bad Request")
|
||||
l_message.replace_substring_all ("$status", "Bad Request" + description)
|
||||
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
|
||||
feature -- Resource not found
|
||||
|
||||
send_resouce_not_found (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Resource not found")
|
||||
l_message.replace_substring_all ("$status", "Resource " + req.request_uri + " not found 404")
|
||||
res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Generic Search Engine</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>Generic Search Engine</h2>
|
||||
<form method="POST" action="/search" target="_blank">
|
||||
<fieldset>
|
||||
Search: <input type="search" name="query" placeholder="EWF framework"><br>
|
||||
<div>
|
||||
<input type="radio" name="engine" value="Google" checked><img src="http://ebizmba.ebizmbainc.netdna-cdn.com/images/logos/google.gif" height="24" width="42">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="radio" name="engine" value="Bing"><img src="http://ebizmba.ebizmbainc.netdna-cdn.com/images/logos/bing.gif" height="24" width="42">
|
||||
</div><br>
|
||||
</fieldset>
|
||||
<input type="submit">
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p><a href="http://www.ebizmba.com/articles/search-engines">Top 15 Most Popular Search Engines | March 2015</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
feature -- Generic Message
|
||||
|
||||
message_template: STRING="[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>$title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>This page is an example of $status</h4>
|
||||
|
||||
<div id="footer">
|
||||
<p><a href="/">Back Home</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
172
doc/workbook/generating_response/search/application_execution.e
Normal file
172
doc/workbook/generating_response/search/application_execution.e
Normal file
@@ -0,0 +1,172 @@
|
||||
note
|
||||
description : "Basic Service that build a generic front end for the most used search engines."
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
if request.is_get_request_method then
|
||||
if request.path_info.same_string ("/") then
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
response.put_string (web_page)
|
||||
else
|
||||
send_resouce_not_found (request, response)
|
||||
end
|
||||
elseif request.is_post_request_method then
|
||||
if request.path_info.same_string ("/search") then
|
||||
if attached {WSF_STRING} request.form_parameter ("query") as l_query then
|
||||
if attached {WSF_STRING} request.form_parameter ("engine") as l_engine then
|
||||
if attached {STRING} map.at (l_engine.value) as l_engine_url then
|
||||
l_engine_url.append (l_query.value)
|
||||
send_redirect (request, response, l_engine_url)
|
||||
-- response.redirect_now (l_engine_url)
|
||||
else
|
||||
send_bad_request (request, response, " <strong>search engine: " + l_engine.value + "</strong> not supported,<br> try with Google or Bing")
|
||||
end
|
||||
else
|
||||
send_bad_request (request, response, " <strong>search engine</strong> not selected")
|
||||
end
|
||||
else
|
||||
send_bad_request (request, response, " form_parameter <strong>query</strong> is not present")
|
||||
end
|
||||
else
|
||||
send_resouce_not_found (request, response)
|
||||
end
|
||||
else
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Method Not Allowed")
|
||||
l_message.replace_substring_all ("$status", "Method Not Allowed 405")
|
||||
-- Method not allowed
|
||||
response.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
response.put_string (l_message)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Engine Map
|
||||
|
||||
map : STRING_TABLE[STRING]
|
||||
do
|
||||
create Result.make (2)
|
||||
Result.put ("http://www.google.com/search?q=", "Google")
|
||||
Result.put ("http://www.bing.com/search?q=", "Bing")
|
||||
end
|
||||
|
||||
feature -- Redirect
|
||||
|
||||
send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
|
||||
-- Redirect to `a_location'
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
h.put_current_date
|
||||
h.put_location (a_location)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
|
||||
res.put_header_text (h.string)
|
||||
end
|
||||
|
||||
feature -- Bad Request
|
||||
|
||||
send_bad_request (req: WSF_REQUEST; res: WSF_RESPONSE; description: STRING)
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Bad Request")
|
||||
l_message.replace_substring_all ("$status", "Bad Request" + description)
|
||||
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
|
||||
feature -- Resource not found
|
||||
|
||||
send_resouce_not_found (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Resource not found")
|
||||
l_message.replace_substring_all ("$status", "Resource " + req.request_uri + " not found 404")
|
||||
res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Generic Search Engine</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>Generic Search Engine</h2>
|
||||
<form method="POST" action="/search" target="_blank">
|
||||
<fieldset>
|
||||
Search: <input type="search" name="query" placeholder="EWF framework"><br>
|
||||
<div>
|
||||
<input type="radio" name="engine" value="Google" checked><img src="http://ebizmba.ebizmbainc.netdna-cdn.com/images/logos/google.gif" height="24" width="42">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="radio" name="engine" value="Bing"><img src="http://ebizmba.ebizmbainc.netdna-cdn.com/images/logos/bing.gif" height="24" width="42">
|
||||
</div><br>
|
||||
</fieldset>
|
||||
<input type="submit">
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p><a href="http://www.ebizmba.com/articles/search-engines">Top 15 Most Popular Search Engines | March 2015</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
feature -- Generic Message
|
||||
|
||||
message_template: STRING="[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>$title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>This page is an example of $status</h4>
|
||||
|
||||
<div id="footer">
|
||||
<p><a href="/">Back Home</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that a simple web page to show the most common status codes"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,127 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
if req.is_get_request_method then
|
||||
if req.path_info.same_string ("/") then
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
res.put_string (web_page)
|
||||
elseif req.path_info.same_string ("/redirect") then
|
||||
send_redirect (req, res, "https://httpwg.github.io/")
|
||||
elseif req.path_info.same_string ("/bad_request") then
|
||||
-- Here you can do some logic for example log, send emails to register the error, before to send the response.
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Bad Request")
|
||||
l_message.replace_substring_all ("$status", "Bad Request 400")
|
||||
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
elseif req.path_info.same_string ("/internal_error") then
|
||||
-- Here you can do some logic for example log, send emails to register the error, before to send the response.
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Internal Server Error")
|
||||
l_message.replace_substring_all ("$status", "Internal Server Error 500")
|
||||
res.put_header ({HTTP_STATUS_CODE}.internal_server_error, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
else
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Resource not found")
|
||||
l_message.replace_substring_all ("$status", "Resource not found 400")
|
||||
res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
else
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Method Not Allowed")
|
||||
l_message.replace_substring_all ("$status", "Method Not Allowed 405")
|
||||
-- Method not allowed
|
||||
res.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
res.put_string (l_message)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
|
||||
-- Redirect to `a_location'
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
h.put_current_date
|
||||
h.put_location (a_location)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
|
||||
res.put_header_text (h.string)
|
||||
end
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example showing common status codes</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>This page is an example of Status Code 200</h4>
|
||||
|
||||
<h4> Redirect Example </h4>
|
||||
<p> Click on the following link will redirect you to the HTTP Specifcation, we can do the redirect from the HTML directly but
|
||||
here we want to show you an exmaple, where you can do something before to send a redirect <a href="/redirect">Redirect</a></p>
|
||||
|
||||
<h4> Bad Request </h4>
|
||||
<p> Click on the following link, the server will answer with a 400 error, check the status code <a href="/bad_request">Bad Request</a></p>
|
||||
|
||||
<h4> Internal Server Error </h4>
|
||||
<p> Click on the following link, the server will answer with a 500 error, check the status code <a href="/internal_error">Internal Error</a></p>
|
||||
|
||||
<h4> Resource not found </h4>
|
||||
<p> Click on the following link or add to the end of the url something like /1030303 the server will answer with a 404 error, check the status code <a href="/not_foundd">Not found</a></p>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>Useful links for status codes <a href="httpstat.us">httpstat.us</a> and <a href="httpbing.org">httpbin.org</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
feature -- Generic Message
|
||||
|
||||
message_template: STRING="[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>$title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>This page is an example of $status</h4>
|
||||
|
||||
<div id="footer">
|
||||
<p><a href="/">Back Home</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
138
doc/workbook/generating_response/status/application_execution.e
Normal file
138
doc/workbook/generating_response/status/application_execution.e
Normal file
@@ -0,0 +1,138 @@
|
||||
note
|
||||
description : "Basic Service that a simple web page to show the most common status codes"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
if request.is_get_request_method then
|
||||
if request.path_info.same_string ("/") then
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
|
||||
response.put_string (web_page)
|
||||
elseif request.path_info.same_string ("/redirect") then
|
||||
send_redirect (request, response, "https://httpwg.github.io/")
|
||||
elseif request.path_info.same_string ("/bad_request") then
|
||||
-- Here you can do some logic for example log, send emails to register the error, before to send the response.
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Bad Request")
|
||||
l_message.replace_substring_all ("$status", "Bad Request 400")
|
||||
response.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
response.put_string (l_message)
|
||||
elseif request.path_info.same_string ("/internal_error") then
|
||||
-- Here you can do some logic for example log, send emails to register the error, before to send the response.
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Internal Server Error")
|
||||
l_message.replace_substring_all ("$status", "Internal Server Error 500")
|
||||
response.put_header ({HTTP_STATUS_CODE}.internal_server_error, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
response.put_string (l_message)
|
||||
else
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Resource not found")
|
||||
l_message.replace_substring_all ("$status", "Resource not found 400")
|
||||
response.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
response.put_string (l_message)
|
||||
end
|
||||
else
|
||||
create l_message.make_from_string (message_template)
|
||||
l_message.replace_substring_all ("$title", "Method Not Allowed")
|
||||
l_message.replace_substring_all ("$status", "Method Not Allowed 405")
|
||||
-- Method not allowed
|
||||
response.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
|
||||
response.put_string (l_message)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
|
||||
-- Redirect to `a_location'
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
h.put_current_date
|
||||
h.put_location (a_location)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
|
||||
res.put_header_text (h.string)
|
||||
end
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example showing common status codes</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>This page is an example of Status Code 200</h4>
|
||||
|
||||
<h4> Redirect Example </h4>
|
||||
<p> Click on the following link will redirect you to the HTTP Specifcation, we can do the redirect from the HTML directly but
|
||||
here we want to show you an exmaple, where you can do something before to send a redirect <a href="/redirect">Redirect</a></p>
|
||||
|
||||
<h4> Bad Request </h4>
|
||||
<p> Click on the following link, the server will answer with a 400 error, check the status code <a href="/bad_request">Bad Request</a></p>
|
||||
|
||||
<h4> Internal Server Error </h4>
|
||||
<p> Click on the following link, the server will answer with a 500 error, check the status code <a href="/internal_error">Internal Error</a></p>
|
||||
|
||||
<h4> Resource not found </h4>
|
||||
<p> Click on the following link or add to the end of the url something like /1030303 the server will answer with a 404 error, check the status code <a href="/not_foundd">Not found</a></p>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>Useful links for status codes <a href="httpstat.us">httpstat.us</a> and <a href="httpbing.org">httpbin.org</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
feature -- Generic Message
|
||||
|
||||
message_template: STRING="[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>$title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
|
||||
</div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<h4>This page is an example of $status</h4>
|
||||
|
||||
<div id="footer">
|
||||
<p><a href="/">Back Home</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that build a generic front to demonstrate the use of Cookies"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -21,133 +19,6 @@ feature {NONE} -- Initialization
|
||||
-- Initialize current service.
|
||||
do
|
||||
set_service_option ("port", 9090)
|
||||
set_service_option ("verbose",True)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
l_header: HTTP_HEADER
|
||||
l_time: HTTP_DATE
|
||||
l_cookies: STRING
|
||||
l_answer: STRING
|
||||
do
|
||||
-- all the cookies
|
||||
create l_cookies.make_empty
|
||||
across req.cookies as ic loop
|
||||
l_cookies.append (ic.item.name)
|
||||
l_cookies.append("<br>")
|
||||
end
|
||||
|
||||
if req.path_info.same_string ("/") then
|
||||
create l_header.make
|
||||
create l_answer.make_from_string (web_page)
|
||||
if req.cookie ("_EWF_Cookie") = Void then
|
||||
-- First access the the home page, find a cookie with specific name `_EWF_Cookie'
|
||||
l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess")
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.day_add (40)
|
||||
l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True)
|
||||
else
|
||||
-- No a new access
|
||||
l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!")
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
end
|
||||
l_header.put_content_type_text_html
|
||||
l_header.put_content_length (l_answer.count)
|
||||
res.put_header_text (l_header.string)
|
||||
res.put_string (l_answer)
|
||||
|
||||
elseif req.path_info.same_string ("/visitors") then
|
||||
create l_header.make
|
||||
create l_answer.make_from_string (visit_page)
|
||||
if req.cookie ("_visits") = Void then
|
||||
-- First access the the visit page, find a cookie with specific name `_visits'
|
||||
l_answer.replace_substring_all ("$visit", "1")
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.day_add (40)
|
||||
l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True)
|
||||
|
||||
else
|
||||
if attached {WSF_STRING} req.cookie ("_visits") as l_visit then
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.day_add (40)
|
||||
l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out )
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True)
|
||||
end
|
||||
end
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.second_add (120)
|
||||
l_header.put_content_type_text_html
|
||||
-- This cookie expires in 120 seconds, its valid for 120 seconds
|
||||
l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True)
|
||||
-- This is a session cookie, valid only to the current browsing session.
|
||||
l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True)
|
||||
l_header.put_content_length (l_answer.count)
|
||||
res.add_header_text (l_header.string)
|
||||
res.put_string (l_answer)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EWF Handling Cookies</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>$header_title</h2>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<a href="/visitors">Visitors</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Cookies for the home page</h3>
|
||||
$cookies
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
visit_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EWF Handling Visit Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>The number of visits is $visit</h2>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Cookies for the Visit page</h3>
|
||||
$cookies
|
||||
</div>
|
||||
</br>
|
||||
|
||||
<div>
|
||||
Back to <a href="/"> Home </a>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<p>EWF Example Cookies</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
end
|
||||
|
||||
141
doc/workbook/handling_cookies/example/application_execution.e
Normal file
141
doc/workbook/handling_cookies/example/application_execution.e
Normal file
@@ -0,0 +1,141 @@
|
||||
note
|
||||
description : "Basic Service that build a generic front to demonstrate the use of Cookies"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_message: STRING
|
||||
l_header: HTTP_HEADER
|
||||
l_time: HTTP_DATE
|
||||
l_cookies: STRING
|
||||
l_answer: STRING
|
||||
do
|
||||
-- all the cookies
|
||||
create l_cookies.make_empty
|
||||
across request.cookies as ic loop
|
||||
l_cookies.append (ic.item.name)
|
||||
l_cookies.append("<br>")
|
||||
end
|
||||
|
||||
if request.path_info.same_string ("/") then
|
||||
create l_header.make
|
||||
create l_answer.make_from_string (web_page)
|
||||
if request.cookie ("_EWF_Cookie") = Void then
|
||||
-- First access the the home page, find a cookie with specific name `_EWF_Cookie'
|
||||
l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess")
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.day_add (40)
|
||||
l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True)
|
||||
else
|
||||
-- No a new access
|
||||
l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!")
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
end
|
||||
l_header.put_content_type_text_html
|
||||
l_header.put_content_length (l_answer.count)
|
||||
response.put_header_text (l_header.string)
|
||||
response.put_string (l_answer)
|
||||
|
||||
elseif request.path_info.same_string ("/visitors") then
|
||||
create l_header.make
|
||||
create l_answer.make_from_string (visit_page)
|
||||
if request.cookie ("_visits") = Void then
|
||||
-- First access the the visit page, find a cookie with specific name `_visits'
|
||||
l_answer.replace_substring_all ("$visit", "1")
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.day_add (40)
|
||||
l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True)
|
||||
|
||||
else
|
||||
if attached {WSF_STRING} request.cookie ("_visits") as l_visit then
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.day_add (40)
|
||||
l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out )
|
||||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||||
l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True)
|
||||
end
|
||||
end
|
||||
create l_time.make_now_utc
|
||||
l_time.date_time.second_add (120)
|
||||
l_header.put_content_type_text_html
|
||||
-- This cookie expires in 120 seconds, its valid for 120 seconds
|
||||
l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True)
|
||||
-- This is a session cookie, valid only to the current browsing session.
|
||||
l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True)
|
||||
l_header.put_content_length (l_answer.count)
|
||||
response.add_header_text (l_header.string)
|
||||
response.put_string (l_answer)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
feature -- Home Page
|
||||
|
||||
web_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EWF Handling Cookies</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>$header_title</h2>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<a href="/visitors">Visitors</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Cookies for the home page</h3>
|
||||
$cookies
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
visit_page: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EWF Handling Visit Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right">
|
||||
<h2>The number of visits is $visit</h2>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Cookies for the Visit page</h3>
|
||||
$cookies
|
||||
</div>
|
||||
</br>
|
||||
|
||||
<div>
|
||||
Back to <a href="/"> Home </a>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<p>EWF Example Cookies</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that show how to handle a GET request"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,90 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
file: WSF_FILE_RESPONSE
|
||||
l_parameter_names: STRING
|
||||
l_answer: STRING
|
||||
idioms: LIST[STRING]
|
||||
l_raw_data: STRING
|
||||
do
|
||||
if req.is_get_request_method then
|
||||
if req.path_info.same_string ("/") then
|
||||
create file.make_html ("form.html")
|
||||
res.send (file)
|
||||
elseif req.path_info.same_string ("/search") then
|
||||
|
||||
-- (1) the parameter is case sensitive
|
||||
if not (attached req.query_parameter ("GIVEN-NAME")) then
|
||||
-- Wrong `GIVEN-NAME' need to be in lower case.
|
||||
end
|
||||
|
||||
-- (2) Multiple values
|
||||
if attached {WSF_MULTIPLE_STRING} req.query_parameter ("languages") as l_languages then
|
||||
-- Get all the associated values
|
||||
create {ARRAYED_LIST[STRING]} idioms.make (2)
|
||||
across l_languages as ic loop idioms.force (ic.item.value) end
|
||||
elseif attached {WSF_STRING} req.query_parameter ("languages") as l_language then
|
||||
-- Single value
|
||||
print (l_language.value)
|
||||
else
|
||||
-- Value Missing
|
||||
end
|
||||
|
||||
-- Read the all parameters names and his values.
|
||||
create l_parameter_names.make_from_string ("<h2>Parameters Names</h2>")
|
||||
l_parameter_names.append ("<br>")
|
||||
create l_answer.make_from_string ("<h2>Parameter Names and Values</h2>")
|
||||
l_answer.append ("<br>")
|
||||
across req.query_parameters as ic loop
|
||||
l_parameter_names.append (ic.item.key)
|
||||
l_parameter_names.append ("<br>")
|
||||
|
||||
l_answer.append (ic.item.key)
|
||||
l_answer.append_character ('=')
|
||||
if attached {WSF_STRING} req.query_parameter (ic.item.key) as l_value then
|
||||
l_answer.append_string (l_value.value)
|
||||
end
|
||||
l_answer.append ("<br>")
|
||||
end
|
||||
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append_string (l_answer)
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
|
||||
res.put_string (l_parameter_names)
|
||||
elseif req.path_info.same_string ("/link") then
|
||||
-- WSF_TABLE example
|
||||
create l_parameter_names.make_from_string ("<h2>Parameters Name</h2>")
|
||||
if attached {WSF_TABLE} req.query_parameter ("tab") as l_tab then
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append (l_tab.name)
|
||||
|
||||
from
|
||||
l_tab.values.start
|
||||
until
|
||||
l_tab.values.after
|
||||
loop
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append (l_tab.values.key_for_iteration)
|
||||
if attached {WSF_STRING} l_tab.value (l_tab.values.key_for_iteration) as l_value then
|
||||
l_parameter_names.append ("=")
|
||||
l_parameter_names.append (l_value.value)
|
||||
end
|
||||
l_tab.values.forth
|
||||
end
|
||||
l_parameter_names.append ("<br>")
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
|
||||
res.put_string (l_parameter_names)
|
||||
|
||||
end
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
101
doc/workbook/handling_request/form/get/application_execution.e
Normal file
101
doc/workbook/handling_request/form/get/application_execution.e
Normal file
@@ -0,0 +1,101 @@
|
||||
note
|
||||
description : "Basic Service that show how to handle a GET request"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
file: WSF_FILE_RESPONSE
|
||||
l_parameter_names: STRING
|
||||
l_answer: STRING
|
||||
idioms: LIST[STRING]
|
||||
l_raw_data: STRING
|
||||
do
|
||||
if request.is_get_request_method then
|
||||
if request.path_info.same_string ("/") then
|
||||
create file.make_html ("form.html")
|
||||
response.send (file)
|
||||
elseif request.path_info.same_string ("/search") then
|
||||
|
||||
-- (1) the parameter is case sensitive
|
||||
if not (attached request.query_parameter ("GIVEN-NAME")) then
|
||||
-- Wrong `GIVEN-NAME' need to be in lower case.
|
||||
end
|
||||
|
||||
-- (2) Multiple values
|
||||
if attached {WSF_MULTIPLE_STRING} request.query_parameter ("languages") as l_languages then
|
||||
-- Get all the associated values
|
||||
create {ARRAYED_LIST[STRING]} idioms.make (2)
|
||||
across l_languages as ic loop idioms.force (ic.item.value) end
|
||||
elseif attached {WSF_STRING} request.query_parameter ("languages") as l_language then
|
||||
-- Single value
|
||||
print (l_language.value)
|
||||
else
|
||||
-- Value Missing
|
||||
end
|
||||
|
||||
-- Read the all parameters names and his values.
|
||||
create l_parameter_names.make_from_string ("<h2>Parameters Names</h2>")
|
||||
l_parameter_names.append ("<br>")
|
||||
create l_answer.make_from_string ("<h2>Parameter Names and Values</h2>")
|
||||
l_answer.append ("<br>")
|
||||
across request.query_parameters as ic loop
|
||||
l_parameter_names.append (ic.item.key)
|
||||
l_parameter_names.append ("<br>")
|
||||
|
||||
l_answer.append (ic.item.key)
|
||||
l_answer.append_character ('=')
|
||||
if attached {WSF_STRING} request.query_parameter (ic.item.key) as l_value then
|
||||
l_answer.append_string (l_value.value)
|
||||
end
|
||||
l_answer.append ("<br>")
|
||||
end
|
||||
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append_string (l_answer)
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
|
||||
response.put_string (l_parameter_names)
|
||||
elseif request.path_info.same_string ("/link") then
|
||||
-- WSF_TABLE example
|
||||
create l_parameter_names.make_from_string ("<h2>Parameters Name</h2>")
|
||||
if attached {WSF_TABLE} request.query_parameter ("tab") as l_tab then
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append (l_tab.name)
|
||||
|
||||
from
|
||||
l_tab.values.start
|
||||
until
|
||||
l_tab.values.after
|
||||
loop
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append (l_tab.values.key_for_iteration)
|
||||
if attached {WSF_STRING} l_tab.value (l_tab.values.key_for_iteration) as l_value then
|
||||
l_parameter_names.append ("=")
|
||||
l_parameter_names.append (l_value.value)
|
||||
end
|
||||
l_tab.values.forth
|
||||
end
|
||||
l_parameter_names.append ("<br>")
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
|
||||
response.put_string (l_parameter_names)
|
||||
|
||||
end
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Reading Parameters from a HTML FORM (method POST) "
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,72 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
file: WSF_FILE_RESPONSE
|
||||
l_parameter_names: STRING
|
||||
l_answer: STRING
|
||||
idioms: LIST[STRING]
|
||||
l_raw_data: STRING
|
||||
do
|
||||
if req.is_get_request_method then
|
||||
create file.make_html ("form.html")
|
||||
res.send (file)
|
||||
elseif req.is_post_request_method then
|
||||
req.set_raw_input_data_recorded (True)
|
||||
|
||||
-- (3) Read Raw Data
|
||||
create l_raw_data.make_empty
|
||||
req.read_input_data_into (l_raw_data)
|
||||
|
||||
-- (1) the parameter is case sensitive
|
||||
if not (attached req.form_parameter ("GIVEN-NAME")) then
|
||||
-- Wrong `GIVEN-NAME' need to be in lower case.
|
||||
end
|
||||
|
||||
-- (2) Multiple values
|
||||
if attached {WSF_MULTIPLE_STRING} req.form_parameter ("languages") as l_languages then
|
||||
-- Get all the associated values
|
||||
create {ARRAYED_LIST[STRING]} idioms.make (2)
|
||||
across l_languages as ic loop idioms.force (ic.item.value) end
|
||||
elseif attached {WSF_STRING} req.form_parameter ("langauges") as l_language then
|
||||
-- Single value
|
||||
print (l_language.value)
|
||||
else
|
||||
-- Value Missing
|
||||
end
|
||||
|
||||
-- Read the all parameters names and his values.
|
||||
create l_parameter_names.make_from_string ("<h2>Parameters Names</h2>")
|
||||
l_parameter_names.append ("<br>")
|
||||
create l_answer.make_from_string ("<h2>Parameter Names and Values</h2>")
|
||||
l_answer.append ("<br>")
|
||||
|
||||
across req.form_parameters as ic loop
|
||||
l_parameter_names.append (ic.item.key)
|
||||
l_parameter_names.append ("<br>")
|
||||
|
||||
l_answer.append (ic.item.key)
|
||||
l_answer.append_character ('=')
|
||||
if attached {WSF_STRING} req.form_parameter (ic.item.key) as l_value then
|
||||
l_answer.append_string (l_value.value)
|
||||
end
|
||||
l_answer.append ("<br>")
|
||||
end
|
||||
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append_string (l_answer)
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append ("<h2>Raw content</h2>")
|
||||
l_parameter_names.append (l_raw_data)
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
|
||||
res.put_string (l_parameter_names)
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
note
|
||||
description : "Reading Parameters from a HTML FORM (method POST) "
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
file: WSF_FILE_RESPONSE
|
||||
l_parameter_names: STRING
|
||||
l_answer: STRING
|
||||
idioms: LIST[STRING]
|
||||
l_raw_data: STRING
|
||||
do
|
||||
if request.is_get_request_method then
|
||||
create file.make_html ("form.html")
|
||||
response.send (file)
|
||||
elseif request.is_post_request_method then
|
||||
request.set_raw_input_data_recorded (True)
|
||||
|
||||
-- (3) Read Raw Data
|
||||
create l_raw_data.make_empty
|
||||
request.read_input_data_into (l_raw_data)
|
||||
|
||||
-- (1) the parameter is case sensitive
|
||||
if not (attached request.form_parameter ("GIVEN-NAME")) then
|
||||
-- Wrong `GIVEN-NAME' need to be in lower case.
|
||||
end
|
||||
|
||||
-- (2) Multiple values
|
||||
if attached {WSF_MULTIPLE_STRING} request.form_parameter ("languages") as l_languages then
|
||||
-- Get all the associated values
|
||||
create {ARRAYED_LIST[STRING]} idioms.make (2)
|
||||
across l_languages as ic loop idioms.force (ic.item.value) end
|
||||
elseif attached {WSF_STRING} request.form_parameter ("langauges") as l_language then
|
||||
-- Single value
|
||||
print (l_language.value)
|
||||
else
|
||||
-- Value Missing
|
||||
end
|
||||
|
||||
-- Read the all parameters names and his values.
|
||||
create l_parameter_names.make_from_string ("<h2>Parameters Names</h2>")
|
||||
l_parameter_names.append ("<br>")
|
||||
create l_answer.make_from_string ("<h2>Parameter Names and Values</h2>")
|
||||
l_answer.append ("<br>")
|
||||
|
||||
across request.form_parameters as ic loop
|
||||
l_parameter_names.append (ic.item.key)
|
||||
l_parameter_names.append ("<br>")
|
||||
|
||||
l_answer.append (ic.item.key)
|
||||
l_answer.append_character ('=')
|
||||
if attached {WSF_STRING} request.form_parameter (ic.item.key) as l_value then
|
||||
l_answer.append_string (l_value.value)
|
||||
end
|
||||
l_answer.append ("<br>")
|
||||
end
|
||||
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append_string (l_answer)
|
||||
l_parameter_names.append ("<br>")
|
||||
l_parameter_names.append ("<h2>Raw content</h2>")
|
||||
l_parameter_names.append (l_raw_data)
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
|
||||
response.put_string (l_parameter_names)
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,14 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that Read a Request, a "
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
EIS: "name=Browser detection using user agent","src=https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent", "protocol=url"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -22,88 +19,6 @@ feature {NONE} -- Initialization
|
||||
-- Initialize current service.
|
||||
do
|
||||
set_service_option ("port", 9090)
|
||||
set_service_option ("verbose", true)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_raw_data: STRING
|
||||
l_page_response: STRING
|
||||
l_rows: STRING
|
||||
do
|
||||
create l_page_response.make_from_string (html_template)
|
||||
if req.path_info.same_string ("/") then
|
||||
|
||||
-- retrieve the user-agent
|
||||
if attached req.http_user_agent as l_user_agent then
|
||||
l_page_response.replace_substring_all ("$user_agent", l_user_agent)
|
||||
l_page_response.replace_substring_all ("$browser", get_browser_name (l_user_agent))
|
||||
else
|
||||
l_page_response.replace_substring_all ("$user_agent", "[]")
|
||||
l_page_response.replace_substring_all ("$browser", "Unknown, the user-agent was not present.")
|
||||
end
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
|
||||
res.put_string (l_page_response)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Browser utility
|
||||
|
||||
get_browser_name (a_user_agent: READABLE_STRING_8):READABLE_STRING_32
|
||||
-- Must contain Must not contain
|
||||
-- Firefox Firefox/xyz Seamonkey/xyz
|
||||
-- Seamonkey Seamonkey/xyz
|
||||
-- Chrome Chrome/xyz Chromium/xyz
|
||||
-- Chromium Chromium/xyz
|
||||
-- Safari Safari/xyz Chrome/xyz
|
||||
-- Chromium/xyz
|
||||
-- Opera OPR/xyz [1]
|
||||
-- Opera/xyz [2]
|
||||
-- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format
|
||||
|
||||
do
|
||||
if
|
||||
a_user_agent.has_substring ("Firefox") and then
|
||||
not a_user_agent.has_substring ("Seamonkey")
|
||||
then
|
||||
Result := "Firefox"
|
||||
elseif a_user_agent.has_substring ("Seamonkey") then
|
||||
Result := "Seamonkey"
|
||||
elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then
|
||||
Result := "Chrome"
|
||||
elseif a_user_agent.has_substring ("Chromium") then
|
||||
Result := "Chromiun"
|
||||
elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then
|
||||
Result := "Safari"
|
||||
elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then
|
||||
Result := "Opera"
|
||||
elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then
|
||||
Result := "Internet Explorer"
|
||||
else
|
||||
Result := "Unknown"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
html_template: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1> <br>
|
||||
|
||||
<strong>User Agent:</strong> $user_agent <br>
|
||||
|
||||
<h2>Enjoy using $browser </h2>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
note
|
||||
description : "Basic Service that Read a Request, a "
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
EIS: "name=Browser detection using user agent","src=https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent", "protocol=url"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_raw_data: STRING
|
||||
l_page_response: STRING
|
||||
l_rows: STRING
|
||||
do
|
||||
create l_page_response.make_from_string (html_template)
|
||||
if request.path_info.same_string ("/") then
|
||||
|
||||
-- retrieve the user-agent
|
||||
if attached request.http_user_agent as l_user_agent then
|
||||
l_page_response.replace_substring_all ("$user_agent", l_user_agent)
|
||||
l_page_response.replace_substring_all ("$browser", browser_name (l_user_agent))
|
||||
else
|
||||
l_page_response.replace_substring_all ("$user_agent", "[]")
|
||||
l_page_response.replace_substring_all ("$browser", "Unknown, the user-agent was not present.")
|
||||
end
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
|
||||
response.put_string (l_page_response)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Browser utility
|
||||
|
||||
browser_name (a_user_agent: READABLE_STRING_8): STRING_8
|
||||
-- Must contain Must not contain
|
||||
-- Firefox Firefox/xyz Seamonkey/xyz
|
||||
-- Seamonkey Seamonkey/xyz
|
||||
-- Chrome Chrome/xyz Chromium/xyz
|
||||
-- Chromium Chromium/xyz
|
||||
-- Safari Safari/xyz Chrome/xyz
|
||||
-- Chromium/xyz
|
||||
-- Opera OPR/xyz [1]
|
||||
-- Opera/xyz [2]
|
||||
-- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format
|
||||
|
||||
do
|
||||
if
|
||||
a_user_agent.has_substring ("Firefox") and then
|
||||
not a_user_agent.has_substring ("Seamonkey")
|
||||
then
|
||||
Result := "Firefox"
|
||||
elseif a_user_agent.has_substring ("Seamonkey") then
|
||||
Result := "Seamonkey"
|
||||
elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then
|
||||
Result := "Chrome"
|
||||
elseif a_user_agent.has_substring ("Chromium") then
|
||||
Result := "Chromiun"
|
||||
elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then
|
||||
Result := "Safari"
|
||||
elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then
|
||||
Result := "Opera"
|
||||
elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then
|
||||
Result := "Internet Explorer"
|
||||
else
|
||||
Result := "Unknown"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
html_template: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1> <br>
|
||||
|
||||
<strong>User Agent:</strong> $user_agent <br>
|
||||
|
||||
<h2>Enjoy using $browser </h2>
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
@@ -1,14 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that shows the standard CGI variables"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
EIS: "name=CGI specification","src=(https://tools.ietf.org/html/rfc3875", "protocol=url"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -22,294 +19,6 @@ feature {NONE} -- Initialization
|
||||
-- Initialize current service.
|
||||
do
|
||||
set_service_option ("port", 9090)
|
||||
set_service_option ("verbose", true)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_raw_data: STRING
|
||||
l_page_response: STRING
|
||||
l_rows: STRING
|
||||
do
|
||||
create l_page_response.make_from_string (html_template)
|
||||
if req.path_info.same_string ("/") then
|
||||
|
||||
-- HTTP method
|
||||
l_page_response.replace_substring_all ("$http_method", req.request_method)
|
||||
-- URI
|
||||
l_page_response.replace_substring_all ("$uri", req.path_info)
|
||||
-- Protocol
|
||||
l_page_response.replace_substring_all ("$protocol", req.server_protocol)
|
||||
|
||||
-- Fill the table rows with CGI standard variables
|
||||
create l_rows.make_empty
|
||||
|
||||
-- Auth_type
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("AUTH_TYPE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.auth_type as l_type then
|
||||
l_rows.append (l_type)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Content length
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("CONTENT_LENGTH")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.content_length as l_content_length then
|
||||
l_rows.append (l_content_length)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Content length
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("CONTENT_TYPE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.content_type as l_content_type then
|
||||
l_rows.append (l_content_type.string)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Gateway interface
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("GATEWAY_INTERFACE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.gateway_interface as l_gateway_interface then
|
||||
l_rows.append (l_gateway_interface)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Path info
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("PATH_INFO")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.path_info as l_path_info then
|
||||
l_rows.append (l_path_info)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Path translated
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("PATH_TRANSLATED")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.path_translated as l_path_translated then
|
||||
l_rows.append (l_path_translated)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Query string
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("QUERY_STRING")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.query_string as l_query_string then
|
||||
l_rows.append (l_query_string)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Remote addr
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_ADDR")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (req.remote_addr)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Remote host
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_HOST")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.remote_host as l_remote_host then
|
||||
l_rows.append (l_remote_host)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
|
||||
-- Remote ident
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_IDENT")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.remote_ident as l_remote_ident then
|
||||
l_rows.append (l_remote_ident)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Remote user
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_USER")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached req.remote_user as l_remote_user then
|
||||
l_rows.append (l_remote_user)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Request method
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REQUEST_METHOD")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (req.request_method)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Script name
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SCRIPT_NAME")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (req.script_name)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Server name
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SERVER_NAME")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (req.server_name)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Server protocol
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SERVER_PROTOCOL")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (req.server_protocol)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Server software
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SERVER_SOFTWARE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (req.server_software)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
l_page_response.replace_substring_all ("$rows", l_rows)
|
||||
|
||||
-- Reading the raw header
|
||||
if attached req.raw_header_data as l_raw_header then
|
||||
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
|
||||
end
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
|
||||
res.put_string (l_page_response)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
html_template: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
thead {color:green;}
|
||||
tbody {color:blue;}
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EWF service example: Showing Standard CGI Variables</h1>
|
||||
|
||||
<strong>HTTP METHOD:</strong>$http_method<br>
|
||||
<strong>URI:</strong>$uri<br>
|
||||
<strong>PROTOCOL:</strong>$protocol<br>
|
||||
|
||||
<br>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>CGI Name</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
$rows
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Raw header</h2>
|
||||
|
||||
$raw_header
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
note
|
||||
description : "Basic Service that shows the standard CGI variables"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
EIS: "name=CGI specification","src=(https://tools.ietf.org/html/rfc3875", "protocol=url"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_raw_data: STRING
|
||||
l_page_response: STRING
|
||||
l_rows: STRING
|
||||
do
|
||||
create l_page_response.make_from_string (html_template)
|
||||
if request.path_info.same_string ("/") then
|
||||
|
||||
-- HTTP method
|
||||
l_page_response.replace_substring_all ("$http_method", request.request_method)
|
||||
-- URI
|
||||
l_page_response.replace_substring_all ("$uri", request.path_info)
|
||||
-- Protocol
|
||||
l_page_response.replace_substring_all ("$protocol", request.server_protocol)
|
||||
|
||||
-- Fill the table rows with CGI standard variables
|
||||
create l_rows.make_empty
|
||||
|
||||
-- Auth_type
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("AUTH_TYPE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.auth_type as l_type then
|
||||
l_rows.append (l_type)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Content length
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("CONTENT_LENGTH")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.content_length as l_content_length then
|
||||
l_rows.append (l_content_length)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Content length
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("CONTENT_TYPE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.content_type as l_content_type then
|
||||
l_rows.append (l_content_type.string)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Gateway interface
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("GATEWAY_INTERFACE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.gateway_interface as l_gateway_interface then
|
||||
l_rows.append (l_gateway_interface)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Path info
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("PATH_INFO")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.path_info as l_path_info then
|
||||
l_rows.append (l_path_info)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Path translated
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("PATH_TRANSLATED")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.path_translated as l_path_translated then
|
||||
l_rows.append (l_path_translated)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Query string
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("QUERY_STRING")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.query_string as l_query_string then
|
||||
l_rows.append (l_query_string)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Remote addr
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_ADDR")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (request.remote_addr)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Remote host
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_HOST")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.remote_host as l_remote_host then
|
||||
l_rows.append (l_remote_host)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
|
||||
-- Remote ident
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_IDENT")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.remote_ident as l_remote_ident then
|
||||
l_rows.append (l_remote_ident)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Remote user
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REMOTE_USER")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
if attached request.remote_user as l_remote_user then
|
||||
l_rows.append (l_remote_user)
|
||||
else
|
||||
l_rows.append ("Not present")
|
||||
end
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Request method
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("REQUEST_METHOD")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (request.request_method)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
-- Script name
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SCRIPT_NAME")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (request.script_name)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Server name
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SERVER_NAME")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (request.server_name)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Server protocol
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SERVER_PROTOCOL")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (request.server_protocol)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
-- Server software
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append ("SERVER_SOFTWARE")
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (request.server_software)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
|
||||
|
||||
l_page_response.replace_substring_all ("$rows", l_rows)
|
||||
|
||||
-- Reading the raw header
|
||||
if attached request.raw_header_data as l_raw_header then
|
||||
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
|
||||
end
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
|
||||
response.put_string (l_page_response)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
html_template: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
thead {color:green;}
|
||||
tbody {color:blue;}
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EWF service example: Showing Standard CGI Variables</h1>
|
||||
|
||||
<strong>HTTP METHOD:</strong>$http_method<br>
|
||||
<strong>URI:</strong>$uri<br>
|
||||
<strong>PROTOCOL:</strong>$protocol<br>
|
||||
|
||||
<br>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>CGI Name</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
$rows
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Raw header</h2>
|
||||
|
||||
$raw_header
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that Read Request Headers"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -21,97 +19,6 @@ feature {NONE} -- Initialization
|
||||
-- Initialize current service.
|
||||
do
|
||||
set_service_option ("port", 9090)
|
||||
set_service_option ("verbose", true)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_raw_data: STRING
|
||||
l_page_response: STRING
|
||||
l_rows: STRING
|
||||
do
|
||||
create l_page_response.make_from_string (html_template)
|
||||
if req.path_info.same_string ("/") then
|
||||
|
||||
-- HTTP method
|
||||
l_page_response.replace_substring_all ("$http_method", req.request_method)
|
||||
-- URI
|
||||
l_page_response.replace_substring_all ("$uri", req.path_info)
|
||||
-- Protocol
|
||||
l_page_response.replace_substring_all ("$protocol", req.server_protocol)
|
||||
|
||||
-- Fill the table rows with HTTP Headers
|
||||
create l_rows.make_empty
|
||||
across req.meta_variables as ic loop
|
||||
if ic.item.name.starts_with ("HTTP_") then
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (ic.item.name)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (ic.item.value)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
end
|
||||
end
|
||||
|
||||
l_page_response.replace_substring_all ("$rows", l_rows)
|
||||
|
||||
-- Reading the raw header
|
||||
if attached req.raw_header_data as l_raw_header then
|
||||
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
|
||||
end
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
|
||||
res.put_string (l_page_response)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
html_template: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
thead {color:green;}
|
||||
tbody {color:blue;}
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EWF service example: Showing Request Headers</h1>
|
||||
|
||||
<strong>HTTP METHOD:</strong>$http_method<br>
|
||||
<strong>URI:</strong>$uri<br>
|
||||
<strong>PROTOCOL:</strong>$protocol<br>
|
||||
<strong>REQUEST TIME:</strong>$time<br>
|
||||
|
||||
<br>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header Name</th>
|
||||
<th>Header Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
$rows
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Raw header</h2>
|
||||
|
||||
$raw_header
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
note
|
||||
description : "Basic Service that Read Request Headers"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
l_raw_data: STRING
|
||||
l_page_response: STRING
|
||||
l_rows: STRING
|
||||
do
|
||||
create l_page_response.make_from_string (html_template)
|
||||
if request.path_info.same_string ("/") then
|
||||
|
||||
-- HTTP method
|
||||
l_page_response.replace_substring_all ("$http_method", request.request_method)
|
||||
-- URI
|
||||
l_page_response.replace_substring_all ("$uri", request.path_info)
|
||||
-- Protocol
|
||||
l_page_response.replace_substring_all ("$protocol", request.server_protocol)
|
||||
|
||||
-- Fill the table rows with HTTP Headers
|
||||
create l_rows.make_empty
|
||||
across request.meta_variables as ic loop
|
||||
if ic.item.name.starts_with ("HTTP_") then
|
||||
l_rows.append ("<tr>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (ic.item.name)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("<td>")
|
||||
l_rows.append (ic.item.value)
|
||||
l_rows.append ("</td>")
|
||||
l_rows.append ("</tr>")
|
||||
end
|
||||
end
|
||||
|
||||
l_page_response.replace_substring_all ("$rows", l_rows)
|
||||
|
||||
-- Reading the raw header
|
||||
if attached request.raw_header_data as l_raw_header then
|
||||
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
|
||||
end
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
|
||||
response.put_string (l_page_response)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
html_template: STRING = "[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
thead {color:green;}
|
||||
tbody {color:blue;}
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EWF service example: Showing Request Headers</h1>
|
||||
|
||||
<strong>HTTP METHOD:</strong>$http_method<br>
|
||||
<strong>URI:</strong>$uri<br>
|
||||
<strong>PROTOCOL:</strong>$protocol<br>
|
||||
<strong>REQUEST TIME:</strong>$time<br>
|
||||
|
||||
<br>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header Name</th>
|
||||
<th>Header Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
$rows
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Raw header</h2>
|
||||
|
||||
$raw_header
|
||||
</body>
|
||||
</html>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
note
|
||||
description : "Basic Service that show how to Upload a file"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description: "Basic Service launcher"
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,47 +21,4 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the incomming request
|
||||
local
|
||||
file: WSF_FILE_RESPONSE
|
||||
l_answer: STRING
|
||||
do
|
||||
if req.is_get_request_method then
|
||||
if req.path_info.same_string ("/") then
|
||||
create file.make_html ("upload.html")
|
||||
res.send (file)
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
end
|
||||
elseif req.is_post_request_method then
|
||||
if req.path_info.same_string ("/upload") then
|
||||
-- Check if we have an uploaded file
|
||||
if req.has_uploaded_file then
|
||||
-- iterate over all the uploaded files
|
||||
create l_answer.make_from_string ("<h1>Uploaded File/s</h1><br>")
|
||||
across req.uploaded_files as ic loop
|
||||
l_answer.append ("<strong>FileName:</strong>")
|
||||
l_answer.append (ic.item.filename)
|
||||
l_answer.append ("<br><strong>Size:</strong>")
|
||||
l_answer.append (ic.item.size.out)
|
||||
l_answer.append ("<br>")
|
||||
end
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
|
||||
res.put_string (l_answer)
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
create l_answer.make_from_string ("<strong>No uploaded files</strong><br>")
|
||||
create l_answer.append ("Back to <a href='/'>Home</a>")
|
||||
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
|
||||
res.put_string (l_answer)
|
||||
end
|
||||
else
|
||||
-- Handle error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
note
|
||||
description : "Basic Service that show how to Upload a file"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
-- Execute the incomming request
|
||||
local
|
||||
file: WSF_FILE_RESPONSE
|
||||
l_answer: STRING
|
||||
do
|
||||
if request.is_get_request_method then
|
||||
if request.path_info.same_string ("/") then
|
||||
create file.make_html ("upload.html")
|
||||
response.send (file)
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
end
|
||||
elseif request.is_post_request_method then
|
||||
if request.path_info.same_string ("/upload") then
|
||||
-- Check if we have an uploaded file
|
||||
if request.has_uploaded_file then
|
||||
-- iterate over all the uploaded files
|
||||
create l_answer.make_from_string ("<h1>Uploaded File/s</h1><br>")
|
||||
across request.uploaded_files as ic loop
|
||||
l_answer.append ("<strong>FileName:</strong>")
|
||||
l_answer.append (ic.item.filename)
|
||||
l_answer.append ("<br><strong>Size:</strong>")
|
||||
l_answer.append (ic.item.size.out)
|
||||
l_answer.append ("<br>")
|
||||
end
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
|
||||
response.put_string (l_answer)
|
||||
else
|
||||
-- Here we should handle unexpected errors.
|
||||
create l_answer.make_from_string ("<strong>No uploaded files</strong><br>")
|
||||
l_answer.append ("Back to <a href='/'>Home</a>")
|
||||
response.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
|
||||
response.put_string (l_answer)
|
||||
end
|
||||
else
|
||||
-- Handle error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -38,14 +38,14 @@ feature -- Router and Filter
|
||||
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
router.handle ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
router.map (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</target>
|
||||
<target name="debug_any" extends="common">
|
||||
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="cgi" location="..\..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="nino" location="..\..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
|
||||
@@ -28,7 +28,7 @@
|
||||
</target>
|
||||
<target name="debug_standalone" extends="common">
|
||||
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
|
||||
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
|
||||
@@ -45,11 +45,11 @@ feature -- Execution
|
||||
req := request
|
||||
|
||||
create router.make (3)
|
||||
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
|
||||
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
|
||||
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
|
||||
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test), Void)
|
||||
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env), Void)
|
||||
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit), Void)
|
||||
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
|
||||
router.handle ("/files", fs)
|
||||
router.handle ("/files", fs, Void)
|
||||
create sess
|
||||
router.dispatch (req, response, sess)
|
||||
if not sess.dispatched then
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</target>
|
||||
<target name="filter_standalone" extends="common">
|
||||
<root class="FILTER_SERVER" feature="make"/>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="true"/>
|
||||
<cluster name="filter" location="src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -59,7 +59,7 @@ feature {NONE} -- Initialization
|
||||
create l_methods
|
||||
l_methods.enable_options
|
||||
l_methods.enable_get
|
||||
router.handle_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
|
||||
router.handle ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
|
||||
end
|
||||
|
||||
initialize_json
|
||||
|
||||
35
examples/obsolete/v0/filter/filter-safe.ecf
Normal file
35
examples/obsolete/v0/filter/filter-safe.ecf
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="filter" uuid="52FF4B77-0614-4D8B-9B96-C07EC852793E" library_target="filter">
|
||||
<target name="common">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<debug name="nino" enabled="true"/>
|
||||
<assertions precondition="true" postcondition="true" invariant="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="true"/>
|
||||
<library name="http" location="../../../../library/network/protocol/http/http-safe.ecf" readonly="true"/>
|
||||
<library name="json" location="..\..\..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="true"/>
|
||||
<library name="wsf" location="..\..\..\..\library\server\obsolete\v0\wsf\wsf-safe.ecf" readonly="true"/>
|
||||
<library name="wsf_router_context" location="..\..\..\..\library\server\obsolete\v0\wsf\wsf_router_context-safe.ecf" readonly="true"/>
|
||||
<library name="wsf_extension" location="..\..\..\..\library\server\obsolete\v0\wsf\wsf_extension-safe.ecf" readonly="true"/>
|
||||
<library name="http_authorization" location="..\..\..\..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="true"/>
|
||||
</target>
|
||||
<target name="filter_nino" extends="common">
|
||||
<root class="FILTER_SERVER" feature="make"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\obsolete\v0\wsf\default\nino-safe.ecf" readonly="true"/>
|
||||
<cluster name="filter" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="filter_fcgi" extends="common">
|
||||
<root class="FILTER_SERVER" feature="make"/>
|
||||
<library name="default_libfcgi" location="..\..\..\..\library\server\obsolete\v0\wsf\default\libfcgi-safe.ecf"/>
|
||||
<cluster name="filter" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="filter" extends="filter_nino">
|
||||
</target>
|
||||
</system>
|
||||
6
examples/obsolete/v0/filter/filter.rc
Normal file
6
examples/obsolete/v0/filter/filter.rc
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <windows.h>
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
1 "This Program was made using EiffelStudio using Visual Studio C++"
|
||||
END
|
||||
4
examples/obsolete/v0/filter/license.lic
Normal file
4
examples/obsolete/v0/filter/license.lic
Normal file
@@ -0,0 +1,4 @@
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "2011-${YEAR}, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
4
examples/obsolete/v0/filter/readme.md
Normal file
4
examples/obsolete/v0/filter/readme.md
Normal file
@@ -0,0 +1,4 @@
|
||||
Filter example
|
||||
|
||||
To test the example, you can just run in a terminal:
|
||||
> curl -u foo:bar http://localhost:9090/user/1 -v
|
||||
57
examples/obsolete/v0/filter/src/database/database_api.e
Normal file
57
examples/obsolete/v0/filter/src/database/database_api.e
Normal file
@@ -0,0 +1,57 @@
|
||||
note
|
||||
description: "Summary description for {DATABASE_API}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DATABASE_API
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make
|
||||
local
|
||||
l_user: USER
|
||||
do
|
||||
create users.make (10)
|
||||
create l_user.make (1, "foo", "bar")
|
||||
users.put (l_user, l_user.id)
|
||||
create l_user.make (2, "demo", "demo")
|
||||
users.put (l_user, l_user.id)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
user (a_id: INTEGER; a_name: detachable READABLE_STRING_GENERAL): detachable USER
|
||||
-- User with id `a_id' or name `a_name'.
|
||||
require
|
||||
a_id > 0 xor a_name /= Void
|
||||
local
|
||||
n: like {USER}.name
|
||||
do
|
||||
if a_id > 0 then
|
||||
Result := users.item (a_id)
|
||||
elseif a_name /= Void then
|
||||
n := a_name.as_string_8
|
||||
across
|
||||
users as c
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
if attached c.item as u and then u.name.same_string (n) then
|
||||
Result := u
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
Result /= Void implies ((a_id > 0 and then Result.id = a_id) xor (a_name /= Void and then Result.name.same_string_general (a_name)))
|
||||
end
|
||||
|
||||
users: HASH_TABLE [USER, INTEGER]
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
note
|
||||
description: "Summary description for {SHARED_DATABASE_API}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SHARED_DATABASE_API
|
||||
|
||||
feature -- Access
|
||||
|
||||
db_access: DATABASE_API
|
||||
once
|
||||
create Result.make
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
52
examples/obsolete/v0/filter/src/domain/json_user_converter.e
Normal file
52
examples/obsolete/v0/filter/src/domain/json_user_converter.e
Normal file
@@ -0,0 +1,52 @@
|
||||
note
|
||||
description: "JSON user converter."
|
||||
author: "Olivier Ligot"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
JSON_USER_CONVERTER
|
||||
|
||||
inherit
|
||||
JSON_CONVERTER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
create object.make (0, "", "")
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
object: USER
|
||||
|
||||
value: detachable JSON_OBJECT
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
from_json (j: attached like value): detachable like object
|
||||
-- Convert from JSON value.
|
||||
do
|
||||
end
|
||||
|
||||
to_json (o: like object): like value
|
||||
-- Convert to JSON value.
|
||||
do
|
||||
create Result.make
|
||||
Result.put (json.value (o.id), id_key)
|
||||
Result.put (json.value (o.name), name_key)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
id_key: STRING = "id"
|
||||
name_key: STRING = "name"
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
59
examples/obsolete/v0/filter/src/domain/user.e
Normal file
59
examples/obsolete/v0/filter/src/domain/user.e
Normal file
@@ -0,0 +1,59 @@
|
||||
note
|
||||
description: "User."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
USER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
redefine
|
||||
is_equal
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (an_id: INTEGER; a_name, a_password: STRING)
|
||||
do
|
||||
id := an_id
|
||||
name := a_name
|
||||
password := a_password
|
||||
ensure
|
||||
id_set: id = an_id
|
||||
name_set: name = a_name
|
||||
password_set: password = a_password
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
id: INTEGER
|
||||
-- Identifier
|
||||
|
||||
name: STRING
|
||||
-- Name
|
||||
|
||||
password: STRING
|
||||
-- Password
|
||||
|
||||
feature -- Comparison
|
||||
|
||||
is_equal (other: like Current): BOOLEAN
|
||||
-- Is `other' attached to an object considered
|
||||
-- equal to current object?
|
||||
do
|
||||
if Current = other then
|
||||
Result := True
|
||||
else
|
||||
Result := (id = other.id) and (name = other.name) and (password = other.password)
|
||||
end
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
note
|
||||
description: "Authentication filter."
|
||||
author: "Olivier Ligot"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
AUTHENTICATION_FILTER
|
||||
|
||||
inherit
|
||||
WSF_FILTER
|
||||
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
SHARED_DATABASE_API
|
||||
|
||||
SHARED_EJSON
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the filter
|
||||
local
|
||||
l_auth: detachable HTTP_AUTHORIZATION
|
||||
do
|
||||
if attached req.http_authorization as l_http_authorization then
|
||||
create l_auth.make (l_http_authorization)
|
||||
end
|
||||
if
|
||||
l_auth /= Void and then
|
||||
l_auth.is_basic and then
|
||||
attached l_auth.login as l_auth_login and then
|
||||
attached Db_access.user (0, l_auth_login) as l_user and then
|
||||
l_auth_login.same_string (l_user.name) and then
|
||||
attached l_auth.password as l_auth_password and then
|
||||
l_auth_password.same_string (l_user.password)
|
||||
then
|
||||
req.set_execution_variable ("user", l_user)
|
||||
execute_next (req, res)
|
||||
else
|
||||
handle_unauthorized ("Unauthorized", req, res)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
handle_unauthorized (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Handle forbidden.
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_text_plain
|
||||
h.put_content_length (a_description.count)
|
||||
h.put_current_date
|
||||
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"User%"")
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (a_description)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
note
|
||||
description: "Summary description for {FILTER_HANDLER_CONTEXT}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
FILTER_HANDLER_CONTEXT
|
||||
|
||||
inherit
|
||||
WSF_HANDLER_CONTEXT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Access
|
||||
|
||||
user: detachable USER
|
||||
-- Authenticated user
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_user (a_user: USER)
|
||||
-- Set `user' to `a_user'
|
||||
do
|
||||
user := a_user
|
||||
ensure
|
||||
user_set: user = a_user
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
111
examples/obsolete/v0/filter/src/filter_server.e
Normal file
111
examples/obsolete/v0/filter/src/filter_server.e
Normal file
@@ -0,0 +1,111 @@
|
||||
note
|
||||
description : "Filter example."
|
||||
author : "Olivier Ligot"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
FILTER_SERVER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
|
||||
WSF_ROUTED_SERVICE
|
||||
undefine
|
||||
execute
|
||||
end
|
||||
|
||||
WSF_FILTERED_SERVICE
|
||||
|
||||
SHARED_EJSON
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
local
|
||||
l_message: STRING
|
||||
l_factory: INET_ADDRESS_FACTORY
|
||||
do
|
||||
initialize_router
|
||||
initialize_filter
|
||||
initialize_json
|
||||
set_service_option ("port", port)
|
||||
create l_message.make_empty
|
||||
l_message.append_string ("Launching filter server at ")
|
||||
create l_factory
|
||||
l_message.append_string (l_factory.create_localhost.host_name)
|
||||
l_message.append_string (" port ")
|
||||
l_message.append_integer (port)
|
||||
io.put_string (l_message)
|
||||
io.put_new_line
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
do
|
||||
create {WSF_CORS_FILTER} filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
local
|
||||
l_routing_filter: WSF_ROUTING_FILTER
|
||||
l_logging_filter: WSF_LOGGING_FILTER
|
||||
do
|
||||
create l_routing_filter.make (router)
|
||||
l_routing_filter.set_execute_default_action (agent execute_default)
|
||||
filter.set_next (l_routing_filter)
|
||||
|
||||
create l_logging_filter
|
||||
l_routing_filter.set_next (l_logging_filter)
|
||||
end
|
||||
|
||||
setup_router
|
||||
-- Setup `router'
|
||||
local
|
||||
l_options_filter: WSF_CORS_OPTIONS_FILTER
|
||||
l_authentication_filter: AUTHENTICATION_FILTER
|
||||
l_user_filter: USER_HANDLER
|
||||
l_methods: WSF_REQUEST_METHODS
|
||||
do
|
||||
create l_options_filter.make (router)
|
||||
create l_authentication_filter
|
||||
create l_user_filter
|
||||
|
||||
l_options_filter.set_next (l_authentication_filter)
|
||||
l_authentication_filter.set_next (l_user_filter)
|
||||
|
||||
create l_methods
|
||||
l_methods.enable_options
|
||||
l_methods.enable_get
|
||||
router.handle_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
|
||||
end
|
||||
|
||||
initialize_json
|
||||
-- Initialize `json'.
|
||||
do
|
||||
json.add_converter (create {JSON_USER_CONVERTER}.make)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
port: INTEGER = 9090
|
||||
-- Port number
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat 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
|
||||
97
examples/obsolete/v0/filter/src/resource/user_handler.e
Normal file
97
examples/obsolete/v0/filter/src/resource/user_handler.e
Normal file
@@ -0,0 +1,97 @@
|
||||
note
|
||||
description: "User handler."
|
||||
author: "Olivier Ligot"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
USER_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_FILTER
|
||||
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
WSF_RESOURCE_HANDLER_HELPER
|
||||
redefine
|
||||
do_get
|
||||
end
|
||||
|
||||
SHARED_DATABASE_API
|
||||
|
||||
SHARED_EJSON
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
do
|
||||
execute_methods (req, res)
|
||||
execute_next (req, res)
|
||||
end
|
||||
|
||||
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Using GET to retrieve resource information.
|
||||
-- If the GET request is SUCCESS, we response with
|
||||
-- 200 OK, and a representation of the user
|
||||
-- If the GET request is not SUCCESS, we response with
|
||||
-- 404 Resource not found
|
||||
require else
|
||||
authenticated_user_attached: attached {USER} req.execution_variable ("user")
|
||||
local
|
||||
id : STRING
|
||||
do
|
||||
if attached req.orig_path_info as orig_path then
|
||||
id := get_user_id_from_path (orig_path)
|
||||
if attached retrieve_user (id) as l_user then
|
||||
if l_user ~ req.execution_variable ("user") then
|
||||
compute_response_get (req, res, l_user)
|
||||
elseif attached {USER} req.execution_variable ("user") as l_auth_user then
|
||||
-- Trying to access another user that the authenticated one,
|
||||
-- which is forbidden in this example...
|
||||
handle_forbidden ("You try to access the user " + id.out + " while authenticating with the user " + l_auth_user.id.out, req, res)
|
||||
end
|
||||
else
|
||||
handle_resource_not_found_response ("The following resource " + orig_path + " is not found ", req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
compute_response_get (req: WSF_REQUEST; res: WSF_RESPONSE; l_user : USER)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
l_msg : STRING
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_application_json
|
||||
if attached {JSON_VALUE} json.value (l_user) as jv then
|
||||
l_msg := jv.representation
|
||||
h.put_content_length (l_msg.count)
|
||||
if attached req.request_time as time then
|
||||
h.put_utc_date (time)
|
||||
end
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (l_msg)
|
||||
end
|
||||
end
|
||||
|
||||
get_user_id_from_path (a_path: READABLE_STRING_32): STRING
|
||||
do
|
||||
Result := a_path.split ('/').at (3)
|
||||
end
|
||||
|
||||
retrieve_user (id: STRING) : detachable USER
|
||||
-- Retrieve the user by id if it exist, in other case, Void
|
||||
do
|
||||
if id.is_integer and then Db_access.users.has (id.to_integer) then
|
||||
Result := db_access.users.item (id.to_integer)
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
The current example has a main target for the server: "restbucks"
|
||||
But we also provide "policy_driven_restbucks" target which is using the
|
||||
policy-driven framework than help coder fulfill HTTP expectations.
|
||||
11
examples/obsolete/v0/restbucksCRUD/client/README.txt
Normal file
11
examples/obsolete/v0/restbucksCRUD/client/README.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Make sure to have the Clib generated in the related cURL library
|
||||
|
||||
- if you use EiffelStudio >= 7.0
|
||||
check %ISE_LIBRARY%\library\cURL\spec\%ISE_C_COMPILER%\$ISE_PLATFORM
|
||||
or $ISE_LIBRARY/library/cURL/spec/$ISE_PLATFORM
|
||||
|
||||
- otherwise if you use earlier version
|
||||
check under ext/ise_library/curl/spec/...
|
||||
|
||||
And on Windows, be sure to get the libcurl.dll from %ISE_LIBRARY%\studio\spec\%ISE_PLATFORM%\bin\libcurl.dll
|
||||
|
||||
19
examples/obsolete/v0/restbucksCRUD/client/client-safe.ecf
Normal file
19
examples/obsolete/v0/restbucksCRUD/client/client-safe.ecf
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="client" uuid="D0059CEB-5F5C-4D21-8C71-842BD0F88468" library_target="client">
|
||||
<target name="client">
|
||||
<root class="RESTBUCK_CLIENT" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="http_client" location="..\..\..\..\..\library\network\http_client\http_client-safe.ecf" readonly="false"/>
|
||||
<library name="json" location="..\..\..\..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
19
examples/obsolete/v0/restbucksCRUD/client/client.ecf
Normal file
19
examples/obsolete/v0/restbucksCRUD/client/client.ecf
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="client" uuid="D0059CEB-5F5C-4D21-8C71-842BD0F88468">
|
||||
<target name="client">
|
||||
<root class="RESTBUCK_CLIENT" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="http_client" location="../../../../../library/network/http_client/http_client.ecf"/>
|
||||
<library name="json" location="..\..\..\..\..\contrib\library\text\parser\json\library\json.ecf" readonly="false"/>
|
||||
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
|
||||
<library name="thread" location="$ISE_LIBRARY/library/thread/thread.ecf"/>
|
||||
<cluster name="src" location="./src" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
6
examples/obsolete/v0/restbucksCRUD/client/client.rc
Normal file
6
examples/obsolete/v0/restbucksCRUD/client/client.rc
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <windows.h>
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
1 "This Program was made using EiffelStudio using Visual Studio C++"
|
||||
END
|
||||
154
examples/obsolete/v0/restbucksCRUD/client/src/restbuck_client.e
Normal file
154
examples/obsolete/v0/restbucksCRUD/client/src/restbuck_client.e
Normal file
@@ -0,0 +1,154 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
RESTBUCK_CLIENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
local
|
||||
h: LIBCURL_HTTP_CLIENT
|
||||
sess: HTTP_CLIENT_SESSION
|
||||
resp : detachable HTTP_CLIENT_RESPONSE
|
||||
l_location : detachable READABLE_STRING_8
|
||||
body : STRING
|
||||
do
|
||||
create h.make
|
||||
sess := h.new_session ("http://127.0.0.1:9090")
|
||||
-- Uncomment the following 2 lines, if you use fiddler2 web debugging tool
|
||||
-- sess.set_is_debug (True)
|
||||
-- sess.set_proxy ("127.0.0.1", 8888)
|
||||
|
||||
-- Create Order
|
||||
print ("%N Create Order %N")
|
||||
resp := create_order (sess)
|
||||
|
||||
|
||||
-- Read the Order
|
||||
print ("%N Read Order %N")
|
||||
l_location := resp.header ("Location")
|
||||
resp := read_order (sess, l_location)
|
||||
|
||||
|
||||
-- Update the Order
|
||||
if resp /= Void and then attached resp.body as l_body then
|
||||
body := l_body.as_string_8
|
||||
body.replace_substring_all ("takeAway", "in Shop")
|
||||
print ("%N Update Order %N")
|
||||
resp := update_order (sess, l_location, body)
|
||||
end
|
||||
end
|
||||
|
||||
update_order ( sess: HTTP_CLIENT_SESSION; uri : detachable READABLE_STRING_8; a_body : STRING): detachable HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
context : HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
if attached uri as l_uri then
|
||||
sess.set_base_url (l_uri)
|
||||
create context.make
|
||||
context.headers.put ("application/json", "Content-Type")
|
||||
Result := sess.put ("", context, a_body )
|
||||
-- Show headers
|
||||
across
|
||||
Result.headers as l_headers
|
||||
loop
|
||||
print (l_headers.item.name)
|
||||
print (":")
|
||||
print (l_headers.item.value)
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
-- Show body
|
||||
print (Result.body)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
read_order ( sess: HTTP_CLIENT_SESSION; uri : detachable READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE
|
||||
do
|
||||
if attached uri as l_uri then
|
||||
sess.set_base_url (l_uri)
|
||||
Result := sess.get ("", Void)
|
||||
-- Show headers
|
||||
across
|
||||
Result.headers as l_headers
|
||||
loop
|
||||
print (l_headers.item.name)
|
||||
print (":")
|
||||
print (l_headers.item.value)
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
-- Show body
|
||||
print (Result.body)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
create_order (sess: HTTP_CLIENT_SESSION) : HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
s: READABLE_STRING_8
|
||||
j: JSON_PARSER
|
||||
id: detachable STRING
|
||||
context : HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
s := "[
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]"
|
||||
|
||||
create context.make
|
||||
context.headers.put ("application/json", "Content-Type")
|
||||
Result := sess.post ("/order", context, s)
|
||||
-- Show the Headers
|
||||
across
|
||||
Result.headers as l_headers
|
||||
loop
|
||||
print (l_headers.item.name)
|
||||
print (":")
|
||||
print (l_headers.item.value)
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
|
||||
-- Show the Response body
|
||||
if attached Result.body as m then
|
||||
create j.make_with_string (m)
|
||||
j.parse_content
|
||||
if j.is_valid and then attached j.parsed_json_object as j_o then
|
||||
if attached {JSON_STRING} j_o.item ("id") as l_id then
|
||||
id := l_id.item
|
||||
end
|
||||
print (m)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
invariant
|
||||
-- invariant_clause: True
|
||||
|
||||
end
|
||||
4
examples/obsolete/v0/restbucksCRUD/license.lic
Normal file
4
examples/obsolete/v0/restbucksCRUD/license.lic
Normal file
@@ -0,0 +1,4 @@
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "2011-${YEAR}, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
297
examples/obsolete/v0/restbucksCRUD/readme.md
Normal file
297
examples/obsolete/v0/restbucksCRUD/readme.md
Normal file
@@ -0,0 +1,297 @@
|
||||
Restbuck Eiffel Implementation based on the book of REST in Practice
|
||||
====================================================================
|
||||
This is an implementation of CRUD pattern for manipulate resources, this is the first step to use
|
||||
the HTTP protocol as an application protocol instead of a transport protocol.
|
||||
|
||||
Restbuck Protocol
|
||||
-----------------
|
||||
|
||||
<table>
|
||||
<TR><TH>Verb</TH> <TH>URI or template</TH> <TH>Use</TH></TR>
|
||||
<TR><TD>POST</TD> <TD>/order</TD> <TD>Create a new order, and upon success, receive a Locationheader specifying the new order's URI.</TD></TR>
|
||||
<TR><TD>GET</TD> <TD>/order/{orderId}</TD> <TD>Request the current state of the order specified by the URI.</TD></TR>
|
||||
<TR><TD>PUT</TD> <TD>/order/{orderId}</TD> <TD>Update an order at the given URI with new information, providing the full representation.</TD></TR>
|
||||
<TR><TD>DELETE</TD> <TD>/order/{orderId}</TD> <TD>Logically remove the order identified by the given URI.</TD></TR>
|
||||
</table>
|
||||
|
||||
Resource Represenation
|
||||
----------------------
|
||||
The previous tables shows a contrat, the URI or URI template, allows us to indentify resources, now we will chose a
|
||||
representacion, for this particular case we will use JSON.
|
||||
|
||||
Note: <br/>
|
||||
1. *A resource can have multiple URIs*.<br/>
|
||||
2. *A resource can have multiple Representations*.<br/>
|
||||
|
||||
RESTBUCKS_SERVER
|
||||
----------------
|
||||
This class implement the main entry of our REST CRUD service, we are using a default connector (Nino Connector,
|
||||
using a WebServer written in Eiffel).
|
||||
We are inheriting from URI_TEMPLATE_ROUTED_SERVICE, this allows us to map our service contrat, as is shown in the previous
|
||||
table, the mapping is defined in the feature setup_router, this also show that the class ORDER_HANDLER will be encharge
|
||||
of to handle different type of request to the ORDER resource.
|
||||
|
||||
|
||||
class
|
||||
RESTBUCKS_SERVER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
URI_TEMPLATE_ROUTED_SERVICE
|
||||
|
||||
DEFAULT_SERVICE
|
||||
-- Here we are using a default connector using the default Nino Connector,
|
||||
-- but it's possible to use other connector (CGI or FCGI).
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize the router (this will have the request handler and
|
||||
-- their context).
|
||||
do
|
||||
initialize_router
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
create_router
|
||||
do
|
||||
create router.make (2)
|
||||
end
|
||||
|
||||
setup_router
|
||||
local
|
||||
order_handler: ORDER_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
create order_handler
|
||||
router.map_with_request_methods ("/order", order_handler, <<"POST">>)
|
||||
router.map_with_request_methods ("/order/{orderid}", order_handler, <<"GET", "DELETE", "PUT">>)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- I'm using this method to handle the method not allowed response
|
||||
-- in the case that the given uri does not have a corresponding http method
|
||||
-- to handle it.
|
||||
local
|
||||
h : HTTP_HEADER
|
||||
l_description : STRING
|
||||
l_api_doc : STRING
|
||||
do
|
||||
if req.content_length_value > 0 then
|
||||
req.input.read_string (req.content_length_value.as_integer_32)
|
||||
end
|
||||
create h.make
|
||||
h.put_status ({HTTP_STATUS_CODE}.method_not_allowed)
|
||||
h.put_content_type_text_plain
|
||||
l_api_doc := "%NPlease check the API%NURI:/order METHOD: POST%NURI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
|
||||
l_description := req.request_method + req.request_uri + " is not allowed" + "%N" + l_api_doc
|
||||
h.put_content_length (l_description.count)
|
||||
h.put_current_date
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
|
||||
res.write_header_text (h.string)
|
||||
res.write_string (l_description)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
How to Create an order with POST
|
||||
--------------------------------
|
||||
|
||||
Here is the convention that we are using:
|
||||
POST is used for creation and the server determines the URI of the created resource.
|
||||
If the request POST is SUCCESS, the server will create the order and will response with
|
||||
201 CREATED, the Location header will contains the newly created order's URI,
|
||||
if the request POST is not SUCCESS, the server will response with
|
||||
400 BAD REQUEST, the client send a bad request or
|
||||
500 INTERNAL_SERVER_ERROR, when the server can deliver the request.
|
||||
|
||||
POST /order HTTP/1.1
|
||||
Host: 127.0.0.1:8080
|
||||
Connection: keep-alive
|
||||
Content-Length: 196
|
||||
Origin: chrome-extension://fhjcajmcbmldlhcimfajhfbgofnpcjmb
|
||||
Content-Type: application/json
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip,deflate,sdch
|
||||
Accept-Language: es-419,es;q=0.8,en;q=0.6
|
||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
|
||||
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response success
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Status 201 Created
|
||||
Content-Type application/json
|
||||
Content-Length 123
|
||||
Location http://localhost:8080/order/1
|
||||
Date FRI,09 DEC 2011 20:34:20.00 GMT
|
||||
|
||||
{
|
||||
"location" : "takeAway",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
note:
|
||||
curl -vv http://localhost:9090/order -H "Content-Type: application/json" -d "{\"location\":\"takeAway\",\"items\":[{\"name\":\"Late\",\"option\":\"skim\",\"size\":\"Small\",\"quantity\":1}]}" -X POST
|
||||
|
||||
|
||||
How to Read an order with GET
|
||||
-----------------------------
|
||||
Using GET to retrieve resource information.
|
||||
If the GET request is SUCCESS, we response with 200 OK, and a representation of the order
|
||||
If the GET request is not SUCCESS, we response with 404 Resource not found
|
||||
If is a Conditional GET and the resource does not change we send a 304, Resource not modifed
|
||||
|
||||
GET /order/1 HTTP/1.1
|
||||
Host: 127.0.0.1:8080
|
||||
Connection: keep-alive
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip,deflate,sdch
|
||||
Accept-Language: es-419,es;q=0.8,en;q=0.6
|
||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
|
||||
If-None-Match: 6542EF270D91D3EAF39CFB382E4CEBA7
|
||||
|
||||
Response
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
Status 200 OK
|
||||
Content-Type application/json
|
||||
Content-Length 123
|
||||
Date FRI,09 DEC 2011 20:53:46.00 GMT
|
||||
etag 2ED3A40954A95D766FC155682DC8BB52
|
||||
|
||||
{
|
||||
"location" : "takeAway",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
note:
|
||||
curl -vv http://localhost:9090/order/1
|
||||
|
||||
How to Update an order with PUT
|
||||
-------------------------------
|
||||
A successful PUT request will not create a new resource, instead it will change the state of the resource identified by the current uri.
|
||||
If success we response with 200 and the updated order.
|
||||
404 if the order is not found
|
||||
400 in case of a bad request
|
||||
500 internal server error
|
||||
If the request is a Conditional PUT, and it does not mat we response 415, precondition failed.
|
||||
|
||||
Suposse that we had created an Order with the values shown in the _How to create an order with POST_
|
||||
But we change our decision and we want to stay in the shop.
|
||||
|
||||
|
||||
|
||||
PUT /order/1 HTTP/1.1
|
||||
Content-Length: 122
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
Expect: 100-Continue
|
||||
|
||||
{
|
||||
"location" : "in shop",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
|
||||
Response success
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Status 200 OK
|
||||
Content-Type application/json
|
||||
Date FRI,09 DEC 2011 21:06:26.00 GMT
|
||||
etag 8767F900674B843E1F3F70BCF3E62403
|
||||
Content-Length 122
|
||||
|
||||
{
|
||||
"location" : "in shop",
|
||||
"status" : "submitted",
|
||||
"items" : [ {
|
||||
"name" : "late",
|
||||
"size" : "small",
|
||||
"quantity" : 1,
|
||||
"option" : "skim"
|
||||
} ]
|
||||
}
|
||||
|
||||
How to Delete an order with DELETE
|
||||
----------------------------------
|
||||
Here we use DELETE to cancel an order, if that order is in state where it can still be canceled.
|
||||
204 if is ok
|
||||
404 Resource not found
|
||||
405 if consumer and service's view of the resouce state is inconsisent
|
||||
500 if we have an internal server error
|
||||
|
||||
|
||||
DELETE /order/1 HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
|
||||
Response success
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
|
||||
Status 204 No Content
|
||||
Content-Type application/json
|
||||
Date FRI,09 DEC 2011 21:10:51.00 GMT
|
||||
|
||||
If we want to check that the resource does not exist anymore we can try to retrieve a GET /order/1 and we will receive a
|
||||
404 No Found
|
||||
|
||||
GET /order/1 HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
|
||||
Response
|
||||
|
||||
HTTP/1.1 404 Not Found
|
||||
|
||||
Status 404 Not Found
|
||||
Content-Type application/json
|
||||
Content-Length 44
|
||||
Date FRI,09 DEC 2011 21:14:17.79 GMT
|
||||
|
||||
The following resource/order/1 is not found
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
1. [How to get a cup of coffe](http://www.infoq.com/articles/webber-rest-workflow)
|
||||
2. [Rest in Practice] (http://restinpractice.com/default.aspx)
|
||||
0
examples/obsolete/v0/restbucksCRUD/readme.txt
Normal file
0
examples/obsolete/v0/restbucksCRUD/readme.txt
Normal file
55
examples/obsolete/v0/restbucksCRUD/restbucks-safe.ecf
Normal file
55
examples/obsolete/v0/restbucksCRUD/restbucks-safe.ecf
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
|
||||
<target name="restbucks_common">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option full_class_checking="false" void_safety="all">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_nino" location="..\..\..\..\library\server\obsolete\v0\ewsgi\connectors\nino\nino-safe.ecf" readonly="false">
|
||||
<option debug="true">
|
||||
<debug name="nino" enabled="true"/>
|
||||
</option>
|
||||
</library>
|
||||
<library name="conneg" location="..\..\..\..\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\obsolete\v0\wsf\default\nino-safe.ecf" readonly="false"/>
|
||||
<library name="encoder" location="..\..\..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="json" location="..\..\..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||
<library name="uri_template" location="..\..\..\..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\..\..\..\library\server\obsolete\v0\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_extension" location="..\..\..\..\library\server\obsolete\v0\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<target name="restbucks" extends="restbucks_common">
|
||||
<root class="RESTBUCKS_SERVER" feature="make"/>
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
|
||||
<debug name="nino" enabled="true"/>
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/policy_driven_resource$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
<target name="policy_driven_restbucks" extends="restbucks_common">
|
||||
<root class="RESTBUCKS_SERVER" feature="make"/>
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
|
||||
<debug name="nino" enabled="true"/>
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="wsf_policy_driven" location="..\..\..\..\library\server\obsolete\v0\wsf\wsf_policy_driven-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/resource$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
6
examples/obsolete/v0/restbucksCRUD/restbucks.rc
Normal file
6
examples/obsolete/v0/restbucksCRUD/restbucks.rc
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <windows.h>
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
1 "This Program was made using EiffelStudio using Visual Studio C++"
|
||||
END
|
||||
@@ -0,0 +1,26 @@
|
||||
note
|
||||
description: "Summary description for {DATABASE_API}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DATABASE_API
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
create orders.make (10)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
orders: HASH_TABLE [ORDER, STRING]
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
note
|
||||
description: "Summary description for {SHARED_DATABASE_API}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SHARED_DATABASE_API
|
||||
|
||||
feature -- Access
|
||||
|
||||
db_access: DATABASE_API
|
||||
once
|
||||
create Result.make
|
||||
end
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
90
examples/obsolete/v0/restbucksCRUD/src/domain/item.e
Normal file
90
examples/obsolete/v0/restbucksCRUD/src/domain/item.e
Normal file
@@ -0,0 +1,90 @@
|
||||
note
|
||||
description: "Summary description for {ITEM}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ITEM
|
||||
inherit
|
||||
ITEM_CONSTANTS
|
||||
create
|
||||
make
|
||||
feature -- Initialization
|
||||
make ( a_name : STRING_32 ; a_size:STRING_32; a_option: STRING_32; a_quantity:INTEGER_8)
|
||||
do
|
||||
set_name (a_name)
|
||||
set_size (a_size)
|
||||
set_option (a_option)
|
||||
set_quantity (a_quantity)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
name : STRING
|
||||
-- product name type of Coffee(Late, Cappuccino, Expresso)
|
||||
|
||||
option : STRING
|
||||
-- customization option Milk (skim, semi, whole)
|
||||
|
||||
size : STRING
|
||||
-- small, mediumm large
|
||||
|
||||
quantity :INTEGER
|
||||
|
||||
|
||||
|
||||
|
||||
feature -- Element Change
|
||||
set_name (a_name: STRING)
|
||||
require
|
||||
valid_name: is_valid_coffee_type (a_name)
|
||||
do
|
||||
name := a_name
|
||||
ensure
|
||||
name_assigned : name.same_string(a_name)
|
||||
end
|
||||
|
||||
set_size (a_size: STRING)
|
||||
require
|
||||
valid_size : is_valid_size_option (a_size)
|
||||
do
|
||||
size := a_size
|
||||
ensure
|
||||
size_assigned : size.same_string(a_size)
|
||||
end
|
||||
|
||||
set_option (an_option: STRING)
|
||||
require
|
||||
valid_option : is_valid_milk_type (an_option)
|
||||
do
|
||||
option := an_option
|
||||
ensure
|
||||
option_assigned : option.same_string (an_option)
|
||||
end
|
||||
|
||||
set_quantity (a_quantity: INTEGER)
|
||||
require
|
||||
valid_quantity : a_quantity > 0
|
||||
do
|
||||
quantity := a_quantity
|
||||
ensure
|
||||
quantity_assigned : quantity = a_quantity
|
||||
end
|
||||
|
||||
feature -- Report
|
||||
hash_code: INTEGER
|
||||
--Hash code value
|
||||
do
|
||||
Result := option.hash_code + name.hash_code + size.hash_code + quantity.hash_code
|
||||
end
|
||||
|
||||
|
||||
invariant
|
||||
valid_size : is_valid_size_option (size)
|
||||
valid_coffe : is_valid_coffee_type (name)
|
||||
valid_customization : is_valid_milk_type (option)
|
||||
valid_quantity : quantity > 0
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,54 @@
|
||||
note
|
||||
description: "Summary description for {ITEM_CONSTANTS}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ITEM_CONSTANTS
|
||||
feature -- Access
|
||||
is_valid_coffee_type (a_type: STRING) : BOOLEAN
|
||||
--is `a_type' a valid coffee type
|
||||
do
|
||||
a_type.to_lower
|
||||
coffe_types.compare_objects
|
||||
Result := coffe_types.has (a_type)
|
||||
end
|
||||
|
||||
Coffe_types : ARRAY[STRING]
|
||||
-- List of valid Coffee types
|
||||
once
|
||||
Result := <<"late","cappuccino", "expresso">>
|
||||
end
|
||||
|
||||
is_valid_milk_type (a_type: STRING) : BOOLEAN
|
||||
--is `a_type' a valid milk type
|
||||
do
|
||||
a_type.to_lower
|
||||
milk_types.compare_objects
|
||||
Result := milk_types.has (a_type)
|
||||
end
|
||||
|
||||
Milk_types : ARRAY[STRING]
|
||||
-- List of valid Milk types
|
||||
once
|
||||
Result := <<"skim","semi", "whole">>
|
||||
end
|
||||
|
||||
is_valid_size_option (an_option: STRING) : BOOLEAN
|
||||
--is `an_option' a valid size option
|
||||
do
|
||||
an_option.to_lower
|
||||
size_options.compare_objects
|
||||
Result := size_options.has (an_option)
|
||||
end
|
||||
|
||||
Size_options : ARRAY[STRING]
|
||||
-- List of valid Size_options
|
||||
once
|
||||
Result := <<"small","mediumn", "large">>
|
||||
end
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,176 @@
|
||||
note
|
||||
description: "Summary description for {JSON_ORDER_CONVERTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
JSON_ORDER_CONVERTER
|
||||
inherit
|
||||
JSON_CONVERTER
|
||||
create
|
||||
make
|
||||
feature -- Initialization
|
||||
make
|
||||
do
|
||||
create object.make ("","","")
|
||||
end
|
||||
feature -- Access
|
||||
object : ORDER
|
||||
|
||||
|
||||
value : detachable JSON_OBJECT
|
||||
feature -- Conversion
|
||||
|
||||
from_json (j: attached like value): detachable like object
|
||||
-- Convert from JSON value. Returns Void if unable to convert
|
||||
local
|
||||
s_id, s_location, s_status: detachable STRING_32
|
||||
q: INTEGER_8
|
||||
o: ORDER
|
||||
i : ITEM
|
||||
l_array : detachable ARRAYED_LIST [JSON_VALUE]
|
||||
is_valid_from_json : BOOLEAN
|
||||
do
|
||||
is_valid_from_json := True
|
||||
|
||||
if attached {STRING_32} json.object (j.item (id_key), Void) as l_id then
|
||||
s_id := s_id
|
||||
end
|
||||
if attached {STRING_32} json.object (j.item (location_key), Void) as l_location then
|
||||
s_location := l_location
|
||||
end
|
||||
if attached {STRING_32} json.object (j.item (status_key), Void) as l_status then
|
||||
s_status := l_status
|
||||
end
|
||||
|
||||
create o.make ("", s_location, s_status)
|
||||
|
||||
if attached {JSON_ARRAY} j.item (items_key) as l_val then
|
||||
l_array := l_val.array_representation
|
||||
from
|
||||
l_array.start
|
||||
until
|
||||
l_array.after
|
||||
loop
|
||||
if attached {JSON_OBJECT} l_array.item_for_iteration as jv then
|
||||
if attached {INTEGER_8} json.object (jv.item (quantity_key), Void) as l_integer then
|
||||
q := l_integer
|
||||
else
|
||||
q := 0
|
||||
end
|
||||
if
|
||||
attached {STRING_32} json.object (jv.item (name_key), Void) as s_name and then
|
||||
attached {STRING_32} json.object (jv.item (size_key), Void) as s_key and then
|
||||
attached {STRING_32} json.object (jv.item (option_key), Void) as s_option
|
||||
then
|
||||
if is_valid_item_customization (s_name, s_key, s_option,q) then
|
||||
create i.make (s_name, s_key, s_option, q)
|
||||
o.add_item (i)
|
||||
else
|
||||
is_valid_from_json := False
|
||||
end
|
||||
else
|
||||
is_valid_from_json := False
|
||||
end
|
||||
end
|
||||
|
||||
l_array.forth
|
||||
end
|
||||
end
|
||||
if not is_valid_from_json or o.items.is_empty then
|
||||
Result := Void
|
||||
else
|
||||
Result := o
|
||||
end
|
||||
end
|
||||
|
||||
to_json (o: like object): like value
|
||||
-- Convert to JSON value
|
||||
local
|
||||
ja : JSON_ARRAY
|
||||
i : ITEM
|
||||
jv: JSON_OBJECT
|
||||
do
|
||||
create Result.make
|
||||
-- Result.put (json.value (o.id), id_key)
|
||||
Result.put (json.value (o.location), location_key)
|
||||
Result.put (json.value (o.status), status_key)
|
||||
from
|
||||
create ja.make_empty
|
||||
o.items.start
|
||||
until
|
||||
o.items.after
|
||||
loop
|
||||
i := o.items.item_for_iteration
|
||||
create jv.make
|
||||
jv.put (json.value (i.name), name_key)
|
||||
jv.put (json.value (i.size),size_key)
|
||||
jv.put (json.value (i.quantity), quantity_key)
|
||||
jv.put (json.value (i.option), option_key)
|
||||
ja.add (jv)
|
||||
o.items.forth
|
||||
end
|
||||
Result.put (ja, items_key)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
id_key: JSON_STRING
|
||||
once
|
||||
create Result.make_from_string ("id")
|
||||
end
|
||||
|
||||
location_key: JSON_STRING
|
||||
once
|
||||
create Result.make_from_string ("location")
|
||||
end
|
||||
|
||||
status_key: JSON_STRING
|
||||
once
|
||||
create Result.make_from_string ("status")
|
||||
end
|
||||
|
||||
items_key : JSON_STRING
|
||||
once
|
||||
create Result.make_from_string ("items")
|
||||
end
|
||||
|
||||
|
||||
name_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_from_string ("name")
|
||||
end
|
||||
|
||||
size_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_from_string ("size")
|
||||
end
|
||||
|
||||
quantity_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_from_string ("quantity")
|
||||
end
|
||||
|
||||
|
||||
option_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_from_string ("option")
|
||||
end
|
||||
feature -- Validation
|
||||
|
||||
is_valid_item_customization ( name : STRING_32; size: STRING_32; option : STRING_32; quantity : INTEGER_8 ) : BOOLEAN
|
||||
local
|
||||
ic : ITEM_CONSTANTS
|
||||
do
|
||||
create ic
|
||||
Result := ic.is_valid_coffee_type (name) and ic.is_valid_milk_type (option) and ic.is_valid_size_option (size) and quantity > 0
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
114
examples/obsolete/v0/restbucksCRUD/src/domain/order.e
Normal file
114
examples/obsolete/v0/restbucksCRUD/src/domain/order.e
Normal file
@@ -0,0 +1,114 @@
|
||||
note
|
||||
description: "Summary description for {ORDER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ORDER
|
||||
create
|
||||
make
|
||||
feature -- Initialization
|
||||
|
||||
make ( an_id : detachable STRING_32; a_location: detachable STRING_32; a_status: detachable STRING_32)
|
||||
do
|
||||
create {ARRAYED_LIST [ITEM]} items.make (10)
|
||||
if an_id /= Void then
|
||||
set_id (an_id)
|
||||
else
|
||||
set_id ("")
|
||||
end
|
||||
if a_location /= Void then
|
||||
set_location (a_location)
|
||||
else
|
||||
set_location ("")
|
||||
end
|
||||
if a_status /= Void then
|
||||
set_status (a_status)
|
||||
else
|
||||
set_status ("")
|
||||
end
|
||||
revision := 0
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
id : STRING_32
|
||||
location : STRING_32
|
||||
items: LIST[ITEM]
|
||||
status : STRING_32
|
||||
revision : INTEGER
|
||||
|
||||
feature -- element change
|
||||
|
||||
set_id (an_id : STRING_32)
|
||||
do
|
||||
id := an_id
|
||||
ensure
|
||||
id_assigned : id.same_string (an_id)
|
||||
end
|
||||
|
||||
set_location (a_location : STRING_32)
|
||||
do
|
||||
location := a_location
|
||||
ensure
|
||||
location_assigned : location.same_string (a_location)
|
||||
end
|
||||
|
||||
set_status (a_status : STRING_32)
|
||||
do
|
||||
status := a_status
|
||||
ensure
|
||||
status_asigned : status.same_string (a_status)
|
||||
end
|
||||
|
||||
add_item (a_item : ITEM)
|
||||
require
|
||||
valid_item: a_item /= Void
|
||||
do
|
||||
items.force (a_item)
|
||||
ensure
|
||||
has_item : items.has (a_item)
|
||||
end
|
||||
|
||||
add_revision
|
||||
do
|
||||
revision := revision + 1
|
||||
ensure
|
||||
revision_incremented : old revision + 1 = revision
|
||||
end
|
||||
|
||||
feature -- Etag
|
||||
|
||||
etag : STRING_32
|
||||
-- Etag generation for Order objects
|
||||
do
|
||||
Result := hash_code.out + revision.out
|
||||
end
|
||||
|
||||
|
||||
feature -- Output
|
||||
|
||||
feature -- Report
|
||||
|
||||
hash_code: INTEGER_32
|
||||
-- Hash code value
|
||||
do
|
||||
from
|
||||
items.start
|
||||
Result := items.item.hash_code
|
||||
until
|
||||
items.off
|
||||
loop
|
||||
Result:= ((Result \\ 8388593) |<< 8) + items.item.hash_code
|
||||
items.forth
|
||||
end
|
||||
if items.count > 1 then
|
||||
Result := Result \\ items.count
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,56 @@
|
||||
note
|
||||
description: "Summary description for {ORDER_TRANSITIONS}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ORDER_VALIDATION
|
||||
feature -- Access
|
||||
|
||||
is_valid_status_state (a_status: STRING) : BOOLEAN
|
||||
--is `a_status' a valid coffee order state
|
||||
do
|
||||
a_status.to_lower
|
||||
Order_states.compare_objects
|
||||
Result := Order_states.has (a_status)
|
||||
end
|
||||
|
||||
Order_states : ARRAY[STRING]
|
||||
-- List of valid status states
|
||||
once
|
||||
Result := <<"submitted","pay","payed", "cancel","canceled","prepare","prepared","deliver","completed">>
|
||||
end
|
||||
|
||||
|
||||
is_valid_transition (order:ORDER a_status : STRING) :BOOLEAN
|
||||
-- Given the current order state, determine if the transition is valid
|
||||
do
|
||||
a_status.to_lower
|
||||
if order.status.same_string ("submitted") then
|
||||
Result := a_status.same_string ("pay") or a_status.same_string ("cancel") or order.status.same_string (a_status)
|
||||
elseif order.status.same_string ("pay") then
|
||||
Result := a_status.same_string ("payed") or order.status.same_string (a_status)
|
||||
elseif order.status.same_string ("cancel") then
|
||||
Result := a_status.same_string ("canceled") or order.status.same_string (a_status)
|
||||
elseif order.status.same_string ("payed") then
|
||||
Result := a_status.same_string ("prepared") or order.status.same_string (a_status)
|
||||
elseif order.status.same_string ("prepared") then
|
||||
Result := a_status.same_string ("deliver") or order.status.same_string (a_status)
|
||||
elseif order.status.same_string ("deliver") then
|
||||
Result := a_status.same_string ("completed") or order.status.same_string (a_status)
|
||||
end
|
||||
end
|
||||
|
||||
is_state_valid_to_update ( a_status : STRING) : BOOLEAN
|
||||
-- Given the current state `a_status' of an order, is possible to update the order?
|
||||
do
|
||||
if a_status.same_string ("submitted") or else a_status.same_string ("pay") or else a_status.same_string ("payed") then
|
||||
Result := true
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
note
|
||||
description: "Summary description for {SHARED_ORDER_VALIDATION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SHARED_ORDER_VALIDATION
|
||||
|
||||
feature
|
||||
order_validation : ORDER_VALIDATION
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,574 @@
|
||||
note
|
||||
description: "{ORDER_HANDLER} handle the resources that we want to expose"
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class ORDER_HANDLER
|
||||
|
||||
inherit
|
||||
|
||||
WSF_SKELETON_HANDLER
|
||||
|
||||
SHARED_DATABASE_API
|
||||
|
||||
SHARED_EJSON
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_ORDER_VALIDATION
|
||||
|
||||
WSF_RESOURCE_HANDLER_HELPER
|
||||
rename
|
||||
execute_options as helper_execute_options,
|
||||
handle_internal_server_error as helper_handle_internal_server_error
|
||||
end
|
||||
|
||||
create
|
||||
|
||||
make_with_router
|
||||
|
||||
|
||||
feature -- Execution variables
|
||||
|
||||
Order_execution_variable: STRING = "ORDER"
|
||||
-- Execution variable used by application
|
||||
|
||||
Generated_content_execution_variable: STRING = "GENERATED_CONTENT"
|
||||
-- Execution variable used by application
|
||||
|
||||
Extracted_order_execution_variable: STRING = "EXTRACTED_ORDER"
|
||||
-- Execution variable used by application
|
||||
|
||||
feature -- Documentation
|
||||
|
||||
description: READABLE_STRING_GENERAL
|
||||
-- General description for self-generated documentation;
|
||||
-- The specific URI templates supported will be described automatically
|
||||
do
|
||||
Result := "Create, Read, Update or Delete an ORDER."
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_chunking (req: WSF_REQUEST): BOOLEAN
|
||||
-- Will the response to `req' using chunked transfer encoding?
|
||||
do
|
||||
-- No.
|
||||
end
|
||||
|
||||
includes_response_entity (req: WSF_REQUEST): BOOLEAN
|
||||
-- Does the response to `req' include an entity?
|
||||
-- Method will be DELETE, POST, PUT or an extension method.
|
||||
do
|
||||
Result := False
|
||||
-- At present, there is no support for this except for DELETE.
|
||||
end
|
||||
|
||||
conneg (req: WSF_REQUEST): SERVER_CONTENT_NEGOTIATION
|
||||
-- Content negotiatior for all requests
|
||||
once
|
||||
create Result.make ({HTTP_MIME_TYPES}.application_json, "en", "UTF-8", "identity")
|
||||
end
|
||||
|
||||
mime_types_supported (req: WSF_REQUEST): LIST [STRING]
|
||||
-- All values for Accept header that `Current' can serve
|
||||
do
|
||||
create {ARRAYED_LIST [STRING]} Result.make_from_array (<<{HTTP_MIME_TYPES}.application_json>>)
|
||||
Result.compare_objects
|
||||
end
|
||||
|
||||
languages_supported (req: WSF_REQUEST): LIST [STRING]
|
||||
-- All values for Accept-Language header that `Current' can serve
|
||||
do
|
||||
create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"en">>)
|
||||
Result.compare_objects
|
||||
end
|
||||
|
||||
charsets_supported (req: WSF_REQUEST): LIST [STRING]
|
||||
-- All values for Accept-Charset header that `Current' can serve
|
||||
do
|
||||
create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"UTF-8">>)
|
||||
Result.compare_objects
|
||||
end
|
||||
|
||||
encodings_supported (req: WSF_REQUEST): LIST [STRING]
|
||||
-- All values for Accept-Encoding header that `Current' can serve
|
||||
do
|
||||
create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"identity">>)
|
||||
Result.compare_objects
|
||||
end
|
||||
|
||||
max_age (req: WSF_REQUEST): NATURAL
|
||||
-- Maximum age in seconds before response to `req` is considered stale;
|
||||
-- This is used to generate a Cache-Control: max-age header.
|
||||
-- Return 0 to indicate already expired.
|
||||
-- Return Never_expires to indicate never expires.
|
||||
do
|
||||
-- All our responses are considered stale.
|
||||
end
|
||||
|
||||
is_freely_cacheable (req: WSF_REQUEST): BOOLEAN
|
||||
-- Should the response to `req' be freely cachable in shared caches?
|
||||
-- If `True', then a Cache-Control: public header will be generated.
|
||||
do
|
||||
-- definitely not!
|
||||
end
|
||||
|
||||
private_headers (req: WSF_REQUEST): detachable LIST [READABLE_STRING_8]
|
||||
-- Header names intended for a single user.
|
||||
-- If non-Void, then a Cache-Control: private header will be generated.
|
||||
-- Returning an empty list prevents the entire response from being served from a shared cache.
|
||||
do
|
||||
create {ARRAYED_LIST [READABLE_STRING_8]} Result.make (0)
|
||||
end
|
||||
|
||||
non_cacheable_headers (req: WSF_REQUEST): detachable LIST [READABLE_STRING_8]
|
||||
-- Header names that will not be sent from a cache without revalidation;
|
||||
-- If non-Void, then a Cache-Control: no-cache header will be generated.
|
||||
-- Returning an empty list prevents the response being served from a cache
|
||||
-- without revalidation.
|
||||
do
|
||||
create {ARRAYED_LIST [READABLE_STRING_8]} Result.make (0)
|
||||
end
|
||||
|
||||
is_sensitive (req: WSF_REQUEST): BOOLEAN
|
||||
-- Is the response to `req' of a sensitive nature?
|
||||
-- If `True' then a Cache-Control: no-store header will be generated.
|
||||
do
|
||||
Result := True
|
||||
-- since it's commercial data.
|
||||
end
|
||||
|
||||
allowed_cross_origins (req: WSF_REQUEST): detachable STRING
|
||||
-- Value for Access-Control-Allow-Origin header;
|
||||
-- If supplied, should be a single URI, or the values "*" or "null".
|
||||
-- This is currently supported only for GET requests, and POSTs that functions as GET.
|
||||
do
|
||||
if req.is_get_head_request_method then
|
||||
Result := "*"
|
||||
end
|
||||
end
|
||||
|
||||
matching_etag (req: WSF_REQUEST; a_etag: READABLE_STRING_32; a_strong: BOOLEAN): BOOLEAN
|
||||
-- Is `a_etag' a match for resource requested in `req'?
|
||||
-- If `a_strong' then the strong comparison function must be used.
|
||||
local
|
||||
l_id: STRING
|
||||
l_etag_util: ETAG_UTILS
|
||||
do
|
||||
l_id := order_id_from_request (req)
|
||||
if db_access.orders.has_key (l_id) then
|
||||
check attached db_access.orders.item (l_id) as l_order then
|
||||
-- postcondition of `has_key'
|
||||
create l_etag_util
|
||||
Result := a_etag.same_string (l_etag_util.md5_digest (l_order.out).as_string_32)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
etag (req: WSF_REQUEST): detachable READABLE_STRING_8
|
||||
-- Optional Etag for `req' in the requested variant
|
||||
local
|
||||
l_etag_utils: ETAG_UTILS
|
||||
do
|
||||
create l_etag_utils
|
||||
if attached {ORDER} req.execution_variable (Order_execution_variable) as l_order then
|
||||
Result := l_etag_utils.md5_digest (l_order.out)
|
||||
end
|
||||
end
|
||||
|
||||
last_modified (req: WSF_REQUEST): detachable DATE_TIME
|
||||
-- When representation of resource selected in `req' was last modified;
|
||||
-- SHOULD be set whenever it can reasonably be determined.
|
||||
do
|
||||
end
|
||||
|
||||
modified_since (req: WSF_REQUEST; a_date_time: DATE_TIME): BOOLEAN
|
||||
-- Has resource requested in `req' been modified since `a_date_time' (UTC)?
|
||||
do
|
||||
-- We don't track this information. It is safe to always say yes.
|
||||
Result := True
|
||||
end
|
||||
|
||||
feature -- Measurement
|
||||
|
||||
content_length (req: WSF_REQUEST): NATURAL
|
||||
-- Length of entity-body of the response to `req'
|
||||
do
|
||||
check attached {READABLE_STRING_8} req.execution_variable (Generated_content_execution_variable) as l_response then
|
||||
-- postcondition generated_content_set_for_get_head of `ensure_content_available'
|
||||
-- We only call this for GET/HEAD in this example.
|
||||
Result := l_response.count.as_natural_32
|
||||
end
|
||||
end
|
||||
|
||||
allow_post_to_missing_resource (req: WSF_REQUEST): BOOLEAN
|
||||
-- The resource named in `req' does not exist, and this is a POST. Do we allow it?
|
||||
do
|
||||
-- No.
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
finished (req: WSF_REQUEST): BOOLEAN
|
||||
-- Has the last chunk been generated for `req'?
|
||||
do
|
||||
-- precondition is never met
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
check_resource_exists (req: WSF_REQUEST; a_helper: WSF_METHOD_HELPER)
|
||||
-- Call `a_helper.set_resource_exists' to indicate that `req.path_translated'
|
||||
-- is the name of an existing resource.
|
||||
-- We also put the order into `req.execution_variable (Order_execution_variable)' for GET or HEAD responses.
|
||||
local
|
||||
l_id: STRING
|
||||
do
|
||||
if req.is_post_request_method then
|
||||
a_helper.set_resource_exists
|
||||
-- because only /order is defined to this handler for POST
|
||||
else
|
||||
-- the request is of the form /order/{orderid}
|
||||
l_id := order_id_from_request (req)
|
||||
if db_access.orders.has_key (l_id) then
|
||||
a_helper.set_resource_exists
|
||||
if req.is_get_head_request_method then
|
||||
check attached db_access.orders.item (l_id) as l_order then
|
||||
-- postcondition `item_if_found' of `has_key'
|
||||
req.set_execution_variable (Order_execution_variable, l_order)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure then
|
||||
order_saved_only_for_get_head: attached {ORDER} req.execution_variable (Order_execution_variable) implies req.is_get_head_request_method
|
||||
end
|
||||
|
||||
feature -- GET/HEAD content
|
||||
|
||||
ensure_content_available (req: WSF_REQUEST)
|
||||
-- Commence generation of response text (entity-body).
|
||||
-- If not chunked, then this will create the entire entity-body so as to be available
|
||||
-- for a subsequent call to `content'.
|
||||
-- If chunked, only the first chunk will be made available to `next_chunk'. If chunk extensions
|
||||
-- are used, then this will also generate the chunk extension for the first chunk.
|
||||
-- We save the text in `req.execution_variable (Generated_content_execution_variable)'
|
||||
-- We ignore the results of content negotiation, as there is only one possible combination.
|
||||
do
|
||||
check attached {ORDER} req.execution_variable (Order_execution_variable) as l_order then
|
||||
-- precondition get_or_head and postcondition order_saved_only_for_get_head of `check_resource_exists' and
|
||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||
req.set_execution_variable (Generated_content_execution_variable, jv.representation)
|
||||
else
|
||||
req.set_execution_variable (Generated_content_execution_variable, "")
|
||||
end
|
||||
end
|
||||
ensure then
|
||||
generated_content_set_for_get_head: req.is_get_head_request_method implies
|
||||
attached {READABLE_STRING_8} req.execution_variable (Generated_content_execution_variable)
|
||||
end
|
||||
|
||||
content (req: WSF_REQUEST): READABLE_STRING_8
|
||||
-- Non-chunked entity body in response to `req';
|
||||
-- We only call this for GET/HEAD in this example.
|
||||
do
|
||||
check attached {READABLE_STRING_8} req.execution_variable (Generated_content_execution_variable) as l_response then
|
||||
-- postcondition generated_content_set_for_get_head of `ensure_content_available'
|
||||
Result := l_response
|
||||
end
|
||||
end
|
||||
|
||||
next_chunk (req: WSF_REQUEST): TUPLE [a_chunk: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8]
|
||||
-- Next chunk of entity body in response to `req';
|
||||
-- The second field of the result is an optional chunk extension.
|
||||
do
|
||||
-- precondition `is_chunking' is never met, but we need a dummy `Result'
|
||||
-- to satisfy the compiler in void-safe mode
|
||||
Result := ["", Void]
|
||||
end
|
||||
|
||||
generate_next_chunk (req: WSF_REQUEST)
|
||||
-- Prepare next chunk (including optional chunk extension) of entity body in response to `req'.
|
||||
-- This is not called for the first chunk.
|
||||
do
|
||||
-- precondition `is_chunking' is never met
|
||||
end
|
||||
|
||||
feature -- DELETE
|
||||
|
||||
delete (req: WSF_REQUEST)
|
||||
-- Delete resource named in `req' or set an error on `req.error_handler'.
|
||||
local
|
||||
l_id: STRING
|
||||
do
|
||||
l_id := order_id_from_request (req)
|
||||
if db_access.orders.has_key (l_id) then
|
||||
if is_valid_to_delete (l_id) then
|
||||
delete_order (l_id)
|
||||
else
|
||||
req.error_handler.add_custom_error ({HTTP_STATUS_CODE}.method_not_allowed, "DELETE not valid",
|
||||
"There is conflict while trying to delete the order, the order could not be deleted in the current state")
|
||||
end
|
||||
else
|
||||
req.error_handler.add_custom_error ({HTTP_STATUS_CODE}.not_found, "DELETE not valid",
|
||||
"There is no such order to delete")
|
||||
end
|
||||
end
|
||||
|
||||
delete_queued (req: WSF_REQUEST): BOOLEAN
|
||||
-- Has resource named by `req' been queued for deletion?
|
||||
do
|
||||
-- No
|
||||
end
|
||||
|
||||
|
||||
feature -- PUT/POST
|
||||
|
||||
is_entity_too_large (req: WSF_REQUEST): BOOLEAN
|
||||
-- Is the entity stored in `req.execution_variable (Request_entity_execution_variable)' too large for the application?
|
||||
do
|
||||
-- No. We don't care for this example.
|
||||
end
|
||||
|
||||
check_content_headers (req: WSF_REQUEST)
|
||||
-- Check we can support all content headers on request entity.
|
||||
-- Set `req.execution_variable (Content_check_code_execution_variable)' to {NATURAL} zero if OK, or 415 or 501 if not.
|
||||
do
|
||||
-- We don't bother for this example. Note that this is equivalent to setting zero.
|
||||
end
|
||||
|
||||
create_resource (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Create new resource in response to a PUT request when `check_resource_exists' returns `False'.
|
||||
-- Implementor must set error code of 200 OK or 500 Server Error.
|
||||
do
|
||||
-- We don't support creating a new resource with PUT. But this can't happen
|
||||
-- with our router mappings, so we don't bother to set a 500 response.
|
||||
end
|
||||
|
||||
append_resource (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Create new resource in response to a POST request.
|
||||
-- Implementor must set error code of 200 OK or 204 No Content or 303 See Other or 500 Server Error.
|
||||
do
|
||||
if attached {ORDER} req.execution_variable (Extracted_order_execution_variable) as l_order then
|
||||
save_order (l_order)
|
||||
compute_response_post (req, res, l_order)
|
||||
else
|
||||
handle_bad_request_response ("Not a valid order", req, res)
|
||||
end
|
||||
end
|
||||
|
||||
check_conflict (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Check we can support all content headers on request entity.
|
||||
-- Set `req.execution_variable (Conflict_check_code_execution_variable)' to {NATURAL} zero if OK, or 409 if not.
|
||||
-- In the latter case, write the full error response to `res'.
|
||||
do
|
||||
if attached {ORDER} req.execution_variable (Extracted_order_execution_variable) as l_order then
|
||||
if not is_valid_to_update (l_order) then
|
||||
req.set_execution_variable (Conflict_check_code_execution_variable, {NATURAL} 409)
|
||||
handle_resource_conflict_response (l_order.out +"%N There is conflict while trying to update the order, the order could not be update in the current state", req, res)
|
||||
end
|
||||
else
|
||||
req.set_execution_variable (Conflict_check_code_execution_variable, {NATURAL} 409)
|
||||
--| This ought to be a 500, as if attached should probably be check attached. But as yet I lack a proof.
|
||||
handle_resource_conflict_response ("There is conflict while trying to update the order, the order could not be update in the current state", req, res)
|
||||
end
|
||||
end
|
||||
|
||||
check_request (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Check that the request entity is a valid request.
|
||||
-- The entity is available as `req.execution_variable (Conflict_check_code_execution_variable)'.
|
||||
-- Set `req.execution_variable (Request_check_code_execution_variable)' to {NATURAL} zero if OK, or 400 if not.
|
||||
-- In the latter case, write the full error response to `res'.
|
||||
local
|
||||
l_order: detachable ORDER
|
||||
l_id: STRING
|
||||
do
|
||||
if attached {READABLE_STRING_8} req.execution_variable (Request_entity_execution_variable) as l_request then
|
||||
l_order := extract_order_request (l_request)
|
||||
if req.is_put_request_method then
|
||||
l_id := order_id_from_request (req)
|
||||
if l_order /= Void and then db_access.orders.has_key (l_id) then
|
||||
l_order.set_id (l_id)
|
||||
req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 0)
|
||||
req.set_execution_variable (Extracted_order_execution_variable, l_order)
|
||||
else
|
||||
req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 400)
|
||||
handle_bad_request_response (l_request +"%N is not a valid ORDER, maybe the order does not exist in the system", req, res)
|
||||
end
|
||||
else
|
||||
req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 0)
|
||||
req.set_execution_variable (Extracted_order_execution_variable, l_order)
|
||||
end
|
||||
else
|
||||
req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 400)
|
||||
handle_bad_request_response ("Request is not a valid ORDER", req, res)
|
||||
end
|
||||
end
|
||||
|
||||
update_resource (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Perform the update requested in `req'.
|
||||
-- Write a response to `res' with a code of 204 or 500.
|
||||
do
|
||||
if attached {ORDER} req.execution_variable (Extracted_order_execution_variable) as l_order then
|
||||
update_order (l_order)
|
||||
compute_response_put (req, res, l_order)
|
||||
else
|
||||
handle_internal_server_error (res)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- HTTP Methods
|
||||
|
||||
compute_response_put (req: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
etag_utils : ETAG_UTILS
|
||||
do
|
||||
create h.make
|
||||
create joc.make
|
||||
create etag_utils
|
||||
json.add_converter(joc)
|
||||
|
||||
create h.make
|
||||
h.put_content_type_application_json
|
||||
if attached req.request_time as time then
|
||||
h.add_header ("Date:" +time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
||||
end
|
||||
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
|
||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||
h.put_content_length (jv.representation.count)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (jv.representation)
|
||||
end
|
||||
end
|
||||
|
||||
compute_response_post (req: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
l_msg : STRING
|
||||
l_location : STRING
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
do
|
||||
create h.make
|
||||
|
||||
create joc.make
|
||||
json.add_converter(joc)
|
||||
|
||||
h.put_content_type_application_json
|
||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||
l_msg := jv.representation
|
||||
h.put_content_length (l_msg.count)
|
||||
if attached req.http_host as host then
|
||||
l_location := "http://" + host + req.request_uri + "/" + l_order.id
|
||||
h.put_location (l_location)
|
||||
end
|
||||
if attached req.request_time as time then
|
||||
h.put_utc_date (time)
|
||||
end
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.created)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (l_msg)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- URI helper methods
|
||||
|
||||
order_id_from_request (req: WSF_REQUEST): STRING
|
||||
-- Value of "orderid" template URI variable in `req'
|
||||
require
|
||||
req_attached: req /= Void
|
||||
do
|
||||
if attached {WSF_VALUE} req.path_parameter ("orderid") as l_value then
|
||||
Result := l_value.as_string.value.as_string_8
|
||||
else
|
||||
Result := ""
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation Repository Layer
|
||||
|
||||
retrieve_order ( id : STRING) : detachable ORDER
|
||||
-- get the order by id if it exist, in other case, Void
|
||||
do
|
||||
Result := db_access.orders.item (id)
|
||||
end
|
||||
|
||||
save_order (an_order: ORDER)
|
||||
-- save the order to the repository
|
||||
local
|
||||
i : INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
not db_access.orders.has_key ((db_access.orders.count + i).out)
|
||||
loop
|
||||
i := i + 1
|
||||
end
|
||||
an_order.set_id ((db_access.orders.count + i).out)
|
||||
an_order.set_status ("submitted")
|
||||
an_order.add_revision
|
||||
db_access.orders.force (an_order, an_order.id)
|
||||
end
|
||||
|
||||
|
||||
is_valid_to_delete ( an_id : STRING) : BOOLEAN
|
||||
-- Is the order identified by `an_id' in a state whre it can still be deleted?
|
||||
do
|
||||
if attached retrieve_order (an_id) as l_order then
|
||||
if order_validation.is_state_valid_to_update (l_order.status) then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_valid_to_update (an_order: ORDER) : BOOLEAN
|
||||
-- Check if there is a conflict while trying to update the order
|
||||
do
|
||||
if attached retrieve_order (an_order.id) as l_order then
|
||||
if order_validation.is_state_valid_to_update (l_order.status) and then order_validation.is_valid_status_state (an_order.status) and then
|
||||
order_validation.is_valid_transition (l_order, an_order.status) then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
update_order (an_order: ORDER)
|
||||
-- update the order to the repository
|
||||
do
|
||||
an_order.add_revision
|
||||
db_access.orders.force (an_order, an_order.id)
|
||||
end
|
||||
|
||||
delete_order (an_order: STRING)
|
||||
-- update the order to the repository
|
||||
do
|
||||
db_access.orders.remove (an_order)
|
||||
end
|
||||
|
||||
extract_order_request (l_post : STRING) : detachable ORDER
|
||||
-- extract an object Order from the request, or Void
|
||||
-- if the request is invalid
|
||||
local
|
||||
parser : JSON_PARSER
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
do
|
||||
create joc.make
|
||||
json.add_converter(joc)
|
||||
create parser.make_with_string (l_post)
|
||||
parser.parse_content
|
||||
if parser.is_valid and then attached parser.parsed_json_value as jv then
|
||||
if attached {like extract_order_request} json.object (jv, "ORDER") as res then
|
||||
Result := res
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
403
examples/obsolete/v0/restbucksCRUD/src/resource/order_handler.e
Normal file
403
examples/obsolete/v0/restbucksCRUD/src/resource/order_handler.e
Normal file
@@ -0,0 +1,403 @@
|
||||
note
|
||||
description: "{ORDER_HANDLER} handle the resources that we want to expose"
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class ORDER_HANDLER
|
||||
inherit
|
||||
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
WSF_RESOURCE_HANDLER_HELPER
|
||||
redefine
|
||||
do_get,
|
||||
do_post,
|
||||
do_put,
|
||||
do_delete
|
||||
end
|
||||
|
||||
SHARED_DATABASE_API
|
||||
|
||||
SHARED_EJSON
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_ORDER_VALIDATION
|
||||
|
||||
WSF_SELF_DOCUMENTED_HANDLER
|
||||
|
||||
create
|
||||
make_with_router
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_with_router (a_router: WSF_ROUTER)
|
||||
-- Initialize `router'.
|
||||
require
|
||||
a_router_attached: a_router /= Void
|
||||
do
|
||||
router := a_router
|
||||
ensure
|
||||
router_aliased: router = a_router
|
||||
end
|
||||
|
||||
feature -- Router
|
||||
|
||||
router: WSF_ROUTER
|
||||
-- Associated router that could be used for advanced strategy
|
||||
|
||||
feature -- Execute
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
do
|
||||
execute_methods (req, res)
|
||||
end
|
||||
|
||||
feature -- API DOC
|
||||
|
||||
api_doc : STRING = "URI:/order METHOD: POST%N URI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
|
||||
|
||||
|
||||
feature -- Documentation
|
||||
|
||||
mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION
|
||||
do
|
||||
create Result.make (m)
|
||||
if a_request_methods /= Void then
|
||||
if a_request_methods.has_method_post then
|
||||
Result.add_description ("URI:/order METHOD: POST")
|
||||
elseif
|
||||
a_request_methods.has_method_get
|
||||
or a_request_methods.has_method_put
|
||||
or a_request_methods.has_method_delete
|
||||
then
|
||||
Result.add_description ("URI:/order/{orderid} METHOD: GET, PUT, DELETE")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- HTTP Methods
|
||||
|
||||
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- <Precursor>
|
||||
local
|
||||
id: STRING
|
||||
do
|
||||
if attached req.path_info as l_path_info then
|
||||
id := get_order_id_from_path (l_path_info)
|
||||
if attached retrieve_order (id) as l_order then
|
||||
if is_conditional_get (req, l_order) then
|
||||
handle_resource_not_modified_response ("The resource" + l_path_info + "does not change", req, res)
|
||||
else
|
||||
compute_response_get (req, res, l_order)
|
||||
end
|
||||
else
|
||||
handle_resource_not_found_response ("The following resource" + l_path_info + " is not found ", req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_conditional_get (req : WSF_REQUEST; l_order : ORDER) : BOOLEAN
|
||||
-- Check if If-None-Match is present and then if there is a representation that has that etag
|
||||
-- if the representation hasn't changed, we return TRUE
|
||||
-- then the response is a 304 with no entity body returned.
|
||||
local
|
||||
etag_util : ETAG_UTILS
|
||||
do
|
||||
if attached req.meta_string_variable ("HTTP_IF_NONE_MATCH") as if_none_match then
|
||||
create etag_util
|
||||
if if_none_match.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
compute_response_get (req: WSF_REQUEST; res: WSF_RESPONSE; l_order: ORDER)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
l_msg : STRING
|
||||
etag_utils : ETAG_UTILS
|
||||
do
|
||||
create h.make
|
||||
create etag_utils
|
||||
h.put_content_type_application_json
|
||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||
l_msg := jv.representation
|
||||
h.put_content_length (l_msg.count)
|
||||
if attached req.request_time as time then
|
||||
h.add_header ("Date:" + time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
||||
end
|
||||
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (l_msg)
|
||||
end
|
||||
end
|
||||
|
||||
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Updating a resource with PUT
|
||||
-- A successful PUT request will not create a new resource, instead it will
|
||||
-- change the state of the resource identified by the current uri.
|
||||
-- If success we response with 200 and the updated order.
|
||||
-- 404 if the order is not found
|
||||
-- 400 in case of a bad request
|
||||
-- 500 internal server error
|
||||
-- If the request is a Conditional PUT, and it does not mat we response
|
||||
-- 415, precondition failed.
|
||||
local
|
||||
l_put: STRING
|
||||
l_order : detachable ORDER
|
||||
id : STRING
|
||||
do
|
||||
if attached req.path_info as l_path_info then
|
||||
id := get_order_id_from_path (l_path_info)
|
||||
l_put := retrieve_data (req)
|
||||
l_order := extract_order_request(l_put)
|
||||
if l_order /= Void and then db_access.orders.has_key (id) then
|
||||
l_order.set_id (id)
|
||||
if is_valid_to_update(l_order) then
|
||||
if is_conditional_put (req, l_order) then
|
||||
update_order( l_order)
|
||||
compute_response_put (req, res, l_order)
|
||||
else
|
||||
handle_precondition_fail_response ("", req, res)
|
||||
end
|
||||
else
|
||||
--| FIXME: Here we need to define the Allow methods
|
||||
handle_resource_conflict_response (l_put +"%N There is conflict while trying to update the order, the order could not be update in the current state", req, res)
|
||||
end
|
||||
else
|
||||
handle_bad_request_response (l_put +"%N is not a valid ORDER, maybe the order does not exist in the system", req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_conditional_put (req : WSF_REQUEST; order : ORDER) : BOOLEAN
|
||||
-- Check if If-Match is present and then if there is a representation that has that etag
|
||||
-- if the representation hasn't changed, we return TRUE
|
||||
local
|
||||
etag_util : ETAG_UTILS
|
||||
do
|
||||
if attached retrieve_order (order.id) as l_order then
|
||||
if attached req.meta_string_variable ("HTTP_IF_MATCH") as if_match then
|
||||
create etag_util
|
||||
if if_match.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||
Result := True
|
||||
end
|
||||
else
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
compute_response_put (req: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
etag_utils : ETAG_UTILS
|
||||
do
|
||||
create h.make
|
||||
create joc.make
|
||||
create etag_utils
|
||||
json.add_converter(joc)
|
||||
|
||||
create h.make
|
||||
h.put_content_type_application_json
|
||||
if attached req.request_time as time then
|
||||
h.add_header ("Date:" +time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
||||
end
|
||||
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
|
||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||
h.put_content_length (jv.representation.count)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (jv.representation)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Here we use DELETE to cancel an order, if that order is in state where
|
||||
-- it can still be canceled.
|
||||
-- 200 if is ok
|
||||
-- 404 Resource not found
|
||||
-- 405 if consumer and service's view of the resouce state is inconsisent
|
||||
-- 500 if we have an internal server error
|
||||
local
|
||||
id: STRING
|
||||
do
|
||||
if attached req.path_info as l_path_info then
|
||||
id := get_order_id_from_path (l_path_info)
|
||||
if db_access.orders.has_key (id) then
|
||||
if is_valid_to_delete (id) then
|
||||
delete_order( id)
|
||||
compute_response_delete (req, res)
|
||||
else
|
||||
--| FIXME: Here we need to define the Allow methods
|
||||
handle_method_not_allowed_response (l_path_info + "%N There is conflict while trying to delete the order, the order could not be deleted in the current state", req, res)
|
||||
end
|
||||
else
|
||||
handle_resource_not_found_response (l_path_info + " not found in this server", req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
compute_response_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h : HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_application_json
|
||||
if attached req.request_time as time then
|
||||
h.put_utc_date (time)
|
||||
end
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.no_content)
|
||||
res.put_header_text (h.string)
|
||||
end
|
||||
|
||||
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Here the convention is the following.
|
||||
-- POST is used for creation and the server determines the URI
|
||||
-- of the created resource.
|
||||
-- If the request post is SUCCESS, the server will create the order and will response with
|
||||
-- HTTP_RESPONSE 201 CREATED, the Location header will contains the newly created order's URI
|
||||
-- if the request post is not SUCCESS, the server will response with
|
||||
-- HTTP_RESPONSE 400 BAD REQUEST, the client send a bad request
|
||||
-- HTTP_RESPONSE 500 INTERNAL_SERVER_ERROR, when the server can deliver the request
|
||||
local
|
||||
l_post: STRING
|
||||
do
|
||||
l_post := retrieve_data (req)
|
||||
if attached extract_order_request (l_post) as l_order then
|
||||
save_order (l_order)
|
||||
compute_response_post (req, res, l_order)
|
||||
else
|
||||
handle_bad_request_response (l_post +"%N is not a valid ORDER", req, res)
|
||||
end
|
||||
end
|
||||
|
||||
compute_response_post (req: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
l_msg : STRING
|
||||
l_location : STRING
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
do
|
||||
create h.make
|
||||
|
||||
create joc.make
|
||||
json.add_converter(joc)
|
||||
|
||||
h.put_content_type_application_json
|
||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||
l_msg := jv.representation
|
||||
h.put_content_length (l_msg.count)
|
||||
if attached req.http_host as host then
|
||||
l_location := "http://" + host + req.request_uri + "/" + l_order.id
|
||||
h.put_location (l_location)
|
||||
end
|
||||
if attached req.request_time as time then
|
||||
h.put_utc_date (time)
|
||||
end
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.created)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (l_msg)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- URI helper methods
|
||||
|
||||
get_order_id_from_path (a_path: READABLE_STRING_32) : STRING
|
||||
do
|
||||
Result := a_path.split ('/').at (3)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation Repository Layer
|
||||
|
||||
retrieve_order ( id : STRING) : detachable ORDER
|
||||
-- get the order by id if it exist, in other case, Void
|
||||
do
|
||||
Result := db_access.orders.item (id)
|
||||
end
|
||||
|
||||
save_order (an_order: ORDER)
|
||||
-- save the order to the repository
|
||||
local
|
||||
i : INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
not db_access.orders.has_key ((db_access.orders.count + i).out)
|
||||
loop
|
||||
i := i + 1
|
||||
end
|
||||
an_order.set_id ((db_access.orders.count + i).out)
|
||||
an_order.set_status ("submitted")
|
||||
an_order.add_revision
|
||||
db_access.orders.force (an_order, an_order.id)
|
||||
end
|
||||
|
||||
|
||||
is_valid_to_delete ( an_id : STRING) : BOOLEAN
|
||||
-- Is the order identified by `an_id' in a state whre it can still be deleted?
|
||||
do
|
||||
if attached retrieve_order (an_id) as l_order then
|
||||
if order_validation.is_state_valid_to_update (l_order.status) then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_valid_to_update (an_order: ORDER) : BOOLEAN
|
||||
-- Check if there is a conflict while trying to update the order
|
||||
do
|
||||
if attached retrieve_order (an_order.id) as l_order then
|
||||
if order_validation.is_state_valid_to_update (l_order.status) and then order_validation.is_valid_status_state (an_order.status) and then
|
||||
order_validation.is_valid_transition (l_order, an_order.status) then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
update_order (an_order: ORDER)
|
||||
-- update the order to the repository
|
||||
do
|
||||
an_order.add_revision
|
||||
db_access.orders.force (an_order, an_order.id)
|
||||
end
|
||||
|
||||
delete_order (an_order: STRING)
|
||||
-- update the order to the repository
|
||||
do
|
||||
db_access.orders.remove (an_order)
|
||||
end
|
||||
|
||||
extract_order_request (l_post : STRING) : detachable ORDER
|
||||
-- extract an object Order from the request, or Void
|
||||
-- if the request is invalid
|
||||
local
|
||||
parser : JSON_PARSER
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
do
|
||||
create joc.make
|
||||
json.add_converter(joc)
|
||||
create parser.make_with_string (l_post)
|
||||
parser.parse_content
|
||||
if
|
||||
parser.is_valid and then
|
||||
attached parser.parsed_json_value as jv
|
||||
then
|
||||
if attached {like extract_order_request} json.object (jv, "ORDER") as res then
|
||||
Result := res
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
58
examples/obsolete/v0/restbucksCRUD/src/restbucks_server.e
Normal file
58
examples/obsolete/v0/restbucksCRUD/src/restbucks_server.e
Normal file
@@ -0,0 +1,58 @@
|
||||
note
|
||||
description : "REST Buck server"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class RESTBUCKS_SERVER
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SKELETON_SERVICE
|
||||
undefine
|
||||
requires_proxy
|
||||
end
|
||||
|
||||
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
|
||||
|
||||
WSF_HANDLER_HELPER
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
initialize_router
|
||||
set_service_option ("port", 9090)
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
setup_router
|
||||
local
|
||||
order_handler: ORDER_HANDLER
|
||||
doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER
|
||||
do
|
||||
create order_handler.make_with_router (router)
|
||||
router.handle_with_request_methods ("/order", order_handler, router.methods_POST)
|
||||
router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
|
||||
create doc.make_hidden (router)
|
||||
router.handle_with_request_methods ("/api/doc", doc, router.methods_GET)
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla 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
|
||||
24
examples/obsolete/v0/restbucksCRUD/src/utils/etag_utils.e
Normal file
24
examples/obsolete/v0/restbucksCRUD/src/utils/etag_utils.e
Normal file
@@ -0,0 +1,24 @@
|
||||
note
|
||||
description: "Summary description for {ETAG_UTILS}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ETAG_UTILS
|
||||
|
||||
feature -- Access
|
||||
|
||||
md5_digest (a_string: STRING): STRING
|
||||
-- Cryptographic hash function that produces a 128-bit (16-byte) hash value, based on `a_string'
|
||||
local
|
||||
md5: MD5
|
||||
do
|
||||
create md5.make
|
||||
md5.update_from_string (a_string)
|
||||
Result := md5.digest_as_string
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -8,7 +8,7 @@
|
||||
</file_rule>
|
||||
<option full_class_checking="false" void_safety="all">
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf" readonly="false">
|
||||
<option debug="true">
|
||||
|
||||
@@ -37,10 +37,10 @@ feature {NONE} -- Initialization
|
||||
doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER
|
||||
do
|
||||
create order_handler.make_with_router (router)
|
||||
router.handle_with_request_methods ("/order", order_handler, router.methods_POST)
|
||||
router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
|
||||
router.handle ("/order", order_handler, router.methods_POST)
|
||||
router.handle ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
|
||||
create doc.make_hidden (router)
|
||||
router.handle_with_request_methods ("/api/doc", doc, router.methods_GET)
|
||||
router.handle ("/api/doc", doc, router.methods_GET)
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<cluster name="simple" location=".\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
|
||||
@@ -8,10 +8,11 @@ To write once and run on any web server, on any platforms thanks to the notion o
|
||||
== What is a connector? ==
|
||||
|
||||
A connector is the layer between the underlying httpd server, and your application based on EWF.
|
||||
Currently, 3 connectors are available within EWF (but others are available outside).
|
||||
Currently, 4 connectors are available within EWF (but others are available outside).
|
||||
* CGI: the common CGI application (apache, iis, ...)
|
||||
* FastCGI: on any server supporting libfcgi handling (apache, iis, ...)
|
||||
* Nino: using the standalone Eiffel Web Nino server, you can run anywhere easily, and debug simply with EiffelStudio's debugger
|
||||
* Standalone: a standalone Eiffel Web server, it can be run anywhere easily, and debug simply with EiffelStudio's debugger. It supports all concurrency modes, and require EiffelStudio >= 15.05.
|
||||
* Nino: similar to the "standalone" connectors, but lack good concurrency support.
|
||||
|
||||
Supporting a new connector is fairly simple, it just has to support the simple EWSGI specification which is really small. Then EWF will bring the power on top of it.
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ or go to [[step_2.wiki|step 2]]
|
||||
|
||||
== Get EWF package ==
|
||||
=== From the archive ===
|
||||
* Get recent archive from https://github.com/EiffelWebFramework/EWF/downloads
|
||||
* Get recent archive of version v1 from https://github.com/EiffelWebFramework/EWF/releases
|
||||
|
||||
=== From the source ===
|
||||
* '''Requirement''': install [http://www.git-scm.org/ git] on your machine
|
||||
|
||||
$ git clone --recursive https://github.com/EiffelWebFramework/EWF.git ewf
|
||||
$ git clone -b v1 --recursive https://github.com/EiffelWebFramework/EWF.git ewf
|
||||
|
||||
== Install EWF ==
|
||||
For now, there is nothing specific to do.
|
||||
|
||||
@@ -13,14 +13,14 @@ or go to [[step_3.wiki|step 3]]
|
||||
== "hello" project ==
|
||||
* using the "wsf" library:
|
||||
** It provides service, request, response, ...
|
||||
* using the "default_nino" library
|
||||
** This is used to build the application in a portable manner, but for this compilation, it uses Eiffel Web Nino as connector.
|
||||
** We use Eiffel Web Nino for this tutorial, because there is no need to configure any apache, iis, and so on. And it is convenient to execute inside EiffelStudio
|
||||
* using the "default_standalone" library
|
||||
** This is used to build the application in a portable manner, but for this compilation, it uses the standalone web server as connector.
|
||||
** We use that standalone connection this tutorial, because there is no need to configure any apache, iis, and so on. And it is convenient to execute with EiffelStudio debugger.
|
||||
|
||||
* To see the result, you should open http://localhost/ on your web browser. Note if the application is using another port such as 9999, you should open http://localhost:9999/
|
||||
|
||||
* You will find inside [[step_2]] the "hello" project
|
||||
** target "hello" provides a very simple implementation (But by default, it is using port 80 with Eiffel Web Nino, which might already be busy by other application)
|
||||
** target "hello" provides a very simple implementation (But by default, it is using port 80 with standalone web server, which might already be busy by other application)
|
||||
** target "hello_custom" which uses almost the same code, but in addition, you can use the ewf.ini file to precise the port number (9999 for this example)
|
||||
|
||||
* To see the result, open http://localhost/ in a web browser.
|
||||
@@ -28,25 +28,38 @@ or go to [[step_3.wiki|step 3]]
|
||||
|
||||
* Eiffel code
|
||||
class
|
||||
HELLO_APPLICATION
|
||||
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_RESPONSE_SERVICE
|
||||
|
||||
WSF_DEFAULT_SERVICE [HELLO_EXECUTION]
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
response (req: WSF_REQUEST): WSF_PAGE_RESPONSE
|
||||
-- Computed response message.
|
||||
do
|
||||
create Result.make
|
||||
Result.put_string ("Hello World")
|
||||
end
|
||||
make_and_launch
|
||||
|
||||
end
|
||||
|
||||
class
|
||||
HELLO_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute
|
||||
local
|
||||
msg: WSF_PAGE_RESPONSE
|
||||
do
|
||||
create msg.make_with_body ("Hello World")
|
||||
response.send (msg)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Note: we could also declare the root class as being "WSF_DEFAULT_SERVICE [HELLO_EXECUTION]" to avoid this HELLO_APPLICATION class.
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
This folder contains 2 alternatives code
|
||||
|
||||
1) "execute" using the WSF_SERVICE interface, i.e
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
1) "message" using the WSF_MESSAGE_EXECUTION interface, i.e
|
||||
message: WSF_RESPONSE_MESSAGE
|
||||
do
|
||||
...
|
||||
end
|
||||
|
||||
|
||||
2) "launcher" using the WSF_RESPONSE_SERVICE interface, but it uses a launcher to start the service, instead of inheriting from WSF_DEFAULT_SERVICE or WSF_DEFAULT_RESPONSE_SERVICE
|
||||
2) "launcher" using the WSF_RESPONSE_SERVICE interface, but it uses a launcher to start the service, instead of inheriting from WSF_DEFAULT_SERVICE
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
APPLICATION implements the `Hello World' service.
|
||||
|
||||
It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready
|
||||
only `execute' needs to be implemented.
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed.
|
||||
|
||||
]"
|
||||
|
||||
class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: WSF_PAGE_RESPONSE
|
||||
do
|
||||
create page.make
|
||||
page.put_string ("Hello World")
|
||||
res.send (page)
|
||||
|
||||
--| another alternative would have been more low level
|
||||
--| by setting the status code, the content type, and the content length which is 11 for "Hello World"
|
||||
--| res.put_header ({WSF_HEADER}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
|
||||
--| res.put_string ("Hello World")
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -11,30 +11,31 @@ class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_RESPONSE_SERVICE
|
||||
WSF_LAUNCHABLE_SERVICE
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_and_launch
|
||||
initialize
|
||||
local
|
||||
launcher: WSF_DEFAULT_SERVICE_LAUNCHER
|
||||
opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
do
|
||||
--| Uncomment the following line, to read options from "ewf.ini" configuration file
|
||||
-- create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} opts.make_from_file ("ewf.ini")
|
||||
|
||||
create launcher.make_and_launch (Current, opts)
|
||||
Precursor
|
||||
--| Uncomment the following 2 lines, to read options from "ewf.ini" configuration file
|
||||
-- create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} opts.make_from_file ("ewf.ini")
|
||||
-- import_service_options (opts)
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
response (req: WSF_REQUEST): WSF_PAGE_RESPONSE
|
||||
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
launcher: WSF_DEFAULT_SERVICE_LAUNCHER [HELLO_EXECUTION]
|
||||
do
|
||||
create Result.make
|
||||
Result.put_string ("Hello World")
|
||||
create launcher.make_and_launch (opts)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
note
|
||||
description: "[
|
||||
Request execution for Current application.
|
||||
Implement `execute' based on `request' and `response'.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HELLO_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute
|
||||
local
|
||||
msg: WSF_PAGE_RESPONSE
|
||||
do
|
||||
create msg.make_with_body ("Hello World")
|
||||
response.send (msg)
|
||||
|
||||
--| alternative would have been more low level
|
||||
--| by setting the content type, and the content length which is 11 for "Hello World"
|
||||
-- response.header.put_content_type_text_plain
|
||||
-- response.header.put_content_length (11)
|
||||
-- response.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
note
|
||||
description: "[
|
||||
APPLICATION implements the `Hello World' service.
|
||||
|
||||
It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready
|
||||
only `execute' needs to be implemented.
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed.
|
||||
|
||||
]"
|
||||
|
||||
class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE [HELLO_EXECUTION]
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "[
|
||||
Request execution for Current application.
|
||||
Implement `message' based on `request' and `response'.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HELLO_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_MESSAGE_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Execution
|
||||
|
||||
message: WSF_PAGE_RESPONSE
|
||||
do
|
||||
create Result.make_with_body ("Hello World")
|
||||
response.send (Result)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -11,9 +11,10 @@
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\..\..\..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\..\..\..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\..\..\..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<cluster name="src" location=".\" />
|
||||
</target>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# For nino connector, use port 9999
|
||||
# For standalone connectors, use port 9999
|
||||
port=9999
|
||||
|
||||
#verbose=true
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</option>
|
||||
<precompile name="precomp_wsf" location="..\..\..\..\precomp\wsf-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
@@ -29,7 +29,7 @@
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<precompile name="precomp_wsf-mt" location="..\..\..\..\precomp\wsf-mt-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -2,19 +2,17 @@ note
|
||||
description: "[
|
||||
This class implements the `Hello World' service.
|
||||
|
||||
It inherits from WSF_DEFAULT_RESPONSE_SERVICE to get default EWF connector ready
|
||||
only `response' needs to be implemented.
|
||||
In this example, it is redefined and specialized to be WSF_PAGE_RESPONSE
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed.
|
||||
It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready
|
||||
only `HELLO_EXECUTION' needs to be implemented.
|
||||
|
||||
`initialize' is redefined to provide custom options if needed.
|
||||
]"
|
||||
|
||||
class
|
||||
CUSTOM_HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_RESPONSE_SERVICE
|
||||
WSF_DEFAULT_SERVICE [HELLO_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -32,7 +30,7 @@ feature {NONE} -- Initialization
|
||||
--| You can also uncomment the following line if you use the Nino connector
|
||||
--| so that the server listens on port 9999
|
||||
--| quite often the port 80 is already busy
|
||||
-- set_service_option ("port", 9999)
|
||||
set_service_option ("port", 9999)
|
||||
|
||||
--| Uncomment next line to have verbose option if available
|
||||
-- set_service_option ("verbose", True)
|
||||
@@ -41,13 +39,4 @@ feature {NONE} -- Initialization
|
||||
Precursor
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
response (req: WSF_REQUEST): WSF_PAGE_RESPONSE
|
||||
-- Computed response message.
|
||||
do
|
||||
create Result.make
|
||||
Result.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -2,30 +2,20 @@ note
|
||||
description: "[
|
||||
This class implements the `Hello World' service.
|
||||
|
||||
It inherits from WSF_DEFAULT_RESPONSE_SERVICE to get default EWF connector ready
|
||||
only `response' needs to be implemented.
|
||||
In this example, it is redefined and specialized to be WSF_PAGE_RESPONSE
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed.
|
||||
It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready.
|
||||
And implement HELLO_EXECUTION.
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed,
|
||||
such as specific port number.
|
||||
]"
|
||||
|
||||
class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_RESPONSE_SERVICE
|
||||
WSF_DEFAULT_SERVICE [HELLO_EXECUTION]
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
response (req: WSF_REQUEST): WSF_PAGE_RESPONSE
|
||||
-- Computed response message.
|
||||
do
|
||||
create Result.make
|
||||
Result.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
35
examples/tutorial/step_2/hello/src/hello_execution.e
Normal file
35
examples/tutorial/step_2/hello/src/hello_execution.e
Normal file
@@ -0,0 +1,35 @@
|
||||
note
|
||||
description: "[
|
||||
Request execution for Current application.
|
||||
Implement `execute' based on `request' and `response'.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HELLO_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute
|
||||
local
|
||||
msg: WSF_PAGE_RESPONSE
|
||||
do
|
||||
create msg.make_with_body ("Hello World")
|
||||
response.send (msg)
|
||||
|
||||
--| alternative would have been more low level
|
||||
--| by setting the content type, and the content length which is 11 for "Hello World"
|
||||
-- response.header.put_content_type_text_plain
|
||||
-- response.header.put_content_length (11)
|
||||
-- response.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
@@ -11,12 +11,12 @@ or go to [[step_4.wiki|step 4]]
|
||||
|
||||
== "hello" project ==
|
||||
* Let's start from the "hello_custom" project
|
||||
* you will learn how to use the req: WSF_REQUEST argument
|
||||
* you will learn how to use the request: WSF_REQUEST argument
|
||||
* See the hello project from [[step_3|step #3]] folder
|
||||
|
||||
* You can find code in [[step_3]] folder :
|
||||
|
||||
response (req: WSF_REQUEST): WSF_HTML_PAGE_RESPONSE
|
||||
message: WSF_HTML_PAGE_RESPONSE
|
||||
-- Computed response message.
|
||||
do
|
||||
--| It is now returning a WSF_HTML_PAGE_RESPONSE
|
||||
@@ -25,7 +25,7 @@ or go to [[step_4.wiki|step 4]]
|
||||
Result.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 l_user then
|
||||
if attached request.string_item ("user") as l_user then
|
||||
--| If yes, say hello world #name
|
||||
Result.set_body ("Hello " + l_user + "!")
|
||||
--| We should html encode this name
|
||||
@@ -43,8 +43,8 @@ or go to [[step_4.wiki|step 4]]
|
||||
end
|
||||
--| note:
|
||||
--| 1) Source of the parameter, we could have used
|
||||
--| req.query_parameter ("user") to search only in the query string
|
||||
--| req.form_parameter ("user") to search only in the form parameters
|
||||
--| request.query_parameter ("user") to search only in the query string
|
||||
--| request.form_parameter ("user") to search only in the form parameters
|
||||
--| 2) response type
|
||||
--| it could also have used WSF_PAGE_REPONSE, and build the html in the code
|
||||
--|
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<precompile name="precomp_wsf-mt" location="..\..\..\..\precomp\wsf-mt-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<cluster name="src" location=".\src" recursive="true"/>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
note
|
||||
description: "[
|
||||
This class implements the `Hello World' service.
|
||||
This class launch the HELLO_EXECUTION service.
|
||||
|
||||
It inherits from WSF_DEFAULT_RESPONSE_SERVICE to get default EWF connector ready
|
||||
only `response' needs to be implemented.
|
||||
In this example, it is redefined and specialized to be WSF_PAGE_RESPONSE
|
||||
It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready
|
||||
only `HELLO_EXECUTION' needs to be implemented.
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed.
|
||||
|
||||
@@ -14,7 +13,7 @@ class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_RESPONSE_SERVICE
|
||||
WSF_DEFAULT_SERVICE [HELLO_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -22,44 +21,6 @@ inherit
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
response (req: WSF_REQUEST): WSF_HTML_PAGE_RESPONSE
|
||||
-- Computed response message.
|
||||
do
|
||||
--| It is now returning a WSF_HTML_PAGE_RESPONSE
|
||||
--| Since it is easier for building html page
|
||||
create Result.make
|
||||
Result.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 l_user then
|
||||
--| If yes, say hello world #name
|
||||
Result.set_body ("Hello " + l_user + "!")
|
||||
--| We should html encode this name
|
||||
--| but to keep the example simple, we don't do that for now.
|
||||
else
|
||||
--| Otherwise, ask for name
|
||||
Result.set_body ("[
|
||||
<form action="/" method="POST">
|
||||
<p>Hello, what is your name?</p>
|
||||
<input type="text" name="user"/>
|
||||
<input type="submit" value="Validate"/>
|
||||
</form>
|
||||
]"
|
||||
)
|
||||
end
|
||||
|
||||
--| note:
|
||||
--| 1) Source of the parameter, we could have used
|
||||
--| req.query_parameter ("user") to search only in the query string
|
||||
--| req.form_parameter ("user") to search only in the form parameters
|
||||
--| 2) response type
|
||||
--| it could also have used WSF_PAGE_REPONSE, and build the html in the code
|
||||
--|
|
||||
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
|
||||
53
examples/tutorial/step_3/hello/src/hello_execution.e
Normal file
53
examples/tutorial/step_3/hello/src/hello_execution.e
Normal file
@@ -0,0 +1,53 @@
|
||||
note
|
||||
description: "Implementation of Hello world with form."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HELLO_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_MESSAGE_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
message: WSF_HTML_PAGE_RESPONSE
|
||||
-- Computed response message.
|
||||
do
|
||||
--| It is now returning a WSF_HTML_PAGE_RESPONSE
|
||||
--| Since it is easier for building html page
|
||||
create Result.make
|
||||
Result.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 request.string_item ("user") as l_user then
|
||||
--| If yes, say hello world #name
|
||||
Result.set_body ("Hello " + l_user + "!")
|
||||
--| We should html encode this name
|
||||
--| but to keep the example simple, we don't do that for now.
|
||||
else
|
||||
--| Otherwise, ask for name
|
||||
Result.set_body ("[
|
||||
<form action="/" method="POST">
|
||||
<p>Hello, what is your name?</p>
|
||||
<input type="text" name="user"/>
|
||||
<input type="submit" value="Validate"/>
|
||||
</form>
|
||||
]"
|
||||
)
|
||||
end
|
||||
|
||||
--| note:
|
||||
--| 1) Source of the parameter, we could have used
|
||||
--| request.query_parameter ("user") to search only in the query string
|
||||
--| request.form_parameter ("user") to search only in the form parameters
|
||||
--| 2) response type
|
||||
--| it could also have used WSF_PAGE_REPONSE, and build the html in the code
|
||||
--|
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -11,30 +11,30 @@ or go to the [[README.wiki|index]]
|
||||
|
||||
== "hello" project ==
|
||||
* Let's start from the "hello" project
|
||||
* you will learn how to use the req: WSF_ROUTER component
|
||||
* you will learn how to use the WSF_ROUTER component
|
||||
* See the hello project from [[step_4|step #4]] folder
|
||||
|
||||
* You can find code in [[step_4]] folder :
|
||||
|
||||
To get a routed service based on URI Template, your service application class should inherit from WSF_URI_TEMPLATE_ROUTED_SERVICE
|
||||
then you need to implement "setup_router", the following code is from the step_4 example
|
||||
To get a routed execution based on URI Template, your execution class should inherit from WSF_URI_TEMPLATE_ROUTED_EXECUTION
|
||||
then you need to implement "setup_router". In addition you can inherit from WSF_ROUTED_URI_HELPER and WSF_ROUTED_URI_TEMPLATE_HELPER, in order to call user-friendly routine provided to work easily with uri, or uri-template mapping. the following code is from the step_4 example
|
||||
|
||||
setup_router
|
||||
do
|
||||
router.map_agent ("/hello", agent execute_hello)
|
||||
map_uri_agent ("/hello", agent execute_hello, Void)
|
||||
|
||||
|
||||
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">>)
|
||||
map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>)
|
||||
map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>)
|
||||
|
||||
router.map_agent_response_with_request_methods ("/users/{user}/{?op}", agent response_user, <<"GET">>)
|
||||
map_uri_template_response_agent ("/users/{user}/{?op}", agent response_user, <<"GET">>)
|
||||
end
|
||||
|
||||
* map_agent is used to handle the url /hello with the feature "execute_hello"
|
||||
* map_agent_response_with_request_methods is similar but you precise the accepted request methods
|
||||
* map and map_with_request_method are similar to previous "agent" variant, but it is using a descendant of WSF_HANDLER to handle the related url.
|
||||
* map_agent_response is similar but you precise the accepted request methods
|
||||
* map is similar to previous "agent" variant, but it is using a descendant of WSF_HANDLER to handle the related request.
|
||||
|
||||
* In this example, we use the URI Template router, this allows to define the route using resource like /user/{user} , and then you get access to the "user" data from the WSF_REQUEST.path_parameter or using the context argument passed for the execute or response handler.
|
||||
* In this example, we use the URI-Template router, this allows to define the route using resource like /user/{user} , and then you get access to the "user" data from the WSF_REQUEST.path_parameter or using the context argument passed for the execute or response handler.
|
||||
|
||||
* The example also includes basic notions of url, html encoding, check the hello.ecf to see the added libraries (http to get easy access to the http status code, encoder for simple encoding components)
|
||||
----
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\..\..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="../../../../library/network/protocol/http/http-safe.ecf" readonly="false"/>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
This class implements the `Hello World' service.
|
||||
|
||||
It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready
|
||||
And from WSF_URI_TEMPLATE_ROUTED_SERVICE to use the router service
|
||||
|
||||
`initialize' can be redefine to provide custom options if needed.
|
||||
|
||||
@@ -13,9 +12,7 @@ class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_SERVICE
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [HELLO_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,136 +20,6 @@ inherit
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
setup_router
|
||||
do
|
||||
-- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello)))
|
||||
map_agent_uri ("/hello", agent execute_hello, Void)
|
||||
|
||||
-- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST)
|
||||
map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST)
|
||||
|
||||
-- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}), router.methods_GET_POST)
|
||||
map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, router.methods_GET_POST)
|
||||
|
||||
-- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/{?op}", create {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.make (agent response_user)), router.methods_GET)
|
||||
map_agent_uri_template_response ("/users/{user}/{?op}", agent response_user, router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
map_uri_template (a_tpl: READABLE_STRING_8; a_handler: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, a_handler), rqst_methods)
|
||||
end
|
||||
|
||||
map_agent_uri_template_response (a_tpl: READABLE_STRING_8; a_action: like {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, create {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Computed response message.
|
||||
local
|
||||
mesg: WSF_HTML_PAGE_RESPONSE
|
||||
s: STRING_8
|
||||
l_user_name: READABLE_STRING_32
|
||||
do
|
||||
--| It is now returning a WSF_HTML_PAGE_RESPONSE
|
||||
--| Since it is easier for building html page
|
||||
create mesg.make
|
||||
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 {WSF_STRING} req.item ("user") as u then
|
||||
--| If yes, say hello world #name
|
||||
|
||||
l_user_name := (create {HTML_ENCODER}).decoded_string (u.value)
|
||||
|
||||
s := "<p>Hello " + mesg.html_encoded_string (l_user_name) + "!</p>"
|
||||
s.append ("Display a <a href=%"/users/" + u.url_encoded_value + "/message/%">message</a></p>")
|
||||
s.append ("<p>Click <a href=%"/users/" + u.url_encoded_value + "/?op=quit%">here</a> to quit.</p>")
|
||||
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
|
||||
s := (create {HTML_ENCODER}).encoded_string ({STRING_32} "Hello / ahoj / नमस्ते / Ciào / مرحبا / Hola / 你好 / Hallo / Selam / Bonjour ")
|
||||
s.append ("[
|
||||
<form action="/hello" method="GET">
|
||||
What is your name?</p>
|
||||
<input type="text" name="user"/>
|
||||
<input type="submit" value="Validate"/>
|
||||
</form>
|
||||
]"
|
||||
)
|
||||
mesg.set_body (s)
|
||||
end
|
||||
|
||||
--| note:
|
||||
--| 1) Source of the parameter, we could have used
|
||||
--| req.query_parameter ("user") to search only in the query string
|
||||
--| req.form_parameter ("user") to search only in the form parameters
|
||||
--| 2) response type
|
||||
--| it could also have used WSF_PAGE_REPONSE, and build the html in the code
|
||||
--|
|
||||
|
||||
res.send (mesg)
|
||||
end
|
||||
|
||||
response_user (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
-- Computed response message.
|
||||
local
|
||||
html: WSF_HTML_PAGE_RESPONSE
|
||||
redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE
|
||||
s: STRING_8
|
||||
l_username: STRING_32
|
||||
do
|
||||
if attached {WSF_STRING} req.path_parameter ("user") as u then
|
||||
l_username := (create {HTML_ENCODER}).general_decoded_string (u.value)
|
||||
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"), 3)
|
||||
create html.make
|
||||
redir.set_title ("Bye " + html.html_encoded_string (l_username))
|
||||
redir.set_body ("Bye " + html.html_encoded_string (l_username) + ",<br/> see you soon.<p>You will be redirected to " +
|
||||
redir.url_location + " in " + redir.delay.out + " second(s) ...</p>"
|
||||
)
|
||||
Result := redir
|
||||
else
|
||||
create html.make
|
||||
html.set_title ("Bad request")
|
||||
html.set_body ("Bad request: unknown operation '" + l_op.url_encoded_value + "'.")
|
||||
Result := html
|
||||
end
|
||||
else
|
||||
create html.make
|
||||
|
||||
s := "<p>User <em>'" + html.html_encoded_string (l_username) + "'</em>!</p>"
|
||||
s.append ("Display a <a href=%"/users/" + u.url_encoded_value + "/message/%">message</a></p>")
|
||||
s.append ("<p>Click <a href=%"/users/" + u.url_encoded_value + "/?op=quit%">here</a> to quit.</p>")
|
||||
html.set_title ("User '" + u.url_encoded_value + "'")
|
||||
html.set_body (s)
|
||||
Result := html
|
||||
end
|
||||
else
|
||||
create html.make
|
||||
html.set_title ("Bad request")
|
||||
html.set_body ("Bad request: missing user parameter")
|
||||
Result := html
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
@@ -163,8 +30,6 @@ feature {NONE} -- Initialization
|
||||
--| If you don't need any custom options, you are not obliged to redefine `initialize'
|
||||
Precursor
|
||||
|
||||
--| Initialize router
|
||||
initialize_router
|
||||
end
|
||||
|
||||
|
||||
|
||||
135
examples/tutorial/step_4/hello/src/hello_execution.e
Normal file
135
examples/tutorial/step_4/hello/src/hello_execution.e
Normal file
@@ -0,0 +1,135 @@
|
||||
note
|
||||
description: "[
|
||||
This class implements the `Hello World' execution service.
|
||||
|
||||
It inherits from WSF_ROUTED_EXECUTION to use the router service
|
||||
and from WSF_ROUTED_URI_TEMPLATE_HELPER to use help feature to map
|
||||
uri-template routes
|
||||
]"
|
||||
|
||||
class
|
||||
HELLO_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_EXECUTION
|
||||
|
||||
WSF_ROUTED_URI_HELPER
|
||||
WSF_ROUTED_URI_TEMPLATE_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
setup_router
|
||||
do
|
||||
-- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello)))
|
||||
map_uri_agent ("/hello", agent execute_hello)
|
||||
|
||||
-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST)
|
||||
map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST)
|
||||
|
||||
-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}), router.methods_GET_POST)
|
||||
map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, router.methods_GET_POST)
|
||||
|
||||
-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/{?op}", create {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.make (agent response_user)), router.methods_GET)
|
||||
map_uri_template_response_agent ("/users/{user}/{?op}", agent response_user, router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Computed response message.
|
||||
local
|
||||
mesg: WSF_HTML_PAGE_RESPONSE
|
||||
s: STRING_8
|
||||
l_user_name: READABLE_STRING_32
|
||||
do
|
||||
--| It is now returning a WSF_HTML_PAGE_RESPONSE
|
||||
--| Since it is easier for building html page
|
||||
create mesg.make
|
||||
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 {WSF_STRING} req.item ("user") as u then
|
||||
--| If yes, say hello world #name
|
||||
|
||||
l_user_name := (create {HTML_ENCODER}).decoded_string (u.value)
|
||||
|
||||
s := "<p>Hello " + mesg.html_encoded_string (l_user_name) + "!</p>"
|
||||
s.append ("Display a <a href=%"/users/" + u.url_encoded_value + "/message/%">message</a></p>")
|
||||
s.append ("<p>Click <a href=%"/users/" + u.url_encoded_value + "/?op=quit%">here</a> to quit.</p>")
|
||||
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
|
||||
s := (create {HTML_ENCODER}).encoded_string ({STRING_32} "Hello / ahoj / नमस्ते / Ciào / مرحبا / Hola / 你好 / Hallo / Selam / Bonjour ")
|
||||
s.append ("[
|
||||
<form action="/hello" method="GET">
|
||||
What is your name?</p>
|
||||
<input type="text" name="user"/>
|
||||
<input type="submit" value="Validate"/>
|
||||
</form>
|
||||
]"
|
||||
)
|
||||
mesg.set_body (s)
|
||||
end
|
||||
|
||||
--| note:
|
||||
--| 1) Source of the parameter, we could have used
|
||||
--| req.query_parameter ("user") to search only in the query string
|
||||
--| req.form_parameter ("user") to search only in the form parameters
|
||||
--| 2) response type
|
||||
--| it could also have used WSF_PAGE_REPONSE, and build the html in the code
|
||||
--|
|
||||
|
||||
res.send (mesg)
|
||||
end
|
||||
|
||||
response_user (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
-- Computed response message.
|
||||
local
|
||||
html: WSF_HTML_PAGE_RESPONSE
|
||||
redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE
|
||||
s: STRING_8
|
||||
l_username: STRING_32
|
||||
do
|
||||
if attached {WSF_STRING} req.path_parameter ("user") as u then
|
||||
l_username := (create {HTML_ENCODER}).general_decoded_string (u.value)
|
||||
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"), 3)
|
||||
create html.make
|
||||
redir.set_title ("Bye " + html.html_encoded_string (l_username))
|
||||
redir.set_body ("Bye " + html.html_encoded_string (l_username) + ",<br/> see you soon.<p>You will be redirected to " +
|
||||
redir.url_location + " in " + redir.delay.out + " second(s) ...</p>"
|
||||
)
|
||||
Result := redir
|
||||
else
|
||||
create html.make
|
||||
html.set_title ("Bad request")
|
||||
html.set_body ("Bad request: unknown operation '" + l_op.url_encoded_value + "'.")
|
||||
Result := html
|
||||
end
|
||||
else
|
||||
create html.make
|
||||
|
||||
s := "<p>User <em>'" + html.html_encoded_string (l_username) + "'</em>!</p>"
|
||||
s.append ("Display a <a href=%"/users/" + u.url_encoded_value + "/message/%">message</a></p>")
|
||||
s.append ("<p>Click <a href=%"/users/" + u.url_encoded_value + "/?op=quit%">here</a> to quit.</p>")
|
||||
html.set_title ("User '" + u.url_encoded_value + "'")
|
||||
html.set_body (s)
|
||||
Result := html
|
||||
end
|
||||
else
|
||||
create html.make
|
||||
html.set_title ("Bad request")
|
||||
html.set_body ("Bad request: missing user parameter")
|
||||
Result := html
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -37,13 +37,13 @@ feature {NONE} -- Initialization
|
||||
local
|
||||
www: WSF_FILE_SYSTEM_HANDLER
|
||||
do
|
||||
map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
|
||||
map_uri_template_agent ("/upload{?nb}", agent execute_upload)
|
||||
map_uri_template_agent ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
|
||||
map_uri_template_agent ("/upload{?nb}", agent execute_upload, Void)
|
||||
|
||||
create www.make_with_path (document_root)
|
||||
www.set_directory_index (<<"index.html">>)
|
||||
www.set_not_found_handler (agent execute_not_found)
|
||||
router.handle_with_request_methods ("", www, router.methods_GET)
|
||||
router.handle ("", www, router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Configuration
|
||||
|
||||
@@ -29,8 +29,8 @@ feature {NONE} -- Initialization
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_uri_template_agent ("/", agent handle_root)
|
||||
map_uri_template_agent ("/openid", agent handle_openid)
|
||||
map_uri_template_agent ("/", agent handle_root, Void)
|
||||
map_uri_template_agent ("/openid", agent handle_openid, Void)
|
||||
end
|
||||
|
||||
handle_root (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
|
||||
@@ -200,43 +200,31 @@ feature -- SSL Helpers
|
||||
set_ssl_protocol_to_ssl_2_or_3
|
||||
-- Set `ssl_protocol' with `Ssl_23'.
|
||||
deferred
|
||||
ensure
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Ssl_23
|
||||
end
|
||||
|
||||
set_ssl_protocol_to_ssl_3
|
||||
-- Set `ssl_protocol' with `Ssl_3'.
|
||||
deferred
|
||||
ensure
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Ssl_3
|
||||
end
|
||||
|
||||
set_ssl_protocol_to_tls_1_0
|
||||
-- Set `ssl_protocol' with `Tls_1_0'.
|
||||
deferred
|
||||
ensure
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Tls_1_0
|
||||
end
|
||||
|
||||
set_ssl_protocol_to_tls_1_1
|
||||
-- Set `ssl_protocol' with `Tls_1_1'.
|
||||
deferred
|
||||
ensure
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Tls_1_1
|
||||
end
|
||||
|
||||
set_ssl_protocol_to_tls_1_2
|
||||
-- Set `ssl_protocol' with `Tls_1_2'.
|
||||
deferred
|
||||
ensure
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Tls_1_2
|
||||
end
|
||||
|
||||
set_ssl_protocol_to_dtls_1_0
|
||||
-- Set `ssl_protocol' with `Dtls_1_0'.
|
||||
deferred
|
||||
ensure
|
||||
ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Dtls_1_0
|
||||
end
|
||||
|
||||
note
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_disabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
</file_rule>
|
||||
<cluster name="no_ssl" location="$|no_ssl" recursive="true">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_disabled" value="true"/>
|
||||
<custom name="httpd_ssl_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="ssl" location="$|ssl" recursive="true">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_disabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_disabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
</file_rule>
|
||||
<cluster name="no_ssl" location="$|no_ssl" recursive="true">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_disabled" value="true"/>
|
||||
<custom name="httpd_ssl_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="ssl" location="$|ssl" recursive="true">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_disabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user