Compare commits

...

143 Commits

Author SHA1 Message Date
Jocelyn Fiat
eaa99c9c61 Used object test 2011-10-19 00:40:04 +02:00
Jocelyn Fiat
5f492d6fb6 removed useless local variable 2011-10-19 00:35:32 +02:00
Jocelyn Fiat
c3f5376ef5 fixed cgi and libfcgi connectors due to recent changes from WGI_APPLICATION 2011-10-14 14:27:54 +02:00
Jocelyn Fiat
21e973f8a4 Removed handling of internal error from WGI_APPLICATION
And for now added it into nino connector
2011-10-14 14:15:23 +02:00
Jocelyn Fiat
dec1958909 Fixed issue with index in uri template matcher 2011-10-14 14:14:13 +02:00
Jocelyn Fiat
1453873b6c Added HTTP_FILE_EXTENSION_MIME_MAPPING
Added REQUEST_FILE_SYSTEM_HANDLER to the router library
Added file system handler in "hello_routed_world" example
2011-10-14 14:13:40 +02:00
Jocelyn Fiat
4c36d75ef3 Using Transfer-Encoding: chunked in example to send response progressively 2011-10-12 17:23:24 +02:00
Jocelyn Fiat
09030a27d9 sync with submodules 2011-10-12 17:22:46 +02:00
Jocelyn Fiat
b9ca22006b removed unwanted code 2011-10-12 15:38:45 +02:00
Jocelyn Fiat
593b48fe90 applied recent changes on HTTP_REQUEST_METHOD_CONSTANTS 2011-10-12 11:56:25 +02:00
Jocelyn Fiat
735730b5a0 cosmetic 2011-10-12 11:52:00 +02:00
Jocelyn Fiat
035a133b5b Addition to "http" library, separated constants into
- HTTP_MIME_TYPES
 - HTTP_HEADER_NAMES
 - HTTP_REQUEST_METHODS
 - HTTP_STATUS_CODE   (already exists)

Do not set the "Status" header when using WGI_RESPONSE_BUFFER.write_header (...)
Cosmetic
2011-10-12 11:51:49 +02:00
Jocelyn Fiat
0144e97d69 Merge branch 'master' of https://github.com/jvelilla/Eiffel-Web-Framework
Conflicts:	examples/restbucks/src/domain/json_order_converter.e
Cosmetics
2011-10-11 14:25:22 +02:00
Jocelyn Fiat
26bfd72f5f Fixed errors recently introduced 2011-10-11 14:16:08 +02:00
Jocelyn Fiat
88542c2762 Merge branch 'master' of github.com:Eiffel-World/Eiffel-Web-Framework 2011-10-11 14:09:10 +02:00
Jocelyn Fiat
12fc54a403 sync with latest JSON 2011-10-11 14:08:41 +02:00
jvelilla
eb44eef885 Update order_handler, fix json_order_converter 2011-10-11 08:18:46 -03:00
Jocelyn Fiat
c2b66d6ca6 Use local curl if compiler is < 7.0.8.7340
otherwise, use ISE_LIBRARY cURL
2011-10-11 11:09:00 +02:00
Jocelyn Fiat
6758c4aef4 Temporary fixed issue of using modified cURL (which is cURL provided with EiffelStudio 7.0)
This changes will be reverted in the future
2011-10-11 10:46:56 +02:00
Jocelyn Fiat
6408bec628 Updated readme related to mirrored Eiffel cURL library 2011-10-10 17:56:09 +02:00
Jocelyn Fiat
f77ba9ccd8 added submodule ext/ise_library/curl to use the updated Eiffel cURL from ISE. 2011-10-10 17:48:18 +02:00
Jocelyn Fiat
c105c267e7 cosmetic 2011-10-10 16:09:44 +02:00
Jocelyn Fiat
19da4d6fd0 added http diagrams found on the web 2011-10-07 16:05:39 +02:00
Jocelyn Fiat
a9e2dc1135 Added the possibility to specify the supported content types
Added FIXME
2011-10-07 15:39:04 +02:00
Jocelyn Fiat
142dbc39b4 Cosmetic 2011-10-07 14:11:03 +02:00
Jocelyn Fiat
b17887d634 Added "Date:" helper feature in EWF_HEADER
Added license.lic to restbuck example, and mainly copyright to Javier
Use HTTP_STATUS_CODES
Minor improvements using object tests
Cosmetic (indentation, ..)
2011-10-07 14:03:31 +02:00
Jocelyn Fiat
f443087e71 Added a first simple test client to test the restbuck client 2011-10-06 19:09:56 +02:00
Jocelyn Fiat
e5eb11b4e7 added support for data in POST request 2011-10-06 19:09:17 +02:00
Jocelyn Fiat
720d8be08a Merge branch 'master' of https://github.com/jvelilla/Eiffel-Web-Framework 2011-10-06 17:37:41 +02:00
jvelilla
ed04b7fba0 Added REQUEST_RESOURCE_HANDLER_HELPER class to contain
common http method behavior.
Updated ORDER_HANLDER to use this new class.
2011-10-06 09:54:20 -03:00
Jocelyn Fiat
4c9e7a4331 Added `base_url' for REQUEST_ROUTER (and descendants)
Fixed implementation of REST_REQUEST_AGENT_HANDLER to avoid wrong path in inherited routine.
Allow to build a URI_TEMPLATE from another URI TEMPLATE,
   this way, if later we have more attribute (status or settings) to URI_TEMPLATE,
   we'll be able to change the `template' without breaking the settings
