Compare commits
143 Commits
Review_EWS
...
WGI_2011_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eaa99c9c61 | ||
|
|
5f492d6fb6 | ||
|
|
c3f5376ef5 | ||
|
|
21e973f8a4 | ||
|
|
dec1958909 | ||
|
|
1453873b6c | ||
|
|
4c36d75ef3 | ||
|
|
09030a27d9 | ||
|
|
b9ca22006b | ||
|
|
593b48fe90 | ||
|
|
735730b5a0 | ||
|
|
035a133b5b | ||
|
|
0144e97d69 | ||
|
|
26bfd72f5f | ||
|
|
88542c2762 | ||
|
|
12fc54a403 | ||
|
|
eb44eef885 | ||
|
|
c2b66d6ca6 | ||
|
|
6758c4aef4 | ||
|
|
6408bec628 | ||
|
|
f77ba9ccd8 | ||
|
|
c105c267e7 | ||
|
|
19da4d6fd0 | ||
|
|
a9e2dc1135 | ||
|
|
142dbc39b4 | ||
|
|
b17887d634 | ||
|
|
f443087e71 | ||
|
|
e5eb11b4e7 | ||
|
|
720d8be08a | ||
|
|
ed04b7fba0 | ||
|
|
4c9e7a4331 | ||
|
|
cc6992a6fc | ||
|
|
71c851ca39 | ||
|
|
900ed8baea | ||
|
|
dba55fcfd9 | ||
|
|
456299ccdf | ||
|
|
810208f176 | ||
|
|
27c637b066 | ||
|
|
a0df04a7f2 | ||
|
|
bc5d20b221 | ||
|
|
7ba3eb9ecd | ||
|
|
2b14a40898 | ||
|
|
aa20a1423f | ||
|
|
34c8cfa427 | ||
|
|
f7dcadccd5 | ||
|
|
f24df1d745 | ||
|
|
5adf40a9ed | ||
|
|
f20bc42b76 | ||
|
|
a4df57a7ac | ||
|
|
df59ae579b | ||
|
|
738eb7555f | ||
|
|
d397d4e35d | ||
|
|
eeaa47d4f1 | ||
|
|
0db4317a49 | ||
|
|
668847f8e8 | ||
|
|
e7fd7af2c5 | ||
|
|
24a5c7613d | ||
|
|
d9f6cbe80e | ||
|
|
95ec2e77df | ||
|
|
19b5edd9b4 | ||
|
|
d25146dd27 | ||
|
|
ab1c696837 | ||
|
|
dae8e1d67d | ||
|
|
888bc61522 | ||
|
|
8291905da1 | ||
|
|
d9ba97d33b | ||
|
|
33eddd9197 | ||
|
|
458cb56f75 | ||
|
|
88c015470e | ||
|
|
f68a713c48 | ||
|
|
0414cd4501 | ||
|
|
284d7826c8 | ||
|
|
dff267cd58 | ||
|
|
c2f7c198e0 | ||
|
|
b3ef7c846b | ||
|
|
111812c4e9 | ||
|
|
92d8357d09 | ||
|
|
64060cfa41 | ||
|
|
d3239ec41b | ||
|
|
7b1557a52a | ||
|
|
c9a4ebcb23 | ||
|
|
3f899f6aae | ||
|
|
18684d167b | ||
|
|
32bb75b9dc | ||
|
|
d06bc76944 | ||
|
|
86825854ca | ||
|
|
774cd004db | ||
|
|
c300cf5b6e | ||
|
|
68247a1849 | ||
|
|
22fd7490fe | ||
|
|
8b6e9273fa | ||
|
|
76fa3e9ff5 | ||
|
|
1e3770d724 | ||
|
|
840ae1e6e4 | ||
|
|
5626e03aa8 | ||
|
|
4bcea900a6 | ||
|
|
b1f5065e63 | ||
|
|
c37fe9ad79 | ||
|
|
2e53f7e0c4 | ||
|
|
512f2d2ce5 | ||
|
|
92105ca7b3 | ||
|
|
f0c6eec23d | ||
|
|
32197d0513 | ||
|
|
11286eeeef | ||
|
|
fb8412fcae | ||
|
|
9ec87a4329 | ||
|
|
0c7e6c08e7 | ||
|
|
c1120a4226 | ||
|
|
5c0cae35ef | ||
|
|
7bd5cdc232 | ||
|
|
ef85c07603 | ||
|
|
10db3c28a5 | ||
|
|
54dc7de189 | ||
|
|
2244d101ea | ||
|
|
244fdf1b02 | ||
|
|
3c9fce293f | ||
|
|
eee085dd5a | ||
|
|
2d9e2d12a0 | ||
|
|
6a581f6d62 | ||
|
|
ed8f5d694f | ||
|
|
c20600f281 | ||
|
|
53ccaa3fde | ||
|
|
22afbd7ed0 | ||
|
|
f6b362217c | ||
|
|
e9ccf855b3 | ||
|
|
4d0148d562 | ||
|
|
ec6cc5f2b8 | ||
|
|
40018d36eb | ||
|
|
8e18329063 | ||
|
|
c372494713 | ||
|
|
10f4a99ee1 | ||
|
|
e9085c614c | ||
|
|
f7d3f519a7 | ||
|
|
4eb22d0272 | ||
|
|
bbcc9ef44b | ||
|
|
801caa4e69 | ||
|
|
1b49445077 | ||
|
|
f005d8bb06 | ||
|
|
a278537f7b | ||
|
|
78b5b6f5fe | ||
|
|
a215c1e4d2 | ||
|
|
fe3726677b | ||
|
|
94d4909644 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
EIFGENs
|
||||
tests/temp/
|
||||
.svn/
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -7,3 +7,6 @@
|
||||
[submodule "ext/text/json"]
|
||||
path = ext/text/json
|
||||
url = http://github.com/Eiffel-World/ejson-svn.git
|
||||
[submodule "ext/ise_library/curl"]
|
||||
path = ext/ise_library/curl
|
||||
url = http://github.com/EiffelSoftware/mirror-Eiffel-cURL.git
|
||||
|
||||
38
CHANGELOGS.txt
Normal file
38
CHANGELOGS.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
History for Eiffel-Web-Framework
|
||||
|
||||
[2011-09-23] Jocelyn
|
||||
* library "ewsgi":
|
||||
- NEW simple autotest cases using Nino web server
|
||||
-fixed issue with RAW_POST_DATA being added in form_data_parameters
|
||||
instead of meta_variables ...
|
||||
- Implemented WGI_VALUE for parameter's type (query_parameter,
|
||||
form_data_parameter, item ...)
|
||||
* Nino connector: added feature to shutdown the server from the WGI application
|
||||
* NEW library "http_client": a new library to perform simple http requests
|
||||
such as get, head, post, put, ... (currently implemented with Eiffel cURL)
|
||||
* NEW library "http_authorization": added simple library to support
|
||||
HTTP_AUTHORIZATION. For now only "Basic" auth type is supported ..
|
||||
|
||||
[2011-09-22] Javier
|
||||
* NEW Example: added partial Restbuck example
|
||||
|
||||
[2011-09-21] Jocelyn
|
||||
* Nino connector: fixed an issue with missing value for Content-Type and Content-Length
|
||||
|
||||
[2011-09-13] Jocelyn
|
||||
* library "router": now using a generic design to allow customization of
|
||||
request handler context class.
|
||||
* NEW library "server/request/rest": first attempt to provide a library to
|
||||
help building RESTful application (the interfaces are likely to change
|
||||
soon) EXPERIMENTAL
|
||||
|
||||
[2011-09-09] Jocelyn
|
||||
* library "uri-template": better support for {/vars} and {?vars}
|
||||
|
||||
[2011-09-07] Jocelyn
|
||||
* library "router": now routing depends on uri (or uri template) and request methods
|
||||
* Nino connector: Fixed issue where HTTP_ prefix were missing for header meta variable.
|
||||
|
||||
[2011-09-07] Jocelyn
|
||||
* changelog: starting to write down changelogs file
|
||||
|
||||
19
README.md
19
README.md
@@ -1,5 +1,5 @@
|
||||
Official project site for Eiffel Web Framework:
|
||||
* https://github.com/Eiffel-World/Eiffel-Web-Framework
|
||||
* http://eiffel-world.github.com/Eiffel-Web-Framework/
|
||||
|
||||
For more information please have a look at the related wiki:
|
||||
* https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki
|
||||
@@ -7,11 +7,15 @@ For more information please have a look at the related wiki:
|
||||
How to get the source code?
|
||||
---------------------------
|
||||
|
||||
git clone https://github.com/Eiffel-World/Eiffel-Web-Framework.git
|
||||
cd Eiffel-Web-Framework
|
||||
git submodule update --init
|
||||
git submodule foreach git pull origin master
|
||||
git submodule foreach git checkout master
|
||||
* git clone https://github.com/Eiffel-World/Eiffel-Web-Framework.git
|
||||
* cd Eiffel-Web-Framework
|
||||
* git submodule update --init
|
||||
* git submodule foreach git pull origin master
|
||||
* git submodule foreach git checkout master
|
||||
|
||||
* And to build the required and related Clibs
|
||||
** cd ext/ise_library/curl
|
||||
** geant compile
|
||||
|
||||
Overview
|
||||
--------
|
||||
@@ -20,6 +24,9 @@ Overview
|
||||
* library/server/ewsgi/connectors: various web server connectors for EWSGI
|
||||
* library/server/libfcgi: Wrapper for libfcgi SDK
|
||||
|
||||
* library/server/request/router: URL dispatching/routing based on uri, uri_template, or custom.
|
||||
* library/server/request/rest: experimental: RESTful library to help building RESTful services
|
||||
|
||||
* library/protocol/http: HTTP related classes, constants for status code, content types, ...
|
||||
* library/protocol/uri_template: URI Template library (parsing and expander)
|
||||
|
||||
|
||||
BIN
doc/http-activity-diagram.png
Normal file
BIN
doc/http-activity-diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
BIN
doc/http-headers-status-v3.png
Normal file
BIN
doc/http-headers-status-v3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 403 KiB |
2
doc/wiki
2
doc/wiki
Submodule doc/wiki updated: c7f4f45f5e...2b112da43d
24
examples/hello_routed_world/hello-safe.ecf
Normal file
24
examples/hello_routed_world/hello-safe.ecf
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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="hello_routed_world" uuid="7C9887BD-4AE4-47F2-A0AA-4BBB6736D433">
|
||||
<target name="hello_routed_world">
|
||||
<root class="HELLO_ROUTED_WORLD" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<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"/>
|
||||
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\library\server\ewsgi\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\library\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="router" location="..\..\library\server\request\router\router-safe.ecf" readonly="false"/>
|
||||
<library name="uri_template" location="..\..\library\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
9
examples/hello_routed_world/htdocs/dft/index.html
Normal file
9
examples/hello_routed_world/htdocs/dft/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello Eiffel::default</title>
|
||||
<link rel="stylesheet" href="../style.css" type="text/css" media="all" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello Eiffel Default World</h1>
|
||||
</body>
|
||||
</html>
|
||||
9
examples/hello_routed_world/htdocs/home.html
Normal file
9
examples/hello_routed_world/htdocs/home.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello Eiffel</title>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" media="all" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello Eiffel World :D</h1>
|
||||
</body>
|
||||
</html>
|
||||
BIN
examples/hello_routed_world/htdocs/htdocs.zip
Normal file
BIN
examples/hello_routed_world/htdocs/htdocs.zip
Normal file
Binary file not shown.
1
examples/hello_routed_world/htdocs/style.css
Normal file
1
examples/hello_routed_world/htdocs/style.css
Normal file
@@ -0,0 +1 @@
|
||||
h1 { border: solid 1px #00f; margin: 5px; padding: 5px; }
|
||||
10
examples/hello_routed_world/license.lic
Normal file
10
examples/hello_routed_world/license.lic
Normal file
@@ -0,0 +1,10 @@
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
1479
examples/hello_routed_world/mime.types
Normal file
1479
examples/hello_routed_world/mime.types
Normal file
File diff suppressed because it is too large
Load Diff
253
examples/hello_routed_world/src/hello_routed_world.e
Normal file
253
examples/hello_routed_world/src/hello_routed_world.e
Normal file
@@ -0,0 +1,253 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
HELLO_ROUTED_WORLD
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
URI_TEMPLATE_ROUTED_APPLICATION
|
||||
|
||||
ROUTED_APPLICATION_HELPER
|
||||
|
||||
DEFAULT_WGI_APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
|
||||
make
|
||||
do
|
||||
initialize_router
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
create_router
|
||||
do
|
||||
create router.make (5)
|
||||
end
|
||||
|
||||
setup_router
|
||||
local
|
||||
ra: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
hello: REQUEST_URI_TEMPLATE_ROUTING_HANDLER
|
||||
www: REQUEST_FILE_SYSTEM_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
router.map_agent ("/home", agent execute_home)
|
||||
create www.make (document_root)
|
||||
www.set_directory_index (<<"index.html">>)
|
||||
|
||||
router.map ("/www{/path}{?query}", www)
|
||||
|
||||
--| Map all "/hello*" using a ROUTING_HANDLER
|
||||
create hello.make (3)
|
||||
router.map ("/hello", hello)
|
||||
|
||||
create ra.make (agent handle_hello)
|
||||
hello.map ("/hello/{name}.{format}", ra)
|
||||
hello.map ("/hello.{format}/{name}", ra)
|
||||
hello.map ("/hello/{name}", ra)
|
||||
|
||||
create ra.make (agent handle_anonymous_hello)
|
||||
hello.map ("/hello", ra)
|
||||
hello.map ("/hello.{format}", ra)
|
||||
|
||||
--| Various various route, directly on the "router"
|
||||
router.map_agent_with_request_methods ("/method/any", agent handle_method_any, Void)
|
||||
router.map_agent_with_request_methods ("/method/guess", agent handle_method_get_or_post, <<"GET", "POST">>)
|
||||
router.map_agent_with_request_methods ("/method/custom", agent handle_method_get, <<"GET">>)
|
||||
router.map_agent_with_request_methods ("/method/custom", agent handle_method_post, <<"POST">>)
|
||||
end
|
||||
|
||||
|
||||
document_root: READABLE_STRING_8
|
||||
local
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
dn: DIRECTORY_NAME
|
||||
once
|
||||
create e
|
||||
create dn.make_from_string (e.current_working_directory)
|
||||
dn.extend ("htdocs")
|
||||
Result := dn.string
|
||||
if Result[Result.count] = Operating_environment.directory_separator then
|
||||
Result := Result.substring (1, Result.count - 1)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_default (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
local
|
||||
h: EWF_HEADER
|
||||
l_url: STRING
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
n: INTEGER
|
||||
i: INTEGER
|
||||
s: STRING_8
|
||||
do
|
||||
l_url := req.script_url ("/home")
|
||||
n := 3
|
||||
create h.make
|
||||
h.put_refresh (l_url, 5)
|
||||
h.put_content_type_text_plain
|
||||
h.put_transfer_encoding_chunked
|
||||
-- h.put_content_length (0)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.moved_permanently)
|
||||
res.write_headers_string (h.string)
|
||||
|
||||
from
|
||||
create e
|
||||
create s.make (255)
|
||||
until
|
||||
n = 0
|
||||
loop
|
||||
if n > 1 then
|
||||
s.append ("%NRedirected to " + l_url + " in " + n.out + " seconds :%N")
|
||||
else
|
||||
s.append ("%NRedirected to " + l_url + " in 1 second :%N")
|
||||
end
|
||||
write_chunk (s, res); s.wipe_out
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i = 1001
|
||||
loop
|
||||
s.append_character ('.')
|
||||
if i \\ 100 = 0 then
|
||||
s.append_character ('%N')
|
||||
end
|
||||
write_chunk (s, res); s.wipe_out
|
||||
e.sleep (1_000_000)
|
||||
i := i + 1
|
||||
end
|
||||
n := n - 1
|
||||
end
|
||||
s.append ("%NYou are now being redirected...%N")
|
||||
write_chunk (s, res); s.wipe_out
|
||||
write_chunk (Void, res)
|
||||
end
|
||||
|
||||
write_chunk (s: detachable READABLE_STRING_8; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
if s /= Void then
|
||||
res.write_string (s.count.to_hex_string + {HTTP_CONSTANTS}.crlf)
|
||||
res.write_string (s)
|
||||
else
|
||||
res.write_string ("0" + {HTTP_CONSTANTS}.crlf)
|
||||
end
|
||||
res.flush
|
||||
end
|
||||
|
||||
execute_home (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
local
|
||||
l_body: STRING_8
|
||||
do
|
||||
create l_body.make (255)
|
||||
l_body.append ("<html><body>Hello World ?!%N")
|
||||
l_body.append ("<h3>Please try the following links</h3><ul>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/") + "%">default</a></li>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/hello") + "%">/hello</a></li>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/hello.html/Joce") + "%">/hello.html/Joce</a></li>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/hello.json/Joce") + "%">/hello.json/Joce</a></li>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/hello/Joce.html") + "%">/hello/Joce.html</a></li>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/hello/Joce.xml") + "%">/hello/Joce.xml</a></li>%N")
|
||||
l_body.append ("<li><a href=%""+ req.script_url ("/hello/Joce") + "%">/hello/Joce</a></li>%N")
|
||||
l_body.append ("</ul>%N")
|
||||
if attached req.item ("REQUEST_COUNT") as rqc then
|
||||
l_body.append ("request #"+ rqc.as_string + "%N")
|
||||
end
|
||||
l_body.append ("</body></html>%N")
|
||||
|
||||
res.write_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_body.count.out]>>)
|
||||
res.write_string (l_body)
|
||||
end
|
||||
|
||||
execute_hello (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_name: detachable READABLE_STRING_32; ctx: REQUEST_HANDLER_CONTEXT)
|
||||
local
|
||||
l_response_content_type: detachable STRING
|
||||
h: EWF_HEADER
|
||||
content_type_supported: ARRAY [STRING]
|
||||
l_body: STRING_8
|
||||
do
|
||||
if a_name /= Void then
|
||||
l_body := "Hello %"" + a_name + "%" !%N"
|
||||
else
|
||||
l_body := "Hello anonymous visitor !%N"
|
||||
end
|
||||
content_type_supported := <<{HTTP_MIME_TYPES}.application_json, {HTTP_MIME_TYPES}.text_html, {HTTP_MIME_TYPES}.text_xml, {HTTP_MIME_TYPES}.text_plain>>
|
||||
inspect ctx.request_format_id ("format", content_type_supported)
|
||||
when {HTTP_FORMAT_CONSTANTS}.json then
|
||||
l_response_content_type := {HTTP_MIME_TYPES}.application_json
|
||||
l_body := "{%N%"application%": %"/hello%",%N %"message%": %"" + l_body + "%" %N}"
|
||||
when {HTTP_FORMAT_CONSTANTS}.html then
|
||||
l_response_content_type := {HTTP_MIME_TYPES}.text_html
|
||||
when {HTTP_FORMAT_CONSTANTS}.xml then
|
||||
l_response_content_type := {HTTP_MIME_TYPES}.text_xml
|
||||
l_body := "<response><application>/hello</application><message>" + l_body + "</message></response>%N"
|
||||
when {HTTP_FORMAT_CONSTANTS}.text then
|
||||
l_response_content_type := {HTTP_MIME_TYPES}.text_plain
|
||||
else
|
||||
execute_content_type_not_allowed (req, res, content_type_supported,
|
||||
<<{HTTP_FORMAT_CONSTANTS}.json_name, {HTTP_FORMAT_CONSTANTS}.html_name, {HTTP_FORMAT_CONSTANTS}.xml_name, {HTTP_FORMAT_CONSTANTS}.text_name>>
|
||||
)
|
||||
end
|
||||
if l_response_content_type /= Void then
|
||||
create h.make
|
||||
h.put_content_type (l_response_content_type)
|
||||
h.put_content_length (l_body.count)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.write_headers_string (h.string)
|
||||
res.write_string (l_body)
|
||||
end
|
||||
end
|
||||
|
||||
handle_hello (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, Void, ctx)
|
||||
end
|
||||
|
||||
handle_anonymous_hello (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, ctx.string_parameter ("name"), ctx)
|
||||
end
|
||||
|
||||
handle_method_any (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, req.request_method, ctx)
|
||||
end
|
||||
|
||||
handle_method_get (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, "GET", ctx)
|
||||
end
|
||||
|
||||
|
||||
handle_method_post (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, "POST", ctx)
|
||||
end
|
||||
|
||||
handle_method_get_or_post (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, "GET or POST", ctx)
|
||||
end
|
||||
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
19
examples/restbucks/client/client-safe.ecf
Normal file
19
examples/restbucks/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-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="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" 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\client\http_client\http_client-safe.ecf" readonly="false"/>
|
||||
<library name="json" location="..\..\..\ext\text\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/restbucks/client/client.ecf
Normal file
19
examples/restbucks/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\client\http_client\http_client.ecf"/>
|
||||
<library name="json" location="..\..\..\ext\text\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>
|
||||
72
examples/restbucks/client/src/restbuck_client.e
Normal file
72
examples/restbucks/client/src/restbuck_client.e
Normal file
@@ -0,0 +1,72 @@
|
||||
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
|
||||
s: READABLE_STRING_8
|
||||
j: JSON_PARSER
|
||||
id: detachable STRING
|
||||
do
|
||||
create h.make
|
||||
sess := h.new_session ("http://127.0.0.1")
|
||||
s := "[
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]"
|
||||
|
||||
if attached sess.post ("/order", Void, s) as r then
|
||||
if attached r.body as m then
|
||||
create j.make_parser (m)
|
||||
|
||||
if j.is_parsed and attached j.parse_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
|
||||
|
||||
if id /= Void and then attached sess.get ("/order/" + id, Void) as r then
|
||||
print (r.body)
|
||||
io.put_new_line
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
feature -- Access
|
||||
|
||||
feature -- Change
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
invariant
|
||||
-- invariant_clause: True
|
||||
|
||||
end
|
||||
4
examples/restbucks/license.lic
Normal file
4
examples/restbucks/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)"
|
||||
|
||||
51
examples/restbucks/readme.txt
Normal file
51
examples/restbucks/readme.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
Restbuck Eiffel Implementation based on the book of REST in Practice
|
||||
|
||||
|
||||
Verb URI or template Use
|
||||
POST /order Create a new order, and upon success, receive a Locationheader specifying the new order<65>s URI.
|
||||
GET /order/{orderId} Request the current state of the order specified by the URI.
|
||||
PUT /order/{orderId} Update an order at the given URI with new information, providing the full representation.
|
||||
DELETE /order/{orderId} Logically remove the order identified by the given URI.
|
||||
|
||||
|
||||
How to Create an order
|
||||
|
||||
* Uri: http://localhost:8080/order
|
||||
* Method: POST
|
||||
* Note: you will get in the response the "location" of the new your order.
|
||||
* HEADERS:
|
||||
|
||||
Content-Type: application/json
|
||||
|
||||
* Example CONTENT
|
||||
|
||||
{
|
||||
"location":"takeAway",
|
||||
"items":[
|
||||
{
|
||||
"name":"Late",
|
||||
"option":"skim",
|
||||
"size":"Small",
|
||||
"quantity":1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
How to Read an order
|
||||
* Uri: http://localhost:8080/order/{order_id}
|
||||
* Method: GET
|
||||
|
||||
|
||||
|
||||
|
||||
How to Update an order
|
||||
* Uri: http://localhost:8080/order/{order_id}
|
||||
* Method: PUT
|
||||
|
||||
|
||||
How to Delete an order
|
||||
* Uri: http://localhost:8080/order/{order_id}
|
||||
* Method: DELETE
|
||||
|
||||
25
examples/restbucks/restbucks-safe.ecf
Normal file
25
examples/restbucks/restbucks-safe.ecf
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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="restbucks" uuid="7C9887BD-4AE4-47F2-A0AA-4BBB6736D433">
|
||||
<target name="restbucks">
|
||||
<root class="RESTBUCKS_SERVER" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<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"/>
|
||||
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\library\server\ewsgi\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="json" location="..\..\ext\text\json\library\json-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\library\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="router" location="..\..\library\server\request\router\router-safe.ecf" readonly="false"/>
|
||||
<library name="uri_template" location="..\..\library\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
1
examples/restbucks/restbucks.rc
Normal file
1
examples/restbucks/restbucks.rc
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
26
examples/restbucks/src/database/database_api.e
Normal file
26
examples/restbucks/src/database/database_api.e
Normal file
@@ -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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
19
examples/restbucks/src/database/shared_database_api.e
Normal file
19
examples/restbucks/src/database/shared_database_api.e
Normal file
@@ -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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
90
examples/restbucks/src/domain/item.e
Normal file
90
examples/restbucks/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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
54
examples/restbucks/src/domain/item_constants.e
Normal file
54
examples/restbucks/src/domain/item_constants.e
Normal file
@@ -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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
170
examples/restbucks/src/domain/json_order_converter.e
Normal file
170
examples/restbucks/src/domain/json_order_converter.e
Normal file
@@ -0,0 +1,170 @@
|
||||
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
|
||||
|
||||
s_id ?= json.object (j.item (id_key), Void)
|
||||
s_location ?= json.object (j.item (location_key), Void)
|
||||
s_status ?= json.object (j.item (status_key), Void)
|
||||
|
||||
create o.make (s_id, 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_array
|
||||
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_json ("id")
|
||||
end
|
||||
|
||||
location_key: JSON_STRING
|
||||
once
|
||||
create Result.make_json ("location")
|
||||
end
|
||||
|
||||
status_key: JSON_STRING
|
||||
once
|
||||
create Result.make_json ("status")
|
||||
end
|
||||
|
||||
items_key : JSON_STRING
|
||||
once
|
||||
create Result.make_json ("items")
|
||||
end
|
||||
|
||||
|
||||
name_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_json ("name")
|
||||
end
|
||||
|
||||
size_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_json ("size")
|
||||
end
|
||||
|
||||
quantity_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_json ("quantity")
|
||||
end
|
||||
|
||||
|
||||
option_key : JSON_STRING
|
||||
|
||||
once
|
||||
create Result.make_json ("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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
111
examples/restbucks/src/domain/order.e
Normal file
111
examples/restbucks/src/domain/order.e
Normal file
@@ -0,0 +1,111 @@
|
||||
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 -- 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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
57
examples/restbucks/src/domain/order_validation.e
Normal file
57
examples/restbucks/src/domain/order_validation.e
Normal file
@@ -0,0 +1,57 @@
|
||||
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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
19
examples/restbucks/src/domain/shared_order_validation.e
Normal file
19
examples/restbucks/src/domain/shared_order_validation.e
Normal file
@@ -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-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
255
examples/restbucks/src/resource/order_handler.e
Normal file
255
examples/restbucks/src/resource/order_handler.e
Normal file
@@ -0,0 +1,255 @@
|
||||
note
|
||||
description: "Summary description for {ORDER_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ORDER_HANDLER [C -> REQUEST_HANDLER_CONTEXT]
|
||||
inherit
|
||||
REQUEST_HANDLER [C]
|
||||
REQUEST_RESOURCE_HANDLER_HELPER [C]
|
||||
redefine
|
||||
do_get,
|
||||
do_post,
|
||||
do_put,
|
||||
do_delete
|
||||
end
|
||||
SHARED_DATABASE_API
|
||||
SHARED_EJSON
|
||||
REFACTORING_HELPER
|
||||
SHARED_ORDER_VALIDATION
|
||||
|
||||
feature -- execute
|
||||
|
||||
execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
-- Execute request handler
|
||||
do
|
||||
execute_methods (ctx, req, res)
|
||||
end
|
||||
|
||||
feature -- API DOC
|
||||
|
||||
api_doc : STRING = "URI:/order METHOD: POST%N URI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
|
||||
|
||||
feature -- HTTP Methods
|
||||
|
||||
do_get (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
-- 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
|
||||
local
|
||||
id : STRING
|
||||
do
|
||||
if attached req.orig_path_info as orig_path then
|
||||
id := get_order_id_from_path (orig_path)
|
||||
if attached retrieve_order (id) as l_order then
|
||||
compute_response_get (ctx, req, res, l_order)
|
||||
else
|
||||
handle_resource_not_found_response ("The following resource" + orig_path + " is not found ", ctx, req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
compute_response_get (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER)
|
||||
local
|
||||
h: EWF_HEADER
|
||||
l_msg : STRING
|
||||
do
|
||||
create h.make
|
||||
h.put_status ({HTTP_STATUS_CODE}.ok)
|
||||
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
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.write_headers_string (h.string)
|
||||
res.write_string (l_msg)
|
||||
end
|
||||
end
|
||||
|
||||
do_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
local
|
||||
l_post: STRING
|
||||
l_location : STRING
|
||||
l_order : detachable ORDER
|
||||
h : EWF_HEADER
|
||||
do
|
||||
fixme ("TODO handle an Internal Server Error")
|
||||
fixme ("Refactor the code, create new abstractions")
|
||||
fixme ("Add Header Date to the response")
|
||||
fixme ("Put implementation is wrong!!!!")
|
||||
req.input.read_stream (req.content_length_value.as_integer_32)
|
||||
l_post := req.input.last_string
|
||||
l_order := extract_order_request(l_post)
|
||||
fixme ("TODO move to a service method")
|
||||
if l_order /= Void and then db_access.orders.has_key (l_order.id) then
|
||||
update_order( l_order)
|
||||
create h.make
|
||||
h.put_status ({HTTP_STATUS_CODE}.ok)
|
||||
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
|
||||
if attached req.http_host as host then
|
||||
l_location := "http://"+host +req.request_uri+"/" + l_order.id
|
||||
h.add_header ("Location:"+ l_location)
|
||||
end
|
||||
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.write_headers_string (h.string)
|
||||
res.write_string (jv.representation)
|
||||
end
|
||||
else
|
||||
handle_bad_request_response (l_post +"%N is not a valid ORDER, maybe the order does not exist in the system", ctx, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
do_delete (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
local
|
||||
id: STRING
|
||||
h : EWF_HEADER
|
||||
do
|
||||
fixme ("TODO handle an Internal Server Error")
|
||||
fixme ("Refactor the code, create new abstractions")
|
||||
if attached req.orig_path_info as orig_path then
|
||||
id := get_order_id_from_path (orig_path)
|
||||
if db_access.orders.has_key (id) then
|
||||
delete_order( id)
|
||||
create h.make
|
||||
h.put_status ({HTTP_STATUS_CODE}.no_content)
|
||||
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.write_headers_string (h.string)
|
||||
else
|
||||
handle_resource_not_found_response (orig_path + " not found in this server", ctx, req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
-- 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
|
||||
req.input.read_stream (req.content_length_value.as_integer_32)
|
||||
l_post := req.input.last_string
|
||||
if attached extract_order_request (l_post) as l_order then
|
||||
save_order (l_order)
|
||||
compute_response_post (ctx, req, res, l_order)
|
||||
else
|
||||
handle_bad_request_response (l_post +"%N is not a valid ORDER", ctx, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
compute_response_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER)
|
||||
local
|
||||
h: EWF_HEADER
|
||||
l_msg : STRING
|
||||
l_location : STRING
|
||||
joc : JSON_ORDER_CONVERTER
|
||||
do
|
||||
create h.make
|
||||
|
||||
create joc.make
|
||||
json.add_converter(joc)
|
||||
|
||||
h.put_status ({HTTP_STATUS_CODE}.created)
|
||||
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.write_headers_string (h.string)
|
||||
res.write_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
|
||||
|
||||
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_parser (l_post)
|
||||
if attached parser.parse as jv and parser.is_parsed then
|
||||
Result ?= json.object (jv, "ORDER")
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
80
examples/restbucks/src/restbucks_server.e
Normal file
80
examples/restbucks/src/restbucks_server.e
Normal file
@@ -0,0 +1,80 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
RESTBUCKS_SERVER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
URI_TEMPLATE_ROUTED_APPLICATION
|
||||
|
||||
ROUTED_APPLICATION_HELPER
|
||||
|
||||
DEFAULT_WGI_APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
-- 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 : EWF_HEADER
|
||||
l_description : STRING
|
||||
l_api_doc : STRING
|
||||
do
|
||||
if req.content_length_value > 0 then
|
||||
req.input.read_stream (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_headers_string (h.string)
|
||||
res.write_string (l_description)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, 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
|
||||
93
ext/ise_library/cURL-safe.ecf
Normal file
93
ext/ise_library/cURL-safe.ecf
Normal file
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-5-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-5-0 http://www.eiffel.com/developers/xml/configuration-1-5-0.xsd" name="curl" uuid="D51EF190-6157-4B47-8E73-FA93DCBB7A71" library_target="curl">
|
||||
<target name="curl">
|
||||
<description>cURL: libcURL wrapper library for Eiffel.
|
||||
Copyright (c) 1984-2006, Eiffel Software and others.
|
||||
Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt).</description>
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGEN.{0,1}$</exclude>
|
||||
<exclude>/temp$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" cat_call_detection="false" is_attached_by_default="true" void_safety="all" namespace="EiffelSoftware.Library">
|
||||
</option>
|
||||
<setting name="dotnet_naming_convention" value="true"/>
|
||||
<external_include location="$(ECF_CONFIG_PATH)\curl\spec\include">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$(ECF_CONFIG_PATH)/curl/spec/include">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_object location="$(ECF_CONFIG_PATH)/curl/spec/$(ISE_PLATFORM)/lib/eiffel_curl.o">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<multithreaded value="false"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH)/curl/spec/$(ISE_PLATFORM)/lib/MTeiffel_curl.o">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<multithreaded value="true"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH)\curl\spec\$(ISE_C_COMPILER)\$(ISE_PLATFORM)\lib\eiffel_curl.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<multithreaded value="false"/>
|
||||
<dotnet value="false"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH)\curl\spec\$(ISE_C_COMPILER)\$(ISE_PLATFORM)\lib\mteiffel_curl.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<multithreaded value="true"/>
|
||||
<dotnet value="false"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH)\spec\$(ISE_C_COMPILER)\$(ISE_PLATFORM)\lib\ileiffel_curl.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<dotnet value="true"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<library name="api_wrapper" location="$ISE_LIBRARY\library\api_wrapper\api_wrapper-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<cluster name="curl" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/spec$</exclude>
|
||||
<exclude>/Clib$</exclude>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/gtk$</exclude>
|
||||
<exclude>/mac$</exclude>
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/mswin$</exclude>
|
||||
<exclude>/gtk$</exclude>
|
||||
<condition>
|
||||
<platform value="macintosh"/>
|
||||
<custom name="vision_implementation" value="cocoa"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/mswin$</exclude>
|
||||
<exclude>/mac$</exclude>
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<custom name="vision_implementation" excluded_value="cocoa"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
<target name="curl_dotnet" extends="curl">
|
||||
<setting name="msil_generation" value="true"/>
|
||||
</target>
|
||||
</system>
|
||||
93
ext/ise_library/cURL.ecf
Normal file
93
ext/ise_library/cURL.ecf
Normal file
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-5-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-5-0 http://www.eiffel.com/developers/xml/configuration-1-5-0.xsd" name="curl" uuid="D51EF190-6157-4B47-8E73-FA93DCBB7A71" library_target="curl">
|
||||
<target name="curl">
|
||||
<description>cURL: libcURL wrapper library for Eiffel.
|
||||
Copyright (c) 1984-2006, Eiffel Software and others.
|
||||
Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt).</description>
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGEN.{0,1}$</exclude>
|
||||
<exclude>/temp$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" namespace="EiffelSoftware.Library">
|
||||
</option>
|
||||
<setting name="dotnet_naming_convention" value="true"/>
|
||||
<external_include location="$(ECF_CONFIG_PATH}\curl\spec\include">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$(ECF_CONFIG_PATH}/curl/spec/include">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_object location="$(ECF_CONFIG_PATH}/curl/spec/$(ISE_PLATFORM)/lib/eiffel_curl.o">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<multithreaded value="false"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH}/curl/spec/$(ISE_PLATFORM)/lib/MTeiffel_curl.o">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<multithreaded value="true"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH}\curl\spec\$(ISE_C_COMPILER)\$(ISE_PLATFORM)\lib\eiffel_curl.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<multithreaded value="false"/>
|
||||
<dotnet value="false"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH}\curl\spec\$(ISE_C_COMPILER)\$(ISE_PLATFORM)\lib\mteiffel_curl.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<multithreaded value="true"/>
|
||||
<dotnet value="false"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<external_object location="$(ECF_CONFIG_PATH}\curl\spec\$(ISE_C_COMPILER)\$(ISE_PLATFORM)\lib\ileiffel_curl.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<dotnet value="true"/>
|
||||
</condition>
|
||||
</external_object>
|
||||
<library name="api_wrapper" location="$ISE_LIBRARY\library\api_wrapper\api_wrapper.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<cluster name="curl" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/spec$</exclude>
|
||||
<exclude>/Clib$</exclude>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/gtk$</exclude>
|
||||
<exclude>/mac$</exclude>
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/mswin$</exclude>
|
||||
<exclude>/gtk$</exclude>
|
||||
<condition>
|
||||
<platform value="macintosh"/>
|
||||
<custom name="vision_implementation" value="cocoa"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/mswin$</exclude>
|
||||
<exclude>/mac$</exclude>
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<custom name="vision_implementation" excluded_value="cocoa"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
<target name="curl_dotnet" extends="curl">
|
||||
<setting name="msil_generation" value="true"/>
|
||||
</target>
|
||||
</system>
|
||||
1
ext/ise_library/curl
Submodule
1
ext/ise_library/curl
Submodule
Submodule ext/ise_library/curl added at 19637b616b
Submodule ext/server/nino updated: 9dd1439a2f...4cd1b67607
Submodule ext/text/json updated: e1c66b50ca...5ec1bdd2ea
1
library/client/http_client/README.md
Normal file
1
library/client/http_client/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Simple HTTP client implemented using Eiffel cURL library
|
||||
39
library/client/http_client/http_client-safe.ecf
Normal file
39
library/client/http_client/http_client-safe.ecf
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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="http_client" uuid="628F5A96-021B-4191-926B-B3BF49272866" library_target="http_client">
|
||||
<target name="http_client">
|
||||
<root all_classes="true"/>
|
||||
<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="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="curl" location="$ISE_LIBRARY\library\cURL\curl-safe.ecf">
|
||||
<condition>
|
||||
<version type="compiler" min="7.0.8.7340"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="curl_local" location="..\..\..\ext\ise_library\curl-safe.ecf">
|
||||
<condition>
|
||||
<version type="compiler" max="7.0.8.7339"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="tests" extends="http_client">
|
||||
<root class="ANY" feature="default_create"/>
|
||||
<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="provisional">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||
<tests name="tests" location=".\tests\"/>
|
||||
</target>
|
||||
</system>
|
||||
26
library/client/http_client/http_client.ecf
Normal file
26
library/client/http_client/http_client.ecf
Normal file
@@ -0,0 +1,26 @@
|
||||
<?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="http_client" uuid="628F5A96-021B-4191-926B-B3BF49272866" library_target="http_client">
|
||||
<target name="http_client">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" void_safety="none" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
|
||||
<library name="curl" location="$ISE_LIBRARY\library\cURL\curl.ecf">
|
||||
<condition>
|
||||
<version type="compiler" min="7.0.8.7340"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="curl_local" location="..\..\..\ext\ise_library\curl.ecf">
|
||||
<condition>
|
||||
<version type="compiler" max="7.0.8.7339"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="encoder" location="../../text/encoder/encoder.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
16
library/client/http_client/src/http_client.e
Normal file
16
library/client/http_client/src/http_client.e
Normal file
@@ -0,0 +1,16 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTP_CLIENT
|
||||
|
||||
feature -- Status
|
||||
|
||||
new_session (a_base_url: READABLE_STRING_8): HTTP_CLIENT_SESSION
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
37
library/client/http_client/src/http_client_constants.e
Normal file
37
library/client/http_client/src/http_client_constants.e
Normal file
@@ -0,0 +1,37 @@
|
||||
note
|
||||
description: "Summary description for {HTTP_CLIENT_CONSTANTS}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_CLIENT_CONSTANTS
|
||||
|
||||
feature -- Auth type
|
||||
|
||||
auth_type_id (a_auth_type_string: READABLE_STRING_8): INTEGER
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
create s.make_from_string (a_auth_type_string)
|
||||
s.to_lower
|
||||
if s.same_string_general ("basic") then
|
||||
Result := Auth_type_basic
|
||||
elseif s.same_string_general ("digest") then
|
||||
Result := Auth_type_digest
|
||||
elseif s.same_string_general ("any") then
|
||||
Result := Auth_type_any
|
||||
elseif s.same_string_general ("anysafe") then
|
||||
Result := Auth_type_anysafe
|
||||
elseif s.same_string_general ("none") then
|
||||
Result := Auth_type_none
|
||||
end
|
||||
end
|
||||
|
||||
Auth_type_none: INTEGER = 0
|
||||
Auth_type_basic: INTEGER = 1
|
||||
Auth_type_digest: INTEGER = 2
|
||||
Auth_type_any: INTEGER = 3
|
||||
Auth_type_anysafe: INTEGER = 4
|
||||
|
||||
end
|
||||
183
library/client/http_client/src/http_client_request.e
Normal file
183
library/client/http_client/src/http_client_request.e
Normal file
@@ -0,0 +1,183 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTP_CLIENT_REQUEST
|
||||
|
||||
inherit
|
||||
REFACTORING_HELPER
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_url: READABLE_STRING_8; a_session: like session)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
session := a_session
|
||||
url := a_url
|
||||
headers := session.headers.twin
|
||||
end
|
||||
|
||||
session: HTTP_CLIENT_SESSION
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_method: READABLE_STRING_8
|
||||
deferred
|
||||
end
|
||||
|
||||
url: READABLE_STRING_8
|
||||
|
||||
headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
|
||||
feature -- Execution
|
||||
|
||||
import (ctx: HTTP_CLIENT_REQUEST_CONTEXT)
|
||||
do
|
||||
headers.fill (ctx.headers)
|
||||
end
|
||||
|
||||
execute (ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Authentication
|
||||
|
||||
auth_type: STRING
|
||||
-- Set the authentication type for the request.
|
||||
-- Types: "basic", "digest", "any"
|
||||
do
|
||||
Result := session.auth_type
|
||||
end
|
||||
|
||||
auth_type_id: INTEGER
|
||||
-- Set the authentication type for the request.
|
||||
-- Types: "basic", "digest", "any"
|
||||
do
|
||||
Result := session.auth_type_id
|
||||
end
|
||||
|
||||
username: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := session.username
|
||||
end
|
||||
|
||||
password: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := session.password
|
||||
end
|
||||
|
||||
credentials: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := session.credentials
|
||||
end
|
||||
|
||||
feature -- Settings
|
||||
|
||||
timeout: INTEGER
|
||||
-- HTTP transaction timeout in seconds.
|
||||
do
|
||||
Result := session.timeout
|
||||
end
|
||||
|
||||
connect_timeout: INTEGER
|
||||
-- HTTP connection timeout in seconds.
|
||||
do
|
||||
Result := session.connect_timeout
|
||||
end
|
||||
|
||||
max_redirects: INTEGER
|
||||
-- Maximum number of times to follow redirects.
|
||||
do
|
||||
Result := session.max_redirects
|
||||
end
|
||||
|
||||
ignore_content_length: BOOLEAN
|
||||
-- Does this session ignore Content-Size headers?
|
||||
do
|
||||
Result := session.ignore_content_length
|
||||
end
|
||||
|
||||
buffer_size: NATURAL
|
||||
-- Set the buffer size for request. This option will
|
||||
-- only be set if buffer_size is positive
|
||||
do
|
||||
Result := session.buffer_size
|
||||
end
|
||||
|
||||
default_response_charset: detachable READABLE_STRING_8
|
||||
-- Default encoding of responses. Used if no charset is provided by the host.
|
||||
do
|
||||
Result := session.default_response_charset
|
||||
end
|
||||
|
||||
feature {NONE} -- Utilities
|
||||
|
||||
append_parameters_to_url (a_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||
-- Append parameters `a_parameters' to `a_url'
|
||||
require
|
||||
a_url_attached: a_url /= Void
|
||||
local
|
||||
i: INTEGER
|
||||
l_first_param: BOOLEAN
|
||||
do
|
||||
if a_parameters /= Void and then a_parameters.count > 0 then
|
||||
if a_url.index_of ('?', 1) > 0 then
|
||||
l_first_param := False
|
||||
elseif a_url.index_of ('&', 1) > 0 then
|
||||
l_first_param := False
|
||||
else
|
||||
l_first_param := True
|
||||
end
|
||||
from
|
||||
i := a_parameters.lower
|
||||
until
|
||||
i > a_parameters.upper
|
||||
loop
|
||||
if attached a_parameters[i] as a_param then
|
||||
if l_first_param then
|
||||
a_url.append_character ('?')
|
||||
else
|
||||
a_url.append_character ('&')
|
||||
end
|
||||
a_url.append_string (a_param.name)
|
||||
a_url.append_character ('=')
|
||||
a_url.append_string (a_param.value)
|
||||
l_first_param := False
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Utilities: encoding
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
urlencode (s: READABLE_STRING_32): READABLE_STRING_8
|
||||
-- URL encode `s'
|
||||
do
|
||||
Result := url_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
urldecode (s: READABLE_STRING_8): READABLE_STRING_32
|
||||
-- URL decode `s'
|
||||
do
|
||||
Result := url_encoder.decoded_string (s)
|
||||
end
|
||||
|
||||
stripslashes (s: STRING): STRING
|
||||
do
|
||||
Result := s.string
|
||||
Result.replace_substring_all ("\%"", "%"")
|
||||
Result.replace_substring_all ("\'", "'")
|
||||
Result.replace_substring_all ("\/", "/")
|
||||
Result.replace_substring_all ("\\", "\")
|
||||
end
|
||||
|
||||
end
|
||||
93
library/client/http_client/src/http_client_request_context.e
Normal file
93
library/client/http_client/src/http_client_request_context.e
Normal file
@@ -0,0 +1,93 @@
|
||||
note
|
||||
description: "Summary description for {HTTP_CLIENT_REQUEST_CONTEXT}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_CLIENT_REQUEST_CONTEXT
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_credentials_required
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
create headers.make (2)
|
||||
create query_parameters.make (5)
|
||||
create form_data_parameters.make (10)
|
||||
end
|
||||
|
||||
make_with_credentials_required
|
||||
do
|
||||
make
|
||||
set_credentials_required (True)
|
||||
end
|
||||
|
||||
feature -- Settings
|
||||
|
||||
credentials_required: BOOLEAN
|
||||
|
||||
feature -- Access
|
||||
|
||||
headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
|
||||
query_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_8]
|
||||
|
||||
form_data_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_8]
|
||||
|
||||
upload_data: detachable READABLE_STRING_8
|
||||
|
||||
upload_filename: detachable READABLE_STRING_8
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_form_data: BOOLEAN
|
||||
do
|
||||
Result := not form_data_parameters.is_empty
|
||||
end
|
||||
|
||||
has_upload_data: BOOLEAN
|
||||
do
|
||||
Result := attached upload_data as d and then not d.is_empty
|
||||
end
|
||||
|
||||
has_upload_filename: BOOLEAN
|
||||
do
|
||||
Result := attached upload_filename as fn and then not fn.is_empty
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
add_query_parameter (k: READABLE_STRING_8; v: READABLE_STRING_32)
|
||||
do
|
||||
query_parameters.force (v, k)
|
||||
end
|
||||
|
||||
add_form_data_parameter (k: READABLE_STRING_8; v: READABLE_STRING_32)
|
||||
do
|
||||
form_data_parameters.force (v, k)
|
||||
end
|
||||
|
||||
set_credentials_required (b: BOOLEAN)
|
||||
do
|
||||
credentials_required := b
|
||||
end
|
||||
|
||||
set_upload_data (a_data: like upload_data)
|
||||
require
|
||||
has_no_upload_data: not has_upload_data
|
||||
do
|
||||
upload_data := a_data
|
||||
end
|
||||
|
||||
set_upload_filename (a_fn: like upload_filename)
|
||||
require
|
||||
has_no_upload_filename: not has_upload_filename
|
||||
do
|
||||
upload_filename := a_fn
|
||||
end
|
||||
|
||||
end
|
||||
71
library/client/http_client/src/http_client_response.e
Normal file
71
library/client/http_client/src/http_client_response.e
Normal file
@@ -0,0 +1,71 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_CLIENT_RESPONSE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
status := 200
|
||||
raw_headers := ""
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
error_occurred: BOOLEAN
|
||||
-- Error occurred during request
|
||||
|
||||
feature {HTTP_CLIENT_REQUEST} -- Status setting
|
||||
|
||||
set_error_occurred (b: BOOLEAN)
|
||||
-- Set `error_occurred' to `b'
|
||||
do
|
||||
error_occurred := b
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
status: INTEGER assign set_status
|
||||
|
||||
raw_headers: READABLE_STRING_8
|
||||
|
||||
headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
local
|
||||
tb: like internal_headers
|
||||
do
|
||||
tb := internal_headers
|
||||
if tb = Void then
|
||||
create tb.make (3)
|
||||
internal_headers := tb
|
||||
end
|
||||
Result := tb
|
||||
end
|
||||
|
||||
body: detachable READABLE_STRING_8 assign set_body
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_status (s: INTEGER)
|
||||
do
|
||||
status := s
|
||||
end
|
||||
|
||||
set_body (s: like body)
|
||||
do
|
||||
body := s
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
internal_headers: detachable like headers
|
||||
|
||||
end
|
||||
178
library/client/http_client/src/http_client_session.e
Normal file
178
library/client/http_client/src/http_client_session.e
Normal file
@@ -0,0 +1,178 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTP_CLIENT_SESSION
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_base_url: READABLE_STRING_8)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
set_defaults
|
||||
create headers.make (3)
|
||||
|
||||
base_url := a_base_url
|
||||
initialize
|
||||
end
|
||||
|
||||
set_defaults
|
||||
do
|
||||
timeout := 5
|
||||
connect_timeout := 1
|
||||
max_redirects := 5
|
||||
set_basic_auth_type
|
||||
end
|
||||
|
||||
initialize
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
head (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
post (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
put (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Settings
|
||||
|
||||
timeout: INTEGER
|
||||
-- HTTP transaction timeout in seconds. Defaults to 5 seconds.
|
||||
|
||||
|
||||
connect_timeout: INTEGER
|
||||
-- HTTP connection timeout in seconds. Defaults to 1 second.
|
||||
|
||||
max_redirects: INTEGER
|
||||
-- Maximum number of times to follow redirects.
|
||||
-- Set to 0 to disable and -1 to follow all redirects. Defaults to 5.
|
||||
|
||||
ignore_content_length: BOOLEAN
|
||||
-- Does this session ignore Content-Size headers?
|
||||
|
||||
buffer_size: NATURAL
|
||||
-- Set the buffer size for request. This option will
|
||||
-- only be set if buffer_size is positive
|
||||
|
||||
default_response_charset: detachable READABLE_STRING_8
|
||||
-- Default encoding of responses. Used if no charset is provided by the host.
|
||||
|
||||
feature -- Access
|
||||
|
||||
base_url: READABLE_STRING_8
|
||||
|
||||
headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
|
||||
feature -- Authentication
|
||||
|
||||
auth_type: STRING
|
||||
-- Set the authentication type for the request.
|
||||
-- Types: "basic", "digest", "any"
|
||||
|
||||
auth_type_id: INTEGER
|
||||
-- See {HTTP_CLIENT_CONSTANTS}.Auth_type_*
|
||||
|
||||
username,
|
||||
password: detachable READABLE_STRING_32
|
||||
|
||||
credentials: detachable READABLE_STRING_32
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_base_url (u: like base_url)
|
||||
do
|
||||
base_url := u
|
||||
end
|
||||
|
||||
set_timeout (n: like timeout)
|
||||
do
|
||||
timeout := n
|
||||
end
|
||||
|
||||
set_connect_timeout (n: like connect_timeout)
|
||||
do
|
||||
connect_timeout := n
|
||||
end
|
||||
|
||||
set_user_agent (v: READABLE_STRING_8)
|
||||
do
|
||||
add_header ("User-Agent", v)
|
||||
end
|
||||
|
||||
add_header (k: READABLE_STRING_8; v: READABLE_STRING_8)
|
||||
do
|
||||
headers.force (v, k)
|
||||
end
|
||||
|
||||
remove_header (k: READABLE_STRING_8)
|
||||
do
|
||||
headers.prune (k)
|
||||
end
|
||||
|
||||
set_credentials (u: like username; p: like password)
|
||||
do
|
||||
username := u
|
||||
password := p
|
||||
if u /= Void and p /= Void then
|
||||
credentials := u + ":" + p
|
||||
else
|
||||
credentials := Void
|
||||
end
|
||||
end
|
||||
|
||||
set_auth_type (s: READABLE_STRING_8)
|
||||
do
|
||||
auth_type := s
|
||||
auth_type_id := http_client_constants.auth_type_id (s)
|
||||
end
|
||||
|
||||
set_basic_auth_type
|
||||
do
|
||||
auth_type := "basic"
|
||||
auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_basic
|
||||
end
|
||||
|
||||
set_digest_auth_type
|
||||
do
|
||||
auth_type := "digest"
|
||||
auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_digest
|
||||
end
|
||||
|
||||
set_any_auth_type
|
||||
do
|
||||
auth_type := "any"
|
||||
auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_any
|
||||
end
|
||||
|
||||
set_anysafe_auth_type
|
||||
do
|
||||
auth_type := "anysafe"
|
||||
auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_anysafe
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
http_client_constants: HTTP_CLIENT_CONSTANTS
|
||||
once
|
||||
create Result
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
LIBCURL_HTTP_CLIENT
|
||||
|
||||
inherit
|
||||
HTTP_CLIENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
new_session (a_base_url: READABLE_STRING_8): LIBCURL_HTTP_CLIENT_SESSION
|
||||
do
|
||||
create Result.make (a_base_url)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,208 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
LIBCURL_HTTP_CLIENT_REQUEST
|
||||
|
||||
inherit
|
||||
HTTP_CLIENT_REQUEST
|
||||
rename
|
||||
make as make_request
|
||||
redefine
|
||||
session
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_url: READABLE_STRING_8; a_request_method: like request_method; a_session: like session)
|
||||
do
|
||||
make_request (a_url, a_session)
|
||||
request_method := a_request_method
|
||||
end
|
||||
|
||||
session: LIBCURL_HTTP_CLIENT_SESSION
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_method: READABLE_STRING_8
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
l_result: INTEGER
|
||||
l_curl_string: CURL_STRING
|
||||
l_url: READABLE_STRING_8
|
||||
p: POINTER
|
||||
a_data: CELL [detachable ANY]
|
||||
l_form, l_last: CURL_FORM
|
||||
curl: CURL_EXTERNALS
|
||||
curl_easy: CURL_EASY_EXTERNALS
|
||||
curl_handle: POINTER
|
||||
do
|
||||
curl := session.curl
|
||||
curl_easy := session.curl_easy
|
||||
|
||||
l_url := url
|
||||
if ctx /= Void then
|
||||
if attached ctx.query_parameters as l_query_params then
|
||||
from
|
||||
l_query_params.start
|
||||
until
|
||||
l_query_params.after
|
||||
loop
|
||||
append_parameters_to_url (l_url, <<[l_query_params.key_for_iteration, urlencode (l_query_params.item_for_iteration)]>>)
|
||||
l_query_params.forth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--| Configure cURL session
|
||||
curl_handle := curl_easy.init
|
||||
|
||||
--| URL
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, l_url)
|
||||
|
||||
--| Timeout
|
||||
if timeout > 0 then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_timeout, timeout)
|
||||
end
|
||||
--| Connect Timeout
|
||||
if connect_timeout > 0 then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_connecttimeout, timeout)
|
||||
end
|
||||
--| Redirection
|
||||
if max_redirects /= 0 then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_followlocation, 1)
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_maxredirs, max_redirects)
|
||||
else
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_followlocation, 0)
|
||||
end
|
||||
|
||||
if request_method.is_case_insensitive_equal ("GET") then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpget, 1)
|
||||
elseif request_method.is_case_insensitive_equal ("POST") then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_post, 1)
|
||||
elseif request_method.is_case_insensitive_equal ("PUT") then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_put, 1)
|
||||
elseif request_method.is_case_insensitive_equal ("HEAD") then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_nobody, 1)
|
||||
elseif request_method.is_case_insensitive_equal ("DELETE") then
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_customrequest, "DELETE")
|
||||
else
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_customrequest, request_method)
|
||||
--| ignored
|
||||
end
|
||||
|
||||
--| Credential
|
||||
if ctx /= Void and then ctx.credentials_required then
|
||||
if attached credentials as l_credentials then
|
||||
inspect auth_type_id
|
||||
when {HTTP_CLIENT_CONSTANTS}.Auth_type_none then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_none)
|
||||
when {HTTP_CLIENT_CONSTANTS}.Auth_type_basic then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_basic)
|
||||
when {HTTP_CLIENT_CONSTANTS}.Auth_type_digest then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_digest)
|
||||
when {HTTP_CLIENT_CONSTANTS}.Auth_type_any then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_any)
|
||||
when {HTTP_CLIENT_CONSTANTS}.Auth_type_anysafe then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_anysafe)
|
||||
else
|
||||
end
|
||||
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_userpwd, l_credentials)
|
||||
else
|
||||
--| Credentials not prov ided ...
|
||||
end
|
||||
end
|
||||
|
||||
if ctx /= Void and then ctx.has_form_data then
|
||||
if attached ctx.form_data_parameters as l_posts and then not l_posts.is_empty then
|
||||
-- curl_easy.set_debug_function (curl_handle)
|
||||
-- curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_verbose, 1)
|
||||
|
||||
create l_form.make
|
||||
create l_last.make
|
||||
from
|
||||
l_posts.start
|
||||
until
|
||||
l_posts.after
|
||||
loop
|
||||
curl.formadd_string_string (l_form, l_last, {CURL_FORM_CONSTANTS}.CURLFORM_COPYNAME, l_posts.key_for_iteration, {CURL_FORM_CONSTANTS}.CURLFORM_COPYCONTENTS, l_posts.item_for_iteration, {CURL_FORM_CONSTANTS}.CURLFORM_END)
|
||||
l_posts.forth
|
||||
end
|
||||
l_last.release_item
|
||||
curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, l_form)
|
||||
end
|
||||
end
|
||||
if ctx /= Void then
|
||||
if
|
||||
request_method.is_case_insensitive_equal ("POST") and then
|
||||
ctx.has_upload_data and then attached ctx.upload_data as l_upload_data
|
||||
then
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, l_upload_data)
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfieldsize, l_upload_data.count)
|
||||
elseif
|
||||
request_method.is_case_insensitive_equal ("PUT") and then
|
||||
ctx.has_upload_filename and then attached ctx.upload_filename as l_upload_filename
|
||||
then
|
||||
-- curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, l_upload_data)
|
||||
-- curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfieldsize, l_upload_data.count)
|
||||
--| Not Yet Implemented
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
curl.global_init
|
||||
if attached headers as l_headers then
|
||||
across
|
||||
l_headers as curs
|
||||
loop
|
||||
p := curl.slist_append (p, curs.key + ": " + curs.item)
|
||||
-- curl_easy.setopt_slist (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpheader, p)
|
||||
end
|
||||
end
|
||||
|
||||
p := curl.slist_append (p, "Expect:")
|
||||
curl_easy.setopt_slist (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpheader, p)
|
||||
|
||||
|
||||
curl.global_cleanup
|
||||
|
||||
curl_easy.set_read_function (curl_handle)
|
||||
curl_easy.set_write_function (curl_handle)
|
||||
create l_curl_string.make_empty
|
||||
curl_easy.setopt_curl_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_curl_string)
|
||||
|
||||
debug ("service")
|
||||
io.put_string ("SERVICE: " + l_url)
|
||||
io.put_new_line
|
||||
end
|
||||
|
||||
create Result.make
|
||||
l_result := curl_easy.perform (curl_handle)
|
||||
|
||||
if l_result = {CURL_CODES}.curle_ok then
|
||||
create a_data.put (Void)
|
||||
l_result := curl_easy.getinfo (curl_handle, {CURL_INFO_CONSTANTS}.curlinfo_response_code, a_data)
|
||||
if l_result = 0 and then attached {INTEGER} a_data.item as l_http_status then
|
||||
Result.status := l_http_status
|
||||
else
|
||||
Result.status := 0
|
||||
end
|
||||
Result.body := l_curl_string.string
|
||||
else
|
||||
Result.set_error_occurred (True)
|
||||
end
|
||||
|
||||
curl_easy.cleanup (curl_handle)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,101 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
LIBCURL_HTTP_CLIENT_SESSION
|
||||
|
||||
inherit
|
||||
HTTP_CLIENT_SESSION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
create curl -- cURL externals
|
||||
create curl_easy -- cURL easy externals
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "GET", Current)
|
||||
Result := execute_request (req, ctx)
|
||||
end
|
||||
|
||||
head (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "HEAD", Current)
|
||||
Result := execute_request (req, ctx)
|
||||
end
|
||||
|
||||
post (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; a_data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "POST", Current)
|
||||
ctx := a_ctx
|
||||
if a_data /= Void then
|
||||
if ctx = Void then
|
||||
create ctx.make
|
||||
end
|
||||
ctx.set_upload_data (a_data)
|
||||
end
|
||||
Result := execute_request (req, ctx)
|
||||
end
|
||||
|
||||
put (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "PUT", Current)
|
||||
ctx := a_ctx
|
||||
if fn /= Void then
|
||||
if ctx = Void then
|
||||
create ctx.make
|
||||
end
|
||||
ctx.set_upload_filename (fn)
|
||||
end
|
||||
Result := execute_request (req, ctx)
|
||||
end
|
||||
|
||||
delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
local
|
||||
req: HTTP_CLIENT_REQUEST
|
||||
do
|
||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "DELETE", Current)
|
||||
Result := execute_request (req, ctx)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
execute_request (req: HTTP_CLIENT_REQUEST; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
do
|
||||
if ctx /= Void then
|
||||
req.import (ctx)
|
||||
end
|
||||
Result := req.execute (ctx)
|
||||
end
|
||||
|
||||
feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation
|
||||
|
||||
curl: CURL_EXTERNALS
|
||||
-- cURL externals
|
||||
|
||||
curl_easy: CURL_EASY_EXTERNALS
|
||||
-- cURL easy externals
|
||||
|
||||
|
||||
end
|
||||
@@ -8,6 +8,11 @@ note
|
||||
class
|
||||
ERROR_HANDLER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
DEBUG_OUTPUT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -17,6 +22,7 @@ feature {NONE} -- Initialization
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
create {ARRAYED_LIST [ERROR]} errors.make (3)
|
||||
create error_added_actions
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
@@ -32,15 +38,43 @@ feature -- Status
|
||||
Result := errors.count
|
||||
end
|
||||
|
||||
feature {ERROR_HANDLER, ERROR_VISITOR} -- Restricted access
|
||||
|
||||
errors: LIST [ERROR]
|
||||
-- Errors container
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
if has_error then
|
||||
Result := count.out + " errors"
|
||||
else
|
||||
Result := "no error"
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Events
|
||||
|
||||
error_added_actions: ACTION_SEQUENCE [TUPLE [ERROR]]
|
||||
-- Actions triggered when a new error is added
|
||||
|
||||
feature {NONE} -- Event: implementation
|
||||
|
||||
on_error_added (e: ERROR)
|
||||
-- Error `e' was just added
|
||||
do
|
||||
error_added_actions.call ([e])
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
add_error (a_error: ERROR)
|
||||
-- Add `a_error' to the stack of error
|
||||
do
|
||||
errors.force (a_error)
|
||||
on_error_added (a_error)
|
||||
end
|
||||
|
||||
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable STRING_32)
|
||||
@@ -52,6 +86,27 @@ feature -- Basic operation
|
||||
add_error (e)
|
||||
end
|
||||
|
||||
append (other: ERROR_HANDLER)
|
||||
-- Append errors from `a_err_handler'
|
||||
local
|
||||
other_errs: LIST [ERROR]
|
||||
do
|
||||
other_errs := other.errors
|
||||
if other_errs.count > 0 then
|
||||
from
|
||||
other_errs.start
|
||||
until
|
||||
other_errs.after
|
||||
loop
|
||||
add_error (other_errs.item)
|
||||
other_errs.forth
|
||||
end
|
||||
end
|
||||
ensure
|
||||
other_error_appended: other.has_error implies has_error
|
||||
new_count: count = old count + other.count
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
as_single_error: detachable ERROR
|
||||
@@ -61,6 +116,20 @@ feature -- Access
|
||||
elseif count > 0 then
|
||||
Result := errors.first
|
||||
end
|
||||
ensure
|
||||
has_error_implies_result_attached: has_error implies Result /= Void
|
||||
end
|
||||
|
||||
as_string_representation: STRING
|
||||
require
|
||||
has_error
|
||||
do
|
||||
if attached as_single_error as e then
|
||||
Result := e.string_representation
|
||||
else
|
||||
check has_error: False end
|
||||
Result := "Error occured"
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Element changes
|
||||
@@ -70,7 +139,7 @@ feature -- Element changes
|
||||
do
|
||||
if count > 1 and then attached as_single_error as e then
|
||||
wipe_out
|
||||
add_error (e)
|
||||
errors.force (e)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
11
library/error/src/error_handler_with_event.e
Normal file
11
library/error/src/error_handler_with_event.e
Normal file
@@ -0,0 +1,11 @@
|
||||
note
|
||||
|
||||
description: "Summary description for {ERROR_HANDLER_WITH_EVENT}."
|
||||
|
||||
author: ""
|
||||
|
||||
date: "$Date$"
|
||||
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
38
library/library.index
Normal file
38
library/library.index
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
# Available libraries.
|
||||
|
||||
http_client-safe : c:\_dev\Dev-Process\web-framework\library\client\http_client\http_client-safe.ecf
|
||||
http_client : c:\_dev\Dev-Process\web-framework\library\client\http_client\http_client.ecf
|
||||
error-safe : c:\_dev\Dev-Process\web-framework\library\error\error-safe.ecf
|
||||
error : c:\_dev\Dev-Process\web-framework\library\error\error.ecf
|
||||
http-safe : c:\_dev\Dev-Process\web-framework\library\protocol\http\http-safe.ecf
|
||||
http : c:\_dev\Dev-Process\web-framework\library\protocol\http\http.ecf
|
||||
uri_template-safe : c:\_dev\Dev-Process\web-framework\library\protocol\uri_template\uri_template-safe.ecf
|
||||
uri_template : c:\_dev\Dev-Process\web-framework\library\protocol\uri_template\uri_template.ecf
|
||||
http_authorization-safe : c:\_dev\Dev-Process\web-framework\library\server\authentication\http_authorization\http_authorization-safe.ecf
|
||||
http_authorization : c:\_dev\Dev-Process\web-framework\library\server\authentication\http_authorization\http_authorization.ecf
|
||||
ewsgi-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\ewsgi-safe.ecf
|
||||
ewsgi : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\ewsgi.ecf
|
||||
ewsgi_spec-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\ewsgi_spec-safe.ecf
|
||||
ewsgi_spec : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\ewsgi_spec.ecf
|
||||
cgi-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\connectors\cgi\cgi-safe.ecf
|
||||
cgi : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\connectors\cgi\cgi.ecf
|
||||
libfcgi-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf
|
||||
libfcgi : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\connectors\libfcgi\libfcgi.ecf
|
||||
nino-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\connectors\nino\nino-safe.ecf
|
||||
nino : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\connectors\nino\nino.ecf
|
||||
ewsgi_cgi-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\default\ewsgi_cgi-safe.ecf
|
||||
ewsgi_cgi : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\default\ewsgi_cgi.ecf
|
||||
ewsgi_nino-safe : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\default\ewsgi_nino-safe.ecf
|
||||
ewsgi_nino : c:\_dev\Dev-Process\web-framework\library\server\ewsgi\default\ewsgi_nino.ecf
|
||||
fcgi-safe : c:\_dev\Dev-Process\web-framework\library\server\libfcgi\fcgi-safe.ecf
|
||||
fcgi : c:\_dev\Dev-Process\web-framework\library\server\libfcgi\fcgi.ecf
|
||||
libfcgi-safe : c:\_dev\Dev-Process\web-framework\library\server\libfcgi\libfcgi-safe.ecf
|
||||
libfcgi : c:\_dev\Dev-Process\web-framework\library\server\libfcgi\libfcgi.ecf
|
||||
rest-safe : c:\_dev\Dev-Process\web-framework\library\server\request\rest\rest-safe.ecf
|
||||
rest : c:\_dev\Dev-Process\web-framework\library\server\request\rest\rest.ecf
|
||||
router-safe : c:\_dev\Dev-Process\web-framework\library\server\request\router\router-safe.ecf
|
||||
router : c:\_dev\Dev-Process\web-framework\library\server\request\router\router.ecf
|
||||
encoder-safe : c:\_dev\Dev-Process\web-framework\library\text\encoder\encoder-safe.ecf
|
||||
encoder : c:\_dev\Dev-Process\web-framework\library\text\encoder\encoder.ecf
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true">
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
note
|
||||
description: "Summary description for {HTTP_CONSTANTS}."
|
||||
description: "[
|
||||
Constants class providing most common constants used in HTTP communication
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
@@ -8,83 +10,31 @@ note
|
||||
class
|
||||
HTTP_CONSTANTS
|
||||
|
||||
inherit
|
||||
HTTP_MIME_TYPES
|
||||
|
||||
HTTP_HEADER_NAMES
|
||||
|
||||
HTTP_STATUS_CODE
|
||||
|
||||
HTTP_REQUEST_METHODS
|
||||
|
||||
feature -- Ports
|
||||
|
||||
default_http_port: INTEGER = 80
|
||||
default_https_port: INTEGER = 443
|
||||
|
||||
feature -- Method
|
||||
|
||||
method_get: STRING = "GET"
|
||||
method_post: STRING = "POST"
|
||||
method_put: STRING = "PUT"
|
||||
method_delete: STRING = "DELETE"
|
||||
method_head: STRING = "HEAD"
|
||||
method_download: STRING = "DOWNLOAD"
|
||||
|
||||
feature -- Content type
|
||||
|
||||
octet_stream: STRING = "application/octet-stream"
|
||||
-- Octet stream content-type header
|
||||
multipart_form: STRING = "multipart/form-data"
|
||||
-- Starting chars of multipart form data content-type header
|
||||
form_encoded: STRING = "application/x-www-form-urlencoded"
|
||||
-- Starting chars of form url-encoded data content-type header
|
||||
xml_text: STRING = "text/xml"
|
||||
-- XML text content-type header
|
||||
html_text: STRING = "text/html"
|
||||
-- HTML text content-type header
|
||||
json_text: STRING = "text/json"
|
||||
-- JSON text content-type header
|
||||
json_app: STRING = "application/json"
|
||||
-- JSON application content-type header
|
||||
js_text: STRING = "text/javascript"
|
||||
-- Javascript text content-type header
|
||||
js_app: STRING = "application/javascript"
|
||||
-- JavaScript application content-type header
|
||||
plain_text: STRING = "text/plain"
|
||||
-- Plain text content-type header
|
||||
|
||||
feature -- Server
|
||||
feature -- Server, header
|
||||
|
||||
http_version_1_0: STRING = "HTTP/1.0"
|
||||
http_version_1_1: STRING = "HTTP/1.1"
|
||||
http_host_header: STRING = "Host"
|
||||
http_authorization_header: STRING = "Authorization: "
|
||||
http_end_of_header_line: STRING = "%R%N"
|
||||
http_end_of_command: STRING = "%R%N%R%N"
|
||||
http_content_length: STRING = "Content-Length: "
|
||||
http_content_type: STRING = "Content-Type: "
|
||||
http_content_location: STRING = "Content-Location: "
|
||||
http_content_disposition: STRING = "Content-Disposition: "
|
||||
http_path_translated: STRING = "Path-Translated: "
|
||||
http_agent: STRING = "User-agent: "
|
||||
http_from: STRING = "From: "
|
||||
|
||||
feature -- Server: header
|
||||
|
||||
header_host: STRING = "Host"
|
||||
header_authorization: STRING = "Authorization"
|
||||
header_content_length: STRING = "Content-Length"
|
||||
header_content_type: STRING = "Content-Type"
|
||||
header_content_location: STRING = "Content-Location"
|
||||
header_content_disposition: STRING = "Content-Disposition"
|
||||
header_cache_control: STRING = "Cache-Control"
|
||||
header_path_translated: STRING = "Path-Translated"
|
||||
header_agent: STRING = "User-Agent"
|
||||
header_referer: STRING = "Referer" -- Officially mispelled in std
|
||||
header_location: STRING = "Location"
|
||||
header_from: STRING = "From"
|
||||
header_status: STRING = "Status"
|
||||
header_multipart_tag_value_separator: CHARACTER = ';'
|
||||
|
||||
feature -- Misc
|
||||
|
||||
http_status_ok: STRING = "200 OK"
|
||||
crlf: STRING = "%R%N"
|
||||
|
||||
default_bufsize: INTEGER = 16384 --| 16K
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
239
library/protocol/http/src/http_file_extension_mime_mapping.e
Normal file
239
library/protocol/http/src/http_file_extension_mime_mapping.e
Normal file
@@ -0,0 +1,239 @@
|
||||
note
|
||||
description: "[
|
||||
Various common MIME types for file extensions
|
||||
|
||||
See also for longer list and description
|
||||
http://www.webmaster-toolkit.com/mime-types.shtml
|
||||
|
||||
Please suggest missing entries
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_FILE_EXTENSION_MIME_MAPPING
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
HTTP_MIME_TYPES
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make_empty,
|
||||
make_default,
|
||||
make_from_string,
|
||||
make_from_file
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_empty (n: INTEGER)
|
||||
-- Create with no mapping
|
||||
-- but one can use `map' to add new mapping
|
||||
do
|
||||
create mapping.make (n)
|
||||
mapping.compare_objects
|
||||
end
|
||||
|
||||
make_default
|
||||
-- Create with default limited mapping
|
||||
-- One can use `map' to add new mapping
|
||||
local
|
||||
m: like mapping
|
||||
do
|
||||
create m.make (40)
|
||||
mapping := m
|
||||
m.compare_objects
|
||||
m.force (text_css, "css")
|
||||
m.force (text_html, "html")
|
||||
m.force (text_xml, "xml")
|
||||
m.force (application_json, "json")
|
||||
m.force (application_javascript, "js")
|
||||
m.force (application_rss_xml, "rss")
|
||||
m.force (application_atom_xml, "atom")
|
||||
m.force (image_x_ico, "ico")
|
||||
m.force (image_gif, "gif")
|
||||
m.force (image_jpeg, "jpeg")
|
||||
m.force (image_jpg, "jpg")
|
||||
m.force (image_png, "png")
|
||||
m.force (application_zip, "zip")
|
||||
m.force (application_x_bzip, "bz")
|
||||
m.force (application_x_bzip2, "bz2")
|
||||
m.force (application_x_gzip, "gz")
|
||||
m.force (application_x_gzip, "gzip")
|
||||
m.force (application_x_tar, "tar")
|
||||
m.force (application_x_compressed, "tgz")
|
||||
m.force (application_postscript, "ps")
|
||||
m.force (application_pdf, "pdf")
|
||||
m.force (application_x_shockwave_flash, "swf")
|
||||
m.force (text_plain, "conf")
|
||||
m.force (text_plain, "log")
|
||||
m.force (text_plain, "text")
|
||||
m.force (text_plain, "txt")
|
||||
end
|
||||
|
||||
make_from_file (fn: READABLE_STRING_8)
|
||||
-- Create with mime.types file
|
||||
-- One can use `map' to add new mapping
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make (fn)
|
||||
if f.exists and then f.is_readable then
|
||||
make_empty (50)
|
||||
f.open_read
|
||||
from
|
||||
f.read_line
|
||||
until
|
||||
f.exhausted or f.end_of_file
|
||||
loop
|
||||
add_mapping_line (f.last_string)
|
||||
f.read_line
|
||||
end
|
||||
f.close
|
||||
else
|
||||
make_empty (0)
|
||||
end
|
||||
end
|
||||
|
||||
make_from_string (t: READABLE_STRING_8)
|
||||
-- Set mapping from multiline string `t'
|
||||
-- line should be formatted as in http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
|
||||
--| # is a comment
|
||||
--| mime-type space(s) extensions
|
||||
local
|
||||
i,j,n: INTEGER
|
||||
do
|
||||
make_empty (10)
|
||||
n := t.count
|
||||
if n > 0 then
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i = 0 or i > n
|
||||
loop
|
||||
j := t.index_of ('%N', i)
|
||||
if j > 0 then
|
||||
add_mapping_line (t.substring (i, j - 1))
|
||||
i := j + 1
|
||||
else
|
||||
add_mapping_line (t.substring (i, n))
|
||||
i := 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
mime_type (ext: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||
-- Mime type for extension `ext'
|
||||
do
|
||||
Result := mapping.item (ext.as_lower)
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
map (e: READABLE_STRING_8; t: READABLE_STRING_8)
|
||||
-- Add mapping extension `e' to mime type `t'
|
||||
do
|
||||
mapping.force (t, e.as_lower)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
add_mapping_line (t: READABLE_STRING_8)
|
||||
local
|
||||
i,j,n: INTEGER
|
||||
l_type, l_ext: READABLE_STRING_8
|
||||
do
|
||||
n := t.count
|
||||
if n > 0 then
|
||||
-- ignore blanks
|
||||
i := next_non_blank_position (t, i)
|
||||
if i > 0 then
|
||||
if t[i] = '#' then
|
||||
--| ignore
|
||||
else
|
||||
j := next_blank_position (t, i)
|
||||
if j > i then
|
||||
l_type := t.substring (i, j - 1)
|
||||
from
|
||||
until
|
||||
i = 0
|
||||
loop
|
||||
i := next_non_blank_position (t, j)
|
||||
if i > 0 then
|
||||
j := next_blank_position (t, i)
|
||||
if j = 0 then
|
||||
l_ext := t.substring (i, n)
|
||||
i := 0
|
||||
else
|
||||
l_ext := t.substring (i, j - 1)
|
||||
i := j
|
||||
end
|
||||
map (l_ext, l_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
next_blank_position (s: READABLE_STRING_8; p: INTEGER): INTEGER
|
||||
local
|
||||
i, n: INTEGER
|
||||
do
|
||||
n := s.count
|
||||
from
|
||||
i := p + 1
|
||||
until
|
||||
i > n or s[i].is_space
|
||||
loop
|
||||
i := i + 1
|
||||
end
|
||||
if i <= n then
|
||||
Result := i
|
||||
end
|
||||
end
|
||||
|
||||
next_non_blank_position (s: READABLE_STRING_8; p: INTEGER): INTEGER
|
||||
local
|
||||
i, n: INTEGER
|
||||
do
|
||||
n := s.count
|
||||
from
|
||||
i := p + 1
|
||||
until
|
||||
i > n or not s[i].is_space
|
||||
loop
|
||||
i := i + 1
|
||||
end
|
||||
if i <= n then
|
||||
Result := i
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Extension MIME mapping
|
||||
|
||||
mapping: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||
|
||||
invariant
|
||||
mapping_keys_are_lowercase: across mapping as c all c.key.same_string (c.key.as_lower) end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -38,11 +38,11 @@ feature -- Name
|
||||
|
||||
feature -- Query
|
||||
|
||||
format_id (a_id: STRING): INTEGER
|
||||
format_id (a_id: READABLE_STRING_GENERAL): INTEGER
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
s := a_id.as_lower
|
||||
s := a_id.as_string_8.as_lower
|
||||
if s.same_string (json_name) then
|
||||
Result := json
|
||||
elseif s.same_string (xml_name) then
|
||||
@@ -58,7 +58,7 @@ feature -- Query
|
||||
end
|
||||
end
|
||||
|
||||
format_name (a_id: INTEGER): STRING
|
||||
format_name (a_id: INTEGER): READABLE_STRING_8
|
||||
do
|
||||
inspect a_id
|
||||
when json then Result := json_name
|
||||
@@ -74,7 +74,7 @@ feature -- Query
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
257
library/protocol/http/src/http_header_names.e
Normal file
257
library/protocol/http/src/http_header_names.e
Normal file
@@ -0,0 +1,257 @@
|
||||
note
|
||||
description: "[
|
||||
See http://en.wikipedia.org/wiki/List_of_HTTP_headers
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_HEADER_NAMES
|
||||
|
||||
feature -- Request header name
|
||||
|
||||
header_accept: STRING = "Accept"
|
||||
-- Content-Types that are acceptable
|
||||
--| Example: Accept: text/plain
|
||||
|
||||
header_accept_charset: STRING = "Accept-Charset"
|
||||
-- Character sets that are acceptable
|
||||
--| Example: Accept-Charset: utf-8
|
||||
|
||||
header_accept_encoding: STRING = "Accept-Encoding"
|
||||
-- Acceptable encodings. See HTTP compression.
|
||||
--| Example: Accept-Encoding: <compress | gzip | deflate | sdch | identity>
|
||||
|
||||
header_accept_language: STRING = "Accept-Language"
|
||||
-- Acceptable languages for response
|
||||
--| Example: Accept-Language: en-US
|
||||
|
||||
header_authorization: STRING = "Authorization"
|
||||
-- Authentication credentials for HTTP authentication
|
||||
--| Example: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
|
||||
|
||||
header_cookie: STRING = "Cookie"
|
||||
-- an HTTP cookie previously sent by the server with Set-Cookie (below)
|
||||
--| Example: Cookie: $Version=1; Skin=new;
|
||||
|
||||
header_expect: STRING = "Expect"
|
||||
-- Indicates that particular server behaviors are required by the client
|
||||
--| Example: Expect: 100-continue
|
||||
|
||||
header_from: STRING = "From"
|
||||
-- The email address of the user making the request
|
||||
--| Example: From: user@example.com
|
||||
|
||||
header_host: STRING = "Host"
|
||||
-- The domain name of the server (for virtual hosting), mandatory since HTTP/1.1
|
||||
--| Example: Host: en.wikipedia.org
|
||||
|
||||
header_if_match: STRING = "If-Match"
|
||||
-- Only perform the action if the client supplied entity matches the same entity on the server. This is mainly for methods like PUT to only update a resource if it has not been modified since the user last updated it.
|
||||
--| Example: If-Match: "737060cd8c284d8af7ad3082f209582d"
|
||||
|
||||
header_if_modified_since: STRING = "If-Modified-Since"
|
||||
-- Allows a 304 Not Modified to be returned if content is unchanged
|
||||
--| Example: If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
|
||||
|
||||
header_if_none_match: STRING = "If-None-Match"
|
||||
-- Allows a 304 Not Modified to be returned if content is unchanged, see HTTP ETag
|
||||
--| Example: If-None-Match: "737060cd8c284d8af7ad3082f209582d"
|
||||
|
||||
header_if_range: STRING = "If-Range"
|
||||
-- If the entity is unchanged, send me the part(s) that I am missing; otherwise, send me the entire new entity
|
||||
--| Example: If-Range: "737060cd8c284d8af7ad3082f209582d"
|
||||
|
||||
header_if_unmodified_since: STRING = "If-Unmodified-Since"
|
||||
-- Only send the response if the entity has not been modified since a specific time.
|
||||
--| Example: If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
|
||||
|
||||
header_max_forwards: STRING = "Max-Forwards"
|
||||
-- Limit the number of times the message can be forwarded through proxies or gateways.
|
||||
--| Example: Max-Forwards: 10
|
||||
|
||||
header_proxy_authorization: STRING = "Proxy-Authorization"
|
||||
-- Authorization credentials for connecting to a proxy.
|
||||
--| Example: Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
|
||||
|
||||
header_range: STRING = "Range"
|
||||
-- Request only part of an entity. Bytes are numbered from 0.
|
||||
--| Example: Range: bytes=500-999
|
||||
|
||||
header_referer: STRING = "Referer[sic]"
|
||||
-- This is the address of the previous web page from which a link to the currently requested page was followed. (The word “referrer” is misspelled in the RFC as well as in most implementations.)
|
||||
--| Example: Referer: http://en.wikipedia.org/wiki/Main_Page
|
||||
|
||||
header_te: STRING = "TE"
|
||||
-- The transfer encodings the user agent is willing to accept: the same values as for the response header Transfer-Encoding can be used, plus the "trailers" value (related to the "chunked" transfer method) to notify the server it accepts to receive additional headers (the trailers) after the last, zero-sized, chunk.
|
||||
--| Example: TE: trailers, deflate
|
||||
|
||||
header_upgrade: STRING = "Upgrade"
|
||||
-- Ask the server to upgrade to another protocol.
|
||||
--| Example: Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
|
||||
|
||||
header_user_agent: STRING = "User-Agent"
|
||||
-- The user agent string of the user agent
|
||||
--| Example: User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
|
||||
|
||||
feature -- Response header name
|
||||
|
||||
header_accept_ranges: STRING = "Accept-Ranges"
|
||||
-- "Accept-Ranges" What partial content range types this server supports
|
||||
--| Example: Accept-Ranges: bytes
|
||||
|
||||
header_age: STRING = "Age"
|
||||
-- The age the object has been in a proxy cache in seconds
|
||||
--| Example: Age: 12
|
||||
|
||||
header_allow: STRING = "Allow"
|
||||
-- Valid actions for a specified resource. To be used for a 405 Method not allowed
|
||||
--| Example: Allow: GET, HEAD
|
||||
|
||||
header_content_encoding: STRING = "Content-Encoding"
|
||||
-- The type of encoding used on the data. See HTTP compression.
|
||||
--| Example: Content-Encoding: gzip
|
||||
|
||||
header_content_language: STRING = "Content-Language"
|
||||
-- The language the content is in
|
||||
--| Example: Content-Language: da
|
||||
|
||||
header_content_location: STRING = "Content-Location"
|
||||
-- An alternate location for the returned data
|
||||
--| Example: Content-Location: /index.htm
|
||||
|
||||
header_content_disposition: STRING = "Content-Disposition"
|
||||
-- An opportunity to raise a "File Download" dialogue box for a known MIME type
|
||||
--| Example: Content-Disposition: attachment; filename=fname.ext
|
||||
|
||||
header_content_range: STRING = "Content-Range"
|
||||
-- Where in a full body message this partial message belongs
|
||||
--| Example: Content-Range: bytes 21010-47021/47022
|
||||
|
||||
header_etag: STRING = "ETag"
|
||||
-- An identifier for a specific version of a resource, often a message digest
|
||||
--| Example: ETag: "737060cd8c284d8af7ad3082f209582d"
|
||||
|
||||
header_expires: STRING = "Expires"
|
||||
-- Gives the date/time after which the response is considered stale
|
||||
--| Example: Expires: Thu, 01 Dec 1994 16:00:00 GMT
|
||||
|
||||
header_last_modified: STRING = "Last-Modified"
|
||||
-- The last modified date for the requested object, in RFC 2822 format
|
||||
--| Example: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
|
||||
header_link: STRING = "Link"
|
||||
-- Used to express a typed relationship with another resource, where the relation type is defined by RFC 5988
|
||||
--| Example: Link: </feed>; rel="alternate"
|
||||
|
||||
header_location: STRING = "Location"
|
||||
-- Used in redirection, or when a new resource has been created.
|
||||
--| Example: Location: http://www.w3.org/pub/WWW/People.html
|
||||
|
||||
header_p3p: STRING = "P3P"
|
||||
-- This header is supposed to set P3P policy, in the form of P3P:CP="your_compact_policy". However, P3P did not take off,[5] most browsers have never fully implemented it, a lot of websites set this header with fake policy text, that was enough to fool browsers the existence of P3P policy and grant permissions for third party cookies.
|
||||
--| Example: P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
|
||||
|
||||
|
||||
header_proxy_authenticate: STRING = "Proxy-Authenticate"
|
||||
-- Request authentication to access the proxy.
|
||||
--| Example: Proxy-Authenticate: Basic
|
||||
|
||||
header_refresh: STRING = "Refresh"
|
||||
-- Used in redirection, or when a new resource has been created. This refresh redirects after 5 seconds. This is a proprietary, non-standard header extension introduced by Netscape and supported by most web browsers.
|
||||
--| Example: Refresh: 5; url=http://www.w3.org/pub/WWW/People.html
|
||||
|
||||
header_retry_after: STRING = "Retry-After"
|
||||
-- If an entity is temporarily unavailable, this instructs the client to try again after a specified period of time.
|
||||
--| Example: Retry-After: 120
|
||||
|
||||
header_server: STRING = "Server"
|
||||
-- A name for the server
|
||||
--| Example: Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
|
||||
|
||||
header_set_cookie: STRING = "Set-Cookie"
|
||||
-- an HTTP cookie
|
||||
--| Example: Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
|
||||
|
||||
header_strict_transport_security: STRING = "Strict-Transport-Security"
|
||||
-- A HSTS Policy informing the HTTP client how long to cache the HTTPS only policy and whether this applies to subdomains.
|
||||
--| Example: Strict-Transport-Security: max-age=16070400; includeSubDomains
|
||||
|
||||
header_trailer: STRING = "Trailer"
|
||||
-- The Trailer general field value indicates that the given set of header fields is present in the trailer of a message encoded with chunked transfer-coding.
|
||||
--| Example: Trailer: Max-Forwards
|
||||
|
||||
header_transfer_encoding: STRING = "Transfer-Encoding"
|
||||
-- The form of encoding used to safely transfer the entity to the user. Currently defined methods are: chunked, compress, deflate, gzip, identity.
|
||||
--| Example: Transfer-Encoding: chunked
|
||||
|
||||
header_vary: STRING = "Vary"
|
||||
-- Tells downstream proxies how to match future request headers to decide whether the cached response
|
||||
-- can be used rather than requesting a fresh one from the origin server.
|
||||
--| Example: Vary: *
|
||||
|
||||
header_www_authenticate: STRING = "WWW-Authenticate"
|
||||
-- Indicates the authentication scheme that should be used to access the requested entity.
|
||||
--| Example: WWW-Authenticate: Basic
|
||||
|
||||
feature -- Request or Response header name
|
||||
|
||||
header_cache_control: STRING = "Cache-Control"
|
||||
-- Request: Used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain
|
||||
-- Response: Tells all caching mechanisms from server to client whether they may cache this object. It is measured in seconds
|
||||
--| Request example: Cache-Control: no-cache
|
||||
--| Response example: Cache-Control: max-age=3600
|
||||
|
||||
header_connection: STRING = "Connection"
|
||||
-- Request: What type of connection the user-agent would prefer
|
||||
-- Response: Options that are desired for the connection[4]
|
||||
--| Example: Connection: close
|
||||
|
||||
header_content_length: STRING = "Content-Length"
|
||||
-- Request: The length of the request body in octets (8-bit bytes)
|
||||
-- Response: The length of the response body in octets (8-bit bytes)
|
||||
--| Example: Content-Length: 348
|
||||
|
||||
header_content_md5: STRING = "Content-MD5"
|
||||
-- Request: A Base64-encoded binary MD5 sum of the content of the request body
|
||||
-- Response: A Base64-encoded binary MD5 sum of the content of the response
|
||||
--| Example: Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
|
||||
|
||||
header_content_type: STRING = "Content-Type"
|
||||
-- Request: The mime type of the body of the request (used with POST and PUT requests)
|
||||
-- Response : The mime type of this content
|
||||
--| Request example: Content-Type: application/x-www-form-urlencoded
|
||||
--| Response example: Content-Type: text/html; charset=utf-8
|
||||
|
||||
header_date: STRING = "Date"
|
||||
-- The date and time that the message was sent
|
||||
--| Example: Date: Tue, 15 Nov 1994 08:12:31 GMT
|
||||
|
||||
header_pragma: STRING = "Pragma"
|
||||
-- Implementation-specific headers that may have various effects anywhere along the request-response chain.
|
||||
--| Example: Pragma: no-cache
|
||||
|
||||
header_via: STRING = "Via"
|
||||
-- Request: Informs the server of proxies through which the request was sent.
|
||||
-- Response: Informs the client of proxies through which the response was sent.
|
||||
--| Example: Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
|
||||
|
||||
header_warning: STRING = "Warning"
|
||||
-- A general warning about possible problems with the entity body.
|
||||
--| Example: Warning: 199 Miscellaneous warning
|
||||
|
||||
feature -- MIME related
|
||||
|
||||
header_content_transfer_encoding: STRING = "Content-Transfer-Encoding"
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
185
library/protocol/http/src/http_mime_types.e
Normal file
185
library/protocol/http/src/http_mime_types.e
Normal file
@@ -0,0 +1,185 @@
|
||||
note
|
||||
description: "[
|
||||
Various common MIME types
|
||||
|
||||
See also for longer list and description
|
||||
http://www.iana.org/assignments/media-types/index.html
|
||||
http://www.webmaster-toolkit.com/mime-types.shtml
|
||||
|
||||
Please suggest common/popular MIME type which might be missing here
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_MIME_TYPES
|
||||
|
||||
feature -- Content type : application
|
||||
|
||||
application_atom_xml: STRING = "application/atom+xml"
|
||||
-- atom application content-type header
|
||||
|
||||
application_force_download: STRING = "application/force-download"
|
||||
|
||||
application_javascript: STRING = "application/javascript"
|
||||
-- JavaScript application content-type header
|
||||
|
||||
application_json: STRING = "application/json"
|
||||
-- JSON application content-type header
|
||||
|
||||
application_octet_stream: STRING = "application/octet-stream"
|
||||
-- Octet stream content-type header
|
||||
|
||||
application_pdf: STRING = "application/pdf"
|
||||
-- pdf application content-type header
|
||||
|
||||
application_postscript: STRING = "application/postscript"
|
||||
-- postscript application content-type header
|
||||
|
||||
application_rss_xml: STRING = "application/rss+xml"
|
||||
-- rss application content-type header
|
||||
|
||||
application_rtf: STRING = "application/rtf"
|
||||
-- RTF application content-type header
|
||||
|
||||
application_xml: STRING = "application/xml"
|
||||
-- xml application content-type header
|
||||
|
||||
application_x_shockwave_flash: STRING = "application/x-shockwave-flash"
|
||||
|
||||
application_x_compressed: STRING = "application/x-compressed"
|
||||
|
||||
application_x_gzip: STRING = "application/x-gzip"
|
||||
|
||||
application_zip: STRING = "application/zip"
|
||||
|
||||
application_x_bzip: STRING = "application/x-bzip"
|
||||
|
||||
application_x_bzip2: STRING = "application/x-bzip2"
|
||||
|
||||
application_x_tar: STRING = "application/x-tar"
|
||||
|
||||
application_x_www_form_encoded: STRING = "application/x-www-form-urlencoded"
|
||||
-- Starting chars of form url-encoded data content-type header
|
||||
|
||||
feature -- Content type : audio
|
||||
|
||||
audio_mpeg3: STRING = "audio/mpeg3"
|
||||
|
||||
audio_mpeg: STRING = "audio/mpeg"
|
||||
|
||||
audio_wav: STRING = "audio/wav"
|
||||
|
||||
feature -- Content type : image
|
||||
|
||||
image_bmp: STRING = "image/bmp"
|
||||
-- BMP image content-type header
|
||||
|
||||
image_gif: STRING = "image/gif"
|
||||
-- GIF image content-type header
|
||||
|
||||
image_jpeg: STRING = "image/jpeg"
|
||||
-- JPEG image content-type header
|
||||
|
||||
image_jpg: STRING = "image/jpg"
|
||||
-- JPEG image content-type header
|
||||
|
||||
image_png: STRING = "image/png"
|
||||
-- PNG image content-type header
|
||||
|
||||
image_svg_xml: STRING = "image/svg+xml"
|
||||
-- SVG+XML image content-type header
|
||||
|
||||
image_tiff: STRING = "image/tiff"
|
||||
-- TIFF image content-type header
|
||||
|
||||
image_x_ico: STRING = "image/x-ico"
|
||||
-- ICO image content-type header
|
||||
|
||||
feature -- Content type : message
|
||||
|
||||
message_http: STRING = "message/http"
|
||||
-- http message content-type header
|
||||
|
||||
message_s_http: STRING = "message/s-http"
|
||||
-- s-http message content-type
|
||||
|
||||
message_partial: STRING = "message/partial"
|
||||
-- partial message content-type
|
||||
|
||||
message_sip: STRING = "message/sip"
|
||||
-- sip message content-type
|
||||
|
||||
feature -- Content type : model
|
||||
|
||||
model_vrml: STRING = "model/vrml"
|
||||
|
||||
feature -- Content type : multipart
|
||||
|
||||
multipart_mixed: STRING = "multipart/mixed"
|
||||
|
||||
multipart_alternative: STRING = "multipart/alternative"
|
||||
|
||||
multipart_related: STRING = "multipart/related"
|
||||
|
||||
multipart_form_data: STRING = "multipart/form-data"
|
||||
|
||||
multipart_signed: STRING = "multipart/signed"
|
||||
|
||||
multipart_encrypted: STRING = "multipart/encrypted"
|
||||
|
||||
multipart_x_gzip: STRING = "multipart/x-gzip"
|
||||
|
||||
feature -- Content type : text
|
||||
|
||||
text_css: STRING = "text/css"
|
||||
-- CSS text content-type header
|
||||
|
||||
text_csv: STRING = "text/csv"
|
||||
-- CSV text content-type header
|
||||
|
||||
text_html: STRING = "text/html"
|
||||
-- HTML text content-type header
|
||||
|
||||
text_javascript: STRING = "text/javascript"
|
||||
-- Javascript text content-type header
|
||||
-- OBSOLETE
|
||||
|
||||
text_json: STRING = "text/json"
|
||||
-- JSON text content-type header
|
||||
|
||||
text_plain: STRING = "text/plain"
|
||||
-- Plain text content-type header
|
||||
|
||||
text_rtf: STRING = "text/rtf"
|
||||
-- rtf content-type header
|
||||
|
||||
text_tab_separated_values: STRING = "text/tab-separated-values"
|
||||
-- TSV text content-type header
|
||||
|
||||
text_xml: STRING = "text/xml"
|
||||
-- XML text content-type header
|
||||
|
||||
text_vcard: STRING = "text/vcard"
|
||||
-- vcard text content-type header
|
||||
|
||||
feature -- Content type : video
|
||||
|
||||
video_avi: STRING = "video/avi"
|
||||
|
||||
video_quicktime: STRING = "video/quicktime"
|
||||
|
||||
video_x_motion_jpeg: STRING = "video/x-motion-jpeg"
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -6,31 +6,30 @@ note
|
||||
class
|
||||
HTTP_REQUEST_METHOD_CONSTANTS
|
||||
|
||||
inherit
|
||||
HTTP_REQUEST_METHODS
|
||||
|
||||
feature -- Id
|
||||
|
||||
method_get: INTEGER = 0x1
|
||||
head: INTEGER = 0x1
|
||||
|
||||
method_post: INTEGER = 0x2
|
||||
get: INTEGER = 0x2
|
||||
|
||||
method_put: INTEGER = 0x4
|
||||
trace: INTEGER = 0x4
|
||||
|
||||
method_delete: INTEGER = 0x8
|
||||
options: INTEGER = 0x8
|
||||
|
||||
method_head: INTEGER = 0x10
|
||||
post: INTEGER = 0x10
|
||||
|
||||
put: INTEGER = 0x20
|
||||
|
||||
delete: INTEGER = 0x40
|
||||
|
||||
connect: INTEGER = 0x80
|
||||
|
||||
feature -- Name
|
||||
|
||||
method_get_name: STRING = "GET"
|
||||
|
||||
method_post_name: STRING = "POST"
|
||||
|
||||
method_put_name: STRING = "PUT"
|
||||
|
||||
method_delete_name: STRING = "DELETE"
|
||||
|
||||
method_head_name: STRING = "HEAD"
|
||||
|
||||
method_empty_name: STRING = ""
|
||||
method_empty: STRING = ""
|
||||
|
||||
feature -- Query
|
||||
|
||||
@@ -39,35 +38,45 @@ feature -- Query
|
||||
s: STRING
|
||||
do
|
||||
s := a_id.as_lower
|
||||
if s.same_string (method_get_name) then
|
||||
Result := method_get
|
||||
elseif s.same_string (method_post_name) then
|
||||
Result := method_post
|
||||
elseif s.same_string (method_put_name) then
|
||||
Result := method_put
|
||||
elseif s.same_string (method_delete_name) then
|
||||
Result := method_delete
|
||||
elseif s.same_string (method_head_name) then
|
||||
Result := method_head
|
||||
if s.same_string (method_get) then
|
||||
Result := get
|
||||
elseif s.same_string (method_post) then
|
||||
Result := post
|
||||
elseif s.same_string (method_put) then
|
||||
Result := put
|
||||
elseif s.same_string (method_delete) then
|
||||
Result := delete
|
||||
elseif s.same_string (method_head) then
|
||||
Result := head
|
||||
elseif s.same_string (method_trace) then
|
||||
Result := trace
|
||||
elseif s.same_string (method_options) then
|
||||
Result := options
|
||||
elseif s.same_string (method_connect) then
|
||||
Result := connect
|
||||
end
|
||||
end
|
||||
|
||||
method_name (a_id: INTEGER): STRING
|
||||
do
|
||||
inspect a_id
|
||||
when method_get then Result := method_get_name
|
||||
when method_post then Result := method_post_name
|
||||
when method_put then Result := method_put_name
|
||||
when method_delete then Result := method_delete_name
|
||||
when method_head then Result := method_head_name
|
||||
else Result := method_empty_name
|
||||
when head then Result := method_head
|
||||
when get then Result := method_get
|
||||
when trace then Result := method_trace
|
||||
when options then Result := method_options
|
||||
when post then Result := method_post
|
||||
when put then Result := method_put
|
||||
when delete then Result := method_delete
|
||||
when connect then Result := method_connect
|
||||
else
|
||||
Result := method_empty
|
||||
end
|
||||
ensure
|
||||
result_is_upper_case: Result /= Void and then Result.as_upper ~ Result
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
@@ -76,4 +85,5 @@ note
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
|
||||
end
|
||||
|
||||
75
library/protocol/http/src/http_request_methods.e
Normal file
75
library/protocol/http/src/http_request_methods.e
Normal file
@@ -0,0 +1,75 @@
|
||||
note
|
||||
description: "[
|
||||
|
||||
Safe method: HEAD, GET, TRACE, OPTIONS
|
||||
Intended only for information retrieval, should not change state of server
|
||||
|
||||
|
||||
See http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_REQUEST_METHODS
|
||||
|
||||
feature -- Safe Methods
|
||||
|
||||
method_head: STRING = "HEAD"
|
||||
-- Asks for the response identical to the one that would correspond
|
||||
-- to a GET request, but without the response body.
|
||||
-- This is useful for retrieving meta-information written in response headers,
|
||||
-- without having to transport the entire content.
|
||||
|
||||
method_get: STRING = "GET"
|
||||
-- Requests a representation of the specified resource.
|
||||
-- Requests using GET (and a few other HTTP methods)
|
||||
-- "SHOULD NOT have the significance of taking an action other than retrieval"
|
||||
-- The W3C has published guidance principles on this distinction, saying,
|
||||
-- "Web application design should be informed by the above principles,
|
||||
-- but also by the relevant limitations."
|
||||
|
||||
method_trace: STRING = "TRACE"
|
||||
-- Echoes back the received request, so that a client can see what
|
||||
-- (if any) changes or additions have been made by intermediate servers.
|
||||
|
||||
method_options: STRING = "OPTIONS"
|
||||
-- Returns the HTTP methods that the server supports for specified URL.
|
||||
-- This can be used to check the functionality of a web server by requesting '*'
|
||||
-- instead of a specific resource.
|
||||
|
||||
feature -- Methods intented for actions
|
||||
|
||||
method_post: STRING = "POST"
|
||||
-- Submits data to be processed (e.g., from an HTML form) to the identified resource.
|
||||
-- The data is included in the body of the request.
|
||||
-- This may result in the creation of a new resource or the updates of existing
|
||||
-- resources or both.
|
||||
|
||||
method_put: STRING = "PUT"
|
||||
-- Uploads a representation of the specified resource.
|
||||
|
||||
method_delete: STRING = "DELETE"
|
||||
-- Deletes the specified resource.
|
||||
|
||||
feature -- Other Methods
|
||||
|
||||
method_connect: STRING = "CONNECT"
|
||||
-- Converts the request connection to a transparent TCP/IP tunnel,
|
||||
-- usually to facilitate SSL-encrypted communication (HTTPS) through
|
||||
-- an unencrypted HTTP proxy.
|
||||
|
||||
method_patch: STRING = "PATCH"
|
||||
-- Is used to apply partial modifications to a resource
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -23,18 +23,44 @@ inherit
|
||||
create
|
||||
make
|
||||
|
||||
create {URI_TEMPLATE}
|
||||
make_from_uri_template
|
||||
|
||||
convert
|
||||
make ({READABLE_STRING_8})
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (s: STRING)
|
||||
make (s: READABLE_STRING_8)
|
||||
do
|
||||
template := s
|
||||
end
|
||||
|
||||
make_from_uri_template (a_tpl: like Current)
|
||||
do
|
||||
template := a_tpl.template.string
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
template: STRING
|
||||
template: READABLE_STRING_8
|
||||
-- URI string representation
|
||||
|
||||
duplicate: like Current
|
||||
-- Duplicate object from Current
|
||||
do
|
||||
create Result.make_from_uri_template (Current)
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_template (t: like template)
|
||||
-- Set `template' to `t'
|
||||
do
|
||||
template := t
|
||||
reset
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
@@ -153,16 +179,20 @@ feature -- Builder
|
||||
feature -- Match
|
||||
|
||||
match (a_uri: STRING): detachable URI_TEMPLATE_MATCH_RESULT
|
||||
require
|
||||
is_valid: is_valid
|
||||
local
|
||||
b: BOOLEAN
|
||||
tpl: like template
|
||||
l_offset: INTEGER
|
||||
p,q: INTEGER
|
||||
p,q,nb: INTEGER
|
||||
exp: URI_TEMPLATE_EXPRESSION
|
||||
vn, s,t: STRING
|
||||
vv: STRING
|
||||
l_vars, l_path_vars, l_query_vars: HASH_TABLE [STRING, STRING]
|
||||
vv, path_vv: STRING
|
||||
l_vars, l_path_vars, l_query_vars: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL]
|
||||
l_uri_count: INTEGER
|
||||
tpl_count: INTEGER
|
||||
l_next_literal_separator: detachable STRING
|
||||
do
|
||||
--| Extract expansion parts "\\{([^\\}]*)\\}"
|
||||
analyze
|
||||
@@ -173,8 +203,10 @@ feature -- Match
|
||||
b := True
|
||||
l_uri_count := a_uri.count
|
||||
tpl := template
|
||||
tpl_count := tpl.count
|
||||
if l_expressions.is_empty then
|
||||
b := a_uri.substring (1, tpl.count).same_string (tpl)
|
||||
-- b := a_uri.substring (1, tpl_count).same_string (tpl)
|
||||
b := a_uri.same_string (tpl)
|
||||
else
|
||||
from
|
||||
l_expressions.start
|
||||
@@ -190,7 +222,10 @@ feature -- Match
|
||||
if p = q then
|
||||
--| There should be at least one literal between two expression
|
||||
--| {var}{foobar} is ambigous for matching ...
|
||||
b := False
|
||||
--| unless with {/var} or {?var} ... since we can search for '/' or '?'
|
||||
exp.analyze
|
||||
b := exp.operator = '/' or exp.operator = '?'
|
||||
p := exp.end_position
|
||||
elseif q > p then
|
||||
if p = 0 then
|
||||
p := 1
|
||||
@@ -200,6 +235,8 @@ feature -- Match
|
||||
b := s.same_string (t)
|
||||
p := exp.end_position
|
||||
end
|
||||
l_expressions.forth --| we forth `l_expressions' so be careful
|
||||
|
||||
--| Check related variable
|
||||
if b and then not vn.is_empty then
|
||||
if exp.is_query then
|
||||
@@ -211,18 +248,66 @@ feature -- Match
|
||||
inspect vn[1]
|
||||
when '?' then
|
||||
import_form_style_parameters_into (a_uri.substring (q + l_offset + 1, l_uri_count), l_vars)
|
||||
p := tpl_count + 1
|
||||
l_offset := l_offset + (l_uri_count - (q + l_offset + 1))
|
||||
when ';' then
|
||||
import_path_style_parameters_into (a_uri.substring (q + l_offset, l_uri_count), l_vars)
|
||||
p := tpl_count + 1
|
||||
else
|
||||
vv := next_path_variable_value (a_uri, q + l_offset)
|
||||
l_vars.force (vv, vn)
|
||||
l_offset := l_offset + vv.count - (vn.count + 2)
|
||||
if not l_expressions.after then
|
||||
exp := l_expressions.item --| We change `exp' here
|
||||
exp.analyze
|
||||
if exp.operator = '/' or exp.operator = '?' then
|
||||
l_next_literal_separator := Void
|
||||
else
|
||||
l_next_literal_separator := tpl.substring (p, exp.position -1)
|
||||
end
|
||||
elseif p < tpl_count then
|
||||
l_next_literal_separator := tpl.substring (p, tpl_count)
|
||||
else
|
||||
l_next_literal_separator := Void
|
||||
end
|
||||
if vn[1] = '/' then
|
||||
vn := vn.substring (2, vn.count)
|
||||
from
|
||||
create path_vv.make_empty
|
||||
vv := "/"
|
||||
nb := 0
|
||||
until
|
||||
vv.is_empty or q + l_offset + 1 > a_uri.count
|
||||
loop
|
||||
vv := next_path_variable_value (a_uri, q + l_offset + 1, l_next_literal_separator)
|
||||
l_offset := l_offset + vv.count + 1
|
||||
nb := nb + 1
|
||||
if not vv.is_empty then
|
||||
path_vv.extend ('/')
|
||||
path_vv.append (vv)
|
||||
l_vars.force (vv, vn + "[" + nb.out + "]")
|
||||
end
|
||||
end
|
||||
l_vars.force (path_vv, vn)
|
||||
l_offset := l_offset - (1 + vn.count + 2)
|
||||
else
|
||||
vv := next_path_variable_value (a_uri, q + l_offset, l_next_literal_separator)
|
||||
l_vars.force (vv, vn)
|
||||
l_offset := l_offset + vv.count - (vn.count + 2)
|
||||
end
|
||||
end
|
||||
else
|
||||
b := exp.is_query --| query are optional
|
||||
end
|
||||
end
|
||||
l_expressions.forth
|
||||
if b and l_expressions.after then
|
||||
if
|
||||
(p < tpl_count) or
|
||||
(p + l_offset < l_uri_count)
|
||||
then
|
||||
--| Remaining literal part
|
||||
t := tpl.substring (p, tpl_count)
|
||||
s := a_uri.substring (p + l_offset, l_uri_count)
|
||||
b := s.same_string (t)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if b then
|
||||
@@ -231,8 +316,36 @@ feature -- Match
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
parse
|
||||
-- Parse template
|
||||
do
|
||||
reset
|
||||
analyze
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_valid: BOOLEAN
|
||||
-- Is Current URI template valid?
|
||||
do
|
||||
analyze
|
||||
Result := not has_syntax_error
|
||||
end
|
||||
|
||||
feature {NONE} -- Internal Access
|
||||
|
||||
reset
|
||||
do
|
||||
expressions := Void
|
||||
has_syntax_error := False
|
||||
end
|
||||
|
||||
has_syntax_error: BOOLEAN
|
||||
-- Has syntax error
|
||||
--| Make sense only if `analyze' was processed before
|
||||
|
||||
expressions: detachable LIST [URI_TEMPLATE_EXPRESSION]
|
||||
-- Expansion parts
|
||||
|
||||
@@ -248,6 +361,7 @@ feature {NONE} -- Implementation
|
||||
in_query: BOOLEAN
|
||||
x: STRING
|
||||
exp: URI_TEMPLATE_EXPRESSION
|
||||
l_has_query_expression: BOOLEAN
|
||||
do
|
||||
l_expressions := expressions
|
||||
if l_expressions = Void then
|
||||
@@ -258,6 +372,7 @@ feature {NONE} -- Implementation
|
||||
from
|
||||
i := 1
|
||||
n := tpl.count
|
||||
l_has_query_expression := False
|
||||
create x.make_empty
|
||||
until
|
||||
i > n
|
||||
@@ -269,6 +384,10 @@ feature {NONE} -- Implementation
|
||||
l_expressions.force (exp)
|
||||
x.wipe_out
|
||||
in_x := False
|
||||
if l_has_query_expression and then i < n then
|
||||
--| Remaining text after {?exp}
|
||||
has_syntax_error := True
|
||||
end
|
||||
else
|
||||
x.extend (c)
|
||||
end
|
||||
@@ -278,8 +397,11 @@ feature {NONE} -- Implementation
|
||||
check x_is_empty: x.is_empty end
|
||||
p := i
|
||||
in_x := True
|
||||
if not l_has_query_expression then
|
||||
l_has_query_expression := tpl.valid_index (i+1) and then tpl[i+1] = '?'
|
||||
end
|
||||
if not in_query then
|
||||
in_query := tpl.valid_index (i+1) and then tpl[i+1] = '?'
|
||||
in_query := l_has_query_expression
|
||||
end
|
||||
when '?' then
|
||||
in_query := True
|
||||
@@ -292,7 +414,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
import_path_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING])
|
||||
import_path_style_parameters_into (a_content: STRING; res: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL])
|
||||
require
|
||||
a_content_attached: a_content /= Void
|
||||
res_attached: res /= Void
|
||||
@@ -300,7 +422,7 @@ feature {NONE} -- Implementation
|
||||
import_custom_style_parameters_into (a_content, ';', res)
|
||||
end
|
||||
|
||||
import_form_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING])
|
||||
import_form_style_parameters_into (a_content: STRING; res: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL])
|
||||
require
|
||||
a_content_attached: a_content /= Void
|
||||
res_attached: res /= Void
|
||||
@@ -308,7 +430,7 @@ feature {NONE} -- Implementation
|
||||
import_custom_style_parameters_into (a_content, '&', res)
|
||||
end
|
||||
|
||||
import_custom_style_parameters_into (a_content: STRING; a_separator: CHARACTER; res: HASH_TABLE [STRING, STRING])
|
||||
import_custom_style_parameters_into (a_content: STRING; a_separator: CHARACTER; res: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL])
|
||||
require
|
||||
a_content_attached: a_content /= Void
|
||||
res_attached: res /= Void
|
||||
@@ -344,23 +466,39 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
next_path_variable_value (a_uri: STRING; a_index: INTEGER): STRING
|
||||
next_path_variable_value (a_uri: STRING; a_index: INTEGER; a_end_token: detachable STRING): STRING
|
||||
require
|
||||
valid_index: a_index <= a_uri.count
|
||||
local
|
||||
c: CHARACTER
|
||||
i,n,p: INTEGER
|
||||
l_end_token_first_char: CHARACTER
|
||||
l_end_token_count: INTEGER
|
||||
do
|
||||
from
|
||||
if a_end_token /= Void and then not a_end_token.is_empty then
|
||||
l_end_token_first_char := a_end_token.item (1)
|
||||
l_end_token_count := a_end_token.count
|
||||
end
|
||||
i := a_index
|
||||
n := a_uri.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
inspect a_uri[i]
|
||||
c := a_uri[i]
|
||||
inspect c
|
||||
when '/', '?' then
|
||||
i := n
|
||||
else
|
||||
p := i
|
||||
if
|
||||
a_end_token /= Void and then
|
||||
c = l_end_token_first_char and then
|
||||
a_uri.substring (i, i + l_end_token_count - 1).same_string (a_end_token)
|
||||
then
|
||||
i := n
|
||||
else
|
||||
p := i
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
|
||||
@@ -11,7 +11,8 @@ inherit
|
||||
ANY
|
||||
|
||||
DEBUG_OUTPUT
|
||||
|
||||
export {NONE} all end
|
||||
|
||||
URI_TEMPLATE_CONSTANTS
|
||||
export {NONE} all end
|
||||
|
||||
|
||||
@@ -24,22 +24,75 @@ feature {NONE} -- Initialization
|
||||
make (create {like path_variables}.make (0), create {like query_variables}.make (0))
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
variable (n: STRING): detachable STRING
|
||||
-- Value related to variable name `n'
|
||||
path_variables: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL]
|
||||
-- Variables being part of the path segments
|
||||
|
||||
query_variables: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL]
|
||||
-- Variables being part of the query segments (i.e: after the ?)
|
||||
|
||||
feature -- Query
|
||||
|
||||
path_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- Value related to query variable name `n'
|
||||
do
|
||||
Result := path_variables.item (n)
|
||||
end
|
||||
|
||||
query_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- Value related to path variable name `n'
|
||||
do
|
||||
Result := query_variables.item (n)
|
||||
end
|
||||
|
||||
variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- Value related to variable name `n'
|
||||
do
|
||||
Result := query_variable (n)
|
||||
if Result = Void then
|
||||
Result := path_variables.item (n)
|
||||
Result := path_variable (n)
|
||||
end
|
||||
end
|
||||
|
||||
path_variables: HASH_TABLE [STRING, STRING]
|
||||
-- Variables being part of the path segments
|
||||
feature -- Query: url-decoded
|
||||
|
||||
query_variables: HASH_TABLE [STRING, STRING]
|
||||
-- Variables being part of the query segments (i.e: after the ? )
|
||||
url_decoded_query_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- Unencoded value related to variable name `n'
|
||||
do
|
||||
if attached query_variable (n) as v then
|
||||
Result := url_decoded_string (v)
|
||||
end
|
||||
end
|
||||
|
||||
url_decoded_path_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- Unencoded value related to variable name `n'
|
||||
do
|
||||
if attached path_variable (n) as v then
|
||||
Result := url_decoded_string (v)
|
||||
end
|
||||
end
|
||||
|
||||
url_decoded_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- Unencoded value related to variable name `n'
|
||||
do
|
||||
if attached variable (n) as v then
|
||||
Result := url_decoded_string (v)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
url_decoded_string (s: READABLE_STRING_GENERAL): READABLE_STRING_32
|
||||
do
|
||||
Result := url_encoder.decoded_string (s.as_string_8)
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
|
||||
@@ -21,6 +21,9 @@ feature -- Test routines
|
||||
do
|
||||
uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>)
|
||||
uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>)
|
||||
uri_template_parse ("/hello/{name}.{format}", <<"name", "format">>, <<>>)
|
||||
uri_template_parse ("/hello.{format}/{name}", <<"format", "name">>, <<>>)
|
||||
-- uri_template_parse ("/hello/{name}.{format}/foo{?foobar};crazy=IDEA", <<"name", "format">>, <<"foobar">>)
|
||||
end
|
||||
|
||||
test_uri_template_matcher
|
||||
@@ -29,6 +32,13 @@ feature -- Test routines
|
||||
local
|
||||
tpl: URI_TEMPLATE
|
||||
do
|
||||
create tpl.make ("/hello.{format}{/vars}")
|
||||
uri_template_match (tpl, "/hello.json/foo/bar", <<["format", "json"], ["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>)
|
||||
|
||||
create tpl.make ("/hello.{format}{?op}")
|
||||
uri_template_match (tpl, "/hello.json?op=foobar", <<["format", "json"]>>, << ["op", "foobar"]>>)
|
||||
|
||||
|
||||
create tpl.make ("{version}/{id}")
|
||||
uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>)
|
||||
|
||||
@@ -49,6 +59,36 @@ feature -- Test routines
|
||||
|
||||
create tpl.make ("weather/{state}/{city}?forecast={day}")
|
||||
uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>)
|
||||
|
||||
create tpl.make ("/hello")
|
||||
uri_template_match (tpl, "/hello", <<>>, <<>>)
|
||||
uri_template_mismatch (tpl, "/hello/Foo2") -- longer
|
||||
uri_template_mismatch (tpl, "/hell") -- shorter
|
||||
|
||||
create tpl.make ("/hello.{format}")
|
||||
uri_template_match (tpl, "/hello.xml", <<["format", "xml"]>>, <<>>)
|
||||
uri_template_mismatch (tpl, "/hello.xml/Bar")
|
||||
|
||||
|
||||
create tpl.make ("/hello.{format}/{name}")
|
||||
uri_template_match (tpl, "/hello.xml/Joce", <<["format", "xml"], ["name", "Joce"]>>, <<>>)
|
||||
|
||||
create tpl.make ("/hello/{name}.{format}")
|
||||
uri_template_match (tpl, "/hello/Joce.json", <<["name", "Joce"], ["format", "json"]>>, <<>>)
|
||||
|
||||
create tpl.make ("/hello/{name}.{format}/foo")
|
||||
uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>)
|
||||
uri_template_mismatch (tpl, "/hello/Joce.xml/fooBAR")
|
||||
|
||||
create tpl.make ("/hello{/vars}")
|
||||
uri_template_match (tpl, "/hello/foo/bar", <<["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>)
|
||||
|
||||
|
||||
-- create tpl.make ("/hello/{name}.{format}/foo{?foo};crazy={idea}")
|
||||
---- uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>)
|
||||
-- uri_template_match (tpl, "/hello/Joce.xml/foo?foo=FOO", <<["name", "Joce"], ["format", "xml"]>>, <<["foo", "FOO"]>>)
|
||||
-- uri_template_match (tpl, "/hello/Joce.xml/foo;crazy=IDEA", <<["name", "Joce"], ["format", "xml"]>>, <<["idea", "IDEA"], ["crazy", "IDEA"]>>)
|
||||
|
||||
end
|
||||
|
||||
uri_template_string_errors: detachable LIST [STRING]
|
||||
@@ -544,6 +584,8 @@ feature -- Test routines
|
||||
i: INTEGER
|
||||
do
|
||||
create u.make (s)
|
||||
u.parse
|
||||
assert ("Template %""+ s +"%" is valid", u.is_valid)
|
||||
if attached u.path_variable_names as vars then
|
||||
matched := vars.count = path_vars.count
|
||||
from
|
||||
@@ -559,7 +601,7 @@ feature -- Test routines
|
||||
else
|
||||
matched := path_vars.is_empty
|
||||
end
|
||||
assert ("path variables matched", matched)
|
||||
assert ("path variables matched for %""+ s +"%"", matched)
|
||||
|
||||
if attached u.query_variable_names as vars then
|
||||
matched := vars.count = query_vars.count
|
||||
@@ -576,7 +618,7 @@ feature -- Test routines
|
||||
else
|
||||
matched := query_vars.is_empty
|
||||
end
|
||||
assert ("query variables matched", matched)
|
||||
assert ("query variables matched %""+ s +"%"", matched)
|
||||
end
|
||||
|
||||
uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?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="http_authorization" uuid="321674DB-CE7C-417C-ADE8-64CFA376CD3E" library_target="http_authorization">
|
||||
<target name="http_authorization">
|
||||
<root all_classes="true"/>
|
||||
<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>
|
||||
<library name="base" location="$ISE_LIBRARY/library/base/base-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<cluster name="src" location="./src" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?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="http_authorization" uuid="321674DB-CE7C-417C-ADE8-64CFA376CD3E" library_target="http_authorization">
|
||||
<target name="http_authorization">
|
||||
<root all_classes="true"/>
|
||||
<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>
|
||||
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf"/>
|
||||
<cluster name="src" location="./src" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -0,0 +1,93 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
HTTP_AUTHORIZATION
|
||||
|
||||
inherit
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make,
|
||||
make_basic_auth,
|
||||
make_custom_auth
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_http_authorization: detachable READABLE_STRING_GENERAL)
|
||||
-- Initialize `Current'.
|
||||
local
|
||||
i: INTEGER
|
||||
t, s: STRING_8
|
||||
u,p: READABLE_STRING_8
|
||||
do
|
||||
if attached a_http_authorization as l_auth then
|
||||
s := l_auth.as_string_8
|
||||
if not s.is_empty then
|
||||
i := 1
|
||||
if s[i] = ' ' then
|
||||
i := i + 1
|
||||
end
|
||||
i := s.index_of (' ', i)
|
||||
if i > 0 then
|
||||
t := s.substring (1, i - 1).as_lower
|
||||
t.right_adjust; t.left_adjust
|
||||
type := t
|
||||
if t.same_string ("basic") then
|
||||
s := (create {BASE64}).decoded_string (s.substring (i + 1, s.count))
|
||||
i := s.index_of (':', 1) --| Let's assume ':' is forbidden in login ...
|
||||
if i > 0 then
|
||||
u := s.substring (1, i - 1).as_string_32
|
||||
p := s.substring (i + 1, s.count).as_string_32
|
||||
login := u
|
||||
password := p
|
||||
check
|
||||
(create {HTTP_AUTHORIZATION}.make_custom_auth (u, p, t)).http_authorization ~ http_authorization
|
||||
end
|
||||
end
|
||||
elseif t.same_string ("digest") then
|
||||
to_implement ("HTTP Authorization %"digest%", not yet implemented")
|
||||
else
|
||||
to_implement ("HTTP Authorization %""+ t +"%", not yet implemented")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
make_basic_auth (u: READABLE_STRING_32; p: READABLE_STRING_32)
|
||||
do
|
||||
make_custom_auth (u, p, "basic")
|
||||
end
|
||||
|
||||
make_custom_auth (u: READABLE_STRING_32; p: READABLE_STRING_32; a_type: READABLE_STRING_8)
|
||||
local
|
||||
t: STRING_8
|
||||
do
|
||||
login := u
|
||||
password := p
|
||||
create t.make_from_string (a_type.as_lower)
|
||||
t.left_adjust; t.right_adjust
|
||||
type := t
|
||||
if t.same_string ("basic") then
|
||||
http_authorization := "Basic " + (create {BASE64}).encoded_string (u + ":" + p)
|
||||
else
|
||||
to_implement ("HTTP Authorization %""+ t +"%", not yet implemented")
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
type: detachable READABLE_STRING_8
|
||||
|
||||
login: detachable READABLE_STRING_32
|
||||
|
||||
password: detachable READABLE_STRING_32
|
||||
|
||||
http_authorization: detachable READABLE_STRING_32
|
||||
|
||||
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
55
library/server/ewsgi/connectors/cgi/src/ewf_cgi_connector.e
Normal file
55
library/server/ewsgi/connectors/cgi/src/ewf_cgi_connector.e
Normal file
@@ -0,0 +1,55 @@
|
||||
note
|
||||
description: "Summary description for {EWF_CGI_CONNECTOR}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
EWF_CGI_CONNECTOR
|
||||
|
||||
inherit
|
||||
WGI_CONNECTOR
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Execution
|
||||
|
||||
launch
|
||||
local
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_RESPONSE_STREAM_BUFFER
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
create req.make ((create {EXECUTION_ENVIRONMENT}).starting_environment_variables, create {EWF_CGI_INPUT_STREAM}.make)
|
||||
create res.make (create {EWF_CGI_OUTPUT_STREAM}.make)
|
||||
application.execute (req, res)
|
||||
else
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.write_string ("<pre>" + l_trace + "</pre>")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
rescued := True
|
||||
retry
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for GW_CGI_INPUT_STREAM."
|
||||
description: "Summary description for EWF_CGI_INPUT_STREAM."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_CGI_INPUT_STREAM
|
||||
EWF_CGI_INPUT_STREAM
|
||||
|
||||
inherit
|
||||
EWSGI_INPUT_STREAM
|
||||
WGI_INPUT_STREAM
|
||||
|
||||
CONSOLE
|
||||
rename
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for GW_CGI_OUTPUT_STREAM."
|
||||
description: "Summary description for EWF_CGI_OUTPUT_STREAM."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_CGI_OUTPUT_STREAM
|
||||
EWF_CGI_OUTPUT_STREAM
|
||||
|
||||
inherit
|
||||
EWSGI_OUTPUT_STREAM
|
||||
WGI_OUTPUT_STREAM
|
||||
undefine
|
||||
flush
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi-safe.ecf" />
|
||||
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi.ecf" />
|
||||
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for {GW_LIBFCGI_CONNECTOR}."
|
||||
description: "Summary description for {EWF_LIBFCGI_CONNECTOR}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_LIBFCGI_CONNECTOR
|
||||
EWF_LIBFCGI_CONNECTOR
|
||||
|
||||
inherit
|
||||
EWSGI_CONNECTOR
|
||||
WGI_CONNECTOR
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -22,8 +22,8 @@ feature {NONE} -- Initialization
|
||||
initialize
|
||||
do
|
||||
create fcgi.make
|
||||
create {GW_LIBFCGI_INPUT_STREAM} input.make (fcgi)
|
||||
create {GW_LIBFCGI_OUTPUT_STREAM} output.make (fcgi)
|
||||
create {EWF_LIBFCGI_INPUT_STREAM} input.make (fcgi)
|
||||
create {EWF_LIBFCGI_OUTPUT_STREAM} output.make (fcgi)
|
||||
end
|
||||
|
||||
feature -- Server
|
||||
@@ -46,18 +46,37 @@ feature -- Execution
|
||||
|
||||
process_fcgi_request (vars: HASH_TABLE [STRING, STRING]; a_input: like input; a_output: like output)
|
||||
local
|
||||
gw_env: EWSGI_ENVIRONMENT_VARIABLES
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_RESPONSE_STREAM_BUFFER
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
create gw_env.make_with_variables (vars)
|
||||
application.process (gw_env, a_input, a_output)
|
||||
if not rescued then
|
||||
create req.make (vars, a_input)
|
||||
create res.make (a_output)
|
||||
application.execute (req, res)
|
||||
else
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.write_string ("<pre>" + l_trace + "</pre>")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
rescued := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature -- Input/Output
|
||||
|
||||
input: EWSGI_INPUT_STREAM
|
||||
input: WGI_INPUT_STREAM
|
||||
-- Input from client (from httpd server via FCGI)
|
||||
|
||||
output: EWSGI_OUTPUT_STREAM
|
||||
output: WGI_OUTPUT_STREAM
|
||||
-- Output to client (via httpd server/fcgi)
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for GW_LIBFCGI_INPUT_STREAM."
|
||||
description: "Summary description for EWF_LIBFCGI_INPUT_STREAM."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_LIBFCGI_INPUT_STREAM
|
||||
EWF_LIBFCGI_INPUT_STREAM
|
||||
|
||||
inherit
|
||||
EWSGI_INPUT_STREAM
|
||||
WGI_INPUT_STREAM
|
||||
|
||||
STRING_HANDLER
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for {GW_LIBFCGI_OUTPUT_STREAM}."
|
||||
description: "Summary description for {EWF_LIBFCGI_OUTPUT_STREAM}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_LIBFCGI_OUTPUT_STREAM
|
||||
EWF_LIBFCGI_OUTPUT_STREAM
|
||||
|
||||
inherit
|
||||
EWSGI_OUTPUT_STREAM
|
||||
WGI_OUTPUT_STREAM
|
||||
|
||||
HTTP_STATUS_CODE_MESSAGES
|
||||
export
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\..\ext\server\nino\nino-safe.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
note
|
||||
description: "Summary description for {GW_NINO_CONNECTOR}."
|
||||
description: "Summary description for {EWF_NINO_CONNECTOR}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_NINO_CONNECTOR
|
||||
EWF_NINO_CONNECTOR
|
||||
|
||||
inherit
|
||||
EWSGI_CONNECTOR
|
||||
WGI_CONNECTOR
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -20,9 +20,11 @@ create
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_with_base (a_app: like application; a_base: like base)
|
||||
require
|
||||
a_base_starts_with_slash: (a_base /= Void and then not a_base.is_empty) implies a_base.starts_with ("/")
|
||||
do
|
||||
make (a_app)
|
||||
base := a_base
|
||||
set_base (a_base)
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
@@ -52,8 +54,12 @@ feature -- Access
|
||||
feature -- Element change
|
||||
|
||||
set_base (b: like base)
|
||||
require
|
||||
b_starts_with_slash: (b /= Void and then not b.is_empty) implies b.starts_with ("/")
|
||||
do
|
||||
base := b
|
||||
ensure
|
||||
valid_base: (attached base as l_base and then not l_base.is_empty) implies l_base.starts_with ("/")
|
||||
end
|
||||
|
||||
feature -- Server
|
||||
@@ -62,7 +68,7 @@ feature -- Server
|
||||
local
|
||||
l_http_handler : HTTP_HANDLER
|
||||
do
|
||||
create {GW_NINO_HANDLER} l_http_handler.make_with_callback (server, "NINO_HANDLER", Current)
|
||||
create {EWF_NINO_HANDLER} l_http_handler.make_with_callback (server, "NINO_HANDLER", Current)
|
||||
debug ("nino")
|
||||
if attached base as l_base then
|
||||
print ("Base=" + l_base + "%N")
|
||||
@@ -73,11 +79,30 @@ feature -- Server
|
||||
|
||||
process_request (env: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM)
|
||||
local
|
||||
gw_env: EWSGI_ENVIRONMENT_VARIABLES
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_RESPONSE_STREAM_BUFFER
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
create gw_env.make_with_variables (env)
|
||||
gw_env.set_variable ("RAW_HEADER_DATA", a_headers_text)
|
||||
application.process (gw_env, create {GW_NINO_INPUT_STREAM}.make (a_input), create {GW_NINO_OUTPUT_STREAM}.make (a_output))
|
||||
if not rescued then
|
||||
create req.make (env, create {EWF_NINO_INPUT_STREAM}.make (a_input))
|
||||
create res.make (create {EWF_NINO_OUTPUT_STREAM}.make (a_output))
|
||||
req.set_meta_string_variable ("RAW_HEADER_DATA", a_headers_text)
|
||||
application.execute (req, res)
|
||||
else
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.write_string ("<pre>" + l_trace + "</pre>")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
rescued := True
|
||||
retry
|
||||
end
|
||||
|
||||
note
|
||||
@@ -5,7 +5,7 @@ note
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
GW_NINO_HANDLER
|
||||
EWF_NINO_HANDLER
|
||||
|
||||
inherit
|
||||
HTTP_CONNECTION_HANDLER
|
||||
@@ -23,7 +23,7 @@ feature {NONE} -- Initialization
|
||||
callback := a_callback
|
||||
end
|
||||
|
||||
callback: GW_NINO_CONNECTOR
|
||||
callback: EWF_NINO_CONNECTOR
|
||||
|
||||
feature -- Access
|
||||
|
||||
@@ -64,8 +64,16 @@ feature -- Request processing
|
||||
until
|
||||
a_headers_map.after
|
||||
loop
|
||||
vn := a_headers_map.key_for_iteration.as_upper
|
||||
create vn.make_from_string (a_headers_map.key_for_iteration.as_upper)
|
||||
vn.replace_substring_all ("-", "_")
|
||||
if
|
||||
vn.starts_with ("CONTENT_") and then
|
||||
(vn.same_string_general ({WGI_META_NAMES}.content_type) or vn.same_string_general ({WGI_META_NAMES}.content_length))
|
||||
then
|
||||
--| Keep this name
|
||||
else
|
||||
vn.prepend ("HTTP_")
|
||||
end
|
||||
add_environment_variable (a_headers_map.item_for_iteration, vn, env)
|
||||
a_headers_map.forth
|
||||
end
|
||||
@@ -90,6 +98,8 @@ feature -- Request processing
|
||||
l_server_name := l_host
|
||||
l_server_port := "80" -- Default
|
||||
end
|
||||
else
|
||||
check host_available: False end
|
||||
end
|
||||
|
||||
if attached a_headers_map.item ("Authorization") as l_authorization then
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for {GW_NINO_INPUT_STREAM}."
|
||||
description: "Summary description for {EWF_NINO_INPUT_STREAM}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_NINO_INPUT_STREAM
|
||||
EWF_NINO_INPUT_STREAM
|
||||
|
||||
inherit
|
||||
EWSGI_INPUT_STREAM
|
||||
WGI_INPUT_STREAM
|
||||
|
||||
create
|
||||
make
|
||||
@@ -22,7 +22,7 @@ feature {NONE} -- Initialization
|
||||
set_nino_input (a_nino_input)
|
||||
end
|
||||
|
||||
feature {GW_NINO_CONNECTOR, EWSGI_APPLICATION} -- Nino
|
||||
feature {EWF_NINO_CONNECTOR, WGI_APPLICATION} -- Nino
|
||||
|
||||
set_nino_input (i: like nino_input)
|
||||
do
|
||||
@@ -1,15 +1,15 @@
|
||||
note
|
||||
description: "Summary description for {GW_NINO_OUTPUT_STREAM}."
|
||||
description: "Summary description for {EWF_NINO_OUTPUT_STREAM}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_NINO_OUTPUT_STREAM
|
||||
EWF_NINO_OUTPUT_STREAM
|
||||
|
||||
inherit
|
||||
EWSGI_OUTPUT_STREAM
|
||||
WGI_OUTPUT_STREAM
|
||||
|
||||
HTTP_STATUS_CODE_MESSAGES
|
||||
export
|
||||
@@ -26,7 +26,7 @@ feature {NONE} -- Initialization
|
||||
set_nino_output (a_nino_output)
|
||||
end
|
||||
|
||||
feature {GW_NINO_CONNECTOR, EWSGI_APPLICATION} -- Nino
|
||||
feature {EWF_NINO_CONNECTOR, WGI_APPLICATION} -- Nino
|
||||
|
||||
set_nino_output (o: like nino_output)
|
||||
do
|
||||
@@ -1,19 +1,19 @@
|
||||
note
|
||||
description: "Summary description for {DEFAULT_EWSGI_APPLICATION}."
|
||||
description: "Summary description for {DEFAULT_WGI_APPLICATION}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
DEFAULT_EWSGI_APPLICATION
|
||||
DEFAULT_WGI_APPLICATION
|
||||
|
||||
inherit
|
||||
GW_APPLICATION_IMP
|
||||
WGI_APPLICATION
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_and_launch
|
||||
local
|
||||
cgi: GW_CGI_CONNECTOR
|
||||
cgi: EWF_CGI_CONNECTOR
|
||||
do
|
||||
create cgi.make (Current)
|
||||
cgi.launch
|
||||
@@ -11,7 +11,6 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="../ewsgi_specification-safe.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi-safe.ecf"/>
|
||||
<library name="connector_cgi" location="../connectors/cgi/cgi-safe.ecf"/>
|
||||
<library name="error" location="..\..\..\error\error-safe.ecf"/>
|
||||
|
||||
21
library/server/ewsgi/default/ewsgi_cgi.ecf
Normal file
21
library/server/ewsgi/default/ewsgi_cgi.ecf
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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="ewsgi_cgi" uuid="82D0E5BA-3EBD-4E0F-94D1-776375158DAA" library_target="ewsgi_cgi">
|
||||
<target name="ewsgi_cgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi.ecf"/>
|
||||
<library name="connector_cgi" location="../connectors/cgi/cgi.ecf"/>
|
||||
<library name="error" location="..\..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<cluster name="default_cgi" location="./cgi" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -11,7 +11,6 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="../ewsgi_specification-safe.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi-safe.ecf"/>
|
||||
<library name="connector_nino" location="../connectors/nino/nino-safe.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\ext\server\nino\nino-safe.ecf" readonly="false">
|
||||
|
||||
25
library/server/ewsgi/default/ewsgi_nino.ecf
Normal file
25
library/server/ewsgi/default/ewsgi_nino.ecf
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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="ewsgi_nino" uuid="11D70618-3D82-4C5B-9501-8833DD04A3D6" library_target="ewsgi_nino">
|
||||
<target name="ewsgi_nino">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi.ecf"/>
|
||||
<library name="connector_nino" location="../connectors/nino/nino.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
|
||||
<library name="error" location="..\..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<cluster name="default_nino" location="./nino" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
44
library/server/ewsgi/default/nino/default_wgi_application.e
Normal file
44
library/server/ewsgi/default/nino/default_wgi_application.e
Normal file
@@ -0,0 +1,44 @@
|
||||
note
|
||||
description: "Summary description for {DEFAULT_WGI_APPLICATION}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
DEFAULT_WGI_APPLICATION
|
||||
|
||||
inherit
|
||||
WGI_APPLICATION
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_and_launch
|
||||
local
|
||||
app: NINO_APPLICATION
|
||||
do
|
||||
port_number := 80
|
||||
base_url := ""
|
||||
debug ("nino")
|
||||
print ("Example: start a Nino web server on port " + port_number.out +
|
||||
", %Nand reply Hello World for any request such as http://localhost:" + port_number.out + "/" + base_url + "%N")
|
||||
end
|
||||
create app.make_custom (agent execute, base_url)
|
||||
app.listen (port_number)
|
||||
end
|
||||
|
||||
port_number: INTEGER
|
||||
|
||||
base_url: STRING
|
||||
|
||||
invariant
|
||||
port_number_valid: port_number > 0
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -12,22 +12,24 @@ create
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
make (a_callback: like {GW_AGENT_APPLICATION}.callback)
|
||||
make (a_callback: like {WGI_AGENT_APPLICATION}.callback)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_custom (a_callback, Void)
|
||||
end
|
||||
|
||||
make_custom (a_callback: like {GW_AGENT_APPLICATION}.callback; a_base_url: detachable STRING)
|
||||
make_custom (a_callback: like {WGI_AGENT_APPLICATION}.callback; a_base_url: detachable STRING)
|
||||
-- Initialize `Current'.
|
||||
require
|
||||
base_url_starts_with_slash: (a_base_url /= Void and then not a_base_url.is_empty) implies a_base_url.starts_with ("/")
|
||||
local
|
||||
app: GW_AGENT_APPLICATION
|
||||
app: WGI_AGENT_APPLICATION
|
||||
do
|
||||
create app.make (a_callback)
|
||||
create connector.make_with_base (app, a_base_url)
|
||||
end
|
||||
|
||||
connector: GW_NINO_CONNECTOR
|
||||
connector: EWF_NINO_CONNECTOR
|
||||
-- Web server connector
|
||||
|
||||
feature -- Status settings
|
||||
@@ -51,6 +53,12 @@ feature -- Server
|
||||
connector.launch
|
||||
end
|
||||
|
||||
shutdown
|
||||
-- Shutdown the server
|
||||
do
|
||||
connector.server.shutdown_server
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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="ewsgi-full" uuid="D924DBE1-1231-434A-80EF-234BA09D1E30" library_target="ewsgi-full">
|
||||
<target name="ewsgi-full">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="false" void_safety="none" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="ewsgi_specification.ecf"/>
|
||||
<library name="error" location="..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\libfcgi\libfcgi.ecf"/>
|
||||
<library name="nino" location="..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="connectors" location="connectors\" recursive="true"/>
|
||||
<cluster name="interface" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -11,10 +11,11 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="ewsgi_specification-safe.ecf"/>
|
||||
<library name="error" location="..\..\error\error-safe.ecf"/>
|
||||
<library name="http" location="..\..\protocol\http\http-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<cluster name="interface" location="src\" recursive="true"/>
|
||||
<cluster name="specification_request" location="specification\request" recursive="true"/>
|
||||
<cluster name="specification_response" location="specification\response" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="ewsgi_spec" location="ewsgi_specification.ecf"/>
|
||||
<library name="error" location="..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<cluster name="interface" location="src\" recursive="true" />
|
||||
<cluster name="specification_request" location="specification\request" recursive="true"/>
|
||||
<cluster name="specification_response" location="specification\response" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="ewsgi_spec" uuid="D6455232-E709-43B3-A2C7-D3E6F6A98288" library_target="ewsgi_spec">
|
||||
<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="ewsgi_spec" uuid="AA193B9F-02FD-47B9-B60D-C42B9AB35E1C" library_target="ewsgi_spec">
|
||||
<target name="ewsgi_spec">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="ewsgi_spec" uuid="D6455232-E709-43B3-A2C7-D3E6F6A98288" library_target="ewsgi_spec">
|
||||
<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="ewsgi_spec" uuid="AA193B9F-02FD-47B9-B60D-C42B9AB35E1C" library_target="ewsgi_spec">
|
||||
<target name="ewsgi_spec">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -13,7 +13,6 @@
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\..\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
19
library/server/ewsgi/examples/hello_world/hello.ecf
Normal file
19
library/server/ewsgi/examples/hello_world/hello.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="hello_world" uuid="734385F1-0D17-4B5F-9138-24DC8D4F06C6">
|
||||
<target name="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\..\connectors\nino\nino.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -18,7 +18,7 @@ feature {NONE} -- Initialization
|
||||
(create {NINO_APPLICATION}.make_custom (agent execute, "")).listen (port_number)
|
||||
end
|
||||
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
|
||||
execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||
do
|
||||
res.write_header (200, <<["Content-Type", "text/plain"]>>)
|
||||
res.write_string ("Hello World!%N")
|
||||
|
||||
@@ -7,23 +7,22 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<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"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<target name="hello_nino_world" extends="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make_and_launch"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\..\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="hello_cgi_world" extends="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make_and_launch"/>
|
||||
<library name="default_cgi" location="..\..\default\ewsgi_cgi-safe.ecf" readonly="false"/>
|
||||
<library name="connector_cgi" location="..\..\connectors\cgi\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="default_cgi" location="..\..\default\ewsgi_cgi-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
</system>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user