2011-10-05 17:09:16 +02:00
Jocelyn Fiat
cc6992a6fc added missing call to pre_execute and post_execute 2011-10-05 14:47:59 +02:00
Jocelyn Fiat
71c851ca39 Fixed missing http:// in absolute URL 2011-10-05 14:47:30 +02:00
Jocelyn Fiat
900ed8baea remove pre_execute, and post_execute, and make process_request frozen
this way, the user won't be tempted to redefine feature not being part of pure EWSGI interface.
2011-10-05 14:46:39 +02:00
Jocelyn Fiat
dba55fcfd9 better argument name, to precise the timeout is in second
also in comment.
2011-10-05 14:45:47 +02:00
Jocelyn Fiat
456299ccdf Fixed agent handler for rest library 2011-10-04 17:33:15 +02:00
Jocelyn Fiat
810208f176 Merge branch 'master' of github.com:jocelyn/Eiffel-Web-Framework 2011-10-04 16:19:36 +02:00
Jocelyn Fiat
27c637b066 fixed inheritance and precursor bad usage. 2011-10-04 16:19:09 +02:00
Jocelyn Fiat
a0df04a7f2 Merge branch 'master' of github.com:jocelyn/Eiffel-Web-Framework 2011-10-04 09:50:14 +02:00
Jocelyn Fiat
bc5d20b221 Merge branch 'master' of https://github.com/jvelilla/Eiffel-Web-Framework 2011-10-04 09:49:20 +02:00
jvelilla
7ba3eb9ecd Updated support for PUT. Now the example support
GET, POST, PUT, DELETE.
2011-10-03 09:26:01 -03:00
Jocelyn Fiat
2b14a40898 fixed compilation for ewsgi/tests/tests.ecf file 2011-09-28 17:08:28 +02:00
Jocelyn Fiat
aa20a1423f Made WGI_VALUE.name as READABLE_STRING_32 .. otherwise it is a pain to manipulate.
Changed return type of meta_variable to be WGI_STRING_VALUE ... since the meta variable can not be anything else.
Made sure REQUEST_URI starts with one and only one slash
Internal implementation: the _table now compares object
Removed SELF variable ... at least for now
Be sure to provide a REQUEST_URI even if the underlying connector does not.
2011-09-28 16:41:22 +02:00
Jocelyn Fiat
34c8cfa427 cleaned http_client configuration files 2011-09-28 14:53:34 +02:00
Jocelyn Fiat
f7dcadccd5 Added library/library.index 2011-09-28 14:42:53 +02:00
Jocelyn Fiat
f24df1d745 restructured ewsgi to avoid too many sub cluster 2011-09-28 14:42:34 +02:00
jvelilla
5adf40a9ed Updated Restbucks examples, handle not method allowed
in a better way, added the readme file.
2011-09-28 08:54:12 -03:00
jvelilla
f20bc42b76 Merge remote-tracking branch 'jocelynEWF/master' 2011-09-28 07:36:35 -03:00
Jocelyn Fiat
a4df57a7ac fixed compilation of rest example 2011-09-26 20:54:04 +02:00
Jocelyn Fiat
df59ae579b fixed typo 2011-09-26 17:19:37 +02:00
Jocelyn Fiat
738eb7555f Changed ITERATION_CURSOR [WGI_VALUE] into ITERABLE [WGI_VALUE] for WGI_REQUEST.*parameters* and similar
Applied recent changes on EWF_HEADER
2011-09-26 17:10:05 +02:00
Jocelyn Fiat
d397d4e35d Updated changelogs.txt
sync with nino and doc
2011-09-23 18:34:44 +02:00
Jocelyn Fiat
eeaa47d4f1 Merge branch 'master' of github.com:jocelyn/Eiffel-Web-Framework 2011-09-23 18:23:35 +02:00
Jocelyn Fiat
0db4317a49 Added AutoTest simple cases for ewsgi using Nino web server 2011-09-23 18:22:42 +02:00
Jocelyn Fiat
668847f8e8 Fixing issue with experimental WGI_MULTIPLE_STRING_VALUE
Fixed issue with RAW_POST_DATA
2011-09-23 18:21:57 +02:00
Jocelyn Fiat
e7fd7af2c5 Removed put_redirection' and replaced by put_location'
Removed useless code in some features
2011-09-23 18:20:23 +02:00
Jocelyn Fiat
24a5c7613d Use READABLE_STRING(_*) instead of just STRING(_*) 2011-09-23 18:20:16 +02:00
Jocelyn Fiat
d9f6cbe80e Added feature to shutdown the Nino http server 2011-09-23 18:18:54 +02:00
Jocelyn Fiat
95ec2e77df Added error reporting in HTTP_CLIENT_RESPONSE
Added missing set_connect_timeout
2011-09-23 18:18:27 +02:00
jvelilla
19b5edd9b4 Added validations. 2011-09-23 09:06:23 -03:00
Jocelyn Fiat
d25146dd27 Merge branch 'master' of https://github.com/jvelilla/Eiffel-Web-Framework 2011-09-22 16:19:48 +02:00
Jocelyn Fiat
ab1c696837 Added code to create an HTTP_AUTHORIZATION from the client side as well.
So now we can either interpret an HTTP_AUTHORIZATION  or build one HTTP_AUTHORIZATION

So far , only Basic auth is supported.
2011-09-22 15:13:59 +02:00
Jocelyn Fiat
dae8e1d67d Made all libraries compilable in any mode (voidsafe or not)
Fixed related examples
2011-09-22 15:12:33 +02:00
jvelilla
888bc61522 Initial import, work in progress restbuck example. Only support create
a resource
2011-09-22 09:29:59 -03:00
jvelilla
8291905da1 Merge remote-tracking branch 'jocelynEWF/master' 2011-09-22 07:53:23 -03:00
Jocelyn Fiat
d9ba97d33b Fixed issue where Content-Type and Content-Length were translated into HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH instead of just
CONTENT_TYPE and CONTENT_LENGTH
2011-09-21 15:33:40 +02:00
Jocelyn Fiat
33eddd9197 better assertion to ensure `base' is a valid base url 2011-09-21 15:30:20 +02:00
Jocelyn Fiat
458cb56f75 synch with Nino 2011-09-21 15:29:25 +02:00
Jocelyn Fiat
88c015470e better return type for http client functions
added helper features
2011-09-21 15:29:12 +02:00
jvelilla
f68a713c48 Merge remote-tracking branch 'jocelynEWF/master' 2011-09-21 07:49:40 -03:00
Jocelyn Fiat
0414cd4501 fixed case sensitive path 2011-09-20 18:19:23 +02:00
Jocelyn Fiat
284d7826c8 missing -safe.ecf config file for http_client 2011-09-20 16:59:54 +02:00
Jocelyn Fiat
dff267cd58 Now using READABLE_STRING_... type 2011-09-20 16:57:28 +02:00
Jocelyn Fiat
c2f7c198e0 Added simple HTTP client.
For now the implementation is using Eiffel cURL library.
It requires Eiffel cURL coming with next EiffelStudio 7.0 (or from eiffelstudio's repo from rev#87244 )
2011-09-20 16:55:44 +02:00
Jocelyn Fiat
b3ef7c846b Fixed issues in WGI_REQUEST's invariant
Fixed issues with guessing the default format for REST handling
Fixed issue with .._ROUTING_.. component.
2011-09-16 20:59:06 +02:00
Jocelyn Fiat
111812c4e9 Fixed issue with uri template router ..
it was applying on request_uri instead of path_info
now it match on PATH_INFO
2011-09-16 18:56:02 +02:00
Jocelyn Fiat
92d8357d09 more flexible authenticated query .. on handler, and not anymore on context object 2011-09-16 18:55:26 +02:00
Jocelyn Fiat
64060cfa41 fixed wrong order in parameter for callers of set_meta_string_variable 2011-09-16 18:54:44 +02:00
Jocelyn Fiat
d3239ec41b added debug_output to WGI_VALUE 2011-09-16 18:54:16 +02:00
Jocelyn Fiat
7b1557a52a first version of http authorization ..
for now, only basic digest
2011-09-16 18:53:57 +02:00
Jocelyn Fiat
c9a4ebcb23 added request_handler_routes_recorder to provide an implementation for `REQUEST_HANDLER.on_handler_mapped' 2011-09-16 15:17:49 +02:00
Jocelyn Fiat
3f899f6aae Added "on_handler_mapped" callback
to allow any REQUEST_HANDLER to record the existing routes.
2011-09-16 15:11:37 +02:00
Jocelyn Fiat
18684d167b typo 2011-09-16 15:02:08 +02:00
jvelilla
32bb75b9dc Merge remote-tracking branch 'jocelynEWF/master' 2011-09-16 07:04:40 -03:00
Jocelyn Fiat
d06bc76944 minor enhancement of error lib 2011-09-15 22:02:58 +02:00
Jocelyn Fiat
86825854ca Added WGI_MULTIPLE_STRING_VALUE
Renamed value as WGI_STRING_VALUE.string
Renamed a few classes .._CONTEXT_I  as .._CONTEXT
updated example.
2011-09-15 17:49:47 +02:00
Jocelyn Fiat
774cd004db cosmetic 2011-09-15 15:49:53 +02:00
Jocelyn Fiat
c300cf5b6e Merge branch 'master' of git://github.com/Eiffel-World/Eiffel-Web-Framework 2011-09-15 11:17:07 +02:00
Jocelyn Fiat
68247a1849 updated README.md 2011-09-15 10:55:14 +02:00
Jocelyn Fiat
22fd7490fe Simplified interface of "router" library classes 2011-09-14 16:48:27 +02:00
Jocelyn Fiat
8b6e9273fa applied renaming for rest and router lib 2011-09-14 16:05:01 +02:00
Jocelyn Fiat
76fa3e9ff5 Reorganized library "server/request/rest" 2011-09-14 15:46:45 +02:00
Jocelyn Fiat
1e3770d724 some renaming to use _I for the generic classes, and removed the DEFAULT_ prefix for default implementation
this should makes things easier for new users
2011-09-14 15:39:37 +02:00
Jocelyn Fiat
840ae1e6e4 reorganized router library 2011-09-14 15:04:29 +02:00
Jocelyn Fiat
5626e03aa8 - Adopted deferred WGI_VALUE design for Result type of *_parameter and similar functions
- Adopted the ITERATION_CURSOR [WGI_VALUE] design for *_parameters and similar functions
- renamed parameter as item
- provided helper function to handle "string" value parameters

Experimental for now.
2011-09-14 14:54:06 +02:00
Jocelyn Fiat
4bcea900a6 better result type (using READABLE_..) 2011-09-14 14:48:08 +02:00
Jocelyn Fiat
b1f5065e63 sync with nino 2011-09-14 14:47:29 +02:00
jvelilla
c37fe9ad79 Merge remote-tracking branch 'jocelynEWF/master' 2011-09-14 07:58:40 -03:00
Jocelyn Fiat
2e53f7e0c4 updated changelogs 2011-09-13 17:12:12 +02:00
Jocelyn Fiat
512f2d2ce5 Added first draft for RESTful library
note: the interfaces are likely to change in the future
2011-09-13 17:08:40 +02:00
Jocelyn Fiat
92105ca7b3 updated config file and examples 2011-09-13 17:07:17 +02:00
Jocelyn Fiat
f0c6eec23d adding routing handler
few renaming
2011-09-13 16:49:45 +02:00
Jocelyn Fiat
32197d0513 changing design to use generic instead of anchor types 2011-09-09 16:24:11 +02:00
Jocelyn Fiat
11286eeeef make router more easy to inherit from and specialized 2011-09-09 14:10:54 +02:00
Jocelyn Fiat
fb8412fcae Merge branch 'master' of github.com:jocelyn/Eiffel-Web-Framework 2011-09-09 08:54:20 +02:00
Jocelyn Fiat
9ec87a4329 Added support during match for {/vars}
and also handle cases such as   /foo.{format}{/vars}  or /foo.{format}{?vars} where no literal exists between the uri template expressions
2011-09-09 08:51:45 +02:00
Jocelyn Fiat
0c7e6c08e7 better type for argument and result (using READABLE_...) 2011-09-09 08:50:29 +02:00
Jocelyn Fiat
c1120a4226 change to standard default values 2011-09-09 08:50:05 +02:00
jvelilla
5c0cae35ef Sync to jocelyn EWF master 2011-09-08 07:45:10 -03:00
jvelilla
7bd5cdc232 Merge remote-tracking branch 'jocelynEWF/master' 2011-09-08 07:44:27 -03:00
jvelilla
ef85c07603 Update 2011-09-08 07:43:36 -03:00
Jocelyn Fiat
10db3c28a5 sync doc/wiki 2011-09-07 14:31:52 +02:00
Jocelyn Fiat
54dc7de189 use `resource' as generic name for uri or uri_template 2011-09-07 12:46:09 +02:00
Jocelyn Fiat
2244d101ea added changelogs.txt 2011-09-07 12:22:11 +02:00
Jocelyn Fiat
244fdf1b02 Added request methods criteria for the router component.
Now one can decide

map_agent_with_request_methods ("/foo/bar/{bar_id}", agent handle_foo_bar, <<"GET">>)
(and similar for non agent way)
This might be useful in pure RESTful environment.
2011-09-07 12:14:03 +02:00
Jocelyn Fiat
3c9fce293f fixed example .. where we forgot to set the status, and send the header
(DbC helped here)
2011-09-07 12:10:48 +02:00
Jocelyn Fiat
eee085dd5a renamed (un)set_meta_parameter as (un)set_meta_variable 2011-09-07 11:42:53 +02:00
Jocelyn Fiat
2d9e2d12a0 Missing HTTP_ prefix for header meta variable in REQUEST 2011-09-07 11:42:02 +02:00
Jocelyn Fiat
6a581f6d62 Changed prefix from EWSGI_ to WGI_
Changed meta variable type to READABLE_STRING_32
2011-08-30 19:20:42 +02:00
Jocelyn Fiat
ed8f5d694f naming: meta_variable(s)
changed some string type to READABLE_STRING_32
or READABLE_STRING_8 for now regarding Meta variables (need decision here..)
2011-08-29 12:48:03 +02:00
Jocelyn Fiat
c20600f281 changed prefix GW_ into EWF_ for EiffelWebFramework
use READABLE_STRING_GENERAL instead of just STRING
2011-08-25 16:00:18 +02:00
Jocelyn Fiat
53ccaa3fde sync wiki doc 2011-08-25 14:48:30 +02:00
Jocelyn Fiat
22afbd7ed0 Merge branch 'master' of github.com:jocelyn/Eiffel-Web-Framework
Conflicts:
	library/server/ewsgi/connectors/nino/src/gw_nino_connector.e
	library/server/ewsgi/ewsgi-safe.ecf
2011-08-25 14:48:02 +02:00
Jocelyn Fiat
f6b362217c Merged REQUEST and ENVIRONMENT into REQUEST
renamed ENVIRONMENT_NAMES into META_NAMES
better usage of READABLE_STRING_GENERAL, and other strings
abstract RESPONSE_BUFFER in implementation of EWSGI
for the implementation, inheriting from deferred specification (more to come later)
2011-08-25 14:41:35 +02:00
Jocelyn Fiat
e9ccf855b3 Merged REQUEST and ENVIRONMENT into REQUEST
renamed ENVIRONMENT_NAMES into META_NAMES
better usage of READABLE_STRING_GENERAL, and other strings
for the implementation, inheriting from deferred specification (more to come later)
2011-08-25 12:33:20 +02:00
Jocelyn Fiat
4d0148d562 fixing wrong feature usage 2011-08-24 15:54:01 +02:00
Jocelyn Fiat
ec6cc5f2b8 code cleaning, and prepare for internal review 2011-08-18 12:25:40 +02:00
Jocelyn Fiat
40018d36eb enhanced the ERROR_HANDLER 2011-08-04 15:11:51 +02:00
Jocelyn Fiat
8e18329063 minor improvements on response_as_result code 2011-08-02 14:53:37 +02:00
Jocelyn Fiat
c372494713 cosmetic in config file .ecf 2011-08-02 10:47:16 +02:00
Jocelyn Fiat
10f4a99ee1 add "write_headers_string" to RESPONSE_BUFFER 2011-08-02 10:46:53 +02:00
Jocelyn Fiat
e9085c614c sync wiki 2011-08-01 17:02:33 +02:00
Jocelyn Fiat
f7d3f519a7 moved ewsgi-full config file under tests (this is mainly for dev purpose, to be able to compile and edit all classes related to ewsgi) 2011-08-01 16:47:00 +02:00
Jocelyn Fiat
4eb22d0272 Tried to reduce gap between both EWSGI proposals
Re-adapt the Spec-compliant solution (instead of Lib-compliant solution).
  Thus no more 100% deferred interface.
Rename EWSGI_RESPONSE into EWSGI_RESPONSE_BUFFER
Added in extra/response-as-result/  an copy/paste from the implementation of Paul's proposal (not up to date with Paul's spec). But this is mainly for information and tests.
Removed part of the ewsgi/specification interfaces ... to be able to test EWSGI compliant library against the pure specification (experimental).
Renamed most of the GW_... into EWSGI_...
2011-08-01 16:41:16 +02:00
Jocelyn Fiat
bbcc9ef44b added http_accept feature to represent "Accept:" HTTP header 2011-07-29 15:13:34 +02:00
Jocelyn Fiat
801caa4e69 added hello_routed_world example
few changes on new `router' library (still in-progress)
2011-07-29 15:13:08 +02:00
Jocelyn Fiat
1b49445077 Added first draft for a URI and/or URI-template base request router. 2011-07-29 10:51:22 +02:00
Jocelyn Fiat
f005d8bb06 cosmetic 2011-07-29 10:50:31 +02:00
Jocelyn Fiat
a278537f7b Added "flush" to the EWSGI_RESPONSE_STREAM 2011-07-29 10:50:24 +02:00
Jocelyn Fiat
78b5b6f5fe Merge branch 'master' of github.com:jocelyn/Eiffel-Web-Framework 2011-07-29 08:52:57 +02:00
Jocelyn Fiat
a215c1e4d2 added missing non-void-safe .ecf 2011-07-29 08:52:36 +02:00
Jocelyn Fiat
fe3726677b added missing non-void-safe .ecf 2011-07-29 08:45:26 +02:00
Jocelyn Fiat
94d4909644 Fixed various issue with URI template, added corresponding tests 2011-07-28 18:45:25 +02:00
230 changed files with 14568 additions and 2935 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
EIFGENs
tests/temp/
.svn/

3
.gitmodules vendored
View File

@@ -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
View 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

View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

View 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>

View 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>

View 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>

Binary file not shown.

View File

@@ -0,0 +1 @@
h1 { border: solid 1px #00f; margin: 5px; padding: 5px; }

View 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
]"

File diff suppressed because it is too large Load Diff

View 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

View 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>

View 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>

View 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

View 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)"

View 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

View 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>

View File

@@ -0,0 +1 @@

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

Submodule ext/ise_library/curl added at 19637b616b

View File

@@ -0,0 +1 @@
Simple HTTP client implemented using Eiffel cURL library

View 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>

View 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>

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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
View 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

View File

@@ -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"/>

View File

@@ -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"/>

View File

@@ -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)"

View 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

View File

@@ -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

View 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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -11,7 +11,8 @@ inherit
ANY
DEBUG_OUTPUT
export {NONE} all end
URI_TEMPLATE_CONSTANTS
export {NONE} all end

View File

@@ -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"

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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"/>

View File

@@ -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"/>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"/>

View File

@@ -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"/>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"/>

View 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>

View File

@@ -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">

View 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>

View 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

View File

@@ -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)"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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")

View File

@@ -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